Feat(Aot): Part4 Load hclass info from ap for aot compiler

Issue: #I7EGRC
Change-Id: I2493cc4f22b5579f28a93433845481febf17effc
Signed-off-by: yingguofeng@huawei.com <yingguofeng@huawei.com>
This commit is contained in:
yingguofeng@huawei.com 2023-06-25 15:02:31 +08:00
parent a54b399699
commit fb20da0b8f
26 changed files with 354 additions and 148 deletions

View File

@ -459,6 +459,8 @@ namespace panda::ecmascript::kungfu {
APPEND_SUFFIX(HandleDefineclasswithbufferImm8Id16Id16Imm16V8, V) \
APPEND_SUFFIX(HandleDefineclasswithbufferImm16Id16Id16Imm16V8, V) \
APPEND_SUFFIX(HandleDefinegettersetterbyvalueV8V8V8V8, V) \
APPEND_SUFFIX(HandleCreateobjectwithbufferImm8Id16, V) \
APPEND_SUFFIX(HandleCreateobjectwithbufferImm16Id16, V) \
APPEND_SUFFIX(HandleLdobjbynameImm8Id16, V) \
APPEND_SUFFIX(HandleLdobjbynameImm16Id16, V) \
APPEND_SUFFIX(HandleLdthisbynameImm16Id16, V) \

View File

@ -1444,6 +1444,26 @@ DEF_CALL_SIGNATURE(ProfileDefineClass)
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(ProfileCreateObject)
{
// 4: 4 input parameters
CallSignature defineProfInstruction(
"ProfileCreateObject", 0, 5, ArgumentsOrder::DEFAULT_ORDER, VariableType::VOID());
*callSign = defineProfInstruction;
// 4: 4 input parameters
std::array<VariableType, 5> params = { // 4 : 4 input parameters
VariableType::NATIVE_POINTER(),
VariableType::JS_ANY(),
VariableType::INT32(),
VariableType::JS_ANY(),
VariableType::JS_ANY(),
};
callSign->SetVariadicArgs(true);
callSign->SetParameters(params.data());
callSign->SetGCLeafFunction(true);
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(ProfileOpType)
{
// 4: 4 input parameters

View File

@ -417,6 +417,7 @@ private:
V(Comment) \
V(ProfileCall) \
V(ProfileDefineClass) \
V(ProfileCreateObject) \
V(ProfileOpType) \
V(ProfileObjLayout) \
V(FatalPrint) \

View File

@ -13,6 +13,7 @@
* limitations under the License.
*/
#include <initializer_list>
#include "ecmascript/base/number_helper.h"
#include "ecmascript/compiler/access_object_stub_builder.h"
#include "ecmascript/compiler/bc_call_signature.h"
@ -59,11 +60,12 @@ void name##StubBuilder::GenerateCircuitImpl(GateRef glue, GateRef sp, GateRef pc
GateRef acc, GateRef hotnessCounter, \
[[maybe_unused]] ProfileOperation callback)
#define REGISTER_PROFILE_CALL_BACK() \
ProfileOperation callback([this, glue, sp, pc, profileTypeInfo](GateRef value, OperationType type) { \
ProfilerStubBuilder profiler(this); \
profiler.PGOProfiler(glue, pc, GetFunctionFromFrame(GetFrame(sp)), profileTypeInfo, value, type); \
});
#define REGISTER_PROFILE_CALL_BACK() \
ProfileOperation callback( \
[this, glue, sp, pc, profileTypeInfo](const std::initializer_list<GateRef> &values, OperationType type) { \
ProfilerStubBuilder profiler(this); \
profiler.PGOProfiler(glue, pc, GetFunctionFromFrame(GetFrame(sp)), profileTypeInfo, values, type); \
});
#define REGISTER_NULL_CALL_BACK() ProfileOperation callback;
@ -3851,6 +3853,7 @@ DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm8Id16)
GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module);
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
callback.ProfileCreateObject(result, res);
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM8_ID16));
}
@ -3862,6 +3865,7 @@ DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm16Id16)
GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module);
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
callback.ProfileCreateObject(result, res);
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM16_ID16));
}

View File

