diff --git a/ecmascript/compiler/call_signature.cpp b/ecmascript/compiler/call_signature.cpp index a083e80602..a1b39abad0 100644 --- a/ecmascript/compiler/call_signature.cpp +++ b/ecmascript/compiler/call_signature.cpp @@ -1447,6 +1447,20 @@ DEF_CALL_SIGNATURE(StringGetEnd) callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); } +DEF_CALL_SIGNATURE(ClearJitCompiledCodeFlags) +{ + // 1 : 1 input parameters + CallSignature ClearJitCompiledCodeFlags("ClearJitCompiledCodeFlags", 0, 1, + ArgumentsOrder::DEFAULT_ORDER, VariableType::VOID()); + *callSign = ClearJitCompiledCodeFlags; + std::array params = { // 1 : 1 input parameters + VariableType::JS_POINTER(), + }; + callSign->SetParameters(params.data()); + callSign->SetGCLeafFunction(true); + callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); +} + #define PUSH_CALL_ARGS_AND_DISPATCH_SIGNATURE_COMMON(name) \ /* 1 : 1 input parameters */ \ CallSignature signature(#name, 0, 1, \ diff --git a/ecmascript/compiler/call_signature.h b/ecmascript/compiler/call_signature.h index 19e5d79c56..32b37853da 100644 --- a/ecmascript/compiler/call_signature.h +++ b/ecmascript/compiler/call_signature.h @@ -512,7 +512,8 @@ private: V(StringGetStart) \ V(StringGetEnd) \ V(ArrayTrim) \ - V(OptimizedFastJmp) + V(OptimizedFastJmp) \ + V(ClearJitCompiledCodeFlags) #define DECL_CALL_SIGNATURE(name) \ class name##CallSignature final { \ diff --git a/ecmascript/compiler/new_object_stub_builder.cpp b/ecmascript/compiler/new_object_stub_builder.cpp index 8046277eae..4dd7aaf109 100644 --- a/ecmascript/compiler/new_object_stub_builder.cpp +++ b/ecmascript/compiler/new_object_stub_builder.cpp @@ -643,9 +643,19 @@ GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, Gat Label isAotWithCallField(env); Label afterAotWithCallField(env); + Label isJitCompiledCode(env); + Label afterJitCompiledCode(env); BRANCH(IsAotWithCallField(method), &isAotWithCallField, &afterAotWithCallField); { Bind(&isAotWithCallField); + BRANCH(IsJitCompiledCode(method), &isJitCompiledCode, &afterJitCompiledCode); + { + Bind(&isJitCompiledCode); + ClearJitCompiledCodeFlags(glue, method); + Jump(&afterAotWithCallField); + } + Bind(&afterJitCompiledCode); + SetCodeEntryToFunction(glue, *result, method); Jump(&afterAotWithCallField); } diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index c8852c31c8..408766ccc0 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -2854,6 +2854,22 @@ inline GateRef StubBuilder::IsFastCall(GateRef method) Int64(0)); } +inline GateRef StubBuilder::IsJitCompiledCode(GateRef method) +{ + GateRef fieldOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET); + GateRef literalField = Load(VariableType::INT64(), method, fieldOffset); + return Int64NotEqual( + Int64And( + Int64LSR(literalField, Int64(Method::IsJitCompiledCodeBit::START_BIT)), + Int64((1LU << Method::IsJitCompiledCodeBit::SIZE) - 1)), + Int64(0)); +} + +inline void StubBuilder::ClearJitCompiledCodeFlags(GateRef glue, GateRef method) +{ + CallNGCRuntime(glue, RTSTUB_ID(ClearJitCompiledCodeFlags), { method }); +} + inline GateRef StubBuilder::HasPrototype(GateRef kind) { GateRef greater = Int32GreaterThanOrEqual(kind, diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 846d25026a..5a8eefaf3d 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -782,6 +782,8 @@ public: GateRef GetIhcFromAOTLiteralInfo(GateRef info); GateRef IsAotWithCallField(GateRef method); GateRef IsFastCall(GateRef method); + GateRef IsJitCompiledCode(GateRef method); + void ClearJitCompiledCodeFlags(GateRef glue, GateRef method); GateRef JudgeAotAndFastCall(GateRef jsFunc, CircuitBuilder::JudgeMethodType type); GateRef JudgeAotAndFastCallWithMethod(GateRef method, CircuitBuilder::JudgeMethodType type); GateRef GetInternalString(GateRef glue, GateRef key); diff --git a/ecmascript/js_function.cpp b/ecmascript/js_function.cpp index 7f39ef72f8..0ab4649bc9 100644 --- a/ecmascript/js_function.cpp +++ b/ecmascript/js_function.cpp @@ -1058,10 +1058,13 @@ void JSFunction::InitializeForConcurrentFunction(JSThread *thread) void JSFunctionBase::SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall) { ASSERT(codeEntry != 0); + SetCodeEntry(codeEntry); + Method* method = Method::Cast(GetMethod()); method->SetCodeEntryAndMarkAOTWhenBinding(codeEntry); - + method->SetJitCompiledCode(true); method->SetIsFastCall(isFastCall); + MethodLiteral *methodLiteral = method->GetMethodLiteral(); methodLiteral->SetAotCodeBit(true); methodLiteral->SetIsFastCall(isFastCall); diff --git a/ecmascript/js_serializer.cpp b/ecmascript/js_serializer.cpp index fe91690849..598becf278 100644 --- a/ecmascript/js_serializer.cpp +++ b/ecmascript/js_serializer.cpp @@ -492,7 +492,7 @@ bool JSSerializer::WriteMethod(const JSHandle &value) if (!WriteString(desc)) { return false; } - if (method->IsAotWithCallField()) { + if (method->CanSerializeCodeEntry()) { uintptr_t codeEntry = method->GetCodeEntryOrLiteral(); if (!WriteRawData(&codeEntry, sizeof(uintptr_t))) { return false; @@ -514,7 +514,8 @@ bool JSSerializer::WriteJSFunction(const JSHandle &value) return false; } JSHandle method(thread_, func->GetMethod()); - if (Method::Cast(method.GetTaggedValue())->IsAotWithCallField()) { + Method *methodPtr = Method::Cast(method.GetTaggedValue()); + if (methodPtr->CanSerializeCodeEntry()) { uintptr_t codeEntry = func->GetCodeEntry(); if (!WriteRawData(&codeEntry, sizeof(uintptr_t))) { return false; @@ -1338,7 +1339,7 @@ JSHandle JSDeserializer::ReadMethod() thread_->GetCurrentEcmaContext()->FindOrCreateConstPool(jsPandaFile.get(), method->GetMethodId()); method->SetConstantPool(thread_, constPool.GetTaggedValue()); - if (method->IsAotWithCallField()) { + if (method->CanSerializeCodeEntry()) { uintptr_t codeEntry; if (!ReadNativePointer(&codeEntry)) { return JSHandle(); diff --git a/ecmascript/method.cpp b/ecmascript/method.cpp index 50bb762559..3783e6bf74 100644 --- a/ecmascript/method.cpp +++ b/ecmascript/method.cpp @@ -126,4 +126,30 @@ void Method::ClearAOTFlagsWhenInit() SetAotCodeBit(false); SetIsFastCall(false); } + +bool Method::IsJitCompiledCode() const +{ + uint64_t extraLiteralInfo = GetExtraLiteralInfo(); + return IsJitCompiledCodeBit::Decode(extraLiteralInfo); +} + +void Method::SetJitCompiledCode(bool flag) +{ + uint64_t extraLiteralInfo = GetExtraLiteralInfo(); + IsJitCompiledCodeBit::Update(extraLiteralInfo, flag); +} + +void Method::ClearJitCompiledCodeFlags() +{ + ClearAOTFlagsWhenInit(); + const JSPandaFile *jsPandaFile = GetJSPandaFile(); + MethodLiteral *methodLiteral = jsPandaFile->FindMethodLiteral(GetMethodId().GetOffset()); + SetCodeEntryOrLiteral(reinterpret_cast(methodLiteral)); + SetJitCompiledCode(false); +} + +bool Method::CanSerializeCodeEntry() const +{ + return IsAotWithCallField() && !IsJitCompiledCode(); +} } // namespace panda::ecmascript diff --git a/ecmascript/method.h b/ecmascript/method.h index e64d8a77dd..35bbc82a35 100644 --- a/ecmascript/method.h +++ b/ecmascript/method.h @@ -389,6 +389,13 @@ public: void SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall); + // jit code + bool IsJitCompiledCode() const; + void SetJitCompiledCode(bool flag); + void ClearJitCompiledCodeFlags(); + + bool CanSerializeCodeEntry() const; + static constexpr size_t Size() { return sizeof(Method); @@ -429,6 +436,7 @@ public: using DeoptCountBits = FunctionKindBits::NextField; // offset 12-19 using DeoptTypeBits = DeoptCountBits::NextField; // offset 20-27 using IsCallNapiBit = DeoptTypeBits::NextFlag; // offset 28 + using IsJitCompiledCodeBit = IsCallNapiBit::NextFlag; // offset 29 static constexpr size_t CONSTANT_POOL_OFFSET = TaggedObjectSize(); ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, CALL_FIELD_OFFSET) diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 4ae50f1a1f..e20b9d9dbd 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -1804,7 +1804,10 @@ JSHandle ObjectFactory::NewJSFunctionByHClass(const JSHandle clazz->SetExtensible(true); JSFunction::InitializeJSFunction(thread_, function, method->GetFunctionKind()); function->SetMethod(thread_, method); - if (method->IsAotWithCallField()) { + if (method->IsJitCompiledCode()) { + // jit install code also set aot callfield, should clear flag when new function + method->ClearJitCompiledCodeFlags(); + } else if (method->IsAotWithCallField()) { thread_->GetEcmaVM()->GetAOTFileManager()-> SetAOTFuncEntry(method->GetJSPandaFile(), *function, *method); } diff --git a/ecmascript/stubs/runtime_stubs.cpp b/ecmascript/stubs/runtime_stubs.cpp index baa65863aa..53f9567e58 100644 --- a/ecmascript/stubs/runtime_stubs.cpp +++ b/ecmascript/stubs/runtime_stubs.cpp @@ -3554,6 +3554,12 @@ void RuntimeStubs::ArrayTrim(uintptr_t argGlue, TaggedArray *array, int64_t newL array->Trim(thread, length); } +void RuntimeStubs::ClearJitCompiledCodeFlags(Method *method) +{ + DISALLOW_GARBAGE_COLLECTION; + method->ClearJitCompiledCodeFlags(); +} + DEF_RUNTIME_STUBS(ArrayForEachContinue) { RUNTIME_STUBS_HEADER(ArrayForEachContinue); diff --git a/ecmascript/stubs/runtime_stubs.h b/ecmascript/stubs/runtime_stubs.h index 465d068898..477c3f90e3 100644 --- a/ecmascript/stubs/runtime_stubs.h +++ b/ecmascript/stubs/runtime_stubs.h @@ -158,7 +158,8 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co V(LocaleCompareNoGc) \ V(StringGetStart) \ V(StringGetEnd) \ - V(ArrayTrim) + V(ArrayTrim) \ + V(ClearJitCompiledCodeFlags) #define RUNTIME_STUB_WITH_GC_LIST(V) \ V(AddElementInternal) \ @@ -529,6 +530,8 @@ public: static int32_t StringGetStart(bool isUtf8, EcmaString *srcString, int32_t length, int32_t startIndex); static int32_t StringGetEnd(bool isUtf8, EcmaString *srcString, int32_t start, int32_t length, int32_t startIndex); + static void ClearJitCompiledCodeFlags(Method *method); + private: static void DumpToStreamWithHint(std::ostream &out, std::string_view prompt, JSTaggedValue value); static void PrintHeapReginInfo(uintptr_t argGlue);