[JIT] Support jit re-compile when deopt

Re-compile func if func deopt reach max cnt, and reset jit hotness cnt

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IADV02?from=project-issue
Change-Id: I1c6810d9c1cd6fbce86094ecc200f2acada7e6ab
Signed-off-by: xiaoweidong <xiaoweidong@huawei.com>
This commit is contained in:
xiaoweidong 2024-07-18 16:05:20 +08:00
parent 63774d563e
commit 4d8c1d1b25
11 changed files with 130 additions and 34 deletions

View File

@ -535,6 +535,25 @@ JSTaggedType Deoptimizier::ConstructAsmInterpretFrame()
return reinterpret_cast<JSTaggedType>(frameWriter.GetTop());
}
void Deoptimizier::ResetJitHotness(JSFunction *jsFunc) const
{
if (jsFunc->GetMachineCode().IsMachineCodeObject()) {
JSTaggedValue profileTypeInfoVal = jsFunc->GetProfileTypeInfo();
if (!profileTypeInfoVal.IsUndefined()) {
ProfileTypeInfo *profileTypeInfo = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
profileTypeInfo->SetJitHotnessCnt(0);
constexpr uint16_t thresholdStep = 4;
constexpr uint16_t thresholdLimit = ProfileTypeInfo::JIT_DISABLE_FLAG / thresholdStep;
uint16_t threshold = profileTypeInfo->GetJitHotnessThreshold();
threshold = threshold >= thresholdLimit ? ProfileTypeInfo::JIT_DISABLE_FLAG : threshold * thresholdStep;
profileTypeInfo->SetJitHotnessThreshold(threshold);
ProfileTypeInfoCell::Cast(jsFunc->GetRawProfileTypeInfo())->SetMachineCode(thread_, JSTaggedValue::Hole());
Method *method = Method::Cast(jsFunc->GetMethod().GetTaggedObject());
LOG_JIT(DEBUG) << "reset jit hotness for func: " << method->GetMethodName() << ", threshold:" << threshold;
}
}
}
void Deoptimizier::ClearCompiledCodeStatusWhenDeopt(JSFunction *func, Method *method)
{
if (func->GetMachineCode().IsMachineCodeObject()) {
@ -548,6 +567,7 @@ void Deoptimizier::ClearCompiledCodeStatusWhenDeopt(JSFunction *func, Method *me
func->SetCodeEntry(entry);
method->ClearAOTStatusWhenDeopt(entry);
func->ClearCompiledCodeFlags();
ResetJitHotness(func);
} // Do not change the func code entry if the method is not aot or deopt has happened already
}

View File

@ -180,6 +180,7 @@ private:
void Dump(JSTaggedValue callTarget, kungfu::DeoptType type, size_t depth);
size_t GetCallSize(size_t curDepth, const uint8_t *resumePc);
void ClearCompiledCodeStatusWhenDeopt(JSFunction *fun, Method *method);
void ResetJitHotness(JSFunction *jsFunc) const;
JSThread *thread_ {nullptr};
uintptr_t *calleeRegAddr_ {nullptr};
size_t numCalleeRegs_ {0};

View File

@ -117,40 +117,15 @@ JSTaggedValue FrameIterator::GetFunction() const
AOTFileInfo::CallSiteInfo FrameIterator::TryCalCallSiteInfoFromMachineCode(uintptr_t retAddr) const
{
// get CallSiteInfo with jsfunction for jit compiled function
FrameType type = GetFrameType();
if (type == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME ||
type == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) {
auto frame = GetFrame<OptimizedJSFunctionFrame>();
JSTaggedValue func = frame->GetFunction();
if (!func.IsHeapObject()) {
return {};
}
// cast to jsfunction directly. JSFunction::Cast may fail,
// as jsfunction class may set forwardingAddress in Evacuate, but forwarding obj not init.
JSFunction *jsfunc = reinterpret_cast<JSFunction*>(func.GetTaggedObject());
// machineCode non move
JSTaggedValue machineCode = jsfunc->GetMachineCode();
if (machineCode.IsMachineCodeObject() &&
MachineCode::Cast(machineCode.GetTaggedObject())->IsInText(retAddr)) {
return MachineCode::Cast(machineCode.GetTaggedObject())->CalCallSiteInfo(retAddr);
}
} else if (type == FrameType::FASTJIT_FUNCTION_FRAME ||
type == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
type == FrameType::FASTJIT_FUNCTION_FRAME ||
type == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME) {
auto frame = GetFrame<FASTJITFunctionFrame>();
JSTaggedValue func = frame->GetFunction();
if (!func.IsHeapObject()) {
return {};
}
// cast to jsfunction directly. JSFunction::Cast may fail,
// as jsfunction class may set forwardingAddress in Evacuate, but forwarding obj not init.
JSFunction *jsfunc = reinterpret_cast<JSFunction*>(func.GetTaggedObject());
// machineCode non move
JSTaggedValue machineCode = jsfunc->GetMachineCode();
if (machineCode.IsMachineCodeObject() &&
MachineCode::Cast(machineCode.GetTaggedObject())->IsInText(retAddr)) {
return MachineCode::Cast(machineCode.GetTaggedObject())->CalCallSiteInfo(retAddr);
}
auto machineCode = thread_->GetEcmaVM()->GetHeap()->GetMachineCodeObject(retAddr);
ASSERT(machineCode != nullptr);
const_cast<FrameIterator*>(this)->machineCode_ = reinterpret_cast<JSTaggedType>(machineCode);
return reinterpret_cast<MachineCode*>(machineCode_)->CalCallSiteInfo(retAddr);
}
return {};
}
@ -664,6 +639,11 @@ ARK_INLINE void OptimizedJSFunctionFrame::GCIterate(const FrameIterator &it,
}
}
auto machineCodeSlot = ObjectSlot(ToUintPtr(it.GetMachineCodeSlot()));
if (machineCodeSlot.GetTaggedType() != JSTaggedValue::VALUE_UNDEFINED) {
visitor(Root::ROOT_FRAME, machineCodeSlot);
}
bool ret = it.IteratorStackMap(visitor, derivedVisitor);
if (!ret) {
#ifndef NDEBUG
@ -722,6 +702,11 @@ ARK_INLINE void FASTJITFunctionFrame::GCIterate(const FrameIterator &it,
}
}
auto machineCodeSlot = ObjectSlot(ToUintPtr(it.GetMachineCodeSlot()));
if (machineCodeSlot.GetTaggedType() != JSTaggedValue::VALUE_UNDEFINED) {
visitor(Root::ROOT_FRAME, machineCodeSlot);
}
bool ret = it.IteratorStackMap(visitor, derivedVisitor);
if (!ret) {
#ifndef NDEBUG

View File

@ -2042,6 +2042,11 @@ public:
return IsOptimizedJSFunctionFrame() || IsFastJitFunctionFrame();
}
JSTaggedType *GetMachineCodeSlot() const
{
return const_cast<JSTaggedType*>(&machineCode_);
}
private:
JSTaggedType *current_ {nullptr};
const JSThread *thread_ {nullptr};
@ -2051,6 +2056,9 @@ private:
uint8_t *stackMapAddr_ {nullptr};
int fpDeltaPrevFrameSp_ {0};
kungfu::CalleeRegAndOffsetVec calleeRegInfo_;
// cache current machine code, it's nonmovable
JSTaggedType machineCode_ {JSTaggedValue::VALUE_UNDEFINED};
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_FRAMES_H