@ -17,6 +17,7 @@
#define ECMASCRIPT_COMPILER_PROFILER_OPERATION_H
#include <functional>
#include <initializer_list>
#include "ecmascript/compiler/gate_meta_data.h"
@ -25,6 +26,7 @@ enum class OperationType : uint8_t {
CALL,
OPERATION_TYPE,
DEFINE_CLASS,
CREATE_OBJECT,
STORE_LAYOUT,
LOAD_LAYOUT,
};
@ -33,7 +35,7 @@ enum class OperationType : uint8_t {
callback.ProfileCombineOpType( \
*curType, type, [this](GateRef curType, GateRef type) -> GateRef { return Int32Or(curType, type); });
using Callback = std::function<void(GateRef, OperationType)>;
using Callback = std::function<void(const std::initializer_list<GateRef> &, OperationType)>;
class ProfileOperation {
public:
ProfileOperation() : callback_(nullptr) {}
@ -47,14 +49,14 @@ public:
inline void ProfileCall(GateRef func) const
{
if (callback_) {
callback_(func, OperationType::CALL);
callback_({ func }, OperationType::CALL);
}
}
inline void ProfileOpType(GateRef type) const
{
if (callback_) {
callback_(type, OperationType::OPERATION_TYPE);
callback_({ type }, OperationType::OPERATION_TYPE);
}
}
@ -63,28 +65,35 @@ public:
{
if (callback_) {
GateRef ret = combine(curType, type);
callback_(ret, OperationType::OPERATION_TYPE);
callback_({ ret }, OperationType::OPERATION_TYPE);
}
}
inline void ProfileDefineClass(GateRef constructor) const
{
if (callback_) {
callback_(constructor, OperationType::DEFINE_CLASS);
callback_({ constructor }, OperationType::DEFINE_CLASS);
}
}
inline void ProfileCreateObject(GateRef originObj, GateRef newObj) const
{
if (callback_) {
callback_({ originObj, newObj }, OperationType::CREATE_OBJECT);
}
}
inline void ProfileObjLayoutByStore(GateRef object) const
{
if (callback_) {
callback_(object, OperationType::STORE_LAYOUT);
callback_({ object }, OperationType::STORE_LAYOUT);
}
}
inline void ProfileObjLayoutByLoad(GateRef object) const
{
if (callback_) {
callback_(object, OperationType::LOAD_LAYOUT);
callback_({ object }, OperationType::LOAD_LAYOUT);
}
}

View File

@ -19,24 +19,27 @@
#include "ecmascript/compiler/stub_builder-inl.h"
namespace panda::ecmascript::kungfu {
void ProfilerStubBuilder::PGOProfiler(
GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, GateRef value, OperationType type)
void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo,
const std::vector<GateRef> &values, OperationType type)
{
switch (type) {
case OperationType::CALL:
ProfileCall(glue, value);
ProfileCall(glue, values[0]);
break;
case OperationType::OPERATION_TYPE:
ProfileOpType(glue, pc, func, profileTypeInfo, value);
ProfileOpType(glue, pc, func, profileTypeInfo, values[0]);
break;
case OperationType::DEFINE_CLASS:
ProfileDefineClass(glue, pc, func, value);
ProfileDefineClass(glue, pc, func, values[0]);
break;
case OperationType::CREATE_OBJECT:
ProfileCreateObject(glue, pc, func, values[0], values[1]);
break;
case OperationType::STORE_LAYOUT:
ProfileObjLayout(glue, pc, func, value, Int32(1));
ProfileObjLayout(glue, pc, func, values[0], Int32(1));
break;
case OperationType::LOAD_LAYOUT:
ProfileObjLayout(glue, pc, func, value, Int32(0));
ProfileObjLayout(glue, pc, func, values[0], Int32(0));
break;
default:
break;
@ -107,6 +110,21 @@ void ProfilerStubBuilder::ProfileDefineClass(GateRef glue, GateRef pc, GateRef f
env->SubCfgExit();
}
void ProfilerStubBuilder::ProfileCreateObject(GateRef glue, GateRef pc, GateRef func, GateRef originObj, GateRef newObj)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
GateRef firstPC =
Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
CallNGCRuntime(glue, RTSTUB_ID(ProfileCreateObject), { glue, func, offset, originObj, newObj });
env->SubCfgExit();
}
void ProfilerStubBuilder::ProfileObjLayout(GateRef glue, GateRef pc, GateRef func, GateRef object, GateRef store)
{
auto env = GetEnvironment();

View File

@ -29,11 +29,12 @@ public:
NO_COPY_SEMANTIC(ProfilerStubBuilder);
void GenerateCircuit() override {}
void PGOProfiler(
GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, GateRef value, OperationType type);
void PGOProfiler(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo,
const std::vector<GateRef> &values, OperationType type);
void ProfileCall(GateRef glue, GateRef func);
void ProfileOpType(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, GateRef type);
void ProfileDefineClass(GateRef glue, GateRef pc, GateRef func, GateRef constructor);
void ProfileCreateObject(GateRef glue, GateRef pc, GateRef func, GateRef originObj, GateRef newObj);
void ProfileObjLayout(GateRef glue, GateRef pc, GateRef func, GateRef object, GateRef store);
GateRef UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback);

View File

@ -40,9 +40,16 @@ void TSHClassGenerator::GenerateTSHClasses() const
}
}
void TSHClassGenerator::UpdateTSHClassFromPGO(JSHClass *hclass, const PGOHClassLayoutDesc &desc) const
void TSHClassGenerator::UpdateTSHClassFromPGO(const kungfu::GateType &type, const PGOHClassLayoutDesc &desc) const
{
DISALLOW_GARBAGE_COLLECTION;
auto hclassValue = tsManager_->GetTSHClass(type);
if (!hclassValue.IsJSHClass()) {
return;
}
tsManager_->InsertPtToGtMap(desc.GetClassType(), type);
auto hclass = JSHClass::Cast(hclassValue.GetTaggedObject());
const JSThread *thread = tsManager_->GetThread();
LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
int element = layoutInfo->NumberOfElements();

View File

@ -26,7 +26,7 @@ public:
~TSHClassGenerator() = default;
void GenerateTSHClasses() const;
void UpdateTSHClassFromPGO(JSHClass *hclass, const PGOHClassLayoutDesc &desc) const;
void UpdateTSHClassFromPGO(const kungfu::GateType &type, const PGOHClassLayoutDesc &desc) const;
private:
void RecursiveGenerate(const JSHandle<TSClassType> &classType) const;

View File

@ -19,6 +19,7 @@
#include "ecmascript/jspandafile/type_literal_extractor.h"
#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h"
#include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
#include "ecmascript/pgo_profiler/pgo_profiler_type.h"
#include "ecmascript/ts_types/ts_type_parser.h"
namespace panda::ecmascript::kungfu {
@ -166,26 +167,23 @@ PGOSampleType TypeRecorder::GetOrUpdatePGOType(TSManager *tsManager, int32_t off
if (!decoder_->GetHClassLayoutDesc(iter, &desc)) {
return PGOSampleType::NoneClassType();
}
auto hclassValue = tsManager->GetTSHClass(type);
if (hclassValue.IsJSHClass()) {
auto hclass = JSHClass::Cast(hclassValue.GetTaggedObject());
TSHClassGenerator generator(tsManager);
generator.UpdateTSHClassFromPGO(hclass, *desc);
}
TSHClassGenerator generator(tsManager);
generator.UpdateTSHClassFromPGO(type, *desc);
}
return iter;
}
if (bcOffsetPGORwTypeMap_.find(offset) != bcOffsetPGORwTypeMap_.end()) {
auto defineType = bcOffsetPGORwTypeMap_.at(offset);
// pass mono first
if (defineType.GetCount() == 1) {
return PGOSampleType(defineType.GetType(0));
}
}
return PGOSampleType::NoneType();
}
PGORWOpType TypeRecorder::GetRwOpType(int32_t offset) const
{
if (bcOffsetPGORwTypeMap_.find(offset) != bcOffsetPGORwTypeMap_.end()) {
return bcOffsetPGORwTypeMap_.at(offset);
}
return PGORWOpType();
}
bool TypeRecorder::TypeNeedFilter(GlobalTSTypeRef gt) const
{
return gt.IsDefault() || gt.IsGenericsModule();

View File

@ -38,6 +38,7 @@ public:
GateType GetType(const int32_t offset) const;
PGOSampleType GetOrUpdatePGOType(TSManager *tsManager, int32_t offset, const GateType &type) const;
PGORWOpType GetRwOpType(int32_t offset) const;
GateType GetArgType(const uint32_t argIndex) const;
GateType UpdateType(const int32_t offset, const GateType &type) const;

View File

@ -695,7 +695,7 @@ void JSHClass::CopyTSInheritInfo(const JSThread *thread, const JSHandle<JSHClass
newHClass->SetVTable(thread, copyVtable);
}
bool JSHClass::DumpForProfile(const JSHClass *hclass, PGOHClassLayoutDesc &desc, PGOObjLayoutKind kind)
bool JSHClass::DumpForProfile(const JSHClass *hclass, PGOHClassLayoutDesc &desc, PGOObjKind kind)
{
DISALLOW_GARBAGE_COLLECTION;
if (hclass->IsDictionaryMode()) {

View File

@ -1670,7 +1670,7 @@ public:
DECL_DUMP()
static CString DumpJSType(JSType type);
static bool DumpForProfile(const JSHClass *hclass, PGOHClassLayoutDesc &desc, PGOObjLayoutKind kind);
static bool DumpForProfile(const JSHClass *hclass, PGOHClassLayoutDesc &desc, PGOObjKind kind);
DECL_VISIT_OBJECT(PROTOTYPE_OFFSET, BIT_FIELD_OFFSET);

View File

@ -26,6 +26,7 @@
#include "ecmascript/jspandafile/literal_data_extractor.h"
#include "ecmascript/module/js_module_manager.h"
#include "ecmascript/patch/quick_fix_manager.h"
#include "ecmascript/pgo_profiler/pgo_profiler.h"
#include "libpandafile/class_data_accessor-inl.h"
#include "libpandafile/index_accessor.h"
@ -286,6 +287,9 @@ public:
valueHandle.Update(elements->Get(i + 1));
JSObject::DefinePropertyByLiteral(thread, obj, key, valueHandle);
}
PGOProfiler *profiler = thread->GetEcmaVM()->GetPGOProfiler();
profiler->InsertLiteralId(JSTaggedType(obj->GetJSHClass()), id);
val = obj.GetTaggedValue();
break;
}

View File

@ -164,7 +164,7 @@ bool LayoutInfo::IsUninitializedProperty(const JSHandle<JSObject> object, uint32
return val.IsHole();
}
void LayoutInfo::DumpFieldIndexForProfile(int index, PGOHClassLayoutDesc &desc, PGOObjLayoutKind kind)
void LayoutInfo::DumpFieldIndexForProfile(int index, PGOHClassLayoutDesc &desc, PGOObjKind kind)
{
auto key = GetKey(index);
if (key.IsString()) {

View File

@ -86,7 +86,7 @@ public:
void GetAllEnumKeys(const JSThread *thread, int end, int offset, TaggedArray *keyArray, uint32_t *keys,
const JSHandle<JSObject> object);
void DumpFieldIndexForProfile(int index, PGOHClassLayoutDesc &desc, PGOObjLayoutKind kind);
void DumpFieldIndexForProfile(int index, PGOHClassLayoutDesc &desc, PGOObjKind kind);
DECL_DUMP()
private:

View File

@ -122,10 +122,53 @@ void PGOProfiler::ProfileDefineClass(JSThread *thread, JSTaggedType func, int32_
}
auto prototypeObj = JSObject::Cast(prototype);
auto prototypeHClass = JSTaggedType(prototypeObj->GetClass());
recordInfos_->AddLayout(currentType, prototypeHClass, PGOObjLayoutKind::PROTOTYPE);
recordInfos_->AddLayout(currentType, prototypeHClass, PGOObjKind::PROTOTYPE);
auto ctorHClass = JSTaggedType(ctorFunction->GetJSHClass());
recordInfos_->AddLayout(currentType, ctorHClass, PGOObjLayoutKind::CONSTRUCTOR);
recordInfos_->AddLayout(currentType, ctorHClass, PGOObjKind::CONSTRUCTOR);
}
}
void PGOProfiler::ProfileCreateObject(JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj)
{
if (!isEnable_) {
return;
}
DISALLOW_GARBAGE_COLLECTION;
JSTaggedValue funcValue(func);
if (funcValue.IsJSFunction()) {
JSFunction *funcFunction = JSFunction::Cast(funcValue);
JSTaggedValue recordNameValue = funcFunction->GetRecordName();
if (recordNameValue.IsHole()) {
return;
}
CString recordName = ConvertToString(recordNameValue);
auto method = funcFunction->GetMethod();
if (!method.IsMethod()) {
return;
}
auto jsMethod = Method::Cast(method);
auto funcMethodId = jsMethod->GetMethodId();
auto originObjValue = JSTaggedValue(originObj);
auto newObjValue = JSTaggedValue(newObj);
if (!originObjValue.IsJSObject() || !newObjValue.IsJSObject()) {
return;
}
auto originHclass = JSObject::Cast(originObjValue)->GetJSHClass();
auto iter = literalIds_.find(JSTaggedType(originHclass));
if (iter == literalIds_.end()) {
return;
}
auto newHClass = JSObject::Cast(newObjValue) ->GetJSHClass();
InsertLiteralId(JSTaggedType(newHClass), iter->second);
auto currentType = PGOSampleType::CreateClassType(iter->second.GetOffset());
auto superType = PGOSampleType::CreateClassType(0);
recordInfos_->AddDefine(recordName, funcMethodId, offset, currentType, superType);
recordInfos_->AddLayout(currentType, JSTaggedType(newHClass), PGOObjKind::LOCAL);
}
}
@ -153,13 +196,20 @@ void PGOProfiler::ProfileObjLayout(JSThread *thread, JSTaggedType func, int32_t
auto holder = JSTaggedValue(object);
auto hclass = holder.GetTaggedObject()->GetClass();
auto ctor = JSTaggedValue::Undefined();
PGOObjLayoutKind kind = PGOObjLayoutKind::LOCAL;
PGOObjKind kind = PGOObjKind::LOCAL;
if (hclass->IsClassPrototype()) {
ctor = JSObject::GetCtorFromPrototype(thread, holder);
kind = PGOObjLayoutKind::PROTOTYPE;
kind = PGOObjKind::PROTOTYPE;
} else if (hclass->IsClassConstructor()) {
ctor = holder;
kind = PGOObjLayoutKind::CONSTRUCTOR;
kind = PGOObjKind::CONSTRUCTOR;
} else if (hclass->IsLiteral()) {
auto iter = literalIds_.find(JSTaggedType(hclass));
if (iter != literalIds_.end()) {
PGOObjectInfo info(ClassType(iter->second.GetOffset()), kind);
recordInfos_->AddObjectInfo(recordName, jsMethod->GetMethodId(), offset, info);
}
return;
} else {
auto prototype = hclass->GetProto();
ctor = JSObject::GetCtorFromPrototype(thread, prototype);
@ -173,12 +223,27 @@ void PGOProfiler::ProfileObjLayout(JSThread *thread, JSTaggedType func, int32_t
}
auto ctorJSMethod = Method::Cast(ctorMethod);
auto methodId = ctorJSMethod->GetMethodId();
PGOSampleType type = PGOSampleType::CreateClassType(methodId.GetOffset());
recordInfos_->AddType(recordName, jsMethod->GetMethodId(), offset, type);
PGOObjectInfo info(ClassType(methodId.GetOffset()), kind);
recordInfos_->AddObjectInfo(recordName, jsMethod->GetMethodId(), offset, info);
if (store) {
PGOSampleType type = PGOSampleType::CreateClassType(methodId.GetOffset());
recordInfos_->AddLayout(type, JSTaggedType(hclass), kind);
}
}
}
}
void PGOProfiler::InsertLiteralId(JSTaggedType hclass, EntityId literalId)
{
if (!isEnable_) {
return;
}
auto iter = literalIds_.find(hclass);
if (iter != literalIds_.end()) {
if (!(iter->second == literalId)) {
literalIds_.erase(iter);
}
}
literalIds_.emplace(hclass, literalId);
}
} // namespace panda::ecmascript

