Optimize AOT ai file loading

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IA4IAA

Signed-off-by: yaoyuan <yuanyao14@huawei.com>
Change-Id: I88995975bfc9fab7bd535e28ffd26eb72b28ffde
This commit is contained in:
yaoyuan 2024-06-24 09:47:15 +08:00
parent 2d8f70fa32
commit 12581dd9ec
10 changed files with 140 additions and 40 deletions

View File

@ -54,7 +54,8 @@ void AOTSnapshot::GenerateSnapshotConstantPools(const CMap<int32_t, JSTaggedValu
for (auto &iter : allConstantPools) {
int32_t cpId = iter.first;
cp.Update(iter.second);
uint32_t cacheSize = cp->GetCacheLength();
// cachedSize should not have extra data included
uint32_t cacheSize = cp->GetCacheLength() - ConstantPool::EXTEND_DATA_NUM;
if (vm_->GetJSOptions().IsEnableCompilerLogSnapshot()) {
LOG_COMPILER(INFO) << "[aot-snapshot] constantPoolID: " << cpId;
LOG_COMPILER(INFO) << "[aot-snapshot] cacheSize: " << cacheSize;

View File

@ -107,13 +107,11 @@ void StringSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData, c
{
for (auto item : info_) {
const ItemData &data = item.second;
JSTaggedValue cp = thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_);
JSTaggedValue str = ConstantPool::GetStringFromCache(thread_, cp, data.constantPoolIdx_);
uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, str);
// Lazy ConstantPool String Loading
snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, JSTaggedValue::Hole());
}
}
@ -144,13 +142,21 @@ void MethodSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
aotLiteralInfo->SetLiteralType(JSTaggedValue(AOTLiteralInfo::METHOD_LITERAL_TYPE));
if (!ihc->IsUndefined()) {
aotLiteralInfo->SetIhc(ihc.GetTaggedValue());
}
if (skippedMethods.find(methodOffset) == skippedMethods.end()) {
aotLiteralInfo->SetObjectToCache(thread_, 0, JSTaggedValue(methodOffset));
if (skippedMethods.find(methodOffset) == skippedMethods.end()) {
aotLiteralInfo->SetObjectToCache(thread_, 0, JSTaggedValue(methodOffset));
globalData.RecordReviseData(
ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
}
snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, aotLiteralInfo.GetTaggedValue());
} else if (skippedMethods.find(methodOffset) == skippedMethods.end()) {
// For MethodSnaphotInfo which does not have ihc info, we insert JSTaggedValue(methodOffset) as revervation.
// For the purpose of reducing ai size.
globalData.RecordReviseData(
ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, JSTaggedValue(methodOffset));
} else {
snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, JSTaggedValue::Hole());
}
snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, aotLiteralInfo.GetTaggedValue());
}
}

View File

