<Perf>(interpreter): Optimization PGO profile

1、Delete field VTable and Super in hclass.
    2、Opt dump hclass transition tree.
    3、Opt profileType of hclass.
    4、Class function supports ProfileTypeInfoCell.

Issue: #IA9QT3
Change-Id: I3d296f19433878c16f70d0260a3e77ce58ba9a3f
Signed-off-by: yingguofeng@huawei.com <yingguofeng@huawei.com>
This commit is contained in:
yingguofeng@huawei.com 2024-07-01 21:06:12 +08:00
parent 3d15b0df15
commit b5eedbb873
57 changed files with 411 additions and 597 deletions

View File

@ -123,18 +123,6 @@ JSTaggedValue BuiltinsArkTools::GetHClass(EcmaRuntimeCallInfo *info)
return JSTaggedValue(hclass);
}
JSTaggedValue BuiltinsArkTools::HasTSSubtyping(EcmaRuntimeCallInfo *info)
{
ASSERT(info);
JSThread *thread = info->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
ASSERT(info->GetArgsNumber() == 1);
JSHandle<JSTaggedValue> object = GetCallArg(info, 0);
JSHClass *hclass = object->GetTaggedObject()->GetClass();
return GetTaggedBoolean(hclass->HasTSSubtyping());
}
JSTaggedValue BuiltinsArkTools::IsSlicedString(EcmaRuntimeCallInfo *info)
{
ASSERT(info);

View File

@ -30,7 +30,6 @@
V("forceFullGC", ForceFullGC, 0, INVALID) \
V("getHClass", GetHClass, 1, INVALID) \
V("getLexicalEnv", GetLexicalEnv, 1, INVALID) \
V("hasTSSubtyping", HasTSSubtyping, 1, INVALID) \
V("isSlicedString", IsSlicedString, 1, INVALID) \
V("hiddenStackSourceFile", HiddenStackSourceFile, 0, INVALID) \
V("hintGC", HintGC, 0, INVALID) \
@ -174,8 +173,6 @@ public:
static JSTaggedValue GetHClass(EcmaRuntimeCallInfo *info);
static JSTaggedValue HasTSSubtyping(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsSlicedString(EcmaRuntimeCallInfo *info);
static JSTaggedValue IsNotHoleProperty(EcmaRuntimeCallInfo *info);

View File

@ -2290,6 +2290,21 @@ DEF_CALL_SIGNATURE(FindElementWithCache)
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(UpdateFieldType)
{
// 2 : 2 input parameters
CallSignature index("UpdateFieldType", 0, 2, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32());
*callSign = index;
// 2 : 2 input parameters
std::array<VariableType, 2> params = {
VariableType::JS_ANY(),
VariableType::INT64(),
};
callSign->SetParameters(params.data());
callSign->SetGCLeafFunction(true);
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(NumberIsFinite)
{
// 1 : 1 input parameters

View File

@ -506,6 +506,7 @@ private:
V(CallDateNow) \
V(NumberIsFinite) \
V(FindElementWithCache) \
V(UpdateFieldType) \
V(MarkingBarrier) \
V(MarkingBarrierWithEden) \
V(SharedGCMarkingBarrier) \

View File

@ -339,7 +339,7 @@ GateRef ProfilerStubBuilder::TryGetBuiltinFunctionId(GateRef target)
Label exit(env);
DEFVARIABLE(functionId, VariableType::INT32(), Int32(PGO_BUILTINS_STUB_ID(NONE)));
BRANCH(IsJSFunction(target), &targetIsFunction, &exit);
Bind(&targetIsFunction);
{
@ -479,7 +479,7 @@ void ProfilerStubBuilder::UpdatePropAttrIC(
BRANCH(Equal(attr, newAttr), &exit, &updateLayout);
Bind(&updateLayout);
{
SetPropAttrToLayoutInfo(glue, layout, attrIndex, newAttr);
UpdateFieldType(glue, LoadHClass(receiver), newAttr);
callback.TryPreDump();
Jump(&exit);
}
@ -488,8 +488,8 @@ void ProfilerStubBuilder::UpdatePropAttrIC(
env->SubCfgExit();
}
void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef layout, GateRef attr,
GateRef attrIndex, GateRef value, ProfileOperation callback)
void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef attr,
GateRef value, ProfileOperation callback)
{
if (callback.IsEmpty()) {
return;
@ -506,7 +506,7 @@ void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef receiver
BRANCH(Equal(attr, newAttr), &exit, &updateLayout);
Bind(&updateLayout);
{
SetPropAttrToLayoutInfo(glue, layout, attrIndex, newAttr);
UpdateFieldType(glue, LoadHClass(receiver), newAttr);
Jump(&exit);
}
Bind(&exit);

View File

@ -113,8 +113,8 @@ public:
GateRef UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback);
void UpdatePropAttrIC(GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback);
void UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef layout, GateRef attr, GateRef attrIndex,
GateRef value, ProfileOperation callback);
void UpdatePropAttrWithValue(
GateRef glue, GateRef receiver, GateRef attr, GateRef value, ProfileOperation callback);
GateRef IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback);

View File

@ -2397,12 +2397,9 @@ inline GateRef StubBuilder::GetIhcFromAOTLiteralInfo(GateRef info)
return Load(VariableType::JS_ANY(), info, dataOffset);
}
inline void StubBuilder::SetPropAttrToLayoutInfo(GateRef glue, GateRef layout, GateRef entry, GateRef attr)
inline void StubBuilder::UpdateFieldType(GateRef glue, GateRef hclass, GateRef attr)
{
GateRef index = Int32Add(Int32LSL(entry, Int32(LayoutInfo::ELEMENTS_INDEX_LOG2)),
Int32(LayoutInfo::ATTR_INDEX_OFFSET));
GateRef taggedAttr = Int64ToTaggedInt(attr);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, layout, index, taggedAttr);
CallNGCRuntime(glue, RTSTUB_ID(UpdateFieldType), { hclass, attr });
}
inline GateRef StubBuilder::GetPropertyMetaDataFromAttr(GateRef attr)

View File

@ -4269,8 +4269,7 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k
CheckUpdateSharedType(false, &result, glue, receiver, attr, value, &executeSetProp, &exit);
Bind(&executeSetProp);
JSObjectSetProperty(glue, *holder, hclass, attr, key, value);
ProfilerStubBuilder(env).UpdatePropAttrWithValue(
glue, receiver, layOutInfo, attr, entry, value, callback);
ProfilerStubBuilder(env).UpdatePropAttrWithValue(glue, receiver, attr, value, callback);
result = Undefined();
Jump(&exit);
}
@ -4373,8 +4372,7 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k
GateRef receiverLayoutInfo = GetLayoutFromHClass(receiverHClass);
GateRef holeAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry);
JSObjectSetProperty(glue, receiver, receiverHClass, holeAttr, key, value);
ProfilerStubBuilder(env).UpdatePropAttrWithValue(
glue, receiver, receiverLayoutInfo, holeAttr, *receiverHoleEntry, value, callback);
ProfilerStubBuilder(env).UpdatePropAttrWithValue(glue, receiver, holeAttr, value, callback);
result = Undefined();
Jump(&exit);
}

View File

@ -576,7 +576,7 @@ ShortcutBoolOr([&]{ return first; }, [&]{ return second; })
template<typename DictionaryT>
GateRef GetKeyFromDictionary(GateRef elements, GateRef entry);
GateRef GetPropAttrFromLayoutInfo(GateRef layout, GateRef entry);
void SetPropAttrToLayoutInfo(GateRef glue, GateRef layout, GateRef entry, GateRef attr);
void UpdateFieldType(GateRef glue, GateRef hclass, GateRef attr);
GateRef GetPropertiesAddrFromLayoutInfo(GateRef layout);
GateRef GetPropertyMetaDataFromAttr(GateRef attr);
GateRef TranslateToRep(GateRef value);

View File

@ -1625,18 +1625,6 @@ void TypedHCRLowering::LowerGetSuperConstructor(GateRef gate)
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), superCtor);
}
GateRef TypedHCRLowering::LoadFromVTable(GateRef receiver, size_t index)
{
GateRef hclass = builder_.LoadConstOffset(
VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
GateRef vtable = builder_.LoadConstOffset(VariableType::JS_ANY(),
hclass, JSHClass::VTABLE_OFFSET);
GateRef itemOwner = builder_.LoadFromTaggedArray(vtable, VTable::TupleItem::OWNER + index);
GateRef itemOffset = builder_.LoadFromTaggedArray(vtable, VTable::TupleItem::OFFSET + index);
return builder_.Load(VariableType::JS_ANY(), itemOwner, builder_.TaggedGetInt(itemOffset));
}
VariableType TypedHCRLowering::GetVarType(PropertyLookupResult plr)
{
if (plr.GetRepresentation() == Representation::DOUBLE) {
@ -1648,11 +1636,6 @@ VariableType TypedHCRLowering::GetVarType(PropertyLookupResult plr)
}
}
GateRef TypedHCRLowering::LoadSupers(GateRef hclass)
{
return builder_.LoadConstOffset(VariableType::JS_ANY(), hclass, JSHClass::SUPERS_OFFSET);
}
GateRef TypedHCRLowering::GetLengthFromSupers(GateRef supers)
{
return builder_.LoadConstOffset(VariableType::INT32(), supers, TaggedArray::EXTRA_LENGTH_OFFSET);

View File

@ -258,12 +258,10 @@ private:
}
VariableType GetVarType(PropertyLookupResult plr);
GateRef LoadSupers(GateRef hclass);
GateRef GetLengthFromSupers(GateRef supers);
GateRef GetValueFromSupers(GateRef supers, size_t index);
GateRef LoadFromTaggedArray(GateRef array, size_t index);
GateRef LoadFromConstPool(GateRef unsharedConstPool, size_t index, size_t valVecType);
GateRef LoadFromVTable(GateRef receiver, size_t index);
GateRef GetLengthFromString(GateRef gate);
GateRef LoadPropertyFromHolder(GateRef holder, PropertyLookupResult plr);
void StorePropertyOnHolder(GateRef holder, GateRef value, PropertyLookupResult plr, bool needBarrier);

View File

@ -755,28 +755,7 @@ static void DumpHClass(const JSHClass *jshclass, std::ostream &os, bool withDeta
os << "\n";
}
JSTaggedValue supers = jshclass->GetSupers();
uint32_t length = 0;
if (supers.IsTaggedArray()) {
length = WeakVector::Cast(supers.GetTaggedObject())->GetExtraLength();
}
os << " - Supers[" << std::dec << length << "]: ";
os << std::setw(DUMP_TYPE_OFFSET);
supers.DumpTaggedValue(os);
if (withDetail && !supers.IsUndefined()) {
WeakVector::Cast(supers.GetTaggedObject())->Dump(os);
} else {
os << "\n";
}
os << " - VTable :" << std::setw(DUMP_TYPE_OFFSET);
JSTaggedValue vtable = jshclass->GetVTable();
vtable.DumpTaggedValue(os);
if (withDetail && !vtable.IsUndefined()) {
VTable::Cast(vtable.GetTaggedObject())->Dump(os);
} else {
os << "\n";
}
os << " - ProfileType : " << std::hex << jshclass->GetProfileType() << "\n";
os << " - Flags : " << std::setw(DUMP_TYPE_OFFSET);
os << "IsCtor :" << std::boolalpha << jshclass->IsConstructor();
@ -4866,8 +4845,6 @@ void JSHClass::DumpForSnapshot([[maybe_unused]] std::vector<Reference> &vec) con
vec.emplace_back(CString("ProtoChangeMarker"), GetProtoChangeMarker());
vec.emplace_back(CString("ProtoChangeDetails"), GetProtoChangeDetails());
vec.emplace_back(CString("EnumCache"), GetEnumCache());
vec.emplace_back(CString("Supers"), GetSupers());
vec.emplace_back(CString("VTable"), GetVTable());
vec.emplace_back(CString("BitField"), JSTaggedValue(GetBitField()));
vec.emplace_back(CString("BitField1"), JSTaggedValue(GetBitField1()));
}