View File

@ -30,6 +30,7 @@ public:
void ProfileCall(JSTaggedType value, SampleMode mode = SampleMode::CALL_MODE);
void ProfileOpType(JSTaggedType func, int32_t offset, uint32_t type);
void ProfileCreateObject(JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj);
void ProfileDefineClass(JSThread *thread, JSTaggedType func, int32_t offset, JSTaggedType ctor);
void ProfileObjLayout(JSThread *thread, JSTaggedType func, int32_t offset, JSTaggedType object, bool store);
void SetSaveTimestamp(std::chrono::system_clock::time_point timestamp)
@ -37,6 +38,8 @@ public:
saveTimestamp_ = timestamp;
}
void InsertLiteralId(JSTaggedType hclass, EntityId literalId);
private:
static constexpr uint32_t MERGED_EVERY_COUNT = 20;
static constexpr auto MERGED_MIN_INTERVAL = std::chrono::milliseconds(15);
@ -69,6 +72,7 @@ private:
bool isEnable_ {false};
uint32_t methodCount_ {0};
std::chrono::system_clock::time_point saveTimestamp_;
CMap<JSTaggedType, EntityId> literalIds_;
std::unique_ptr<PGORecordDetailInfos> recordInfos_;
friend class PGOProfilerManager;
};