@ -39,9 +39,28 @@ void ReviseData::Resolve(JSThread *thread, const SnapshotGlobalData *globalData,
item.dataIdx_, item.cpArrayIdx_);
JSTaggedValue val = newCP->GetObjectFromCache(item.constpoolIdx_);
if (val.IsHole()) {
continue;
}
std::string name = globalData->GetFileNameByDataIdx(item.dataIdx_).c_str();
// For MethodSnaphotInfo which does not have ihc info, we insert JSTaggedValue(methodOffset) as revervation.
// We need to set JSTaggedValue(codeEntry); to replace JSTaggedValue(methodOffset).
if (val.IsInt()) {
if (val.GetInt() == -1) {
continue;
}
uint32_t methodOffset = static_cast<uint32_t>(val.GetInt());
if (thread->GetEcmaVM()->GetJSOptions().IsEnableCompilerLogSnapshot()) {
LOG_COMPILER(INFO) << "[aot-snapshot] store AOT entry index of method (offset: "
<< methodOffset << ") ";
}
AnFileInfo::FuncEntryIndexKey key = std::make_pair(name, methodOffset);
uint32_t entryIndex = methodToEntryIndexMap.at(key);
newCP->SetObjectToCache(thread, item.constpoolIdx_, JSTaggedValue(entryIndex));
continue;
}
AOTLiteralInfo *aotLiteralInfo = AOTLiteralInfo::Cast(val.GetTaggedObject());
uint32_t aotLiteralInfoLen = aotLiteralInfo->GetCacheLength();
std::string name = globalData->GetFileNameByDataIdx(item.dataIdx_).c_str();
for (uint32_t i = 0; i < aotLiteralInfoLen; ++i) {
JSTaggedValue methodOffsetVal = aotLiteralInfo->GetObjectFromCache(i);
if (methodOffsetVal.GetInt() == -1) {

View File

@ -841,31 +841,58 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga
Bind(&cache);
{
if (type == ConstPoolType::METHOD) {
Label isAOTLiteralInfo(env_);
BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
Bind(&isAOTLiteralInfo);
Label isHeapObj(env_);
Label checkInteger(env_);
BRANCH_CIR2(TaggedIsHeapObject(*result), &isHeapObj, &checkInteger);
Bind(&isHeapObj);
{
result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef,
{ sharedConstPool, Int32ToTaggedInt(index) }, hirGate);
Jump(&exit);
Label isAOTLiteralInfo(env_);
BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
Bind(&isAOTLiteralInfo);
{
result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef,
{ sharedConstPool, Int32ToTaggedInt(index) }, hirGate);
Jump(&exit);
}
}
Bind(&checkInteger);
{
Label isInteger(env_);
BRANCH_CIR2(TaggedIsInt(*result), &isInteger, &exit);
Bind(&isInteger);
{
result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef,
{ sharedConstPool, Int32ToTaggedInt(index) }, hirGate);
Jump(&exit);
}
}
} else if (type == ConstPoolType::ARRAY_LITERAL) {
Label isAOTLiteralInfo(env_);
BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
Bind(&isAOTLiteralInfo);
Label isHeapObj(env_);
BRANCH_CIR2(TaggedIsHeapObject(*result), &isHeapObj, &exit);
Bind(&isHeapObj);
{
result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef,
{ sharedConstPool, Int32ToTaggedInt(index), module }, hirGate);
Jump(&exit);
Label isAOTLiteralInfo(env_);
BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
Bind(&isAOTLiteralInfo);
{
result = CallRuntime(glue, RTSTUB_ID(GetArrayLiteralFromCache), Gate::InvalidGateRef,
{ sharedConstPool, Int32ToTaggedInt(index), module }, hirGate);
Jump(&exit);
}
}
} else if (type == ConstPoolType::OBJECT_LITERAL) {
Label isAOTLiteralInfo(env_);
BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
Bind(&isAOTLiteralInfo);
Label isHeapObj(env_);
BRANCH_CIR2(TaggedIsHeapObject(*result), &isHeapObj, &exit);
Bind(&isHeapObj);
{
result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef,
{ sharedConstPool, Int32ToTaggedInt(index), module }, hirGate);
Jump(&exit);
Label isAOTLiteralInfo(env_);
BRANCH_CIR2(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
Bind(&isAOTLiteralInfo);
{
result = CallRuntime(glue, RTSTUB_ID(GetObjectLiteralFromCache), Gate::InvalidGateRef,
{ sharedConstPool, Int32ToTaggedInt(index), module }, hirGate);
Jump(&exit);
}
}
} else {
Jump(&exit);

View File

@ -154,11 +154,10 @@ GateRef CircuitBuilder::IsStableArray(GateRef hClass)
GateRef CircuitBuilder::IsAOTLiteralInfo(GateRef x)
{
GateRef isHeapObj = TaggedIsHeapObject(x);
GateRef objType = GetObjectType(LoadHClass(x));
GateRef isAOTLiteralInfoObj = Equal(objType,
Int32(static_cast<int32_t>(JSType::AOT_LITERAL_INFO)));
return LogicAnd(isHeapObj, isAOTLiteralInfoObj);
return isAOTLiteralInfoObj;
}
GateRef CircuitBuilder::LoadHClass(GateRef object)

View File

@ -76,6 +76,18 @@ std::pair<EcmaString *, uint32_t> EcmaStringTable::GetStringThreadUnsafe(const u
return std::make_pair(nullptr, hashCode);
}
EcmaString *EcmaStringTable::GetStringWithHashThreadUnsafe(EcmaString *string, uint32_t hashcode) const
{
auto range = table_.equal_range(hashcode);
for (auto item = range.first; item != range.second; ++item) {
auto foundString = item->second;
if (EcmaStringAccessor::StringsAreEqual(foundString, string)) {
return foundString;
}
}
return nullptr;
}
EcmaString *EcmaStringTable::GetStringThreadUnsafe(EcmaString *string) const
{
auto hashcode = EcmaStringAccessor(string).GetHashcode();
@ -296,6 +308,16 @@ EcmaString *EcmaStringTable::GetOrInternStringThreadUnsafe(EcmaVM *vm, EcmaStrin
return strFlat;
}
void EcmaStringTable::InsertStringToTableWithHashThreadUnsafe(EcmaString* string, uint32_t hashcode)
{
// Strings in string table should not be in the young space.
ASSERT(Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(string))->InSharedHeap());
ASSERT(EcmaStringAccessor(string).NotTreeString());
ASSERT(EcmaStringAccessor(string).GetHashcode() == hashcode);
table_.emplace(hashcode, string);
EcmaStringAccessor(string).SetInternString();
}
EcmaString *EcmaStringTable::InsertStringToTable(EcmaVM *vm, const JSHandle<EcmaString> &strHandle)
{
RuntimeLockHolder locker(vm->GetJSThread(), mutex_);

View File

@ -54,6 +54,7 @@ public:
EcmaString *GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
MemSpaceType type);
EcmaString *TryGetInternString(JSThread *thread, const JSHandle<EcmaString> &string);
void InsertStringToTableWithHashThreadUnsafe(EcmaString* string, uint32_t hashcode);
EcmaString *InsertStringToTable(EcmaVM *vm, const JSHandle<EcmaString> &strHandle);
void SweepWeakReference(const WeakRootVisitor &visitor);
@ -68,6 +69,7 @@ private:
std::pair<EcmaString *, uint32_t> GetStringThreadUnsafe(const uint8_t *utf8Data, uint32_t utf8Len,
bool canBeCompress) const;
std::pair<EcmaString *, uint32_t> GetStringThreadUnsafe(const uint16_t *utf16Data, uint32_t utf16Len) const;
EcmaString *GetStringWithHashThreadUnsafe(EcmaString *string, uint32_t hashcode) const;
EcmaString *GetStringThreadUnsafe(EcmaString *string) const;
void InternStringThreadUnsafe(EcmaString *string);

View File

@ -29,8 +29,7 @@ JSTaggedValue ConstantPool::GetMethodFromCache(JSTaggedValue constpool, uint32_t
auto val = taggedPool->GetObjectFromCache(index);
JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
if (isLoadedAOT && val.IsAOTLiteralInfo()) {
if (IsLoadedMethodInfoFromAOT(jsPandaFile, val)) {
val = JSTaggedValue::Hole();
}
@ -47,13 +46,24 @@ void ConstantPool::UpdateConstpoolWhenDeserialAI(EcmaVM *vm, const ConstantPool
ConstantPool *sharedCP, ConstantPool *unsharedCP)
{
uint32_t constpoolLen = aiCP->GetCacheLength();
auto aiCPLength = aiCP->GetLength();
for (uint32_t i = 0; i < constpoolLen; i++) {
// We need preserve unshared constantPool index and shared constantPool id instead of fetching from ai.
// Because framework abc's ai does not contain those infos.
if (i == (aiCPLength - ConstantPool::UNSHARED_CONSTPOOL_INDEX) ||
i == (aiCPLength - ConstantPool::SHARED_CONSTPOOL_ID)) {
continue;
}
JSThread *thread = vm->GetJSThread();
auto val = aiCP->GetObjectFromCache(i);
if (IsAotMethodLiteralInfo(val)) {
JSHandle<AOTLiteralInfo> valHandle(thread, val);
JSHandle<AOTLiteralInfo> methodLiteral = CopySharedMethodAOTLiteralInfo(vm, valHandle);
sharedCP->SetObjectToCache(thread, i, methodLiteral.GetTaggedValue());
} else if (val.IsInt()) {
// For MethodInfo which does not have ihc infos, we store codeEntry directly.
sharedCP->SetObjectToCache(thread, i, val);
unsharedCP->SetObjectToCache(thread, i, val);
}
// update method, class and object aotliteralinfo
if (val.IsAOTLiteralInfo()) {

View File

@ -206,6 +206,9 @@ public:
JSHandle<AOTLiteralInfo> valHandle(thread, val);
JSHandle<AOTLiteralInfo> methodLiteral = CopySharedMethodAOTLiteralInfo(vm, valHandle);
sconstpool->SetObjectToCache(thread, i, methodLiteral.GetTaggedValue());
} else if (val.IsInt()) {
// Here is to copy methodCodeEntry which does not have ihc infos from aot.
sconstpool->SetObjectToCache(thread, i, val);
}
}
@ -436,8 +439,8 @@ public:
std::atomic<JSTaggedValue> *atomicVal = reinterpret_cast<std::atomic<JSTaggedValue> *>(
reinterpret_cast<uintptr_t>(taggedPool) + DATA_OFFSET + index * JSTaggedValue::TaggedTypeSize());
JSTaggedValue tempVal = taggedPool->GetObjectFromCache(index);
JSTaggedValue expected = taggedPool->GetJSPandaFile()->IsLoadedAOT() && tempVal.IsAOTLiteralInfo() ?
tempVal : JSTaggedValue::Hole();
JSTaggedValue expected = IsLoadedMethodInfoFromAOT(taggedPool->GetJSPandaFile(), tempVal) ? tempVal :
JSTaggedValue::Hole();
JSTaggedValue desired = value;
if (std::atomic_compare_exchange_strong_explicit(atomicVal, &expected, desired,
std::memory_order_release, std::memory_order_relaxed)) {
@ -461,9 +464,15 @@ public:
bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
bool hasEntryIndex = false;
uint32_t entryIndex = 0;
if (isLoadedAOT && val.IsAOTLiteralInfo()) {
JSHandle<AOTLiteralInfo> entryIndexes(thread, val);
int entryIndexVal = entryIndexes->GetObjectFromCache(0).GetInt(); // 0: only one method
if (IsLoadedMethodInfoFromAOT(jsPandaFile, val)) {
int entryIndexVal = 0; // 0: only one method
if (val.IsInt()) {
// For MethodInfo which does not have ihc infos, we store codeEntry directly.
entryIndexVal = static_cast<uint32_t>(val.GetInt());
} else {
JSHandle<AOTLiteralInfo> entryIndexes(thread, val);
entryIndexVal = entryIndexes->GetObjectFromCache(0).GetInt(); // 0: only one method
}
if (entryIndexVal != static_cast<int>(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE)) {
hasEntryIndex = true;
entryIndex = static_cast<uint32_t>(entryIndexVal);
@ -812,6 +821,11 @@ private:
return JSTaggedValue::TaggedTypeSize() * GetLength() + DATA_OFFSET;
}
static bool IsLoadedMethodInfoFromAOT(const JSPandaFile *pf, JSTaggedValue cachedVal)
{
return pf->IsLoadedAOT() && (cachedVal.IsAOTLiteralInfo() || cachedVal.IsInt());
};
static JSHandle<ConstantPool> GetDeserializedConstantPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, int32_t cpID);
};
} // namespace ecmascript

View File

@ -1392,7 +1392,8 @@ void SnapshotProcessor::DeserializeString(uintptr_t stringBegin, uintptr_t strin
strSize = AlignUp(strSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
{
RuntimeLockHolder locker(thread, stringTable->mutex_);
auto strFromTable = stringTable->GetStringThreadUnsafe(str);
auto hashcode = EcmaStringAccessor(str).GetHashcode();
auto strFromTable = stringTable->GetStringWithHashThreadUnsafe(str, hashcode);
if (strFromTable) {
deserializeStringVector_.emplace_back(thread, strFromTable);
} else {
@ -1411,8 +1412,7 @@ void SnapshotProcessor::DeserializeString(uintptr_t stringBegin, uintptr_t strin
UNREACHABLE();
}
str = reinterpret_cast<EcmaString *>(newObj);
EcmaStringAccessor(str).ClearInternString();
stringTable->GetOrInternStringThreadUnsafe(vm_, str);
stringTable->InsertStringToTableWithHashThreadUnsafe(str, hashcode);
deserializeStringVector_.emplace_back(thread, str);
}
}