Implement setIndexedPropertyHandler for ObjectTemplate

* rename data related to PropertyHandler
* refactoring ObjectWithPropertyHandler to handle NamedProperty and IndexedProperty both
* add cctest

Signed-off-by: HyukWoo Park <hyukwoo.park@samsung.com>
This commit is contained in:
HyukWoo Park 2021-11-12 16:45:22 +09:00 committed by Patrick Kim
commit ab15bd5574
5 changed files with 618 additions and 140 deletions

View file

@ -3565,14 +3565,24 @@ ObjectTemplateRef* ObjectTemplateRef::create()
return toRef(new ObjectTemplate());
}
void ObjectTemplateRef::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data)
void ObjectTemplateRef::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
{
toImpl(this)->setNamedPropertyHandler(data);
}
void ObjectTemplateRef::removePropertyHandler()
void ObjectTemplateRef::setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
{
toImpl(this)->removePropertyHandler();
toImpl(this)->setIndexedPropertyHandler(data);
}
void ObjectTemplateRef::removeNamedPropertyHandler()
{
toImpl(this)->removeNamedPropertyHandler();
}
void ObjectTemplateRef::removeIndexedPropertyHandler()
{
toImpl(this)->removeIndexedPropertyHandler();
}
OptionalRef<FunctionTemplateRef> ObjectTemplateRef::constructor()

View file