View File

@ -1054,6 +1054,24 @@ void JSFunction::SetProfileTypeInfo(const JSThread *thread, const JSHandle<JSFun
handleRaw->SetValue(thread, value, mode);
}
void JSFunction::UpdateProfileTypeInfoCell(JSThread *thread, JSHandle<JSFunction> literalFunc,
JSHandle<JSFunction> targetFunc)
{
auto profileTypeInfoCellVal = literalFunc->GetRawProfileTypeInfo();
ASSERT(profileTypeInfoCellVal.IsProfileTypeInfoCell());
auto profileTypeInfoCell = ProfileTypeInfoCell::Cast(profileTypeInfoCellVal);
if (profileTypeInfoCell->IsEmptyProfileTypeInfoCell(thread)) {
JSHandle<JSTaggedValue> handleUndefined(thread, JSTaggedValue::Undefined());
JSHandle<ProfileTypeInfoCell> newProfileTypeInfoCell =
thread->GetEcmaVM()->GetFactory()->NewProfileTypeInfoCell(handleUndefined);
literalFunc->SetRawProfileTypeInfo(thread, newProfileTypeInfoCell);
targetFunc->SetRawProfileTypeInfo(thread, newProfileTypeInfoCell);
} else {
ProfileTypeInfoCell::Cast(profileTypeInfoCell)->UpdateProfileTypeInfoCellType(thread);
targetFunc->SetRawProfileTypeInfo(thread, profileTypeInfoCellVal);
}
}
void JSFunction::SetJitMachineCodeCache(const JSThread *thread, const JSHandle<MachineCode> &machineCode)
{
JSHandle<ProfileTypeInfoCell> handleRaw(thread, GetRawProfileTypeInfo());

View File

@ -308,6 +308,8 @@ public:
void *data, size_t nativeBindingsize = 0);
static void SetProfileTypeInfo(const JSThread *thread, const JSHandle<JSFunction> &func,
const JSHandle<JSTaggedValue> &value, BarrierMode mode = WRITE_BARRIER);
static void UpdateProfileTypeInfoCell(JSThread *thread, JSHandle<JSFunction> literalFunc,
JSHandle<JSFunction> targetFunc);
void SetJitMachineCodeCache(const JSThread *thread, const JSHandle<MachineCode> &machineCode);
JSTaggedValue GetFunctionExtraInfo() const;

View File

