• 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 
21 namespace panda::ecmascript::kungfu {
Iterate(const RootVisitor & v)22 void PGOTypeManager::Iterate(const RootVisitor &v)
23 {
24     for (auto &iter : hcData_) {
25         for (auto &hclassIter : iter.second) {
26             v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(hclassIter.second))));
27         }
28     }
29     aotSnapshot_.Iterate(v);
30     for (auto &iter : hclassInfoLocal_) {
31         v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(iter))));
32     }
33 }
34 
GetConstantPoolIDByMethodOffset(const uint32_t methodOffset) const35 uint32_t PGOTypeManager::GetConstantPoolIDByMethodOffset(const uint32_t methodOffset) const
36 {
37     ASSERT(curJSPandaFile_!=nullptr);
38     panda_file::IndexAccessor indexAccessor(*curJSPandaFile_->GetPandaFile(),
39                                             panda_file::File::EntityId(methodOffset));
40     return static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
41 }
42 
GetConstantPoolByMethodOffset(const uint32_t methodOffset) const43 JSTaggedValue PGOTypeManager::GetConstantPoolByMethodOffset(const uint32_t methodOffset) const
44 {
45     uint32_t cpId = GetConstantPoolIDByMethodOffset(methodOffset);
46     return thread_->GetCurrentEcmaContext()->FindConstpool(curJSPandaFile_, cpId);
47 }
48 
GetStringFromConstantPool(const uint32_t methodOffset,const uint16_t cpIdx) const49 JSTaggedValue PGOTypeManager::GetStringFromConstantPool(const uint32_t methodOffset, const uint16_t cpIdx) const
50 {
51     JSTaggedValue cp = GetConstantPoolByMethodOffset(methodOffset);
52     return ConstantPool::GetStringFromCache(thread_, cp, cpIdx);
53 }
54 
InitAOTSnapshot(uint32_t compileFilesCount)55 void PGOTypeManager::InitAOTSnapshot(uint32_t compileFilesCount)
56 {
57     aotSnapshot_.InitSnapshot(compileFilesCount);
58     GenHClassInfo();
59     GenSymbolInfo();
60     GenArrayInfo();
61     GenConstantIndexInfo();
62     GenProtoTransitionInfo();
63 }
64 
GetSymbolCountFromHClassData()65 uint32_t PGOTypeManager::GetSymbolCountFromHClassData()
66 {
67     uint32_t count = 0;
68     for (auto& root: hcData_) {
69         for (auto& child: root.second) {
70             if (!JSTaggedValue(child.second).IsJSHClass()) {
71                 continue;
72             }
73             JSHClass* hclass = JSHClass::Cast(JSTaggedValue(child.second).GetTaggedObject());
74             if (!hclass->HasTransitions()) {
75                 LayoutInfo* layoutInfo = LayoutInfo::GetLayoutInfoFromHClass(hclass);
76                 uint32_t len = hclass->NumberOfProps();
77                 for (uint32_t i = 0; i < len; i++) {
78                     JSTaggedValue key = layoutInfo->GetKey(i);
79                     if (key.IsSymbol()) {
80                         count++;
81                     }
82                 }
83             }
84         }
85     }
86     return count;
87 }
88 
GenSymbolInfo()89 void PGOTypeManager::GenSymbolInfo()
90 {
91     uint32_t count = GetSymbolCountFromHClassData();
92     ObjectFactory* factory = thread_->GetEcmaVM()->GetFactory();
93     JSHandle<TaggedArray> symbolInfo = factory->NewTaggedArray(count * 2); // 2: symbolId, symbol
94     uint32_t pos = 0;
95 
96     for (auto& root: hcData_) {
97         ProfileType rootType = root.first;
98         for (auto& child: root.second) {
99             if (!JSTaggedValue(child.second).IsJSHClass()) {
100                 continue;
101             }
102             ProfileType childType = child.first;
103             JSHClass* hclass = JSHClass::Cast(JSTaggedValue(child.second).GetTaggedObject());
104             if (!hclass->HasTransitions()) {
105                 LayoutInfo* layoutInfo = LayoutInfo::GetLayoutInfoFromHClass(hclass);
106                 uint32_t len = hclass->NumberOfProps();
107                 for (uint32_t i = 0; i < len; i++) {
108                     JSTaggedValue symbol = layoutInfo->GetKey(i);
109                     if (symbol.IsSymbol()) {
110                         JSSymbol* symbolPtr = JSSymbol::Cast(symbol.GetTaggedObject());
111                         uint64_t symbolId = symbolPtr->GetPrivateId();
112                         uint64_t slotIndex = JSSymbol::GetSlotIndex(symbolId);
113                         ProfileTypeTuple symbolIdKey = std::make_tuple(rootType, childType, slotIndex);
114                         profileTypeToSymbolId_.emplace(symbolIdKey, symbolId);
115                         symbolInfo->Set(thread_, pos++, JSTaggedValue(symbolId));
116                         symbolInfo->Set(thread_, pos++, symbol);
117                     }
118                 }
119             }
120         }
121     }
122 
123     EcmaVM *vm = thread_->GetEcmaVM();
124     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
125         vm->AddAOTSnapShotStats("SymbolInfo", symbolInfo->GetLength());
126     }
127     aotSnapshot_.StoreSymbolInfo(symbolInfo);
128 }
129 
GenHClassInfo()130 void PGOTypeManager::GenHClassInfo()
131 {
132     uint32_t count = 1; // For object literal hclass cache
133     for (auto& root: hcData_) {
134         count += root.second.size();
135     }
136 
137     ObjectFactory* factory = thread_->GetEcmaVM()->GetFactory();
138     JSHandle<TaggedArray> hclassInfo = factory->NewTaggedArray(count);
139     uint32_t pos = 0;
140     profileTyperToHClassIndex_.clear();
141     for (auto& root: hcData_) {
142         ProfileType rootType = root.first;
143         for (auto& child: root.second) {
144             ProfileType childType = child.first;
145             JSTaggedType hclass = child.second;
146             ProfileTyper key = std::make_pair(rootType, childType);
147             profileTyperToHClassIndex_.emplace(key, pos);
148             hclassInfo->Set(thread_, pos++, JSTaggedValue(hclass));
149         }
150     }
151     // The cache of Object literal serializes to last index of AOTHClassInfo.
152     JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();
153     JSHandle<JSTaggedValue> maybeCache = env->GetObjectLiteralHClassCache();
154     if (!maybeCache->IsHole()) {
155         // It cannot be serialized if object in global env.
156         JSHandle<TaggedArray> array(maybeCache);
157         auto cloneResult = factory->CopyArray(array, array->GetLength(), array->GetLength());
158         hclassInfo->Set(thread_, pos++, cloneResult);
159     }
160 
161     EcmaVM *vm = thread_->GetEcmaVM();
162     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
163         vm->AddAOTSnapShotStats("HClassInfo", hclassInfo->GetLength());
164     }
165     aotSnapshot_.StoreHClassInfo(hclassInfo);
166 }
167 
GenProtoTransitionInfo()168 void PGOTypeManager::GenProtoTransitionInfo()
169 {
170     auto transitionTable = thread_->GetCurrentEcmaContext()->GetFunctionProtoTransitionTable();
171     for (auto &protoTransType : protoTransTypes_) {
172         JSTaggedValue ihc = QueryHClass(protoTransType.ihcType, protoTransType.ihcType);
173         JSTaggedValue baseIhc = QueryHClass(protoTransType.baseRootType, protoTransType.baseType);
174         JSTaggedValue transIhc = QueryHClass(protoTransType.transIhcType, protoTransType.transIhcType);
175         JSTaggedValue transPhc = QueryHClass(protoTransType.transPhcType, protoTransType.transPhcType);
176         if (ihc.IsUndefined() || baseIhc.IsUndefined() || transIhc.IsUndefined() || transPhc.IsUndefined()) {
177             LOG_COMPILER(ERROR) << "broken prototype transition info!";
178             continue;
179         }
180         transitionTable->InsertTransitionItem(thread_,
181                                               JSHandle<JSTaggedValue>(thread_, ihc),
182                                               JSHandle<JSTaggedValue>(thread_, baseIhc),
183                                               JSHandle<JSTaggedValue>(thread_, transIhc),
184                                               JSHandle<JSTaggedValue>(thread_, transPhc));
185         // Situation:
186         // 1: d1.prototype = p
187         // 2: d2.prototype = p
188         // For this case, baseIhc is transPhc
189         transitionTable->InsertTransitionItem(thread_,
190                                               JSHandle<JSTaggedValue>(thread_, ihc),
191                                               JSHandle<JSTaggedValue>(thread_, transPhc),
192                                               JSHandle<JSTaggedValue>(thread_, transIhc),
193                                               JSHandle<JSTaggedValue>(thread_, transPhc));
194     }
195     aotSnapshot_.StoreProtoTransTableInfo(JSHandle<JSTaggedValue>(thread_, transitionTable->GetProtoTransitionTable()));
196 }
197 
GenArrayInfo()198 void PGOTypeManager::GenArrayInfo()
199 {
200     EcmaVM *vm = thread_->GetEcmaVM();
201     ObjectFactory *factory = vm->GetFactory();
202     JSHandle<TaggedArray> arrayInfo = factory->EmptyArray();
203     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
204         vm->AddAOTSnapShotStats("ArrayInfo", arrayInfo->GetLength());
205     }
206     aotSnapshot_.StoreArrayInfo(arrayInfo);
207 }
208 
GenConstantIndexInfo()209 void PGOTypeManager::GenConstantIndexInfo()
210 {
211     uint32_t count = constantIndexData_.size();
212     EcmaVM *vm = thread_->GetEcmaVM();
213     ObjectFactory *factory = vm->GetFactory();
214     JSHandle<TaggedArray> constantIndexInfo = factory->NewTaggedArray(count);
215     for (uint32_t pos = 0; pos < count; pos++) {
216         constantIndexInfo->Set(thread_, pos, JSTaggedValue(constantIndexData_[pos]));
217     }
218     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
219         vm->AddAOTSnapShotStats("ConstantIndexInfo", constantIndexInfo->GetLength());
220     }
221     aotSnapshot_.StoreConstantIndexInfo(constantIndexInfo);
222 }
223 
RecordHClass(ProfileType rootType,ProfileType childType,JSTaggedType hclass,bool update)224 void PGOTypeManager::RecordHClass(ProfileType rootType, ProfileType childType, JSTaggedType hclass, bool update)
225 {
226     LockHolder lock(mutex_);
227     auto iter = hcData_.find(rootType);
228     if (iter == hcData_.end()) {
229         auto map = TransIdToHClass();
230         map.emplace(childType, hclass);
231         hcData_.emplace(rootType, map);
232         return;
233     }
234 
235     auto &hclassMap = iter->second;
236     auto hclassIter = hclassMap.find(childType);
237     if (hclassIter != hclassMap.end()) {
238         if (!update) {
239             ASSERT(hclass == hclassIter->second);
240             return;
241         } else {
242             hclassMap[childType]= hclass;
243             return;
244         }
245     }
246     hclassMap.emplace(childType, hclass);
247 }
248 
RecordConstantIndex(uint32_t bcAbsoluteOffset,uint32_t index)249 void PGOTypeManager::RecordConstantIndex(uint32_t bcAbsoluteOffset, uint32_t index)
250 {
251     constantIndexData_.emplace_back(bcAbsoluteOffset);
252     constantIndexData_.emplace_back(index);
253 }
254 
GetHClassIndexByProfileType(ProfileTyper type) const255 uint32_t PGOTypeManager::GetHClassIndexByProfileType(ProfileTyper type) const
256 {
257     uint32_t index = -1;
258     auto iter = profileTyperToHClassIndex_.find(type);
259     if (iter != profileTyperToHClassIndex_.end()) {
260         index = iter->second;
261     }
262     return index;
263 }
264 
GetHolderHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type,bool isAot)265 int PGOTypeManager::GetHolderHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type, bool isAot)
266 {
267     if (isAot) {
268         ProfileTyper holderType = std::make_pair(type.GetHoldRootType(), type.GetHoldType());
269         int holderHCIndex = static_cast<int>(GetHClassIndexByProfileType(holderType));
270         ASSERT(QueryHClass(holderType.first, holderType.second).IsJSHClass());
271         return holderHCIndex;
272     } else {
273         JSHClass *holderHClass = type.GetHolderHclass();
274         int holderHCIndex = RecordAndGetHclassIndexForJIT(holderHClass);
275         return holderHCIndex;
276     }
277 }
278 
GetReceiverHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type,bool isAot)279 int PGOTypeManager::GetReceiverHIndexByPGOObjectInfoType(pgo::PGOObjectInfo type, bool isAot)
280 {
281     if (isAot) {
282         ProfileTyper receiverType = std::make_pair(type.GetReceiverRootType(), type.GetReceiverType());
283         int receiverHCIndex = static_cast<int>(GetHClassIndexByProfileType(receiverType));
284         ASSERT(QueryHClass(receiverType.first, receiverType.second).IsJSHClass());
285         return receiverHCIndex;
286     } else {
287         JSHClass *receiverHClass = type.GetReceiverHclass();
288         int receiverHCIndex = RecordAndGetHclassIndexForJIT(receiverHClass);
289         return receiverHCIndex;
290     }
291 }
292 
GetSymbolIdByProfileType(ProfileTypeTuple type) const293 std::optional<uint64_t> PGOTypeManager::GetSymbolIdByProfileType(ProfileTypeTuple type) const
294 {
295     auto iter = profileTypeToSymbolId_.find(type);
296     if (iter != profileTypeToSymbolId_.end()) {
297         return iter->second;
298     }
299     return std::nullopt;
300 }
301 
QueryHClass(ProfileType rootType,ProfileType childType)302 JSTaggedValue PGOTypeManager::QueryHClass(ProfileType rootType, ProfileType childType)
303 {
304     LockHolder lock(mutex_);
305     JSTaggedValue result = JSTaggedValue::Undefined();
306     auto iter = hcData_.find(rootType);
307     if (iter != hcData_.end()) {
308         auto hclassMap = iter->second;
309         auto hclassIter = hclassMap.find(childType);
310         if (hclassIter != hclassMap.end()) {
311             result = JSTaggedValue(hclassIter->second);
312         }
313     }
314     // Can return real hclass of object or prototype of it
315     return result;
316 }
317 
QueryHClassByIndexForJIT(uint32_t hclassIndex)318 JSTaggedValue PGOTypeManager::QueryHClassByIndexForJIT(uint32_t hclassIndex)
319 {
320     ASSERT(hclassIndex < pos_);
321     return hclassInfoLocal_[hclassIndex];
322 }
323 
RecordAndGetHclassIndexForJIT(JSHClass * hclass)324 int PGOTypeManager::RecordAndGetHclassIndexForJIT(JSHClass* hclass)
325 {
326     // The hclass in hclassInfoLocal_ cannot currently be cleared after each
327     // JIT session because it depends on ensuring the survival of hclass.
328     // If a reference from machineCode to hclass is added in the future, then it can be cleared.
329     auto value = JSTaggedValue::Cast(hclass);
330     for (int i = 0; i < pos_; i++) {
331         if (hclassInfoLocal_[i] == value) {
332             return i;
333         }
334     }
335     hclassInfoLocal_.emplace_back(value);
336     return pos_++;
337 }
338 
339 
340 }  // namespace panda::ecmascript
341