@ -1728,45 +1728,53 @@ public:
void* instanceExtraData();
};
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerGetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
typedef OptionalRef<ValueRef> (*PropertyHandlerGetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
// if intercepted you may returns non-empty value.
// the returned value will be use futuer operation(you can return true, or false)
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerSetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value);
enum TemplatePropertyAttribute {
TemplatePropertyAttributeNotExist = 1 << 0,
TemplatePropertyAttributeExist = 1 << 1,
TemplatePropertyAttributeWritable = 1 << 2,
TemplatePropertyAttributeEnumerable = 1 << 3,
TemplatePropertyAttributeConfigurable = 1 << 4,
typedef OptionalRef<ValueRef> (*PropertyHandlerSetterCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value);
enum class ObjectTemplatePropertyAttribute : uint8_t {
PropertyAttributeNotExist = 1 << 0,
PropertyAttributeExist = 1 << 1,
PropertyAttributeWritable = 1 << 2,
PropertyAttributeEnumerable = 1 << 3,
PropertyAttributeConfigurable = 1 << 4,
};
typedef TemplatePropertyAttribute (*TemplatePropertyHandlerQueryCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
inline bool operator&(ObjectTemplatePropertyAttribute a, ObjectTemplatePropertyAttribute b)
{
return static_cast<uint8_t>(a) & static_cast<uint8_t>(b);
}
inline ObjectTemplatePropertyAttribute operator|(ObjectTemplatePropertyAttribute a, ObjectTemplatePropertyAttribute b)
{
return static_cast<ObjectTemplatePropertyAttribute>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
}
typedef ObjectTemplatePropertyAttribute (*PropertyHandlerQueryCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
// if intercepted you may returns non-empty value.
// the returned value will be use futuer operation(you can return true, or false)
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerDeleteCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
typedef ValueVectorRef* (*TemplatePropertyHandlerEnumerationCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data);
typedef OptionalRef<ValueRef> (*PropertyHandlerDeleteCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
typedef ValueVectorRef* (*PropertyHandlerEnumerationCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data);
// if intercepted you may returns non-empty value.
// the returned value will be use futuer operation(you can return true, or false)
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerDefineOwnPropertyCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc);
typedef OptionalRef<ValueRef> (*TemplatePropertyHandlerGetPropertyDescriptorCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
typedef OptionalRef<ValueRef> (*PropertyHandlerDefineOwnPropertyCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc);
typedef OptionalRef<ValueRef> (*PropertyHandlerGetPropertyDescriptorCallback)(ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName);
struct ESCARGOT_EXPORT ObjectTemplatePropertyHandlerData {
TemplatePropertyHandlerGetterCallback getter;
TemplatePropertyHandlerSetterCallback setter;
TemplatePropertyHandlerQueryCallback query;
TemplatePropertyHandlerDeleteCallback deleter;
TemplatePropertyHandlerEnumerationCallback enumerator;
TemplatePropertyHandlerDefineOwnPropertyCallback definer;
TemplatePropertyHandlerGetPropertyDescriptorCallback descriptor;
void* data;
struct ESCARGOT_EXPORT ObjectTemplatePropertyHandlerConfiguration {
PropertyHandlerGetterCallback getter;
PropertyHandlerSetterCallback setter;
PropertyHandlerQueryCallback query;
PropertyHandlerDeleteCallback deleter;
PropertyHandlerEnumerationCallback enumerator;
PropertyHandlerDefineOwnPropertyCallback definer;
PropertyHandlerGetPropertyDescriptorCallback descriptor;
void* data; // this data member is guaranteed to be kept in GC heap
ObjectTemplatePropertyHandlerData(
TemplatePropertyHandlerGetterCallback getter = nullptr,
TemplatePropertyHandlerSetterCallback setter = nullptr,
TemplatePropertyHandlerQueryCallback query = nullptr,
TemplatePropertyHandlerDeleteCallback deleter = nullptr,
TemplatePropertyHandlerEnumerationCallback enumerator = nullptr,
TemplatePropertyHandlerDefineOwnPropertyCallback definer = nullptr,
TemplatePropertyHandlerGetPropertyDescriptorCallback descriptor = nullptr,
ObjectTemplatePropertyHandlerConfiguration(
PropertyHandlerGetterCallback getter = nullptr,
PropertyHandlerSetterCallback setter = nullptr,
PropertyHandlerQueryCallback query = nullptr,
PropertyHandlerDeleteCallback deleter = nullptr,
PropertyHandlerEnumerationCallback enumerator = nullptr,
PropertyHandlerDefineOwnPropertyCallback definer = nullptr,
PropertyHandlerGetPropertyDescriptorCallback descriptor = nullptr,
void* data = nullptr)
: getter(getter)
, setter(setter)
@ -1790,8 +1798,10 @@ public:
class ESCARGOT_EXPORT ObjectTemplateRef : public TemplateRef {
public:
static ObjectTemplateRef* create();
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data);
void removePropertyHandler();
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
void setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
void removeNamedPropertyHandler();
void removeIndexedPropertyHandler();
// returns function template if object template is instance template of function template
OptionalRef<FunctionTemplateRef> constructor();

View file

@ -29,21 +29,69 @@
namespace Escargot {
class ObjectTemplatePropertyHandlerData : public gc {
friend class ObjectWithPropertyHandler;
public:
explicit ObjectTemplatePropertyHandlerData(const ObjectTemplatePropertyHandlerConfiguration& data)
: m_getter(data.getter)
, m_setter(data.setter)
, m_query(data.query)
, m_deleter(data.deleter)
, m_enumerator(data.enumerator)
, m_definer(data.definer)
, m_descriptor(data.descriptor)
, m_data(data.data)
{
}
void* operator new(size_t size)
{
static MAY_THREAD_LOCAL bool typeInited = false;
static MAY_THREAD_LOCAL GC_descr descr;
if (!typeInited) {
// only mark m_data
GC_word obj_bitmap[GC_BITMAP_SIZE(ObjectTemplatePropertyHandlerData)] = { 0 };
GC_set_bit(obj_bitmap, GC_WORD_OFFSET(ObjectTemplatePropertyHandlerData, m_data));
descr = GC_make_descriptor(obj_bitmap, GC_WORD_LEN(ObjectTemplatePropertyHandlerData));
typeInited = true;
}
return GC_MALLOC_EXPLICITLY_TYPED(size, descr);
}
private:
PropertyHandlerGetterCallback m_getter;
PropertyHandlerSetterCallback m_setter;
PropertyHandlerQueryCallback m_query;
PropertyHandlerDeleteCallback m_deleter;
PropertyHandlerEnumerationCallback m_enumerator;
PropertyHandlerDefineOwnPropertyCallback m_definer;
PropertyHandlerGetPropertyDescriptorCallback m_descriptor;
void* m_data;
};
class ObjectWithPropertyHandler : public Object {
public:
virtual bool isValidPropertyName(const ObjectPropertyName& P) = 0;
ObjectWithPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplatePropertyHandlerData* namedData, ObjectTemplatePropertyHandlerData* indexedData)
: Object(structure, std::move(values), proto)
, m_namedPropertyHandler(namedData)
, m_indexedPropertyHandler(indexedData)
{
ASSERT(namedData || indexedData);
}
virtual ObjectGetResult getOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
{
if (isValidPropertyName(P) && m_propertyHandler->getter) {
auto ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler && propertyHandler->m_getter) {
auto ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
if (ret.hasValue()) {
if (m_propertyHandler->query) {
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
if (propertyHandler->m_query) {
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
return ObjectGetResult(toImpl(ret.value()), attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
return ObjectGetResult(toImpl(ret.value()), attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
} else {
return ObjectGetResult(toImpl(ret.value()), true, true, true);
}
@ -55,8 +103,9 @@ public:
virtual Value getOwnPropertyDescriptor(ExecutionState& state, const ObjectPropertyName& P) override
{
if (isValidPropertyName(P) && m_propertyHandler->descriptor) {
auto ret = m_propertyHandler->descriptor(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler && propertyHandler->m_descriptor) {
auto ret = propertyHandler->m_descriptor(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
if (ret.hasValue()) {
return toImpl(ret.value());
@ -68,14 +117,15 @@ public:
virtual bool defineOwnProperty(ExecutionState& state, const ObjectPropertyName& P, const ObjectPropertyDescriptor& desc) override
{
if (isValidPropertyName(P)) {
if (m_propertyHandler->definer) {
auto ret = m_propertyHandler->definer(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data, toRef(P.toPlainValue()), ObjectPropertyDescriptorRef((void*)&desc));
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler) {
if (propertyHandler->m_definer) {
auto ret = propertyHandler->m_definer(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data, toRef(P.toPlainValue()), ObjectPropertyDescriptorRef((void*)&desc));
if (ret.hasValue()) {
return ret.value()->toBoolean(toRef(&state));
}
} else if (m_propertyHandler->setter && desc.isValuePresent() && desc.isWritable() && desc.isEnumerable() && desc.isConfigurable()) {
auto ret = m_propertyHandler->setter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data, toRef(P.toPlainValue()), toRef(desc.value()));
} else if (propertyHandler->m_setter && desc.isValuePresent() && desc.isWritable() && desc.isEnumerable() && desc.isConfigurable()) {
auto ret = propertyHandler->m_setter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data, toRef(P.toPlainValue()), toRef(desc.value()));
if (ret.hasValue()) {
return ret.value()->toBoolean(toRef(&state));
}
@ -87,10 +137,11 @@ public:
virtual bool hasOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
{
if (isValidPropertyName(P) && m_propertyHandler->query) {
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler && propertyHandler->m_query) {
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
return attr & TemplatePropertyAttributeExist;
return attr & ObjectTemplatePropertyAttribute::PropertyAttributeExist;
}
return Object::hasOwnProperty(state, P);
@ -98,18 +149,19 @@ public:
virtual ObjectHasPropertyResult hasProperty(ExecutionState& state, const ObjectPropertyName& P) override
{
if (isValidPropertyName(P)) {
if (m_propertyHandler->query) {
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler) {
if (propertyHandler->m_query) {
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
if (attr & TemplatePropertyAttributeExist) {
bool isWritable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable;
bool isEnumerable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable;
bool isConfigurable = attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable;
if (attr & ObjectTemplatePropertyAttribute::PropertyAttributeExist) {
bool isWritable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable;
bool isEnumerable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable;
bool isConfigurable = attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable;
Value v;
if (m_propertyHandler->getter) {
OptionalRef<ValueRef> ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
if (propertyHandler->m_getter) {
OptionalRef<ValueRef> ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
if (ret.hasValue()) {
v = toImpl(ret.value());
@ -119,8 +171,8 @@ public:
ObjectHasPropertyResult result(ObjectGetResult(v, isWritable, isEnumerable, isConfigurable));
return result;
}
} else if (m_propertyHandler->getter) {
OptionalRef<ValueRef> ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
} else if (propertyHandler->m_getter) {
OptionalRef<ValueRef> ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
if (ret.hasValue()) {
return ObjectGetResult(toImpl(ret.value()), true, true, true);
@ -133,8 +185,9 @@ public:
virtual bool deleteOwnProperty(ExecutionState& state, const ObjectPropertyName& P) override
{
if (isValidPropertyName(P) && m_propertyHandler->deleter) {
auto ret = m_propertyHandler->deleter(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler && propertyHandler->m_deleter) {
auto ret = propertyHandler->m_deleter(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
toRef(P.toPlainValue()));
if (ret.hasValue()) {
return ret.value()->toBoolean(toRef(&state));
@ -146,35 +199,40 @@ public:
virtual void enumeration(ExecutionState& state, bool (*callback)(ExecutionState& state, Object* self, const ObjectPropertyName&, const ObjectStructurePropertyDescriptor& desc, void* data), void* data, bool shouldSkipSymbolKey = true) override
{
if (m_propertyHandler->enumerator) {
auto ret = m_propertyHandler->enumerator(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data);
if (m_propertyHandler->query) {
for (size_t i = 0; i < ret->size(); i++) {
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
continue;
}
ObjectTemplatePropertyHandlerData* propertyHandler = m_namedPropertyHandler;
for (size_t i = 0; i < 2; i++) {
if (propertyHandler && propertyHandler->m_enumerator) {
auto ret = propertyHandler->m_enumerator(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data);
if (propertyHandler->m_query) {
for (size_t i = 0; i < ret->size(); i++) {
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
continue;
}
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(this), m_propertyHandler->data,
ret->at(i));
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(this), propertyHandler->m_data,
ret->at(i));
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor(
(ObjectStructurePropertyDescriptor::PresentAttribute)(
((attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable) ? ObjectStructurePropertyDescriptor::WritablePresent : 0) | ((attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable) ? ObjectStructurePropertyDescriptor::EnumerablePresent : 0) | ((attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable) ? ObjectStructurePropertyDescriptor::ConfigurablePresent : 0)));
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
return;
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor(
(ObjectStructurePropertyDescriptor::PresentAttribute)(
((attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable) ? ObjectStructurePropertyDescriptor::WritablePresent : 0) | ((attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable) ? ObjectStructurePropertyDescriptor::EnumerablePresent : 0) | ((attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable) ? ObjectStructurePropertyDescriptor::ConfigurablePresent : 0)));
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
return;
}
}
}
} else {
for (size_t i = 0; i < ret->size(); i++) {
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
continue;
}
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor();
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
return;
} else {
for (size_t i = 0; i < ret->size(); i++) {
if (shouldSkipSymbolKey && ret->at(i)->isSymbol()) {
continue;
}
ObjectStructurePropertyDescriptor desc = ObjectStructurePropertyDescriptor::createDataDescriptor();
if (!callback(state, this, ObjectPropertyName(state, toImpl(ret->at(i))), desc, data)) {
return;
}
}
}
}
propertyHandler = m_indexedPropertyHandler;
}
Object::enumeration(state, callback, data, shouldSkipSymbolKey);
@ -182,15 +240,16 @@ public:
virtual ObjectGetResult get(ExecutionState& state, const ObjectPropertyName& P, const Value& receiver) override
{
if (isValidPropertyName(P)) {
auto ret = m_propertyHandler->getter(toRef(&state), toRef(this), toRef(receiver), m_propertyHandler->data,
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler && propertyHandler->m_getter) {
auto ret = propertyHandler->m_getter(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data,
toRef(P.toPlainValue()));
if (ret.hasValue()) {
if (m_propertyHandler->query) {
auto attr = m_propertyHandler->query(toRef(&state), toRef(this), toRef(receiver), m_propertyHandler->data,
if (propertyHandler->m_query) {
auto attr = propertyHandler->m_query(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data,
toRef(P.toPlainValue()));
return ObjectGetResult(toImpl(ret.value()), attr & TemplatePropertyAttribute::TemplatePropertyAttributeWritable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable, attr & TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
return ObjectGetResult(toImpl(ret.value()), attr & ObjectTemplatePropertyAttribute::PropertyAttributeWritable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable, attr & ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
} else {
return ObjectGetResult(toImpl(ret.value()), true, true, true);
}
@ -202,8 +261,9 @@ public:
virtual bool set(ExecutionState& state, const ObjectPropertyName& P, const Value& v, const Value& receiver) override
{
if (isValidPropertyName(P) && m_propertyHandler->setter) {
auto ret = m_propertyHandler->setter(toRef(&state), toRef(this), toRef(receiver), m_propertyHandler->data, toRef(P.toPlainValue()), toRef(v));
ObjectTemplatePropertyHandlerData* propertyHandler = P.isIndexString() ? m_indexedPropertyHandler : m_namedPropertyHandler;
if (propertyHandler && propertyHandler->m_setter) {
auto ret = propertyHandler->m_setter(toRef(&state), toRef(this), toRef(receiver), propertyHandler->m_data, toRef(P.toPlainValue()), toRef(v));
if (ret.hasValue()) {
return ret.value()->toBoolean(toRef(&state));
}
@ -222,28 +282,9 @@ public:
return false;
}
protected:
ObjectWithPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplatePropertyHandlerData* data)
: Object(structure, std::move(values), proto)
, m_propertyHandler(data)
{
ASSERT(!!m_propertyHandler);
}
ObjectTemplatePropertyHandlerData* m_propertyHandler;
};
class ObjectWithNamedPropertyHandler : public ObjectWithPropertyHandler {
public:
ObjectWithNamedPropertyHandler(ObjectStructure* structure, ObjectPropertyValueVector&& values, Object* proto, ObjectTemplatePropertyHandlerData* data)
: ObjectWithPropertyHandler(structure, std::forward<ObjectPropertyValueVector>(values), proto, data)
{
}
virtual bool isValidPropertyName(const ObjectPropertyName& P) override
{
return !P.isIndexString();
}
private:
ObjectTemplatePropertyHandlerData* m_namedPropertyHandler;
ObjectTemplatePropertyHandlerData* m_indexedPropertyHandler;
};
void* ObjectTemplate::operator new(size_t size)
@ -254,7 +295,8 @@ void* ObjectTemplate::operator new(size_t size)
GC_word objBitmap[GC_BITMAP_SIZE(ObjectTemplate)] = { 0 };
Template::fillGCDescriptor(objBitmap);
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_constructor));
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_propertyHandler));
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_namedPropertyHandler));
GC_set_bit(objBitmap, GC_WORD_OFFSET(ObjectTemplate, m_indexedPropertyHandler));
descr = GC_make_descriptor(objBitmap, GC_WORD_LEN(ObjectTemplate));
typeInited = true;
}
@ -263,7 +305,8 @@ void* ObjectTemplate::operator new(size_t size)
ObjectTemplate::ObjectTemplate(Optional<FunctionTemplate*> constructor)
: m_constructor(constructor)
, m_propertyHandler(nullptr)
, m_namedPropertyHandler(nullptr)
, m_indexedPropertyHandler(nullptr)
{
}
@ -289,8 +332,8 @@ Object* ObjectTemplate::instantiate(Context* ctx)
proto = ctx->globalObject()->objectPrototype();
}
if (m_propertyHandler) {
result = new ObjectWithNamedPropertyHandler(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto, m_propertyHandler);
if (m_namedPropertyHandler || m_indexedPropertyHandler) {
result = new ObjectWithPropertyHandler(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto, m_namedPropertyHandler, m_indexedPropertyHandler);
} else {
result = new Object(m_cachedObjectStructure.m_objectStructure, std::move(objectPropertyValues), proto);
}
@ -372,16 +415,29 @@ bool ObjectTemplate::installTo(Context* ctx, Object* target)
return result.error.isEmpty();
}
void ObjectTemplate::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data)
void ObjectTemplate::setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
{
ASSERT(!m_propertyHandler);
m_propertyHandler = new (GC) ObjectTemplatePropertyHandlerData(data);
ASSERT(!m_namedPropertyHandler);
m_namedPropertyHandler = new ObjectTemplatePropertyHandlerData(data);
}
void ObjectTemplate::removePropertyHandler()
void ObjectTemplate::setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data)
{
ASSERT(!m_propertyHandler);
GC_FREE(m_propertyHandler);
m_propertyHandler = nullptr;
ASSERT(!m_indexedPropertyHandler);
m_indexedPropertyHandler = new ObjectTemplatePropertyHandlerData(data);
}
void ObjectTemplate::removeNamedPropertyHandler()
{
// just set nullptr here because property handler might be used in instantiated ObjectWithPropertyHandler
ASSERT(!m_namedPropertyHandler);
m_namedPropertyHandler = nullptr;
}
void ObjectTemplate::removeIndexedPropertyHandler()
{
// just set nullptr here because property handler might be used in instantiated ObjectWithPropertyHandler
ASSERT(!m_indexedPropertyHandler);
m_indexedPropertyHandler = nullptr;
}
} // namespace Escargot

View file

@ -25,7 +25,8 @@
namespace Escargot {
class FunctionTemplate;
struct ObjectTemplatePropertyHandlerData;
class ObjectTemplatePropertyHandlerData;
struct ObjectTemplatePropertyHandlerConfiguration;
class ObjectTemplate : public Template {
public:
@ -50,12 +51,15 @@ public:
void* operator new(size_t size);
void* operator new[](size_t size) = delete;
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerData& data);
void removePropertyHandler();
void setNamedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
void setIndexedPropertyHandler(const ObjectTemplatePropertyHandlerConfiguration& data);
void removeNamedPropertyHandler();
void removeIndexedPropertyHandler();
private:
Optional<FunctionTemplate*> m_constructor;
ObjectTemplatePropertyHandlerData* m_propertyHandler;
ObjectTemplatePropertyHandlerData* m_namedPropertyHandler;
ObjectTemplatePropertyHandlerData* m_indexedPropertyHandler;
};
} // namespace Escargot

View file

@ -743,7 +743,7 @@ TEST(ObjectTemplate, Basic4)
{
ObjectTemplateRef* tpl = ObjectTemplateRef::create();
ObjectTemplatePropertyHandlerData handler;
ObjectTemplatePropertyHandlerConfiguration handler;
handler.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
return (ValueRef*)self->extraData();
@ -768,14 +768,14 @@ TEST(ObjectTemplate, Basic4)
return OptionalRef<ValueRef>();
};
handler.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> TemplatePropertyAttribute {
handler.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
return (TemplatePropertyAttribute)(TemplatePropertyAttribute::TemplatePropertyAttributeWritable | TemplatePropertyAttribute::TemplatePropertyAttributeEnumerable | TemplatePropertyAttribute::TemplatePropertyAttributeConfigurable);
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
}
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
return (TemplatePropertyAttribute)(TemplatePropertyAttribute::TemplatePropertyAttributeWritable);
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
}
return TemplatePropertyAttribute::TemplatePropertyAttributeNotExist;
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
};
handler.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
@ -861,7 +861,7 @@ TEST(ObjectTemplate, Basic4)
ObjectTemplateRef* tpl2 = ObjectTemplateRef::create();
ObjectTemplatePropertyHandlerData handler2;
ObjectTemplatePropertyHandlerConfiguration handler2;
handler2.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
return OptionalRef<ValueRef>();
};
@ -883,6 +883,404 @@ TEST(ObjectTemplate, Basic4)
obj);
}
TEST(ObjectTemplate, Basic5)
{
ObjectTemplateRef* tpl = ObjectTemplateRef::create();
ObjectTemplatePropertyHandlerConfiguration handler;
handler.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 1) {
return (ValueRef*)self->extraData();
}
if (indexProperty == 3) {
return ValueRef::create(555.555);
}
return OptionalRef<ValueRef>();
};
handler.setter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 1) {
self->setExtraData(value);
return OptionalRef<ValueRef>(ValueRef::create(true));
}
if (indexProperty == 3) {
self->setExtraData(ValueRef::create(123));
return OptionalRef<ValueRef>(ValueRef::create(true));
}
return OptionalRef<ValueRef>();
};
handler.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 1) {
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
}
if (indexProperty == 3) {
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
}
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
};
handler.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
ValueVectorRef* v = ValueVectorRef::create(2);
v->set(0, StringRef::createFromASCII("1"));
v->set(1, ValueRef::create(3));
return v;
};
handler.deleter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 4) {
return OptionalRef<ValueRef>(ValueRef::create(false));
}
return OptionalRef<ValueRef>();
};
handler.descriptor = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 5) {
ObjectRef* desc = ObjectRef::create(state);
desc->set(state, StringRef::createFromASCII("value"), ValueRef::createNull());
return desc;
}
return OptionalRef<ValueRef>();
};
tpl->setIndexedPropertyHandler(handler);
ObjectRef* obj = tpl->instantiate(g_context.get());
obj->setExtraData(ValueRef::create(123));
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
EXPECT_TRUE(obj->set(state, StringRef::createFromASCII("1"), ValueRef::createNull()));
ValueRef* one = obj->get(state, ValueRef::create(1));
EXPECT_TRUE(one->isNull());
ValueRef* two = obj->get(state, ValueRef::create(2));
EXPECT_TRUE(two->isUndefined());
EXPECT_TRUE(obj->defineDataProperty(state, ValueRef::create(3), ValueRef::create(333), true, true, true));
ValueRef* threeResult = obj->get(state, StringRef::createFromASCII("1"));
EXPECT_TRUE(threeResult->equalsTo(state, ValueRef::create(123)));
ValueRef* desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("1"));
ValueRef* json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":123,\"writable\":true,\"enumerable\":true,\"configurable\":true}");
desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("3"));
json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":555.555,\"writable\":true,\"enumerable\":false,\"configurable\":false}");
int pcnt = 0;
obj->enumerateObjectOwnProperties(state, [&](ExecutionStateRef* state, ValueRef* propertyName, bool isWritable, bool isEnumerable, bool isConfigurable) -> bool {
if (pcnt == 0) {
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 1);
EXPECT_TRUE(isWritable);
EXPECT_TRUE(isEnumerable);
EXPECT_TRUE(isConfigurable);
} else if (pcnt == 1) {
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 3);
EXPECT_TRUE(isWritable);
EXPECT_TRUE(!isEnumerable);
EXPECT_TRUE(!isConfigurable);
}
pcnt++;
return true;
});
EXPECT_TRUE(pcnt == 2);
EXPECT_TRUE(obj->deleteOwnProperty(state, StringRef::createFromASCII("6")));
EXPECT_FALSE(obj->deleteOwnProperty(state, ValueRef::create(4)));
auto descObj = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("5"));
EXPECT_TRUE(descObj->isObject());
EXPECT_TRUE(descObj->asObject()->get(state, StringRef::createFromASCII("value"))->isNull());
return ValueRef::createUndefined();
},
obj);
ObjectTemplateRef* tpl2 = ObjectTemplateRef::create();
ObjectTemplatePropertyHandlerConfiguration handler2;
handler2.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
return OptionalRef<ValueRef>();
};
handler2.definer = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, const ObjectPropertyDescriptorRef& desc) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 100) {
return OptionalRef<ValueRef>(ValueRef::create(false));
}
return OptionalRef<ValueRef>();
};
tpl2->setIndexedPropertyHandler(handler2);
obj = tpl2->instantiate(g_context.get());
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
EXPECT_FALSE(obj->defineDataProperty(state, StringRef::createFromASCII("100"), ValueRef::create(111), false, false, false));
return ValueRef::createUndefined();
},
obj);
}
TEST(ObjectTemplate, Basic6)
{
ObjectTemplateRef* tpl = ObjectTemplateRef::create();
ObjectTemplatePropertyHandlerConfiguration handler1;
handler1.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
return (ValueRef*)self->extraData();
}
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
return ValueRef::create(555.555);
}
return OptionalRef<ValueRef>();
};
handler1.setter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value) -> OptionalRef<ValueRef> {
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
self->setExtraData(value);
return OptionalRef<ValueRef>(ValueRef::create(true));
}
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
self->setExtraData(ValueRef::create(123));
return OptionalRef<ValueRef>(ValueRef::create(true));
}
return OptionalRef<ValueRef>();
};
handler1.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("aaa", 3)) {
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
}
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ccc", 3)) {
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
}
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
};
handler1.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
ValueVectorRef* v = ValueVectorRef::create(2);
v->set(0, StringRef::createFromASCII("aaa"));
v->set(1, StringRef::createFromASCII("ccc"));
return v;
};
handler1.deleter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("ddd", 3)) {
return OptionalRef<ValueRef>(ValueRef::create(false));
}
return OptionalRef<ValueRef>();
};
handler1.descriptor = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
if (propertyName->isString() && propertyName->asString()->equalsWithASCIIString("eee", 3)) {
ObjectRef* desc = ObjectRef::create(state);
desc->set(state, StringRef::createFromASCII("value"), ValueRef::createNull());
return desc;
}
return OptionalRef<ValueRef>();
};
ObjectTemplatePropertyHandlerConfiguration handler2;
handler2.getter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 1) {
return (ValueRef*)self->extraData();
}
if (indexProperty == 3) {
return ValueRef::create(555.555);
}
return OptionalRef<ValueRef>();
};
handler2.setter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName, ValueRef* value) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 1) {
self->setExtraData(value);
return OptionalRef<ValueRef>(ValueRef::create(true));
}
if (indexProperty == 3) {
self->setExtraData(ValueRef::create(123));
return OptionalRef<ValueRef>(ValueRef::create(true));
}
return OptionalRef<ValueRef>();
};
handler2.query = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> ObjectTemplatePropertyAttribute {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 1) {
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable | ObjectTemplatePropertyAttribute::PropertyAttributeEnumerable | ObjectTemplatePropertyAttribute::PropertyAttributeConfigurable);
}
if (indexProperty == 3) {
return (ObjectTemplatePropertyAttribute)(ObjectTemplatePropertyAttribute::PropertyAttributeWritable);
}
return ObjectTemplatePropertyAttribute::PropertyAttributeNotExist;
};
handler2.enumerator = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data) -> ValueVectorRef* {
ValueVectorRef* v = ValueVectorRef::create(2);
v->set(0, StringRef::createFromASCII("1"));
v->set(1, ValueRef::create(3));
return v;
};
handler2.deleter = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 4) {
return OptionalRef<ValueRef>(ValueRef::create(false));
}
return OptionalRef<ValueRef>();
};
handler2.descriptor = [](ExecutionStateRef* state, ObjectRef* self, ValueRef* receiver, void* data, ValueRef* propertyName) -> OptionalRef<ValueRef> {
uint32_t indexProperty = propertyName->tryToUseAsIndexProperty(state);
EXPECT_TRUE(indexProperty != ValueRef::InvalidIndexPropertyValue);
if (indexProperty == 5) {
ObjectRef* desc = ObjectRef::create(state);
desc->set(state, StringRef::createFromASCII("value"), ValueRef::createNull());
return desc;
}
return OptionalRef<ValueRef>();
};
tpl->setNamedPropertyHandler(handler1);
tpl->setIndexedPropertyHandler(handler2);
ObjectRef* obj = tpl->instantiate(g_context.get());
obj->setExtraData(ValueRef::create(123));
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
EXPECT_TRUE(obj->set(state, StringRef::createFromASCII("aaa"), ValueRef::createNull()));
ValueRef* aaa = obj->get(state, StringRef::createFromASCII("aaa"));
EXPECT_TRUE(aaa->isNull());
ValueRef* bbb = obj->get(state, StringRef::createFromASCII("bbb"));
EXPECT_TRUE(bbb->isUndefined());
EXPECT_TRUE(obj->defineDataProperty(state, StringRef::createFromASCII("ccc"), ValueRef::create(333), true, true, true));
ValueRef* cccResult = obj->get(state, StringRef::createFromASCII("aaa"));
EXPECT_TRUE(cccResult->equalsTo(state, ValueRef::create(123)));
ValueRef* desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("aaa"));
ValueRef* json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":123,\"writable\":true,\"enumerable\":true,\"configurable\":true}");
desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("ccc"));
json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":555.555,\"writable\":true,\"enumerable\":false,\"configurable\":false}");
int pcnt = 0;
// FIXME enumration operation
obj->enumerateObjectOwnProperties(state, [&](ExecutionStateRef* state, ValueRef* propertyName, bool isWritable, bool isEnumerable, bool isConfigurable) -> bool {
if (pcnt == 0) {
EXPECT_TRUE(propertyName->toString(state)->toStdUTF8String() == "aaa");
EXPECT_TRUE(isWritable);
EXPECT_TRUE(isEnumerable);
EXPECT_TRUE(isConfigurable);
} else if (pcnt == 1) {
EXPECT_TRUE(propertyName->toString(state)->toStdUTF8String() == "ccc");
EXPECT_TRUE(isWritable);
EXPECT_TRUE(!isEnumerable);
EXPECT_TRUE(!isConfigurable);
}
pcnt++;
return true;
});
EXPECT_TRUE(pcnt == 4);
EXPECT_TRUE(obj->deleteOwnProperty(state, StringRef::createFromASCII("fff")));
EXPECT_FALSE(obj->deleteOwnProperty(state, StringRef::createFromASCII("ddd")));
auto descObj = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("eee"));
EXPECT_TRUE(descObj->isObject());
EXPECT_TRUE(descObj->asObject()->get(state, StringRef::createFromASCII("value"))->isNull());
return ValueRef::createUndefined();
},
obj);
obj->setExtraData(ValueRef::create(123));
Evaluator::execute(g_context.get(), [](ExecutionStateRef* state, ObjectRef* obj) -> ValueRef* {
EXPECT_TRUE(obj->set(state, StringRef::createFromASCII("1"), ValueRef::createNull()));
ValueRef* one = obj->get(state, ValueRef::create(1));
EXPECT_TRUE(one->isNull());
ValueRef* two = obj->get(state, ValueRef::create(2));
EXPECT_TRUE(two->isUndefined());
EXPECT_TRUE(obj->defineDataProperty(state, ValueRef::create(3), ValueRef::create(333), true, true, true));
ValueRef* threeResult = obj->get(state, StringRef::createFromASCII("1"));
EXPECT_TRUE(threeResult->equalsTo(state, ValueRef::create(123)));
ValueRef* desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("1"));
ValueRef* json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":123,\"writable\":true,\"enumerable\":true,\"configurable\":true}");
desc = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("3"));
json = state->context()->globalObject()->jsonStringify()->call(state, ValueRef::createUndefined(), 1, &desc);
EXPECT_TRUE(json->toString(state)->toStdUTF8String() == "{\"value\":555.555,\"writable\":true,\"enumerable\":false,\"configurable\":false}");
int pcnt = 0;
// FIXME enumration operation
obj->enumerateObjectOwnProperties(state, [&](ExecutionStateRef* state, ValueRef* propertyName, bool isWritable, bool isEnumerable, bool isConfigurable) -> bool {
if (pcnt == 2) {
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 1);
EXPECT_TRUE(isWritable);
EXPECT_TRUE(isEnumerable);
EXPECT_TRUE(isConfigurable);
} else if (pcnt == 3) {
EXPECT_TRUE(propertyName->tryToUseAsIndexProperty(state) == 3);
EXPECT_TRUE(isWritable);
EXPECT_TRUE(!isEnumerable);
EXPECT_TRUE(!isConfigurable);
}
pcnt++;
return true;
});
EXPECT_TRUE(pcnt == 4);
EXPECT_TRUE(obj->deleteOwnProperty(state, StringRef::createFromASCII("6")));
EXPECT_FALSE(obj->deleteOwnProperty(state, ValueRef::create(4)));
auto descObj = obj->getOwnPropertyDescriptor(state, StringRef::createFromASCII("5"));
EXPECT_TRUE(descObj->isObject());
EXPECT_TRUE(descObj->asObject()->get(state, StringRef::createFromASCII("value"))->isNull());
return ValueRef::createUndefined();
},
obj);
}
TEST(FunctionTemplate, Basic1)
{
auto ft = FunctionTemplateRef::create(AtomicStringRef::create(g_context.get(), "asdf"), 2, true, true, [](ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, OptionalRef<ObjectRef> newTarget) -> ValueRef* {