!7013 Can not modify properties inherit from sendable parent in napi

Merge pull request !7013 from diartyz/bugfix
This commit is contained in:
openharmony_ci 2024-05-28 08:26:45 +00:00 committed by Gitee
commit 619ee92cf1
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
4 changed files with 278 additions and 40 deletions

View File

@ -1401,6 +1401,7 @@ PropertyLookupResult JSHClass::LookupPropertyInBuiltinHClass(const JSThread *thr
JSHandle<JSHClass> JSHClass::CreateSHClass(JSThread *thread, JSHandle<JSHClass> JSHClass::CreateSHClass(JSThread *thread,
const std::vector<PropertyDescriptor> &descs, const std::vector<PropertyDescriptor> &descs,
const JSHClass *parentHClass,
bool isFunction) bool isFunction)
{ {
EcmaVM *vm = thread->GetEcmaVM(); EcmaVM *vm = thread->GetEcmaVM();
@ -1409,18 +1410,22 @@ JSHandle<JSHClass> JSHClass::CreateSHClass(JSThread *thread,
uint32_t length = descs.size(); uint32_t length = descs.size();
uint32_t maxInline = isFunction ? JSSharedFunction::MAX_INLINE : JSSharedObject::MAX_INLINE; uint32_t maxInline = isFunction ? JSSharedFunction::MAX_INLINE : JSSharedObject::MAX_INLINE;
if (parentHClass) {
if (parentHClass->IsDictionaryMode()) {
auto dict = reinterpret_cast<NameDictionary *>(parentHClass->GetLayout().GetTaggedObject());
length += dict->EntriesCount();
} else {
length += parentHClass->NumberOfProps();
}
}
JSHandle<JSHClass> hclass = JSHandle<JSHClass> hclass =
isFunction ? factory->NewSEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, length) isFunction ? factory->NewSEcmaHClass(JSSharedFunction::SIZE, JSType::JS_SHARED_FUNCTION, length)
: factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, length); : factory->NewSEcmaHClass(JSSharedObject::SIZE, JSType::JS_SHARED_OBJECT, length);
if (LIKELY(length <= maxInline)) { if (LIKELY(length <= maxInline)) {
auto layout = CreateSInlinedLayout(thread, descs); CreateSInlinedLayout(thread, descs, hclass, parentHClass);
hclass->SetLayout(thread, layout);
hclass->SetNumberOfProps(length);
} else { } else {
auto layout = CreateSDictLayout(thread, descs); CreateSDictLayout(thread, descs, hclass, parentHClass);
hclass->SetLayout(thread, layout);
hclass->SetNumberOfProps(0);
hclass->SetIsDictionaryMode(true);
} }
return hclass; return hclass;
@ -1428,7 +1433,7 @@ JSHandle<JSHClass> JSHClass::CreateSHClass(JSThread *thread,
JSHandle<JSHClass> JSHClass::CreateSConstructorHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs) JSHandle<JSHClass> JSHClass::CreateSConstructorHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs)
{ {
auto hclass = CreateSHClass(thread, descs, true); auto hclass = CreateSHClass(thread, descs, nullptr, true);
hclass->SetClassConstructor(true); hclass->SetClassConstructor(true);
hclass->SetConstructor(true); hclass->SetConstructor(true);
return hclass; return hclass;
@ -1442,15 +1447,22 @@ JSHandle<JSHClass> JSHClass::CreateSPrototypeHClass(JSThread *thread, const std:
return hclass; return hclass;
} }
JSHandle<LayoutInfo> JSHClass::CreateSInlinedLayout(JSThread *thread, const std::vector<PropertyDescriptor> &descs) void JSHClass::CreateSInlinedLayout(JSThread *thread,
const std::vector<PropertyDescriptor> &descs,
const JSHandle<JSHClass> &hclass,
const JSHClass *parentHClass)
{ {
EcmaVM *vm = thread->GetEcmaVM(); EcmaVM *vm = thread->GetEcmaVM();
ObjectFactory *factory = vm->GetFactory(); ObjectFactory *factory = vm->GetFactory();
uint32_t parentLength{0};
if (parentHClass) {
parentLength = parentHClass->NumberOfProps();
}
auto length = descs.size(); auto length = descs.size();
auto layout = factory->CreateSLayoutInfo(length); auto layout = factory->CreateSLayoutInfo(length + parentLength);
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
for (uint32_t i = 0; i < length; ++i) { for (uint32_t i = 0; i < length; ++i) {
key.Update(descs[i].GetKey()); key.Update(descs[i].GetKey());
PropertyAttributes attr = PropertyAttributes attr =
@ -1465,16 +1477,50 @@ JSHandle<LayoutInfo> JSHClass::CreateSInlinedLayout(JSThread *thread, const std:
layout->AddKey(thread, i, key.GetTaggedValue(), attr); layout->AddKey(thread, i, key.GetTaggedValue(), attr);
} }
return layout; auto index = length;
if (parentHClass) {
JSHandle<LayoutInfo> old(thread, parentHClass->GetLayout());
for (uint32_t i = 0; i < parentLength; i++) {
key.Update(descs[i].GetKey());
auto entry = layout->FindElementWithCache(thread, *hclass, key.GetTaggedValue(), index);
if (entry != -1) {
continue;
}
auto attr = PropertyAttributes(old->GetAttr(i));
attr.SetOffset(index);
layout->AddKey(thread, index, old->GetKey(i), attr);
++index;
}
}
hclass->SetLayout(thread, layout);
hclass->SetNumberOfProps(index);
auto inlinedPropsLength = hclass->GetInlinedProperties();
if (inlinedPropsLength > index) {
uint32_t duplicatedSize = (inlinedPropsLength - index) * JSTaggedValue::TaggedTypeSize();
hclass->SetObjectSize(hclass->GetObjectSize() - duplicatedSize);
}
} }
JSHandle<NameDictionary> JSHClass::CreateSDictLayout(JSThread *thread, const std::vector<PropertyDescriptor> &descs) void JSHClass::CreateSDictLayout(JSThread *thread,
const std::vector<PropertyDescriptor> &descs,
const JSHandle<JSHClass> &hclass,
const JSHClass *parentHClass)
{ {
uint32_t parentLength{0};
if (parentHClass) {
if (parentHClass->IsDictionaryMode()) {
parentLength =
reinterpret_cast<NameDictionary *>(parentHClass->GetLayout().GetTaggedObject())->EntriesCount();
} else {
parentLength = parentHClass->NumberOfProps();
}
}
auto length = descs.size(); auto length = descs.size();
JSMutableHandle<NameDictionary> dict( JSMutableHandle<NameDictionary> dict(
thread, NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(length))); thread,
NameDictionary::CreateInSharedHeap(thread, NameDictionary::ComputeHashTableSize(length + parentLength)));
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants()); auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
JSHandle<JSTaggedValue> value = globalConst->GetHandledUndefined(); JSHandle<JSTaggedValue> value = globalConst->GetHandledUndefined();
@ -1488,7 +1534,30 @@ JSHandle<NameDictionary> JSHClass::CreateSDictLayout(JSThread *thread, const std
dict.Update(newDict); dict.Update(newDict);
} }
return dict; if (parentHClass) {
if (parentHClass->IsDictionaryMode()) {
JSHandle<NameDictionary> old(thread, parentHClass->GetLayout());
std::vector<int> indexOrder = old->GetEnumerationOrder();
for (uint32_t i = 0; i < parentLength; i++) {
key.Update(old->GetKey(indexOrder[i]));
JSHandle<NameDictionary> newDict = NameDictionary::Put(
thread, dict, key, value, PropertyAttributes(old->GetAttributes(indexOrder[i])));
dict.Update(newDict);
}
} else {
JSHandle<LayoutInfo> old(thread, parentHClass->GetLayout());
for (uint32_t i = 0; i < parentLength; i++) {
key.Update(old->GetKey(i));
JSHandle<NameDictionary> newDict =
NameDictionary::Put(thread, dict, key, value, PropertyAttributes(old->GetAttr(i)));
dict.Update(newDict);
}
}
}
hclass->SetLayout(thread, dict);
hclass->SetNumberOfProps(0);
hclass->SetIsDictionaryMode(true);
} }
} // namespace panda::ecmascript } // namespace panda::ecmascript