@ -299,10 +299,12 @@ inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshclass)
inline JSHClass *JSHClass::FindRootHClass(JSHClass *hclass)
{
auto root = hclass;
auto parent = hclass->GetParent();
while (parent.IsJSHClass()) {
while (!ProfileType(root->GetProfileType()).IsRootType()) {
auto parent = root->GetParent();
if (!parent.IsJSHClass()) {
break;
}
root = JSHClass::Cast(parent.GetTaggedObject());
parent = root->GetParent();
}
return root;
}

View File

@ -159,9 +159,7 @@ void JSHClass::InitializeWithDefaultValue(const JSThread *thread, uint32_t size,
SetProtoChangeMarker(thread, JSTaggedValue::Null());
SetProtoChangeDetails(thread, JSTaggedValue::Null());
SetEnumCache(thread, JSTaggedValue::Null());
SetSupers(thread, JSTaggedValue::Undefined());
SetLevel(0);
SetVTable(thread, JSTaggedValue::Undefined());
}
bool JSHClass::IsJSTypeShared(JSType type)
@ -207,7 +205,6 @@ void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, ui
if (JSType::JS_OBJECT_FIRST <= type && type <= JSType::JS_OBJECT_LAST) {
SetLayout(thread, thread->GlobalConstants()->GetEmptyLayoutInfo());
}
InitTSInheritInfo(thread);
}
// for sharedHeap
@ -223,22 +220,6 @@ void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type,
}
}
void JSHClass::InitTSInheritInfo(const JSThread *thread)
{
// Supers and Level are used to record the relationship between TSHClass.
if (ShouldSetDefaultSupers()) {
ASSERT(thread->GlobalConstants()->GetDefaultSupers().IsTaggedArray());
SetSupers(thread, thread->GlobalConstants()->GetDefaultSupers());
} else {
SetSupers(thread, JSTaggedValue::Undefined());
}
SetLevel(0);
// VTable records the location information of properties and methods of TSHClass,
// which is used to perform efficient IC at runtime
SetVTable(thread, JSTaggedValue::Undefined());
}
JSHandle<JSHClass> JSHClass::Clone(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
bool withoutInlinedProperties, uint32_t incInlinedProperties)
{
@ -563,7 +544,6 @@ void JSHClass::TransitionToDictionary(const JSThread *thread, const JSHandle<JSO
// 1. new a hclass
JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
JSHandle<JSHClass> newJsHClass = CloneWithoutInlinedProperties(thread, jshclass);
UpdateRootHClass(thread, jshclass, newJsHClass);
{
DISALLOW_GARBAGE_COLLECTION;
@ -587,7 +567,6 @@ void JSHClass::OptimizeAsFastProperties(const JSThread *thread, const JSHandle<J
// 1. new a hclass
JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
JSHandle<JSHClass> newJsHClass = Clone(thread, jshclass, isDictionary);
UpdateRootHClass(thread, jshclass, newJsHClass);
// 2. If it is dictionary, migrate should change layout. otherwise, copy the hclass only.
JSHandle<NameDictionary> properties(thread, obj->GetProperties());
@ -752,6 +731,62 @@ bool JSHClass::TransitToElementsKind(const JSThread *thread, const JSHandle<JSOb
return false;
}
void JSHClass::UpdateFieldType(JSHClass *hclass, const PropertyAttributes &attr)
{
DISALLOW_GARBAGE_COLLECTION;
JSHClass *ownHClass = FindFieldOwnHClass(hclass, attr);
VisitAndUpdateLayout(ownHClass, attr);
}
JSHClass *JSHClass::FindFieldOwnHClass(JSHClass *hclass, const PropertyAttributes &attr)
{
uint32_t offset = attr.GetOffset();
JSTaggedValue parent(hclass);
JSHClass *curHClass = hclass;
while (parent.IsJSHClass()) {
auto parentHClass = JSHClass::Cast(parent.GetTaggedObject());
if (parentHClass->NumberOfProps() <= offset) {
break;
}
curHClass = parentHClass;
parent = curHClass->GetParent();
}
return curHClass;
}
void JSHClass::VisitAndUpdateLayout(JSHClass *ownHClass, const PropertyAttributes &attr)
{
uint32_t offset = attr.GetOffset();
auto targetTrackType = attr.GetTrackType();
std::queue<JSHClass *> backHClass;
backHClass.push(ownHClass);
while (!backHClass.empty()) {
JSHClass *current = backHClass.front();
backHClass.pop();
auto layout = LayoutInfo::Cast(current->GetLayout().GetTaggedObject());
if (layout->GetAttr(offset).GetTrackType() != targetTrackType) {
layout->UpdateTrackTypeAttr(offset, attr);
}
auto transitions = current->GetTransitions();
if (transitions.IsUndefined()) {
continue;
}
if (transitions.IsWeak()) {
auto cache = transitions.GetTaggedWeakRef();
backHClass.push(JSHClass::Cast(cache));
continue;
}
ASSERT(transitions.IsTaggedArray());
TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
dict->IterateEntryValue([&backHClass] (JSHClass *cache) {
backHClass.push(JSHClass::Cast(cache));
});
}
}
TransitionResult JSHClass::ConvertOrTransitionWithRep(const JSThread *thread,
const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
PropertyAttributes &attr)
@ -760,7 +795,7 @@ TransitionResult JSHClass::ConvertOrTransitionWithRep(const JSThread *thread,
auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
attr = layout->GetAttr(attr.GetOffset());
if (thread->IsPGOProfilerEnable() && !hclass->IsJSShared() && attr.UpdateTrackType(value.GetTaggedValue())) {
layout->SetNormalAttr(thread, attr.GetOffset(), attr);
UpdateFieldType(hclass, attr);
}
Representation oldRep = attr.GetRepresentation();
@ -805,11 +840,7 @@ JSHandle<JSTaggedValue> JSHClass::EnableProtoChangeMarker(const JSThread *thread
// PHC (prototype-HClass) and its IHC (instance-HClass) from the current PHC along the chain.
// therefore, when registering, it is also necessary to register IHC into its
// PHC's Listener to ensure that it can be notified.
if (jshclass->IsTSIHCWithInheritInfo()) {
RegisterOnProtoChain(thread, jshclass);
} else {
RegisterOnProtoChain(thread, protoClass);
}
RegisterOnProtoChain(thread, protoClass);
JSTaggedValue protoChangeMarker = protoClass->GetProtoChangeMarker();
if (protoChangeMarker.IsProtoChangeMarker()) {
@ -980,19 +1011,15 @@ JSHandle<ProtoChangeDetails> JSHClass::GetProtoChangeDetails(const JSThread *thr
return GetProtoChangeDetails(thread, jshclass);
}
void JSHClass::MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
void JSHClass::MarkProtoChanged([[maybe_unused]] const JSThread *thread, const JSHandle<JSHClass> &jshclass)
{
DISALLOW_GARBAGE_COLLECTION;
ASSERT(jshclass->IsPrototype() || jshclass->HasTSSubtyping());
ASSERT(jshclass->IsPrototype());
JSTaggedValue markerValue = jshclass->GetProtoChangeMarker();
if (markerValue.IsProtoChangeMarker()) {
ProtoChangeMarker *protoChangeMarker = ProtoChangeMarker::Cast(markerValue.GetTaggedObject());
protoChangeMarker->SetHasChanged(true);
}
if (jshclass->HasTSSubtyping()) {
jshclass->InitTSInheritInfo(thread);
}
}
void JSHClass::NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
@ -1038,21 +1065,6 @@ void JSHClass::RefreshUsers(const JSThread *thread, const JSHandle<JSHClass> &ol
}
}
bool JSHClass::HasTSSubtyping() const
{
// if fill TS inherit info, supers must not be empty
if (!GetSupers().IsHeapObject()) {
return false;
}
WeakVector *supers = WeakVector::Cast(GetSupers().GetTaggedObject());
return !(supers->Empty());
}
bool JSHClass::IsTSIHCWithInheritInfo() const
{
return IsTS() && !IsPrototype() && HasTSSubtyping();
}
PropertyLookupResult JSHClass::LookupPropertyInAotHClass(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
{
DISALLOW_GARBAGE_COLLECTION;
@ -1089,23 +1101,6 @@ PropertyLookupResult JSHClass::LookupPropertyInAotHClass(const JSThread *thread,
return result;
}
// found in vtable
if (hclass->GetVTable().IsUndefined()) {
result.SetIsFound(false);
return result;
}
JSHandle<VTable> vtable(thread, hclass->GetVTable());
entry = vtable->GetTupleIndexByName(key);
if (entry != -1) {
result.SetIsVtable();
uint32_t offset = static_cast<uint32_t>(entry * VTable::TUPLE_SIZE);
result.SetOffset(offset);
if (vtable->IsAccessor(entry)) {
result.SetIsAccessor(true);
}
return result;
}
// not found
result.SetIsFound(false);
return result;
@ -1191,21 +1186,6 @@ PropertyLookupResult JSHClass::LookupPropertyInBuiltinPrototypeHClass(const JSTh
return result;
}
void JSHClass::CopyTSInheritInfo(const JSThread *thread, const JSHandle<JSHClass> &oldHClass,
JSHandle<JSHClass> &newHClass)
{
JSHandle<WeakVector> supers(thread, oldHClass->GetSupers());
JSHandle<WeakVector> copySupers = WeakVector::Copy(thread, supers);
newHClass->SetSupers(thread, copySupers);
uint8_t level = oldHClass->GetLevel();
newHClass->SetLevel(level);
JSHandle<VTable> vtable(thread, oldHClass->GetVTable());
JSHandle<VTable> copyVtable = VTable::Copy(thread, vtable);
newHClass->SetVTable(thread, copyVtable);
}
JSHandle<JSTaggedValue> JSHClass::ParseKeyFromPGOCString(ObjectFactory* factory,
const CString& cstring,
const PGOHandler& handler)
@ -1385,9 +1365,7 @@ bool JSHClass::UpdateChildLayoutDescByPGO(const JSHClass* hclass, HClassLayoutDe
return layoutInfo->UpdateFieldIndexByPGO(last, childDesc);
}
bool JSHClass::UpdateRootLayoutDescByPGO(const JSHClass* hclass,
const PGOHClassTreeDesc* treeDesc,
HClassLayoutDesc* desc)
bool JSHClass::UpdateRootLayoutDescByPGO(const JSHClass* hclass, HClassLayoutDesc* desc)
{
DISALLOW_GARBAGE_COLLECTION;
if (hclass->IsDictionaryMode()) {
@ -1396,25 +1374,10 @@ bool JSHClass::UpdateRootLayoutDescByPGO(const JSHClass* hclass,
auto rootDesc = reinterpret_cast<const pgo::RootHClassLayoutDesc *>(desc);
int rootPropLen = static_cast<int>(rootDesc->NumOfProps());
int element = static_cast<int>(hclass->NumberOfProps());
ASSERT(element >= rootPropLen);
LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
for (int i = 0; i < rootPropLen; i++) {
layout->UpdateFieldIndexByPGO(i, desc);
}
auto lastDesc = desc;
for (int i = rootPropLen; i < element - 1; i++) {
if (lastDesc == nullptr || lastDesc->GetChildSize() == 0) {
break;
}
lastDesc->IterateChilds([treeDesc, layout, i, &lastDesc] (const ProfileType &childType) -> bool {
lastDesc = treeDesc->GetHClassLayoutDesc(childType);
if (lastDesc == nullptr) {
return true;
}
return !layout->UpdateFieldIndexByPGO(i, lastDesc);
});
}
return true;
}
@ -1432,10 +1395,13 @@ CString JSHClass::DumpToString(JSTaggedType hclassVal)
for (int i = 0; i < element; i++) {
auto key = layout->GetKey(i);
if (key.IsString()) {
result += EcmaStringAccessor(key).ToCString();
uint64_t value = EcmaStringAccessor(key).GetHashcode();
value <<= sizeof(uint32_t) * BITS_PER_BYTE;
auto attr = layout->GetAttr(i);
result += static_cast<int32_t>(attr.GetTrackType());
result += attr.GetPropertyMetaData();
auto defaultAttr = PropertyAttributes(attr.GetPropertyMetaData());
defaultAttr.SetTrackType(attr.GetTrackType());
value += defaultAttr.GetValue();
result += ToCString(value);
} else if (key.IsSymbol()) {
result += JSSymbol::Cast(key)->GetPrivateId();
auto attr = layout->GetAttr(i);

View File

@ -475,6 +475,10 @@ public:
const JSHandle<JSObject> &receiver, const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value,
PropertyAttributes &attr);
static void UpdateFieldType(JSHClass *hclass, const PropertyAttributes &attr);
static JSHClass *FindFieldOwnHClass(JSHClass *hclass, const PropertyAttributes &attr);
static void VisitAndUpdateLayout(JSHClass *ownHClass, const PropertyAttributes &attr);
static JSHandle<JSTaggedValue> EnableProtoChangeMarker(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
static JSHandle<JSTaggedValue> EnablePHCProtoChangeMarker(
const JSThread *thread, const JSHandle<JSHClass> &protoClass);
@ -504,21 +508,13 @@ public:
static void RefreshUsers(const JSThread *thread, const JSHandle<JSHClass> &oldHclass,
const JSHandle<JSHClass> &newHclass);
void InitTSInheritInfo(const JSThread *thread);
bool PUBLIC_API HasTSSubtyping() const;
bool IsTSIHCWithInheritInfo() const;
static void CopyTSInheritInfo(const JSThread *thread, const JSHandle<JSHClass> &oldHClass,
JSHandle<JSHClass> &newHClass);
static JSHandle<JSTaggedValue> ParseKeyFromPGOCString(ObjectFactory* factory,
const CString& key,
const PGOHandler& handler);
inline void ClearBitField()
{
SetProfileType(0ULL);
SetBitField(0UL);
SetBitField1(0UL);
}
@ -1977,9 +1973,8 @@ public:
ACCESSORS(Parent, PARENT_OFFSET, PROTO_CHANGE_MARKER_OFFSET);
ACCESSORS(ProtoChangeMarker, PROTO_CHANGE_MARKER_OFFSET, PROTO_CHANGE_DETAILS_OFFSET);
ACCESSORS(ProtoChangeDetails, PROTO_CHANGE_DETAILS_OFFSET, ENUM_CACHE_OFFSET);
ACCESSORS(EnumCache, ENUM_CACHE_OFFSET, SUPERS_OFFSET);
ACCESSORS(Supers, SUPERS_OFFSET, VTABLE_OFFSET);
ACCESSORS(VTable, VTABLE_OFFSET, BIT_FIELD_OFFSET);
ACCESSORS(EnumCache, ENUM_CACHE_OFFSET, PROFILE_TYPE);
ACCESSORS_PRIMITIVE_FIELD(ProfileType, uint64_t, PROFILE_TYPE, BIT_FIELD_OFFSET);
ACCESSORS_PRIMITIVE_FIELD(BitField, uint32_t, BIT_FIELD_OFFSET, BIT_FIELD1_OFFSET);
ACCESSORS_PRIMITIVE_FIELD(BitField1, uint32_t, BIT_FIELD1_OFFSET, LAST_OFFSET);
DEFINE_ALIGN_SIZE(LAST_OFFSET);
@ -2019,13 +2014,11 @@ public:
const HClassLayoutDesc* desc);
static bool DumpRootHClassByPGO(const JSHClass* hclass, HClassLayoutDesc* desc);
static bool DumpChildHClassByPGO(const JSHClass* hclass, HClassLayoutDesc* desc);
static bool UpdateRootLayoutDescByPGO(const JSHClass* hclass,
const PGOHClassTreeDesc* treeDesc,
HClassLayoutDesc* rootDesc);
static bool UpdateRootLayoutDescByPGO(const JSHClass* hclass, HClassLayoutDesc* rootDesc);
static bool UpdateChildLayoutDescByPGO(const JSHClass* hclass, HClassLayoutDesc* childDesc);
static CString DumpToString(JSTaggedType hclassVal);
DECL_VISIT_OBJECT(PROTOTYPE_OFFSET, BIT_FIELD_OFFSET);
DECL_VISIT_OBJECT(PROTOTYPE_OFFSET, PROFILE_TYPE);
inline JSHClass *FindProtoTransitions(const JSTaggedValue &key, const JSTaggedValue &proto);
inline bool HasTransitions() const
{

View File

@ -415,7 +415,9 @@ JSHandle<JSFunction> ClassHelper::DefineClassFromExtractor(JSThread *thread, con
for (uint32_t index = 0; index < nonStaticLength; ++index) {
propValue.Update(nonStaticProperties->Get(index));
if (propValue->IsJSFunction()) {
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(JSHandle<JSFunction>::Cast(propValue));
auto literalFunc = JSHandle<JSFunction>::Cast(propValue);
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(literalFunc);
JSFunction::UpdateProfileTypeInfoCell(thread, literalFunc, propFunc);
propFunc->SetHomeObject(thread, prototype);
propFunc->SetLexicalEnv(thread, lexenv);
propValue.Update(propFunc);
@ -441,7 +443,9 @@ JSHandle<JSFunction> ClassHelper::DefineClassFromExtractor(JSThread *thread, con
for (uint32_t index = 0; index < staticLength; ++index) {
propValue.Update(staticProperties->Get(index));
if (propValue->IsJSFunction()) {
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(JSHandle<JSFunction>::Cast(propValue));
auto literalFunc = JSHandle<JSFunction>::Cast(propValue);
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(literalFunc);
JSFunction::UpdateProfileTypeInfoCell(thread, literalFunc, propFunc);
propFunc->SetHomeObject(thread, constructor);
propFunc->SetLexicalEnv(thread, lexenv);
propValue.Update(propFunc);
@ -508,7 +512,9 @@ JSHandle<JSFunction> ClassHelper::DefineClassWithIHClass(JSThread *thread,
for (uint32_t index = 0; index < nonStaticLength; ++index) {
propValue.Update(nonStaticProperties->Get(index));
if (propValue->IsJSFunction()) {
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(JSHandle<JSFunction>::Cast(propValue));
auto literalFunc = JSHandle<JSFunction>::Cast(propValue);
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(literalFunc);
JSFunction::UpdateProfileTypeInfoCell(thread, literalFunc, propFunc);
propFunc->SetHomeObject(thread, prototype);
propFunc->SetLexicalEnv(thread, lexenv);
propValue.Update(propFunc);
@ -535,7 +541,9 @@ JSHandle<JSFunction> ClassHelper::DefineClassWithIHClass(JSThread *thread,
for (uint32_t index = 0; index < staticLength; ++index) {
propValue.Update(staticProperties->Get(index));
if (propValue->IsJSFunction()) {
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(JSHandle<JSFunction>::Cast(propValue));
auto literalFunc = JSHandle<JSFunction>::Cast(propValue);
JSHandle<JSFunction> propFunc = factory->CloneJSFunction(literalFunc);
JSFunction::UpdateProfileTypeInfoCell(thread, literalFunc, propFunc);
propFunc->SetHomeObject(thread, constructor);
propFunc->SetLexicalEnv(thread, lexenv);
propValue.Update(propFunc);

View File

@ -626,13 +626,8 @@ public:
}
}
JSHandle<JSObject> obj = JSObject::CreateObjectFromProperties(thread, properties, ihcVal);
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
pgo::ApEntityId abcId(0);
pgo::PGOProfilerManager::GetInstance()->GetPandaFileId(jsPandaFile->GetJSPandaFileDesc(),
abcId);
thread->GetEcmaVM()->GetPGOProfiler()->ProfileCreateObject(obj.GetTaggedType(), abcId,
id.GetOffset());
}
auto profiler = thread->GetEcmaVM()->GetPGOProfiler();
profiler->RecordProfileType(obj->GetClass(), jsPandaFile, id.GetOffset());
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
size_t elementsLen = elements->GetLength();

View File

@ -187,6 +187,22 @@ inline void LayoutInfo::SetIsNotHole(const JSThread *thread, int index)
TaggedArray::Set(thread, fixedIdx, attr.GetTaggedValue());
}
inline void LayoutInfo::UpdateTrackTypeAttr(int index, const PropertyAttributes &attr)
{
uint32_t fixedIdx = GetAttrIndex(index);
PropertyAttributes oldAttr(TaggedArray::Get(fixedIdx));
oldAttr.SetNormalAttr(attr.GetNormalAttr());
oldAttr.SetIsPGODumped(false);
TaggedArray::Set(fixedIdx, oldAttr.GetTaggedValue());
}
inline void LayoutInfo::SetIsPGODumped(int index)
{
uint32_t fixedIdx = GetAttrIndex(index);
PropertyAttributes attr(TaggedArray::Get(fixedIdx));
attr.SetIsPGODumped(true);
TaggedArray::Set(fixedIdx, attr.GetTaggedValue());
}
template<bool checkDuplicateKeys /* = false*/>
void LayoutInfo::AddKey(const JSThread *thread, [[maybe_unused]] int index, const JSTaggedValue &key,

View File

@ -226,16 +226,14 @@ CString LayoutInfo::GetSymbolKeyString(JSTaggedValue key)
void LayoutInfo::DumpFieldIndexByPGO(int index, pgo::HClassLayoutDesc* desc)
{
auto key = GetKey(index);
auto attr = GetAttr(index);
SetIsPGODumped(index);
TrackType type = attr.GetTrackType();
int propertyMeta = attr.GetPropertyMetaData();
if (key.IsString()) {
auto attr = GetAttr(index);
TrackType type = attr.GetTrackType();
int propertyMeta = attr.GetPropertyMetaData();
auto keyString = EcmaStringAccessor(key).ToCString();
desc->InsertKeyAndDesc(keyString, PGOHandler(type, propertyMeta, false));
} else if (key.IsSymbol()) {
auto attr = GetAttr(index);
TrackType type = attr.GetTrackType();
int propertyMeta = attr.GetPropertyMetaData();
auto keyString = GetSymbolKeyString(key);
if (keyString.empty()) {
return;
@ -247,16 +245,17 @@ void LayoutInfo::DumpFieldIndexByPGO(int index, pgo::HClassLayoutDesc* desc)
bool LayoutInfo::UpdateFieldIndexByPGO(int index, pgo::HClassLayoutDesc* desc)
{
auto key = GetKey(index);
auto attr = GetAttr(index);
if (attr.IsPGODumped()) {
return true;
}
SetIsPGODumped(index);
TrackType type = attr.GetTrackType();
int propertyMeta = attr.GetPropertyMetaData();
if (key.IsString()) {
auto attr = GetAttr(index);
TrackType type = attr.GetTrackType();
int propertyMeta = attr.GetPropertyMetaData();
auto keyString = EcmaStringAccessor(key).ToCString();
return desc->UpdateKeyAndDesc(keyString, PGOHandler(type, propertyMeta, false));
} else if (key.IsSymbol()) {
auto attr = GetAttr(index);
TrackType type = attr.GetTrackType();
int propertyMeta = attr.GetPropertyMetaData();
auto keyString = GetSymbolKeyString(key);
if (keyString.empty()) {
return false;

View File

@ -67,6 +67,8 @@ public:
template<bool checkDuplicateKeys = false>
void AddKey(const JSThread *thread, int index, const JSTaggedValue &key, const PropertyAttributes &attr);
void SetIsNotHole(const JSThread *thread, int index);
void UpdateTrackTypeAttr(int index, const PropertyAttributes &attr);
void SetIsPGODumped(int index);
inline uint32_t GetLength() const
{

View File

@ -41,18 +41,16 @@
#include "macros.h"
namespace panda::ecmascript::pgo {
void PGOProfiler::ProfileCreateObject(JSTaggedType object, ApEntityId abcId, int32_t traceId)
void PGOProfiler::RecordProfileType(JSHClass *hclass, JSPandaFile *pandaFile, int32_t traceId)
{
if (!isEnable_) {
return;
}
JSTaggedValue objectValue(object);
if (objectValue.IsJSObject()) {
auto hclass = objectValue.GetTaggedObject()->GetClass();
hclass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
ProfileType traceType(abcId, traceId, ProfileType::Kind::ObjectLiteralId, true);
InsertProfileTypeSafe(JSTaggedType(hclass), JSTaggedType(hclass), traceType);
ProfileType traceType = GetProfileType(hclass);
if (traceType.IsNone()) {
pgo::ApEntityId abcId(0);
pgo::PGOProfilerManager::GetInstance()->GetPandaFileId(pandaFile->GetJSPandaFileDesc(), abcId);
SetRootProfileType(hclass, abcId, traceId, ProfileType::Kind::ObjectLiteralId);
}
}
@ -77,31 +75,19 @@ void PGOProfiler::ProfileDefineClass(JSTaggedType ctor)
return;
}
auto ctorMethodHClass = ctorFunc->GetClass();
ctorMethodHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
auto ctorRootHClass = JSTaggedType(ctorMethodHClass);
if (GetProfileType(ctorRootHClass, ctorRootHClass).IsNone()) {
ProfileType ctorProfileType(GetMethodAbcId(ctorFunc), entityId, ProfileType::Kind::ConstructorId, true);
InsertProfileTypeSafe(ctorRootHClass, ctorRootHClass, ctorProfileType);
}
auto abcId = GetMethodAbcId(ctorFunc);
auto chc = ctorFunc->GetClass();
SetRootProfileType(chc, abcId, entityId, ProfileType::Kind::ConstructorId);
auto protoOrHClass = ctorFunc->GetProtoOrHClass();
if (protoOrHClass.IsJSHClass()) {
auto ihc = JSHClass::Cast(protoOrHClass.GetTaggedObject());
ihc->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
auto localRootHClass = JSTaggedType(ihc);
ProfileType localProfileType(GetMethodAbcId(ctorFunc), entityId, ProfileType::Kind::ClassId, true);
InsertProfileTypeSafe(localRootHClass, localRootHClass, localProfileType);
SetRootProfileType(ihc, abcId, entityId, ProfileType::Kind::ClassId);
protoOrHClass = ihc->GetProto();
}
if (protoOrHClass.IsJSObject()) {
auto prototypeHClass = protoOrHClass.GetTaggedObject()->GetClass();
prototypeHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
auto protoRootHClass = JSTaggedType(prototypeHClass);
if (GetProfileType(protoRootHClass, protoRootHClass).IsNone()) {
ProfileType protoProfileType(GetMethodAbcId(ctorFunc), entityId, ProfileType::Kind::PrototypeId, true);
InsertProfileTypeSafe(protoRootHClass, protoRootHClass, protoProfileType);
}
auto phc = protoOrHClass.GetTaggedObject()->GetClass();
SetRootProfileType(phc, abcId, entityId, ProfileType::Kind::PrototypeId);
}
}
@ -130,11 +116,8 @@ void PGOProfiler::ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcV
}
auto rootHc = JSHClass::Cast(JSTaggedValue(rootHcValue).GetTaggedObject());
rootHc->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
if (GetProfileType(rootHcValue, rootHcValue).IsNone()) {
ProfileType ihcProfileType(GetMethodAbcId(ctorFunc), entityId, kind, true);
InsertProfileTypeSafe(rootHcValue, rootHcValue, ihcProfileType);
}
auto abcId = GetMethodAbcId(ctorFunc);
SetRootProfileType(rootHc, abcId, entityId, kind);
}
void PGOProfiler::ProfileProtoTransitionClass(JSHandle<JSFunction> func,
@ -238,22 +221,11 @@ void PGOProfiler::UpdateRootProfileTypeSafe(JSHClass* oldHClass, JSHClass* newHC
return;
}
auto oldRootHClass = JSHClass::FindRootHClass(oldHClass);
auto iter = tracedProfiles_.find(JSTaggedType(oldRootHClass));
if (iter == tracedProfiles_.end()) {
return;
ProfileType oldPt = GetProfileType(oldRootHClass);
if (oldPt.IsRootType()) {
newHClass->SetProfileType(oldPt.GetRaw());
oldRootHClass->SetProfileType(0);
}
auto generator = iter->second;
auto rootProfileType = generator->GetProfileType(JSTaggedType(oldRootHClass));
{
LockHolder lock(tracedProfilesMutex_);
nativeAreaAllocator_->Delete(iter->second);
tracedProfiles_.erase(iter);
}
if (rootProfileType.IsNone()) {
return;
}
newHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
InsertProfileTypeSafe(JSTaggedType(newHClass), JSTaggedType(newHClass), rootProfileType);
}
void PGOProfiler::UpdateTrackElementsKind(JSTaggedValue trackInfoVal, ElementsKind newKind)
@ -1229,11 +1201,10 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco
void PGOProfiler::TryDumpProtoTransitionType(JSHClass *hclass)
{
JSHClass *ihc1 = JSHClass::FindRootHClass(hclass);
auto transitionType = GetProfileTypeSafe(JSTaggedType(ihc1), JSTaggedType(ihc1));
if (transitionType.IsNone() || !transitionType.IsTransitionClassType()) {
auto transitionType = GetProfileType(ihc1, true);
if (!transitionType.IsRootType() || !transitionType.IsTransitionClassType()) {
return;
}
ASSERT(transitionType.IsRootType());
JSTaggedValue phc1Root = JSHClass::FindProtoRootHClass(ihc1);
auto thread = vm_->GetJSThread();
@ -1243,21 +1214,23 @@ void PGOProfiler::TryDumpProtoTransitionType(JSHClass *hclass)
if ((ihc0 == 0) || (baseIhc == 0)) {
return;
}
UpdateLayout(JSHClass::Cast(JSTaggedValue(ihc0).GetTaggedObject()));
auto ihc0Obj = JSHClass::Cast(JSTaggedValue(ihc0).GetTaggedObject());
auto baseIhcObj = JSHClass::Cast(JSTaggedValue(baseIhc).GetTaggedObject());
UpdateLayout(ihc0Obj);
UpdateLayout(ihc1);
UpdateLayout(JSHClass::Cast(JSTaggedValue(baseIhc).GetTaggedObject()));
UpdateLayout(baseIhcObj);
auto ihc0RootType = GetProfileTypeSafe(ihc0, ihc0);
auto ihc0RootType = GetProfileType(ihc0Obj);
ASSERT(ihc0RootType.IsRootType());
auto transitionProtoType = GetProfileTypeSafe(phc1Root.GetRawData(), phc1Root.GetRawData());
auto transitionProtoType = GetProfileType(JSHClass::Cast(phc1Root.GetTaggedObject()), true);
ASSERT(transitionProtoType.IsRootType());
auto baseRootHClass = JSHClass::FindRootHClass(JSHClass::Cast(JSTaggedValue(baseIhc).GetTaggedObject()));
auto baseRootType = GetProfileTypeSafe(JSTaggedType(baseRootHClass), JSTaggedType(baseRootHClass));
auto baseRootHClass = JSHClass::FindRootHClass(baseIhcObj);
auto baseRootType = GetProfileType(baseRootHClass, true);
if (!baseRootType.IsRootType()) {
LOG_ECMA(WARN) << "Unsupported prototypes which cannot be recorded!";
return;
}
auto baseType = GetProfileTypeSafe(JSTaggedType(baseRootHClass), baseIhc);
auto baseType = GetProfileType(baseIhcObj);
ASSERT(!baseType.IsNone());
PGOProtoTransitionType protoTransitionType(ihc0RootType);
protoTransitionType.SetBaseType(baseRootType, baseType);
@ -1301,55 +1274,48 @@ void PGOProfiler::DumpDefineClass(ApEntityId abcId, const CString &recordName, E
if (object->GetClass()->IsJSFunction()) {
JSFunction *ctorFunction = JSFunction::Cast(object);
auto ctorMethod = ctorFunction->GetMethod();
if (!ctorMethod.IsMethod()) {
return;
}
if (!FunctionKindVerify(ctorFunction)) {
if (!ctorMethod.IsMethod() || !FunctionKindVerify(ctorFunction)) {
return;
}
ApEntityId ctorAbcId = GetMethodAbcId(ctorFunction);
auto ctorJSMethod = Method::Cast(ctorMethod);
auto ctorMethodId = ctorJSMethod->GetMethodId().GetOffset();
ProfileType recordType = GetRecordProfileType(abcId, recordName);
auto localType = PGOSampleType::CreateProfileType(ctorAbcId, ctorMethodId, ProfileType::Kind::ClassId, true);
PGODefineOpType objDefType(localType.GetProfileType());
auto localType = ProfileType(ctorAbcId, ctorMethodId, ProfileType::Kind::ClassId, true);
if (IsSkippableObjectTypeSafe(localType)) {
return;
}
PGODefineOpType objDefType(localType);
auto protoOrHClass = ctorFunction->GetProtoOrHClass();
if (protoOrHClass.IsJSHClass()) {
auto hclass = JSHClass::Cast(protoOrHClass.GetTaggedObject());
auto result = InsertProfileTypeSafe(JSTaggedType(hclass), JSTaggedType(hclass), localType.GetProfileType());
if (!result) {
LOG_COMPILER(DEBUG)
<< "DumpDefineClass InsertFail, May already exist , Method Name "
<< Method::Cast(ctorFunction->GetMethod())->GetMethodName();
}
recordInfos_->AddRootLayout(JSTaggedType(hclass), localType.GetProfileType());
protoOrHClass = hclass->GetProto();
auto ihc = JSHClass::Cast(protoOrHClass.GetTaggedObject());
SetRootProfileType(ihc, ctorAbcId, ctorMethodId, ProfileType::Kind::ClassId);
recordInfos_->AddRootLayout(JSTaggedType(ihc), localType);
protoOrHClass = ihc->GetProto();
}
auto ctorHClass = ctorFunction->GetJSHClass();
auto ctorRootHClass = JSTaggedType(JSHClass::FindRootHClass(ctorHClass));
auto ctorType = GetProfileTypeSafe(ctorRootHClass, ctorRootHClass);
if (ctorType.IsNone()) {
auto ctorRootHClass = JSHClass::FindRootHClass(ctorFunction->GetJSHClass());
auto ctorType = GetProfileType(ctorRootHClass);
if (!ctorType.IsRootType()) {
LOG_ECMA(DEBUG) << "The profileType of constructor root hclass was not found.";
} else {
objDefType.SetCtorPt(ctorType);
recordInfos_->AddRootLayout(ctorRootHClass, ctorType);
recordInfos_->AddRootLayout(JSTaggedType(ctorRootHClass), ctorType);
}
if (protoOrHClass.IsJSObject()) {
auto prototypeObj = JSObject::Cast(protoOrHClass);
auto prototypeHClass = prototypeObj->GetClass();
auto prototypeRootHClass = JSTaggedType(JSHClass::FindRootHClass(prototypeHClass));
auto prototypeType = GetProfileType(prototypeRootHClass, prototypeRootHClass);
if (prototypeType.IsNone()) {
auto prototypeHClass = JSObject::Cast(protoOrHClass)->GetClass();
auto prototypeRootHClass = JSHClass::FindRootHClass(prototypeHClass);
ProfileType prototypeType = GetProfileType(prototypeRootHClass);
if (!prototypeType.IsRootType()) {
LOG_ECMA(DEBUG) << "The profileType of prototype root hclass was not found.";
} else {
objDefType.SetProtoTypePt(prototypeType);
recordInfos_->AddRootLayout(prototypeRootHClass, prototypeType);
recordInfos_->AddRootLayout(JSTaggedType(prototypeRootHClass), prototypeType);
}
}
ProfileType recordType = GetRecordProfileType(abcId, recordName);
recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
}
}
@ -1367,9 +1333,8 @@ void PGOProfiler::DumpCreateObject(ApEntityId abcId, const CString &recordName,
if (object->GetClass()->IsHClass()) {
auto newHClass = JSHClass::Cast(object);
auto rootHClass = JSHClass::FindRootHClass(newHClass);
ASSERT(rootHClass->IsJSObject());
auto profileType = GetProfileTypeSafe(JSTaggedType(rootHClass), JSTaggedType(rootHClass));
if (profileType.IsNone()) {
ProfileType profileType = GetProfileType(rootHClass);
if (!profileType.IsRootType()) {
return;
}
ASSERT(profileType.GetKind() == ProfileType::Kind::ObjectLiteralId);
@ -1502,27 +1467,26 @@ void PGOProfiler::DumpInstanceof(ApEntityId abcId, const CString &recordName, En
void PGOProfiler::UpdateLayout(JSHClass *hclass)
{
auto parentHClass = hclass->GetParent();
if (parentHClass.IsJSHClass()) {
if (!GetProfileType(hclass).IsRootType() && parentHClass.IsJSHClass()) {
UpdateTransitionLayout(JSHClass::Cast(parentHClass.GetTaggedObject()), hclass);
} else {
auto rootHClass = JSHClass::FindRootHClass(hclass);
auto rootHClassVal = JSTaggedType(rootHClass);
auto rootType = GetProfileTypeSafe(rootHClassVal, rootHClassVal);
if (rootType.IsNone()) {
ProfileType rootType = GetProfileType(rootHClass, true);
if (!rootType.IsRootType()) {
return;
}
auto prototypeHClass = JSHClass::FindProtoRootHClass(rootHClass);
if (prototypeHClass.IsJSHClass()) {
auto prototypeValue = prototypeHClass.GetRawData();
auto prototypeType = GetProfileTypeSafe(prototypeValue, prototypeValue);
if (!prototypeType.IsNone()) {
auto prototypeObject = JSHClass::Cast(prototypeHClass.GetTaggedObject());
ProfileType prototypeType = GetProfileType(prototypeObject, true);
if (prototypeType.IsRootType()) {
recordInfos_->AddRootPtType(rootType, prototypeType);
UpdateLayout(JSHClass::Cast(prototypeHClass.GetTaggedObject()));
}
}
auto curType = GetOrInsertProfileTypeSafe(rootHClassVal, JSTaggedType(hclass));
auto curType = GetOrInsertProfileType(hclass, rootType);
recordInfos_->UpdateLayout(rootType, JSTaggedType(hclass), curType);
}
}
@ -1530,49 +1494,45 @@ void PGOProfiler::UpdateLayout(JSHClass *hclass)
void PGOProfiler::UpdateTransitionLayout(JSHClass* parent, JSHClass* child)
{
auto rootHClass = JSHClass::FindRootHClass(parent);
auto rootHClassVal = JSTaggedType(rootHClass);
auto rootType = GetProfileTypeSafe(rootHClassVal, rootHClassVal);
if (rootType.IsNone()) {
auto rootType = GetProfileType(rootHClass, true);
if (!rootType.IsRootType()) {
return;
}
auto curHClass = JSTaggedType(child);
auto curType = GetOrInsertProfileTypeSafe(rootHClassVal, curHClass);
CVector<JSTaggedType> hclassVec;
CVector<ProfileType> typeVec;
hclassVec.push_back(curHClass);
typeVec.push_back(curType);
CStack<JSHClass *> hclassVec;
hclassVec.emplace(child);
ASSERT(!GetProfileType(child).IsRootType());
hclassVec.emplace(parent);
auto parentHClass = JSTaggedValue(parent);
auto parentHCValue = JSTaggedType(parent);
auto parentType = GetOrInsertProfileTypeSafe(rootHClassVal, parentHCValue);
while (parentHClass.IsJSHClass()) {
parentHClass = JSHClass::Cast(parentHClass.GetTaggedObject())->GetParent();
if (!parentHClass.IsJSHClass()) {
while (!GetProfileType(parent).IsRootType()) {
auto parentHCValue = parent->GetParent();
if (!parentHCValue.IsJSHClass()) {
break;
}
hclassVec.push_back(parentHCValue);
typeVec.push_back(parentType);
parentHCValue = JSTaggedType(parentHClass.GetTaggedObject());
parentType = GetOrInsertProfileTypeSafe(rootHClassVal, parentHCValue);
parent = JSHClass::Cast(parentHCValue.GetTaggedObject());
hclassVec.emplace(parent);
}
auto prototypeHClass = JSHClass::FindProtoRootHClass(rootHClass);
if (prototypeHClass.IsJSHClass()) {
auto prototypeValue = prototypeHClass.GetRawData();
auto prototypeType = GetProfileTypeSafe(prototypeValue, prototypeValue);
if (!prototypeType.IsNone()) {
auto prototypeRootHClassVal = JSHClass::FindProtoRootHClass(rootHClass);
if (prototypeRootHClassVal.IsJSHClass()) {
auto prototypeRootHClass = JSHClass::Cast(prototypeRootHClassVal.GetTaggedObject());
auto prototypeType = GetProfileType(prototypeRootHClass);
if (prototypeType.IsRootType()) {
recordInfos_->AddRootPtType(rootType, prototypeType);
UpdateLayout(JSHClass::Cast(prototypeHClass.GetTaggedObject()));
UpdateLayout(prototypeRootHClass);
}
}
int32_t size = static_cast<int32_t>(hclassVec.size());
for (int32_t i = size - 1; i >= 0; i--) {
curHClass = hclassVec[i];
curType = typeVec[i];
recordInfos_->UpdateTransitionLayout(rootType, parentHCValue, parentType, curHClass, curType);
parentHCValue = curHClass;
parentType = curType;
parent = hclassVec.top();
hclassVec.pop();
auto parentType = GetProfileType(parent);
while (!hclassVec.empty()) {
child = hclassVec.top();
hclassVec.pop();
auto childType = GetOrInsertProfileType(child, rootType);
recordInfos_->UpdateTransitionLayout(
rootType, JSTaggedType(parent), parentType, JSTaggedType(child), childType);
parentType = childType;
parent = child;
}
}
@ -1584,26 +1544,19 @@ bool PGOProfiler::AddTransitionObjectInfo(ProfileType recordType,
JSHClass* holdTra,
PGOSampleType accessorMethod)
{
auto receiverRootHClass = JSTaggedType(JSHClass::FindRootHClass(receiver));
auto receiverRootType = GetProfileTypeSafe(receiverRootHClass, receiverRootHClass);
if (receiverRootType.IsNone()) {
auto receiverRootType = FindRootProfileType(receiver);
if (!receiverRootType.IsRootType()) {
return false;
}
auto receiverType = GetOrInsertProfileTypeSafe(receiverRootHClass, JSTaggedType(receiver));
auto holdRootHClass = JSTaggedType(JSHClass::FindRootHClass(hold));
auto holdRootType = GetProfileTypeSafe(holdRootHClass, holdRootHClass);
if (holdRootType.IsNone()) {
auto holdRootType = FindRootProfileType(hold);
if (!holdRootType.IsRootType()) {
return true;
}
auto holdType = GetOrInsertProfileTypeSafe(holdRootHClass, JSTaggedType(hold));
auto holdTraRootHClass = JSTaggedType(JSHClass::FindRootHClass(holdTra));
auto holdTraRootType = GetProfileTypeSafe(holdTraRootHClass, holdTraRootHClass);
if (holdTraRootType.IsNone()) {
return true;
}
auto holdTraType = GetOrInsertProfileTypeSafe(holdTraRootHClass, JSTaggedType(holdTra));
auto receiverType = GetOrInsertProfileType(receiver, receiverRootType);
auto holdType = GetOrInsertProfileType(hold, holdRootType);
auto holdTraType = GetOrInsertProfileType(holdTra, holdRootType);
if (receiver != hold) {
UpdateLayout(receiver);
@ -1615,7 +1568,7 @@ bool PGOProfiler::AddTransitionObjectInfo(ProfileType recordType,
UpdateTransitionLayout(hold, holdTra);
}
PGOObjectInfo info(receiverRootType, receiverType, holdRootType, holdType, holdTraRootType, holdTraType,
PGOObjectInfo info(receiverRootType, receiverType, holdRootType, holdType, holdRootType, holdTraType,
accessorMethod);
UpdatePrototypeChainInfo(receiver, hold, info);
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
@ -1643,12 +1596,11 @@ void PGOProfiler::UpdatePrototypeChainInfo(JSHClass *receiver, JSHClass *holder,
if (protoHClass == holder) {
break;
}
auto protoRootHClass = JSTaggedType(JSHClass::FindRootHClass(protoHClass));
auto protoRootType = GetProfileTypeSafe(protoRootHClass, protoRootHClass);
if (protoRootType.IsNone()) {
auto protoRootType = FindRootProfileType(protoHClass);
if (!protoRootType.IsRootType()) {
break;
}
auto protoType = GetOrInsertProfileTypeSafe(protoRootHClass, JSTaggedType(protoHClass));
auto protoType = GetOrInsertProfileType(protoHClass, protoRootType);
protoChain.emplace_back(protoRootType, protoType);
proto = JSHClass::FindProtoHClass(protoHClass);
}
@ -1817,82 +1769,51 @@ bool PGOProfiler::IsRecoredTransRootType(ProfileType type)
return false;
}
bool PGOProfiler::InsertProfileTypeSafe(JSTaggedType root, JSTaggedType child, ProfileType traceType)
void PGOProfiler::SetRootProfileType(JSHClass *root, ApEntityId abcId, uint32_t type, ProfileType::Kind kind)
{
if (!isEnable_) {
return false;
}
if (IsRecoredTransRootType(traceType)) {
return false;
}
auto iter = tracedProfiles_.find(root);
if (iter != tracedProfiles_.end()) {
auto generator = iter->second;
return generator->InsertProfileType(child, traceType);
} else {
LockHolder lock(tracedProfilesMutex_);
auto generator = nativeAreaAllocator_->New<PGOTypeGenerator>();
generator->InsertProfileType(child, traceType);
tracedProfiles_.emplace(root, generator);
return true;
ProfileType traceType(root->GetProfileType());
if (traceType.IsNone()) {
traceType = ProfileType(abcId, type, kind, true);
if (IsRecoredTransRootType(traceType)) {
return;
}
root->SetProfileType(traceType.GetRaw());
}
}
ProfileType PGOProfiler::GetProfileType(JSTaggedType root, JSTaggedType child)
ProfileType PGOProfiler::FindRootProfileType(JSHClass *hclass)
{
auto iter = tracedProfiles_.find(root);
if (iter == tracedProfiles_.end()) {
return ProfileType::PROFILE_TYPE_NONE;
auto rootHClass = JSHClass::FindRootHClass(hclass);
return GetProfileType(rootHClass, true);
}
ProfileType PGOProfiler::GetOrInsertProfileType(JSHClass *child, ProfileType rootType)
{
ProfileType childType = GetProfileType(child);
if (childType.IsNone()) {
ASSERT(rootType.IsRootType());
childType = PGOTypeGenerator::GenerateProfileType(JSTaggedType(child), rootType);
child->SetProfileType(childType.GetRaw());
}
auto generator = iter->second;
auto result = generator->GetProfileType(child);
if (IsSkippableObjectTypeSafe(result)) {
return ProfileType::PROFILE_TYPE_NONE;
return childType;
}
ProfileType PGOProfiler::GetProfileType(JSHClass *hclass, bool check)
{
auto result = ProfileType(hclass->GetProfileType());
if (check) {
if (IsSkippableObjectTypeSafe(result)) {
result = ProfileType::PROFILE_TYPE_NONE;
}
}
return result;
}
ProfileType PGOProfiler::GetProfileTypeSafe(JSTaggedType root, JSTaggedType child)
{
LockHolder lock(tracedProfilesMutex_);
return GetProfileType(root, child);
}
ProfileType PGOProfiler::GetOrInsertProfileTypeSafe(JSTaggedType root, JSTaggedType child)
{
LockHolder lock(tracedProfilesMutex_);
auto iter = tracedProfiles_.find(root);
if (iter == tracedProfiles_.end()) {
return ProfileType::PROFILE_TYPE_NONE;
}
auto generator = iter->second;
auto rootType = generator->GetProfileType(root);
if (rootType.IsNone()) {
return ProfileType::PROFILE_TYPE_NONE;
}
return generator->GenerateProfileType(rootType, child);
}
void PGOProfiler::ProcessReferences(const WeakRootVisitor &visitor)
{
if (!isEnable_) {
return;
}
for (auto iter = tracedProfiles_.begin(); iter != tracedProfiles_.end();) {
JSTaggedType object = iter->first;
auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
if (fwd == nullptr) {
nativeAreaAllocator_->Delete(iter->second);
iter = tracedProfiles_.erase(iter);
continue;
}
if (fwd != reinterpret_cast<TaggedObject *>(object)) {
UNREACHABLE();
}
auto generator = iter->second;
generator->ProcessReferences(visitor);
++iter;
}
preDumpWorkList_.Iterate([this, &visitor](WorkNode *node) {
auto object = reinterpret_cast<TaggedObject *>(node->GetValue());
auto fwd = visitor(object);
@ -1933,9 +1854,6 @@ PGOProfiler::PGOProfiler(EcmaVM* vm, bool isEnable)
PGOProfiler::~PGOProfiler()
{
Reset(false);
for (auto iter : tracedProfiles_) {
nativeAreaAllocator_->Delete(iter.second);
}
}
void PGOProfiler::Reset(bool isEnable)

View File

@ -57,8 +57,9 @@ public:
virtual ~PGOProfiler();
void PUBLIC_API RecordProfileType(JSHClass *hclass, JSPandaFile *pandaFile, int32_t traceId);
static ProfileType CreateRecordProfileType(ApEntityId abcId, ApEntityId classId);
void PUBLIC_API ProfileCreateObject(JSTaggedType object, ApEntityId abcId, int32_t traceId);
void ProfileDefineClass(JSTaggedType ctor);
void ProfileProtoTransitionClass(JSHandle<JSFunction> func,
JSHandle<JSHClass> hclass,
@ -216,10 +217,12 @@ private:
void AddBuiltinsGlobalInfo(ApEntityId abcId, const CString &recordName, EntityId methodId,
int32_t bcOffset, GlobalIndex globalId);
ProfileType GetProfileType(JSTaggedType root, JSTaggedType child);
ProfileType GetProfileTypeSafe(JSTaggedType root, JSTaggedType child);
ProfileType GetOrInsertProfileTypeSafe(JSTaggedType root, JSTaggedType child);
bool InsertProfileTypeSafe(JSTaggedType root, JSTaggedType child, ProfileType traceType);
void SetRootProfileType(JSHClass *root, ApEntityId abcId, uint32_t type, ProfileType::Kind kind);
ProfileType FindRootProfileType(JSHClass *hclass);
ProfileType GetOrInsertProfileType(JSHClass *child, ProfileType rootType);
ProfileType GetProfileType(JSHClass *hclass, bool check = false);
bool IsRecoredTransRootType(ProfileType type);
class WorkNode;
@ -525,8 +528,6 @@ private:
ConditionVariable condition_;
WorkList dumpWorkList_;
WorkList preDumpWorkList_;
Mutex tracedProfilesMutex_;
CMap<JSTaggedType, PGOTypeGenerator *> tracedProfiles_;
std::unique_ptr<PGORecordDetailInfos> recordInfos_;
// AOT only supports executing Defineclass bc once currently.
// If defineclass executed multiple times, It will gives up collection.

View File

@ -81,6 +81,7 @@ bool PGOHClassTreeDesc::DumpForRoot(JSTaggedType root, ProfileType rootType)
auto rootHClass = JSHClass::Cast(JSTaggedValue(root).GetTaggedObject());
if (iter != transitionLayout_.end()) {
rootLayout = iter->second;
return JSHClass::UpdateRootLayoutDescByPGO(rootHClass, rootLayout);
} else {
rootLayout = new RootHClassLayoutDesc(rootType, rootHClass->GetObjectType(),
rootHClass->GetObjectSizeExcludeInlinedProps());
@ -93,13 +94,7 @@ bool PGOHClassTreeDesc::DumpForRoot(JSTaggedType root, ProfileType rootType)
bool PGOHClassTreeDesc::DumpForChild(JSTaggedType child, ProfileType childType)
{
ASSERT(!childType.IsRootType());
auto rootType = GetProfileType();
auto rootIter = transitionLayout_.find(rootType);
auto childHClass = JSHClass::Cast(JSTaggedValue(child).GetTaggedObject());
if (rootIter != transitionLayout_.end()) {
auto rootLayout = rootIter->second;
JSHClass::UpdateRootLayoutDescByPGO(childHClass, this, rootLayout);
}
HClassLayoutDesc *childLayout;
auto iter = transitionLayout_.find(childType);
@ -134,10 +129,6 @@ bool PGOHClassTreeDesc::UpdateForTransition(
if (!DumpForRoot(parent, parentType)) {
return false;
}
} else {
if (!DumpForChild(parent, parentType)) {
return false;
}
}
bool ret = DumpForChild(child, childType);
auto parentLayoutDesc = transitionLayout_.find(parentType)->second;

View File

@ -35,12 +35,8 @@
namespace panda::ecmascript::pgo {
class PGOHandler {
public:
using PropertyMetaDataField = BitField<int, 0, 4>; // 4: property metaData field occupies 4 bits
using WritableField = BitField<bool, 0, 1>;
using EnumerableField = WritableField::NextFlag;
using ConfigurableField = EnumerableField::NextFlag;
using IsAccessorField = ConfigurableField::NextFlag;
using TrackTypeField = IsAccessorField::NextField<TrackType, PropertyAttributes::TRACK_TYPE_NUM>;
using TrackTypeField =
PropertyAttributes::PropertyMetaDataField::NextField<TrackType, PropertyAttributes::TRACK_TYPE_NUM>;
using IsSymbol = TrackTypeField::NextFlag;
PGOHandler()
@ -120,32 +116,32 @@ public:
void SetPropertyMeta(int meta)
{
PropertyMetaDataField::Set(meta, &value_);
PropertyAttributes::PropertyMetaDataField::Set(meta, &value_);
}
int GetPropertyMeta() const
{
return PropertyMetaDataField::Get(value_);
return PropertyAttributes::PropertyMetaDataField::Get(value_);
}
bool IsAccessor() const
{
return IsAccessorField::Get(value_);
return PropertyAttributes::IsAccessorField::Get(value_);
}
bool IsWritable() const
{
return WritableField::Get(value_);
return PropertyAttributes::WritableField::Get(value_);
}
bool IsEnumerable() const
{
return EnumerableField::Get(value_);
return PropertyAttributes::EnumerableField::Get(value_);
}
bool IsConfigurable() const
{
return ConfigurableField::Get(value_);
return PropertyAttributes::ConfigurableField::Get(value_);
}
bool operator!=(const PGOHandler &right) const

View File

@ -26,76 +26,18 @@
namespace panda::ecmascript::pgo {
class PGOTypeGenerator {
public:
ProfileType GenerateProfileType(ProfileType rootType, JSTaggedType hclass)
static ProfileType GenerateProfileType(JSTaggedType child, ProfileType rootType)
{
{
LockHolder lock(mutex_);
auto iter = exsitId_.find(hclass);
if (iter != exsitId_.end()) {
return iter->second;
}
}
CString result = JSHClass::DumpToString(hclass);
CString result = JSHClass::DumpToString(child);
uint32_t traceId = ComputeHashCode(result);
ProfileType type(rootType.GetAbcId(), traceId, rootType.GetKind());
LockHolder lock(mutex_);
exsitId_.emplace(hclass, type);
return type;
}
ProfileType GetProfileType(JSTaggedType hclass)
{
LockHolder lock(mutex_);
auto iter = exsitId_.find(hclass);
if (iter != exsitId_.end()) {
return iter->second;
}
return ProfileType::PROFILE_TYPE_NONE;
}
bool InsertProfileType(JSTaggedType hclass, ProfileType type)
{
LockHolder lock(mutex_);
auto iter = exsitId_.find(hclass);
if (iter != exsitId_.end()) {
return false;
}
exsitId_.emplace(hclass, type);
return true;
}
void UpdateProfileType(JSTaggedType oldHClass, JSTaggedType newHClass)
{
LockHolder lock(mutex_);
auto iter = exsitId_.find(oldHClass);
if (iter != exsitId_.end()) {
auto profileType = iter->second;
exsitId_.erase(oldHClass);
exsitId_.emplace(newHClass, profileType);
}
}
void ProcessReferences(const WeakRootVisitor &visitor)
{
for (auto iter = exsitId_.begin(); iter != exsitId_.end();) {
JSTaggedType object = iter->first;
auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
if (fwd == nullptr) {
iter = exsitId_.erase(iter);
continue;
}
if (fwd != reinterpret_cast<TaggedObject *>(object)) {
UNREACHABLE();
}
++iter;
}
}
private:
static constexpr uint32_t INVALID_ID = 0;
uint32_t ComputeHashCode(const CString &string)
static uint32_t ComputeHashCode(const CString &string)
{
uint32_t hash = INVALID_ID;
Span<const char> sp(string.c_str(), string.size());
@ -105,9 +47,6 @@ private:
}
return hash;
}
Mutex mutex_;
CMap<JSTaggedType, ProfileType> exsitId_;
};
} // namespace panda::ecmascript::pgo
#endif // ECMASCRIPT_PGO_PROFILER_TYPES_PGO_TYPE_GENERATOR_H

View File

@ -124,6 +124,7 @@ public:
static_assert(FastModeStartField::SIZE == CommonLastBitField::SIZE);
using OffsetField = FastModeStartField::NextField<uint32_t, OFFSET_BITFIELD_NUM>; // 17
using TrackTypeField = OffsetField::NextField<TrackType, TRACK_TYPE_NUM>; // 20: 3 bits
static_assert(TrackTypeField::END_BIT <= sizeof(uint32_t) * BITS_PER_BYTE, "Invalid");
// normal attr should include SharedFieldTypeField when set to layout
static constexpr uint32_t NORMAL_ATTR_BITS = 28;
@ -132,7 +133,8 @@ public:
using SortedIndexField = SharedFieldTypeField::NextField<uint32_t, OFFSET_BITFIELD_NUM>; // 38: 10 bits
using IsConstPropsField = SortedIndexField::NextFlag; // 39
using IsNotHoleField = IsConstPropsField::NextFlag; // 40
using FastModeLastField = IsNotHoleField;
using IsPGODumpedField = IsNotHoleField::NextFlag; // 41
using FastModeLastField = IsPGODumpedField;
static_assert(
FastModeLastField::START_BIT + FastModeLastField::SIZE <= MAX_BIT_SIZE, "Invalid");
@ -321,6 +323,16 @@ public:
TrackTypeField::Set<uint64_t>(type, &value_);
}
inline bool IsPGODumped()
{
return IsPGODumpedField::Get(value_);
}
inline void SetIsPGODumped(bool isDumped)
{
IsPGODumpedField::Set<uint64_t>(isDumped, &value_);
}
inline SharedFieldType GetSharedFieldType() const
{
return SharedFieldTypeField::Get(value_);

View File

@ -152,8 +152,7 @@ void BaseSerializer::SerializeHClassFieldIndividually(TaggedObject *root, Object
break;
}
case JSHClass::TRANSTIONS_OFFSET:
case JSHClass::PARENT_OFFSET:
case JSHClass::VTABLE_OFFSET: {
case JSHClass::PARENT_OFFSET: {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
slot++;
@ -167,13 +166,6 @@ void BaseSerializer::SerializeHClassFieldIndividually(TaggedObject *root, Object
slot++;
break;
}
case JSHClass::SUPERS_OFFSET: {
auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
data_->WriteEncodeFlag(EncodeFlag::ROOT_OBJECT);
data_->WriteUint32(globalConst->GetEmptyArrayIndex());
slot++;
break;
}
default: {
SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
slot++;

View File

@ -3089,6 +3089,13 @@ int32_t RuntimeStubs::FindElementWithCache(uintptr_t argGlue, JSTaggedType hclas
return index;
}
void RuntimeStubs::UpdateFieldType(JSTaggedType hclass, uint64_t value)
{
auto cls = reinterpret_cast<JSHClass *>(hclass);
PropertyAttributes attrValue(value);
JSHClass::UpdateFieldType(cls, attrValue);
}
JSTaggedType RuntimeStubs::GetActualArgvNoGC(uintptr_t argGlue)
{
auto thread = JSThread::GlueToJSThread(argGlue);

View File

@ -194,6 +194,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(CallDateNow) \
V(NumberIsFinite) \
V(FindElementWithCache) \
V(UpdateFieldType) \
V(CreateArrayFromList) \
V(StringsAreEquals) \
V(BigIntEquals) \
@ -595,6 +596,7 @@ public:
static double CallDateNow();
static int32_t FindElementWithCache(uintptr_t argGlue, JSTaggedType hclass,
JSTaggedType key, int32_t num);
static void UpdateFieldType(JSTaggedType hclass, uint64_t value);
static bool StringsAreEquals(EcmaString *str1, EcmaString *str2);
static bool BigIntEquals(JSTaggedType left, JSTaggedType right);
static bool BigIntSameValueZero(JSTaggedType key, JSTaggedType other);

View File

@ -98,6 +98,15 @@ inline void TaggedArray::Set(const JSThread *thread, uint32_t idx, const JSTagge
}
}
inline void TaggedArray::Set(uint32_t idx, const JSTaggedValue &value)
{
ASSERT(idx < GetLength());
ASSERT(!value.IsHeapObject());
size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, value.GetRawData());
}
JSHandle<TaggedArray> TaggedArray::Append(const JSThread *thread, const JSHandle<TaggedArray> &first,
const JSHandle<TaggedArray> &second)
{

View File

@ -43,6 +43,8 @@ public:
template <bool needBarrier = true>
void Set(const JSThread *thread, uint32_t idx, const JSTaggedValue &value);
void Set(uint32_t idx, const JSTaggedValue &value);
void SetBit(const JSThread* thread, uint32_t idx, uint32_t bitOffset, const JSTaggedValue& value);
static inline JSHandle<TaggedArray> Append(const JSThread *thread, const JSHandle<TaggedArray> &first,

View File

@ -900,7 +900,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
break;
}
case JSType::HCLASS: {
CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), JSHClass::SIZE, 10U);
CHECK_DUMP_FIELDS(TaggedObject::TaggedObjectSize(), JSHClass::SIZE, 9U);
JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSHClass::SIZE, JSType::HCLASS, proto);
DUMP_FOR_HANDLE(hclass);
break;

View File

@ -128,11 +128,24 @@ public:
}
int FindEntry(const JSTaggedValue &key, const JSTaggedValue &metaData);
template <typename Callback>
void IterateEntryValue(Callback callback)
{
auto number = EntriesCount();
for (int entry = 0; entry < number; entry++) {
JSTaggedValue ret = GetValue(entry);
if (ret.IsWeak()) {
auto next = ret.GetTaggedWeakRef();
callback(JSHClass::Cast(next));
}
}
}
static JSHandle<TransitionsDictionary> PutIfAbsent(const JSThread *thread,
const JSHandle<TransitionsDictionary> &dictionary,
const JSHandle<JSTaggedValue> &key,
const JSHandle<JSTaggedValue> &value,
const JSHandle<JSTaggedValue> &metaData);
// For test
static JSHandle<TransitionsDictionary> Remove(const JSThread *thread, const JSHandle<TransitionsDictionary> &table,
const JSHandle<JSTaggedValue> &key, const JSTaggedValue &metaData);
void Rehash(const JSThread *thread, TransitionsDictionary *newTable);

View File

@ -338,6 +338,7 @@
panda::ecmascript::pgo::ApNameUtils::GetRuntimeApName*;
panda::ecmascript::pgo::PGOMethodInfo::CalcChecksum*;
panda::ecmascript::pgo::PGOProfiler::ProfileCreateObject*;
panda::ecmascript::pgo::PGOProfiler::RecordProfileType*;
panda::ecmascript::pgo::PGOProfiler::GetMethodAbcId*;
panda::ecmascript::pgo::PGOProfilerManager::GetInstance*;
panda::ecmascript::pgo::PGOProfilerManager::MergeApFiles*;

View File

@ -14,3 +14,5 @@
0.5
0.5
0.5
1
-20

View File

@ -14,3 +14,5 @@
0.5
0.5
0.5
1
-10

View File

@ -58,3 +58,41 @@ Vec3.set(a.a0, 0.5, 0.5, 0.5);
print(a.a0.x)
print(a.a0.y)
print(a.a0.z)
class QType {
arr: number[];
Lastx:number = 0;
Lasty:number = 0;
Normal: Float64Array[] = new Array();
Line: boolean[] = new Array();
Edge: number[][] = new Array();
}
let obj = {x: 1, y: 2, z: 3, u: 3, v: 4}
let next = {x: 1, z: 2, y: 3, v: 3, u: 3}
let count = 0;
let Init = Change;
function Change(CubeSize: number) {
let Q: QType = new QType();
Q.arr = []
Q.arr[0] = base + 0 * -20;
if (count == 0) {
Q.arr[0] = 1;
}
obj.x = Q.arr[0];
print(obj.x);
}
let base = -10
if (ArkTools.isAOTCompiled(Init)) {
base = -20
}
Init(20)
count++;
Init(20)

View File

@ -16,7 +16,6 @@
declare function print(a0:any, a1?:any):string;
declare class ArkTools {
static isTSHClass(o:object):boolean;
static hasTSSubtyping(o:object):boolean;
}
class A {
@ -38,7 +37,6 @@ function testVTable(o:A) {
let b = new B();
print("Before breaking, B's ihclass is TS:", ArkTools.isTSHClass(b));
print("Before breaking, B's ihclass has TS inherit info:", ArkTools.hasTSSubtyping(b));
testVTable(b);
// break TS Chain on object
@ -47,5 +45,4 @@ b.foo = function () {
}
print("After breaking, b's hclass is TS:", ArkTools.isTSHClass(b));
print("After breaking, b's hclass has TS inherit info:", ArkTools.hasTSSubtyping(b));
testVTable(b); // occur deopt

View File

@ -12,8 +12,6 @@
# limitations under the License.
Before breaking, B's ihclass is TS: false
Before breaking, B's ihclass has TS inherit info: false
A foo
After breaking, b's hclass is TS: false
After breaking, b's hclass has TS inherit info: false
b foo

View File

@ -14,9 +14,6 @@
*/
declare function print(a0:any, a1?:any):string;
declare class ArkTools {
static hasTSSubtyping(o:object):boolean;
}
class A {
x:number;
@ -36,7 +33,6 @@ function testVTable(o:A) {
}
let b = new B();
print("Before breaking, B's ihclass has TS inherit info:", ArkTools.hasTSSubtyping(b));
testVTable(b);
// break TS Chain on prototype and notify through chain
@ -45,5 +41,4 @@ Object.defineProperty(B.prototype, "foo", { value: function() {
}
})
print("After breaking, B's ihclass has TS inherit info:", ArkTools.hasTSSubtyping(b));
testVTable(b); // occur deopt

View File

@ -11,7 +11,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
Before breaking, B's ihclass has TS inherit info: false
A foo
After breaking, B's ihclass has TS inherit info: false
B foo

View File

@ -15,9 +15,6 @@
// @ts-nocheck
declare function print(a0:any, a1?:any):string;
declare class ArkTools {
static hasTSSubtyping(o:object):boolean;
}
class A {
x:number;
@ -39,7 +36,6 @@ class B extends A {
let b = new B();
b.z1 = 123;
b.z2 = 456;
print(ArkTools.hasTSSubtyping(b));
print(b.x);
print(b.y);
print(b.z);
@ -50,7 +46,6 @@ print(b.z2);
A.prototype.t = 789; // break inherit info
let b1 = new B();
b1.z1 = 321; // transion success, has cleared inherit info
print(ArkTools.hasTSSubtyping(b1));
print(b1.x); // occur depot
print(b1.y);
print(b1.z);

View File

@ -11,13 +11,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
false
1
2
z
123
456
false
1
2
z

View File

@ -14,9 +14,6 @@
*/
declare function print(a0:any, a1?:any):string;
declare class ArkTools {
static hasTSSubtyping(o:object):boolean;
}
class A {
x:number;
@ -38,7 +35,6 @@ class B extends A {
let b = new B();
delete b.y;
Reflect.deleteProperty(b, "z");
print(ArkTools.hasTSSubtyping(b));
print(b.x);
print(b.y);
print(b.z);

View File

@ -11,7 +11,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
false
1
undefined
undefined

View File

@ -11,5 +11,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
false
1

View File

@ -35,5 +35,4 @@ class B {
}
let b = new B();
print(ArkTools.hasTSSubtyping(b));
print(b.x);

View File

@ -11,7 +11,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
false
1
false
123

View File

@ -43,9 +43,7 @@ class B extends A {
}
let a = new A();
print(ArkTools.hasTSSubtyping(a));
print(a.x);
let b = new B();
print(ArkTools.hasTSSubtyping(b));
print(b.x);

View File

@ -11,19 +11,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
false
1
false
1
false
1
false
2
false
3
false
4
false
5
false
6

View File

@ -48,12 +48,10 @@ class B extends A {
}
let a = new A();
print(ArkTools.hasTSSubtyping(a)); // true
print(a.foo()); // typedpath ---> 1
let b = new B();
print(ArkTools.hasTSSubtyping(b)); // false
print(b.foo); // slowpath ---> 1
// Base class and Object check
@ -64,7 +62,6 @@ class C {
}
let c = new C();
print(ArkTools.hasTSSubtyping(c)); // false
print(c.hasOwnProperty);
class C2 {
@ -74,7 +71,6 @@ class C2 {
}
let c2 = new C2();
print(ArkTools.hasTSSubtyping(c2)); // false
print(c2.isPrototypeOf);
class C3 {
@ -84,7 +80,6 @@ class C3 {
}
let c3 = new C3();
print(ArkTools.hasTSSubtyping(c3)); // false
print(c3.propertyIsEnumerable);
class C4 {
@ -94,7 +89,6 @@ class C4 {
}
let c4 = new C4();
print(ArkTools.hasTSSubtyping(c4)); // false
print(c4.toLocaleString);
class C5 {
@ -104,7 +98,6 @@ class C5 {
}
let c5 = new C5();
print(ArkTools.hasTSSubtyping(c5)); // false
print(c5.toString);
class C6 {
@ -114,5 +107,4 @@ class C6 {
}
let c6 = new C6();
print(ArkTools.hasTSSubtyping(c6)); // false
print(c6.valueOf);

View File

@ -11,7 +11,5 @@
# See the License for the specific language governing permissions and
# limitations under the License.
false
undefined
false
x

View File

@ -38,10 +38,8 @@ class B extends A {
}
let a = new A();
print(ArkTools.hasTSSubtyping(a));
print(a.x);
let b = new B();
print(ArkTools.hasTSSubtyping(b));
print(b.x());

View File

@ -11,19 +11,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
false
x
false
1
false
1
false
2
false
3
false
4
false
5
false
6

View File

@ -38,12 +38,10 @@ class B extends A {
}
let a = new A();
print(ArkTools.hasTSSubtyping(a));
print(a.x());
let b = new B();
print(ArkTools.hasTSSubtyping(b));
print(b.x);
// Base class and Object check
@ -55,7 +53,6 @@ class C {
}
let c = new C();
print(ArkTools.hasTSSubtyping(c)); // false
print(c.hasOwnProperty);
class C2 {
@ -66,7 +63,6 @@ class C2 {
}
let c2 = new C2();
print(ArkTools.hasTSSubtyping(c2)); // false
print(c2.isPrototypeOf);
class C3 {
@ -77,7 +73,6 @@ class C3 {
}
let c3 = new C3();
print(ArkTools.hasTSSubtyping(c3)); // false
print(c3.propertyIsEnumerable);
class C4 {
@ -88,7 +83,6 @@ class C4 {
}
let c4 = new C4();
print(ArkTools.hasTSSubtyping(c4)); // false
print(c4.toLocaleString);
class C5 {
@ -99,7 +93,6 @@ class C5 {
}
let c5 = new C5();
print(ArkTools.hasTSSubtyping(c5)); // false
print(c5.toString);
class C6 {
@ -110,5 +103,4 @@ class C6 {
}
let c6 = new C6();
print(ArkTools.hasTSSubtyping(c6)); // false
print(c6.valueOf);