diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 6c0acdb3d94eb9865f725c5d86db1e755011575c..a98f1a892112422ef5225cabe8fd2ecaee7c201e 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -558,6 +558,9 @@ public: int32_t length); Local Constructor(const EcmaVM *vm, const Local argv[], int32_t length); Local GetFunctionPrototype(const EcmaVM *vm); + // Inherit Prototype from parent function + // set this.Prototype.__proto__ to parent.Prototype, set this.__proto__ to parent function + bool Inherit(const EcmaVM *vm, Local parent); void SetName(const EcmaVM *vm, Local name); Local GetName(const EcmaVM *vm); bool IsNative(const EcmaVM *vm); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index a5f88fbd87134f7f36c4376fcf362c2157a3e7af..50d056a1c5ae3b67211957c36cea0d2a29cc3681 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -938,6 +938,23 @@ Local FunctionRef::GetFunctionPrototype(const EcmaVM *vm) return JSNApiHelper::ToLocal(prototype); } +bool FunctionRef::Inherit(const EcmaVM *vm, Local parent) +{ + JSThread *thread = vm->GetJSThread(); + JSHandle parentValue = JSNApiHelper::ToJSHandle(parent); + JSHandle parentHandle = JSHandle::Cast(parentValue); + JSHandle thisHandle = JSHandle::Cast(JSNApiHelper::ToJSHandle(this)); + // Set this.__proto__ to parent + bool res = JSObject::SetPrototype(thread, thisHandle, parentValue); + if (!res) { + return false; + } + // Set this.Prototype.__proto__ to parent.Prototype + JSHandle parentProtoType(thread, JSFunction::PrototypeGetter(thread, parentHandle)); + JSHandle thisProtoType(thread, JSFunction::PrototypeGetter(thread, thisHandle)); + return JSObject::SetPrototype(thread, JSHandle::Cast(thisProtoType), parentProtoType); +} + void FunctionRef::SetName(const EcmaVM *vm, Local name) { JSThread *thread = vm->GetJSThread(); diff --git a/ecmascript/napi/test/jsnapi_tests.cpp b/ecmascript/napi/test/jsnapi_tests.cpp index 8c25504b75d91399eb33a951d763eca8fcbcf2d5..d0282cca4840686bc9cabab21f000dd6219cf508 100644 --- a/ecmascript/napi/test/jsnapi_tests.cpp +++ b/ecmascript/napi/test/jsnapi_tests.cpp @@ -18,8 +18,10 @@ #include #include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" #include "ecmascript/js_thread.h" #include "ecmascript/napi/include/jsnapi.h" +#include "ecmascript/napi/jsnapi_helper-inl.h" #include "ecmascript/object_factory.h" using namespace panda; @@ -628,4 +630,67 @@ HWTEST_F_L0(JSNApiTests, SyntaxError) JSNApi::ThrowException(vm_, error); ASSERT_TRUE(thread_->HasPendingException()); } + +HWTEST_F_L0(JSNApiTests, InheritPrototype) +{ + LocalScope scope(vm_); + JSHandle env = vm_->GetGlobalEnv(); + // new with Builtins::Set Prototype + JSHandle set = env->GetBuiltinsSetFunction(); + Local setLocal = JSNApiHelper::ToLocal(set); + // new with Builtins::Map Prototype + JSHandle map = env->GetBuiltinsMapFunction(); + Local mapLocal = JSNApiHelper::ToLocal(map); + JSHandle setPrototype(thread_, JSHandle::Cast(set)->GetFunctionPrototype()); + JSHandle mapPrototype(thread_, JSHandle::Cast(map)->GetFunctionPrototype()); + JSHandle mapPrototypeProto(thread_, JSHandle::Cast(mapPrototype)->GetPrototype(thread_)); + bool same = JSTaggedValue::SameValue(setPrototype, mapPrototypeProto); + // before inherit, map.Prototype.__proto__ should be different from set.Prototype + ASSERT_FALSE(same); + // before inherit, map.__proto__ should be different from set + JSHandle mapProto(thread_, JSHandle::Cast(map)->GetPrototype(thread_)); + bool same1 = JSTaggedValue::SameValue(set, mapProto); + ASSERT_FALSE(same1); + + // Set property to Set Function + auto factory = vm_->GetFactory(); + JSHandle defaultString = thread_->GlobalConstants()->GetHandledDefaultString(); + PropertyDescriptor desc = PropertyDescriptor(thread_, defaultString); + bool success = JSObject::DefineOwnProperty(thread_, JSHandle::Cast(set), defaultString, desc); + ASSERT_TRUE(success); + JSHandle property1String(thread_, factory->NewFromCanBeCompressString("property1").GetTaggedValue()); + JSHandle func = env->GetTypedArrayFunction(); + PropertyDescriptor desc1 = PropertyDescriptor(thread_, func); + bool success1 = JSObject::DefineOwnProperty(thread_, JSHandle::Cast(set), property1String, desc1); + ASSERT_TRUE(success1); + + mapLocal->Inherit(vm_, setLocal); + JSHandle sonHandle = JSNApiHelper::ToJSHandle(mapLocal); + JSHandle sonPrototype(thread_, JSHandle::Cast(sonHandle)->GetFunctionPrototype()); + JSHandle sonPrototypeProto(thread_, JSHandle::Cast(sonPrototype)->GetPrototype(thread_)); + bool same2 = JSTaggedValue::SameValue(setPrototype, sonPrototypeProto); + ASSERT_TRUE(same2); + JSHandle sonProto(thread_, JSHandle::Cast(map)->GetPrototype(thread_)); + bool same3 = JSTaggedValue::SameValue(set, sonProto); + ASSERT_TRUE(same3); + + // son = new Son(), Son() inherit from Parent(), Test whether son.InstanceOf(Parent) is true + JSHandle sonObj = factory->NewJSObjectByConstructor(JSHandle::Cast(sonHandle), sonHandle); + bool isInstance = JSObject::InstanceOf(thread_, JSHandle::Cast(sonObj), set); + ASSERT_TRUE(isInstance); + + // Test whether son Function can access to property of parent Function + OperationResult res = JSObject::GetProperty(thread_, JSHandle::Cast(sonHandle), defaultString); + bool same4 = JSTaggedValue::SameValue(defaultString, res.GetValue()); + ASSERT_TRUE(same4); + OperationResult res1 = JSObject::GetProperty(thread_, JSHandle::Cast(sonHandle), property1String); + bool same5 = JSTaggedValue::SameValue(func, res1.GetValue()); + ASSERT_TRUE(same5); + + // new with empty Function Constructor + Local son1 = FunctionRef::New(vm_, FunctionCallback, nullptr); + son1->Inherit(vm_, mapLocal); + JSHandle son1Handle = JSHandle::Cast(JSNApiHelper::ToJSHandle(son1)); + ASSERT_TRUE(son1Handle->HasFunctionPrototype()); +} } // namespace panda::test