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