• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
17 
18 #include "ecmascript/jspandafile/program_object.h"
19 #include "ecmascript/layout_info-inl.h"
20 namespace panda::ecmascript::kungfu {
Iterate(RootVisitor & v)21 void PGOTypeManager::Iterate(RootVisitor &v)
22 {
23     for (auto &iter : hcData_) {
24         for (auto &hclassIter : iter.second) {
25             v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(hclassIter.second))));
26         }
27     }
28     aotSnapshot_.Iterate(v);
29     for (auto &iter : hclassInfoLocal_) {
30         v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(iter))));
31     }
32 }
33 
GetConstantPoolIDByMethodOffset(const uint32_t methodOffset) const34 uint32_t PGOTypeManager::GetConstantPoolIDByMethodOffset(const uint32_t methodOffset) const
35 {
36     ASSERT(curJSPandaFile_!=nullptr);
37     panda_file::IndexAccessor indexAccessor(*curJSPandaFile_->GetPandaFile(),
38                                             panda_file::File::EntityId(methodOffset));
39     return static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
40 }
41 
GetConstantPoolByMethodOffset(const uint32_t methodOffset) const42 JSTaggedValue PGOTypeManager::GetConstantPoolByMethodOffset(const uint32_t methodOffset) const
43 {
44     uint32_t cpId = GetConstantPoolIDByMethodOffset(methodOffset);
45     return thread_->GetCurrentEcmaContext()->FindConstpool(curJSPandaFile_, cpId);
46 }
47 
GetStringFromConstantPool(const uint32_t methodOffset,const uint16_t cpIdx) const48 JSTaggedValue PGOTypeManager::GetStringFromConstantPool(const uint32_t methodOffset, const uint16_t cpIdx) const
49 {
50     JSTaggedValue cp = GetConstantPoolByMethodOffset(methodOffset);
51     return ConstantPool::GetStringFromCache(thread_, cp, cpIdx);
52 }
53 
InitAOTSnapshot(uint32_t compileFilesCount)54 void PGOTypeManager::InitAOTSnapshot(uint32_t compileFilesCount)
55 {
56     aotSnapshot_.InitSnapshot(compileFilesCount);
57     GenHClassInfo();
58     GenSymbolInfo();
59     GenArrayInfo();
60     GenConstantIndexInfo();
61     GenProtoTransitionInfo();
62 }
63 
GetSymbolCountFromHClassData()64 uint32_t PGOTypeManager::GetSymbolCountFromHClassData()
65 {
66     uint32_t count = 0;
67     for (auto& root: hcData_) {
68         for (auto& child: root.second) {
69             if (!JSTaggedValue(child.second).IsJSHClass()) {
70                 continue;
71             }
72             JSHClass* hclass = JSHClass::Cast(JSTaggedValue(child.second).GetTaggedObject());
73             if (!hclass->HasTransitions()) {
74                 LayoutInfo* layoutInfo = LayoutInfo::GetLayoutInfoFromHClass(hclass);
75                 uint32_t len = hclass->NumberOfProps();
76                 for (uint32_t i = 0; i < len; i++) {
77                     JSTaggedValue key = layoutInfo->GetKey(i);
78                     if (key.IsSymbol() && JSSymbol::Cast(key)->HasId()) {
79                         count++;
80                     }
81                 }
82             }
83         }
84     }
85     return count;
86 }
87 
GenSymbolInfo()88 void PGOTypeManager::GenSymbolInfo()
89 {
90     uint32_t count = GetSymbolCountFromHClassData();
91     ObjectFactory* factory = thread_->GetEcmaVM()->GetFactory();
92     JSHandle<TaggedArray> symbolInfo = factory->NewTaggedArray(count * 2); // 2: symbolId, symbol
93     uint32_t pos = 0;
94 
95     for (auto& root: hcData_) {
96         ProfileType rootType = root.first;
97         for (auto& child: root.second) {
98             if (!JSTaggedValue(child.second).IsJSHClass()) {
99                 continue;
100             }
101             ProfileType childType = child.first;
102             JSHClass* hclass = JSHClass::Cast(JSTaggedValue(child.second).GetTaggedObject());
103             if (!hclass->HasTransitions()) {
104                 LayoutInfo* layoutInfo = LayoutInfo::GetLayoutInfoFromHClass(hclass);
105                 uint32_t len = hclass->NumberOfProps();
106                 for (uint32_t i = 0; i < len; i++) {
107                     JSTaggedValue symbol = layoutInfo->GetKey(i);
108                     if (symbol.IsSymbol() && JSSymbol::Cast(symbol)->HasId()) {
109                         JSSymbol* symbolPtr = JSSymbol::Cast(symbol.GetTaggedObject());
110                         uint64_t symbolId = symbolPtr->GetPrivateId();
111                         uint64_t slotIndex = JSSymbol::GetSlotIndex(symbolId);
112                         ProfileTypeTuple symbolIdKey = std::make_tuple(rootType, childType, slotIndex);
113                         profileTypeToSymbolId_.emplace(symbolIdKey, symbolId);
114                         symbolInfo->Set(thread_, pos++, JSTaggedValue(symbolId));
115                         symbolInfo->Set(thread_, pos++, symbol);
116                     }
117                 }
118             }
119         }
120     }
121 
122     EcmaVM *vm = thread_->GetEcmaVM();
123     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
124         vm->AddAOTSnapShotStats("SymbolInfo", symbolInfo->GetLength());
125     }
126     aotSnapshot_.StoreSymbolInfo(symbolInfo);
127 }
128 
IsNapiIhc(ProfileType rootType,ProfileType childType)129 bool PGOTypeManager::IsNapiIhc(ProfileType rootType, ProfileType childType)
130 {
131     // If the rootType is NapiType and the childType is root, it must be napi object's ihc.
132     return rootType.IsNapiType() && childType.IsRootType();
133 }
134 
135 /*                  hclassInfo
136  *      +-----------------------------------+----
137  *      |          AOT Napi Hclass          |  zero slot
138  *      +-----------------------------------+----
139  *      |              ...                  |   ^
140  *      |              ...                  |   |
141  *      |             hcData                |  pos
142  *      |              ...                  |   |
143  *      |              ...                  |   v
144  *      +-----------------------------------+----
145  *      | Object Literal Cache (maybe hole) |  last slot
146  *      +-----------------------------------+----
147  */
148 
GenHClassInfo()149 void PGOTypeManager::GenHClassInfo()
150 {
151     uint32_t count = 2; // For object literal hclass cache and Napi root type.
152     for (auto& root: hcData_) {
153         count += root.second.size();
154     }
155 
156     ObjectFactory* factory = thread_->GetEcmaVM()->GetFactory();
157     JSHandle<TaggedArray> hclassInfo = factory->NewTaggedArray(count);
158     uint32_t pos = 1; // 1: the first one is the napi object's ihc.
159     profileTyperToHClassIndex_.clear();
160     for (auto& root: hcData_) {
161         ProfileType rootType = root.first;
162         for (auto& child: root.second) {
163             ProfileType childType = child.first;
164             JSTaggedType hclass = child.second;
165             ProfileTyper key = std::make_pair(rootType, childType);
166             if (IsNapiIhc(rootType, childType)) {
167                 profileTyperToHClassIndex_.emplace(key, 0);
168                 hclassInfo->Set(thread_, 0, JSTaggedValue(hclass));
169             } else {
170                 profileTyperToHClassIndex_.emplace(key, pos);
171                 hclassInfo->Set(thread_, pos++, JSTaggedValue(hclass));
172             }
173         }
174     }
175     // The cache of Object literal serializes to last index of AOTHClassInfo.
176     JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();
177     JSHandle<JSTaggedValue> maybeCache = env->GetObjectLiteralHClassCache();
178     if (!maybeCache->IsHole()) {
179         // It cannot be serialized if object in global env.
180         JSHandle<TaggedArray> array(maybeCache);
181         auto cloneResult = factory->CopyArray(array, array->GetLength(), array->GetLength());
182         hclassInfo->Set(thread_, hclassInfo->GetLength() - 1, cloneResult);
183     }
184 
185     EcmaVM *vm = thread_->GetEcmaVM();
186     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
187         vm->AddAOTSnapShotStats("HClassInfo", hclassInfo->GetLength());
188     }
189     aotSnapshot_.StoreHClassInfo(hclassInfo);
190 }
191 
GenProtoTransitionInfo()192 void PGOTypeManager::GenProtoTransitionInfo()
193 {
194     auto transitionTable = thread_->GetCurrentEcmaContext()->GetFunctionProtoTransitionTable();
195     for (auto &protoTransType : protoTransTypes_) {
196         JSTaggedValue ihc = QueryHClass(protoTransType.ihcType, protoTransType.ihcType);
197         JSTaggedValue baseIhc = QueryHClass(protoTransType.baseRootType, protoTransType.baseType);
198         JSTaggedValue transIhc = QueryHClass(protoTransType.transIhcType, protoTransType.transIhcType);
199         JSTaggedValue transPhc = QueryHClass(protoTransType.transPhcType, protoTransType.transPhcType);
200         if (ihc.IsUndefined() || baseIhc.IsUndefined() || transIhc.IsUndefined() || transPhc.IsUndefined()) {
201             LOG_COMPILER(DEBUG) << "broken prototype transition info!";
202             continue;
203         }
204         transitionTable->InsertTransitionItem(thread_,
205                                               JSHandle<JSTaggedValue>(thread_, ihc),
206                                               JSHandle<JSTaggedValue>(thread_, baseIhc),
207                                               JSHandle<JSTaggedValue>(thread_, transIhc),
208                                               JSHandle<JSTaggedValue>(thread_, transPhc));
209         // Situation:
210         // 1: d1.prototype = p
211         // 2: d2.prototype = p
212         // For this case, baseIhc is transPhc
213         transitionTable->InsertTransitionItem(thread_,
214                                               JSHandle<JSTaggedValue>(thread_, ihc),
215                                               JSHandle<JSTaggedValue>(thread_, transPhc),
216                                               JSHandle<JSTaggedValue>(thread_, transIhc),
217                                               JSHandle<JSTaggedValue>(thread_, transPhc));
218     }
219     aotSnapshot_.StoreProtoTransTableInfo(JSHandle<JSTaggedValue>(thread_, transitionTable->GetProtoTransitionTable()));
220 }
221 
GenArrayInfo()222 void PGOTypeManager::GenArrayInfo()
223 {
224     EcmaVM *vm = thread_->GetEcmaVM();
225     ObjectFactory *factory = vm->GetFactory();
226     JSHandle<TaggedArray> arrayInfo = factory->EmptyArray();
227     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
228         vm->AddAOTSnapShotStats("ArrayInfo", arrayInfo->GetLength());
229     }
230     aotSnapshot_.StoreArrayInfo(arrayInfo);
231 }
232 
GenConstantIndexInfo()233 void PGOTypeManager::GenConstantIndexInfo()
234 {
235     uint32_t count = constantIndexData_.size();
236     EcmaVM *vm = thread_->GetEcmaVM();
237     ObjectFactory *factory = vm->GetFactory();
238     JSHandle<TaggedArray> constantIndexInfo = factory->NewTaggedArray(count);
239     for (uint32_t pos = 0; pos < count; pos++) {
240         constantIndexInfo->Set(thread_, pos, JSTaggedValue(constantIndexData_[pos]));
241     }
242     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
243         vm->AddAOTSnapShotStats("ConstantIndexInfo", constantIndexInfo->GetLength());
244     }
245     aotSnapshot_.StoreConstantIndexInfo(constantIndexInfo);
246 }
247 
RecordHClass(ProfileType rootType,ProfileType childType,JSTaggedType hclass,bool update)248 void PGOTypeManager::RecordHClass(ProfileType rootType, ProfileType childType, JSTaggedType hclass, bool update)
249 {
250     LockHolder lock(mutex_);
251     auto iter = hcData_.find(rootType);
252     if (iter == hcData_.end()) {
253         auto map = TransIdToHClass();
254         map.emplace(childType, hclass);
255         hcData_.emplace(rootType, map);
256         return;
257     }
258 
259     auto &hclassMap = iter->second;
260     auto hclassIter = hclassMap.find(childType);
261     if (hclassIter != hclassMap.end()) {
262         if (!update) {
263             ASSERT(hclass == hclassIter->second);
264             return;
265         } else {
266             hclassMap[childType]= hclass;
267             return;
268         }
269     }
270     hclassMap.emplace(childType, hclass);
271 }
272 
RecordConstantIndex(uint32_t bcAbsoluteOffset,uint32_t index)273 void PGOTypeManager::RecordConstantIndex(uint32_t bcAbsoluteOffset, uint32_t index)
274 {
275     constantIndexData_.emplace_back(bcAbsoluteOffset);
276     constantIndexData_.emplace_back(index);
277 }
278 
GetHClassIndexByProfileType(ProfileTyper type) const279 uint32_t PGOTypeManager::GetHClassIndexByProfileType(ProfileTyper type) const
280 {
281     uint32_t index = -1;
282     auto iter = profileTyperToHClassIndex_.find(type);
283     if (iter != profileTyperToHClassIndex_.end()) {
284         index = iter->second;
285     }
286     return index;
287 }
288 
GetHolderHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type,bool isAot)289 int PGOTypeManager::GetHolderHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type, bool isAot)
290 {
291     if (isAot) {
292         ProfileTyper holderType = std::make_pair(type.GetHoldRootType(), type.GetHoldType());
293         int holderHCIndex = static_cast<int>(GetHClassIndexByProfileType(holderType));
294         ASSERT(QueryHClass(holderType.first, holderType.second).IsJSHClass());
295         return holderHCIndex;
296     } else {
297         JSHClass *holderHClass = type.GetHolderHclass();
298         int holderHCIndex = RecordAndGetHclassIndexForJIT(holderHClass);
299         return holderHCIndex;
300     }
301 }
302 
GetReceiverHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type,bool isAot)303 int PGOTypeManager::GetReceiverHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type, bool isAot)
304 {
305     if (isAot) {
306         ProfileTyper receiverType = std::make_pair(type.GetReceiverRootType(), type.GetReceiverType());
307         int receiverHCIndex = static_cast<int>(GetHClassIndexByProfileType(receiverType));
308         ASSERT(QueryHClass(receiverType.first, receiverType.second).IsJSHClass());
309         return receiverHCIndex;
310     } else {
311         JSHClass *receiverHClass = type.GetReceiverHclass();
312         int receiverHCIndex = RecordAndGetHclassIndexForJIT(receiverHClass);
313         return receiverHCIndex;
314     }
315 }
316 
GetSymbolIdByProfileType(ProfileTypeTuple type) const317 std::optional<uint64_t> PGOTypeManager::GetSymbolIdByProfileType(ProfileTypeTuple type) const
318 {
319     auto iter = profileTypeToSymbolId_.find(type);
320     if (iter != profileTypeToSymbolId_.end()) {
321         return iter->second;
322     }
323     return std::nullopt;
324 }
325 
QueryHClass(ProfileType rootType,ProfileType childType)326 JSTaggedValue PGOTypeManager::QueryHClass(ProfileType rootType, ProfileType childType)
327 {
328     LockHolder lock(mutex_);
329     JSTaggedValue result = JSTaggedValue::Undefined();
330     auto iter = hcData_.find(rootType);
331     if (iter != hcData_.end()) {
332         auto hclassMap = iter->second;
333         auto hclassIter = hclassMap.find(childType);
334         if (hclassIter != hclassMap.end()) {
335             result = JSTaggedValue(hclassIter->second);
336         }
337     }
338     // Can return real hclass of object or prototype of it
339     return result;
340 }
341 
QueryHClassByIndexForJIT(uint32_t hclassIndex)342 JSTaggedValue PGOTypeManager::QueryHClassByIndexForJIT(uint32_t hclassIndex)
343 {
344     ASSERT(hclassIndex < pos_);
345     return hclassInfoLocal_[hclassIndex];
346 }
347 
RecordAndGetHclassIndexForJIT(JSHClass * hclass)348 int PGOTypeManager::RecordAndGetHclassIndexForJIT(JSHClass* hclass)
349 {
350     // The hclass in hclassInfoLocal_ cannot currently be cleared after each
351     // JIT session because it depends on ensuring the survival of hclass.
352     // If a reference from machineCode to hclass is added in the future, then it can be cleared.
353     auto value = JSTaggedValue::Cast(hclass);
354     for (int i = 0; i < pos_; i++) {
355         if (hclassInfoLocal_[i] == value) {
356             return i;
357         }
358     }
359     hclassInfoLocal_.emplace_back(value);
360     return pos_++;
361 }
362 
MergeRepresentationForProtoTransition()363 void PGOTypeManager::MergeRepresentationForProtoTransition()
364 {
365     for (auto &protoTransType : protoTransTypes_) {
366         JSTaggedValue ihc = QueryHClass(protoTransType.ihcType, protoTransType.ihcType);
367         JSTaggedValue baseIhc = QueryHClass(protoTransType.baseRootType, protoTransType.baseType);
368         JSTaggedValue transIhc = QueryHClass(protoTransType.transIhcType, protoTransType.transIhcType);
369         JSTaggedValue transPhc = QueryHClass(protoTransType.transPhcType, protoTransType.transPhcType);
370         if (ihc.IsUndefined() || baseIhc.IsUndefined() || transIhc.IsUndefined() || transPhc.IsUndefined()) {
371             LOG_COMPILER(DEBUG) << "broken prototype transition info!";
372             continue;
373         }
374         JSHClass::MergeRepresentation(thread_, JSHClass::Cast(baseIhc.GetTaggedObject()),
375             JSHClass::Cast(transPhc.GetTaggedObject()));
376         JSHClass::MergeRepresentation(thread_, JSHClass::Cast(ihc.GetTaggedObject()),
377             JSHClass::Cast(transIhc.GetTaggedObject()));
378     }
379 }
380 
GetMaxPropsNum(uint32_t literalLength) const381 uint32_t PGOTypeManager::GetMaxPropsNum(uint32_t literalLength) const
382 {
383     auto it = maxPropsNum_.find(literalLength);
384     if (it != maxPropsNum_.end()) {
385         return it->second;
386     }
387     LOG_ECMA(FATAL) << "this branch is unreachable";
388     UNREACHABLE();
389 }
390 
SetMaxPropsNum(uint32_t literalLength,uint32_t maxPropsNum) const391 void PGOTypeManager::SetMaxPropsNum(uint32_t literalLength, uint32_t maxPropsNum) const
392 {
393     auto it = maxPropsNum_.find(literalLength);
394     if (it != maxPropsNum_.end()) {
395         it->second = std::max(it->second, maxPropsNum);
396     } else {
397         maxPropsNum_[literalLength] = maxPropsNum;
398     }
399 }
400 }  // namespace panda::ecmascript
401