View File

@ -230,17 +230,21 @@ void Jit::ReuseCompiledFunc(JSThread *thread, JSHandle<JSFunction> &jsFunction)
if (machineCode.IsHole()) {
return;
}
ProfileTypeInfo *profileTypeInfo = ProfileTypeInfo::Cast(profCell->GetValue().GetTaggedObject());
if (profileTypeInfo->GetJitHotnessThreshold() == ProfileTypeInfo::JIT_DISABLE_FLAG) {
// disable reuse as disable jit in deopt
return;
}
if (machineCode.IsUndefined()) {
LOG_JIT(DEBUG) << "reset fuction jit hotness count";
// if old gc triggered, jit hotness cnt need to be recounted
ProfileTypeInfo::Cast(profCell->GetValue().GetTaggedObject())->SetJitHotnessCnt(0);
profileTypeInfo->SetJitHotnessCnt(0);
profCell->SetMachineCode(thread, JSTaggedValue::Hole());
return;
}
JSHandle<MachineCode> machineCodeHandle(thread, machineCode.GetTaggedObject());
JSHandle<Method> method(thread, Method::Cast(jsFunction->GetMethod().GetTaggedObject()));
LOG_JIT(DEBUG) << "reuse fuction machine code : " << method->GetJSPandaFile()->GetJSPandaFileDesc()
<< ":" << method->GetRecordNameStr() << "." << CString(method->GetMethodName());
uintptr_t codeAddr = machineCodeHandle->GetFuncAddr();
FuncEntryDes *funcEntryDes = reinterpret_cast<FuncEntryDes *>(machineCodeHandle->GetFuncEntryDes());
jsFunction->SetCompiledFuncEntry(codeAddr, funcEntryDes->isFastCall_);

View File

