1 /*
2 * Copyright (c) 2023 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_location.h"
19 #include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
20 #include "ecmascript/jspandafile/program_object.h"
21 #include "ecmascript/ts_types/global_type_info.h"
22 #include "ecmascript/global_env_constants-inl.h"
23
24 namespace panda::ecmascript::kungfu {
GetItemKey(uint32_t constantPoolId,uint32_t constantPoolIdx)25 uint64_t BaseSnapshotInfo::GetItemKey(uint32_t constantPoolId, uint32_t constantPoolIdx)
26 {
27 uint64_t result = constantPoolId;
28 result = result << CONSTPOOL_MASK;
29 result |= constantPoolIdx;
30 return result;
31 }
32
TryGetABCId(ApEntityId & abcId)33 bool BaseSnapshotInfo::TryGetABCId(ApEntityId &abcId)
34 {
35 return pfDecoder_->GetABCIdByJSPandaFile(jsPandaFile_, abcId);
36 }
37
TryGetHClass(ProfileType rootType,ProfileType childType) const38 JSHandle<JSTaggedValue> BaseSnapshotInfo::TryGetHClass(ProfileType rootType, ProfileType childType) const
39 {
40 PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
41 JSTaggedValue hclass = ptManager->QueryHClass(rootType, childType);
42 return JSHandle<JSTaggedValue>(thread_, hclass);
43 }
44
TryGetHClassByPGOTypeLocation(PGOTypeLocation loc) const45 JSHandle<JSTaggedValue> BaseSnapshotInfo::TryGetHClassByPGOTypeLocation(PGOTypeLocation loc) const
46 {
47 PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
48 ProfileType pt = ptManager->GetRootIdByLocation(loc);
49 return TryGetHClass(pt, pt);
50 }
51
Record(ItemData & data)52 void BaseSnapshotInfo::Record(ItemData &data)
53 {
54 ItemKey key = GetItemKey(data.constantPoolId_, data.constantPoolIdx_);
55 info_.emplace(key, data);
56 }
57
CollectLiteralInfo(JSHandle<TaggedArray> array,uint32_t constantPoolIndex,JSHandle<ConstantPool> snapshotConstantPool,const std::set<uint32_t> & skippedMethods,JSHandle<JSTaggedValue> ihc,JSHandle<JSTaggedValue> chc,int32_t elementIndex)58 void BaseSnapshotInfo::CollectLiteralInfo(JSHandle<TaggedArray> array, uint32_t constantPoolIndex,
59 JSHandle<ConstantPool> snapshotConstantPool,
60 const std::set<uint32_t> &skippedMethods,
61 JSHandle<JSTaggedValue> ihc, JSHandle<JSTaggedValue> chc,
62 int32_t elementIndex)
63 {
64 ObjectFactory *factory = vm_->GetFactory();
65 JSMutableHandle<JSTaggedValue> valueHandle(thread_, JSTaggedValue::Undefined());
66 uint32_t len = array->GetLength();
67 std::vector<int> methodOffsetVec;
68 for (uint32_t i = 0; i < len; i++) {
69 valueHandle.Update(array->Get(i));
70 if (valueHandle->IsJSFunction()) {
71 auto methodOffset = JSHandle<JSFunction>(valueHandle)->GetCallTarget()->GetMethodId().GetOffset();
72 if (skippedMethods.find(methodOffset) != skippedMethods.end()) {
73 methodOffsetVec.emplace_back(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE);
74 } else {
75 methodOffsetVec.emplace_back(methodOffset);
76 }
77 }
78 }
79
80 uint32_t methodSize = methodOffsetVec.size();
81 JSHandle<AOTLiteralInfo> aotLiteralInfo = factory->NewAOTLiteralInfo(methodSize);
82 for (uint32_t i = 0; i < methodSize; ++i) {
83 auto methodOffset = methodOffsetVec[i];
84 aotLiteralInfo->SetObjectToCache(thread_, i, JSTaggedValue(methodOffset));
85 }
86
87 if (!ihc->IsUndefined()) {
88 aotLiteralInfo->SetIhc(ihc.GetTaggedValue());
89 }
90
91 if (!chc->IsUndefined()) {
92 aotLiteralInfo->SetChc(chc.GetTaggedValue());
93 }
94
95 if (elementIndex != AOT_ELEMENT_INDEX_DEFAULT_VALUE) {
96 aotLiteralInfo->SetElementIndex(JSTaggedValue(elementIndex));
97 }
98
99 snapshotConstantPool->SetObjectToCache(thread_, constantPoolIndex, aotLiteralInfo.GetTaggedValue());
100 }
101
StoreDataToGlobalData(SnapshotGlobalData & globalData,const std::set<uint32_t> &)102 void StringSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData, const std::set<uint32_t>&)
103 {
104 for (auto item : info_) {
105 const ItemData &data = item.second;
106 JSTaggedValue cp = thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_);
107 JSTaggedValue str = ConstantPool::GetStringFromCache(thread_, cp, data.constantPoolIdx_);
108
109 uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
110 JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
111 JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
112 snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, str);
113 }
114 }
115
StoreDataToGlobalData(SnapshotGlobalData & globalData,const std::set<uint32_t> & skippedMethods)116 void MethodSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
117 const std::set<uint32_t> &skippedMethods)
118 {
119 ApEntityId abcId = INVALID_INDEX;
120 bool hasAbcId = TryGetABCId(abcId);
121 ObjectFactory *factory = vm_->GetFactory();
122 for (auto item : info_) {
123 const ItemData &data = item.second;
124 JSHandle<ConstantPool> cp(thread_,
125 thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_));
126 uint32_t methodOffset = cp->GetEntityId(data.constantPoolIdx_).GetOffset();
127
128 uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
129 JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
130 JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
131
132 JSHandle<JSTaggedValue> ihc = thread_->GlobalConstants()->GetHandledUndefined();
133 if (hasAbcId) {
134 ProfileType pt(abcId, methodOffset, ProfileType::Kind::ClassId, true);
135 ihc = TryGetHClass(pt, pt);
136 }
137 JSHandle<AOTLiteralInfo> aotLiteralInfo = factory->NewAOTLiteralInfo(1); // 1: only one method
138 int initValue = static_cast<int>(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE);
139 aotLiteralInfo->SetObjectToCache(thread_, 0, JSTaggedValue(initValue));
140 if (!ihc->IsUndefined()) {
141 aotLiteralInfo->SetIhc(ihc.GetTaggedValue());
142 }
143 if (skippedMethods.find(methodOffset) == skippedMethods.end()) {
144 aotLiteralInfo->SetObjectToCache(thread_, 0, JSTaggedValue(methodOffset));
145 globalData.RecordReviseData(
146 ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
147 }
148 snapshotCp->SetObjectToCache(thread_, data.constantPoolIdx_, aotLiteralInfo.GetTaggedValue());
149 }
150 }
151
StoreDataToGlobalData(SnapshotGlobalData & globalData,const std::set<uint32_t> & skippedMethods)152 void ClassLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
153 const std::set<uint32_t> &skippedMethods)
154 {
155 ApEntityId abcId = INVALID_INDEX;
156 bool hasAbcId = TryGetABCId(abcId);
157 for (auto item : info_) {
158 const ItemData &data = item.second;
159 JSHandle<ConstantPool> cp(thread_,
160 thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_));
161 auto literalObj = ConstantPool::GetClassLiteralFromCache(thread_, cp, data.constantPoolIdx_, data.recordName_);
162 JSHandle<ClassLiteral> classLiteral(thread_, literalObj);
163 JSHandle<TaggedArray> arrayHandle(thread_, classLiteral->GetArray());
164
165 uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
166 JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
167 JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
168
169 uint32_t methodId = cp->GetEntityId(data.ctorMethodOffset_).GetOffset();
170 JSHandle<JSTaggedValue> ihc = thread_->GlobalConstants()->GetHandledUndefined();
171 JSHandle<JSTaggedValue> chc = thread_->GlobalConstants()->GetHandledUndefined();
172 if (hasAbcId) {
173 ProfileType pt(abcId, methodId, ProfileType::Kind::ClassId, true);
174 ProfileType ctorPt(abcId, methodId, ProfileType::Kind::ConstructorId, true);
175 ihc = TryGetHClass(pt, pt);
176 chc = TryGetHClass(ctorPt, ctorPt);
177 }
178
179 CollectLiteralInfo(arrayHandle, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
180 globalData.RecordReviseData(
181 ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
182 }
183 }
184
185
StoreDataToGlobalData(SnapshotGlobalData & globalData,const std::set<uint32_t> & skippedMethods)186 void ObjectLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
187 const std::set<uint32_t> &skippedMethods)
188 {
189 ApEntityId abcId = INVALID_INDEX;
190 bool hasAbcId = TryGetABCId(abcId);
191 for (auto item : info_) {
192 const ItemData &data = item.second;
193 JSHandle<ConstantPool> cp(thread_,
194 thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_));
195 panda_file::File::EntityId id = cp->GetEntityId(data.constantPoolIdx_);
196 JSMutableHandle<TaggedArray> elements(thread_, JSTaggedValue::Undefined());
197 JSMutableHandle<TaggedArray> properties(thread_, JSTaggedValue::Undefined());
198 LiteralDataExtractor::ExtractObjectDatas(thread_, jsPandaFile_, id, elements,
199 properties, cp, data.recordName_);
200
201 uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
202 JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
203 JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
204
205 JSHandle<JSTaggedValue> ihc = thread_->GlobalConstants()->GetHandledUndefined();
206 JSHandle<JSTaggedValue> chc = thread_->GlobalConstants()->GetHandledUndefined();
207 if (hasAbcId) {
208 ProfileType pt(abcId, id.GetOffset(), ProfileType::Kind::LiteralId, true);
209 ProfileType ctorPt(abcId, id.GetOffset(), ProfileType::Kind::ConstructorId, true);
210 ihc = TryGetHClass(pt, pt);
211 chc = TryGetHClass(ctorPt, ctorPt);
212 if (ihc->IsUndefined()) {
213 PGOTypeLocation loc(jsPandaFile_, data.methodOffset_, data.bcIndex_);
214 ihc = TryGetHClassByPGOTypeLocation(loc);
215 }
216 }
217
218 CollectLiteralInfo(properties, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
219 globalData.RecordReviseData(
220 ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
221 }
222 }
223
StoreDataToGlobalData(SnapshotGlobalData & globalData,const std::set<uint32_t> & skippedMethods)224 void ArrayLiteralSnapshotInfo::StoreDataToGlobalData(SnapshotGlobalData &globalData,
225 const std::set<uint32_t> &skippedMethods)
226 {
227 PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
228 for (auto item : info_) {
229 const ItemData &data = item.second;
230 JSHandle<ConstantPool> cp(thread_,
231 thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, data.constantPoolId_));
232 panda_file::File::EntityId id = cp->GetEntityId(data.constantPoolIdx_);
233 JSHandle<TaggedArray> literal = LiteralDataExtractor::GetDatasIgnoreType(
234 thread_, jsPandaFile_, id, cp, data.recordName_);
235 int32_t elementIndex = ptManager->GetElementsIndexByEntityId(id);
236
237 uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
238 JSHandle<TaggedArray> snapshotCpArr(thread_, globalData.GetCurSnapshotCpArray());
239 JSHandle<ConstantPool> snapshotCp(thread_, snapshotCpArr->Get(snapshotCpArrIdx));
240 JSHandle<JSTaggedValue> ihc = thread_->GlobalConstants()->GetHandledUndefined();
241 JSHandle<JSTaggedValue> chc = thread_->GlobalConstants()->GetHandledUndefined();
242 CollectLiteralInfo(literal, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc, elementIndex);
243 globalData.RecordReviseData(
244 ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
245 }
246 }
247
Record(const BytecodeInstruction & bcIns,int32_t bcIndex,const CString & recordName,const MethodLiteral * method)248 void SnapshotConstantPoolData::Record(const BytecodeInstruction &bcIns, int32_t bcIndex,
249 const CString &recordName, const MethodLiteral *method)
250 {
251 BytecodeInstruction::Opcode opcode = static_cast<BytecodeInstruction::Opcode>(bcIns.GetOpcode());
252 uint32_t methodOffset = method->GetMethodId().GetOffset();
253 panda_file::IndexAccessor indexAccessor(*jsPandaFile_->GetPandaFile(),
254 panda_file::File::EntityId(methodOffset));
255 uint32_t constantPoolId = static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
256
257 switch (opcode) {
258 case BytecodeInstruction::Opcode::LDA_STR_ID16:
259 case BytecodeInstruction::Opcode::STOWNBYNAME_IMM8_ID16_V8:
260 case BytecodeInstruction::Opcode::STOWNBYNAME_IMM16_ID16_V8:
261 case BytecodeInstruction::Opcode::CREATEREGEXPWITHLITERAL_IMM8_ID16_IMM8:
262 case BytecodeInstruction::Opcode::CREATEREGEXPWITHLITERAL_IMM16_ID16_IMM8:
263 case BytecodeInstruction::Opcode::STCONSTTOGLOBALRECORD_IMM16_ID16:
264 case BytecodeInstruction::Opcode::TRYLDGLOBALBYNAME_IMM8_ID16:
265 case BytecodeInstruction::Opcode::TRYLDGLOBALBYNAME_IMM16_ID16:
266 case BytecodeInstruction::Opcode::TRYSTGLOBALBYNAME_IMM8_ID16:
267 case BytecodeInstruction::Opcode::TRYSTGLOBALBYNAME_IMM16_ID16:
268 case BytecodeInstruction::Opcode::STTOGLOBALRECORD_IMM16_ID16:
269 case BytecodeInstruction::Opcode::STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8:
270 case BytecodeInstruction::Opcode::STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8:
271 case BytecodeInstruction::Opcode::LDTHISBYNAME_IMM8_ID16:
272 case BytecodeInstruction::Opcode::LDTHISBYNAME_IMM16_ID16:
273 case BytecodeInstruction::Opcode::STTHISBYNAME_IMM8_ID16:
274 case BytecodeInstruction::Opcode::STTHISBYNAME_IMM16_ID16:
275 case BytecodeInstruction::Opcode::LDGLOBALVAR_IMM16_ID16:
276 case BytecodeInstruction::Opcode::LDOBJBYNAME_IMM8_ID16:
277 case BytecodeInstruction::Opcode::LDOBJBYNAME_IMM16_ID16:
278 case BytecodeInstruction::Opcode::STOBJBYNAME_IMM8_ID16_V8:
279 case BytecodeInstruction::Opcode::STOBJBYNAME_IMM16_ID16_V8:
280 case BytecodeInstruction::Opcode::LDSUPERBYNAME_IMM8_ID16:
281 case BytecodeInstruction::Opcode::LDSUPERBYNAME_IMM16_ID16:
282 case BytecodeInstruction::Opcode::STSUPERBYNAME_IMM8_ID16_V8:
283 case BytecodeInstruction::Opcode::STSUPERBYNAME_IMM16_ID16_V8:
284 case BytecodeInstruction::Opcode::STGLOBALVAR_IMM16_ID16:
285 case BytecodeInstruction::Opcode::LDBIGINT_ID16: {
286 auto constantPoolIdx = bcIns.GetId().AsRawValue();
287 BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
288 RecordInfo(Type::STRING, itemData);
289 break;
290 }
291 case BytecodeInstruction::Opcode::DEFINEFUNC_IMM8_ID16_IMM8:
292 case BytecodeInstruction::Opcode::DEFINEFUNC_IMM16_ID16_IMM8:
293 case BytecodeInstruction::Opcode::DEFINEMETHOD_IMM8_ID16_IMM8:
294 case BytecodeInstruction::Opcode::DEFINEMETHOD_IMM16_ID16_IMM8: {
295 auto constantPoolIdx = bcIns.GetId().AsRawValue();
296 BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
297 RecordInfo(Type::METHOD, itemData);
298 break;
299 }
300 case BytecodeInstruction::Opcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
301 case BytecodeInstruction::Opcode::CREATEOBJECTWITHBUFFER_IMM16_ID16: {
302 auto constantPoolIdx = bcIns.GetId().AsRawValue();
303 BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
304 RecordInfo(Type::OBJECT_LITERAL, itemData);
305 break;
306 }
307 case BytecodeInstruction::Opcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
308 case BytecodeInstruction::Opcode::CREATEARRAYWITHBUFFER_IMM16_ID16: {
309 auto constantPoolIdx = bcIns.GetId().AsRawValue();
310 BaseSnapshotInfo::ItemData itemData = {recordName, constantPoolId, constantPoolIdx, methodOffset, bcIndex};
311 RecordInfo(Type::ARRAY_LITERAL, itemData);
312 break;
313 }
314 case BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8: {
315 auto methodCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM8_ID16_ID16_IMM16_V8, 0>()).AsRawValue();
316 BaseSnapshotInfo::ItemData methodItemData = {recordName, constantPoolId,
317 methodCPIdx, methodOffset, bcIndex};
318 RecordInfo(Type::METHOD, methodItemData);
319
320 auto literalCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM8_ID16_ID16_IMM16_V8, 1>()).AsRawValue();
321 BaseSnapshotInfo::ItemData literalItemData = {recordName, constantPoolId,
322 literalCPIdx, methodOffset, bcIndex, methodCPIdx};
323 RecordInfo(Type::CLASS_LITERAL, literalItemData);
324 break;
325 }
326 case BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8: {
327 auto methodCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM16_ID16_ID16_IMM16_V8, 0>()).AsRawValue();
328 BaseSnapshotInfo::ItemData methodItemData = {recordName, constantPoolId,
329 methodCPIdx, methodOffset, bcIndex};
330 RecordInfo(Type::METHOD, methodItemData);
331
332 auto literalCPIdx = (bcIns.GetId <BytecodeInstruction::Format::IMM16_ID16_ID16_IMM16_V8, 1>()).AsRawValue();
333 BaseSnapshotInfo::ItemData literalItemData = {recordName, constantPoolId,
334 literalCPIdx, methodOffset, bcIndex, methodCPIdx};
335 RecordInfo(Type::CLASS_LITERAL, literalItemData);
336 break;
337 }
338 default:
339 break;
340 }
341 }
342
StoreDataToGlobalData(SnapshotGlobalData & snapshotData,const std::set<uint32_t> & skippedMethods) const343 void SnapshotConstantPoolData::StoreDataToGlobalData(SnapshotGlobalData &snapshotData,
344 const std::set<uint32_t> &skippedMethods) const
345 {
346 for (auto &info : infos_) {
347 info->StoreDataToGlobalData(snapshotData, skippedMethods);
348 }
349 }
350 } // namespace panda::ecmascript
351