View File

@ -1999,13 +1999,20 @@ public:
static JSHandle<JSHClass> CreateSHClass(JSThread *thread, static JSHandle<JSHClass> CreateSHClass(JSThread *thread,
const std::vector<PropertyDescriptor> &descs, const std::vector<PropertyDescriptor> &descs,
const JSHClass *parentHClass = nullptr,
bool isFunction = false); bool isFunction = false);
static JSHandle<JSHClass> CreateSConstructorHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs); static JSHandle<JSHClass> CreateSConstructorHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs);
static JSHandle<JSHClass> CreateSPrototypeHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs); static JSHandle<JSHClass> CreateSPrototypeHClass(JSThread *thread, const std::vector<PropertyDescriptor> &descs);
private: private:
static JSHandle<LayoutInfo> CreateSInlinedLayout(JSThread *thread, const std::vector<PropertyDescriptor> &descs); static void CreateSInlinedLayout(JSThread *thread,
static JSHandle<NameDictionary> CreateSDictLayout(JSThread *thread, const std::vector<PropertyDescriptor> &descs); const std::vector<PropertyDescriptor> &descs,
const JSHandle<JSHClass> &hclass,
const JSHClass *parentHClass = nullptr);
static void CreateSDictLayout(JSThread *thread,
const std::vector<PropertyDescriptor> &descs,
const JSHandle<JSHClass> &hclass,
const JSHClass *parentHClass = nullptr);
static inline void AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, static inline void AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key, const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key,
PropertyAttributes attr); PropertyAttributes attr);

