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/aot_snapshot/snapshot_constantpool_data.h"
17 
18 #include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
19 #include "ecmascript/js_object-inl.h"
20 #include "ecmascript/jspandafile/program_object.h"
21 
22 namespace panda::ecmascript::kungfu {
GetItemKey(uint32_t constantPoolId, uint32_t constantPoolIdx)23 uint64_t BaseSnapshotInfo::GetItemKey(uint32_t constantPoolId, uint32_t constantPoolIdx)
24 {
25     uint64_t result = constantPoolId;
26     result = result << CONSTPOOL_MASK;
27     result |= constantPoolIdx;
28     return result;
29 }
30 
TryGetABCId(ApEntityId &abcId)31 bool BaseSnapshotInfo::TryGetABCId(ApEntityId &abcId)
32 {
33     return pfDecoder_->GetABCIdByJSPandaFile(jsPandaFile_, abcId);
34 }
35 
TryGetIHClass(ProfileType rootType, ProfileType childType, const ItemData &data, const JSHandle<TaggedArray> &properties, const SnapshotGlobalData &globalData) const36 JSHandle<JSTaggedValue> BaseSnapshotInfo::TryGetIHClass(ProfileType rootType, ProfileType childType,
37     const ItemData &data, const JSHandle<TaggedArray> &properties, const SnapshotGlobalData &globalData) const
38 {
39     JSHandle<JSTaggedValue> ihc = TryGetHClass(rootType, childType);
40     if (ihc->IsUndefined()) {
41         PGOTypeLocation loc(jsPandaFile_, data.methodOffset_, data.bcIndex_);
42         ihc = TryGetHClassByPGOTypeLocation(loc);
43         if (ihc->IsUndefined()) {
44             ihc = TryGetHClassFromCached(properties, globalData);
45         }
46     }
47     return ihc;
48 }
49 
TryGetHClass(ProfileType rootType, ProfileType childType) const50 JSHandle<JSTaggedValue> BaseSnapshotInfo::TryGetHClass(ProfileType rootType, ProfileType childType) const
51 {
52     PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
53     JSTaggedValue hclass = ptManager->QueryHClass(rootType, childType);
54     return JSHandle<JSTaggedValue>(thread_, hclass);
55 }
56 
TryGetHClassByPGOTypeLocation(PGOTypeLocation loc) const57 JSHandle<JSTaggedValue> BaseSnapshotInfo::TryGetHClassByPGOTypeLocation(PGOTypeLocation loc) const
58 {
59     PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
60     ProfileType  pt = ptManager->GetRootIdByLocation(loc);
61     return TryGetHClass(pt, pt);
62 }
63 
TryGetHClassFromCached(const JSHandle<TaggedArray> &properties, const SnapshotGlobalData &globalData) const64 JSHandle<JSTaggedValue> BaseSnapshotInfo::TryGetHClassFromCached(const JSHandle<TaggedArray> &properties,
65                                                                  const SnapshotGlobalData &globalData) const
66 {
67     DISALLOW_GARBAGE_COLLECTION;
68     JSHandle<JSTaggedValue> maybeCache(thread_, globalData.GetObjectLiteralHClassCache());
69     if (maybeCache->IsTaggedArray()) {
70         size_t length = properties->GetLength();
71         uint32_t propsLen = 0;
72         for (size_t i = 0; i < length; i += 2) { // 2: skip a pair of key and value
73             if (properties->Get(i).IsHole()) {
74                 break;
75             }
76             propsLen++;
77         }
78 
79         if (!ObjectFactory::CanObjectLiteralHClassCache(propsLen)) {
80             return thread_->GlobalConstants()->GetHandledUndefined();
81         }
82 
83         JSHandle<TaggedArray> hclassCacheArr = JSHandle<TaggedArray>::Cast(maybeCache);
84         JSTaggedValue maybeHClass = hclassCacheArr->Get(propsLen);
85         if (!maybeHClass.IsJSHClass()) {
86             return thread_->GlobalConstants()->GetHandledUndefined();
87         }
88         JSHClass *newClass = JSHClass::Cast(maybeHClass.GetTaggedObject());
89         JSMutableHandle<JSTaggedValue> key(thread_, JSTaggedValue::Undefined());
90 
91         for (size_t fieldOffset = 0; fieldOffset < propsLen; fieldOffset++) {
92             key.Update(properties->Get(fieldOffset * 2)); // 2 : pair of key and value
93             ASSERT_PRINT(JSTaggedValue::IsPropertyKey(key), "Key is not a property key");
94             PropertyAttributes attributes = PropertyAttributes::Default();
95             auto value = properties->Get(fieldOffset * 2 + 1);
96             if (value.IsAccessor()) {  // 2: Meaning to double
97                 attributes.SetIsAccessor(true);
98             }
99             attributes.SetIsInlinedProps(true);
100             attributes.SetRepresentation(Representation::TAGGED);
101             attributes.SetOffset(fieldOffset);
102 
103             auto metadata = JSTaggedValue(attributes.GetPropertyMetaData());
104             auto rep = PropertyAttributes::TranslateToRep(value);
105             newClass = newClass->FindTransitions(key.GetTaggedValue(), metadata, rep);
106             if (newClass == nullptr) {
107                 return thread_->GlobalConstants()->GetHandledUndefined();
108             }
109         }
110 
111         auto result = JSHandle<JSHClass>(thread_, newClass);
112         if (JSObject::CheckPropertiesForRep(properties, propsLen, result)) {
113             return JSHandle<JSTaggedValue>(result);
114         }
115     }
116     return thread_->GlobalConstants()->GetHandledUndefined();
117 }
118 
Record(ItemData &data)119 void BaseSnapshotInfo::Record(ItemData &data)
120 {
121     ItemKey key = GetItemKey(data.constantPoolId_, data.constantPoolIdx_);
122     info_.emplace(key, data);
123 }
124 
CollectLiteralInfo(JSHandle<TaggedArray> array, uint32_t constantPoolIndex, JSHandle<ConstantPool> snapshotConstantPool, const std::set<uint32_t> &skippedMethods, JSHandle<JSTaggedValue> ihc, JSHandle<JSTaggedValue> chc)125 void BaseSnapshotInfo::CollectLiteralInfo(JSHandle<TaggedArray> array, uint32_t constantPoolIndex,
126                                           JSHandle<ConstantPool> snapshotConstantPool,
127                                           const std::set<uint32_t> &skippedMethods,
128                                           JSHandle<JSTaggedValue> ihc, JSHandle<JSTaggedValue> chc)
129 {
130     ObjectFactory *factory = vm_->GetFactory();
131     JSMutableHandle<JSTaggedValue> valueHandle(thread_, JSTaggedValue::Undefined());
132     uint32_t len = array->GetLength();
133     std::vector<int> methodOffsetVec;
134     for (uint32_t i = 0; i < len; i++) {
135         valueHandle.Update(array->Get(i));
136         uint32_t methodOffset = 0;
137         if (valueHandle->IsJSFunction()) {
138             methodOffset = JSHandle<JSFunction>(valueHandle)->GetCallTarget()->GetMethodId().GetOffset();
139         } else if (valueHandle->IsFunctionTemplate()) {
140             auto method = Method::Cast(JSHandle<FunctionTemplate>(valueHandle)->GetMethod());
141             methodOffset = method->GetMethodId().GetOffset();
142         }
143         if (methodOffset != 0) {
144             if (skippedMethods.find(methodOffset) != skippedMethods.end()) {
145                 methodOffsetVec.emplace_back(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE);
146             } else {
147                 methodOffsetVec.emplace_back(methodOffset);
148             }
149         }
150     }
151 
152     uint32_t methodSize = methodOffsetVec.size();
153     JSHandle<AOTLiteralInfo> aotLiteralInfo = factory->NewAOTLiteralInfo(methodSize);
154     for (uint32_t i = 0; i < methodSize; ++i) {
155         auto methodOffset = methodOffsetVec[i];
156         aotLiteralInfo->SetObjectToCache(thread_, i, JSTaggedValue(methodOffset));
157     }
158 
159     if (!ihc->IsUndefined()) {
160         aotLiteralInfo->SetIhc(ihc.GetTaggedValue());
161     }
162 
163     if (!chc->IsUndefined()) {
164         aotLiteralInfo->SetChc(chc.GetTaggedValue());
165     }
166 
167     snapshotConstantPool->SetObjectToCache(thread_, constantPoolIndex, aotLiteralInfo.GetTaggedValue());
168 }
169 
CheckAOTPropertiesForRep(const JSHandle<TaggedArray> &properties, const JSHandle<JSHClass> &hclass)170 bool BaseSnapshotInfo::CheckAOTPropertiesForRep(const JSHandle<TaggedArray> &properties,
171                                                 const JSHandle<JSHClass> &hclass)
172 {
173     auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
174     for (size_t i = 0; i < properties->GetLength(); i++) {
175         auto attr = layout->GetAttr(i);
176         auto value = JSObject::ConvertValueWithRep(attr, properties->Get(i));
177         // If value.first is false, indicating that value cannot be converted to the expected value of
178         // representation. For example, the representation is INT, but the value type is string.
179         if (!value.first) {
180             return false;
181         }
182     }
183     return true;
184 }
185 
CheckAOTIhcPropertiesForRep(JSThread *thread, const JSHandle<JSTaggedValue> &ihc, const JSHandle<ClassInfoExtractor> &extractor)186 bool BaseSnapshotInfo::CheckAOTIhcPropertiesForRep(JSThread *thread, const JSHandle<JSTaggedValue> &ihc,
187                                                    const JSHandle<ClassInfoExtractor> &extractor)
188 {
189     if (ihc->IsUndefinedOrNull()) {
190         return false;
191     }
192     JSHandle<JSObject> prototype;
193     if (ihc->IsJSHClass()) {
194         JSHandle<JSHClass> ihclass(ihc);
195         prototype = JSHandle<JSObject>(thread, ihclass->GetProto());
196     } else {
197         prototype = JSHandle<JSObject>(ihc);
198     }
199 
200     ASSERT(!prototype->GetJSHClass()->IsDictionaryMode());
201     JSHandle<TaggedArray> nonStaticProperties(thread, extractor->GetNonStaticProperties());
202     JSHandle<JSHClass> protohclass(thread, prototype->GetJSHClass());
203     return CheckAOTPropertiesForRep(nonStaticProperties, protohclass);
204 }
205 
CheckAOTChcPropertiesForRep(JSThread *thread, const JSHandle<JSTaggedValue> &chc, const JSHandle<ClassInfoExtractor> &extractor)206 bool BaseSnapshotInfo::CheckAOTChcPropertiesForRep(JSThread *thread, const JSHandle<JSTaggedValue> &chc,
207                                                    const JSHandle<ClassInfoExtractor> &extractor)
208 {
209     if (chc->IsUndefinedOrNull()) {
210         return false;
211     }
212     JSHandle<JSHClass> chclass(thread, JSHClass::Cast(chc->GetTaggedObject()));
213     ASSERT(!chclass->IsDictionaryMode());
214     JSHandle<TaggedArray> staticProperties(thread, extractor->GetStaticProperties());
215     return CheckAOTPropertiesForRep(staticProperties, chclass);
216 }
217 
StoreDataToGlobalData(SnapshotGlobalData &globalData, const std::set<uint32_t>&)218 void StringSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData, const std::set<uint32_t>&)
219 {
220     for (auto item : info_) {
221         const ItemData &data = item.second;
222         uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
223         JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
224         JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
225         // Lazy ConstantPool String Loading
226         snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, JSTaggedValue::Hole());
227     }
228 
229     if (vm_->GetJSOptions().IsEnableCompilerLogSnapshot()) {
230         vm_->AddAOTSnapShotStats("String", info_.size());
231     }
232 }
233 
StoreDataToGlobalData(SnapshotGlobalData &globalData, const std::set<uint32_t> &skippedMethods)234 void MethodSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
235                                                const std::set<uint32_t> &skippedMethods)
236 {
237     ApEntityId abcId = INVALID_INDEX;
238     bool hasAbcId = TryGetABCId(abcId);
239     ObjectFactory *factory = vm_->GetFactory();
240     for (auto item : info_) {
241         const ItemData &data = item.second;
242         JSHandle<ConstantPool> cp(thread_,
243             thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_));
244         uint32_t methodOffset = cp->GetEntityId(data.constantPoolIdx_).GetOffset();
245 
246         uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
247         JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
248         JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
249 
250         JSHandle<JSTaggedValue> ihc = thread_->GlobalConstants()->GetHandledUndefined();
251         if (hasAbcId) {
252             ProfileType pt(abcId, methodOffset, ProfileType::Kind::ClassId, true);
253             ihc = TryGetHClass(pt, pt);
254         }
255         JSHandle<AOTLiteralInfo> aotLiteralInfo = factory->NewAOTLiteralInfo(1); // 1: only one method
256         int initValue = static_cast<int>(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE);
257         aotLiteralInfo->SetObjectToCache(thread_, 0, JSTaggedValue(initValue));
258         aotLiteralInfo->SetLiteralType(JSTaggedValue(AOTLiteralInfo::METHOD_LITERAL_TYPE));
259         if (!ihc->IsUndefined()) {
260             aotLiteralInfo->SetIhc(ihc.GetTaggedValue());
261             if (skippedMethods.find(methodOffset) == skippedMethods.end()) {
262                 aotLiteralInfo->SetObjectToCache(thread_, 0, JSTaggedValue(methodOffset));
263                 globalData.RecordReviseData(
264                     ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
265             }
266             snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, aotLiteralInfo.GetTaggedValue());
267         } else if (skippedMethods.find(methodOffset) == skippedMethods.end()) {
268             // For MethodSnaphotInfo which does not have ihc info, we insert JSTaggedValue(methodOffset) as revervation.
269             // For the purpose of reducing ai size.
270             globalData.RecordReviseData(
271                 ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
272             snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, JSTaggedValue(methodOffset));
273         } else {
274             snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, JSTaggedValue::Hole());
275         }
276     }
277     if (vm_->GetJSOptions().IsEnableCompilerLogSnapshot()) {
278         vm_->AddAOTSnapShotStats("Method", info_.size());
279     }
280 }
281 
StoreDataToGlobalData(SnapshotGlobalData &globalData, const std::set<uint32_t> &skippedMethods)282 void ClassLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
283                                                      const std::set<uint32_t> &skippedMethods)
284 {
285     ApEntityId abcId = INVALID_INDEX;
286     bool hasAbcId = TryGetABCId(abcId);
287     for (auto item : info_) {
288         const ItemData &data = item.second;
289         JSHandle<ConstantPool> cp = GetUnsharedConstpool(data);
290         auto literalObj = ConstantPool::GetClassLiteralFromCache(thread_, cp, data.constantPoolIdx_, data.recordName_);
291         JSHandle<ClassLiteral> classLiteral(thread_, literalObj);
292         JSHandle<TaggedArray> arrayHandle(thread_, classLiteral->GetArray());
293 
294         uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
295         JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
296         JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
297 
298         uint32_t methodId = cp->GetEntityId(data.ctorMethodOffset_).GetOffset();
299         JSHandle<JSTaggedValue> undefinedHandle = thread_->GlobalConstants()->GetHandledUndefined();
300         JSHandle<JSTaggedValue> ihc = undefinedHandle;
301         JSHandle<JSTaggedValue> chc = undefinedHandle;
302         if (hasAbcId) {
303             ProfileType pt(abcId, methodId, ProfileType::Kind::ClassId, true);
304             ProfileType ctorPt(abcId, methodId, ProfileType::Kind::ConstructorId, true);
305             ihc = TryGetHClass(pt, pt);
306             chc = TryGetHClass(ctorPt, ctorPt);
307 
308             auto method = ConstantPool::GetMethodFromCache(thread_, cp.GetTaggedValue(), data.ctorMethodOffset_);
309             auto *factory = thread_->GetEcmaVM()->GetFactory();
310             auto extractor = factory->NewClassInfoExtractor(JSHandle<JSTaggedValue>(thread_, method));
311             ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(thread_, extractor, arrayHandle,
312                 arrayHandle->GetLength());
313             if (!CheckAOTIhcPropertiesForRep(thread_, ihc, extractor)) {
314                 ihc = undefinedHandle;
315             }
316             if (!CheckAOTChcPropertiesForRep(thread_, chc, extractor)) {
317                 chc = undefinedHandle;
318             }
319         }
320 
321         CollectLiteralInfo(arrayHandle, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
322         globalData.RecordReviseData(
323             ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
324     }
325     if (vm_->GetJSOptions().IsEnableCompilerLogSnapshot()) {
326         vm_->AddAOTSnapShotStats("ClassLiteral", info_.size());
327     }
328 }
329 
StoreDataToGlobalData(SnapshotGlobalData &globalData, const std::set<uint32_t> &skippedMethods)330 void ObjectLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
331                                                       const std::set<uint32_t> &skippedMethods)
332 {
333     ApEntityId abcId = INVALID_INDEX;
334     bool hasAbcId = TryGetABCId(abcId);
335     for (auto item : info_) {
336         const ItemData &data = item.second;
337         JSHandle<ConstantPool> cp = GetUnsharedConstpool(data);
338         panda_file::File::EntityId id = cp->GetEntityId(data.constantPoolIdx_);
339         JSMutableHandle<TaggedArray> elements(thread_, JSTaggedValue::Undefined());
340         JSMutableHandle<TaggedArray> properties(thread_, JSTaggedValue::Undefined());
341         LiteralDataExtractor::ExtractObjectDatas(thread_, jsPandaFile_, id, elements,
342                                                  properties, cp, data.recordName_);
343 
344         uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
345         JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
346         JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
347 
348         JSHandle<JSTaggedValue> ihc = thread_->GlobalConstants()->GetHandledUndefined();
349         JSHandle<JSTaggedValue> chc = thread_->GlobalConstants()->GetHandledUndefined();
350         if (hasAbcId) {
351             ProfileType pt(abcId, id.GetOffset(), ProfileType::Kind::ObjectLiteralId, true);
352             ProfileType ctorPt(abcId, id.GetOffset(), ProfileType::Kind::ConstructorId, true);
353             chc = TryGetHClass(ctorPt, ctorPt);
354             ihc = TryGetIHClass(pt, pt, data, properties, globalData);
355         }
356 
357         CollectLiteralInfo(properties, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
358         globalData.RecordReviseData(
359             ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
360     }
361     if (vm_->GetJSOptions().IsEnableCompilerLogSnapshot()) {
362         vm_->AddAOTSnapShotStats("ObjectLiteral", info_.size());
363     }
364 }
365 
StoreDataToGlobalData(SnapshotGlobalData &globalData, const std::set<uint32_t> &skippedMethods)366 void ArrayLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
367                                                      const std::set<uint32_t> &skippedMethods)
368 {
369     for (auto item : info_) {
370         const ItemData &data = item.second;
371         JSHandle<ConstantPool> cp = GetUnsharedConstpool(data);
372         panda_file::File::EntityId id = cp->GetEntityId(data.constantPoolIdx_);
373         JSHandle<TaggedArray> literal = LiteralDataExtractor::GetDatasIgnoreType(
374             thread_, jsPandaFile_, id, cp, data.recordName_);
375         uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
376         JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
377         JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
378         JSHandle<JSTaggedValue> ihc = thread_->GlobalConstants()->GetHandledUndefined();
379         JSHandle<JSTaggedValue> chc = thread_->GlobalConstants()->GetHandledUndefined();
380         CollectLiteralInfo(literal, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
381         globalData.RecordReviseData(
382             ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
383     }
384     if (vm_->GetJSOptions().IsEnableCompilerLogSnapshot()) {
385         vm_->AddAOTSnapShotStats("ArrayLiteral", info_.size());
386     }
387 }
388 
GetUnsharedConstpool(const ItemData &data)389 JSHandle<ConstantPool> BaseSnapshotInfo::GetUnsharedConstpool(const ItemData &data)
390 {
391     EcmaContext *context = thread_->GetCurrentEcmaContext();
392     JSTaggedValue shareCp = context->FindConstpool(jsPandaFile_, data.constantPoolId_);
393     JSHandle<ConstantPool> cp(thread_, context->FindOrCreateUnsharedConstpool(shareCp));
394     return cp;
395 }
396 
Record(const BytecodeInstruction &bcIns, int32_t bcIndex, const CString &recordName, const MethodLiteral *method)397 void SnapshotConstantPoolData::Record(const BytecodeInstruction &bcIns, int32_t bcIndex,
398                                       const CString &recordName, const MethodLiteral *method)
399 {
400     BytecodeInstruction::Opcode opcode = static_cast<BytecodeInstruction::Opcode>(bcIns.GetOpcode());
401     uint32_t methodOffset = method->GetMethodId().GetOffset();
402     panda_file::IndexAccessor indexAccessor(*jsPandaFile_->GetPandaFile(),
403                                             panda_file::File::EntityId(methodOffset));
404     uint32_t constantPoolId = static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
405 
406     switch (opcode) {
407         case BytecodeInstruction::Opcode::LDA_STR_ID16:
408         case BytecodeInstruction::Opcode::STOWNBYNAME_IMM8_ID16_V8:
409         case BytecodeInstruction::Opcode::STOWNBYNAME_IMM16_ID16_V8:
410         case BytecodeInstruction::Opcode::CREATEREGEXPWITHLITERAL_IMM8_ID16_IMM8:
411         case BytecodeInstruction::Opcode::CREATEREGEXPWITHLITERAL_IMM16_ID16_IMM8:
412         case BytecodeInstruction::Opcode::STCONSTTOGLOBALRECORD_IMM16_ID16:
413         case BytecodeInstruction::Opcode::TRYLDGLOBALBYNAME_IMM8_ID16:
414         case BytecodeInstruction::Opcode::TRYLDGLOBALBYNAME_IMM16_ID16:
415         case BytecodeInstruction::Opcode::TRYSTGLOBALBYNAME_IMM8_ID16:
416         case BytecodeInstruction::Opcode::TRYSTGLOBALBYNAME_IMM16_ID16:
417         case BytecodeInstruction::Opcode::STTOGLOBALRECORD_IMM16_ID16:
418         case BytecodeInstruction::Opcode::STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8:
419         case BytecodeInstruction::Opcode::STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8:
420         case BytecodeInstruction::Opcode::LDTHISBYNAME_IMM8_ID16:
421         case BytecodeInstruction::Opcode::LDTHISBYNAME_IMM16_ID16:
422         case BytecodeInstruction::Opcode::STTHISBYNAME_IMM8_ID16:
423         case BytecodeInstruction::Opcode::STTHISBYNAME_IMM16_ID16:
424         case BytecodeInstruction::Opcode::LDGLOBALVAR_IMM16_ID16:
425         case BytecodeInstruction::Opcode::LDOBJBYNAME_IMM8_ID16:
426         case BytecodeInstruction::Opcode::LDOBJBYNAME_IMM16_ID16:
427         case BytecodeInstruction::Opcode::STOBJBYNAME_IMM8_ID16_V8:
428         case BytecodeInstruction::Opcode::STOBJBYNAME_IMM16_ID16_V8:
429         case BytecodeInstruction::Opcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
430         case BytecodeInstruction::Opcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
431         case BytecodeInstruction::Opcode::LDSUPERBYNAME_IMM8_ID16:
432         case BytecodeInstruction::Opcode::LDSUPERBYNAME_IMM16_ID16:
433         case BytecodeInstruction::Opcode::STSUPERBYNAME_IMM8_ID16_V8:
434         case BytecodeInstruction::Opcode::STSUPERBYNAME_IMM16_ID16_V8:
435         case BytecodeInstruction::Opcode::STGLOBALVAR_IMM16_ID16:
436         case BytecodeInstruction::Opcode::LDBIGINT_ID16: {
437             auto constantPoolIdx = bcIns.GetId().AsRawValue();
438             BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
439             RecordInfo(Type::STRING, itemData);
440             break;
441         }
442         case BytecodeInstruction::Opcode::DEFINEFUNC_IMM8_ID16_IMM8:
443         case BytecodeInstruction::Opcode::DEFINEFUNC_IMM16_ID16_IMM8:
444         case BytecodeInstruction::Opcode::DEFINEMETHOD_IMM8_ID16_IMM8:
445         case BytecodeInstruction::Opcode::DEFINEMETHOD_IMM16_ID16_IMM8: {
446             auto constantPoolIdx = bcIns.GetId().AsRawValue();
447             BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
448             RecordInfo(Type::METHOD, itemData);
449             break;
450         }
451         case BytecodeInstruction::Opcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
452         case BytecodeInstruction::Opcode::CREATEOBJECTWITHBUFFER_IMM16_ID16: {
453             auto constantPoolIdx = bcIns.GetId().AsRawValue();
454             BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
455             RecordInfo(Type::OBJECT_LITERAL, itemData);
456             break;
457         }
458         case BytecodeInstruction::Opcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
459         case BytecodeInstruction::Opcode::CREATEARRAYWITHBUFFER_IMM16_ID16: {
460             auto constantPoolIdx = bcIns.GetId().AsRawValue();
461             BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
462             RecordInfo(Type::ARRAY_LITERAL, itemData);
463             break;
464         }
465         case BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: {
466             auto methodCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM8_ID16_ID16_IMM16_V8, 0>()).AsRawValue();
467             BaseSnapshotInfo::ItemData methodItemData = {recordName, constantPoolId,
468                 methodCPIdx, methodOffset, bcIndex};
469             RecordInfo(Type::METHOD, methodItemData);
470 
471             auto literalCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM8_ID16_ID16_IMM16_V8, 1>()).AsRawValue();
472             BaseSnapshotInfo::ItemData literalItemData = {recordName, constantPoolId,
473                 literalCPIdx, methodOffset, bcIndex, methodCPIdx};
474             RecordInfo(Type::CLASS_LITERAL, literalItemData);
475             break;
476         }
477         case BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: {
478             auto methodCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM16_ID16_ID16_IMM16_V8, 0>()).AsRawValue();
479             BaseSnapshotInfo::ItemData methodItemData = {recordName, constantPoolId,
480                 methodCPIdx, methodOffset, bcIndex};
481             RecordInfo(Type::METHOD, methodItemData);
482 
483             auto literalCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM16_ID16_ID16_IMM16_V8, 1>()).AsRawValue();
484             BaseSnapshotInfo::ItemData literalItemData = {recordName, constantPoolId,
485                 literalCPIdx, methodOffset, bcIndex, methodCPIdx};
486             RecordInfo(Type::CLASS_LITERAL, literalItemData);
487             break;
488         }
489         default:
490             break;
491     }
492 }
493 
StoreDataToGlobalData(SnapshotGlobalData &snapshotData, const std::set<uint32_t> &skippedMethods) const494 void SnapshotConstantPoolData::StoreDataToGlobalData(SnapshotGlobalData &snapshotData,
495                                                      const std::set<uint32_t> &skippedMethods) const
496 {
497     for (auto &info : infos_) {
498         info->StoreDataToGlobalData(snapshotData, skippedMethods);
499     }
500 }
501 }  // namespace panda::ecmascript
502