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