View File

@ -243,7 +243,7 @@ void PGOMethodTypeSet::SkipFromBinary(void **buffer)
}
}
bool PGOMethodTypeSet::ParseFromBinary(void **buffer)
bool PGOMethodTypeSet::ParseFromBinary(void **buffer, PGOProfilerHeader *const header)
{
uint32_t size = base::ReadBuffer<uint32_t>(buffer, sizeof(uint32_t));
for (uint32_t i = 0; i < size; i++) {
@ -252,7 +252,7 @@ bool PGOMethodTypeSet::ParseFromBinary(void **buffer)
scalarOpTypeInfos_.emplace(*reinterpret_cast<ScalarOpTypeInfo *>(typeInfo));
} else if (typeInfo->GetInfoType() == InfoType::DEFINE_CLASS_TYPE) {
objDefOpTypeInfos_.emplace(*reinterpret_cast<ObjDefOpTypeInfo *>(typeInfo));
} else if (typeInfo->GetInfoType() == InfoType::USE_HCLASS_TYPE) {
} else if (header->SupportUseHClassType() && typeInfo->GetInfoType() == InfoType::USE_HCLASS_TYPE) {
rwScalarOpTypeInfos_.emplace(*reinterpret_cast<RWScalarOpTypeInfo *>(typeInfo));
}
}
@ -488,7 +488,7 @@ void PGOMethodTypeSet::RWScalarOpTypeInfo::ProcessToText(std::string &text) cons
text += TYPE_SEPARATOR + SPACE;
}
isFirst = false;
text += type_.GetType(i).GetTypeString();
text += type_.GetObjectInfo(i).GetInfoString();
}
text += (SPACE + ARRAY_END);
}
@ -547,6 +547,14 @@ bool PGOMethodInfoMap::AddType(Chunk *chunk, PGOMethodId methodId, int32_t offse
return true;
}
bool PGOMethodInfoMap::AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info)
{
auto typeInfoSet = GetOrInsertMethodTypeSet(chunk, methodId);
ASSERT(typeInfoSet != nullptr);
typeInfoSet->AddObjectInfo(offset, info);
return true;
}
bool PGOMethodInfoMap::AddDefine(
Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType)
{
@ -625,7 +633,7 @@ bool PGOMethodInfoMap::ParseFromBinary(Chunk *chunk, uint32_t threshold, void **
}
if (header->SupportType()) {
auto typeInfoSet = chunk->New<PGOMethodTypeSet>();
typeInfoSet->ParseFromBinary(buffer);
typeInfoSet->ParseFromBinary(buffer, header);
methodTypeInfos_.emplace(info->GetMethodId(), typeInfoSet);
}
}
@ -802,7 +810,7 @@ bool PGOMethodIdSet::ParseFromBinary(uint32_t threshold, void **buffer, PGOProfi
<< ELEMENT_SEPARATOR << std::to_string(static_cast<int>(info->GetSampleMode()))
<< ELEMENT_SEPARATOR << info->GetMethodName();
if (header->SupportType()) {
methodInfo.GetPGOMethodTypeSet().ParseFromBinary(buffer);
methodInfo.GetPGOMethodTypeSet().ParseFromBinary(buffer, header);
}
}
@ -850,6 +858,14 @@ bool PGORecordDetailInfos::AddType(const CString &recordName, PGOMethodId method
return curMethodInfos->AddType(chunk_.get(), methodId, offset, type);
}
bool PGORecordDetailInfos::AddObjectInfo(
const CString &recordName, EntityId methodId, int32_t offset, const PGOObjectInfo &info)
{
auto curMethodInfos = GetMethodInfoMap(recordName);
ASSERT(curMethodInfos != nullptr);
return curMethodInfos->AddObjectInfo(chunk_.get(), methodId, offset, info);
}
bool PGORecordDetailInfos::AddDefine(
const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType)
{
@ -867,7 +883,7 @@ bool PGORecordDetailInfos::AddDefine(
return true;
}
bool PGORecordDetailInfos::AddLayout(PGOSampleType type, JSTaggedType hclass, PGOObjLayoutKind kind)
bool PGORecordDetailInfos::AddLayout(PGOSampleType type, JSTaggedType hclass, PGOObjKind kind)
{
auto hclassObject = JSHClass::Cast(JSTaggedValue(hclass).GetTaggedObject());
PGOHClassLayoutDesc descInfo(type.GetClassType());

View File

@ -52,59 +52,47 @@ static constexpr size_t ALIGN_SIZE = 4;
using PGOMethodId = EntityId;
/**
* |----PGOProfilerHeader
* |--------MAGIC
* |--------VERSION
* |--------SECTION_NUMBER
* |--------PANDA_FILE_INFO_SECTION_INFO
* |------------offset
* |------------size (reserve)
* |------------number
* |--------RECORD_INFO_SECTION_INFO
* |------------offset
* |------------size (reserve)
* |------------number
* |----PGOPandaFileInfos
* |--------SIZE
* |--------CHECK_SUM
* |--------...
* |----PGORecordDetailInfos
* |--------PGOMethodInfoMap
* |------------PGOMethodInfo
* |----------------size
* |----------------id
* |----------------count
* |----------------mode
* |----------------methodName
* |----------------methodChecksum
* |----------------...
* |------------PGOMethodTypeSet
* |----------------ScalarOpTypeInfo
* |--------------------size
* |--------------------offset
* |--------------------type
* |----------------...
* |----------------PGOHClassLayoutDescInner
* |--------------------size
* |--------------------offset
* |--------------------type
* |--------------------count
* |--------------------PGOLayoutDescInfo
* |------------------------size
* |------------------------type
* |------------------------key
* |--------------------...
* |----------------...
* |----PGORecordSimpleInfos
* |--------PGOMethodIdSet
* |------------id
* |------------...
|----PGOProfilerHeader
|--------MAGIC(8)
|------------{ 'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0' }
|--------VERSION(4)
|------------{ '0', '0', '0', '0' }
|--------SECTION_NUMBER(4)
|------------{ 3 }
|--------PANDA_FILE_INFO_SECTION_INFO(12)
|------------{ offset, size (reserve), number1 }
|--------RECORD_INFO_SECTION_INFO(12)
|------------{ offset, size (reserve), number2 }
|--------LAYOUT_DESC_SECTION_INFO(12)
|------------{ offset, size (reserve), number3 }
|
|----Section1: PGOPandaFileInfos(number1)
|--------[{ size, CHECK_SUM }, { size, CHECK_SUM }, ...]
|
|----Section2: PGORecordDetailInfos(number2)
|--------[ PGOMethodInfoMap(number4)
|------------{ offset, size, number4 }
|------------[ PGOMethodInfo(size1)
|----------------{ size1, entityId, count, mode, methodName, [{ size, offset, type }, { size, offset, type }, ...]},
|------------ PGOMethodInfo(size1)
|----------------{ size1, entityId, count, mode, methodName, [{ size, offset, type }, { size, offset, type }, ...]},
|--------------... ]
|-------- PGOMethodInfoMap()
|--------... ]
|
|----Section3: PGHClassLayoutDescs(number3)
|--------{ offset, size, number5 }
|--------[ PGOHClassLayoutDescInner(size)
|------------{ size, type, superType, count, ptCount, ctorCount, [{ size, handle, key }, { size, heandle, key }, ...]}
|-------- PGOHClassLayoutDescInner(size)
|------------{ size, type, superType, count, ptCount, ctorCount, [{ size, handle, key }, { size, heandle, key }, ...]}
*/
class PGOProfilerHeader : public base::FileHeader {
public:
static constexpr VersionType TYPE_MINI_VERSION = {0, 0, 0, 2};
static constexpr VersionType METHOD_CHECKSUM_MINI_VERSION = {0, 0, 0, 4};
static constexpr std::array<uint8_t, VERSION_SIZE> LAST_VERSION = {0, 0, 0, 4};
static constexpr VersionType USE_HCLASS_TYPE_MINI_VERSION = {0, 0, 0, 5};
static constexpr std::array<uint8_t, VERSION_SIZE> LAST_VERSION = {0, 0, 0, 5};
static constexpr size_t SECTION_SIZE = 3;
static constexpr size_t PANDA_FILE_SECTION_INDEX = 0;
static constexpr size_t RECORD_INFO_SECTION_INDEX = 1;
@ -176,6 +164,11 @@ public:
return InternalVerifyVersion(METHOD_CHECKSUM_MINI_VERSION);
}
bool SupportUseHClassType() const
{
return InternalVerifyVersion(USE_HCLASS_TYPE_MINI_VERSION);
}
NO_COPY_SEMANTIC(PGOProfilerHeader);
NO_MOVE_SEMANTIC(PGOProfilerHeader);
@ -395,26 +388,22 @@ public:
void AddType(uint32_t offset, PGOSampleType type)
{
if (type.IsClassType()) {
AddClassType(offset, type);
auto result = scalarOpTypeInfos_.find(ScalarOpTypeInfo(offset, type));
if (result != scalarOpTypeInfos_.end()) {
auto combineType = result->GetType().CombineType(type);
const_cast<ScalarOpTypeInfo &>(*result).SetType(combineType);
} else {
auto result = scalarOpTypeInfos_.find(ScalarOpTypeInfo(offset, type));
if (result != scalarOpTypeInfos_.end()) {
auto combineType = result->GetType().CombineType(type);
const_cast<ScalarOpTypeInfo &>(*result).SetType(combineType);
} else {
scalarOpTypeInfos_.emplace(offset, type);
}
scalarOpTypeInfos_.emplace(offset, type);
}
}
void AddClassType(uint32_t offset, PGOSampleType type)
void AddObjectInfo(uint32_t offset, const PGOObjectInfo &info)
{
auto result = rwScalarOpTypeInfos_.find(RWScalarOpTypeInfo(offset));
if (result != rwScalarOpTypeInfos_.end()) {
const_cast<RWScalarOpTypeInfo &>(*result).AddClassType(type);
const_cast<RWScalarOpTypeInfo &>(*result).AddObjectInfo(info);
} else {
rwScalarOpTypeInfos_.emplace(offset, type);
rwScalarOpTypeInfos_.emplace(offset, info);
}
}
@ -447,7 +436,7 @@ public:
void Merge(const PGOMethodTypeSet *info);
static void SkipFromBinary(void **buffer);
bool ParseFromBinary(void **buffer);
bool ParseFromBinary(void **buffer, PGOProfilerHeader *const header);
bool ProcessToBinary(std::stringstream &stream) const;
bool ParseFromText(const std::string &typeString);
@ -490,10 +479,10 @@ private:
public:
explicit RWScalarOpTypeInfo(uint32_t offset)
: TypeInfoHeader(InfoType::USE_HCLASS_TYPE, offset) {};
RWScalarOpTypeInfo(uint32_t offset, PGOSampleType type)
RWScalarOpTypeInfo(uint32_t offset, PGOObjectInfo info)
: TypeInfoHeader(sizeof(RWScalarOpTypeInfo), InfoType::USE_HCLASS_TYPE, offset)
{
type_.AddClassType(type.GetClassType());
type_.AddObjectInfo(info);
}
bool operator<(const RWScalarOpTypeInfo &right) const
@ -511,10 +500,9 @@ private:
type_.Merge(type.type_);
}
void AddClassType(const PGOSampleType &type)
void AddObjectInfo(const PGOObjectInfo &info)
{
ASSERT(type.IsClassType());
type_.AddClassType(type.GetClassType());
type_.AddObjectInfo(info);
}
PGORWOpType GetType() const
@ -761,6 +749,7 @@ public:
bool AddMethod(Chunk *chunk, Method *jsMethod, SampleMode mode);
bool AddType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type);
bool AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
bool AddDefine(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType);
void Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos);
@ -883,9 +872,10 @@ public:
// If it is a new method, return true.
bool AddMethod(const CString &recordName, Method *jsMethod, SampleMode mode);
bool AddType(const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type);
bool AddObjectInfo(const CString &recordName, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
bool AddDefine(
const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType);
bool AddLayout(PGOSampleType type, JSTaggedType hclass, PGOObjLayoutKind kind);
bool AddLayout(PGOSampleType type, JSTaggedType hclass, PGOObjKind kind);
void Merge(const PGORecordDetailInfos &recordInfos);
void ParseFromBinary(void *buffer, PGOProfilerHeader *const header);

View File

@ -16,16 +16,16 @@
#include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
namespace panda::ecmascript {
void PGOHClassLayoutDesc::UpdateKeyAndDesc(const CString &key, const PGOHandler &handler, PGOObjLayoutKind kind)
void PGOHClassLayoutDesc::UpdateKeyAndDesc(const CString &key, const PGOHandler &handler, PGOObjKind kind)
{
switch (kind) {
case PGOObjLayoutKind::LOCAL:
case PGOObjKind::LOCAL:
UpdateKeyAndDesc(key, handler, layoutDesc_);
break;
case PGOObjLayoutKind::PROTOTYPE:
case PGOObjKind::PROTOTYPE:
UpdateKeyAndDesc(key, handler, ptLayoutDesc_);
break;
case PGOObjLayoutKind::CONSTRUCTOR:
case PGOObjKind::CONSTRUCTOR:
UpdateKeyAndDesc(key, handler, ctorLayoutDesc_);
break;
default:
@ -47,13 +47,13 @@ bool PGOHClassLayoutDesc::FindDescWithKey(const CString &key, PGOHandler &handle
void PGOHClassLayoutDesc::Merge(const PGOHClassLayoutDesc &from)
{
for (const auto &iter : from.layoutDesc_) {
UpdateKeyAndDesc(iter.first, iter.second, PGOObjLayoutKind::LOCAL);
UpdateKeyAndDesc(iter.first, iter.second, PGOObjKind::LOCAL);
}
for (const auto &iter : from.ptLayoutDesc_) {
UpdateKeyAndDesc(iter.first, iter.second, PGOObjLayoutKind::PROTOTYPE);
UpdateKeyAndDesc(iter.first, iter.second, PGOObjKind::PROTOTYPE);
}
for (const auto &iter : from.ctorLayoutDesc_) {
UpdateKeyAndDesc(iter.first, iter.second, PGOObjLayoutKind::CONSTRUCTOR);
UpdateKeyAndDesc(iter.first, iter.second, PGOObjKind::CONSTRUCTOR);
}
}

View File

@ -82,11 +82,6 @@ private:
using PropertyDesc = std::pair<CString, PGOHandler>;
using LayoutDesc = CVector<PropertyDesc>;
enum class PGOObjLayoutKind {
LOCAL,
PROTOTYPE,
CONSTRUCTOR,
};
class PGOHClassLayoutDesc {
public:
@ -154,7 +149,7 @@ public:
ctorLayoutDesc_.emplace_back(key, handler);
}
void UpdateKeyAndDesc(const CString &key, const PGOHandler &handler, PGOObjLayoutKind kind);
void UpdateKeyAndDesc(const CString &key, const PGOHandler &handler, PGOObjKind kind);
bool FindDescWithKey(const CString &key, PGOHandler &handler) const;

View File

@ -293,45 +293,99 @@ private:
std::variant<Type, ClassType> type_;
};
enum class PGOObjKind {
LOCAL,
PROTOTYPE,
CONSTRUCTOR,
};
class PGOObjectInfo {
public:
PGOObjectInfo() : type_(ClassType()), objKind_(PGOObjKind::LOCAL) {}
PGOObjectInfo(ClassType type, PGOObjKind kind) : type_(type), objKind_(PGOObjKind::LOCAL)
{
if (kind == PGOObjKind::CONSTRUCTOR) {
objKind_ = kind;
}
}
std::string GetInfoString() const
{
std::string result = type_.GetTypeString();
result += "(";
if (objKind_ == PGOObjKind::CONSTRUCTOR) {
result += "c";
} else {
result += "l";
}
result += ")";
return result;
}
ClassType GetClassType() const
{
return type_;
}
bool IsNone() const
{
return type_.IsNone();
}
bool InConstructor() const
{
return objKind_ == PGOObjKind::CONSTRUCTOR;
}
bool operator<(const PGOObjectInfo &right) const
{
return type_ < right.type_ || objKind_ < right.objKind_;
}
bool operator==(const PGOObjectInfo &right) const
{
return type_ == right.type_ && objKind_ == right.objKind_;
}
private:
ClassType type_ { ClassType() };
PGOObjKind objKind_ { PGOObjKind::LOCAL };
};
class PGORWOpType : public PGOType {
public:
PGORWOpType() : PGOType(TypeKind::RW_OP_TYPE) {};
explicit PGORWOpType(const PGOSampleType &type) : PGOType(TypeKind::RW_OP_TYPE), count_(0)
{
ASSERT(type.IsClassType());
AddClassType(type.GetClassType());
}
PGORWOpType() : PGOType(TypeKind::RW_OP_TYPE), count_(0) {};
void Merge(const PGORWOpType &type)
{
for (int i = 0; i < type.count_; i++) {
AddClassType(type.type_[i]);
AddObjectInfo(type.infos_[i]);
}
}
void AddClassType(const ClassType &type)
void AddObjectInfo(const PGOObjectInfo &info)
{
if (type.IsNone()) {
if (info.IsNone()) {
return;
}
int32_t count = 0;
for (; count < count_; count++) {
if (type_[count] == type) {
if (infos_[count] == info) {
return;
}
}
if (count < 4) { // 4 : Class type
type_[count] = type;
if (count < POLY_CASE_NUM) {
infos_[count] = info;
count_++;
} else {
LOG_ECMA(DEBUG) << "Class type exceeds 4, discard";
}
}
ClassType GetType(int32_t index) const
PGOObjectInfo GetObjectInfo(int32_t index) const
{
ASSERT(index < count_);
return type_[index];
return infos_[index];
}
int32_t GetCount() const
@ -340,8 +394,9 @@ public:
}
private:
static constexpr int POLY_CASE_NUM = 4;
int count_ = 0;
ClassType type_[4];
PGOObjectInfo infos_[POLY_CASE_NUM];
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_PGO_PROFILER_TYPE_H

View File

@ -406,6 +406,13 @@ void RuntimeStubs::ProfileDefineClass(uintptr_t argGlue, uintptr_t func, int32_t
thread->GetEcmaVM()->GetPGOProfiler()->ProfileDefineClass(thread, func, offset, ctor);
}
void RuntimeStubs::ProfileCreateObject(
uintptr_t argGlue, JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj)
{
auto thread = JSThread::GlueToJSThread(argGlue);
thread->GetEcmaVM()->GetPGOProfiler()->ProfileCreateObject(func, offset, originObj, newObj);
}
void RuntimeStubs::ProfileObjLayout(uintptr_t argGlue, uintptr_t func, int32_t offset, uintptr_t object, int32_t store)
{
auto thread = JSThread::GlueToJSThread(argGlue);

View File

@ -98,6 +98,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(DebugPrintInstruction) \
V(ProfileCall) \
V(ProfileDefineClass) \
V(ProfileCreateObject) \
V(ProfileOpType) \
V(ProfileObjLayout) \
V(Comment) \
@ -354,6 +355,8 @@ public:
static void Comment(uintptr_t argStr);
static void ProfileCall(uintptr_t argGlue, uintptr_t func);
static void ProfileDefineClass(uintptr_t argGlue, uintptr_t func, int32_t offset, uintptr_t ctor);
static void ProfileCreateObject(
uintptr_t argGlue, JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj);
static void ProfileOpType(uintptr_t argGlue, uintptr_t func, int32_t offset, int32_t type);
static void ProfileObjLayout(uintptr_t argGlue, uintptr_t func, int32_t offset, uintptr_t object, int32_t store);
static void FatalPrint(int fmtMessageId, ...);

View File

@ -709,6 +709,11 @@ public:
return collectedGT_;
}
inline void InsertPtToGtMap(ClassType pgoType, const kungfu::GateType &gateType)
{
ptToGtMap_.emplace(pgoType, gateType);
}
void PrintNumOfTypes() const;
void PrintTypeInfo(const JSPandaFile *jsPandaFile) const;
@ -808,6 +813,7 @@ private:
JSThread *thread_ {nullptr};
ObjectFactory *factory_ {nullptr};
JSTaggedValue globalModuleTable_ {JSTaggedValue::Hole()};
CMap<ClassType, const kungfu::GateType> ptToGtMap_ {};
std::map<GlobalTSTypeRef, IHClassData> gtIhcMap_ {};
std::map<GlobalTSTypeRef, IHClassData> gtConstructorhcMap_ {};
bool assertTypes_ {false};