• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #ifndef ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H
17 #define ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H
18 
19 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/js_tagged_value-inl.h"
22 #include "ecmascript/jspandafile/class_info_extractor.h"
23 #include "ecmascript/jspandafile/class_literal.h"
24 #include "ecmascript/jspandafile/constpool_value.h"
25 #include "ecmascript/jspandafile/js_pandafile_manager.h"
26 #include "ecmascript/jspandafile/literal_data_extractor.h"
27 #include "ecmascript/module/js_module_manager.h"
28 #include "ecmascript/patch/quick_fix_manager.h"
29 #include "ecmascript/pgo_profiler/pgo_profiler.h"
30 
31 #include "libpandafile/class_data_accessor-inl.h"
32 #include "libpandafile/index_accessor.h"
33 
34 namespace panda {
35 namespace ecmascript {
36 class JSThread;
37 
38 class Program : public ECMAObject {
39 public:
40     DECL_CAST(Program)
41 
42     static constexpr size_t MAIN_FUNCTION_OFFSET = ECMAObject::SIZE;
43     ACCESSORS(MainFunction, MAIN_FUNCTION_OFFSET, SIZE)
44 
45     DECL_VISIT_OBJECT(MAIN_FUNCTION_OFFSET, SIZE)
46     DECL_DUMP()
47 };
48 
49 /*                  ConstantPool
50  *      +--------------------------------+----
51  *      |             cache              |  ^
52  *      |              ...               |  |
53  *      |        string(EcmaString)      |  |
54  *      |        method(Method)          |cacheLength
55  *      |     array literal(JSArray)     |  |
56  *      |    object literal(JSObject)    |  |
57  *      |   class literal(ClassLiteral)  |  v
58  *      +--------------------------------+----
59  *      |           IndexHeader          |
60  *      +--------------------------------+
61  *      |           JSPandaFile          |
62  *      +--------------------------------+
63  */
64 class ConstantPool : public TaggedArray {
65 public:
66     static constexpr size_t JS_PANDA_FILE_INDEX = 1;
67     static constexpr size_t INDEX_HEADER_INDEX = 2;
68     static constexpr size_t RESERVED_POOL_LENGTH = INDEX_HEADER_INDEX;
69 
Cast(TaggedObject * object)70     static ConstantPool *Cast(TaggedObject *object)
71     {
72         ASSERT(JSTaggedValue(object).IsConstantPool());
73         return static_cast<ConstantPool *>(object);
74     }
75 
CreateConstPool(EcmaVM * vm,const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)76     static JSHandle<ConstantPool> CreateConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile,
77                                                   panda_file::File::EntityId id)
78     {
79         const panda_file::File::IndexHeader *mainIndex = jsPandaFile->GetPandaFile()->GetIndexHeader(id);
80         LOG_ECMA_IF(mainIndex == nullptr, FATAL) << "Unknown methodId: " << id.GetOffset();
81         auto constpoolSize = mainIndex->method_idx_size;
82 
83         JSHandle<ConstantPool> constpool(vm->GetJSThread(), JSTaggedValue::Hole());
84         bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
85         if (isLoadedAOT) {
86 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
87             panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id);
88             int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
89             constpool = GetDeserializedConstantPool(vm, jsPandaFile, index);
90 #else
91             LOG_FULL(FATAL) << "Aot don't support Windows and MacOS platform";
92             UNREACHABLE();
93 #endif
94         }
95         if (constpool.GetTaggedValue().IsHole()) {
96             ObjectFactory *factory = vm->GetFactory();
97             constpool = factory->NewConstantPool(constpoolSize);
98         }
99 
100         constpool->SetJSPandaFile(jsPandaFile);
101         constpool->SetIndexHeader(mainIndex);
102 
103         return constpool;
104     }
105 
GetEntityId(uint32_t index)106     panda_file::File::EntityId GetEntityId(uint32_t index) const
107     {
108         JSPandaFile *jsPandaFile = GetJSPandaFile();
109         panda_file::File::IndexHeader *indexHeader = GetIndexHeader();
110         Span<const panda_file::File::EntityId> indexs = jsPandaFile->GetMethodIndex(indexHeader);
111         return indexs[index];
112     }
113 
GetMethodIndexByEntityId(panda_file::File::EntityId entityId)114     int GetMethodIndexByEntityId(panda_file::File::EntityId entityId) const
115     {
116         JSPandaFile *jsPandaFile = GetJSPandaFile();
117         panda_file::File::IndexHeader *indexHeader = GetIndexHeader();
118         Span<const panda_file::File::EntityId> indexs = jsPandaFile->GetMethodIndex(indexHeader);
119         int size = static_cast<int>(indexs.size());
120         for (int i = 0; i < size; i++) {
121             if (indexs[i] == entityId) {
122                 return i;
123             }
124         }
125         return -1;
126     }
127 
SetIndexHeader(const panda_file::File::IndexHeader * indexHeader)128     inline void SetIndexHeader(const panda_file::File::IndexHeader *indexHeader)
129     {
130         Barriers::SetPrimitive(GetData(), GetIndexHeaderOffset(), indexHeader);
131     }
132 
GetIndexHeader()133     inline panda_file::File::IndexHeader *GetIndexHeader() const
134     {
135         return Barriers::GetValue<panda_file::File::IndexHeader *>(GetData(), GetIndexHeaderOffset());
136     }
137 
ComputeSize(uint32_t cacheSize)138     static size_t ComputeSize(uint32_t cacheSize)
139     {
140         return TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), cacheSize + RESERVED_POOL_LENGTH);
141     }
142 
143     inline void InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t capacity, uint32_t extraLength = 0)
144     {
145         ASSERT(initValue.IsSpecial());
146         SetLength(capacity + RESERVED_POOL_LENGTH);
147         SetExtraLength(extraLength);
148         for (uint32_t i = 0; i < capacity; i++) {
149             size_t offset = JSTaggedValue::TaggedTypeSize() * i;
150             Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData());
151         }
152         SetJSPandaFile(nullptr);
153         SetIndexHeader(nullptr);
154     }
155 
GetCacheLength()156     inline uint32_t GetCacheLength() const
157     {
158         return GetLength() - RESERVED_POOL_LENGTH;
159     }
160 
SetJSPandaFile(const void * jsPandaFile)161     inline void SetJSPandaFile(const void *jsPandaFile)
162     {
163         Barriers::SetPrimitive(GetData(), GetJSPandaFileOffset(), jsPandaFile);
164     }
165 
GetJSPandaFile()166     inline JSPandaFile *GetJSPandaFile() const
167     {
168         return Barriers::GetValue<JSPandaFile *>(GetData(), GetJSPandaFileOffset());
169     }
170 
SetObjectToCache(JSThread * thread,uint32_t index,JSTaggedValue value)171     inline void SetObjectToCache(JSThread *thread, uint32_t index, JSTaggedValue value)
172     {
173         Set(thread, index, value);
174     }
175 
GetObjectFromCache(uint32_t index)176     inline JSTaggedValue GetObjectFromCache(uint32_t index) const
177     {
178         return Get(index);
179     }
180 
GetMethodFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index)181     static JSTaggedValue GetMethodFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index)
182     {
183         const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
184         auto val = taggedPool->GetObjectFromCache(index);
185         JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
186 
187         // For AOT
188         bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
189         bool hasEntryIndex = false;
190         uint32_t entryIndex = 0;
191         if (isLoadedAOT && val.IsInt()) {
192             entryIndex = static_cast<uint32_t>(val.GetInt());
193             hasEntryIndex = true;
194             val = JSTaggedValue::Hole();
195         }
196 
197         if (!val.IsHole()) {
198             return val;
199         }
200 
201         [[maybe_unused]] EcmaHandleScope handleScope(thread);
202         ASSERT(jsPandaFile->IsNewVersion());
203         JSHandle<ConstantPool> constpoolHandle(thread, constpool);
204         EcmaVM *vm = thread->GetEcmaVM();
205 
206         EntityId id = constpoolHandle->GetEntityId(index);
207         MethodLiteral *methodLiteral = jsPandaFile->FindMethodLiteral(id.GetOffset());
208         ASSERT(methodLiteral != nullptr);
209         ObjectFactory *factory = vm->GetFactory();
210         JSHandle<Method> method = factory->NewMethod(jsPandaFile, methodLiteral, constpoolHandle,
211                                                      entryIndex, isLoadedAOT && hasEntryIndex);
212         constpoolHandle->SetObjectToCache(thread, index, method.GetTaggedValue());
213         return method.GetTaggedValue();
214     }
215 
GetClassLiteralFromCache(JSThread * thread,JSHandle<ConstantPool> constpool,uint32_t literal,CString entry)216     static JSTaggedValue GetClassLiteralFromCache(JSThread *thread, JSHandle<ConstantPool> constpool,
217                                                   uint32_t literal, CString entry)
218     {
219         [[maybe_unused]] EcmaHandleScope handleScope(thread);
220         auto val = constpool->GetObjectFromCache(literal);
221         JSPandaFile *jsPandaFile = constpool->GetJSPandaFile();
222 
223         // For AOT
224         bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
225         JSHandle<AOTLiteralInfo> entryIndexes(thread, JSTaggedValue::Undefined());
226         if (isLoadedAOT && val.IsAOTLiteralInfo()) {
227             entryIndexes = JSHandle<AOTLiteralInfo>(thread, val);
228             val = JSTaggedValue::Hole();
229         }
230 
231         if (val.IsHole()) {
232             EcmaVM *vm = thread->GetEcmaVM();
233             ObjectFactory *factory = vm->GetFactory();
234             ASSERT(jsPandaFile->IsNewVersion());
235             panda_file::File::EntityId literalId = constpool->GetEntityId(literal);
236             bool needSetAotFlag = isLoadedAOT && !entryIndexes.GetTaggedValue().IsUndefined();
237             JSHandle<TaggedArray> literalArray = LiteralDataExtractor::GetDatasIgnoreType(
238                 thread, jsPandaFile, literalId, constpool, entry, needSetAotFlag, entryIndexes);
239             JSHandle<ClassLiteral> classLiteral = factory->NewClassLiteral();
240             classLiteral->SetArray(thread, literalArray);
241             val = classLiteral.GetTaggedValue();
242             constpool->SetObjectToCache(thread, literal, val);
243         }
244 
245         return val;
246     }
247 
248     template <ConstPoolType type>
GetLiteralFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index,CString entry)249     static JSTaggedValue GetLiteralFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index, CString entry)
250     {
251         static_assert(type == ConstPoolType::OBJECT_LITERAL || type == ConstPoolType::ARRAY_LITERAL);
252         [[maybe_unused]] EcmaHandleScope handleScope(thread);
253         const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
254         auto val = taggedPool->GetObjectFromCache(index);
255         JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
256 
257         // For AOT
258         bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
259         JSHandle<AOTLiteralInfo> entryIndexes(thread, JSTaggedValue::Undefined());
260         if (isLoadedAOT && val.IsAOTLiteralInfo()) {
261             entryIndexes = JSHandle<AOTLiteralInfo>(thread, val);
262             val = JSTaggedValue::Hole();
263         }
264 
265         if (val.IsHole()) {
266             JSHandle<ConstantPool> constpoolHandle(thread, constpool);
267 
268             ASSERT(jsPandaFile->IsNewVersion());
269             panda_file::File::EntityId id = taggedPool->GetEntityId(index);
270             bool needSetAotFlag = isLoadedAOT && !entryIndexes.GetTaggedValue().IsUndefined();
271             // New inst
272             switch (type) {
273                 case ConstPoolType::OBJECT_LITERAL: {
274                     JSMutableHandle<TaggedArray> elements(thread, JSTaggedValue::Undefined());
275                     JSMutableHandle<TaggedArray> properties(thread, JSTaggedValue::Undefined());
276                     LiteralDataExtractor::ExtractObjectDatas(thread, jsPandaFile, id, elements,
277                         properties, constpoolHandle, entry, needSetAotFlag, entryIndexes);
278                     JSTaggedValue ihcVal = JSTaggedValue::Undefined();
279                     if (needSetAotFlag) {
280                         ihcVal = entryIndexes->GetIhc();
281                     }
282                     JSHandle<JSObject> obj = JSObject::CreateObjectFromProperties(thread, properties, ihcVal);
283                     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
284                     JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
285                     size_t elementsLen = elements->GetLength();
286                     for (size_t i = 0; i < elementsLen; i += 2) {  // 2: Each literal buffer has a pair of key-value.
287                         key.Update(elements->Get(i));
288                         if (key->IsHole()) {
289                             break;
290                         }
291                         valueHandle.Update(elements->Get(i + 1));
292                         JSObject::DefinePropertyByLiteral(thread, obj, key, valueHandle);
293                     }
294 
295                     val = obj.GetTaggedValue();
296                     break;
297                 }
298                 case ConstPoolType::ARRAY_LITERAL: {
299                     JSHandle<TaggedArray> literal = LiteralDataExtractor::GetDatasIgnoreType(thread, jsPandaFile, id,
300                         constpoolHandle, entry, needSetAotFlag, entryIndexes);
301                     uint32_t length = literal->GetLength();
302                     JSHandle<JSArray> arr(JSArray::ArrayCreate(thread, JSTaggedNumber(length), ArrayMode::LITERAL));
303                     arr->SetElements(thread, literal);
304                     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
305                         JSHClass::TransitToElementsKind(thread, arr);
306                     }
307                     val = arr.GetTaggedValue();
308                     break;
309                 }
310                 default:
311                     LOG_FULL(FATAL) << "Unknown type: " << static_cast<uint8_t>(type);
312                     UNREACHABLE();
313             }
314             constpoolHandle->SetObjectToCache(thread, index, val);
315         }
316 
317         return val;
318     }
319 
GetIdFromCache(JSTaggedValue constpool,uint32_t index)320     static panda_file::File::EntityId GetIdFromCache(JSTaggedValue constpool, uint32_t index)
321     {
322         const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
323         panda_file::File::EntityId id = taggedPool->GetEntityId(index);
324         return id;
325     }
326 
327     template <ConstPoolType type>
GetLiteralFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index,JSTaggedValue module)328     static JSTaggedValue GetLiteralFromCache(JSThread *thread, JSTaggedValue constpool,
329                                              uint32_t index, JSTaggedValue module)
330     {
331         CString entry = ModuleManager::GetRecordName(module);
332         return GetLiteralFromCache<type>(thread, constpool, index, entry);
333     }
334 
GetStringFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index)335     static JSTaggedValue PUBLIC_API GetStringFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index)
336     {
337         const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
338         auto val = taggedPool->Get(index);
339         if (val.IsHole()) {
340             [[maybe_unused]] EcmaHandleScope handleScope(thread);
341 
342             JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile();
343             panda_file::File::EntityId id = taggedPool->GetEntityId(index);
344             auto foundStr = jsPandaFile->GetStringData(id);
345 
346             EcmaVM *vm = thread->GetEcmaVM();
347             ObjectFactory *factory = vm->GetFactory();
348             JSHandle<ConstantPool> constpoolHandle(thread, constpool);
349             auto string = factory->GetRawStringFromStringTable(foundStr, MemSpaceType::OLD_SPACE,
350                 jsPandaFile->IsFirstMergedAbc(), id.GetOffset());
351 
352             val = JSTaggedValue(string);
353             constpoolHandle->SetObjectToCache(thread, index, val);
354         }
355 
356         return val;
357     }
358 
359     DECL_VISIT_ARRAY(DATA_OFFSET, GetCacheLength());
360     DECL_VISIT_NATIVE_FIELD(GetLastOffset() - JSTaggedValue::TaggedTypeSize() * RESERVED_POOL_LENGTH, GetLastOffset());
361 
DECL_DUMP()362     DECL_DUMP()
363 
364 private:
365     inline size_t GetJSPandaFileOffset() const
366     {
367         return JSTaggedValue::TaggedTypeSize() * (GetLength() - JS_PANDA_FILE_INDEX);
368     }
369 
GetIndexHeaderOffset()370     inline size_t GetIndexHeaderOffset() const
371     {
372         return JSTaggedValue::TaggedTypeSize() * (GetLength() - INDEX_HEADER_INDEX);
373     }
374 
GetLastOffset()375     inline size_t GetLastOffset() const
376     {
377         return JSTaggedValue::TaggedTypeSize() * GetLength() + DATA_OFFSET;
378     }
379 
380     static JSHandle<ConstantPool> GetDeserializedConstantPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, int32_t cpID);
381 };
382 }  // namespace ecmascript
383 }  // namespace panda
384 #endif  // ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H
385