mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 08:03:29 +00:00
80e765b204
Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAKOX0?from=project-issue Signed-off-by: daizihan <daizihan@huawei.com> Change-Id: I38cc2df9e43268441d7bec55ec08f85038283a15
1195 lines
45 KiB
C++
1195 lines
45 KiB
C++
/*
|
|
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "ecmascript/compiler/profiler_stub_builder.h"
|
|
|
|
#include "ecmascript/base/number_helper.h"
|
|
#include "ecmascript/compiler/circuit_builder_helper.h"
|
|
#include "ecmascript/compiler/share_gate_meta_data.h"
|
|
#include "ecmascript/compiler/interpreter_stub-inl.h"
|
|
#include "ecmascript/compiler/stub_builder-inl.h"
|
|
#include "ecmascript/ic/profile_type_info.h"
|
|
|
|
namespace panda::ecmascript::kungfu {
|
|
void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo,
|
|
const std::vector<GateRef> &values, SlotIDFormat format, OperationType type)
|
|
{
|
|
if (type == OperationType::TRUE_BRANCH ||
|
|
type == OperationType::FALSE_BRANCH ||
|
|
type == OperationType::TRY_JIT) {
|
|
SlotIDInfo slotIdInfo(pc, SlotIDInfo::SlotIDInfoType::PC);
|
|
PGOProfiler(glue, func, profileTypeInfo, slotIdInfo, values, type);
|
|
} else {
|
|
SlotIDInfo slotIdInfo(pc, format);
|
|
PGOProfiler(glue, func, profileTypeInfo, slotIdInfo, values, type);
|
|
}
|
|
}
|
|
|
|
void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef func, GateRef profileTypeInfo,
|
|
GateRef slotId, const std::vector<GateRef> &values, OperationType type)
|
|
{
|
|
SlotIDInfo slotIdInfo(slotId, SlotIDInfo::SlotIDInfoType::SLOT_ID);
|
|
PGOProfiler(glue, func, profileTypeInfo, slotIdInfo, values, type);
|
|
}
|
|
|
|
void ProfilerStubBuilder::TryDump(GateRef glue, GateRef func, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
Label updatePeriodCounter(env);
|
|
Label exit(env);
|
|
Label needDump(env);
|
|
|
|
BRANCH(IsProfileTypeInfoWithBigMethod(profileTypeInfo), &exit, &needDump);
|
|
Bind(&needDump);
|
|
BRANCH(IsProfileTypeInfoDumped(profileTypeInfo), &exit, &updatePeriodCounter);
|
|
Bind(&updatePeriodCounter);
|
|
{
|
|
SetDumpPeriodIndex(glue, profileTypeInfo);
|
|
CallRuntime(glue, RTSTUB_ID(PGODump), { func });
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::TryPreDump(GateRef glue, GateRef func, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label exit(env);
|
|
Label profiler(env);
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
|
|
Bind(&profiler);
|
|
{
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileOpType(
|
|
GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef profileTypeInfo, GateRef type)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
Label exit(env);
|
|
Label profiler(env);
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
|
|
Bind(&profiler);
|
|
{
|
|
Label icSlotValid(env);
|
|
Label uninitialized(env);
|
|
Label compareLabel(env);
|
|
Label updateSlot(env);
|
|
|
|
GateRef slotId = GetSlotID(slotInfo);
|
|
GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
|
|
Bind(&icSlotValid);
|
|
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
|
|
DEFVARIABLE(curType, VariableType::INT32(), type);
|
|
DEFVARIABLE(curCount, VariableType::INT32(), Int32(0));
|
|
BRANCH(TaggedIsInt(slotValue), &compareLabel, &uninitialized);
|
|
Bind(&compareLabel);
|
|
{
|
|
GateRef oldSlotValue = TaggedGetInt(slotValue);
|
|
GateRef oldType = Int32And(oldSlotValue, Int32(PGOSampleType::AnyType()));
|
|
curType = Int32Or(oldType, type);
|
|
curCount = Int32And(oldSlotValue, Int32(0xfffffc00)); // 0xfffffc00: count bits
|
|
BRANCH(Int32Equal(oldType, *curType), &exit, &updateSlot);
|
|
}
|
|
Bind(&uninitialized);
|
|
{
|
|
// Only when slot value is undefined, it means uninitialized, so we need to update the slot.
|
|
// When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
|
|
BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
|
|
}
|
|
Bind(&updateSlot);
|
|
{
|
|
GateRef newSlotValue = Int32Or(*curCount, *curType);
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newSlotValue));
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileDefineClass(
|
|
GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef constructor, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
Label exit(env);
|
|
Label profiler(env);
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
|
|
Bind(&profiler);
|
|
{
|
|
Label icSlotValid(env);
|
|
Label updateSlot(env);
|
|
Label isHeapObject(env);
|
|
Label isProfileTypeInfoCell0(env);
|
|
|
|
GateRef slotId = GetSlotID(slotInfo);
|
|
GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
|
|
Bind(&icSlotValid);
|
|
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
|
|
Branch(TaggedIsHeapObject(slotValue), &isHeapObject, &exit);
|
|
Bind(&isHeapObject);
|
|
Branch(IsProfileTypeInfoCell0(slotValue), &isProfileTypeInfoCell0, &exit);
|
|
Bind(&isProfileTypeInfoCell0);
|
|
GateRef handleOffset = IntPtr(ProfileTypeInfoCell::HANDLE_OFFSET);
|
|
GateRef handle = Load(VariableType::JS_ANY(), slotValue, handleOffset);
|
|
BRANCH(TaggedIsUndefined(handle), &updateSlot, &exit);
|
|
Bind(&updateSlot);
|
|
auto weakCtor = env->GetBuilder()->CreateWeakRef(constructor);
|
|
Store(VariableType::JS_POINTER(), glue, slotValue, handleOffset, weakCtor);
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileCreateObject(
|
|
GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef newObj, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label exit(env);
|
|
|
|
Label profiler(env);
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
|
|
Bind(&profiler);
|
|
{
|
|
Label icSlotValid(env);
|
|
Label isHeapObject(env);
|
|
Label isWeak(env);
|
|
Label uninitialized(env);
|
|
Label updateSlot(env);
|
|
|
|
GateRef slotId = GetSlotID(slotInfo);
|
|
GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
|
|
Bind(&icSlotValid);
|
|
auto hclass = LoadHClass(newObj);
|
|
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
|
|
BRANCH(TaggedIsHeapObject(slotValue), &isHeapObject, &uninitialized);
|
|
Bind(&isHeapObject);
|
|
{
|
|
BRANCH(TaggedIsWeak(slotValue), &isWeak, &updateSlot);
|
|
}
|
|
Bind(&isWeak);
|
|
{
|
|
auto cachedHClass = LoadObjectFromWeakRef(slotValue);
|
|
BRANCH(Equal(cachedHClass, hclass), &exit, &updateSlot);
|
|
}
|
|
Bind(&uninitialized);
|
|
{
|
|
// Only when slot value is undefined, it means uninitialized, so we need to update the slot.
|
|
// When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
|
|
BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
|
|
}
|
|
Bind(&updateSlot);
|
|
{
|
|
auto weakCtor = env->GetBuilder()->CreateWeakRef(hclass);
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, weakCtor);
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileCall(
|
|
GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef target, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
Label exit(env);
|
|
Label slowPath(env);
|
|
Label fastPath(env);
|
|
Label targetIsFunction(env);
|
|
|
|
BRANCH(IsJSFunction(target), &targetIsFunction, &exit);
|
|
Bind(&targetIsFunction);
|
|
{
|
|
GateRef targetProfileInfo = GetProfileTypeInfo(target);
|
|
Label targetIsNotHot(env);
|
|
Label targetIsHot(env);
|
|
Label currentIsHot(env);
|
|
|
|
BRANCH(IsProfileTypeInfoHotAndValid(targetProfileInfo), &targetIsHot, &targetIsNotHot);
|
|
Bind(&targetIsNotHot);
|
|
{
|
|
CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounterWithProf), { target });
|
|
Jump(&targetIsHot);
|
|
}
|
|
Bind(&targetIsHot);
|
|
{
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), ¤tIsHot, &exit);
|
|
}
|
|
Bind(¤tIsHot);
|
|
{
|
|
Label icSlotValid(env);
|
|
Label isHeapObject(env);
|
|
Label uninitialized(env);
|
|
Label updateSlot(env);
|
|
|
|
GateRef slotId = GetSlotID(slotInfo);
|
|
GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
|
|
Bind(&icSlotValid);
|
|
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
|
|
BRANCH(TaggedIsHeapObject(slotValue), &isHeapObject, &uninitialized);
|
|
Bind(&isHeapObject);
|
|
{
|
|
Label change(env);
|
|
Label resetSlot(env);
|
|
BRANCH(Int64Equal(slotValue, target), &exit, &change);
|
|
Bind(&change);
|
|
{
|
|
BRANCH(Int64Equal(ChangeTaggedPointerToInt64(slotValue), Int64(0)), &exit, &resetSlot);
|
|
}
|
|
Bind(&resetSlot);
|
|
{
|
|
// NOTICE-PGO: lx about poly
|
|
GateRef nonType = IntToTaggedInt(Int32(0));
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, nonType);
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&uninitialized);
|
|
{
|
|
// Only when slot value is undefined, it means uninitialized, so we need to update the slot.
|
|
// When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
|
|
BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
|
|
}
|
|
Bind(&updateSlot);
|
|
{
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, target);
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileGetterSetterCall(GateRef glue, GateRef target)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
Label exit(env);
|
|
|
|
Label targetIsFunction(env);
|
|
BRANCH(IsJSFunction(target), &targetIsFunction, &exit);
|
|
Bind(&targetIsFunction);
|
|
{
|
|
GateRef targetProfileInfo = GetProfileTypeInfo(target);
|
|
Label targetNonHotness(env);
|
|
BRANCH(TaggedIsUndefined(targetProfileInfo), &targetNonHotness, &exit);
|
|
Bind(&targetNonHotness);
|
|
{
|
|
CallRuntime(glue, RTSTUB_ID(UpdateHotnessCounterWithProf), { target });
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::TryGetBuiltinFunctionId(GateRef target)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label targetIsFunction(env);
|
|
Label exit(env);
|
|
|
|
DEFVARIABLE(functionId, VariableType::INT32(), Int32(PGO_BUILTINS_STUB_ID(NONE)));
|
|
|
|
BRANCH(IsJSFunction(target), &targetIsFunction, &exit);
|
|
Bind(&targetIsFunction);
|
|
{
|
|
auto builtinsId = env->GetBuilder()->GetBuiltinsId(target);
|
|
functionId = Int32Mul(TruncInt64ToInt32(builtinsId), Int32(-1));
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *functionId;
|
|
env->SubCfgExit();
|
|
return ret;
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileNativeCall(
|
|
GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef target, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
Label exit(env);
|
|
Label currentIsHot(env);
|
|
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), ¤tIsHot, &exit);
|
|
Bind(¤tIsHot);
|
|
{
|
|
Label icSlotValid(env);
|
|
Label updateSlot(env);
|
|
Label initSlot(env);
|
|
Label sameValueCheck(env);
|
|
Label invalidate(env);
|
|
Label notOverflow(env);
|
|
|
|
GateRef slotId = GetSlotID(slotInfo);
|
|
GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
|
|
Bind(&icSlotValid);
|
|
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
|
|
BRANCH(TaggedIsHole(slotValue), &exit, ¬Overflow); // hole -- slot is overflow
|
|
Bind(¬Overflow);
|
|
BRANCH(TaggedIsInt(slotValue), &updateSlot, &initSlot);
|
|
Bind(&updateSlot);
|
|
GateRef oldId = TaggedGetInt(slotValue);
|
|
BRANCH(Int32Equal(oldId, Int32(PGO_BUILTINS_STUB_ID(NONE))), &exit, &sameValueCheck);
|
|
Bind(&sameValueCheck);
|
|
{
|
|
GateRef newId = TryGetBuiltinFunctionId(target);
|
|
BRANCH(Int32Equal(oldId, newId), &exit, &invalidate);
|
|
}
|
|
Bind(&invalidate);
|
|
{
|
|
GateRef invalidId = Int32(PGO_BUILTINS_STUB_ID(NONE));
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidId));
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
Bind(&initSlot);
|
|
{
|
|
GateRef newId = TryGetBuiltinFunctionId(target);
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newId));
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback)
|
|
{
|
|
if (callback.IsEmpty()) {
|
|
return Boolean(true);
|
|
}
|
|
return IsProfileTypeInfoDumped(profileTypeInfo);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback)
|
|
{
|
|
if (callback.IsEmpty()) {
|
|
return attr;
|
|
}
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->SubCfgEntry(&entry);
|
|
|
|
GateRef oldTrackType = GetTrackTypeInPropAttr(attr);
|
|
DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
|
|
DEFVARIABLE(result, VariableType::INT64(), attr);
|
|
|
|
Label exit(env);
|
|
Label judgeValue(env);
|
|
BRANCH(Equal(oldTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &exit, &judgeValue);
|
|
Bind(&judgeValue);
|
|
{
|
|
newTrackType = TaggedToTrackType(value);
|
|
Label update(env);
|
|
Label merge(env);
|
|
BRANCH(Int32Equal(*newTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &update, &merge);
|
|
Bind(&merge);
|
|
{
|
|
newTrackType = Int32Or(oldTrackType, *newTrackType);
|
|
BRANCH(Int32Equal(oldTrackType, *newTrackType), &exit, &update);
|
|
}
|
|
Bind(&update);
|
|
{
|
|
result = SetTrackTypeInPropAttr(attr, *newTrackType);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *result;
|
|
env->SubCfgExit();
|
|
return ret;
|
|
}
|
|
|
|
void ProfilerStubBuilder::UpdatePropAttrIC(
|
|
GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback)
|
|
{
|
|
if (callback.IsEmpty()) {
|
|
return;
|
|
}
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->SubCfgEntry(&entry);
|
|
Label exit(env);
|
|
Label handleUnShared(env);
|
|
Label updateLayout(env);
|
|
|
|
GateRef attrIndex = HandlerBaseGetAttrIndex(handler);
|
|
GateRef hclass = LoadHClass(receiver);
|
|
GateRef layout = GetLayoutFromHClass(hclass);
|
|
GateRef attr = GetPropAttrFromLayoutInfo(layout, attrIndex);
|
|
GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback);
|
|
BRANCH(IsJSShared(receiver), &exit, &handleUnShared);
|
|
Bind(&handleUnShared);
|
|
{
|
|
BRANCH(Equal(attr, newAttr), &exit, &updateLayout);
|
|
Bind(&updateLayout);
|
|
{
|
|
UpdateFieldType(glue, LoadHClass(receiver), newAttr);
|
|
callback.TryPreDump();
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef attr,
|
|
GateRef value, ProfileOperation callback)
|
|
{
|
|
if (callback.IsEmpty()) {
|
|
return;
|
|
}
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->SubCfgEntry(&entry);
|
|
Label exit(env);
|
|
Label updateLayout(env);
|
|
Label isNotJSShared(env);
|
|
BRANCH(IsJSShared(receiver), &exit, &isNotJSShared);
|
|
Bind(&isNotJSShared);
|
|
GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback);
|
|
BRANCH(Equal(attr, newAttr), &exit, &updateLayout);
|
|
Bind(&updateLayout);
|
|
{
|
|
UpdateFieldType(glue, LoadHClass(receiver), newAttr);
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::TaggedToTrackType(GateRef value)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label entry(env);
|
|
env->SubCfgEntry(&entry);
|
|
|
|
DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
|
|
Label exit(env);
|
|
Label isInt(env);
|
|
Label notInt(env);
|
|
BRANCH(TaggedIsInt(value), &isInt, ¬Int);
|
|
Bind(&isInt);
|
|
{
|
|
newTrackType = Int32(static_cast<int32_t>(TrackType::INT));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬Int);
|
|
{
|
|
Label isObject(env);
|
|
Label isDouble(env);
|
|
BRANCH(TaggedIsObject(value), &isObject, &isDouble);
|
|
Bind(&isObject);
|
|
{
|
|
newTrackType = Int32(static_cast<int32_t>(TrackType::TAGGED));
|
|
Jump(&exit);
|
|
}
|
|
Bind(&isDouble);
|
|
{
|
|
newTrackType = Int32(static_cast<int32_t>(TrackType::DOUBLE));
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *newTrackType;
|
|
env->SubCfgExit();
|
|
return ret;
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileBranch(
|
|
GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef profileTypeInfo, bool isTrue)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label profiler(env);
|
|
Label icSlotValid(env);
|
|
Label hasSlot(env);
|
|
Label currentIsTrue(env);
|
|
Label currentIsFalse(env);
|
|
Label genCurrentWeight(env);
|
|
Label compareLabel(env);
|
|
Label updateSlot(env);
|
|
Label preProfile(env);
|
|
Label needUpdate(env);
|
|
Label exit(env);
|
|
DEFVARIABLE(oldPrama, VariableType::INT32(), Int32(PGOSampleType::None()));
|
|
DEFVARIABLE(newTrue, VariableType::INT32(), isTrue ? Int32(1) : Int32(0));
|
|
DEFVARIABLE(newFalse, VariableType::INT32(), isTrue ? Int32(0) : Int32(1));
|
|
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
|
|
Bind(&profiler);
|
|
{
|
|
GateRef slotId = GetSlotID(slotInfo);
|
|
GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
|
|
Bind(&icSlotValid);
|
|
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
|
|
BRANCH(TaggedIsHole(slotValue), &exit, &hasSlot); // ishole -- isundefined
|
|
Bind(&hasSlot);
|
|
{
|
|
Label uninitialized(env);
|
|
BRANCH(TaggedIsInt(slotValue), &compareLabel, &uninitialized);
|
|
Bind(&compareLabel);
|
|
{
|
|
GateRef oldSlotValue = TaggedGetInt(slotValue);
|
|
GateRef oldTrue = Int32LSR(oldSlotValue, Int32(PGOSampleType::WEIGHT_TRUE_START_BIT));
|
|
GateRef oldFalse = Int32LSR(oldSlotValue, Int32(PGOSampleType::WEIGHT_START_BIT));
|
|
oldFalse = Int32And(oldFalse, Int32(PGOSampleType::WEIGHT_MASK));
|
|
oldPrama = Int32And(oldSlotValue, Int32(PGOSampleType::AnyType()));
|
|
auto condition = BoolAnd(Int32LessThan(oldTrue, Int32(PGOSampleType::WEIGHT_THRESHOLD)),
|
|
Int32LessThan(oldFalse, Int32(PGOSampleType::WEIGHT_THRESHOLD)));
|
|
BRANCH(condition, &needUpdate, &exit); // WEIGHT_THRESHOLD: 2047 limit
|
|
Bind(&needUpdate);
|
|
{
|
|
newTrue = Int32Add(*newTrue, oldTrue);
|
|
newFalse = Int32Add(*newFalse, oldFalse);
|
|
Jump(&updateSlot);
|
|
}
|
|
}
|
|
Bind(&uninitialized);
|
|
{
|
|
// Only when slot value is undefined, it means uninitialized, so we need to update the slot.
|
|
// When the slot value is hole, it means slot is overflow (0xff). Otherwise, do nothing.
|
|
BRANCH(TaggedIsUndefined(slotValue), &updateSlot, &exit);
|
|
}
|
|
Bind(&updateSlot);
|
|
{
|
|
GateRef newSlotValue =
|
|
Int32Or(*oldPrama, Int32LSL(*newTrue, Int32(PGOSampleType::WEIGHT_TRUE_START_BIT)));
|
|
newSlotValue = Int32Or(newSlotValue, Int32LSL(*newFalse, Int32(PGOSampleType::WEIGHT_START_BIT)));
|
|
SetValueToTaggedArray(
|
|
VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newSlotValue));
|
|
auto isFinal = BoolOr(Int32Equal(*newTrue, Int32(PGOSampleType::WEIGHT_THRESHOLD)),
|
|
Int32Equal(*newFalse, Int32(PGOSampleType::WEIGHT_THRESHOLD)));
|
|
BRANCH(isFinal, &preProfile, &exit);
|
|
}
|
|
Bind(&preProfile);
|
|
{
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::TryPreDumpInner(GateRef glue, GateRef func, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label setPreDumpPeriodIndex(env);
|
|
Label isInPredumpWorkList(env);
|
|
Label addPredumpWorkList(env);
|
|
Label exit(env);
|
|
BRANCH(IsProfileTypeInfoPreDumped(profileTypeInfo), &exit, &setPreDumpPeriodIndex);
|
|
Bind(&setPreDumpPeriodIndex);
|
|
{
|
|
SetPreDumpPeriodIndex(glue, profileTypeInfo);
|
|
Jump(&addPredumpWorkList);
|
|
}
|
|
Bind(&addPredumpWorkList);
|
|
{
|
|
CallRuntime(glue, RTSTUB_ID(PGOPreDump), { func });
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterator)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label exit(env);
|
|
|
|
DEFVARIABLE(functionId, VariableType::INT32(), Int32(PGO_BUILTINS_STUB_ID(NONE)));
|
|
DEFVARIABLE(maybeFunc, VariableType::JS_ANY(), Undefined());
|
|
Label isArrayProtoValues(env);
|
|
Label notArrayProtoValues(env);
|
|
Label isSetProtoValues(env);
|
|
Label notSetProtoValues(env);
|
|
Label isMapProtoEntries(env);
|
|
Label notMapProtoEntries(env);
|
|
Label isStringProtoIter(env);
|
|
Label notStringProtoIter(env);
|
|
Label isTypedArrayProtoValues(env);
|
|
|
|
GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
|
|
GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
|
|
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_PROTO_VALUES_FUNCTION_INDEX);
|
|
BRANCH(Int64Equal(iterator, *maybeFunc), &isArrayProtoValues, ¬ArrayProtoValues);
|
|
Bind(&isArrayProtoValues);
|
|
{
|
|
functionId = Int32(PGO_BUILTINS_STUB_ID(ArrayProtoIterator));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬ArrayProtoValues);
|
|
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::SET_PROTO_VALUES_FUNCTION_INDEX);
|
|
BRANCH(Int64Equal(iterator, *maybeFunc), &isSetProtoValues, ¬SetProtoValues);
|
|
Bind(&isSetProtoValues);
|
|
{
|
|
functionId = Int32(PGO_BUILTINS_STUB_ID(SetProtoIterator));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬SetProtoValues);
|
|
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::MAP_PROTO_ENTRIES_FUNCTION_INDEX);
|
|
BRANCH(Int64Equal(iterator, *maybeFunc), &isMapProtoEntries, ¬MapProtoEntries);
|
|
Bind(&isMapProtoEntries);
|
|
{
|
|
functionId = Int32(PGO_BUILTINS_STUB_ID(MapProtoIterator));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬MapProtoEntries);
|
|
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::STRING_PROTO_ITER_FUNCTION_INDEX);
|
|
BRANCH(Int64Equal(iterator, *maybeFunc), &isStringProtoIter, ¬StringProtoIter);
|
|
Bind(&isStringProtoIter);
|
|
{
|
|
functionId = Int32(PGO_BUILTINS_STUB_ID(StringProtoIterator));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬StringProtoIter);
|
|
maybeFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
|
|
GlobalEnv::TYPED_ARRAY_PROTO_VALUES_FUNCTION_INDEX);
|
|
BRANCH(Int64Equal(iterator, *maybeFunc), &isTypedArrayProtoValues, &exit);
|
|
Bind(&isTypedArrayProtoValues);
|
|
{
|
|
functionId = Int32(PGO_BUILTINS_STUB_ID(TypeArrayProtoIterator));
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *functionId;
|
|
env->SubCfgExit();
|
|
return ret;
|
|
}
|
|
|
|
void ProfilerStubBuilder::ProfileGetIterator(
|
|
GateRef glue, SlotIDInfo slotInfo, GateRef func, GateRef iterator, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
Label exit(env);
|
|
Label profiler(env);
|
|
BRANCH(IsProfileTypeInfoHotAndValid(profileTypeInfo), &profiler, &exit);
|
|
Bind(&profiler);
|
|
{
|
|
Label icSlotValid(env);
|
|
Label updateSlot(env);
|
|
Label initSlot(env);
|
|
Label sameValueCheck(env);
|
|
Label invalidate(env);
|
|
Label notOverflow(env);
|
|
|
|
GateRef slotId = GetSlotID(slotInfo);
|
|
GateRef length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit);
|
|
Bind(&icSlotValid);
|
|
GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
|
|
BRANCH(TaggedIsHole(slotValue), &exit, ¬Overflow); // hole -- slot is overflow
|
|
Bind(¬Overflow);
|
|
BRANCH(TaggedIsInt(slotValue), &updateSlot, &initSlot);
|
|
Bind(&updateSlot);
|
|
GateRef oldIterKind = TaggedGetInt(slotValue);
|
|
BRANCH(Int32Equal(oldIterKind, Int32(PGO_BUILTINS_STUB_ID(NONE))),
|
|
&exit, &sameValueCheck);
|
|
Bind(&sameValueCheck);
|
|
{
|
|
GateRef newIterKind = GetIterationFunctionId(glue, iterator);
|
|
BRANCH(Int32Equal(oldIterKind, newIterKind), &exit, &invalidate);
|
|
}
|
|
Bind(&invalidate);
|
|
{
|
|
GateRef invalidKind = Int32(PGO_BUILTINS_STUB_ID(NONE));
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(invalidKind));
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
Bind(&initSlot);
|
|
{
|
|
GateRef newIterKind = GetIterationFunctionId(glue, iterator);
|
|
SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(newIterKind));
|
|
TryPreDumpInner(glue, func, profileTypeInfo);
|
|
Jump(&exit);
|
|
}
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetSlotID(const SlotIDInfo &slotInfo)
|
|
{
|
|
auto slotType = slotInfo.GetSlotType();
|
|
if (slotType == SlotIDInfo::SlotIDInfoType::SLOT_ID) {
|
|
return slotInfo.GetSlotID();
|
|
}
|
|
if (slotType == SlotIDInfo::SlotIDInfoType::PC) {
|
|
// for PROFILE_BRANCH
|
|
return ZExtInt8ToInt32(Load(VariableType::INT8(), slotInfo.GetPC(), IntPtr(1)));
|
|
}
|
|
ASSERT(slotType == SlotIDInfo::SlotIDInfoType::PC_FORMAT);
|
|
auto format = slotInfo.GetFormat();
|
|
auto pc = slotInfo.GetPC();
|
|
if (format == SlotIDFormat::IMM16) {
|
|
auto hight = Load(VariableType::INT8(), pc, IntPtr(2)); // 2 : skip 1 byte of bytecode
|
|
hight = Int16LSL(ZExtInt8ToInt16(hight), Int16(8)); // 8 : set as high 8 bits
|
|
auto low = Load(VariableType::INT8(), pc, IntPtr(1));
|
|
auto result = Int16Add(hight, ZExtInt8ToInt16(low));
|
|
return ZExtInt16ToInt32(result);
|
|
} else if (format == SlotIDFormat::PREF_IMM8) {
|
|
return ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(2)));
|
|
}
|
|
return ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(1)));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetBitFieldOffsetFromProfileTypeInfo(GateRef profileTypeInfo)
|
|
{
|
|
auto length = GetLengthOfTaggedArray(profileTypeInfo);
|
|
auto index = Int32Sub(length, Int32(ProfileTypeInfo::BIT_FIELD_INDEX));
|
|
auto indexOffset = PtrMul(ZExtInt32ToPtr(index), IntPtr(JSTaggedValue::TaggedTypeSize()));
|
|
return PtrAdd(indexOffset, IntPtr(TaggedArray::DATA_OFFSET));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::IsProfileTypeInfoDumped(GateRef profileTypeInfo)
|
|
{
|
|
GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
|
|
return Int32Equal(count, Int32(ProfileTypeInfo::DUMP_PERIOD_INDEX));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::IsProfileTypeInfoPreDumped(GateRef profileTypeInfo)
|
|
{
|
|
GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
|
|
return Int32Equal(count, Int32(ProfileTypeInfo::PRE_DUMP_PERIOD_INDEX));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::IsProfileTypeInfoWithBigMethod(GateRef profileTypeInfo)
|
|
{
|
|
GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
GateRef count = Load(VariableType::INT32(), profileTypeInfo, periodCounterOffset);
|
|
return Int32Equal(count, Int32(ProfileTypeInfo::BIG_METHOD_PERIOD_INDEX));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::IsProfileTypeInfoHotAndValid(GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label exit(env);
|
|
Label isHot(env);
|
|
Label hotAndValid(env);
|
|
DEFVARIABLE(res, VariableType::BOOL(), Boolean(false));
|
|
BRANCH(TaggedIsUndefined(profileTypeInfo), &exit, &isHot);
|
|
Bind(&isHot);
|
|
{
|
|
res = BoolNot(IsProfileTypeInfoWithBigMethod(profileTypeInfo));
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
auto ret = *res;
|
|
env->SubCfgExit();
|
|
return ret;
|
|
}
|
|
|
|
void ProfilerStubBuilder::SetDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)
|
|
{
|
|
GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
GateRef newCount = Int32(ProfileTypeInfo::DUMP_PERIOD_INDEX);
|
|
Store(VariableType::INT32(), glue, profileTypeInfo, periodCounterOffset, newCount);
|
|
}
|
|
|
|
void ProfilerStubBuilder::SetPreDumpPeriodIndex(GateRef glue, GateRef profileTypeInfo)
|
|
{
|
|
GateRef periodCounterOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
GateRef newCount = Int32(ProfileTypeInfo::PRE_DUMP_PERIOD_INDEX);
|
|
Store(VariableType::INT32(), glue, profileTypeInfo, periodCounterOffset, newCount);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::IsCompiledOrTryCompile(GateRef glue, GateRef func, GateRef profileTypeInfo,
|
|
ProfileOperation callback)
|
|
{
|
|
if (callback.IsEmpty() && callback.IsJitEmpty()) {
|
|
return Boolean(true);
|
|
}
|
|
return IsCompiledOrTryCompile(glue, func, profileTypeInfo);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitHotnessThresholdOffset(GateRef profileTypeInfo)
|
|
{
|
|
GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
return PtrAdd(bitFieldOffset,
|
|
IntPtr(ProfileTypeInfo::JIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitHotnessCntOffset(GateRef profileTypeInfo)
|
|
{
|
|
GateRef thresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
|
|
return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::JIT_CNT_OFFSET_FROM_THRESHOLD));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitHotnessCnt(GateRef profileTypeInfo)
|
|
{
|
|
GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
|
|
GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset);
|
|
return ZExtInt16ToInt32(hotnessCnt);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitHotnessThreshold(GateRef profileTypeInfo)
|
|
{
|
|
GateRef hotnessThresholdOffset = GetJitHotnessThresholdOffset(profileTypeInfo);
|
|
GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
|
|
return ZExtInt16ToInt32(hotnessThreshold);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitCallThresholdOffset(GateRef profileTypeInfo)
|
|
{
|
|
GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
return PtrAdd(bitFieldOffset,
|
|
IntPtr(ProfileTypeInfo::JIT_CALL_THRESHOLD_OFFSET_FROM_BITFIELD));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitCallThreshold(GateRef profileTypeInfo)
|
|
{
|
|
GateRef jitCallThresholdOffset = GetJitCallThresholdOffset(profileTypeInfo);
|
|
GateRef jitCallThreshold = Load(VariableType::INT8(), profileTypeInfo, jitCallThresholdOffset);
|
|
return ZExtInt8ToInt32(jitCallThreshold);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitCallCntOffset(GateRef profileTypeInfo)
|
|
{
|
|
GateRef jitCallThresholdOffset = GetJitCallThresholdOffset(profileTypeInfo);
|
|
return PtrAdd(jitCallThresholdOffset, IntPtr(ProfileTypeInfo::JIT_CALL_CNT_OFFSET_FROM_JIT_CALL_THRESHOLD));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetJitCallCnt(GateRef profileTypeInfo)
|
|
{
|
|
GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo);
|
|
GateRef jitCallCnt = Load(VariableType::INT8(), profileTypeInfo, jitCallCntOffset);
|
|
return ZExtInt8ToInt32(jitCallCnt);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetOsrHotnessThresholdOffset(GateRef profileTypeInfo)
|
|
{
|
|
GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
return PtrAdd(bitFieldOffset,
|
|
IntPtr(ProfileTypeInfo::OSR_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetOsrHotnessThreshold(GateRef profileTypeInfo)
|
|
{
|
|
GateRef hotnessThresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo);
|
|
GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
|
|
return ZExtInt16ToInt32(hotnessThreshold);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetBaselineJitHotnessThresholdOffset(GateRef profileTypeInfo)
|
|
{
|
|
GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo);
|
|
return PtrAdd(bitFieldOffset,
|
|
IntPtr(ProfileTypeInfo::BASELINEJIT_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetBaselineJitHotnessThreshold(GateRef profileTypeInfo)
|
|
{
|
|
GateRef hotnessThresholdOffset = GetBaselineJitHotnessThresholdOffset(profileTypeInfo);
|
|
GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset);
|
|
return ZExtInt16ToInt32(hotnessThreshold);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetOsrHotnessCntOffset(GateRef profileTypeInfo)
|
|
{
|
|
GateRef thresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo);
|
|
return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::OSR_CNT_OFFSET_FROM_OSR_THRESHOLD));
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::GetOsrHotnessCnt(GateRef profileTypeInfo)
|
|
{
|
|
GateRef hotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo);
|
|
GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset);
|
|
return ZExtInt16ToInt32(hotnessCnt);
|
|
}
|
|
|
|
GateRef ProfilerStubBuilder::IsCompiledOrTryCompile(GateRef glue, GateRef func, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
|
|
DEFVARIABLE(result, VariableType::BOOL(), False());
|
|
|
|
GateRef hotnessThreshold = GetJitHotnessThreshold(profileTypeInfo);
|
|
GateRef hotnessCnt = GetJitHotnessCnt(profileTypeInfo);
|
|
GateRef jitCallThreshold = GetJitCallThreshold(profileTypeInfo);
|
|
GateRef jitCallCnt = GetJitCallCnt(profileTypeInfo);
|
|
|
|
Label cmpJitHotnessCnt(env);
|
|
Label checkJitCallThreshold(env);
|
|
Label cmpJitCallThreshold(env);
|
|
Label equalJitCallThreshold(env);
|
|
Label notEqualJitCallThreshold(env);
|
|
Label incJitCallCnt(env);
|
|
Label setResultAsTrue(env);
|
|
Label exit(env);
|
|
|
|
Branch(Int32Equal(hotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)), &setResultAsTrue, &cmpJitHotnessCnt);
|
|
Bind(&cmpJitHotnessCnt);
|
|
BRANCH(Int32GreaterThan(hotnessCnt, hotnessThreshold), &setResultAsTrue, &checkJitCallThreshold);
|
|
Bind(&checkJitCallThreshold);
|
|
BRANCH(Int32Equal(jitCallThreshold, Int32(ProfileTypeInfo::INITIAL_JIT_CALL_THRESHOLD)),
|
|
&exit, &cmpJitCallThreshold);
|
|
Bind(&cmpJitCallThreshold);
|
|
BRANCH(Int32Equal(jitCallCnt, jitCallThreshold), &equalJitCallThreshold, ¬EqualJitCallThreshold);
|
|
Bind(&equalJitCallThreshold);
|
|
{
|
|
DEFVARIABLE(invalidOsrOffset, VariableType::INT32(), Int32(MachineCode::INVALID_OSR_OFFSET));
|
|
CallRuntime(glue, RTSTUB_ID(JitCompile), { func, IntToTaggedInt(*invalidOsrOffset) });
|
|
GateRef newJitCallCnt = Int32Add(jitCallCnt, Int32(1));
|
|
GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo);
|
|
Store(VariableType::INT8(), glue, profileTypeInfo, jitCallCntOffset, TruncInt32ToInt8(newJitCallCnt));
|
|
Jump(&setResultAsTrue);
|
|
}
|
|
Bind(¬EqualJitCallThreshold);
|
|
BRANCH(Int32LessThan(jitCallCnt, jitCallThreshold), &incJitCallCnt, &setResultAsTrue);
|
|
Bind(&incJitCallCnt);
|
|
{
|
|
GateRef newJitCallCnt = Int32Add(jitCallCnt, Int32(1));
|
|
GateRef jitCallCntOffset = GetJitCallCntOffset(profileTypeInfo);
|
|
Store(VariableType::INT8(), glue, profileTypeInfo, jitCallCntOffset, TruncInt32ToInt8(newJitCallCnt));
|
|
Jump(&exit);
|
|
}
|
|
Bind(&setResultAsTrue);
|
|
result = True();
|
|
Jump(&exit);
|
|
Bind(&exit);
|
|
GateRef ret = *result;
|
|
env->SubCfgExit();
|
|
return ret;
|
|
}
|
|
|
|
void ProfilerStubBuilder::TryJitCompile(GateRef glue, OffsetInfo offsetInfo,
|
|
GateRef func, GateRef profileTypeInfo)
|
|
{
|
|
auto env = GetEnvironment();
|
|
Label subEntry(env);
|
|
env->SubCfgEntry(&subEntry);
|
|
Label equalJitThreshold(env);
|
|
Label equalBaselineJitThreshold(env);
|
|
Label notEqualJitThreshold(env);
|
|
Label checkEqualJitThreshold(env);
|
|
Label incJitHotnessCntAndCmpOpcode(env);
|
|
Label incJitHotnessCntAndExit(env);
|
|
Label cmpOpcode(env);
|
|
Label cmpOsrThreshold(env);
|
|
Label equalOsrThreshold(env);
|
|
Label notEqualOsrThreshold(env);
|
|
Label incOsrHotnessCnt(env);
|
|
Label checkFastJit(env);
|
|
Label checkBaselineJit(env);
|
|
Label exit(env);
|
|
Label checkNeedIncHotnessCnt(env);
|
|
|
|
GateRef jitHotnessThreshold = GetJitHotnessThreshold(profileTypeInfo);
|
|
GateRef jitHotnessCnt = GetJitHotnessCnt(profileTypeInfo);
|
|
GateRef osrHotnessThreshold = GetOsrHotnessThreshold(profileTypeInfo);
|
|
GateRef osrHotnessCnt = GetOsrHotnessCnt(profileTypeInfo);
|
|
GateRef baselineJitHotnessThreshold = GetBaselineJitHotnessThreshold(profileTypeInfo);
|
|
Branch(Int32Equal(baselineJitHotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)),
|
|
&checkFastJit, &checkBaselineJit);
|
|
|
|
Bind(&checkBaselineJit);
|
|
BRANCH(Int32Equal(jitHotnessCnt, baselineJitHotnessThreshold),
|
|
&equalBaselineJitThreshold, &checkFastJit);
|
|
Bind(&equalBaselineJitThreshold);
|
|
{
|
|
CallRuntime(glue, RTSTUB_ID(BaselineJitCompile), { func });
|
|
Jump(&checkFastJit);
|
|
}
|
|
|
|
Bind(&checkFastJit);
|
|
Branch(Int32Equal(jitHotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)),
|
|
&checkNeedIncHotnessCnt, &checkEqualJitThreshold);
|
|
Bind(&checkNeedIncHotnessCnt);
|
|
Branch(Int32Equal(baselineJitHotnessThreshold, Int32(ProfileTypeInfo::JIT_DISABLE_FLAG)),
|
|
&exit, &incJitHotnessCntAndExit);
|
|
|
|
Bind(&checkEqualJitThreshold);
|
|
BRANCH(Int32Equal(jitHotnessCnt, jitHotnessThreshold), &equalJitThreshold, ¬EqualJitThreshold);
|
|
Bind(&equalJitThreshold);
|
|
{
|
|
DEFVARIABLE(varOffset, VariableType::INT32(), Int32(MachineCode::INVALID_OSR_OFFSET));
|
|
CallRuntime(glue, RTSTUB_ID(JitCompile), { func, IntToTaggedInt(*varOffset) });
|
|
Jump(&incJitHotnessCntAndExit);
|
|
}
|
|
Bind(¬EqualJitThreshold);
|
|
{
|
|
BRANCH(Int32LessThan(jitHotnessCnt, jitHotnessThreshold), &incJitHotnessCntAndCmpOpcode, &exit);
|
|
}
|
|
Bind(&incJitHotnessCntAndCmpOpcode);
|
|
{
|
|
#if ECMASCRIPT_ENABLE_JIT_WARMUP_PROFILER
|
|
CallRuntime(glue, RTSTUB_ID(CountInterpExecFuncs), { func });
|
|
#endif
|
|
GateRef newJitHotnessCnt = Int16Add(jitHotnessCnt, Int16(1));
|
|
GateRef jitHotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
|
|
Store(VariableType::INT16(), glue, profileTypeInfo, jitHotnessCntOffset, newJitHotnessCnt);
|
|
Jump(&cmpOpcode);
|
|
}
|
|
Bind(&incJitHotnessCntAndExit);
|
|
{
|
|
GateRef newJitHotnessCnt = Int16Add(jitHotnessCnt, Int16(1));
|
|
GateRef jitHotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo);
|
|
Store(VariableType::INT16(), glue, profileTypeInfo, jitHotnessCntOffset, newJitHotnessCnt);
|
|
Jump(&exit);
|
|
}
|
|
Bind(&cmpOpcode);
|
|
{
|
|
GateRef isJmp = 0;
|
|
if (offsetInfo.isPc) {
|
|
GateRef opcode = Load(VariableType::INT8(), offsetInfo.pc);
|
|
GateRef jmpImm8 = Int8(static_cast<uint8_t>(EcmaOpcode::JMP_IMM8));
|
|
GateRef jmpImm16 = Int8(static_cast<uint8_t>(EcmaOpcode::JMP_IMM16));
|
|
GateRef jmpImm32 = Int8(static_cast<uint8_t>(EcmaOpcode::JMP_IMM32));
|
|
isJmp = BoolOr(Int8Equal(opcode, jmpImm8), Int8Equal(opcode, jmpImm16));
|
|
isJmp = BoolOr(isJmp, Int8Equal(opcode, jmpImm32));
|
|
} else {
|
|
isJmp = Boolean(offsetInfo.offset == 0);
|
|
}
|
|
BRANCH(isJmp, &cmpOsrThreshold, &exit);
|
|
}
|
|
Bind(&cmpOsrThreshold);
|
|
{
|
|
BRANCH(Int32Equal(osrHotnessCnt, osrHotnessThreshold), &equalOsrThreshold, ¬EqualOsrThreshold);
|
|
}
|
|
Bind(&equalOsrThreshold);
|
|
{
|
|
GateRef method = GetMethodFromJSFunctionOrProxy(func);
|
|
GateRef firstPC = Load(VariableType::NATIVE_POINTER(), method,
|
|
IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
|
|
GateRef offset = offsetInfo.isPc ? TaggedPtrToTaggedIntPtr(PtrSub(offsetInfo.pc, firstPC))
|
|
: offsetInfo.offset;
|
|
CallRuntime(glue, RTSTUB_ID(JitCompile), { func, offset });
|
|
GateRef osrHotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo);
|
|
Store(VariableType::INT16(), glue, profileTypeInfo, osrHotnessCntOffset, Int16(0));
|
|
Jump(&exit);
|
|
}
|
|
Bind(¬EqualOsrThreshold);
|
|
{
|
|
BRANCH(Int32LessThan(osrHotnessCnt, osrHotnessThreshold), &incOsrHotnessCnt, &exit);
|
|
}
|
|
Bind(&incOsrHotnessCnt);
|
|
{
|
|
GateRef newOsrHotnessCnt = Int16Add(osrHotnessCnt, Int16(1));
|
|
GateRef osrHotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo);
|
|
Store(VariableType::INT16(), glue, profileTypeInfo, osrHotnessCntOffset, newOsrHotnessCnt);
|
|
Jump(&exit);
|
|
}
|
|
Bind(&exit);
|
|
env->SubCfgExit();
|
|
}
|
|
|
|
void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef func, GateRef profileTypeInfo,
|
|
SlotIDInfo slotIdInfo, const std::vector<GateRef> &values, OperationType type)
|
|
{
|
|
switch (type) {
|
|
case OperationType::CALL:
|
|
ProfileCall(glue, slotIdInfo, func, values[0], profileTypeInfo);
|
|
break;
|
|
case OperationType::NATIVE_CALL:
|
|
ProfileNativeCall(glue, slotIdInfo, func, values[0], profileTypeInfo);
|
|
break;
|
|
case OperationType::GETTER_SETTER_CALL:
|
|
ProfileGetterSetterCall(glue, values[0]);
|
|
break;
|
|
case OperationType::OPERATION_TYPE:
|
|
ProfileOpType(glue, slotIdInfo, func, profileTypeInfo, values[0]);
|
|
break;
|
|
case OperationType::DEFINE_CLASS:
|
|
ProfileDefineClass(glue, slotIdInfo, func, values[0], profileTypeInfo);
|
|
break;
|
|
case OperationType::CREATE_OBJECT:
|
|
ProfileCreateObject(glue, slotIdInfo, func, values[0], profileTypeInfo);
|
|
break;
|
|
case OperationType::TRY_DUMP:
|
|
TryDump(glue, func, profileTypeInfo);
|
|
break;
|
|
case OperationType::TRY_PREDUMP:
|
|
TryPreDump(glue, func, profileTypeInfo);
|
|
break;
|
|
case OperationType::TRUE_BRANCH:
|
|
ProfileBranch(glue, slotIdInfo, func, profileTypeInfo, true);
|
|
break;
|
|
case OperationType::FALSE_BRANCH:
|
|
ProfileBranch(glue, slotIdInfo, func, profileTypeInfo, false);
|
|
break;
|
|
case OperationType::ITERATOR_FUNC_KIND:
|
|
ProfileGetIterator(glue, slotIdInfo, func, values[0], profileTypeInfo);
|
|
break;
|
|
case OperationType::TRY_JIT:
|
|
TryJitCompile(glue, { 0, slotIdInfo.GetPC(), true }, func, profileTypeInfo);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} // namespace panda::ecmascript::kungfu
|