* Copyright (c) 2024-2026 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/jit/jit_profiler.h"
#include "ecmascript/compiler/lazy_deopt_dependency.h"
#include "ecmascript/compiler/jit_compilation_env.h"
#include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
#include "ecmascript/enum_conversion.h"
#include "ecmascript/interpreter/interpreter-inl.h"
#include "ecmascript/jit/jit.h"
namespace panda::ecmascript {
using namespace pgo;
JITProfiler::JITProfiler(EcmaVM *vm) : vm_(vm)
{
}
void JITProfiler::ProfileBytecode(JSThread *thread, const JSHandle<ProfileTypeInfo> &profileTypeInfo, EntityId methodId,
ApEntityId abcId, const uint8_t *pcStart, uint32_t codeSize,
[[maybe_unused]] const panda_file::File::Header *header,
JSHandle<JSFunction> jsFunction, JSHandle<GlobalEnv> env)
{
Clear();
jsFunction_ = jsFunction;
SetCurrentGlobalEnv(env);
{
Jit::JitLockHolder lock(thread);
profileTypeInfo_ = profileTypeInfo;
if (profileTypeInfo_.GetTaggedType() == 0) {
return;
}
}
abcId_ = abcId;
methodId_ = methodId;
pcStart_ = pcStart;
BytecodeInstruction bcIns(pcStart);
auto bcInsLast = bcIns.JumpTo(codeSize);
while (bcIns.GetAddress() != bcInsLast.GetAddress()) {
auto opcode = bcIns.GetOpcode();
auto bcOffset = bcIns.GetAddress() - pcStart;
auto pc = bcIns.GetAddress();
SetBcOffsetBool(bcOffset);
switch (opcode) {
case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
case EcmaOpcode::LDOBJBYNAME_IMM8_ID16: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertICByName(bcOffset, slotId, BCType::LOAD);
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
break;
}
case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
Jit::JitLockHolder lock(thread);
uint16_t slotId = READ_INST_16_0();
ConvertICByName(bcOffset, slotId, BCType::LOAD);
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
break;
}
case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
case EcmaOpcode::LDTHISBYVALUE_IMM8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertICByValue(bcOffset, slotId, BCType::LOAD);
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
break;
}
case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
case EcmaOpcode::LDTHISBYVALUE_IMM16: {
Jit::JitLockHolder lock(thread);
uint16_t slotId = READ_INST_16_0();
ConvertICByValue(bcOffset, slotId, BCType::LOAD);
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
break;
}
case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16: {
Jit::JitLockHolder lock(thread);
uint32_t slotId = READ_INST_8_0();
ASSERT(bcOffset >= 0);
ConvertTryldGlobalByName(static_cast<uint32_t>(bcOffset), slotId);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16: {
Jit::JitLockHolder lock(thread);
uint32_t slotId = READ_INST_16_0();
ASSERT(bcOffset >= 0);
ConvertTryldGlobalByName(static_cast<uint32_t>(bcOffset), slotId);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertICByName(bcOffset, slotId, BCType::STORE);
if (opcode != EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8) {
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
}
break;
}
case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
Jit::JitLockHolder lock(thread);
uint16_t slotId = READ_INST_16_0();
ConvertICByName(bcOffset, slotId, BCType::STORE);
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
break;
}
case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
case EcmaOpcode::STOWNBYINDEX_IMM8_V8_IMM16:
case EcmaOpcode::STTHISBYVALUE_IMM8_V8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertICByValue(bcOffset, slotId, BCType::STORE);
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
break;
}
case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
case EcmaOpcode::STOWNBYINDEX_IMM16_V8_IMM16:
case EcmaOpcode::STTHISBYVALUE_IMM16_V8: {
Jit::JitLockHolder lock(thread);
uint16_t slotId = READ_INST_16_0();
ConvertICByValue(bcOffset, slotId, BCType::STORE);
UpdateBcOffsetBoolWithNearSlotId(bcOffset, slotId);
break;
}
case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8: {
Jit::JitLockHolder lock(thread);
uint32_t index = READ_INST_8_0();
ConvertExternalModuleVar(index, bcOffset);
break;
}
case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16: {
Jit::JitLockHolder lock(thread);
uint32_t index = READ_INST_16_1();
ConvertExternalModuleVar(index, bcOffset);
break;
}
case EcmaOpcode::ADD2_IMM8_V8:
case EcmaOpcode::SUB2_IMM8_V8:
case EcmaOpcode::MUL2_IMM8_V8:
case EcmaOpcode::DIV2_IMM8_V8:
case EcmaOpcode::MOD2_IMM8_V8:
case EcmaOpcode::SHL2_IMM8_V8:
case EcmaOpcode::SHR2_IMM8_V8:
case EcmaOpcode::AND2_IMM8_V8:
case EcmaOpcode::OR2_IMM8_V8:
case EcmaOpcode::XOR2_IMM8_V8:
case EcmaOpcode::ASHR2_IMM8_V8:
case EcmaOpcode::NEG_IMM8:
case EcmaOpcode::NOT_IMM8:
case EcmaOpcode::INC_IMM8:
case EcmaOpcode::DEC_IMM8:
case EcmaOpcode::EQ_IMM8_V8:
case EcmaOpcode::NOTEQ_IMM8_V8:
case EcmaOpcode::LESS_IMM8_V8:
case EcmaOpcode::LESSEQ_IMM8_V8:
case EcmaOpcode::GREATER_IMM8_V8:
case EcmaOpcode::GREATEREQ_IMM8_V8:
case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
case EcmaOpcode::STRICTEQ_IMM8_V8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertOpType(slotId, bcOffset);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::EXP_IMM8_V8:
case EcmaOpcode::TONUMERIC_IMM8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertOpType(slotId, bcOffset);
break;
}
case EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8:
case EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_1();
CHECK_SLOTID_BREAK(slotId);
ConvertOpType(slotId, bcOffset);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::CALLARG0_IMM8:
case EcmaOpcode::CALLARG1_IMM8_V8:
case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
case EcmaOpcode::CALLTHIS0_IMM8_V8:
case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
case EcmaOpcode::CALLTHIS0WITHNAME_IMM8_ID16_V8:
case EcmaOpcode::CALLTHIS1WITHNAME_IMM8_ID16_V8_V8:
case EcmaOpcode::CALLTHIS2WITHNAME_IMM8_ID16_V8_V8_V8:
case EcmaOpcode::CALLTHIS3WITHNAME_IMM8_ID16_V8_V8_V8_V8:
case EcmaOpcode::CALLTHISRANGEWITHNAME_IMM8_IMM8_ID16_V8:
case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertCall(slotId, bcOffset);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_1();
CHECK_SLOTID_BREAK(slotId);
ConvertCall(slotId, bcOffset);
break;
}
case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
case EcmaOpcode::WIDE_CALLTHISRANGEWITHNAME_PREF_IMM16_ID16_V8: {
break;
}
case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertNewObjRange(slotId, bcOffset);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8: {
Jit::JitLockHolder lock(thread);
uint16_t slotId = READ_INST_16_0();
ConvertNewObjRange(slotId, bcOffset);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8: {
break;
}
case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: {
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
(void) slotId;
break;
}
case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: {
uint16_t slotId = READ_INST_16_0();
(void) slotId;
break;
}
case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8: {
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
break;
}
case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8: {
uint16_t slotId = READ_INST_16_0();
(void) slotId;
break;
}
case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEEMPTYARRAY_IMM8: {
Jit::JitLockHolder lock(thread);
auto traceId =
static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertCreateObject(slotId, bcOffset, traceId);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
case EcmaOpcode::CREATEEMPTYARRAY_IMM16: {
Jit::JitLockHolder lock(thread);
auto traceId =
static_cast<int32_t>(reinterpret_cast<uintptr_t>(pc) - reinterpret_cast<uintptr_t>(header));
uint16_t slotId = READ_INST_16_0();
ConvertCreateObject(slotId, bcOffset, traceId);
UpdateBcOffsetBool(bcOffset, slotId);
break;
}
case EcmaOpcode::GETITERATOR_IMM8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertGetIterator(slotId, bcOffset);
break;
}
case EcmaOpcode::GETITERATOR_IMM16: {
Jit::JitLockHolder lock(thread);
uint16_t slotId = READ_INST_16_0();
ConvertGetIterator(slotId, bcOffset);
break;
}
case EcmaOpcode::INSTANCEOF_IMM8_V8: {
Jit::JitLockHolder lock(thread);
uint8_t slotId = READ_INST_8_0();
CHECK_SLOTID_BREAK(slotId);
ConvertInstanceof(bcOffset, slotId);
break;
}
case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8:
default:
break;
}
bcIns = bcIns.GetNext();
}
}
void JITProfiler::ConvertOpType(uint32_t slotId, long bcOffset)
{
JSTaggedValue slotValue = profileTypeInfo_->Get(mainThread_, slotId);
if (slotValue.IsInt()) {
auto type = slotValue.GetInt();
UpdatePGOType(bcOffset, chunk_->New<PGOSampleType>(type));
}
}
void JITProfiler::ConvertCall(uint32_t slotId, long bcOffset)
{
JSTaggedValue slotValue = profileTypeInfo_->Get(mainThread_, slotId);
ProfileType::Kind kind;
int calleeMethodId = 0;
ApEntityId calleeAbcId = 0;
if (slotValue.IsFuncSlot()) {
auto funcSlot = FuncSlot::Cast(slotValue);
slotValue = funcSlot->GetFunction(mainThread_);
}
if (slotValue.IsInt()) {
calleeMethodId = slotValue.GetInt();
if (calleeMethodId == 0) {
return;
}
calleeAbcId = abcId_;
ASSERT(calleeMethodId <= 0);
kind = ProfileType::Kind::BuiltinFunctionId;
} else if (slotValue.IsJSFunction()) {
auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
auto slotValueHandle = jitCompilationEnv->NewJSHandle(slotValue);
auto callee = JSHandle<JSFunction>::Cast(slotValueHandle);
Method *calleeMethod = Method::Cast(callee->GetMethod(mainThread_));
compilationEnv_->ProcessMethod(calleeMethod->GetMethodLiteral(mainThread_),
calleeMethod->GetJSPandaFile(mainThread_));
calleeMethodId = static_cast<int>(calleeMethod->GetMethodId().GetOffset());
if (compilationEnv_->SupportHeapConstant() &&
calleeMethod->GetFunctionKind() != FunctionKind::ARROW_FUNCTION &&
callee->IsCallable()) {
auto heapConstantIndex = jitCompilationEnv->RecordHeapConstant(slotValueHandle);
if (calleeMethod->GetMethodLiteral(mainThread_)->IsTypedCall() && callee->IsCompiledCode()) {
jitCompilationEnv->RecordCallMethodId2HeapConstantIndex(calleeMethodId, heapConstantIndex);
} else {
jitCompilationEnv->RecordOnlyInlineMethodId2HeapConstantIndex(calleeMethodId, heapConstantIndex);
}
}
calleeAbcId = PGOProfiler::GetMethodAbcId(mainThread_, *callee);
jitCompilationEnv->SetCalleeJSFunction(calleeMethodId, callee);
kind = ProfileType::Kind::MethodId;
} else {
return;
}
PGOSampleType* type = chunk_->New<PGOSampleType>(ProfileType(calleeAbcId, std::abs(calleeMethodId), kind));
UpdatePGOType(bcOffset, type);
}
void JITProfiler::ConvertNewObjRange(uint32_t slotId, long bcOffset)
{
JSTaggedValue slotValue = profileTypeInfo_->Get(mainThread_, slotId);
int ctorMethodId = 0;
JSHClass* hclass = nullptr;
if (slotValue.IsFuncSlot()) {
auto funcSlot = FuncSlot::Cast(slotValue);
slotValue = funcSlot->GetFunction(mainThread_);
}
if (slotValue.IsInt()) {
ctorMethodId = slotValue.GetInt();
if (ctorMethodId > 0) {
return;
}
} else if (slotValue.IsJSFunction()) {
JSFunction *callee = JSFunction::Cast(slotValue);
Method *calleeMethod = Method::Cast(callee->GetMethod(mainThread_));
compilationEnv_->ProcessMethod(calleeMethod->GetMethodLiteral(mainThread_),
calleeMethod->GetJSPandaFile(mainThread_));
ctorMethodId = static_cast<int>(calleeMethod->GetMethodId().GetOffset());
if (compilationEnv_->SupportHeapConstant()) {
auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
JSHandle<JSTaggedValue> calleeHandle = jitCompilationEnv->NewJSHandle(JSTaggedValue(callee));
auto heapConstantIndex = jitCompilationEnv->RecordHeapConstant(calleeHandle);
jitCompilationEnv->RecordCtorMethodId2HeapConstantIndex(ctorMethodId, heapConstantIndex);
}
JSTaggedValue protoOrHClass = callee->GetProtoOrHClass(mainThread_);
if (protoOrHClass.IsJSHClass()) {
hclass = JSHClass::Cast(protoOrHClass.GetTaggedObject());
} else {
return;
}
} else {
return;
}
if (ctorMethodId > 0) {
ptManager_->RecordAndGetHclassIndexForJIT(hclass);
auto pt = ProfileType(abcId_, std::abs(ctorMethodId), ProfileType::Kind::JITClassId, true);
PGODefineOpType* type = chunk_->New<PGODefineOpType>(pt, hclass);
UpdatePGOType(bcOffset, type);
} else {
auto kind = ProfileType::Kind::BuiltinFunctionId;
auto type = chunk_->New<PGOSampleType>(ProfileType(abcId_, std::abs(ctorMethodId), kind));
UpdatePGOType(bcOffset, type);
}
}
void JITProfiler::ConvertGetIterator(uint32_t slotId, long bcOffset)
{
if (mainThread_->GetEnableLazyBuiltins()) {
return;
}
JSTaggedValue value = profileTypeInfo_->Get(mainThread_, slotId);
if (!value.IsInt()) {
return;
}
int iterKind = value.GetInt();
ASSERT(iterKind <= 0);
ProfileType::Kind pgoKind = ProfileType::Kind::BuiltinFunctionId;
auto type = chunk_->New<PGOSampleType>(ProfileType(abcId_, std::abs(iterKind), pgoKind));
UpdatePGOType(bcOffset, type);
}
void JITProfiler::ConvertCreateObject(uint32_t slotId, long bcOffset, [[maybe_unused]]int32_t traceId)
{
JSTaggedValue slotValue = profileTypeInfo_->Get(mainThread_, slotId);
if (!slotValue.IsHeapObject()) {
return;
}
if (slotValue.IsWeak()) {
auto object = slotValue.GetWeakReferentUnChecked();
if (object->GetClass()->IsHClass()) {
auto newHClass = JSHClass::Cast(object);
PGODefineOpType* objDefType = chunk_->New<PGODefineOpType>(ProfileType::CreateJITType(), newHClass);
ptManager_->RecordAndGetHclassIndexForJIT(newHClass);
UpdatePGOType(bcOffset, objDefType);
}
} else if (slotValue.IsTrackInfoObject()) {
TrackInfo *trackInfo = TrackInfo::Cast(slotValue.GetTaggedObject());
auto hclass = JSHClass::Cast(trackInfo->GetCachedHClass(mainThread_).GetTaggedObject());
PGODefineOpType* objDefType = chunk_->New<PGODefineOpType>(ProfileType::CreateJITType(), hclass);
ptManager_->RecordAndGetHclassIndexForJIT(hclass);
auto elementsKind = trackInfo->GetElementsKind();
objDefType->SetElementsKind(elementsKind);
objDefType->SetElementsLength(trackInfo->GetArrayLength());
objDefType->SetSpaceFlag(trackInfo->GetSpaceFlag());
UpdatePGOType(bcOffset, objDefType);
}
}
#if ECMASCRIPT_ENABLE_TRACE_JIT_IC_STATE
void JITProfiler::TraceICState(int32_t bcOffset, std::string_view s)
{
const uint8_t *pc = bcOffset + pcStart_;
auto opcode = kungfu::Bytecodes::GetOpcode(pc);
uint16_t slotId;
BCType type;
switch (opcode) {
case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
case EcmaOpcode::LDOBJBYNAME_IMM8_ID16: {
type = BCType::LOAD;
slotId = READ_INST_8_0();
break;
}
case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8: {
type = BCType::STORE;
slotId = READ_INST_8_0();
break;
}
case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: {
type = BCType::LOAD;
slotId = READ_INST_16_0();
break;
}
case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
case EcmaOpcode::STTHISBYNAME_IMM16_ID16: {
type = BCType::STORE;
slotId = READ_INST_16_0();
break;
}
default:
return;
}
std::string icType;
JSTaggedValue firstValue = profileTypeInfo_->Get(mainThread_, slotId);
if (s != "IC-All") {
if (!firstValue.IsHeapObject()) {
} else if (firstValue.IsWeak()) {
icType = "Mono";
} else {
icType = "Poly";
}
}
std::string out = "(JIT IC Trace) Function Name:";
out += Method::Cast(jsFunction_->GetMethod(mainThread_))->GetMethodName(mainThread_);
out += " ";
out += (type == BCType::LOAD) ? "LOAD" : "STORE";
out += " ";
out += icType;
out += " ";
out += s;
ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, out.c_str(), "");
LOG_JIT(INFO) << out;
}
#else
void JITProfiler::TraceICState(int32_t bcOffset, std::string_view s) {}
#endif
void JITProfiler::ConvertICByName(int32_t bcOffset, uint32_t slotId, BCType type)
{
IcAccessorLockScope accessorLockScope(vm_->GetJSThreadNoCheck());
TraceICState(bcOffset, "IC-All");
JSTaggedValue firstValue = profileTypeInfo_->Get(mainThread_, slotId);
if (!firstValue.IsHeapObject()) {
JSTaggedValue secondValue = profileTypeInfo_->Get(mainThread_, slotId + 1);
if (firstValue.IsHole() && secondValue.IsString()) {
TraceICState(bcOffset, "IC-Mega");
AddObjectInfoWithMega(bcOffset);
return;
}
if (firstValue.IsHole()) {
TraceICState(bcOffset, "IC-Miss");
} else {
TraceICState(bcOffset, "IC-Uninitialized");
}
return;
}
if (firstValue.IsWeak()) {
TaggedObject *object = firstValue.GetWeakReferentUnChecked();
if (object->GetClass()->IsHClass()) {
JSTaggedValue secondValue = profileTypeInfo_->Get(mainThread_, slotId + 1);
JSHClass *hclass = JSHClass::Cast(object);
ConvertICByNameWithHandler(abcId_, bcOffset, hclass, secondValue, type, slotId + 1);
}
return;
}
ConvertICByNameWithPoly(abcId_, bcOffset, firstValue, type, slotId);
}
void JITProfiler::ConvertICByNameWithHandler(ApEntityId abcId, int32_t bcOffset,
JSHClass *hclass,
JSTaggedValue secondValue, BCType type, uint32_t slotId)
{
if (type == BCType::LOAD) {
HandleLoadType(abcId, bcOffset, hclass, secondValue, slotId);
return;
}
HandleOtherTypes(abcId, bcOffset, hclass, secondValue, slotId);
}
void JITProfiler::HandleLoadType(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)
{
if (secondValue.IsInt()) {
HandleLoadTypeInt(abcId, bcOffset, hclass, secondValue);
} else if (secondValue.IsPrototypeHandler()) {
HandleLoadTypePrototypeHandler(abcId, bcOffset, hclass, secondValue, slotId);
} else {
TraceICState(bcOffset, "IC-Other-Handler");
}
}
void JITProfiler::HandleLoadTypeInt(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
if (!HandlerBase::IsNonExist(handlerInfo)) {
if (AddBuiltinsInfoByNameInInstance(abcId, bcOffset, hclass)) {
return;
}
}
if (HandlerBase::IsField(handlerInfo) || HandlerBase::IsAccessor(handlerInfo)) {
if (HandlerBase::IsNonExist(handlerInfo)) {
AddObjectInfo(abcId, bcOffset, hclass, nullptr, nullptr);
} else {
AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass);
}
return;
}
TraceICState(bcOffset, "IC-No-Use");
}
void JITProfiler::HandleLoadTypePrototypeHandler(ApEntityId &abcId, int32_t &bcOffset, JSHClass *hclass,
JSTaggedValue &secondValue, uint32_t slotId, JSTaggedValue name)
{
auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
auto cellValue = prototypeHandler->GetProtoCell(mainThread_);
if (cellValue.IsUndefined()) {
TraceICState(bcOffset, "IC-Cell-Undefined");
return;
}
ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
if (cell->GetHasChanged()) {
TraceICState(bcOffset, "IC-Cell-Changed");
return;
}
JSTaggedValue handlerInfoVal = prototypeHandler->GetHandlerInfo(mainThread_);
auto accessorMethodId = prototypeHandler->GetAccessorMethodId();
auto accessor = prototypeHandler->GetAccessorJSFunction(mainThread_);
if (!handlerInfoVal.IsInt()) {
TraceICState(bcOffset, "IC-Handler-Invalid");
return;
}
auto handlerInfo = static_cast<uint32_t>(handlerInfoVal.GetInt());
JSTaggedValue holder = prototypeHandler->GetHolder(mainThread_);
JSHClass *holderHClass = nullptr;
bool isNonExist = HandlerBase::IsNonExist(handlerInfo);
if (holder.IsHeapObject()) {
holderHClass = holder.GetTaggedObject()->GetClass();
}
if (!kungfu::LazyDeoptAllDependencies::CheckStableProtoChain(mainThread_, hclass, holderHClass,
GetCurrentGlobalEnv().GetObject<GlobalEnv>())) {
TraceICState(bcOffset, "IC-Not-Stable");
return;
}
if (accessor.IsJSFunction()) {
auto jitCompilationEnv = static_cast<JitCompilationEnv *>(compilationEnv_);
auto accessorFunction = JSHandle<JSFunction>::Cast(jitCompilationEnv->NewJSHandle(accessor));
auto methodId = Method::Cast(accessorFunction->GetMethod(mainThread_))->GetMethodId().GetOffset();
ASSERT(accessorMethodId == methodId);
accessorMethodId = methodId;
jitCompilationEnv->SetCalleeJSFunction(accessorMethodId, accessorFunction);
}
if (AddBuiltinsInfoByNameInProt(abcId, bcOffset, hclass, holderHClass, isNonExist)) {
return;
}
if (isNonExist) {
AddObjectInfo(abcId, bcOffset, hclass, nullptr, nullptr);
return;
}
if (compilationEnv_->SupportHeapConstant()) {
auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
JSHandle<JSTaggedValue> holderHandler = jitCompilationEnv->NewJSHandle(holder);
uint32_t heapConstantIndex = jitCompilationEnv->RecordHeapConstant(holderHandler);
int32_t holderHClassIndex = ptManager_->RecordAndGetHclassIndexForJIT(holderHClass);
jitCompilationEnv->RecordHolderHClassIndex2HeapConstantIndex(holderHClassIndex, heapConstantIndex);
}
auto primitiveType = HandlerBase::TryGetPrimitiveType(handlerInfo);
AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass, accessorMethodId, primitiveType, name);
}
void JITProfiler::HandleOtherTypes(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)
{
if (secondValue.IsInt()) {
AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass);
} else if (secondValue.IsTransitionHandler()) {
HandleTransitionHandler(abcId, bcOffset, hclass, secondValue);
} else if (secondValue.IsTransWithProtoHandler()) {
HandleTransWithProtoHandler(abcId, bcOffset, hclass, secondValue);
} else if (secondValue.IsPrototypeHandler()) {
HandleOtherTypesPrototypeHandler(abcId, bcOffset, hclass, secondValue, slotId);
} else if (secondValue.IsPropertyBox()) {
TraceICState(bcOffset, "IC-PropertyBox-Miss");
} else if (secondValue.IsStoreAOTHandler()) {
HandleStoreAOTHandler(abcId, bcOffset, hclass, secondValue);
}
}
void JITProfiler::HandleTransitionHandler(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
auto transitionHClassVal = transitionHandler->GetTransitionHClass(mainThread_);
if (transitionHClassVal.IsJSHClass()) {
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
} else {
TraceICState(bcOffset, "IC-Transition-Miss");
}
}
void JITProfiler::HandleTransWithProtoHandler(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
auto cellValue = transWithProtoHandler->GetProtoCell(mainThread_);
ASSERT(cellValue.IsProtoChangeMarker());
ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
if (cell->GetHasChanged()) {
TraceICState(bcOffset, "IC-Cell-Changed");
return;
}
auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass(mainThread_);
if (transitionHClassVal.IsJSHClass()) {
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
} else {
TraceICState(bcOffset, "IC-Transition-Not-JSHClass");
}
}
void JITProfiler::HandleOtherTypesPrototypeHandler(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue, uint32_t slotId)
{
auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
auto cellValue = prototypeHandler->GetProtoCell(mainThread_);
if (cellValue.IsUndefined()) {
TraceICState(bcOffset, "IC-Cell-Undefined");
return;
}
ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
if (cell->GetHasChanged()) {
TraceICState(bcOffset, "IC-Cell-Changed");
return;
}
auto holder = prototypeHandler->GetHolder(mainThread_);
auto holderHClass = holder.GetTaggedObject()->GetClass();
auto accessorMethodId = prototypeHandler->GetAccessorMethodId();
auto accessor = prototypeHandler->GetAccessorJSFunction(mainThread_);
if (accessor.IsJSFunction()) {
auto jitCompilationEnv = static_cast<JitCompilationEnv *>(compilationEnv_);
auto accessorFunction = JSHandle<JSFunction>::Cast(jitCompilationEnv->NewJSHandle(accessor));
auto methodId = Method::Cast(accessorFunction->GetMethod(mainThread_))->GetMethodId().GetOffset();
ASSERT(accessorMethodId == methodId);
accessorMethodId = methodId;
jitCompilationEnv->SetCalleeJSFunction(accessorMethodId, accessorFunction);
}
AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass, accessorMethodId);
}
void JITProfiler::HandleStoreAOTHandler(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
StoreAOTHandler *storeAOTHandler = StoreAOTHandler::Cast(secondValue.GetTaggedObject());
auto cellValue = storeAOTHandler->GetProtoCell(mainThread_);
ASSERT(cellValue.IsProtoChangeMarker());
ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
if (cell->GetHasChanged()) {
TraceICState(bcOffset, "IC-Cell-Changed");
return;
}
auto holder = storeAOTHandler->GetHolder(mainThread_);
auto holderHClass = holder.GetTaggedObject()->GetClass();
AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass);
}
void JITProfiler::ConvertICByNameWithPoly(ApEntityId abcId, int32_t bcOffset, JSTaggedValue cacheValue, BCType type,
uint32_t slotId)
{
if (cacheValue.IsWeak()) {
return;
}
ASSERT(cacheValue.IsTaggedArray());
auto array = TaggedArray::Cast(cacheValue);
uint32_t length = array->GetLength();
for (uint32_t i = 0; i < length; i += 2) {
auto result = array->Get(mainThread_, i);
auto handler = array->Get(mainThread_, i + 1);
if (!result.IsHeapObject() || !result.IsWeak()) {
continue;
}
TaggedObject *object = result.GetWeakReferentUnChecked();
if (!object->GetClass()->IsHClass()) {
continue;
}
JSHClass *hclass = JSHClass::Cast(object);
ConvertICByNameWithHandler(abcId, bcOffset, hclass, handler, type, slotId);
}
}
void JITProfiler::ConvertICByValue(int32_t bcOffset, uint32_t slotId, BCType type)
{
IcAccessorLockScope accessorLockScope(vm_->GetJSThreadNoCheck());
JSTaggedValue firstValue = profileTypeInfo_->Get(mainThread_, slotId);
if (!firstValue.IsHeapObject()) {
if (firstValue.IsHole()) {
AddObjectInfoWithMega(bcOffset);
}
return;
}
if (firstValue.IsWeak()) {
TaggedObject *object = firstValue.GetWeakReferentUnChecked();
if (object->GetClass()->IsHClass()) {
JSTaggedValue secondValue = profileTypeInfo_->Get(mainThread_, slotId + 1);
JSHClass *hclass = JSHClass::Cast(object);
ConvertICByValueWithHandler(abcId_, bcOffset, hclass, secondValue, type, slotId);
}
return;
}
if ((firstValue.IsString() || firstValue.IsSymbol())) {
JSTaggedValue secondValue = profileTypeInfo_->Get(mainThread_, slotId + 1);
ConvertICByValueWithPoly(abcId_, bcOffset, firstValue, secondValue, type, slotId);
return;
}
ConvertICByValueWithPoly(abcId_, bcOffset, firstValue, firstValue, type, slotId);
}
void JITProfiler::ConvertICByValueWithHandler(ApEntityId abcId, int32_t bcOffset,
JSHClass *hclass, JSTaggedValue secondValue,
BCType type, uint32_t slotId, JSTaggedValue name)
{
if (type == BCType::LOAD) {
if (secondValue.IsInt()) {
auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
if (HandlerBase::NeedSkipInPGODump(handlerInfo)) {
return;
}
AddBuiltinsInfo(abcId, bcOffset, hclass, hclass);
return;
}
if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
OnHeapMode onHeap = HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
AddBuiltinsInfo(abcId, bcOffset, hclass, hclass, onHeap);
return;
}
AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass, INVALID_METHOD_INDEX, PRIMITIVE_TYPE_INVALID, name);
} else if (secondValue.IsPrototypeHandler()) {
HandleLoadTypePrototypeHandler(abcId, bcOffset, hclass, secondValue, slotId, name);
}
return;
}
HandleStoreType(abcId, bcOffset, hclass, secondValue);
}
void JITProfiler::HandleStoreType(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
if (secondValue.IsInt()) {
auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
if (HandlerBase::IsNormalElement(handlerInfo) || HandlerBase::IsStringElement(handlerInfo)) {
AddBuiltinsInfo(abcId, bcOffset, hclass, hclass,
OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
return;
}
if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
OnHeapMode onHeap = HandlerBase::IsOnHeap(handlerInfo) ? OnHeapMode::ON_HEAP : OnHeapMode::NOT_ON_HEAP;
AddBuiltinsInfo(abcId, bcOffset, hclass, hclass, onHeap,
HandlerBase::IsStoreOutOfBounds(handlerInfo));
return;
}
AddObjectInfo(abcId, bcOffset, hclass, hclass, hclass);
} else if (secondValue.IsTransitionHandler()) {
HandleTransition(abcId, bcOffset, hclass, secondValue);
} else if (secondValue.IsTransWithProtoHandler()) {
HandleTransWithProto(abcId, bcOffset, hclass, secondValue);
} else if (secondValue.IsPrototypeHandler()) {
HandlePrototypeHandler(abcId, bcOffset, hclass, secondValue);
}
}
void JITProfiler::HandleTransition(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
auto transitionHandler = TransitionHandler::Cast(secondValue.GetTaggedObject());
auto transitionHClassVal = transitionHandler->GetTransitionHClass(mainThread_);
if (!transitionHClassVal.IsJSHClass()) {
return ;
}
auto handlerInfoValue = transitionHandler->GetHandlerInfo(mainThread_);
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
if (handlerInfoValue.IsInt()) {
auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, bcOffset, hclass, transitionHClass,
OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
return;
}
}
AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
}
void JITProfiler::HandleTransWithProto(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
auto transWithProtoHandler = TransWithProtoHandler::Cast(secondValue.GetTaggedObject());
auto transitionHClassVal = transWithProtoHandler->GetTransitionHClass(mainThread_);
if (!transitionHClassVal.IsJSHClass()) {
return ;
}
auto handlerInfoValue = transWithProtoHandler->GetHandlerInfo(mainThread_);
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
if (handlerInfoValue.IsInt()) {
auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, bcOffset, hclass, transitionHClass,
OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
return;
}
}
AddObjectInfo(abcId, bcOffset, hclass, hclass, transitionHClass);
}
void JITProfiler::HandlePrototypeHandler(ApEntityId &abcId, int32_t &bcOffset,
JSHClass *hclass, JSTaggedValue &secondValue)
{
PrototypeHandler *prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
auto cellValue = prototypeHandler->GetProtoCell(mainThread_);
if (!cellValue.IsProtoChangeMarker()) {
return;
}
ASSERT(cellValue.IsProtoChangeMarker());
ProtoChangeMarker *cell = ProtoChangeMarker::Cast(cellValue.GetTaggedObject());
if (cell->GetHasChanged()) {
return;
}
JSTaggedValue handlerInfoValue = prototypeHandler->GetHandlerInfo(mainThread_);
if (handlerInfoValue.IsInt()) {
auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, bcOffset, hclass, hclass,
OnHeapMode::NONE, HandlerBase::IsStoreOutOfBounds(handlerInfo));
return;
}
}
auto holder = prototypeHandler->GetHolder(mainThread_);
auto holderHClass = holder.GetTaggedObject()->GetClass();
AddObjectInfo(abcId, bcOffset, hclass, holderHClass, holderHClass);
}
void JITProfiler::ConvertICByValueWithPoly(ApEntityId abcId, int32_t bcOffset,
JSTaggedValue name,
JSTaggedValue cacheValue,
BCType type, uint32_t slotId)
{
if (cacheValue.IsWeak()) {
return;
}
if (!cacheValue.IsTaggedArray()) {
return;
}
auto array = TaggedArray::Cast(cacheValue);
uint32_t length = array->GetLength();
for (uint32_t i = 0; i < length; i += 2) {
auto result = array->Get(mainThread_, i);
auto handler = array->Get(mainThread_, i + 1);
if (!result.IsHeapObject() || !result.IsWeak()) {
continue;
}
TaggedObject *object = result.GetWeakReferentUnChecked();
if (!object->GetClass()->IsHClass()) {
continue;
}
JSHClass *hclass = JSHClass::Cast(object);
ConvertICByValueWithHandler(abcId, bcOffset, hclass, handler, type, slotId, name);
}
}
void JITProfiler::ConvertExternalModuleVar(uint32_t index, uint32_t bcOffset)
{
auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
auto jsfunc = *jsFunction_;
if (jsfunc == nullptr) {
return;
}
if (!ModuleManager::CheckModuleValueOutterResolved(mainThread_, index, jsfunc)) {
return;
}
jitCompilationEnv->SetLdExtModuleVarResolved(methodId_.GetOffset(), bcOffset);
}
void JITProfiler::ConvertInstanceof(int32_t bcOffset, uint32_t slotId)
{
JSTaggedValue firstValue = profileTypeInfo_->Get(mainThread_, slotId);
if (!firstValue.IsHeapObject()) {
if (firstValue.IsHole()) {
AddObjectInfoWithMega(bcOffset);
}
return;
}
if (firstValue.IsWeak()) {
TaggedObject *object = firstValue.GetWeakReferentUnChecked();
if (object->GetClass()->IsHClass()) {
JSHClass *hclass = JSHClass::Cast(object);
JSTaggedValue key = mainThread_->GlobalConstants()->GetHasInstanceSymbol();
JSHClass *functionPrototypeHC =
JSObject::Cast(GetCurrentGlobalEnv()->GetFunctionPrototypeWithBarrier().GetTaggedValue())->GetClass();
JSTaggedValue foundHClass = TryFindKeyInPrototypeChain(object, hclass, key);
if (!foundHClass.IsUndefined() && JSHClass::Cast(foundHClass.GetTaggedObject()) != functionPrototypeHC) {
return;
}
AddObjectInfo(abcId_, bcOffset, hclass, hclass, hclass);
}
return;
}
return;
}
void JITProfiler::ConvertTryldGlobalByName(uint32_t bcOffset, uint32_t slotId)
{
auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
if (!jitCompilationEnv->SupportHeapConstant()) {
return;
}
JSTaggedValue handler = profileTypeInfo_->Get(mainThread_, slotId);
if (handler.IsHeapObject()) {
ASSERT(handler.IsPropertyBox());
PropertyBox *cell = PropertyBox::Cast(handler.GetTaggedObject());
if (cell->IsInvalid(mainThread_) || cell->GetValue(mainThread_).IsAccessorData()) {
return;
}
JSHandle<JSTaggedValue> boxHandle = jitCompilationEnv->NewJSHandle(handler);
uint32_t heapConstantIndex = jitCompilationEnv->RecordHeapConstant(boxHandle);
if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
jitCompilationEnv->RecordLdGlobalByNameBcOffset2HeapConstantIndex(methodId_.GetOffset(),
bcOffset, heapConstantIndex);
}
}
}
JSTaggedValue JITProfiler::TryFindKeyInPrototypeChain(TaggedObject *currObj, JSHClass *currHC, JSTaggedValue key)
{
if (currHC->IsDictionaryMode()) {
return JSTaggedValue(currHC);
}
while (!JSTaggedValue(currHC).IsUndefinedOrNull()) {
if (LIKELY(!currHC->IsDictionaryMode())) {
int entry = JSHClass::FindPropertyEntry(mainThread_, currHC, key);
if (entry != -1) {
return JSTaggedValue(currHC);
}
} else {
TaggedArray *array =
TaggedArray::Cast(JSObject::Cast(currObj)->GetProperties(mainThread_).GetTaggedObject());
ASSERT(array->IsDictionaryMode());
NameDictionary *dict = NameDictionary::Cast(array);
int entry = dict->FindEntry(mainThread_, key);
if (entry != -1) {
return JSTaggedValue(currHC);
}
}
auto proto = currHC->GetProto(mainThread_);
if (!proto.IsHeapObject()) {
return JSTaggedValue::Undefined();
}
currObj = proto.GetTaggedObject();
if (JSTaggedValue(currObj).IsUndefinedOrNull()) {
break;
}
currHC = currObj->GetClass();
}
return JSTaggedValue::Undefined();
}
void JITProfiler::AddObjectInfoWithMega(int32_t bcOffset)
{
auto megaType = ProfileType::CreateMegaType();
PGOObjectInfo info(megaType, megaType, megaType, megaType, megaType, megaType, PGOSampleType());
AddObjectInfoImplement(bcOffset, info);
}
void JITProfiler::AddObjectInfoImplement(int32_t bcOffset, const PGOObjectInfo &info, JSTaggedValue name)
{
PGORWOpType *cur = nullptr;
if (bcOffsetPGORwTypeMap_.find(bcOffset) == bcOffsetPGORwTypeMap_.end()) {
cur = chunk_->New<PGORWOpType>();
bcOffsetPGORwTypeMap_[bcOffset] = cur;
} else {
cur = const_cast<PGORWOpType*>(bcOffsetPGORwTypeMap_.at(bcOffset));
}
if (cur != nullptr) {
auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
if (name != JSTaggedValue::Undefined() && compilationEnv_->SupportHeapConstant()) {
JSHandle<JSTaggedValue> nameHandle = jitCompilationEnv->NewJSHandle(name);
auto nameConstantIndex = jitCompilationEnv->RecordHeapConstant(nameHandle);
cur->SetName(nameHandle);
cur->SetNameIdx(nameConstantIndex);
}
cur->AddObjectInfo(info);
}
}
bool JITProfiler::AddObjectInfo(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver, JSHClass *hold,
JSHClass *holdTra, uint32_t accessorMethodId, PrimitiveType primitiveType, JSTaggedValue name)
{
PGOSampleType accessor = PGOSampleType::CreateProfileType(abcId, accessorMethodId, ProfileType::Kind::MethodId);
if (UNLIKELY(receiver->GetPrototype(mainThread_).IsNull())) {
TraceICState(bcOffset, "IC-(receiver's prototype == Null)");
return false;
}
return AddTranstionObjectInfo(bcOffset, receiver, hold, holdTra, accessor, primitiveType, name);
}
bool JITProfiler::AddTranstionObjectInfo(int32_t bcOffset, JSHClass *receiver, JSHClass *hold,
JSHClass *holdTra, PGOSampleType accessorMethod, PrimitiveType primitiveType, JSTaggedValue name)
{
ptManager_->RecordAndGetHclassIndexForJIT(receiver);
ptManager_->RecordAndGetHclassIndexForJIT(hold);
ptManager_->RecordAndGetHclassIndexForJIT(holdTra);
PGOObjectInfo info(ProfileType::CreateJITType(), receiver, hold, holdTra, accessorMethod, primitiveType);
AddObjectInfoImplement(bcOffset, info, name);
return true;
}
bool JITProfiler::IsTypedArrayRootHClass(JSType jsType, OnHeapMode mode, JSHClass *receiver)
{
if (OnHeap::IsOnHeap(mode) || OnHeap::IsNone(mode)) {
JSHClass* rootHClass = GetCurrentGlobalEnv()->GetBuildinTypedArrayHClassByJSType(jsType, OnHeapMode::ON_HEAP);
if (rootHClass != nullptr && rootHClass == receiver) {
return true;
}
}
if (OnHeap::IsNotOnHeap(mode) || OnHeap::IsNone(mode)) {
JSHClass* rootHClass =
GetCurrentGlobalEnv()->GetBuildinTypedArrayHClassByJSType(jsType, OnHeapMode::NOT_ON_HEAP);
if (rootHClass != nullptr && rootHClass == receiver) {
return true;
}
}
return false;
}
void JITProfiler::AddBuiltinsInfo(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver,
JSHClass *transitionHClass, OnHeapMode onHeap, bool everOutOfBounds)
{
if (receiver->IsJSArray()) {
auto type = receiver->GetObjectType();
auto elementsKind = receiver->GetElementsKind();
auto transitionElementsKind = transitionHClass->GetElementsKind();
auto profileType = ProfileType::CreateBuiltinsArray(abcId, type, elementsKind, transitionElementsKind,
everOutOfBounds);
PGOObjectInfo info(profileType, receiver);
AddObjectInfoImplement(bcOffset, info);
} else if (receiver->IsTypedArray()) {
JSType jsType = receiver->GetObjectType();
auto profileType = IsTypedArrayRootHClass(jsType, onHeap, receiver) ?
ProfileType::CreateBuiltinsTypedArray(abcId, jsType, onHeap, everOutOfBounds) :
ProfileType::CreateInvalid(abcId);
PGOObjectInfo info(profileType, receiver);
AddObjectInfoImplement(bcOffset, info);
} else {
auto type = receiver->GetObjectType();
PGOObjectInfo info(ProfileType::CreateBuiltins(abcId, type), receiver);
AddObjectInfoImplement(bcOffset, info);
}
}
void JITProfiler::AddBuiltinsGlobalInfo(ApEntityId abcId, int32_t bcOffset, GlobalIndex globalsId)
{
PGOObjectInfo info(ProfileType::CreateGlobals(abcId, globalsId));
AddObjectInfoImplement(bcOffset, info);
}
bool JITProfiler::AddBuiltinsInfoByNameInInstance(ApEntityId abcId, int32_t bcOffset, JSHClass *receiver)
{
auto type = receiver->GetObjectType();
const auto &ctorEntries = mainThread_->GetCtorHclassEntries();
auto entry = ctorEntries.find(receiver);
if (entry != ctorEntries.end()) {
AddBuiltinsGlobalInfo(abcId, bcOffset, entry->second);
return true;
}
auto builtinsId = ToBuiltinsTypeId(type);
if (!builtinsId.has_value()) {
return false;
}
JSHClass *exceptRecvHClass = nullptr;
if (builtinsId == BuiltinTypeId::ARRAY) {
bool receiverIsPrototype = receiver->IsPrototype();
exceptRecvHClass = mainThread_->GetArrayInstanceHClass(GetCurrentGlobalEnv(),
receiver->GetElementsKind(), receiverIsPrototype, JSThread::ThreadKind::JitThread);
} else if (builtinsId == BuiltinTypeId::STRING) {
exceptRecvHClass = receiver;
} else {
exceptRecvHClass = mainThread_->GetBuiltinInstanceHClass(builtinsId.value());
}
if (exceptRecvHClass != receiver) {
if (builtinsId == BuiltinTypeId::OBJECT) {
exceptRecvHClass = JSHClass::Cast(
GetCurrentGlobalEnv()->GetIteratorResultClassWithBarrier().GetTaggedValue().GetTaggedObject());
if (exceptRecvHClass == receiver) {
GlobalIndex globalsId;
globalsId.UpdateGlobalEnvId(static_cast<size_t>(GlobalEnvField::ITERATOR_RESULT_CLASS_INDEX));
AddBuiltinsGlobalInfo(abcId, bcOffset, globalsId);
return true;
}
return false;
}
TraceICState(bcOffset, "IC-(receiver != expected)");
return true;
}
AddBuiltinsInfo(abcId, bcOffset, receiver, receiver);
return true;
}
bool JITProfiler::AddBuiltinsInfoByNameInProt(ApEntityId abcId, int32_t bcOffset,
JSHClass *receiver, JSHClass *hold, bool isNonExist)
{
auto type = receiver->GetObjectType();
auto builtinsId = ToBuiltinsTypeId(type);
if (!builtinsId.has_value()) {
return false;
}
if (isNonExist) {
if (builtinsId == BuiltinTypeId::STRING) {
TraceICState(bcOffset, "IC-Non-Exist-String");
return true;
}
return false;
}
JSHClass *exceptRecvHClass = nullptr;
if (builtinsId == BuiltinTypeId::ARRAY) {
bool receiverIsPrototype = receiver->IsPrototype();
exceptRecvHClass = mainThread_->GetArrayInstanceHClass(GetCurrentGlobalEnv(),
receiver->GetElementsKind(), receiverIsPrototype, JSThread::ThreadKind::JitThread);
} else if (builtinsId == BuiltinTypeId::STRING) {
exceptRecvHClass = receiver;
} else {
exceptRecvHClass = mainThread_->GetBuiltinInstanceHClass(builtinsId.value());
}
auto exceptHoldHClass = mainThread_->GetBuiltinPrototypeHClass(builtinsId.value());
auto exceptPrototypeOfPrototypeHClass =
mainThread_->GetBuiltinPrototypeOfPrototypeHClass(builtinsId.value());
if (builtinsId == BuiltinTypeId::ARRAY_ITERATOR) {
if ((exceptRecvHClass != receiver) ||
(exceptHoldHClass != hold && exceptPrototypeOfPrototypeHClass != hold)) {
TraceICState(bcOffset, "IC-(ARRAY_ITERATOR fail)");
return true;
}
} else if (IsTypedArrayType(builtinsId.value())) {
auto exceptRecvHClassOnHeap = mainThread_->GetBuiltinExtraHClass(builtinsId.value());
ASSERT_PRINT(exceptRecvHClassOnHeap == nullptr || exceptRecvHClassOnHeap->IsOnHeapFromBitField(),
"must be on heap");
if (JITProfiler::IsJSHClassNotEqual(receiver, hold, exceptRecvHClass, exceptRecvHClassOnHeap, exceptHoldHClass,
exceptPrototypeOfPrototypeHClass)) {
TraceICState(bcOffset, "IC-TypedArray-(receiver != expected)");
return true;
}
} else if (exceptRecvHClass != receiver || exceptHoldHClass != hold) {
if (builtinsId == BuiltinTypeId::OBJECT) {
return false;
} else {
TraceICState(bcOffset, "IC-Prototype-(receiver != expected)");
return true;
}
}
AddBuiltinsInfo(abcId, bcOffset, receiver, receiver);
return true;
}
bool JITProfiler::IsJSHClassNotEqual(JSHClass *receiver, JSHClass *hold, JSHClass *exceptRecvHClass,
JSHClass *exceptRecvHClassOnHeap, JSHClass *exceptHoldHClass,
JSHClass *exceptPrototypeOfPrototypeHClass)
{
return ((exceptRecvHClass != receiver && exceptRecvHClassOnHeap != receiver) ||
(exceptHoldHClass != hold && exceptPrototypeOfPrototypeHClass != hold));
}
bool JITProfiler::IsIncompleteProfileTypeInfo()
{
if (profileTypeInfo_.GetTaggedType() == 0 || profileTypeInfo_.GetTaggedValue().IsUndefined()) {
return true;
}
return profileTypeInfo_->Get(mainThread_, 0).IsUndefined();
}
bool JITProfiler::SlotValueIsUndefined(uint32_t slotId)
{
return profileTypeInfo_->Get(mainThread_, slotId).IsUndefined();
}
void JITProfiler::UpdateBcOffsetBool(uint32_t offset, uint32_t slotId)
{
if (IsIncompleteProfileTypeInfo()) {
return;
}
SetBcOffsetBool(offset, SlotValueIsUndefined(slotId));
}
void JITProfiler::UpdateBcOffsetBoolWithNearSlotId(uint32_t offset, uint32_t slotId)
{
if (IsIncompleteProfileTypeInfo()) {
return;
}
bool isInsufficientPGO = SlotValueIsUndefined(slotId) && SlotValueIsUndefined(slotId + 1);
SetBcOffsetBool(offset, isInsufficientPGO);
}
void JITProfiler::Clear()
{
bcOffsetPGOOpTypeMap_.clear();
bcOffsetPGODefOpTypeMap_.clear();
bcOffsetPGORwTypeMap_.clear();
bcOffsetBoolMap_.clear();
abcId_ = 0;
methodId_ = (EntityId)0;
}
JITProfiler::~JITProfiler()
{
}
}