View File

@ -2926,6 +2926,7 @@ Local<FunctionRef> FunctionRef::NewSendableClassFunction(const EcmaVM *vm,
EscapeLocalScope scope(vm); EscapeLocalScope scope(vm);
ObjectFactory *factory = vm->GetFactory(); ObjectFactory *factory = vm->GetFactory();
bool hasParent = !parent->IsNull();
JSNapiSendable sendable(thread, infos, name); JSNapiSendable sendable(thread, infos, name);
JSHandle<JSHClass> prototypeHClass = JSHClass::CreateSPrototypeHClass(thread, sendable.GetNonStaticDescs()); JSHandle<JSHClass> prototypeHClass = JSHClass::CreateSPrototypeHClass(thread, sendable.GetNonStaticDescs());
JSHandle<JSObject> prototype = factory->NewSharedOldSpaceJSObject(prototypeHClass); JSHandle<JSObject> prototype = factory->NewSharedOldSpaceJSObject(prototypeHClass);
@ -2937,23 +2938,28 @@ Local<FunctionRef> FunctionRef::NewSendableClassFunction(const EcmaVM *vm,
JSObject::SetSProperties(thread, prototype, sendable.GetNonStaticDescs()); JSObject::SetSProperties(thread, prototype, sendable.GetNonStaticDescs());
JSObject::SetSProperties(thread, JSHandle<JSObject>::Cast(constructor), sendable.GetStaticDescs()); JSObject::SetSProperties(thread, JSHandle<JSObject>::Cast(constructor), sendable.GetStaticDescs());
if (!parent->IsNull()) { if (hasParent) {
auto parentPrototype = parent->GetFunctionPrototype(vm); auto parentPrototype = parent->GetFunctionPrototype(vm);
prototypeHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parentPrototype)); prototypeHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parentPrototype));
constructorHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parent)); constructorHClass->SetPrototype(thread, JSNApiHelper::ToJSHandle(parent));
} }
prototype->GetJSHClass()->SetExtensible(false); prototypeHClass->SetExtensible(false);
constructor->SetHomeObject(thread, prototype); constructor->SetHomeObject(thread, prototype);
constructor->SetProtoOrHClass(thread, prototype); constructor->SetProtoOrHClass(thread, prototype);
constructor->SetLexicalEnv(thread, constructor); constructor->SetLexicalEnv(thread, constructor);
constructor->SetCallNapi(callNapi); constructor->SetCallNapi(callNapi);
constructor->SetSFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingSize); constructor->SetSFunctionExtraInfo(thread, nullptr, deleter, data, nativeBindingSize);
JSHandle<JSHClass> iHClass = JSHClass::CreateSHClass(thread, sendable.GetInstanceDescs()); JSHClass *parentIHClass{nullptr};
if (hasParent) {
JSHandle<JSFunction> parentHandle(JSNApiHelper::ToJSHandle(parent));
parentIHClass = reinterpret_cast<JSHClass *>(parentHandle->GetProtoOrHClass().GetTaggedObject());
}
JSHandle<JSHClass> iHClass = JSHClass::CreateSHClass(thread, sendable.GetInstanceDescs(), parentIHClass);
iHClass->SetPrototype(thread, JSHandle<JSTaggedValue>(prototype)); iHClass->SetPrototype(thread, JSHandle<JSTaggedValue>(prototype));
iHClass->SetExtensible(false); iHClass->SetExtensible(false);
constructor->SetProtoOrHClass(thread, iHClass); constructor->SetProtoOrHClass(thread, iHClass);
constructor->GetJSHClass()->SetExtensible(false); constructorHClass->SetExtensible(false);
Local<FunctionRef> result = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(constructor)); Local<FunctionRef> result = JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(constructor));
return scope.Escape(result); return scope.Escape(result);