@ -2347,6 +2347,17 @@ void Heap::UpdateWorkManager(WorkManager *workManager)
partialGC_->workManager_ = workManager;
}
MachineCode *Heap::GetMachineCodeObject(uintptr_t pc) const
{
MachineCodeSpace *machineCodeSpace = GetMachineCodeSpace();
MachineCode *machineCode = reinterpret_cast<MachineCode*>(machineCodeSpace->GetMachineCodeObject(pc));
if (machineCode != nullptr) {
return machineCode;
}
HugeMachineCodeSpace *hugeMachineCodeSpace = GetHugeMachineCodeSpace();
return reinterpret_cast<MachineCode*>(hugeMachineCodeSpace->GetMachineCodeObject(pc));
}
std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec> Heap::CalCallSiteInfo(uintptr_t retAddr) const
{
MachineCodeSpace *machineCodeSpace = GetMachineCodeSpace();

View File

@ -1355,6 +1355,7 @@ public:
void InstallEdenAllocator();
void DumpHeapSnapshotBeforeOOM(bool isFullGC = true);
std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec> CalCallSiteInfo(uintptr_t retAddr) const;
MachineCode *GetMachineCodeObject(uintptr_t pc) const;
PUBLIC_API GCListenerId AddGCListener(FinishGCListener listener, void *data);
PUBLIC_API void RemoveGCListener(GCListenerId listenerId);

View File

@ -16,6 +16,7 @@
#include "ecmascript/mem/space-inl.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/mem/heap_region_allocator.h"
#include "ecmascript/mem/mem_controller.h"
#include "ecmascript/mem/region-inl.h"
@ -107,6 +108,25 @@ HugeMachineCodeSpace::HugeMachineCodeSpace(Heap *heap, HeapRegionAllocator *heap
{
}
uintptr_t HugeMachineCodeSpace::GetMachineCodeObject(uintptr_t pc) const
{
uintptr_t machineCode = 0;
EnumerateRegions([&](Region *region) {
if (machineCode != 0) {
return;
}
if (!region->InRange(pc)) {
return;
}
uintptr_t curPtr = region->GetBegin();
auto obj = MachineCode::Cast(reinterpret_cast<TaggedObject*>(curPtr));
if (obj->IsInText(pc)) {
machineCode = curPtr;
}
});
return machineCode;
}
#ifdef ENABLE_JITFORT
uintptr_t HugeMachineCodeSpace::Allocate(size_t objectSize, JSThread *thread, size_t instructionsSize,
uintptr_t &instructionsAddr, AllocateEventType allocType)

View File

@ -306,6 +306,7 @@ class HugeMachineCodeSpace : public HugeObjectSpace {
public:
HugeMachineCodeSpace(Heap *heap, HeapRegionAllocator *regionAllocator, size_t initialCapacity,
size_t maximumCapacity);
uintptr_t GetMachineCodeObject(uintptr_t pc) const;
#ifdef ENABLE_JITFORT
uintptr_t Allocate(size_t objectSize, JSThread *thread, size_t instructionsSize, uintptr_t &instructionsAddr,
AllocateEventType allocType = AllocateEventType::NORMAL);

View File

@ -711,4 +711,46 @@ uintptr_t MachineCodeSpace::Allocate(size_t size, MachineCodeDesc &desc, bool al
}
#endif // ENABLE_JITFORT
size_t MachineCodeSpace::CheckMachineCodeObject(uintptr_t curPtr, uintptr_t &machineCode, uintptr_t pc)
{
auto freeObject = FreeObject::Cast(curPtr);
size_t objSize = 0;
if (!freeObject->IsFreeObject()) {
auto obj = MachineCode::Cast(reinterpret_cast<TaggedObject*>(curPtr));
if (obj->IsInText(pc)) {
machineCode = curPtr;
}
objSize = obj->GetClass()->SizeFromJSHClass(obj);
} else {
objSize = freeObject->Available();
}
return objSize;
}
uintptr_t MachineCodeSpace::GetMachineCodeObject(uintptr_t pc)
{
uintptr_t machineCode = 0;
allocator_->FillBumpPointer();
EnumerateRegions([&](Region *region) {
if (machineCode != 0) {
return;
}
if (region->InCollectSet() || !region->InRange(pc)) {
return;
}
uintptr_t curPtr = region->GetBegin();
uintptr_t endPtr = region->GetEnd();
while (curPtr < endPtr) {
size_t objSize = CheckMachineCodeObject(curPtr, machineCode, pc);
if (machineCode != 0) {
return;
}
curPtr += objSize;
CHECK_OBJECT_SIZE(objSize);
}
CHECK_REGION_END(curPtr, endPtr);
});
return machineCode;
}
} // namespace panda::ecmascript

View File

@ -295,6 +295,9 @@ public:
~MachineCodeSpace() override;
NO_COPY_SEMANTIC(MachineCodeSpace);
NO_MOVE_SEMANTIC(MachineCodeSpace); // Note: Expand() left for define
uintptr_t GetMachineCodeObject(uintptr_t pc);
size_t CheckMachineCodeObject(uintptr_t curPtr, uintptr_t &machineCode, uintptr_t pc);
#ifdef ENABLE_JITFORT
void FreeRegion(Region *current, bool isMain = true) override;
uintptr_t Allocate(size_t size, MachineCodeDesc &desc, bool allowGC = true);