Fix(Aot): Support ldobjbyValue and string.length fastpath by pgotype

Issue: #I8HJDP
Change-Id: I80eb3096f8e3c40218ae1142194b5b5d4a5afb1d
Signed-off-by: yingguofeng@huawei.com <yingguofeng@huawei.com>
This commit is contained in:
yingguofeng@huawei.com 2023-11-21 16:47:28 +08:00
parent c544e90445
commit 82336875e9
23 changed files with 375 additions and 110 deletions

View File

@ -440,7 +440,7 @@ public:
GateRef RangeGuard(GateRef gate, uint32_t left, uint32_t right);
GateRef BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId type);
GateRef OrdinaryHasInstanceCheck(GateRef target, GateRef jsFunc, std::vector<GateRef> &expectedHCIndexes);
GateRef IndexCheck(GateType type, GateRef gate, GateRef index);
GateRef IndexCheck(GateRef gate, GateRef index);
GateRef ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex);
GateRef ObjectTypeCompare(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex);
GateRef TryPrimitiveTypeCheck(GateType type, GateRef gate);

View File

@ -324,7 +324,6 @@ bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs)
break;
}
case OpCode::TYPED_ARRAY_CHECK:
case OpCode::INDEX_CHECK:
case OpCode::TYPE_OF_CHECK: {
if (acc_.GetParamGateType(lhs) != acc_.GetParamGateType(rhs)) {
return false;

View File

@ -234,13 +234,13 @@ GateRef CircuitBuilder::BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId
return ret;
}
GateRef CircuitBuilder::IndexCheck(GateType type, GateRef gate, GateRef index)
GateRef CircuitBuilder::IndexCheck(GateRef gate, GateRef index)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
auto frameState = acc_.FindNearestFrameState(currentDepend);
GateRef ret = GetCircuit()->NewGate(circuit_->IndexCheck(static_cast<size_t>(type.Value())),
GateRef ret = GetCircuit()->NewGate(circuit_->IndexCheck(),
MachineType::I64, {currentControl, currentDepend, gate, index, frameState}, GateType::IntType());
currentLabel->SetControl(ret);
currentLabel->SetDepend(ret);

View File

@ -53,6 +53,7 @@ namespace panda::ecmascript::kungfu {
V(InlineAccessorCheck, INLINE_ACCESSOR_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(ArrayConstructorCheck, ARRAY_CONSTRUCTOR_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(ObjectConstructorCheck, OBJECT_CONSTRUCTOR_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(IndexCheck, INDEX_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
MCR_BINARY_GATE_META_DATA_CACHE_LIST(V)
#define MCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \
@ -90,7 +91,6 @@ namespace panda::ecmascript::kungfu {
V(PrimitiveTypeCheck, PRIMITIVE_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(TypedArrayCheck, TYPED_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(LoadTypedArrayLength, LOAD_TYPED_ARRAY_LENGTH, GateFlags::NO_WRITE, 1, 1, 1) \
V(IndexCheck, INDEX_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \
V(TypedUnaryOp, TYPED_UNARY_OP, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedConditionJump, TYPED_CONDITION_JUMP, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedConvert, TYPE_CONVERT, GateFlags::NO_WRITE, 1, 1, 1) \

View File

@ -56,8 +56,8 @@ std::vector<ElementsKind> PGOTypeRecorder::GetElementsKindsForUser(int32_t offse
for (uint32_t i = 0; i < rwType.GetCount(); i++) {
PGOObjectInfo info = rwType.GetObjectInfo(i);
auto profileType = info.GetProfileType();
if (profileType.IsElementType()) {
elementsKinds.emplace_back(ElementsKind(profileType.GetId()));
if (profileType.IsBuiltinsArray()) {
elementsKinds.emplace_back(profileType.GetElementsKind());
continue;
}
}

View File

@ -1048,6 +1048,18 @@ GateRef TypeBytecodeLowering::BuildNamedPropertyAccess(
bool TypeBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate, GateType receiverType, JSTaggedValue key)
{
ChunkVector<ProfileType> types(chunk_);
FetchBuiltinsTypes(gate, types);
// Just supported mono.
if (types.size() == 1) {
if (types[0].IsBuiltinsString()) {
return TryLowerTypedLdObjByNameForBuiltin(gate, key, BuiltinTypeId::STRING);
}
if (types[0].IsBuiltinsArray()) {
return TryLowerTypedLdObjByNameForBuiltin(gate, key, BuiltinTypeId::ARRAY);
}
}
// String: primitive string type only
// e.g. let s1 = "ABC"; // OK
// let s2 = new String("DEF"); // Not included, whose type is JSType::JS_PRIMITIVE_REF
@ -1239,7 +1251,7 @@ void TypeBytecodeLowering::LowerTypedStObjByIndex(GateRef gate)
index = builder_.Int32(indexValue);
auto length = builder_.LoadTypedArrayLength(receiverType, receiver);
if (!Uncheck()) {
builder_.IndexCheck(receiverType, length, index);
builder_.IndexCheck(length, index);
}
if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY, receiverType)) {
@ -1267,22 +1279,34 @@ void TypeBytecodeLowering::LowerTypedLdObjByValue(GateRef gate, bool isThis)
receiver = acc_.GetValueIn(gate, 1);
propKey = acc_.GetValueIn(gate, 2); // 2: the third parameter
}
ChunkVector<ProfileType> types(chunk_);
FetchBuiltinsTypes(gate, types);
GateRef result = Circuit::NullGate();
// Just supported mono.
if (types.size() == 1) {
if (types[0].IsBuiltinsString()) {
AddProfiling(gate);
acc_.SetGateType(propKey, GateType::NumberType());
result = LoadStringByIndex(receiver, propKey);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
return;
} else if (types[0].IsBuiltinsArray()) {
AddProfiling(gate);
ElementsKind kind = acc_.TryGetArrayElementsKind(gate);
acc_.SetGateType(propKey, GateType::NumberType());
result = LoadJSArrayByIndex(receiver, propKey, kind);
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
return;
}
}
GateType receiverType = acc_.GetGateType(receiver);
GateType propKeyType = acc_.GetGateType(propKey);
receiverType = tsManager_->TryNarrowUnionType(receiverType);
if (!propKeyType.IsNumberType()) {
return; // slowpath
}
GateRef result = Circuit::NullGate();
if (receiverType.IsStringType()) {
AddProfiling(gate);
result = LoadStringByIndex(receiver, propKey);
} else if (tsManager_->IsArrayTypeKind(receiverType)) {
AddProfiling(gate);
ElementsKind kind = acc_.TryGetArrayElementsKind(gate);
result = LoadJSArrayByIndex(receiver, propKey, kind);
} else if (tsManager_->IsValidTypedArrayType(receiverType)) {
if (tsManager_->IsValidTypedArrayType(receiverType)) {
AddProfiling(gate);
result = LoadTypedArrayByIndex(receiver, propKey);
} else {
@ -1294,11 +1318,9 @@ void TypeBytecodeLowering::LowerTypedLdObjByValue(GateRef gate, bool isThis)
GateRef TypeBytecodeLowering::LoadStringByIndex(GateRef receiver, GateRef propKey)
{
if (!Uncheck()) {
GateType receiverType = acc_.GetGateType(receiver);
receiverType = tsManager_->TryNarrowUnionType(receiverType);
builder_.EcmaStringCheck(receiver);
GateRef length = builder_.LoadStringLength(receiver);
propKey = builder_.IndexCheck(receiverType, length, propKey);
propKey = builder_.IndexCheck(length, propKey);
receiver = builder_.FlattenTreeStringCheck(receiver);
}
return builder_.LoadElement<TypedLoadOp::STRING_LOAD_ELEMENT>(receiver, propKey);
@ -1307,13 +1329,11 @@ GateRef TypeBytecodeLowering::LoadStringByIndex(GateRef receiver, GateRef propKe
GateRef TypeBytecodeLowering::LoadJSArrayByIndex(GateRef receiver, GateRef propKey, ElementsKind kind)
{
if (!Uncheck()) {
GateType receiverType = acc_.GetGateType(receiver);
receiverType = tsManager_->TryNarrowUnionType(receiverType);
if (!IsCreateArray(receiver)) {
builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
}
GateRef length = builder_.LoadArrayLength(receiver);
propKey = builder_.IndexCheck(receiverType, length, propKey);
propKey = builder_.IndexCheck(length, propKey);
}
GateRef result = Circuit::NullGate();
@ -1338,7 +1358,7 @@ GateRef TypeBytecodeLowering::LoadTypedArrayByIndex(GateRef receiver, GateRef pr
if (!Uncheck()) {
builder_.TypedArrayCheck(receiverType, receiver);
GateRef length = builder_.LoadTypedArrayLength(receiverType, receiver);
propKey = builder_.IndexCheck(receiverType, length, propKey);
propKey = builder_.IndexCheck(length, propKey);
}
auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
switch (builtinTypeId) {
@ -1371,13 +1391,11 @@ GateRef TypeBytecodeLowering::LoadTypedArrayByIndex(GateRef receiver, GateRef pr
void TypeBytecodeLowering::StoreJSArrayByIndex(GateRef receiver, GateRef propKey, GateRef value, ElementsKind kind)
{
if (!Uncheck()) {
GateType receiverType = acc_.GetGateType(receiver);
receiverType = tsManager_->TryNarrowUnionType(receiverType);
if (!IsCreateArray(receiver)) {
builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
}
GateRef length = builder_.LoadArrayLength(receiver);
builder_.IndexCheck(receiverType, length, propKey);
builder_.IndexCheck(length, propKey);
builder_.COWArrayCheck(receiver);
if (Elements::IsObject(kind)) {
@ -1396,7 +1414,7 @@ void TypeBytecodeLowering::StoreTypedArrayByIndex(GateRef receiver, GateRef prop
if (!Uncheck()) {
builder_.TypedArrayCheck(receiverType, receiver);
GateRef length = builder_.LoadTypedArrayLength(receiverType, receiver);
propKey = builder_.IndexCheck(receiverType, length, propKey);
propKey = builder_.IndexCheck(length, propKey);
}
auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
@ -2032,11 +2050,25 @@ void TypeBytecodeLowering::AddProfiling(GateRef gate)
}
}
void TypeBytecodeLowering::FetchBuiltinsTypes(GateRef gate, ChunkVector<ProfileType> &types)
{
const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate).GetPGORWOpType();
for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
auto temp = pgoTypes->GetObjectInfo(i);
if (temp.GetReceiverType().IsBuiltinsType()) {
types.emplace_back(temp.GetReceiverType());
}
}
}
void TypeBytecodeLowering::FetchPGORWTypesDual(GateRef gate, ChunkVector<std::pair<ProfileTyper, ProfileTyper>> &types)
{
const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate).GetPGORWOpType();
for (uint32_t i = 0; i < pgoTypes->GetCount(); ++i) {
auto temp = pgoTypes->GetObjectInfo(i);
if (temp.GetReceiverType().IsBuiltinsType()) {
continue;
}
types.emplace_back(std::make_pair(
std::make_pair(temp.GetReceiverRootType(), temp.GetReceiverType()),
std::make_pair(temp.GetHoldRootType(), temp.GetHoldType())

View File

@ -21,6 +21,7 @@
#include "ecmascript/compiler/builtins/builtins_call_signature.h"
#include "ecmascript/compiler/bytecode_circuit_builder.h"
#include "ecmascript/compiler/circuit_builder-inl.h"
#include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
#include "ecmascript/compiler/object_access_helper.h"
#include "ecmascript/compiler/pass_manager.h"
#include "ecmascript/enum_conversion.h"
@ -41,6 +42,7 @@ public:
builder_(circuit, ctx->GetCompilerConfig()),
dependEntry_(circuit->GetDependRoot()),
tsManager_(ctx->GetTSManager()),
ptManager_(ctx->GetPTManager()),
chunk_(chunk),
enableLog_(enableLog),
enableTypeLog_(enableTypeLog),
@ -190,6 +192,7 @@ private:
void DeleteConstDataIfNoUser(GateRef gate);
bool TryLowerNewBuiltinConstructor(GateRef gate);
void FetchBuiltinsTypes(GateRef gate, ChunkVector<ProfileType> &types);
void FetchPGORWTypesDual(GateRef gate, ChunkVector<std::pair<ProfileTyper, ProfileTyper>> &types);
void AddProfiling(GateRef gate);
@ -203,6 +206,7 @@ private:
CircuitBuilder builder_;
GateRef dependEntry_ {Gate::InvalidGateRef};
TSManager *tsManager_ {nullptr};
PGOTypeManager *ptManager_ {nullptr};
Chunk *chunk_ {nullptr};
bool enableLog_ {false};
bool enableTypeLog_ {false};

View File

@ -81,6 +81,11 @@ public:
}
static inline bool IsElement(uint32_t handler)
{
return IsNormalElement(handler) || IsStringElement(handler) || IsTypedArrayElement(handler);
}
static inline bool IsNormalElement(uint32_t handler)
{
return GetKind(handler) == HandlerKind::ELEMENT;
}

View File

@ -113,7 +113,7 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::TryLoadICByValue(JSThread *thread, JSTag
if (receiver.IsHeapObject()) {
auto hclass = receiver.GetTaggedObject()->GetClass();
if (firstValue.GetWeakReferentUnChecked() == hclass) {
if (HandlerBase::IsElement(secondValue.GetInt())) {
if (HandlerBase::IsNormalElement(secondValue.GetInt())) {
return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
} else if (HandlerBase::IsTypedArrayElement(secondValue.GetInt())) {
return LoadTypedArrayElement(thread, receiver, key);

View File

@ -65,7 +65,7 @@ HWTEST_F_L0(ICHandlerTest, LoadElement)
JSHandle<JSTaggedValue> handleKey(factory->NewFromASCII("key"));
ObjectOperator handleOp(thread, handleKey);
JSTaggedValue result = LoadHandler::LoadElement(thread, handleOp).GetTaggedValue();
EXPECT_TRUE(HandlerBase::IsElement(result.GetInt()));
EXPECT_TRUE(HandlerBase::IsNormalElement(result.GetInt()));
EXPECT_EQ(HandlerBase::GetKind(result.GetInt()), HandlerKind::ELEMENT);
}

View File

@ -443,7 +443,7 @@ void JSHClass::ShouldUpdateProtoClass(const JSThread *thread, const JSHandle<JST
#endif
JSObject::Cast(proto->GetTaggedObject())->SynchronizedSetClass(*newProtoClass);
newProtoClass->SetIsPrototype(true);
thread->GetEcmaVM()->GetPGOProfiler()->UpdateProfileType(*hclass, *newProtoClass);
thread->GetEcmaVM()->GetPGOProfiler()->UpdateRootProfileType(*hclass, *newProtoClass);
} else {
hclass->SetIsPrototype(true);
}

View File

@ -23,6 +23,7 @@
#include "ecmascript/ic/profile_type_info.h"
#include "ecmascript/interpreter/interpreter-inl.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/jspandafile/js_pandafile_manager.h"
#include "ecmascript/log_wrapper.h"
#include "ecmascript/pgo_profiler/pgo_context.h"
@ -152,7 +153,7 @@ void PGOProfiler::ProfileDefineGetterSetter(
AddTranstionLayout(receverHClass, holderHClass);
}
void PGOProfiler::UpdateProfileType(JSHClass *oldHClass, JSHClass *newHClass)
void PGOProfiler::UpdateRootProfileType(JSHClass *oldHClass, JSHClass *newHClass)
{
if (!isEnable_) {
return;
@ -163,12 +164,14 @@ void PGOProfiler::UpdateProfileType(JSHClass *oldHClass, JSHClass *newHClass)
return;
}
auto generator = iter->second;
generator->UpdateProfileType(JSTaggedType(oldHClass), JSTaggedType(newHClass));
if (oldRootHClass == oldHClass) {
auto rootProfileType = generator->GetProfileType(JSTaggedType(oldRootHClass));
if (rootProfileType.IsNone()) {
tracedProfiles_.erase(iter);
auto newRootHClass = JSHClass::FindRootHClass(newHClass);
tracedProfiles_.emplace(JSTaggedType(newRootHClass), generator);
return;
}
tracedProfiles_.erase(iter);
newHClass->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
InsertProfileType(JSTaggedType(newHClass), JSTaggedType(newHClass), rootProfileType);
}
void PGOProfiler::UpdateTrackElementsKind(JSTaggedValue trackInfoVal, ElementsKind newKind)
@ -770,7 +773,10 @@ void PGOProfiler::DumpICByNameWithHandler(ApEntityId abcId, const CString &recor
if (HandlerBase::IsNonExist(handlerInfo)) {
return;
}
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
if (HandlerBase::IsField(handlerInfo)) {
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
}
AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass);
} else if (secondValue.IsPrototypeHandler()) {
auto prototypeHandler = PrototypeHandler::Cast(secondValue.GetTaggedObject());
auto cellValue = prototypeHandler->GetProtoCell();
@ -854,8 +860,8 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco
if (type == BCType::LOAD) {
if (secondValue.IsInt()) {
auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
if (HandlerBase::IsJSArray(handlerInfo) || HandlerBase::IsTypedArrayElement(handlerInfo)) {
AddElementInfo(abcId, recordName, methodId, bcOffset, hclass);
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass);
return;
}
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
@ -864,8 +870,8 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco
}
if (secondValue.IsInt()) {
auto handlerInfo = static_cast<uint32_t>(secondValue.GetInt());
if (HandlerBase::IsJSArray(handlerInfo) || HandlerBase::IsTypedArrayElement(handlerInfo)) {
AddElementInfo(abcId, recordName, methodId, bcOffset, hclass);
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass);
return;
}
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, hclass);
@ -878,8 +884,8 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco
auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
if (transitionHClassVal.IsJSHClass()) {
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
if (HandlerBase::IsJSArray(handlerInfo)) {
AddElementInfo(abcId, recordName, methodId, bcOffset, transitionHClass);
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, transitionHClass);
return;
}
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
@ -894,8 +900,8 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco
auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
if (transitionHClassVal.IsJSHClass()) {
auto transitionHClass = JSHClass::Cast(transitionHClassVal.GetTaggedObject());
if (HandlerBase::IsJSArray(handlerInfo)) {
AddElementInfo(abcId, recordName, methodId, bcOffset, transitionHClass);
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, transitionHClass);
return;
}
AddObjectInfo(abcId, recordName, methodId, bcOffset, hclass, hclass, transitionHClass);
@ -913,8 +919,8 @@ void PGOProfiler::DumpICByValueWithHandler(ApEntityId abcId, const CString &reco
JSTaggedValue handlerInfoValue = prototypeHandler->GetHandlerInfo();
ASSERT(handlerInfoValue.IsInt());
auto handlerInfo = static_cast<uint32_t>(handlerInfoValue.GetInt());
if (HandlerBase::IsJSArray(handlerInfo)) {
AddElementInfo(abcId, recordName, methodId, bcOffset, hclass);
if (HandlerBase::IsElement(handlerInfo)) {
AddBuiltinsInfo(abcId, recordName, methodId, bcOffset, hclass);
return;
}
auto holder = prototypeHandler->GetHolder();
@ -983,16 +989,24 @@ void PGOProfiler::DumpDefineClass(ApEntityId abcId, const CString &recordName, E
auto ctorHClass = ctorFunction->GetJSHClass();
auto ctorRootHClass = JSTaggedType(JSHClass::FindRootHClass(ctorHClass));
auto ctorType = GetProfileType(ctorRootHClass, ctorRootHClass);
objDefType.SetCtorPt(ctorType);
recordInfos_->AddRootLayout(ctorRootHClass, ctorType);
if (ctorType.IsNone()) {
LOG_ECMA(DEBUG) << "The profileType of constructor root hclass was not found.";
} else {
objDefType.SetCtorPt(ctorType);
recordInfos_->AddRootLayout(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);
objDefType.SetProtoTypePt(prototypeType);
recordInfos_->AddRootLayout(prototypeRootHClass, prototypeType);
if (prototypeType.IsNone()) {
LOG_ECMA(DEBUG) << "The profileType of prototype root hclass was not found.";
} else {
objDefType.SetProtoTypePt(prototypeType);
recordInfos_->AddRootLayout(prototypeRootHClass, prototypeType);
}
}
recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
@ -1185,19 +1199,19 @@ void PGOProfiler::AddObjectInfoWithMega(
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
}
void PGOProfiler::AddElementInfo(
void PGOProfiler::AddBuiltinsInfo(
ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *receiver)
{
ProfileType recordType = GetRecordProfileType(abcId, recordName);
if (receiver->IsJSArray()) {
auto type = receiver->GetObjectType();
auto elementsKind = receiver->GetElementsKind();
auto profileType = ProfileType(abcId, static_cast<uint32_t>(elementsKind), ProfileType::Kind::ElementId);
auto profileType = ProfileType::CreateBuiltinsArray(abcId, type, elementsKind);
PGOObjectInfo info(profileType);
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
} else if (receiver->IsTypedArray()) {
// Depend to TypedArray IC
auto id = static_cast<uint32_t>(receiver->GetObjectType());
PGOObjectInfo info(ProfileType(abcId, id, ProfileType::Kind::BuiltinsId));
} else if (receiver->IsTypedArray() || receiver->IsString()) {
auto type = receiver->GetObjectType();
PGOObjectInfo info(ProfileType::CreateBuiltins(abcId, type));
recordInfos_->AddObjectInfo(recordType, methodId, bcOffset, info);
}
}

View File

@ -61,7 +61,7 @@ public:
JSHClass *receverHClass, JSHClass *holderHClass, const JSHandle<JSTaggedValue> &func, int32_t pcOffset);
void ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcValue,
ProfileType::Kind kind = ProfileType::Kind::ClassId);
void UpdateProfileType(JSHClass *oldHClass, JSHClass *newHClass);
void UpdateRootProfileType(JSHClass *oldHClass, JSHClass *newHClass);
void SetSaveTimestamp(std::chrono::system_clock::time_point timestamp)
{
@ -146,7 +146,7 @@ private:
void AddObjectInfo(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset,
JSHClass *receiver, JSHClass *hold, JSHClass *holdTra);
void AddObjectInfoWithMega(ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset);
void AddElementInfo(
void AddBuiltinsInfo(
ApEntityId abcId, const CString &recordName, EntityId methodId, int32_t bcOffset, JSHClass *receiver);
ProfileType GetProfileType(JSTaggedType root, JSTaggedType child);

View File

@ -935,21 +935,21 @@ HWTEST_F_L0(PGOProfilerTest, ArrayProfileTest)
if (std::string(methodName) == "foo") {
ASSERT_TRUE(pgoRWOpType.GetCount() == 3);
auto classType = pgoRWOpType.GetObjectInfo(0).GetProfileType();
ASSERT_TRUE(classType.IsElementType());
ASSERT_EQ(classType.GetId(), static_cast<uint32_t>(ElementsKind::NUMBER));
ASSERT_TRUE(classType.IsBuiltinsArray());
ASSERT_EQ(classType.GetElementsKind(), ElementsKind::NUMBER);
classType = pgoRWOpType.GetObjectInfo(1).GetProfileType();
ASSERT_TRUE(classType.IsElementType());
ASSERT_EQ(classType.GetId(), static_cast<uint32_t>(ElementsKind::HOLE_INT));
ASSERT_TRUE(classType.IsBuiltinsArray());
ASSERT_EQ(classType.GetElementsKind(), ElementsKind::HOLE_INT);
classType = pgoRWOpType.GetObjectInfo(2).GetProfileType();
ASSERT_TRUE(classType.IsElementType());
ASSERT_EQ(classType.GetId(), static_cast<uint32_t>(ElementsKind::TAGGED));
ASSERT_TRUE(classType.IsBuiltinsArray());
ASSERT_EQ(classType.GetElementsKind(), ElementsKind::TAGGED);
} else if (std::string(methodName) == "foo1") {
ASSERT_TRUE(pgoRWOpType.GetCount() == 1);
auto classType = pgoRWOpType.GetObjectInfo(0).GetProfileType();
ASSERT_TRUE(classType.IsElementType());
ASSERT_EQ(classType.GetId(), static_cast<uint32_t>(ElementsKind::TAGGED));
ASSERT_TRUE(classType.IsBuiltinsArray());
ASSERT_EQ(classType.GetElementsKind(), ElementsKind::TAGGED);
}
}
};
@ -1107,39 +1107,6 @@ HWTEST_F_L0(PGOProfilerTest, MergeApSelfTwice)
}
#endif
HWTEST_F_L0(PGOProfilerTest, ClassTypeLegacyCheckForWideClassType)
{
PGOContextMock context(PGOProfilerHeader::RECORD_POOL_MINI_VERSION);
ProfileTypeLegacy classTypeLegacy(0xafe, ProfileType::Kind::ElementId);
auto &profileTypeRef = *(static_cast<ProfileTypeRef *>(static_cast<void *>(&classTypeLegacy)));
ProfileType classType(context, profileTypeRef);
ASSERT_EQ(classTypeLegacy.GetId(), 0xafe);
ASSERT_EQ(classTypeLegacy.GetKind(), ProfileType::Kind::ElementId);
ASSERT_EQ(classType.GetId(), 0xafe);
ASSERT_EQ(classType.GetKind(), ProfileType::Kind::ElementId);
}
HWTEST_F_L0(PGOProfilerTest, PGOSampleTypeLegacyCheckForWideClassType)
{
PGOContextMock context(PGOProfilerHeader::RECORD_POOL_MINI_VERSION);
PGOSampleTypeRef sampleTypeLegacyType(PGOSampleTypeRef::Type::NUMBER);
PGOSampleType sampleType = PGOSampleType::ConvertFrom(context, sampleTypeLegacyType);
ASSERT_TRUE(sampleTypeLegacyType.IsNumber());
ASSERT_TRUE(sampleType.IsNumber());
ASSERT_FALSE(sampleType.IsProfileType());
ProfileTypeLegacy classTypeLegacy(0xafe, ProfileType::Kind::ElementId);
auto &profileTypeRef = *(static_cast<ProfileTypeRef *>(static_cast<void *>(&classTypeLegacy)));
PGOSampleTypeRef sampleTypeLegacyClass(profileTypeRef);
ASSERT_TRUE(sampleTypeLegacyClass.IsProfileType());
sampleType = PGOSampleType::ConvertFrom(context, sampleTypeLegacyClass);
ASSERT_FALSE(sampleType.IsNumber());
ASSERT_TRUE(sampleType.IsProfileType());
ASSERT_EQ(sampleType.GetProfileType().GetId(), classTypeLegacy.GetId());
ASSERT_EQ(sampleType.GetProfileType().GetKind(), classTypeLegacy.GetKind());
}
HWTEST_F_L0(PGOProfilerTest, RuntimeMerge)
{
mkdir("ark-profiler19/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

View File

@ -20,6 +20,9 @@
#include <string>
#include <variant>
#include "ecmascript/builtin_entries.h"
#include "ecmascript/elements.h"
#include "ecmascript/js_hclass.h"
#include "ecmascript/log.h"
#include "ecmascript/log_wrapper.h"
#include "ecmascript/pgo_profiler/pgo_context.h"
@ -38,7 +41,6 @@ public:
enum class Kind : uint8_t {
ClassId,
LiteralId,
ElementId,
BuiltinsId,
LegacyKind = BuiltinsId,
MethodId, // method offset of js function
@ -63,6 +65,55 @@ public:
using KindBits = AbcIdBits::NextField<Kind, KIND_BITFIELD_NUM>;
using IsRootBits = KindBits::NextFlag;
class BuiltinsId {
public:
static constexpr uint32_t BUILTINS_ID_NUM = 16;
using BuiltinsIdBits = BitField<JSType, 0, BUILTINS_ID_NUM>;
explicit BuiltinsId() = default;
explicit BuiltinsId(uint32_t id) : id_(id) {}
uint32_t GetId() const
{
return id_;
}
BuiltinsId SetBuiltinsId(JSType type)
{
id_ = BuiltinsIdBits::Update(id_, type);
return *this;
}
JSType GetBuiltinsId() const
{
return BuiltinsIdBits::Decode(id_);
}
protected:
uint32_t id_ { 0 };
};
class BuiltinsArrayId : public BuiltinsId {
public:
// BuilitinsArray second bit field
static constexpr uint32_t ELEMENTS_KIND_BITFIELD_NUM = 5;
using ElementsKindBits = BuiltinsIdBits::NextField<ElementsKind, ELEMENTS_KIND_BITFIELD_NUM>;
explicit BuiltinsArrayId() = default;
explicit BuiltinsArrayId(uint32_t id) : BuiltinsId(id) {}
BuiltinsArrayId UpdateElementsKind(ElementsKind kind)
{
id_ = ElementsKindBits::Update(id_, kind);
return *this;
}
ElementsKind GetElementsKind() const
{
return ElementsKindBits::Decode(id_);
}
};
static_assert(KindBits::IsValid(Kind::TotalKinds));
ProfileType() = default;
@ -87,6 +138,18 @@ public:
return type;
}
static ProfileType CreateBuiltinsArray(ApEntityId abcId, JSType type, ElementsKind kind)
{
auto id = BuiltinsArrayId().UpdateElementsKind(kind).SetBuiltinsId(type).GetId();
return ProfileType(abcId, id, Kind::BuiltinsId);
}
static ProfileType CreateBuiltins(ApEntityId abcId, JSType type)
{
auto id = BuiltinsId().SetBuiltinsId(type).GetId();
return ProfileType(abcId, id, Kind::BuiltinsId);
}
ProfileType &Remap(const PGOContext &context);
bool IsNone() const
@ -114,11 +177,6 @@ public:
return GetKind() == Kind::ClassId;
}
bool IsElementType() const
{
return GetKind() == Kind::ElementId;
}
bool IsMethodId() const
{
return GetKind() == Kind::MethodId;
@ -209,6 +267,47 @@ public:
type_ = IsRootBits::Update(type_, root);
}
JSType GetBuiltinsId() const
{
ASSERT(IsBuiltinsType());
auto builtinsId = BuiltinsId(GetId());
return builtinsId.GetBuiltinsId();
}
ElementsKind GetElementsKind() const
{
ASSERT(IsBuiltinsArray());
auto builtinsArrayId = BuiltinsArrayId(GetId());
return builtinsArrayId.GetElementsKind();
}
bool IsBuiltinsString() const
{
if (IsBuiltinsType()) {
JSType type = GetBuiltinsId();
return type >= JSType::STRING_FIRST && type <= JSType::STRING_LAST;
}
return false;
}
bool IsBuiltinsArray() const
{
if (IsBuiltinsType()) {
JSType type = GetBuiltinsId();
return type == JSType::JS_ARRAY;
}
return false;
}
bool IsBuiltinsTypeArray() const
{
if (IsBuiltinsType()) {
JSType type = GetBuiltinsId();
return type > JSType::JS_TYPED_ARRAY_FIRST && type <= JSType::JS_TYPED_ARRAY_LAST;
}
return false;
}
private:
void UpdateId(uint64_t type)
{
@ -242,7 +341,7 @@ public:
return typeId_ == 0;
}
bool IsElementType() const
bool IsBuiltinsArray() const
{
return false;
}

View File

@ -463,7 +463,7 @@ public:
bool InElement() const
{
return receiverType_.IsElementType();
return receiverType_.IsBuiltinsArray();
}
bool operator<(const PGOObjectTemplate &right) const

View File

@ -858,7 +858,7 @@ BuiltinTypeId TSManager::GetBuiltinTypeIdByJSType(JSType jsType)
const kungfu::GateType TSManager::GetBuiltinsGateTypeByPt(ProfileType pgoType)
{
ASSERT(pgoType.IsBuiltinsType());
JSType jsType = static_cast<JSType>(pgoType.GetId());
JSType jsType = pgoType.GetBuiltinsId();
auto it = pgoBuiltinGTCache_.find(jsType);
if (it != pgoBuiltinGTCache_.end()) {

View File

@ -193,6 +193,7 @@ group("ark_aot_ts_test") {
"pgo_forof_typed_array",
"pgo_function_operation",
"pgo_function_prototype",
"pgo_length",
"pgo_objectliteral_operation",
"pgo_call_deopt",
"poplexenv",

View File

@ -0,0 +1,21 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_js_test_action("pgo_length") {
deps = []
is_enable_pgo = true
is_enable_opt_inlining = true
is_enable_trace_deopt = true
}

View File

@ -0,0 +1,17 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
11
e
3
23

View File

@ -0,0 +1,17 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
11
e
3
23

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
let string = "hello world"
let array = [1, 23, 3]
function foo(p) {
print(p.length)
print(p[1])
}
foo(string)
foo(array)

View File

@ -552,6 +552,7 @@ template("host_aot_js_test_action") {
_test_aot_arg_ = "$target_out_dir/${_target_name_}"
_test_aot_log_level = "info"
_test_expect_path_ = "./expect_output.txt"
_test_pgo_expect_path_ = "./pgo_expect_output.txt"
if (defined(invoker.is_common_js) && invoker.is_common_js) {
extra_args = [ "--commonjs" ]
@ -579,6 +580,60 @@ template("host_aot_js_test_action") {
_script_args_ = rebase_path(_test_abc_path_)
action("${_target_name_}PgoExecute") {
testonly = true
_host_jsvm_target_ =
"$js_root/ecmascript/js_vm:ark_js_vm(${host_toolchain})"
_root_out_dir_ = get_label_info(_host_jsvm_target_, "root_out_dir")
deps = [
":gen_${_target_name_}_abc",
_host_jsvm_target_,
]
deps += _deps_
script = "$js_root/script/run_ark_executable.py"
_aot_run_options_ =
" --asm-interpreter=true" + " --entry-point=${_target_name_}" +
" --enable-pgo-profiler=true" + " --compiler-pgo-profiler-path=" +
rebase_path(_test_aot_arg_) + "/modules.ap"
if (defined(invoker.is_enable_enableArkTools) &&
invoker.is_enable_enableArkTools) {
_aot_run_options_ += " --enable-ark-tools=true"
_aot_run_options_ += " --enable-force-gc=false"
}
if (defined(invoker.log_option)) {
_aot_run_options_ += invoker.log_option
}
args = [
"--script-file",
rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime/ark_js_vm",
"--script-options",
_aot_run_options_,
"--script-args",
_script_args_,
"--expect-file",
rebase_path(_test_pgo_expect_path_),
"--env-path",
rebase_path(_root_out_dir_) + "/arkcompiler/ets_runtime:" +
rebase_path(_root_out_dir_) + "/${_icu_path_}:" +
rebase_path(_root_out_dir_) + "/thirdparty/zlib:" +
rebase_path(_root_out_dir_) + "/resourceschedule/frame_aware_sched:" +
rebase_path(_root_out_dir_) + "/hiviewdfx/hilog:" +
rebase_path(_root_out_dir_) +
"/thirdparty/bounds_checking_function:" +
rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib/"),
]
inputs = [ _test_abc_path_ ]
outputs = [ "$target_out_dir/${_target_name_}/pgo" ]
}
action("${_target_name_}AotCompileAction") {
testonly = true
@ -590,11 +645,20 @@ template("host_aot_js_test_action") {
]
deps += _deps_
if (defined(invoker.is_enable_pgo) && invoker.is_enable_pgo) {
deps += [ ":${_target_name_}PgoExecute" ]
}
script = "//arkcompiler/ets_runtime/script/run_ark_executable.py"
_aot_compile_options_ = " --aot-file=" + rebase_path(_test_aot_arg_) +
" --log-level=" + _test_aot_log_level + " --log-components=compiler --compiler-opt-type-lowering=false --compiler-opt-inlining=false" + " --compiler-opt-loop-peeling=false"
if (defined(invoker.is_enable_pgo) && invoker.is_enable_pgo) {
_aot_compile_options_ += " --compiler-pgo-profiler-path=" +
rebase_path(_test_aot_arg_) + "/modules.ap"
}
if (defined(invoker.is_enable_trace_deopt) &&
invoker.is_enable_trace_deopt) {
_aot_compile_options_ += " --compiler-trace-deopt=true"