View File

@ -101,26 +101,62 @@ panda::JSValueRef FunctionCallback(JsiRuntimeCallInfo *info)
return **thisRef; return **thisRef;
} }
Local<FunctionRef> GetNewSendableClassFunction( Local<FunctionRef> GetNewSendableClassFunction(EcmaVM *vm,
EcmaVM *vm, const char *instanceKey, const char *staticKey, const char *nonStaticKey, Local<FunctionRef> parent) Local<FunctionRef> parent,
bool isDict = false,
bool duplicated = false)
{ {
FunctionRef::SendablePropertiesInfos infos; FunctionRef::SendablePropertiesInfos infos;
Local<StringRef> instanceStr = StringRef::NewFromUtf8(vm, instanceKey); if (isDict) {
uint32_t maxInline = std::max(JSSharedFunction::MAX_INLINE, JSSharedObject::MAX_INLINE);
for (uint32_t i = 0; i < maxInline; ++i) {
Local<StringRef> tempStr = StringRef::NewFromUtf8(vm, std::to_string(i).c_str());
infos.instancePropertiesInfo.keys.push_back(tempStr);
infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
infos.staticPropertiesInfo.keys.push_back(tempStr);
infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
infos.nonStaticPropertiesInfo.keys.push_back(tempStr);
infos.nonStaticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
infos.nonStaticPropertiesInfo.attributes.push_back(PropertyAttribute(tempStr, true, true, true));
}
}
std::string instanceKey = "instance";
std::string staticKey = "static";
std::string nonStaticKey = "nonStatic";
if (!parent->IsNull()) {
instanceKey = "parentInstance";
staticKey = "parentStatic";
nonStaticKey = "parentNonStatic";
}
Local<StringRef> instanceStr = StringRef::NewFromUtf8(vm, instanceKey.c_str());
infos.instancePropertiesInfo.keys.push_back(instanceStr); infos.instancePropertiesInfo.keys.push_back(instanceStr);
infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE); infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(instanceStr, true, true, true)); infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(instanceStr, true, true, true));
Local<StringRef> staticStr = StringRef::NewFromUtf8(vm, staticKey); Local<StringRef> staticStr = StringRef::NewFromUtf8(vm, staticKey.c_str());
infos.staticPropertiesInfo.keys.push_back(staticStr); infos.staticPropertiesInfo.keys.push_back(staticStr);
infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE); infos.staticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(staticStr, true, true, true)); infos.staticPropertiesInfo.attributes.push_back(PropertyAttribute(staticStr, true, true, true));
Local<StringRef> nonStaticStr = StringRef::NewFromUtf8(vm, nonStaticKey); Local<StringRef> nonStaticStr = StringRef::NewFromUtf8(vm, nonStaticKey.c_str());
infos.nonStaticPropertiesInfo.keys.push_back(nonStaticStr); infos.nonStaticPropertiesInfo.keys.push_back(nonStaticStr);
infos.nonStaticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE); infos.nonStaticPropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
infos.nonStaticPropertiesInfo.attributes.push_back(PropertyAttribute(nonStaticStr, true, true, true)); infos.nonStaticPropertiesInfo.attributes.push_back(PropertyAttribute(nonStaticStr, true, true, true));
if (duplicated) {
Local<StringRef> duplicatedKey = StringRef::NewFromUtf8(vm, "instance");
Local<NumberRef> duplicatedValue = NumberRef::New(vm, 0);
infos.instancePropertiesInfo.keys.push_back(duplicatedKey);
infos.instancePropertiesInfo.types.push_back(FunctionRef::SendableType::NONE);
infos.instancePropertiesInfo.attributes.push_back(PropertyAttribute(duplicatedValue, true, true, true));
}
Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction( Local<FunctionRef> constructor = FunctionRef::NewSendableClassFunction(
vm, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm, "name"), infos, parent); vm, FunctionCallback, nullptr, nullptr, StringRef::NewFromUtf8(vm, "name"), infos, parent);
@ -130,8 +166,7 @@ Local<FunctionRef> GetNewSendableClassFunction(
HWTEST_F_L0(JSNApiTests, NewSendableClassFunction) HWTEST_F_L0(JSNApiTests, NewSendableClassFunction)
{ {
LocalScope scope(vm_); LocalScope scope(vm_);
Local<FunctionRef> constructor = Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", FunctionRef::Null(vm_));
ASSERT_EQ("name", constructor->GetName(vm_)->ToString()); ASSERT_EQ("name", constructor->GetName(vm_)->ToString());
ASSERT_TRUE(constructor->IsFunction()); ASSERT_TRUE(constructor->IsFunction());
@ -154,8 +189,41 @@ HWTEST_F_L0(JSNApiTests, NewSendableClassFunction)
HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionProperties) HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionProperties)
{ {
LocalScope scope(vm_); LocalScope scope(vm_);
Local<FunctionRef> constructor = Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", FunctionRef::Null(vm_)); Local<ObjectRef> prototype = constructor->GetFunctionPrototype(vm_);
ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString());
ASSERT_EQ("nonStatic", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString());
ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString());
// set static property on constructor
constructor->Set(vm_, staticKey, StringRef::NewFromUtf8(vm_, "static0"));
ASSERT_EQ("static0", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString());
// set non static property on prototype
prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
ASSERT_EQ("nonStatic0", prototype->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
// set invalid property on constructor
ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
constructor->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ("undefined", constructor->Get(vm_, invalidKey)->ToString(vm_)->ToString());
// set invalid property on prototype
ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
prototype->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ("undefined", prototype->Get(vm_, invalidKey)->ToString(vm_)->ToString());
}
HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictProperties)
{
LocalScope scope(vm_);
Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), true);
Local<ObjectRef> prototype = constructor->GetFunctionPrototype(vm_); Local<ObjectRef> prototype = constructor->GetFunctionPrototype(vm_);
ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString()); ASSERT_EQ("static", constructor->Get(vm_, staticKey)->ToString(vm_)->ToString());
@ -189,8 +257,50 @@ HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionProperties)
HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInstance) HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInstance)
{ {
LocalScope scope(vm_); LocalScope scope(vm_);
Local<FunctionRef> constructor = Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", FunctionRef::Null(vm_)); Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(constructor)));
ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(constructor)));
// set instance property
ASSERT_EQ("undefined", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString());
ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString());
obj->Set(vm_, instanceKey, StringRef::NewFromUtf8(vm_, "instance"));
ASSERT_EQ("instance", obj->Get(vm_, instanceKey)->ToString(vm_)->ToString());
ASSERT_EQ("undefined", obj0->Get(vm_, instanceKey)->ToString(vm_)->ToString());
// set non static property on prototype and get from instance
ASSERT_EQ("nonStatic", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
ASSERT_EQ("nonStatic", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
Local<ObjectRef> prototype = obj->GetPrototype(vm_);
prototype->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic0"));
ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
// set non static property on instance
ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
obj->Set(vm_, nonStaticKey, StringRef::NewFromUtf8(vm_, "nonStatic1"));
ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ("nonStatic0", obj->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
ASSERT_EQ("nonStatic0", obj0->Get(vm_, nonStaticKey)->ToString(vm_)->ToString());
// set invalid property on instance
ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString());
ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
obj->Set(vm_, invalidKey, StringRef::NewFromUtf8(vm_, "invalid"));
ASSERT_TRUE(vm_->GetJSThread()->HasPendingException());
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ("undefined", obj->Get(vm_, invalidKey)->ToString(vm_)->ToString());
}
HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictInstance)
{
LocalScope scope(vm_);
Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), true);
Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)}; Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0); Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0); Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
@ -233,9 +343,8 @@ HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInstance)
HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInherit) HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInherit)
{ {
LocalScope scope(vm_); LocalScope scope(vm_);
Local<FunctionRef> parent = Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
GetNewSendableClassFunction(vm_, "parentInstance", "parentStatic", "parentNonStatic", FunctionRef::Null(vm_)); Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent);
Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, "instance", "static", "nonStatic", parent);
Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)}; Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0); Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0); Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
@ -246,11 +355,8 @@ HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInherit)
// set parent instance property on instance // set parent instance property on instance
Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance"); Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString()); ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString());
ASSERT_FALSE(vm_->GetJSThread()->HasPendingException());
obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance")); obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance"));
ASSERT_TRUE(vm_->GetJSThread()->HasPendingException()); ASSERT_EQ("parentInstance", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString());
JSNApi::GetAndClearUncaughtException(vm_);
ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString());
// get parent static property from constructor // get parent static property from constructor
Local<StringRef> parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic"); Local<StringRef> parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic");
@ -261,6 +367,56 @@ HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInherit)
ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString()); ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString());
} }
HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionDictInherit)
{
LocalScope scope(vm_);
Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_), true);
Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent);
Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
Local<ObjectRef> obj0 = constructor->Constructor(vm_, argv, 0);
ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj0), JSNApiHelper::ToJSHandle(parent)));
// set parent instance property on instance
Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString());
obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance"));
ASSERT_EQ("parentInstance", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString());
// get parent static property from constructor
Local<StringRef> parentStaticKey = StringRef::NewFromUtf8(vm_, "parentStatic");
ASSERT_EQ("parentStatic", constructor->Get(vm_, parentStaticKey)->ToString(vm_)->ToString());
// get parent non static property form instance
Local<StringRef> parentNonStaticKey = StringRef::NewFromUtf8(vm_, "parentNonStatic");
ASSERT_EQ("parentNonStatic", obj->Get(vm_, parentNonStaticKey)->ToString(vm_)->ToString());
}
HWTEST_F_L0(JSNApiTests, NewSendableClassFunctionInheritWithDuplicatedKey)
{
LocalScope scope(vm_);
Local<FunctionRef> parent = GetNewSendableClassFunction(vm_, FunctionRef::Null(vm_));
Local<FunctionRef> constructor = GetNewSendableClassFunction(vm_, parent, false, true);
Local<JSValueRef> argv[1] = {NumberRef::New(vm_, 0)};
Local<ObjectRef> obj = constructor->Constructor(vm_, argv, 0);
ASSERT_TRUE(JSFunction::InstanceOf(thread_, JSNApiHelper::ToJSHandle(obj), JSNApiHelper::ToJSHandle(parent)));
// set parent instance property on instance
Local<StringRef> parentInstanceKey = StringRef::NewFromUtf8(vm_, "parentInstance");
ASSERT_EQ("undefined", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString());
obj->Set(vm_, parentInstanceKey, StringRef::NewFromUtf8(vm_, "parentInstance"));
ASSERT_EQ("parentInstance", obj->Get(vm_, parentInstanceKey)->ToString(vm_)->ToString());
// set duplicated instance property on instance
Local<StringRef> duplicatedInstanceKey = StringRef::NewFromUtf8(vm_, "instance");
ASSERT_EQ("undefined", obj->Get(vm_, duplicatedInstanceKey)->ToString(vm_)->ToString());
obj->Set(vm_, duplicatedInstanceKey, NumberRef::New(vm_, 1));
ASSERT_EQ("1", obj->Get(vm_, duplicatedInstanceKey)->ToString(vm_)->ToString());
}
HWTEST_F_L0(JSNApiTests, NewSendable) HWTEST_F_L0(JSNApiTests, NewSendable)
{ {
LocalScope scope(vm_); LocalScope scope(vm_);