diff --git a/ecmascript/compiler/fast_stub.cpp b/ecmascript/compiler/fast_stub.cpp index 46ff2415f12acabafa022604086a2fdf7c41d933..9e125fa833ae6be39409247402f3f23ac9edb7c0 100644 --- a/ecmascript/compiler/fast_stub.cpp +++ b/ecmascript/compiler/fast_stub.cpp @@ -1550,4 +1550,87 @@ void SetPropertyByValueStub::GenerateCircuit() Bind(&exit); Return(GetHoleConstant()); } + +void FastEqualStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift x = Int64Argument(0); + AddrShift y = Int64Argument(1); + DEFVARIABLE(doubleX, MachineType::FLOAT64_TYPE, 0); + Label xIsEqualy(env); + Label xIsNotEqualy(env); + Branch(Word64Equal(x, y), &xIsEqualy, &xIsNotEqualy); + Bind(&xIsEqualy); + { + Label xIsDouble(env); + Label xNotDoubleOrxNotNan(env); + Branch(TaggedIsDouble(x), &xIsDouble, &xNotDoubleOrxNotNan); + Bind(&xIsDouble); + { + AddrShift doubleX = TaggedCastToDouble(x); + Label xIsNan(env); + Branch(DoubleIsNAN(doubleX), &xIsNan, &xNotDoubleOrxNotNan); + Bind(&xIsNan); + Return(TaggedFalse()); + } + Bind(&xNotDoubleOrxNotNan); + Return(TaggedTrue()); + } + Bind(&xIsNotEqualy); + { + Label xIsNumber(env); + Label xNotNumberAndxNotIntAndyNotInt(env); + Branch(TaggedIsNumber(x), &xIsNumber, &xNotNumberAndxNotIntAndyNotInt); + Bind(&xIsNumber); + { + Label xIsInt(env); + Branch(TaggedIsInt(x), &xIsInt, &xNotNumberAndxNotIntAndyNotInt); + Bind(&xIsInt); + { + Label yIsInt(env); + Branch(TaggedIsInt(y), &yIsInt, &xNotNumberAndxNotIntAndyNotInt); + Bind(&yIsInt); + Return(TaggedFalse()); + } + } + Bind(&xNotNumberAndxNotIntAndyNotInt); + { + Label yIsUndefinedOrNull(env); + Label xyNotUndefinedAndNull(env); + Branch(TaggedIsUndefinedOrNull(y), &yIsUndefinedOrNull, &xyNotUndefinedAndNull); + Bind(&yIsUndefinedOrNull); + { + Label xIsHeapObject(env); + Label xNotHeapObject(env); + Branch(TaggedIsHeapObject(x), &xIsHeapObject, &xNotHeapObject); + Bind(&xIsHeapObject); + Return(TaggedFalse()); + Bind(&xNotHeapObject); + { + Label xIsUndefinedOrNull(env); + Branch(TaggedIsUndefinedOrNull(x), &xIsUndefinedOrNull, &xyNotUndefinedAndNull); + Bind(&xIsUndefinedOrNull); + Return(TaggedTrue()); + } + } + Bind(&xyNotUndefinedAndNull); + { + Label xIsBoolean(env); + Label xNotBooleanAndyNotSpecial(env); + Branch(TaggedIsBoolean(x), &xIsBoolean, &xNotBooleanAndyNotSpecial); + Bind(&xIsBoolean); + { + Label yIsSpecial(env); + Branch(TaggedIsSpecial(y), &yIsSpecial, &xNotBooleanAndyNotSpecial); + Bind(&yIsSpecial); + Return(TaggedFalse()); + } + Bind(&xNotBooleanAndyNotSpecial); + { + Return(GetHoleConstant()); + } + } + } + } +} } // namespace kungfu diff --git a/ecmascript/compiler/fast_stub.h b/ecmascript/compiler/fast_stub.h index 0b37583f12ceac42cbe19bd93b29cf1ff8802dfe..23f2de65f3a21bd69f8e65ffbfa2cb85f04ebcdb 100644 --- a/ecmascript/compiler/fast_stub.h +++ b/ecmascript/compiler/fast_stub.h @@ -220,6 +220,16 @@ public: NO_COPY_SEMANTIC(SetPropertyByValueStub); void GenerateCircuit() override; }; + +class FastEqualStub : public Stub { +public: + // 2 means argument counts + explicit FastEqualStub(Circuit *circuit) : Stub("FastEqual", 2, circuit) {} + ~FastEqualStub() = default; + NO_MOVE_SEMANTIC(FastEqualStub); + NO_COPY_SEMANTIC(FastEqualStub); + void GenerateCircuit() override; +}; } // namespace kungfu #endif // ECMASCRIPT_COMPILER_FASTPATH_STUB_H diff --git a/ecmascript/compiler/stub.h b/ecmascript/compiler/stub.h index 3116a7edfa7433387e2522fcccc46c5e462cc7bf..6bce838ef160cd62dde1860afc8183220a9e0774 100644 --- a/ecmascript/compiler/stub.h +++ b/ecmascript/compiler/stub.h @@ -851,6 +851,31 @@ public: Word32Equal(SExtInt1ToInt32(diff2), GetInt32Constant(1)))); } + AddrShift TaggedIsNull(AddrShift x) + { + return Word64Equal(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_NULL)); + } + + AddrShift TaggedIsUndefinedOrNull(AddrShift x) + { + return TruncInt32ToInt1(Word32Or(SExtInt1ToInt32(TaggedIsUndefined(x)), SExtInt1ToInt32(TaggedIsNull(x)))); + } + + AddrShift TaggedIsTrue(AddrShift x) + { + return Word64Equal(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_TRUE)); + } + + AddrShift TaggedIsFalse(AddrShift x) + { + return Word64Equal(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_FALSE)); + } + + AddrShift TaggedIsBoolean(AddrShift x) + { + return TruncInt32ToInt1(Word32Or(SExtInt1ToInt32(TaggedIsTrue(x)), SExtInt1ToInt32(TaggedIsFalse(x)))); + } + AddrShift IntBuildTagged(AddrShift x) { AddrShift val = ZExtInt32ToInt64(x); @@ -873,6 +898,16 @@ public: return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::BITCAST_FLOAT64_TO_INT64), x); } + AddrShift TaggedTrue() + { + return GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_TRUE); + } + + AddrShift TaggedFalse() + { + return GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_FALSE); + } + // compare operation AddrShift Word32Equal(AddrShift x, AddrShift y) { diff --git a/ecmascript/compiler/stub_aot_compiler.cpp b/ecmascript/compiler/stub_aot_compiler.cpp index d6b30c872e5ba871e470442145a927c24757d163..7403ee7d6e17bb24d763d17953a4d0612cc72e63 100644 --- a/ecmascript/compiler/stub_aot_compiler.cpp +++ b/ecmascript/compiler/stub_aot_compiler.cpp @@ -152,6 +152,7 @@ void StubAotCompiler::BuildStubModuleAndSave(const char *triple, panda::ecmascri SET_STUB_TO_MODULE(module, FastDiv) \ SET_STUB_TO_MODULE(module, FastMod) \ SET_STUB_TO_MODULE(module, FastTypeOf) \ + SET_STUB_TO_MODULE(module, FastEqual) \ SET_STUB_TO_MODULE(module, FindOwnElement) \ SET_STUB_TO_MODULE(module, GetElement) \ SET_STUB_TO_MODULE(module, FindOwnElement2) \ diff --git a/ecmascript/compiler/stub_descriptor.cpp b/ecmascript/compiler/stub_descriptor.cpp index 90b0a399da0b7070ad0c4763326705d0f5fd4c50..11e1768bb4976154b76317e6986d4321b92a8e1a 100644 --- a/ecmascript/compiler/stub_descriptor.cpp +++ b/ecmascript/compiler/stub_descriptor.cpp @@ -124,8 +124,6 @@ CALL_STUB_INIT_DESCRIPTOR(FloatMod) descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); } -CALL_STUB_INIT_DESCRIPTOR(FastEqual) {} - CALL_STUB_INIT_DESCRIPTOR(FastTypeOf) { // 2 input parameters @@ -139,6 +137,19 @@ CALL_STUB_INIT_DESCRIPTOR(FastTypeOf) descriptor->SetParameters(params.data()); } +CALL_STUB_INIT_DESCRIPTOR(FastEqual) +{ + // 2 input parameters + StubDescriptor fastEqual("FastEqual", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = fastEqual; + // 2 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} + CALL_STUB_INIT_DESCRIPTOR(FastStrictEqual) {} CALL_STUB_INIT_DESCRIPTOR(IsSpecialIndexedObjForSet) {} diff --git a/ecmascript/compiler/tests/stub_tests.cpp b/ecmascript/compiler/tests/stub_tests.cpp index 8e656928f1a2c6bda14e7fc3d47f778c02a4bdf7..0ad470c698a00c55b81a93399f3ef0986c44f175 100644 --- a/ecmascript/compiler/tests/stub_tests.cpp +++ b/ecmascript/compiler/tests/stub_tests.cpp @@ -1354,4 +1354,73 @@ HWTEST_F_L0(StubTest, FastTypeOfTest) EXPECT_EQ(resultVal9, globalConst->GetObjectString()); EXPECT_EQ(resultVal9, expectResult9); } + +HWTEST_F_L0(StubTest, FastEqualTest) +{ + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastEqual)); + Circuit netOfGates; + FastEqualStub optimizer(&netOfGates); + optimizer.GenerateCircuit(); + netOfGates.PrintAllGates(); + auto cfg = Scheduler::Run(&netOfGates); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); + llvmBuilder.Build(); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); + assembler.Run(); + LLVMDumpModule(module); + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); + // test for 1 == 1 + auto resA = fn(JSTaggedValue(1).GetRawData(), JSTaggedValue(1).GetRawData()); + auto expectA = FastRuntimeStub::FastEqual(JSTaggedValue(1), JSTaggedValue(1)); + EXPECT_EQ(resA, expectA); + + // test for nan == nan + double nan = std::numeric_limits::quiet_NaN(); + auto resB = fn(JSTaggedValue(nan).GetRawData(), JSTaggedValue(nan).GetRawData()); + auto expectB = FastRuntimeStub::FastEqual(JSTaggedValue(nan), JSTaggedValue(nan)); + EXPECT_EQ(resB, expectB); + + // test for undefined == null + auto resC = fn(JSTaggedValue::Undefined().GetRawData(), JSTaggedValue::Null().GetRawData()); + auto expectC = FastRuntimeStub::FastEqual(JSTaggedValue::Undefined(), JSTaggedValue::Null()); + EXPECT_EQ(resC, expectC); + + // test for "hello world" == undefined + auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); + auto str = factory->NewFromStdString("hello world"); + auto resD = fn(str.GetTaggedValue().GetRawData(), JSTaggedValue::Undefined().GetRawData()); + auto expectD = FastRuntimeStub::FastEqual(str.GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(resD, expectD); + + // test for true == hole + auto resE = fn(JSTaggedValue::True().GetRawData(), JSTaggedValue::Hole().GetRawData()); + auto expectE = FastRuntimeStub::FastEqual(JSTaggedValue::True(), JSTaggedValue::Hole()); + EXPECT_EQ(resE, expectE); + + // test for "hello world" == "hello world" + auto resF = fn(str.GetTaggedValue().GetRawData(), str.GetTaggedValue().GetRawData()); + auto expectF = FastRuntimeStub::FastEqual(str.GetTaggedValue(), str.GetTaggedValue()); + EXPECT_EQ(resF, expectF); + + // test for 5.2 == 5.2 + auto resG = fn(JSTaggedValue(5.2).GetRawData(), JSTaggedValue(5.2).GetRawData()); + auto expectG = FastRuntimeStub::FastEqual(JSTaggedValue(5.2), JSTaggedValue(5.2)); + EXPECT_EQ(resG, expectG); + + // test for false == false + auto resH = fn(JSTaggedValue::False().GetRawData(), JSTaggedValue::False().GetRawData()); + auto expectH = FastRuntimeStub::FastEqual(JSTaggedValue::False(), JSTaggedValue::False()); + EXPECT_EQ(resH, expectH); + + // test for obj == obj + JSHandle obj1 = factory->NewEmptyJSObject(); + JSHandle obj2 = factory->NewEmptyJSObject(); + FastRuntimeStub::SetOwnElement(thread, obj1.GetTaggedValue(), 1, JSTaggedValue(1)); + FastRuntimeStub::SetOwnElement(thread, obj2.GetTaggedValue(), 1, JSTaggedValue(1)); + auto resI = fn(obj1.GetTaggedValue().GetRawData(), obj2.GetTaggedValue().GetRawData()); + auto expectI = FastRuntimeStub::FastEqual(obj1.GetTaggedValue(), obj2.GetTaggedValue()); + EXPECT_EQ(resI, expectI); +} } // namespace panda::test diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index 41555801d7fcb8b5ee303d8284d934d4f06c2239..a92d165ddb44d94d03dc0f38d43b801a0863e00f 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -1138,7 +1138,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool } HANDLE_OPCODE(HANDLE_TYPEOFDYN_PREF) { LOG_INST() << "intrinsics::typeofdyn"; +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(FastTypeOf)); + typedef JSTaggedValue (*PFFastTypeOf)(JSThread *, JSTaggedValue); + auto fastTypeOfPtr = reinterpret_cast(stubAddr); + JSTaggedValue res = fastTypeOfPtr(thread, GET_ACC()); +#else JSTaggedValue res = FastRuntimeStub::FastTypeOf(thread, GET_ACC()); +#endif SET_ACC(res); DISPATCH(BytecodeInstruction::Format::PREF_NONE); } @@ -1331,8 +1338,15 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool << " v" << vs; JSTaggedValue left = GET_VREG_VALUE(vs); JSTaggedValue right = GET_ACC(); - // fast path + +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(FastMod)); + typedef JSTaggedValue (*PFFastMod)(JSTaggedValue, JSTaggedValue); + auto fastModPtr = reinterpret_cast(stubAddr); + JSTaggedValue res = fastModPtr(left, right); +#else JSTaggedValue res = FastRuntimeStub::FastMod(left, right); +#endif if (!res.IsHole()) { SET_ACC(res); } else { @@ -1350,7 +1364,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool << " v" << v0; JSTaggedValue left = GET_VREG_VALUE(v0); JSTaggedValue right = acc; +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(FastEqual)); + typedef JSTaggedValue (*PFFastEqual)(JSTaggedValue, JSTaggedValue); + auto fastEqualPtr = reinterpret_cast(stubAddr); + JSTaggedValue res = fastEqualPtr(left, right); +#else JSTaggedValue res = FastRuntimeStub::FastEqual(left, right); +#endif if (!res.IsHole()) { SET_ACC(res); } else {