From 2e1c797e857993d224ee4f7103629ae7d57dce53 Mon Sep 17 00:00:00 2001 From: yaoyuan Date: Fri, 24 Nov 2023 11:35:15 +0800 Subject: [PATCH] Instanceof Stub FastPath && AOT Instanceof bugfix Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8J4X8 Signed-off-by: yaoyuan Change-Id: I220725e5b71ff6b4c5528b5cc3fcb2177beb58aa --- ecmascript/compiler/stub_builder.cpp | 63 ++++++++++++++++++++--- ecmascript/compiler/stub_builder.h | 1 + ecmascript/compiler/type_hcr_lowering.cpp | 43 ++++++++++++++-- ecmascript/stubs/runtime_stubs.cpp | 8 +++ ecmascript/stubs/runtime_stubs.h | 1 + test/aottest/instanceof/expect_output.txt | 3 ++ test/aottest/instanceof/instanceof.ts | 10 ++++ 7 files changed, 118 insertions(+), 11 deletions(-) diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 0bfe9e9ea5..c554d52de8 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -4408,6 +4408,35 @@ void StubBuilder::FastSetPropertyByIndex(GateRef glue, GateRef obj, GateRef inde env->SubCfgExit(); } +GateRef StubBuilder::GetCtorPrototype(GateRef ctor) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(constructorPrototype, VariableType::JS_ANY(), Undefined()); + Label exit(env); + Label isHClass(env); + Label isPrototype(env); + + GateRef ctorProtoOrHC = Load(VariableType::JS_POINTER(), ctor, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + Branch(IsJSHClass(ctorProtoOrHC), &isHClass, &isPrototype); + Bind(&isHClass); + { + constructorPrototype = Load(VariableType::JS_POINTER(), ctorProtoOrHC, IntPtr(JSHClass::PROTOTYPE_OFFSET)); + Jump(&exit); + } + Bind(&isPrototype); + { + constructorPrototype = ctorProtoOrHC; + Jump(&exit); + } + + Bind(&exit); + auto ret = *constructorPrototype; + env->SubCfgExit(); + return ret; +} + GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj) { auto env = GetEnvironment(); @@ -4457,10 +4486,32 @@ GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef o Bind(&objIsEcmaObject); { // 4. Let P be Get(C, "prototype"). - auto prototypeString = GetGlobalConstantValue( - VariableType::JS_POINTER(), glue, ConstantIndex::PROTOTYPE_STRING_INDEX); + Label getCtorProtoSlowPath(env); + Label ctorIsJSFunction(env); + Label gotCtorPrototype(env); + DEFVARIABLE(constructorPrototype, VariableType::JS_ANY(), Undefined()); + Branch(IsJSFunction(target), &ctorIsJSFunction, &getCtorProtoSlowPath); + Bind(&ctorIsJSFunction); + { + Label getCtorProtoFastPath(env); + GateRef ctorProtoOrHC = Load(VariableType::JS_POINTER(), target, + IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); - GateRef constructorPrototype = FastGetPropertyByName(glue, target, prototypeString, ProfileOperation()); + Branch(TaggedIsHole(ctorProtoOrHC), &getCtorProtoSlowPath, &getCtorProtoFastPath); + Bind(&getCtorProtoFastPath); + { + constructorPrototype = GetCtorPrototype(target); + Jump(&gotCtorPrototype); + } + } + Bind(&getCtorProtoSlowPath); + { + auto prototypeString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, + ConstantIndex::PROTOTYPE_STRING_INDEX); + constructorPrototype = FastGetPropertyByName(glue, target, prototypeString, ProfileOperation()); + Jump(&gotCtorPrototype); + } + Bind(&gotCtorPrototype); // 5. ReturnIfAbrupt(P). // no throw exception, so needn't return @@ -4478,10 +4529,10 @@ GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef o Label constructorPrototypeIsHeapObject(env); Label constructorPrototypeIsEcmaObject(env); Label constructorPrototypeNotEcmaObject(env); - Branch(TaggedIsHeapObject(constructorPrototype), &constructorPrototypeIsHeapObject, + Branch(TaggedIsHeapObject(*constructorPrototype), &constructorPrototypeIsHeapObject, &constructorPrototypeNotEcmaObject); Bind(&constructorPrototypeIsHeapObject); - Branch(TaggedObjectIsEcmaObject(constructorPrototype), &constructorPrototypeIsEcmaObject, + Branch(TaggedObjectIsEcmaObject(*constructorPrototype), &constructorPrototypeIsEcmaObject, &constructorPrototypeNotEcmaObject); Bind(&constructorPrototypeNotEcmaObject); { @@ -4508,7 +4559,7 @@ GateRef StubBuilder::OrdinaryHasInstance(GateRef glue, GateRef target, GateRef o Branch(TaggedIsNull(*object), &afterLoop, &loopHead); LoopBegin(&loopHead); { - GateRef isEqual = SameValue(glue, *object, constructorPrototype); + GateRef isEqual = SameValue(glue, *object, *constructorPrototype); Branch(isEqual, &strictEqual1, ¬StrictEqual1); Bind(&strictEqual1); diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 9fd812e3b2..607fef69e2 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -389,6 +389,7 @@ public: GateRef HclassIsTransitionHandler(GateRef hClass); GateRef HclassIsPropertyBox(GateRef hClass); GateRef PropAttrGetOffset(GateRef attr); + GateRef GetCtorPrototype(GateRef ctor); GateRef InstanceOf(GateRef glue, GateRef object, GateRef target, GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback); GateRef OrdinaryHasInstance(GateRef glue, GateRef target, GateRef obj); diff --git a/ecmascript/compiler/type_hcr_lowering.cpp b/ecmascript/compiler/type_hcr_lowering.cpp index 1c73a99c73..3aa05ec9fd 100644 --- a/ecmascript/compiler/type_hcr_lowering.cpp +++ b/ecmascript/compiler/type_hcr_lowering.cpp @@ -2182,11 +2182,44 @@ void TypeHCRLowering::LowerOrdinaryHasInstance(GateRef gate, GateRef glue) builder_.Bind(&objIsEcmaObject); { // 4. Let P be Get(C, "prototype"). - // target must be a builtin function - GateRef ctorHClass = builder_.LoadConstOffset(VariableType::JS_POINTER(), target, - JSFunction::PROTO_OR_DYNCLASS_OFFSET); - GateRef constructorPrototype = builder_.LoadPrototype(ctorHClass); + Label getCtorProtoSlowPath(&builder_); + Label ctorIsJSFunction(&builder_); + Label gotCtorPrototype(&builder_); + DEFVALUE(constructorPrototype, (&builder_), VariableType::JS_ANY(), builder_.Undefined()); + builder_.Branch(builder_.IsJSFunction(target), &ctorIsJSFunction, &getCtorProtoSlowPath); + builder_.Bind(&ctorIsJSFunction); + { + Label getCtorProtoFastPath(&builder_); + GateRef ctorProtoOrHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), target, + JSFunction::PROTO_OR_DYNCLASS_OFFSET); + builder_.Branch(builder_.TaggedIsHole(ctorProtoOrHC), &getCtorProtoSlowPath, &getCtorProtoFastPath); + builder_.Bind(&getCtorProtoFastPath); + { + Label isHClass(&builder_); + Label isPrototype(&builder_); + builder_.Branch(builder_.IsJSHClass(ctorProtoOrHC), &isHClass, &isPrototype); + builder_.Bind(&isHClass); + { + constructorPrototype = builder_.LoadConstOffset(VariableType::JS_POINTER(), ctorProtoOrHC, + JSHClass::PROTOTYPE_OFFSET); + builder_.Jump(&gotCtorPrototype); + } + builder_.Bind(&isPrototype); + { + constructorPrototype = ctorProtoOrHC; + builder_.Jump(&gotCtorPrototype); + } + } + } + builder_.Bind(&getCtorProtoSlowPath); + { + auto prototypeString = builder_.GetGlobalConstantValue(ConstantIndex::PROTOTYPE_STRING_INDEX); + constructorPrototype = builder_.CallRuntime(glue, RTSTUB_ID(GetPropertyByName), Gate::InvalidGateRef, + { target, prototypeString }, gate); + builder_.Jump(&gotCtorPrototype); + } + builder_.Bind(&gotCtorPrototype); // 7. Repeat // a.Let O be O.[[GetPrototypeOf]](). // b.ReturnIfAbrupt(O). @@ -2203,7 +2236,7 @@ void TypeHCRLowering::LowerOrdinaryHasInstance(GateRef gate, GateRef glue) builder_.Branch(builder_.TaggedIsNull(*object), &afterLoop, &loopHead); builder_.LoopBegin(&loopHead); { - GateRef isEqual = builder_.Equal(*object, constructorPrototype); + GateRef isEqual = builder_.Equal(*object, *constructorPrototype); builder_.Branch(isEqual, &strictEqual1, ¬StrictEqual1); builder_.Bind(&strictEqual1); diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index 38449f0d2d..67e2ed1cb1 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -2251,6 +2251,14 @@ DEF_RUNTIME_STUBS(FastCopyElementToArray) return JSTaggedValue(JSTypedArray::FastCopyElementToArray(thread, typedArray, array)).GetRawData(); } +DEF_RUNTIME_STUBS(GetPropertyByName) +{ + RUNTIME_STUBS_HEADER(GetPropertyByName); + JSHandle target = GetHArg(argv, argc, 0); // 0: means the zeroth parameter + JSHandle key = GetHArg(argv, argc, 1); // 1: means the first parameter + return JSTaggedValue::GetProperty(thread, target, key).GetValue()->GetRawData(); +} + DEF_RUNTIME_STUBS(DebugAOTPrint) { RUNTIME_STUBS_HEADER(DebugAOTPrint); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index 19fdd642d6..9c8204bcec 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -316,6 +316,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(GetTypeArrayPropertyByIndex) \ V(SetTypeArrayPropertyByIndex) \ V(FastCopyElementToArray) \ + V(GetPropertyByName) \ V(JSObjectGetMethod) \ V(DebugAOTPrint) \ V(ProfileOptimizedCode) \ diff --git a/test/aottest/instanceof/expect_output.txt b/test/aottest/instanceof/expect_output.txt index bedb3fa1dd..0bb3008073 100644 --- a/test/aottest/instanceof/expect_output.txt +++ b/test/aottest/instanceof/expect_output.txt @@ -22,6 +22,9 @@ true false true true +false +true +true true true true diff --git a/test/aottest/instanceof/instanceof.ts b/test/aottest/instanceof/instanceof.ts index 7a313e98bc..42e91d58c3 100644 --- a/test/aottest/instanceof/instanceof.ts +++ b/test/aottest/instanceof/instanceof.ts @@ -67,6 +67,16 @@ function test5() { } test5(); +function foo() {}; +function bar() {}; +const proxy = new Proxy(foo, {}); + +let f = new foo(); + +print(f instanceof foo); // true +print(f instanceof proxy); // true +print(f instanceof bar); // false + print(ArkTools.isAOTCompiled(test1)); print(ArkTools.isAOTCompiled(test2)); print(ArkTools.isAOTCompiled(test3));