diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index 0fcc17683ab076fd3de0ade1fdad8dcc9f3c2fad..541311d2f5bc45ce4eec78e72bc84ddca284b799 100644 --- a/ecmascript/compiler/circuit_builder.cpp +++ b/ecmascript/compiler/circuit_builder.cpp @@ -365,7 +365,7 @@ AddrShift CircuitBuilder::NewCallGate(StubDescriptor *descriptor, AddrShift targ AddrShift CircuitBuilder::NewCallRuntimeGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, std::initializer_list args) { - ASSERT(descriptor->GetStubKind() == StubDescriptor::RUNTIME_STUB); + ASSERT(descriptor->GetStubKind() == StubDescriptor::CallStubKind::RUNTIME_STUB); std::vector inputs; auto dependEntry = Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY)); inputs.push_back(dependEntry); @@ -382,7 +382,7 @@ AddrShift CircuitBuilder::NewCallRuntimeGate(StubDescriptor *descriptor, AddrShi AddrShift CircuitBuilder::NewCallRuntimeGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, AddrShift depend, std::initializer_list args) { - ASSERT(descriptor->GetStubKind() == StubDescriptor::RUNTIME_STUB); + ASSERT(descriptor->GetStubKind() == StubDescriptor::CallStubKind::RUNTIME_STUB); std::vector inputs; inputs.push_back(depend); inputs.push_back(target); diff --git a/ecmascript/compiler/compile_llvm_lib.sh b/ecmascript/compiler/compile_llvm_lib.sh index 58c117ed66e0976cb4030519ac5fe03035dd3bf9..bc0d5735224912247671fd2a16ff97a8dca8caf8 100755 --- a/ecmascript/compiler/compile_llvm_lib.sh +++ b/ecmascript/compiler/compile_llvm_lib.sh @@ -32,13 +32,13 @@ fi cd ${BASE_HOME}/third_party/llvm-project if [ ! -d "build" ];then mkdir build && cd build - cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llvm + cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_TERMINFO=OFF ../llvm ninja else cd build if [ ! -d "lib" ]; then rm -rf * - cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llvm + cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_TERMINFO=OFF ../llvm ninja fi fi diff --git a/ecmascript/compiler/fast_stub.cpp b/ecmascript/compiler/fast_stub.cpp index ac005e5b53c0a9d3b7c40941583eae2ff1687815..fa3eb7139f1816de29ed7b921bc147289aae9261 100644 --- a/ecmascript/compiler/fast_stub.cpp +++ b/ecmascript/compiler/fast_stub.cpp @@ -1158,4 +1158,159 @@ void FastModStub::GenerateCircuit() } } } + +void FastGetPropertyByValueStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift thread = PtrArgument(0); + AddrShift receiver = PtrArgument(1); + DEFVARIABLE(key, TAGGED_TYPE, PtrArgument(2)); /* 2 : 3rd parameter is key */ + + Label isNumberOrStringSymbol(env); + Label notNumber(env); + Label isStringOrSymbol(env); + Label notStringOrSymbol(env); + Label exit(env); + + Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, ¬Number); + Bind(¬Number); + { + Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, ¬StringOrSymbol); + Bind(¬StringOrSymbol); + { + Return(GetHoleConstant()); + } + } + Bind(&isNumberOrStringSymbol); + { + AddrShift index = TryToElementsIndex(*key); + Label validIndex(env); + Label notValidIndex(env); + Branch(Int32GreaterThanOrEqual(index, GetInteger32Constant(0)), &validIndex, ¬ValidIndex); + Bind(&validIndex); + { + auto getPropertyByIndex = GET_STUBDESCRIPTOR(GetPropertyByIndex); + Return(CallStub(getPropertyByIndex, GetWord64Constant(FAST_STUB_ID(GetPropertyByIndex)), + {thread, receiver, index})); + } + Bind(¬ValidIndex); + { + Label notNumber(env); + Label getByName(env); + Branch(TaggedIsNumber(*key), &exit, ¬Number); + Bind(¬Number); + { + Label isString(env); + Label notString(env); + Label isInternalString(env); + Label notIntenalString(env); + Branch(TaggedIsString(*key), &isString, ¬String); + Bind(&isString); + { + Branch(IsInternalString(*key), &isInternalString, ¬IntenalString); + Bind(&isInternalString); + Jump(&getByName); + Bind(¬IntenalString); + { + StubDescriptor *newInternalString = GET_STUBDESCRIPTOR(NewInternalString); + key = CallRuntime(newInternalString, thread, + GetWord64Constant(FAST_STUB_ID(NewInternalString)), + {thread, *key}); + Jump(&getByName); + } + } + Bind(¬String); + { + Jump(&getByName); + } + } + Bind(&getByName); + { + auto getPropertyByName = GET_STUBDESCRIPTOR(GetPropertyByName); + Return(CallStub(getPropertyByName, GetWord64Constant(FAST_STUB_ID(GetPropertyByName)), + {thread, receiver, *key})); + } + } + } + Bind(&exit); + Return(GetHoleConstant()); +} + +void FastSetPropertyByValueStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift thread = PtrArgument(0); + AddrShift receiver = PtrArgument(1); + DEFVARIABLE(key, TAGGED_TYPE, PtrArgument(2)); /* 2 : 3rd parameter is key */ + AddrShift value = Int64Argument(3); /* 3 : 4th parameter is value */ + + Label isNumberOrStringSymbol(env); + Label notNumber(env); + Label isStringOrSymbol(env); + Label notStringOrSymbol(env); + Label exit(env); + + Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, ¬Number); + Bind(¬Number); + { + Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, ¬StringOrSymbol); + Bind(¬StringOrSymbol); + { + Return(GetHoleConstant()); + } + } + Bind(&isNumberOrStringSymbol); + { + AddrShift index = TryToElementsIndex(*key); + Label validIndex(env); + Label notValidIndex(env); + Branch(Int32GreaterThanOrEqual(index, GetInteger32Constant(0)), &validIndex, ¬ValidIndex); + Bind(&validIndex); + { + auto setPropertyByIndex = GET_STUBDESCRIPTOR(SetPropertyByIndex); + Return(CallStub(setPropertyByIndex, GetWord64Constant(FAST_STUB_ID(SetPropertyByIndex)), + {thread, receiver, index, value})); + } + Bind(¬ValidIndex); + { + Label notNumber(env); + Label getByName(env); + Branch(TaggedIsNumber(*key), &exit, ¬Number); + Bind(¬Number); + { + Label isString(env); + Label notString(env); + Label isInternalString(env); + Label notIntenalString(env); + Branch(TaggedIsString(*key), &isString, ¬String); + Bind(&isString); + { + Branch(IsInternalString(*key), &isInternalString, ¬IntenalString); + Bind(&isInternalString); + Jump(&getByName); + Bind(¬IntenalString); + { + StubDescriptor *newInternalString = GET_STUBDESCRIPTOR(NewInternalString); + key = CallRuntime(newInternalString, thread, + GetWord64Constant(FAST_STUB_ID(NewInternalString)), + {thread, *key}); + Jump(&getByName); + } + } + Bind(¬String); + { + Jump(&getByName); + } + } + Bind(&getByName); + { + auto setPropertyByName = GET_STUBDESCRIPTOR(SetPropertyByName); + Return(CallStub(setPropertyByName, GetWord64Constant(FAST_STUB_ID(SetPropertyByName)), + {thread, receiver, *key, value})); + } + } + } + Bind(&exit); + Return(GetHoleConstant()); +} } // namespace kungfu \ No newline at end of file diff --git a/ecmascript/compiler/fast_stub.h b/ecmascript/compiler/fast_stub.h index 6814fa37c7eb71f9d6dd577b292a622817038769..004a6279688d684610557a74e1791907dee51d02 100644 --- a/ecmascript/compiler/fast_stub.h +++ b/ecmascript/compiler/fast_stub.h @@ -149,5 +149,25 @@ public: NO_COPY_SEMANTIC(FastModStub); void GenerateCircuit() override; }; + +class FastGetPropertyByValueStub : public Stub { +public: + // 3 : 3 means argument counts + explicit FastGetPropertyByValueStub(Circuit *circuit) : Stub("FastGetPropertyByValue", 3, circuit) {} + ~FastGetPropertyByValueStub() = default; + NO_MOVE_SEMANTIC(FastGetPropertyByValueStub); + NO_COPY_SEMANTIC(FastGetPropertyByValueStub); + void GenerateCircuit() override; +}; + +class FastSetPropertyByValueStub : public Stub { +public: + // 4 : 4 means argument counts + explicit FastSetPropertyByValueStub(Circuit *circuit) : Stub("FastSetPropertyByValue", 4, circuit) {} + ~FastSetPropertyByValueStub() = default; + NO_MOVE_SEMANTIC(FastSetPropertyByValueStub); + NO_COPY_SEMANTIC(FastSetPropertyByValueStub); + void GenerateCircuit() override; +}; } // namespace kungfu #endif // ECMASCRIPT_COMPILER_FASTPATH_STUB_H \ No newline at end of file diff --git a/ecmascript/compiler/fast_stub_define.h b/ecmascript/compiler/fast_stub_define.h index ccf3bf3c3140ef41882c7dfac82dce6aea719be5..7c5151394ab660831778ee8419378745073905e2 100644 --- a/ecmascript/compiler/fast_stub_define.h +++ b/ecmascript/compiler/fast_stub_define.h @@ -27,7 +27,8 @@ namespace kungfu { V(JSProxySetProperty, 6) \ V(GetHash32, 2) \ V(FindElementWithCache, 4) \ - V(StringGetHashCode, 1) + V(StringGetHashCode, 1) \ + V(NewInternalString, 2) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define FAST_RUNTIME_STUB_LIST(V) \ @@ -57,7 +58,9 @@ namespace kungfu { V(FindOwnProperty2, 6) \ V(FindOwnElement2, 6) \ V(GetPropertyByIndex, 3) \ - V(SetPropertyByIndex, 4) + V(SetPropertyByIndex, 4) \ + V(GetPropertyByValue, 3) \ + V(SetPropertyByValue, 4) #define CALL_STUB_LIST(V) \ FAST_RUNTIME_STUB_LIST(V) \ diff --git a/ecmascript/compiler/gate.cpp b/ecmascript/compiler/gate.cpp index f2e09834fd7cd10388850bd7a88853a39aa1ec4e..bcecfaddb57966748701100f2895287576e304b3 100644 --- a/ecmascript/compiler/gate.cpp +++ b/ecmascript/compiler/gate.cpp @@ -185,12 +185,20 @@ Properties OpCode::GetProperties() const return {INT64, NO_STATE, NO_DEPEND, VALUE(INT32), NO_ROOT}; case ZEXT_INT1_TO_INT32: return {INT32, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; + case ZEXT_INT8_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT8), NO_ROOT}; + case ZEXT_INT16_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT16), NO_ROOT}; case ZEXT_INT1_TO_INT64: return {INT64, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; case SEXT_INT32_TO_INT64: return {INT64, NO_STATE, NO_DEPEND, VALUE(INT32), NO_ROOT}; case SEXT_INT1_TO_INT32: return {INT32, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; + case SEXT_INT8_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT8), NO_ROOT}; + case SEXT_INT16_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT8), NO_ROOT}; case SEXT_INT1_TO_INT64: return {INT64, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; case TRUNC_INT64_TO_INT32: @@ -400,9 +408,13 @@ std::string OpCode::Str() const {FLOAT64_CONSTANT, "FLOAT64_CONSTANT"}, {ZEXT_INT32_TO_INT64, "ZEXT_INT32_TO_INT64"}, {ZEXT_INT1_TO_INT32, "ZEXT_INT1_TO_INT32"}, + {ZEXT_INT8_TO_INT32, "ZEXT_INT8_TO_INT32"}, + {ZEXT_INT16_TO_INT32, "ZEXT_INT16_TO_INT32"}, {ZEXT_INT1_TO_INT64, "ZEXT_INT1_TO_INT64"}, {SEXT_INT32_TO_INT64, "SEXT_INT32_TO_INT64"}, {SEXT_INT1_TO_INT32, "SEXT_INT1_TO_INT32"}, + {SEXT_INT8_TO_INT32, "SEXT_INT8_TO_INT32"}, + {SEXT_INT16_TO_INT32, "SEXT_INT16_TO_INT32"}, {SEXT_INT1_TO_INT64, "SEXT_INT1_TO_INT64"}, {TRUNC_INT64_TO_INT32, "TRUNC_INT64_TO_INT32"}, {TRUNC_INT64_TO_INT1, "TRUNC_INT64_TO_INT1"}, @@ -1305,4 +1317,9 @@ bool OpCode::IsLoopHead() const { return (this->op == OpCode::LOOP_BEGIN); } + +bool OpCode::IsNop() const +{ + return (this->op == OpCode::NOP); +} } // namespace kungfu \ No newline at end of file diff --git a/ecmascript/compiler/gate.h b/ecmascript/compiler/gate.h index a112479593b8bf378cf7639eb60a96ab746a5cd9..fbc99b70948c20b07670704494e22ce26e5ab569 100644 --- a/ecmascript/compiler/gate.h +++ b/ecmascript/compiler/gate.h @@ -147,9 +147,13 @@ public: FLOAT64_CONSTANT, ZEXT_INT32_TO_INT64, ZEXT_INT1_TO_INT32, + ZEXT_INT8_TO_INT32, + ZEXT_INT16_TO_INT32, ZEXT_INT1_TO_INT64, SEXT_INT32_TO_INT64, SEXT_INT1_TO_INT32, + SEXT_INT8_TO_INT32, + SEXT_INT16_TO_INT32, SEXT_INT1_TO_INT64, TRUNC_INT64_TO_INT32, TRUNC_INT64_TO_INT1, @@ -253,6 +257,7 @@ public: [[nodiscard]] bool IsCFGMerge() const; [[nodiscard]] bool IsControlCase() const; [[nodiscard]] bool IsLoopHead() const; + [[nodiscard]] bool IsNop() const; ~OpCode() = default; private: diff --git a/ecmascript/compiler/llvm_ir_builder.cpp b/ecmascript/compiler/llvm_ir_builder.cpp index 388aed1e90bc7dc1f42f16bcf19e5c5b46ed1fb0..262972b25d0db65fb417d4461317590caba2b2cd 100644 --- a/ecmascript/compiler/llvm_ir_builder.cpp +++ b/ecmascript/compiler/llvm_ir_builder.cpp @@ -235,7 +235,9 @@ void LLVMIRBuilder::Build() VisitFloat64Constant(gate, doubleValue); break; } - case OpCode::ZEXT_INT1_TO_INT32: { + case OpCode::ZEXT_INT1_TO_INT32: // no break, fall through + case OpCode::ZEXT_INT8_TO_INT32: + case OpCode::ZEXT_INT16_TO_INT32: { VisitZExtInt(gate, ins[0], MachineRep::K_WORD32); break; } @@ -364,6 +366,16 @@ void LLVMIRBuilder::Build() VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntNE); break; } + case OpCode::INT8_LOAD: { + AddrShift base = ins[1]; + VisitLoad(gate, MachineRep::K_WORD8, base); + break; + } + case OpCode::INT16_LOAD: { + AddrShift base = ins[1]; + VisitLoad(gate, MachineRep::K_WORD16, base); + break; + } case OpCode::INT32_LOAD: { AddrShift base = ins[1]; VisitLoad(gate, MachineRep::K_WORD32, base); @@ -572,6 +584,9 @@ LLVMTypeRef LLVMIRBuilder::GetMachineRepType(MachineRep rep) const case MachineRep::K_WORD8: dstType = LLVMInt8TypeInContext(context_); break; + case MachineRep::K_WORD16: + dstType = LLVMInt16TypeInContext(context_); + break; case MachineRep::K_WORD32: dstType = LLVMInt32TypeInContext(context_); break; diff --git a/ecmascript/compiler/stub.cpp b/ecmascript/compiler/stub.cpp index 4f9a0eeb822ae9ebd1864f0031869ce3e2a43b5b..765cced15d09c44f94907a137d78312ee4a1787f 100644 --- a/ecmascript/compiler/stub.cpp +++ b/ecmascript/compiler/stub.cpp @@ -34,10 +34,11 @@ AddrShift Stub::Variable::AddPhiOperand(AddrShift val) Label label = env_->GetLabelFromSelector(val); size_t idx = 0; for (auto pred : label.GetPredecessors()) { + auto preVal = pred.ReadVariable(this); + ASSERT(!env_->GetCircuit()->GetOpCode(preVal).IsNop()); idx++; - val = AddOperandToSelector(val, idx, pred.ReadVariable(this)); + val = AddOperandToSelector(val, idx, preVal); } - return TryRemoveTrivialPhi(val); } @@ -66,6 +67,7 @@ AddrShift Stub::Variable::TryRemoveTrivialPhi(AddrShift phiVal) // the phi is unreachable or in the start block same = env_->GetCircuit()->LoadGatePtr(env_->GetCircuitBuilder().UndefineConstant()); } + auto same_addr_shift = env_->GetCircuit()->SaveGatePtr(same); // remove the trivial phi // get all users of phi except self @@ -92,10 +94,15 @@ AddrShift Stub::Variable::TryRemoveTrivialPhi(AddrShift phiVal) for (auto out : outs) { if (IsSelector(out->GetGate())) { auto out_addr_shift = env_->GetCircuit()->SaveGatePtr(out->GetGate()); - TryRemoveTrivialPhi(out_addr_shift); + auto result = TryRemoveTrivialPhi(out_addr_shift); + if (same_addr_shift == out_addr_shift) + { + same_addr_shift = result; + } + } } - return env_->GetCircuit()->SaveGatePtr(same); + return same_addr_shift; } void Stub::Variable::RerouteOuts(const std::vector &outs, Gate *newGate) @@ -123,7 +130,10 @@ void LabelImpl::WriteVariable(Variable *var, AddrShift value) AddrShift LabelImpl::ReadVariable(Variable *var) { if (valueMap_.find(var) != valueMap_.end()) { - return valueMap_.at(var); + auto result = valueMap_.at(var); + if (!env_->GetCircuit()->GetOpCode(result).IsNop()) { + return result; + } } return ReadVariableRecursive(var); } @@ -778,4 +788,248 @@ void Stub::UpdateAndStoreRepresention(AddrShift hclass, AddrShift value) AddrShift newRep = UpdateRepresention(GetElementRepresentation(hclass), value); SetElementRepresentation(hclass, newRep); } + +AddrShift Stub::TaggedIsString(AddrShift obj) +{ + auto env = GetEnvironment(); + Label entry(env); + [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + Label exit(env); + DEFVARIABLE(result, BOOL_TYPE, FalseConstant()); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); + Bind(&isHeapObject); + { + result = Word32Equal(GetObjectType(LoadHClass(obj)), + GetInteger32Constant(static_cast(panda::ecmascript::JSType::STRING))); + Jump(&exit); + } + Bind(&exit); + return *result; +} + +AddrShift Stub::TaggedIsStringOrSymbol(AddrShift obj) +{ + auto env = GetEnvironment(); + Label entry(env); + [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + Label exit(env); + DEFVARIABLE(result, BOOL_TYPE, FalseConstant()); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); + Bind(&isHeapObject); + { + AddrShift objType = GetObjectType(LoadHClass(obj)); + result = Word32Equal(objType, + GetInteger32Constant(static_cast(panda::ecmascript::JSType::STRING))); + Label isString(env); + Label notString(env); + Branch(*result, &exit, ¬String); + Bind(¬String); + { + result = Word32Equal(objType, + GetInteger32Constant(static_cast(panda::ecmascript::JSType::SYMBOL))); + Jump(&exit); + } + } + Bind(&exit); + return *result; +} + +AddrShift Stub::IsUtf16String(AddrShift string) +{ + // compressedStringsEnabled fixed to true constant + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + return Word32Equal( + Word32And(len, GetInteger32Constant(panda::ecmascript::EcmaString::STRING_COMPRESSED_BIT)), + GetInteger32Constant(panda::ecmascript::EcmaString::STRING_UNCOMPRESSED)); +} + +AddrShift Stub::IsUtf8String(AddrShift string) +{ + // compressedStringsEnabled fixed to true constant + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + return Word32Equal( + Word32And(len, GetInteger32Constant(panda::ecmascript::EcmaString::STRING_COMPRESSED_BIT)), + GetInteger32Constant(panda::ecmascript::EcmaString::STRING_COMPRESSED)); +} + +AddrShift Stub::IsInternalString(AddrShift string) +{ + // compressedStringsEnabled fixed to true constant + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + return Word32NotEqual( + Word32And(len, GetInteger32Constant(panda::ecmascript::EcmaString::STRING_INTERN_BIT)), + GetInteger32Constant(0)); +} + +AddrShift Stub::IsDigit(AddrShift ch) +{ + return TruncInt32ToInt1( + Word32And(SExtInt1ToInt32(Int32LessThanOrEqual(ch, GetInteger32Constant('9'))), + SExtInt1ToInt32(Int32GreaterThanOrEqual(ch, GetInteger32Constant('0'))))); +} + +AddrShift Stub::StringToElementIndex(AddrShift string) +{ + auto env = GetEnvironment(); + Label entry(env); + [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + Label exit(env); + DEFVARIABLE(result, INT32_TYPE, GetInteger32Constant(-1)); + Label greatThanZero(env); + Label inRange(env); + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + len = Word32LSR(len, GetInteger32Constant(2)); + Branch(Word32Equal(len, GetInteger32Constant(0)), &exit, &greatThanZero); + Bind(&greatThanZero); + Branch(Int32GreaterThan(len, GetInteger32Constant(panda::ecmascript::MAX_INDEX_LEN)), &exit, &inRange); + Bind(&inRange); + { + AddrShift dataUtf16 = PtrAdd(string, GetPtrConstant(panda::ecmascript::EcmaString::GetDataOffset())); + DEFVARIABLE(c, UINT32_TYPE, GetInteger32Constant(0)); + Label isUtf16(env); + Label isUtf8(env); + Label getChar1(env); + AddrShift isUtf16String = IsUtf16String(string); + Branch(isUtf16String, &isUtf16, &isUtf8); + Bind(&isUtf16); + { + c = ZExtInt16ToInt32(Load(INT16_TYPE, dataUtf16)); + Jump(&getChar1); + } + Bind(&isUtf8); + { + c = ZExtInt8ToInt32(Load(INT8_TYPE, dataUtf16)); + Jump(&getChar1); + } + Bind(&getChar1); + { + Label isDigitZero(env); + Label notDigitZero(env); + Branch(Word32Equal(*c, GetInteger32Constant('0')), &isDigitZero, ¬DigitZero); + Bind(&isDigitZero); + { + Label lengthIsOne(env); + Branch(Word32Equal(len, GetInteger32Constant(1)), &lengthIsOne, &exit); + Bind(&lengthIsOne); + { + result = GetInteger32Constant(0); + Jump(&exit); + } + } + Bind(¬DigitZero); + { + Label isDigit(env); + DEFVARIABLE(i, UINT32_TYPE, GetInteger32Constant(1)); + DEFVARIABLE(n, UINT32_TYPE, Int32Sub(*c, GetInteger32Constant('0'))); + Branch(IsDigit(*c), &isDigit, &exit); + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Bind(&isDigit); + Branch(Int32LessThan(*i, len), &loopHead, &exit); + LoopBegin(&loopHead); + { + Label isUtf16(env); + Label notUtf16(env); + Label getChar2(env); + Branch(isUtf16String, &isUtf16, ¬Utf16); + Bind(&isUtf16); + { + c = ZExtInt16ToInt32(Load(INT16_TYPE, dataUtf16, PtrMul(*i, GetPtrConstant(2)))); + Jump(&getChar2); + } + Bind(¬Utf16); + { + c = ZExtInt8ToInt32(Load(INT8_TYPE, dataUtf16, *i)); + Jump(&getChar2); + } + Bind(&getChar2); + { + Label isDigit2(env); + Label notDigit2(env); + Branch(IsDigit(*c), &isDigit2, ¬Digit2); + Bind(&isDigit2); + { + n = Int32Add(Int32Mul(*n, GetInteger32Constant(10)), + Int32Sub(*c, GetInteger32Constant('0'))); + i = Int32Add(*i, GetInteger32Constant(1)); + Branch(Int32LessThan(*i, len), &loopEnd, &afterLoop); + } + Bind(¬Digit2); + Jump(&exit); + } + } + Bind(&loopEnd); + LoopEnd(&loopHead); + Bind(&afterLoop); + { + Label lessThanMaxIndex(env); + Branch(Word32LessThan(*n, GetInteger32Constant(panda::ecmascript::JSObject::MAX_ELEMENT_INDEX)), + &lessThanMaxIndex, &exit); + Bind(&lessThanMaxIndex); + { + result = *n; + Jump(&exit); + } + } + } + } + } + Bind(&exit); + return *result; +} + +AddrShift Stub::TryToElementsIndex(AddrShift key) +{ + auto env = GetEnvironment(); + Label entry(env); + [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + Label exit(env); + Label isKeyInt(env); + Label notKeyInt(env); + + DEFVARIABLE(resultKey, INT32_TYPE, GetInteger32Constant(0)); + Branch(TaggedIsInt(key), &isKeyInt, ¬KeyInt); + Bind(&isKeyInt); + { + resultKey = TaggedCastToInt32(key); + Jump(&exit); + } + Bind(¬KeyInt); + { + Label isString(env); + Label notString(env); + Branch(TaggedIsString(key), &isString, ¬String); + Bind(&isString); + { + resultKey = StringToElementIndex(key); + Jump(&exit); + } + Bind(¬String); + { + Label isDouble(env); + Branch(TaggedIsDouble(key), &isDouble, &exit); + Bind(&isDouble); + { + AddrShift number = TaggedCastToDouble(key); + AddrShift integer = ChangeInt64ToInt32(CastDoubleToInt64(number)); + Label isEqual(env); + Branch(DoubleEqual(number, CastInt64ToFloat64(SExtInt32ToInt64(integer))), &isEqual, &exit); + Bind(&isEqual); + { + resultKey = integer; + Jump(&exit); + } + } + } + } + Bind(&exit); + return *resultKey; +} } // namespace kungfu \ No newline at end of file diff --git a/ecmascript/compiler/stub.h b/ecmascript/compiler/stub.h index 1260e34bb681ab99c7c9d6aabc655fec551dde4d..525f5566f36ba56bf82fb97926dae37429c05bfb 100644 --- a/ecmascript/compiler/stub.h +++ b/ecmascript/compiler/stub.h @@ -751,11 +751,6 @@ public: return env_.GetCircuitBuilder().NewLogicGate(OpCode(OpCode::INT32_AND), x, y); } - AddrShift WordLogicNot(AddrShift x) - { - return env_.GetCircuitBuilder().NewLogicGate(OpCode(OpCode::INT32_REV), x); - } - AddrShift Word32LSL(AddrShift x, AddrShift y) { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT32_LSL), x, y); @@ -819,16 +814,21 @@ public: Word64Equal(Word64And(x, GetWord64Constant(~panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)), GetWord64Constant(0))), WordLogicOr(SExtInt1ToInt32(Word64NotEqual( - Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)), + Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_VALUE)), GetWord64Constant(0))), SExtInt1ToInt32(TaggedIsHole(x))))); } AddrShift TaggedIsHeapObject(AddrShift x) { return TruncInt32ToInt1( - WordLogicAnd(SExtInt1ToInt32(TaggedIsObject(x)), WordLogicNot(SExtInt1ToInt32(TaggedIsSpecial(x))))); + WordLogicAnd(SExtInt1ToInt32(TaggedIsObject(x)), + SExtInt1ToInt32(Word32Equal(SExtInt1ToInt32(TaggedIsSpecial(x)), GetInteger32Constant(0))))); } + AddrShift TaggedIsString(AddrShift obj); + + AddrShift TaggedIsStringOrSymbol(AddrShift obj); + AddrShift DoubleIsNAN(AddrShift x) { AddrShift diff = DoubleEqual(x, x); @@ -841,8 +841,8 @@ public: AddrShift negativeInfinity = GetDoubleConstant(-base::POSITIVE_INFINITY); AddrShift diff1 = DoubleEqual(x, infinity); AddrShift diff2 = DoubleEqual(x, negativeInfinity); - return Word32Or(Word32Equal(SExtInt1ToInt32(diff1), GetInteger32Constant(1)), - Word32Equal(SExtInt1ToInt32(diff2), GetInteger32Constant(1))); + return TruncInt32ToInt1(Word32Or(Word32Equal(SExtInt1ToInt32(diff1), GetInteger32Constant(1)), + Word32Equal(SExtInt1ToInt32(diff2), GetInteger32Constant(1)))); } AddrShift IntBuildTagged(AddrShift x) @@ -1270,6 +1270,18 @@ public: AddrShift JSObjectGetProperty(AddrShift obj, AddrShift hClass, AddrShift propAttr); + AddrShift IsUtf16String(AddrShift string); + + AddrShift IsUtf8String(AddrShift string); + + AddrShift IsInternalString(AddrShift string); + + AddrShift IsDigit(AddrShift ch); + + AddrShift StringToElementIndex(AddrShift string); + + AddrShift TryToElementsIndex(AddrShift key); + AddrShift TaggedCastToInt64(AddrShift x) { return Word64And(x, GetWord64Constant(~panda::ecmascript::JSTaggedValue::TAG_MASK)); @@ -1326,6 +1338,16 @@ public: return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::ZEXT_INT1_TO_INT32), x); } + AddrShift ZExtInt8ToInt32(AddrShift x) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::ZEXT_INT8_TO_INT32), x); + } + + AddrShift ZExtInt16ToInt32(AddrShift x) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::ZEXT_INT16_TO_INT32), x); + } + AddrShift TruncInt64ToInt32(AddrShift x) { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::TRUNC_INT64_TO_INT32), x); diff --git a/ecmascript/compiler/stub_descriptor.cpp b/ecmascript/compiler/stub_descriptor.cpp index 31cc658a5ac2963abab8c4d4510a84423aab2c1e..93716b87eb610f750795c7aa1b46fc8cfec5b567 100644 --- a/ecmascript/compiler/stub_descriptor.cpp +++ b/ecmascript/compiler/stub_descriptor.cpp @@ -208,6 +208,36 @@ CALL_STUB_INIT_DESCRIPTOR(SetPropertyByIndex) descriptor->SetParameters(params.data()); } +CALL_STUB_INIT_DESCRIPTOR(GetPropertyByValue) +{ + // 3 : 3 input parameters + static StubDescriptor getPropertyByValue("GetPropertyByValue", 0, 3, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + *descriptor = getPropertyByValue; + // 3 : 3 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} + +CALL_STUB_INIT_DESCRIPTOR(SetPropertyByValue) +{ + // 4 : 4 input parameters + static StubDescriptor setPropertyByValue("SetPropertyByValue", 0, 4, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + *descriptor = setPropertyByValue; + // 4 : 4 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} + + CALL_STUB_INIT_DESCRIPTOR(AddElementInternal) { // 5 : 5 input parameters @@ -334,6 +364,20 @@ CALL_STUB_INIT_DESCRIPTOR(StringGetHashCode) descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); } +CALL_STUB_INIT_DESCRIPTOR(NewInternalString) +{ + // 2 : 2 input parameters + static StubDescriptor stringGetHashCode("NewInternalString", 0, 2, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + *descriptor = stringGetHashCode; + // 2 : 2 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); +} + void FastStubDescriptors::InitializeStubDescriptors() { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) diff --git a/ecmascript/compiler/tests/stub_tests.cpp b/ecmascript/compiler/tests/stub_tests.cpp index c684a94da8171bc183ae22d099ac1600159fd5d8..bd5e71d7183fe664d92a22d55c4f383a35b325e3 100644 --- a/ecmascript/compiler/tests/stub_tests.cpp +++ b/ecmascript/compiler/tests/stub_tests.cpp @@ -1264,8 +1264,8 @@ HWTEST_F_L0(StubTest, FastModTest) for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" << std::endl; - for (size_t instIdex = cfg[bbIdx].size(); instIdex < 0; instIdex--) { - netOfGates.Print(cfg[bbIdx][instIdex - 1]); + for (size_t instIdx = cfg[bbIdx].size(); instIdx < 0; instIdx--) { + netOfGates.Print(cfg[bbIdx][instIdx - 1]); } } LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); @@ -1318,4 +1318,84 @@ HWTEST_F_L0(StubTest, FastModTest) std::cout << "result1 for FastMod(7, 'helloworld') = " << result5.GetRawData() << std::endl; EXPECT_EQ(result5, expectRes5); } + +HWTEST_F_L0(StubTest, FastGetPropertyByValueStub) +{ + auto module = stubModule.GetModule(); + LLVMValueRef getPropertyByIndexfunction = LLVMGetNamedFunction(module, "GetPropertyByIndex"); + Circuit netOfGates2; + FastGetPropertyByIndexStub getPropertyByIndexStub(&netOfGates2); + getPropertyByIndexStub.GenerateCircuit(); + netOfGates2.PrintAllGates(); + auto cfg2 = Scheduler::Run(&netOfGates2); + LLVMIRBuilder llvmBuilder2(&cfg2, &netOfGates2, &stubModule, getPropertyByIndexfunction); + llvmBuilder2.Build(); + + LLVMValueRef getPropertyByNamefunction = LLVMGetNamedFunction(module, "GetPropertyByName"); + Circuit netOfGates1; + FastGetPropertyByNameStub getPropertyByNameStub(&netOfGates1); + getPropertyByNameStub.GenerateCircuit(); + bool result = Verifier::Run(&netOfGates1); + ASSERT_TRUE(result); + auto cfg1 = Scheduler::Run(&netOfGates1); + LLVMIRBuilder llvmBuilder1(&cfg1, &netOfGates1, &stubModule, getPropertyByNamefunction); + llvmBuilder1.Build(); + + LLVMValueRef function = LLVMGetNamedFunction(module, "GetPropertyByValue"); + Circuit netOfGates; + FastGetPropertyByValueStub optimizer(&netOfGates); + optimizer.GenerateCircuit(); + netOfGates.PrintAllGates(); + result = Verifier::Run(&netOfGates); + ASSERT_TRUE(result); + auto cfg = Scheduler::Run(&netOfGates); + for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { + std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" + << std::endl; + for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { + netOfGates.Print(cfg[bbIdx][instIdx - 1]); + } + } + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); + llvmBuilder.Build(); + LLVMAssembler assembler(module); + assembler.Run(); + auto engine = assembler.GetEngine(); + auto *getPropertyByValuePtr = reinterpret_cast( + reinterpret_cast(LLVMGetPointerToGlobal(engine, function))); + auto *getPropertyByNamePtr = reinterpret_cast( + reinterpret_cast(LLVMGetPointerToGlobal(engine, getPropertyByNamefunction))); + auto *getpropertyByIndexPtr = reinterpret_cast( + reinterpret_cast(LLVMGetPointerToGlobal(engine, getPropertyByIndexfunction))); + auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); + JSHandle obj = factory->NewEmptyJSObject(); + int x = 213; + int y = 10; + + FastRuntimeStub::SetOwnElement(thread, obj.GetTaggedValue(), 1, JSTaggedValue(x)); + FastRuntimeStub::SetOwnElement(thread, obj.GetTaggedValue(), 10250, JSTaggedValue(y)); + + JSHandle strA(factory->NewFromCanBeCompressString("a")); + JSHandle strBig(factory->NewFromCanBeCompressString("biggest")); + JSHandle strDigit(factory->NewFromCanBeCompressString("10250")); + + FastRuntimeStub::SetPropertyByName(thread, obj.GetTaggedValue(), strA.GetTaggedValue(), JSTaggedValue(x)); + FastRuntimeStub::SetPropertyByName(thread, obj.GetTaggedValue(), strBig.GetTaggedValue(), JSTaggedValue(y)); + assembler.Disassemble(); + + JSTaggedValue resVal1 = getPropertyByNamePtr(thread, obj.GetTaggedValue().GetRawData(), + strA.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal1.GetNumber(), x); + JSTaggedValue resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), + strA.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal.GetNumber(), x); + resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), strBig.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal.GetNumber(), y); + resVal = getpropertyByIndexPtr(thread, obj.GetTaggedValue(), 1); + EXPECT_EQ(resVal.GetNumber(), x); + resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), JSTaggedValue(10250).GetRawData()); + EXPECT_EQ(resVal.GetNumber(), y); + resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), strDigit.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal.GetNumber(), y); +} } // namespace panda::test diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index 499295787b1dc9e21cf603ddf98a1ca1da7f96d4..eab7f022298eee4d4c3116d3a8e5c8ab4fb3f996 100644 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -45,6 +45,13 @@ public: static EcmaString *FastSubString(const JSHandle &src, uint32_t start, uint32_t utf16Len, const EcmaVM *vm); + static constexpr uint32_t STRING_COMPRESSED_BIT = 0x1; + static constexpr uint32_t STRING_INTERN_BIT = 0x2; + enum CompressedStatus { + STRING_COMPRESSED, + STRING_UNCOMPRESSED, + }; + template uint16_t At(int32_t index) const; @@ -285,12 +292,6 @@ private: static void CopyUtf16AsUtf8(const uint16_t *utf16From, uint8_t *utf8To, uint32_t utf16Len); static bool compressedStringsEnabled; - static constexpr uint32_t STRING_COMPRESSED_BIT = 0x1; - static constexpr uint32_t STRING_INTERN_BIT = 0x2; - enum CompressedStatus { - STRING_COMPRESSED, - STRING_UNCOMPRESSED, - }; static bool IsASCIICharacter(uint16_t data) { diff --git a/ecmascript/runtime_trampolines.cpp b/ecmascript/runtime_trampolines.cpp index 839459d5e09e02ed0560d85e2b61496b333070d4..a0e7a775d7af2e791a7756ec9480895408c8bc9d 100644 --- a/ecmascript/runtime_trampolines.cpp +++ b/ecmascript/runtime_trampolines.cpp @@ -103,4 +103,11 @@ uint32_t RuntimeTrampolines::StringGetHashCode(uint64_t ecmaString) auto string = reinterpret_cast(ecmaString); return string->GetHashcode(); } + +uint64_t RuntimeTrampolines::NewInternalString(uint64_t argThread, uint64_t argKey) +{ + auto thread = reinterpret_cast(argThread); + JSHandle keyHandle(thread, JSTaggedValue(reinterpret_cast(argKey))); + return JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(keyHandle)).GetRawData(); +} } // namespace panda::ecmascript diff --git a/ecmascript/runtime_trampolines.h b/ecmascript/runtime_trampolines.h index 678ea521eeab52a92c509428ab7068bee809a88e..6fe25f01a6b6b05968dedbf10a45e19962d2aad2 100644 --- a/ecmascript/runtime_trampolines.h +++ b/ecmascript/runtime_trampolines.h @@ -48,6 +48,7 @@ public: static uint32_t GetHash32(uint64_t key, uint64_t len); static int32_t FindElementWithCache(uint64_t argThread, uint64_t hClass, uint64_t key, int32_t num); static uint32_t StringGetHashCode(uint64_t ecmaString); + static uint64_t NewInternalString(uint64_t argThread, uint64_t argKey); }; } // namespace panda::ecmascript #endif \ No newline at end of file