1 /* 2 * Copyright (c) 2021-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 #ifndef ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H 17 #define ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H 18 19 #include <atomic> 20 #include "ecmascript/compiler/aot_file/aot_file_manager.h" 21 #include "ecmascript/ecma_macros.h" 22 #include "ecmascript/global_env.h" 23 #include "ecmascript/js_array.h" 24 #include "ecmascript/js_tagged_value-inl.h" 25 #include "ecmascript/jspandafile/class_info_extractor.h" 26 #include "ecmascript/jspandafile/class_literal.h" 27 #include "ecmascript/jspandafile/constpool_value.h" 28 #include "ecmascript/jspandafile/js_pandafile_manager.h" 29 #include "ecmascript/jspandafile/literal_data_extractor.h" 30 #include "ecmascript/module/js_module_manager.h" 31 #include "ecmascript/module/js_shared_module.h" 32 #include "ecmascript/patch/quick_fix_manager.h" 33 #include "ecmascript/pgo_profiler/pgo_profiler.h" 34 #include "ecmascript/tagged_array-inl.h" 35 36 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" 37 #include "ecmascript/pgo_profiler/pgo_utils.h" 38 #include "libpandafile/class_data_accessor-inl.h" 39 #include "libpandafile/index_accessor.h" 40 41 namespace panda { 42 namespace ecmascript { 43 class JSThread; 44 45 class Program : public ECMAObject { 46 public: 47 DECL_CAST(Program) 48 49 static constexpr size_t MAIN_FUNCTION_OFFSET = ECMAObject::SIZE; 50 ACCESSORS(MainFunction, MAIN_FUNCTION_OFFSET, SIZE) 51 52 DECL_VISIT_OBJECT(MAIN_FUNCTION_OFFSET, SIZE) 53 DECL_DUMP() 54 }; 55 56 /* ConstantPool(TaggedArray) 57 * +--------------------------------+---------------------------------- 58 * | ... | ^ ^ ^ index 0 59 * | Method / AOTLiteralInfo / Int | | | | 60 * | String | | | | 61 * | Array Literal | ConstpoolLength | | 62 * | Class Literal | | | | 63 * | Object Literal | | | | 64 * | ... | v | | 65 * +--------------------------------+--------------- | | 66 * | ProtoTransTableInfo |PointerToIndexDic | | 67 * +--------------------------------+--------------- | | 68 * | AOTSymbolInfo |TaggedArray | | 69 * +--------------------------------+--------------- | | 70 * | unshared constpool index |int32_t CacheLength | 71 * +--------------------------------+--------------- | Length 72 * | shared constpool id |int32_t | | 73 * +--------------------------------+--------------- | | 74 * | AOTHClassInfo |TaggedArray | | 75 * +--------------------------------+--------------- | | 76 * | AOTArrayInfo |TaggedArray | | 77 * +--------------------------------+--------------- | | 78 * | constIndexInfo |TaggedArray v | 79 * +--------------------------------+-------------------------- | 80 * | IndexHeader | | 81 * +--------------------------------+ | 82 * | JSPandaFile | v index: Length-1 83 * +--------------------------------+----------------------------------- 84 */ 85 class ConstantPool : public TaggedArray { 86 public: 87 static constexpr size_t JS_PANDA_FILE_INDEX = 1; // not need gc 88 static constexpr size_t INDEX_HEADER_INDEX = 2; // not need gc 89 static constexpr size_t CONSTANT_INDEX_INFO_INDEX = 3; 90 static constexpr size_t AOT_ARRAY_INFO_INDEX = 4; 91 static constexpr size_t AOT_HCLASS_INFO_INDEX = 5; 92 static constexpr size_t UNSHARED_CONSTPOOL_INDEX = 6; 93 static constexpr size_t SHARED_CONSTPOOL_ID = 7; 94 static constexpr size_t AOT_SYMBOL_INFO_INDEX = 8; 95 static constexpr size_t PROTO_TRANS_TABLE_INFO_INDEX = 9; 96 static constexpr size_t RESERVED_POOL_LENGTH = INDEX_HEADER_INDEX; // divide the gc area 97 98 // AOTHClassInfo, AOTArrayInfo, ConstIndexInfo, unsharedConstpoolIndex, constpoolId, AOTSymbolInfo, 99 // ProtoTransTableInfo 100 static constexpr size_t EXTEND_DATA_NUM = 7; 101 102 static constexpr int32_t CONSTPOOL_TYPE_FLAG = INT32_MAX; // INT32_MAX : unshared constpool. 103 static constexpr int32_t CONSTPOOL_INVALID_ID = 0; 104 Cast(TaggedObject * object)105 static ConstantPool *Cast(TaggedObject *object) 106 { 107 ASSERT(JSTaggedValue(object).IsConstantPool()); 108 return static_cast<ConstantPool *>(object); 109 } 110 CreateUnSharedConstPool(EcmaVM * vm,const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)111 static JSHandle<ConstantPool> CreateUnSharedConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, 112 panda_file::File::EntityId id) 113 { 114 const panda_file::File::IndexHeader *mainIndex = jsPandaFile->GetPandaFile()->GetIndexHeader(id); 115 LOG_ECMA_IF(mainIndex == nullptr, FATAL) << "Unknown methodId: " << id.GetOffset(); 116 auto constpoolSize = mainIndex->method_idx_size; 117 118 JSHandle<JSTaggedValue> constpool(vm->GetJSThread(), JSTaggedValue::Hole()); 119 bool isLoadedAOT = jsPandaFile->IsLoadedAOT(); 120 if (isLoadedAOT) { 121 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) 122 panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id); 123 int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex()); 124 constpool = GetDeserializedConstantPool(vm, jsPandaFile, index); 125 #else 126 LOG_FULL(FATAL) << "Aot don't support Windows and MacOS platform"; 127 UNREACHABLE(); 128 #endif 129 } 130 JSHandle<ConstantPool> constpoolObj; 131 if (constpool.GetTaggedValue().IsHole()) { 132 ObjectFactory *factory = vm->GetFactory(); 133 constpoolObj = factory->NewConstantPool(constpoolSize); 134 } else { 135 constpoolObj = JSHandle<ConstantPool>(constpool); 136 } 137 138 constpoolObj->SetJSPandaFile(jsPandaFile); 139 constpoolObj->SetIndexHeader(mainIndex); 140 141 return constpoolObj; 142 } 143 CreateUnSharedConstPoolBySharedConstpool(EcmaVM * vm,const JSPandaFile * jsPandaFile,ConstantPool * shareCp)144 static JSHandle<ConstantPool> CreateUnSharedConstPoolBySharedConstpool( 145 EcmaVM *vm, const JSPandaFile *jsPandaFile, ConstantPool *shareCp) 146 { 147 const panda_file::File::IndexHeader *mainIndex = shareCp->GetIndexHeader(); 148 auto constpoolSize = mainIndex->method_idx_size; 149 150 JSHandle<JSTaggedValue> constpool(vm->GetJSThread(), JSTaggedValue::Hole()); 151 bool isLoadedAOT = jsPandaFile->IsLoadedAOT(); 152 if (isLoadedAOT) { 153 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) 154 int32_t cpId = shareCp->GetSharedConstpoolId().GetInt(); 155 constpool = GetDeserializedConstantPool(vm, jsPandaFile, cpId); 156 #else 157 LOG_FULL(FATAL) << "Aot don't support Windows and MacOS platform"; 158 UNREACHABLE(); 159 #endif 160 } 161 JSHandle<ConstantPool> constpoolObj; 162 if (constpool.GetTaggedValue().IsHole()) { 163 ObjectFactory *factory = vm->GetFactory(); 164 constpoolObj = factory->NewConstantPool(constpoolSize); 165 } else { 166 constpoolObj = JSHandle<ConstantPool>(constpool); 167 } 168 169 constpoolObj->SetJSPandaFile(jsPandaFile); 170 constpoolObj->SetIndexHeader(mainIndex); 171 172 return constpoolObj; 173 } 174 175 static JSHandle<ConstantPool> CreateSharedConstPool(EcmaVM *vm, const JSPandaFile *jsPandaFile, 176 panda_file::File::EntityId id, 177 int32_t cpId = 0) 178 { 179 const panda_file::File::IndexHeader *mainIndex = jsPandaFile->GetPandaFile()->GetIndexHeader(id); 180 LOG_ECMA_IF(mainIndex == nullptr, FATAL) << "Unknown methodId: " << id.GetOffset(); 181 auto constpoolSize = mainIndex->method_idx_size; 182 183 JSHandle<ConstantPool> constpool(vm->GetJSThread(), JSTaggedValue::Hole()); 184 if (constpool.GetTaggedValue().IsHole()) { 185 ObjectFactory *factory = vm->GetFactory(); 186 constpool = factory->NewSConstantPool(constpoolSize); 187 } 188 189 constpool->SetJSPandaFile(jsPandaFile); 190 constpool->SetIndexHeader(mainIndex); 191 constpool->SetUnsharedConstpoolIndex(JSTaggedValue(0)); 192 constpool->SetSharedConstpoolId(JSTaggedValue(cpId)); 193 194 return constpool; 195 } 196 IsAotSymbolInfoExist(JSHandle<TaggedArray> symbolInfo,JSTaggedValue symbol)197 static bool IsAotSymbolInfoExist(JSHandle<TaggedArray> symbolInfo, JSTaggedValue symbol) 198 { 199 return symbolInfo->GetLength() > 0 && !symbol.IsHole(); 200 } 201 202 static JSHandle<ConstantPool> CreateSharedConstPoolForAOT( 203 EcmaVM *vm, JSHandle<ConstantPool> constpool, int32_t cpId = 0) 204 { 205 JSHandle<ConstantPool> sconstpool(vm->GetJSThread(), JSTaggedValue::Hole()); 206 uint32_t capacity = constpool->GetConstpoolLength(); 207 if (sconstpool.GetTaggedValue().IsHole()) { 208 ObjectFactory *factory = vm->GetFactory(); 209 sconstpool = factory->NewSConstantPool(capacity); 210 } 211 JSThread *thread = vm->GetJSThread(); 212 for (uint32_t i = 0; i < capacity; i++) { 213 JSTaggedValue val = constpool->GetObjectFromCache(thread, i); 214 if (val.IsString()) { 215 sconstpool->SetObjectToCache(thread, i, val); 216 } else if (IsAotMethodLiteralInfo(val)) { 217 JSHandle<AOTLiteralInfo> valHandle(thread, val); 218 JSHandle<AOTLiteralInfo> methodLiteral = CopySharedMethodAOTLiteralInfo(vm, valHandle); 219 sconstpool->SetObjectToCache(thread, i, methodLiteral.GetTaggedValue()); 220 } else if (val.IsInt()) { 221 // Here is to copy methodCodeEntry which does not have ihc infos from aot. 222 sconstpool->SetObjectToCache(thread, i, val); 223 } 224 } 225 226 JSHandle<TaggedArray> array(thread->GlobalConstants()->GetHandledEmptyArray()); 227 sconstpool->SetAotSymbolInfo(thread, array.GetTaggedValue()); 228 sconstpool->SetProtoTransTableInfo(thread, JSTaggedValue::Undefined()); 229 sconstpool->SetAotHClassInfo(thread, array.GetTaggedValue()); 230 sconstpool->SetAotArrayInfo(thread, array.GetTaggedValue()); 231 sconstpool->SetConstantIndexInfo(thread, array.GetTaggedValue()); 232 sconstpool->SetJSPandaFile(constpool->GetJSPandaFile()); 233 sconstpool->SetIndexHeader(constpool->GetIndexHeader()); 234 sconstpool->SetUnsharedConstpoolIndex(JSTaggedValue(0)); 235 sconstpool->SetSharedConstpoolId(JSTaggedValue(cpId)); 236 return sconstpool; 237 } 238 CopySharedMethodAOTLiteralInfo(EcmaVM * vm,JSHandle<AOTLiteralInfo> src)239 static JSHandle<AOTLiteralInfo> CopySharedMethodAOTLiteralInfo(EcmaVM *vm, 240 JSHandle<AOTLiteralInfo> src) 241 { 242 JSThread *thread = vm->GetJSThread(); 243 ObjectFactory *factory = vm->GetFactory(); 244 JSHandle<AOTLiteralInfo> dst = factory->NewSAOTLiteralInfo(1); 245 for (uint32_t i = 0; i < src->GetCacheLength(); i++) { 246 JSTaggedValue val = src->GetObjectFromCache(thread, i); 247 ASSERT(!val.IsHeapObject() || val.IsJSShared()); 248 dst->SetObjectToCache(thread, i, val); 249 } 250 dst->SetLiteralType(JSTaggedValue(src->GetLiteralType())); 251 return dst; 252 } 253 CheckUnsharedConstpool(JSTaggedValue constpool)254 static bool CheckUnsharedConstpool(JSTaggedValue constpool) 255 { 256 int32_t index = ConstantPool::Cast(constpool.GetTaggedObject())->GetUnsharedConstpoolIndex(); 257 if (index == CONSTPOOL_TYPE_FLAG) { 258 return true; 259 } 260 return false; 261 } 262 SetUnsharedConstpoolIndex(const JSTaggedValue index)263 inline void SetUnsharedConstpoolIndex(const JSTaggedValue index) 264 { 265 Barriers::SetPrimitive(GetData(), GetUnsharedConstpoolIndexOffset(), index); 266 } 267 GetUnsharedConstpoolIndex()268 inline int32_t GetUnsharedConstpoolIndex() const 269 { 270 return Barriers::GetPrimitive<JSTaggedValue>(GetData(), GetUnsharedConstpoolIndexOffset()).GetInt(); 271 } 272 SetSharedConstpoolId(const JSTaggedValue index)273 inline void SetSharedConstpoolId(const JSTaggedValue index) 274 { 275 Barriers::SetPrimitive(GetData(), GetSharedConstpoolIdOffset(), index); 276 } 277 GetSharedConstpoolId()278 inline JSTaggedValue GetSharedConstpoolId() const 279 { 280 return JSTaggedValue(Barriers::GetPrimitive<JSTaggedValue>(GetData(), GetSharedConstpoolIdOffset())); 281 } 282 GetEntityId(uint32_t index)283 panda_file::File::EntityId GetEntityId(uint32_t index) const 284 { 285 JSPandaFile *jsPandaFile = GetJSPandaFile(); 286 panda_file::File::IndexHeader *indexHeader = GetIndexHeader(); 287 Span<const panda_file::File::EntityId> indexs = jsPandaFile->GetMethodIndex(indexHeader); 288 return indexs[index]; 289 } 290 GetMethodIndexByEntityId(panda_file::File::EntityId entityId)291 int GetMethodIndexByEntityId(panda_file::File::EntityId entityId) const 292 { 293 JSPandaFile *jsPandaFile = GetJSPandaFile(); 294 panda_file::File::IndexHeader *indexHeader = GetIndexHeader(); 295 Span<const panda_file::File::EntityId> indexs = jsPandaFile->GetMethodIndex(indexHeader); 296 int size = static_cast<int>(indexs.size()); 297 for (int i = 0; i < size; i++) { 298 if (indexs[i] == entityId) { 299 return i; 300 } 301 } 302 return -1; 303 } 304 SetIndexHeader(const panda_file::File::IndexHeader * indexHeader)305 inline void SetIndexHeader(const panda_file::File::IndexHeader *indexHeader) 306 { 307 Barriers::SetPrimitive(GetData(), GetIndexHeaderOffset(), indexHeader); 308 } 309 GetIndexHeader()310 inline panda_file::File::IndexHeader *GetIndexHeader() const 311 { 312 return Barriers::GetPrimitive<panda_file::File::IndexHeader *>(GetData(), GetIndexHeaderOffset()); 313 } 314 ComputeSize(uint32_t cacheSize)315 static size_t ComputeSize(uint32_t cacheSize) 316 { 317 return TaggedArray::ComputeSize( 318 JSTaggedValue::TaggedTypeSize(), cacheSize + EXTEND_DATA_NUM + RESERVED_POOL_LENGTH); 319 } 320 321 void InitializeWithSpecialValue(JSThread *thread, JSTaggedValue initValue, 322 uint32_t capacity, uint32_t extraLength = 0) 323 { 324 ASSERT(initValue.IsSpecial()); 325 SetLength(capacity + EXTEND_DATA_NUM + RESERVED_POOL_LENGTH); 326 SetExtraLength(extraLength); 327 for (uint32_t i = 0; i < capacity; i++) { 328 size_t offset = JSTaggedValue::TaggedTypeSize() * i; 329 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData()); 330 } 331 JSHandle<TaggedArray> array(thread->GlobalConstants()->GetHandledEmptyArray()); 332 SetAotSymbolInfo(thread, array.GetTaggedValue()); 333 SetProtoTransTableInfo(thread, JSTaggedValue::Undefined()); 334 SetAotHClassInfo(thread, array.GetTaggedValue()); 335 SetAotArrayInfo(thread, array.GetTaggedValue()); 336 SetConstantIndexInfo(thread, array.GetTaggedValue()); 337 SetJSPandaFile(nullptr); 338 SetIndexHeader(nullptr); 339 SetUnsharedConstpoolIndex(JSTaggedValue(CONSTPOOL_TYPE_FLAG)); 340 SetSharedConstpoolId(JSTaggedValue(CONSTPOOL_INVALID_ID)); 341 } 342 GetCacheLength()343 inline uint32_t GetCacheLength() const 344 { 345 return GetLength() - RESERVED_POOL_LENGTH; 346 } 347 GetConstpoolLength()348 inline uint32_t GetConstpoolLength() const 349 { 350 return GetLength() - RESERVED_POOL_LENGTH - EXTEND_DATA_NUM; 351 } 352 SetJSPandaFile(const void * jsPandaFile)353 inline void SetJSPandaFile(const void *jsPandaFile) 354 { 355 Barriers::SetPrimitive(GetData(), GetJSPandaFileOffset(), jsPandaFile); 356 } 357 GetJSPandaFile()358 inline JSPandaFile *GetJSPandaFile() const 359 { 360 return Barriers::GetPrimitive<JSPandaFile *>(GetData(), GetJSPandaFileOffset()); 361 } 362 InitConstantPoolTail(const JSThread * thread,JSHandle<ConstantPool> constPool)363 inline void InitConstantPoolTail(const JSThread *thread, JSHandle<ConstantPool> constPool) 364 { 365 SetAotArrayInfo(thread, constPool->GetAotArrayInfo(thread)); 366 SetAotHClassInfo(thread, constPool->GetAotHClassInfo(thread)); 367 SetConstantIndexInfo(thread, constPool->GetConstantIndexInfo(thread)); 368 SetAotSymbolInfo(thread, constPool->GetAotSymbolInfo(thread)); 369 SetProtoTransTableInfo(thread, constPool->GetProtoTransTableInfo(thread)); 370 } 371 SetConstantIndexInfo(const JSThread * thread,JSTaggedValue info)372 inline void SetConstantIndexInfo(const JSThread *thread, JSTaggedValue info) 373 { 374 Set(thread, (GetLength() - CONSTANT_INDEX_INFO_INDEX), info); 375 } 376 GetConstantIndexInfo(const JSThread * thread)377 inline JSTaggedValue GetConstantIndexInfo(const JSThread *thread) const 378 { 379 return JSTaggedValue(Barriers::GetTaggedValue(thread, GetData(), GetConstantIndexInfoOffset())); 380 } 381 SetAotArrayInfo(const JSThread * thread,JSTaggedValue info)382 inline void SetAotArrayInfo(const JSThread *thread, JSTaggedValue info) 383 { 384 Set(thread, (GetLength() - AOT_ARRAY_INFO_INDEX), info); 385 } 386 GetAotArrayInfo(const JSThread * thread)387 inline JSTaggedValue GetAotArrayInfo(const JSThread *thread) const 388 { 389 return JSTaggedValue(Barriers::GetTaggedValue(thread, GetData(), GetAotArrayInfoOffset())); 390 } 391 GetAotSymbolInfo(const JSThread * thread)392 inline JSTaggedValue GetAotSymbolInfo(const JSThread *thread) const 393 { 394 return JSTaggedValue(Barriers::GetTaggedValue(thread, GetData(), GetAotSymbolInfoOffset())); 395 } 396 GetProtoTransTableInfo(const JSThread * thread)397 inline JSTaggedValue GetProtoTransTableInfo(const JSThread *thread) const 398 { 399 return JSTaggedValue(Barriers::GetTaggedValue(thread, GetData(), GetProtoTransTableInfoOffset())); 400 } 401 GetSymbolFromSymbolInfo(const JSThread * thread,JSHandle<TaggedArray> symbolInfoHandler,uint64_t id)402 static JSTaggedValue GetSymbolFromSymbolInfo(const JSThread *thread, JSHandle<TaggedArray> symbolInfoHandler, 403 uint64_t id) 404 { 405 uint32_t len = symbolInfoHandler->GetLength(); 406 for (uint32_t j = 0; j < len; j += 2) { // 2: symbolId, symbol 407 ASSERT(j + 1 < len); 408 uint64_t symbolId = symbolInfoHandler->Get(thread, j).GetRawData(); 409 if (symbolId == id) { 410 return symbolInfoHandler->Get(thread, j + 1); 411 } 412 } 413 return JSTaggedValue::Hole(); 414 } 415 GetSymbolFromSymbolInfo(const JSThread * thread,JSTaggedValue symbolInfo,uint64_t id)416 static JSTaggedValue GetSymbolFromSymbolInfo(const JSThread *thread, JSTaggedValue symbolInfo, uint64_t id) 417 { 418 TaggedArray* info = TaggedArray::Cast(symbolInfo.GetTaggedObject()); 419 uint32_t len = info->GetLength(); 420 for (uint32_t j = 0; j < len; j += 2) { // 2: symbolId, symbol 421 ASSERT(j + 1 < len); 422 uint64_t symbolId = info->Get(thread, j).GetRawData(); 423 if (symbolId == id) { 424 return info->Get(thread, j + 1); 425 } 426 } 427 return JSTaggedValue::Hole(); 428 } 429 SetAotHClassInfo(const JSThread * thread,JSTaggedValue info)430 inline void SetAotHClassInfo(const JSThread *thread, JSTaggedValue info) 431 { 432 Set(thread, (GetLength() - AOT_HCLASS_INFO_INDEX), info); 433 } 434 GetAotHClassInfo(const JSThread * thread)435 inline JSTaggedValue GetAotHClassInfo(const JSThread *thread) const 436 { 437 return JSTaggedValue(Barriers::GetTaggedValue(thread, GetData(), GetAotHClassInfoOffset())); 438 } 439 SetAotSymbolInfo(const JSThread * thread,JSTaggedValue info)440 inline void SetAotSymbolInfo(const JSThread *thread, JSTaggedValue info) 441 { 442 Set(thread, (GetLength() - AOT_SYMBOL_INFO_INDEX), info); 443 } 444 SetProtoTransTableInfo(const JSThread * thread,JSTaggedValue info)445 inline void SetProtoTransTableInfo(const JSThread *thread, JSTaggedValue info) 446 { 447 Set(thread, (GetLength() - PROTO_TRANS_TABLE_INFO_INDEX), info); 448 } 449 SetObjectToCache(JSThread * thread,uint32_t index,JSTaggedValue value)450 inline void SetObjectToCache(JSThread *thread, uint32_t index, JSTaggedValue value) 451 { 452 Set(thread, index, value); 453 } 454 CASSetObjectToCache(JSThread * thread,const JSTaggedValue constpool,uint32_t index,JSTaggedValue value)455 static void CASSetObjectToCache( 456 JSThread *thread, const JSTaggedValue constpool, uint32_t index, JSTaggedValue value) 457 { 458 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); 459 JSHandle<ConstantPool> constpoolHandle(thread, constpool); 460 std::atomic<JSTaggedValue> *atomicVal = reinterpret_cast<std::atomic<JSTaggedValue> *>( 461 reinterpret_cast<uintptr_t>(taggedPool) + DATA_OFFSET + index * JSTaggedValue::TaggedTypeSize()); 462 JSTaggedValue tempVal = taggedPool->GetObjectFromCache(thread, index); 463 JSTaggedValue expected = IsLoadingAOTMethodInfo(taggedPool->GetJSPandaFile(), tempVal) ? tempVal : 464 JSTaggedValue::Hole(); 465 JSTaggedValue desired = value; 466 if (std::atomic_compare_exchange_strong_explicit(atomicVal, &expected, desired, 467 std::memory_order_release, std::memory_order_relaxed)) { 468 // set val by Barrier. 469 constpoolHandle->SetObjectToCache(thread, index, value); 470 } 471 } 472 GetObjectFromCache(const JSThread * thread,uint32_t index)473 inline JSTaggedValue GetObjectFromCache(const JSThread *thread, uint32_t index) const 474 { 475 return Get(thread, index); 476 } 477 GetMethodFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index)478 static JSTaggedValue GetMethodFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index) 479 { 480 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); 481 auto val = taggedPool->GetObjectFromCache(thread, index); 482 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile(); 483 484 // For AOT 485 bool isLoadedAOT = jsPandaFile->IsLoadedAOT(); 486 bool hasEntryIndex = false; 487 uint32_t entryIndex = 0; 488 if (IsLoadingAOTMethodInfo(jsPandaFile, val)) { 489 int entryIndexVal = 0; // 0: only one method 490 if (val.IsInt()) { 491 // For MethodInfo which does not have ihc infos, we store codeEntry directly. 492 entryIndexVal = val.GetInt(); 493 } else { 494 JSHandle<AOTLiteralInfo> entryIndexes(thread, val); 495 entryIndexVal = entryIndexes->GetObjectFromCache(thread, 0).GetInt(); // 0: only one method 496 } 497 if (entryIndexVal != static_cast<int>(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE)) { 498 hasEntryIndex = true; 499 entryIndex = static_cast<uint32_t>(entryIndexVal); 500 } 501 val = JSTaggedValue::Hole(); 502 } 503 504 if (!val.IsHole()) { 505 return val; 506 } 507 508 if (!taggedPool->GetJSPandaFile()->IsNewVersion()) { 509 JSTaggedValue unsharedCp = thread->GetEcmaVM()->FindOrCreateUnsharedConstpool(constpool); 510 taggedPool = ConstantPool::Cast(unsharedCp.GetTaggedObject()); 511 return taggedPool->Get(thread, index); 512 } 513 514 [[maybe_unused]] EcmaHandleScope handleScope(thread); 515 ASSERT(jsPandaFile->IsNewVersion()); 516 JSHandle<ConstantPool> constpoolHandle(thread, constpool); 517 EcmaVM *vm = thread->GetEcmaVM(); 518 519 EntityId id = constpoolHandle->GetEntityId(index); 520 MethodLiteral *methodLiteral = jsPandaFile->FindMethodLiteral(id.GetOffset()); 521 CHECK_INPUT_NULLPTR(methodLiteral, 522 "GetMethodFromCache:methodLiteral is nullptr, offset: " + std::to_string(id.GetOffset())); 523 ObjectFactory *factory = vm->GetFactory(); 524 JSHandle<Method> method = factory->NewSMethod( 525 jsPandaFile, methodLiteral, constpoolHandle, entryIndex, isLoadedAOT && hasEntryIndex); 526 527 CASSetObjectToCache(thread, constpoolHandle.GetTaggedValue(), index, method.GetTaggedValue()); 528 return method.GetTaggedValue(); 529 } 530 531 static JSTaggedValue PUBLIC_API GetMethodFromCache(JSTaggedValue constpool, uint32_t index, JSThread *thread); 532 533 static void PUBLIC_API UpdateConstpoolWhenDeserialAI(EcmaVM *vm, JSHandle<ConstantPool> aiCP, 534 JSHandle<ConstantPool> sharedCP, JSHandle<ConstantPool> unsharedCP); 535 536 static bool PUBLIC_API IsAotMethodLiteralInfo(JSTaggedValue literalInfo); 537 static JSTaggedValue PUBLIC_API GetIhcFromAOTLiteralInfo(JSThread *thread, JSTaggedValue constpool, uint32_t index); 538 539 static JSTaggedValue GetClassLiteralFromCache(JSThread *thread, JSHandle<ConstantPool> constpool, 540 uint32_t literal, CString entry, JSHandle<JSTaggedValue> sendableEnv = JSHandle<JSTaggedValue>(), 541 ClassKind kind = ClassKind::NON_SENDABLE); 542 543 static JSHandle<TaggedArray> GetFieldLiteral(JSThread *thread, JSHandle<ConstantPool> constpool, 544 uint32_t literal, CString entry); 545 546 template <ConstPoolType type> GetLiteralFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index,CString entry)547 static JSTaggedValue GetLiteralFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index, CString entry) 548 { 549 static_assert(type == ConstPoolType::OBJECT_LITERAL || type == ConstPoolType::ARRAY_LITERAL); 550 [[maybe_unused]] EcmaHandleScope handleScope(thread); 551 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); 552 auto val = taggedPool->GetObjectFromCache(thread, index); 553 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile(); 554 555 // For AOT 556 bool isLoadedAOT = jsPandaFile->IsLoadedAOT(); 557 JSHandle<AOTLiteralInfo> entryIndexes(thread, JSTaggedValue::Undefined()); 558 if (isLoadedAOT && val.IsAOTLiteralInfo()) { 559 entryIndexes = JSHandle<AOTLiteralInfo>(thread, val); 560 val = JSTaggedValue::Hole(); 561 } 562 563 if (val.IsHole()) { 564 JSHandle<ConstantPool> constpoolHandle(thread, constpool); 565 566 ASSERT(jsPandaFile->IsNewVersion()); 567 panda_file::File::EntityId id = taggedPool->GetEntityId(index); 568 bool needSetAotFlag = isLoadedAOT && !entryIndexes.GetTaggedValue().IsUndefined(); 569 // New inst 570 switch (type) { 571 case ConstPoolType::OBJECT_LITERAL: { 572 JSMutableHandle<TaggedArray> elements(thread, JSTaggedValue::Undefined()); 573 JSMutableHandle<TaggedArray> properties(thread, JSTaggedValue::Undefined()); 574 LiteralDataExtractor::ExtractObjectDatas(thread, jsPandaFile, id, elements, 575 properties, constpoolHandle, entry, needSetAotFlag, entryIndexes); 576 JSTaggedValue ihcVal = JSTaggedValue::Undefined(); 577 if (needSetAotFlag) { 578 ihcVal = entryIndexes->GetIhc(thread); 579 if (!ihcVal.IsUndefined()) { 580 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv(); 581 JSHClass::Cast(ihcVal.GetTaggedObject())->SetPrototype(thread, 582 env->GetObjectFunctionPrototype()); 583 JSHClass::EnableProtoChangeMarker(thread, JSHandle<JSHClass>(thread, ihcVal)); 584 } 585 } 586 JSHandle<JSObject> obj = JSObject::CreateObjectFromProperties(thread, properties, ihcVal); 587 auto profiler = thread->GetEcmaVM()->GetPGOProfiler(); 588 profiler->RecordProfileType(obj->GetClass(), jsPandaFile, id.GetOffset()); 589 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 590 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined()); 591 size_t elementsLen = elements->GetLength(); 592 for (size_t i = 0; i < elementsLen; i += 2) { // 2: Each literal buffer has a pair of key-value. 593 key.Update(elements->Get(thread, i)); 594 if (key->IsHole()) { 595 break; 596 } 597 valueHandle.Update(elements->Get(thread, i + 1)); 598 JSObject::DefinePropertyByLiteral(thread, obj, key, valueHandle); 599 } 600 val = obj.GetTaggedValue(); 601 break; 602 } 603 case ConstPoolType::ARRAY_LITERAL: { 604 // literal fetching from AOT ArrayInfos 605 JSMutableHandle<TaggedArray> literal(thread, JSTaggedValue::Undefined()); 606 #if ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC 607 ElementsKind dataKind = ElementsKind::GENERIC; 608 #else 609 ElementsKind dataKind = ElementsKind::NONE; 610 #endif 611 literal.Update(LiteralDataExtractor::GetDatasIgnoreType(thread, jsPandaFile, id, 612 constpoolHandle, entry, 613 needSetAotFlag, entryIndexes, 614 &dataKind)); 615 uint32_t length = literal->GetLength(); 616 JSHandle<JSArray> arr(JSArray::ArrayCreate(thread, JSTaggedNumber(length), ArrayMode::LITERAL)); 617 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 618 arr->SetElements(thread, literal); 619 if (thread->GetEcmaVM()->IsEnablePGOProfiler() || thread->GetEcmaVM()->IsEnableElementsKind() || 620 thread->GetEcmaVM()->GetAOTFileManager()->IsEnableAOT()) { 621 // for all JSArray, the initial ElementsKind should be NONE 622 // Because AOT Stable Array Deopt check, we have support arrayLiteral elementskind 623 // If array is loaded from AOT, no need to do migration. 624 JSHandle<GlobalEnv> globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); 625 auto classIndex = static_cast<size_t>(GlobalEnvField::ELEMENT_NONE_HCLASS_INDEX); 626 auto hclassVal = globalEnv->GetGlobalEnvObjectByIndex(classIndex).GetTaggedValue(); 627 arr->SynchronizedTransitionClass(thread, JSHClass::Cast(hclassVal.GetTaggedObject())); 628 ElementsKind oldKind = arr->GetClass()->GetElementsKind(); 629 JSHClass::TransitToElementsKind(thread, arr, dataKind); 630 ElementsKind newKind = arr->GetClass()->GetElementsKind(); 631 JSHandle<JSObject> receiver(arr); 632 Elements::MigrateArrayWithKind(thread, receiver, oldKind, newKind); 633 } 634 val = arr.GetTaggedValue(); 635 break; 636 } 637 default: 638 LOG_FULL(FATAL) << "Unknown type: " << static_cast<uint8_t>(type); 639 UNREACHABLE(); 640 } 641 constpoolHandle->SetObjectToCache(thread, index, val); 642 } 643 644 return val; 645 } 646 647 template <ConstPoolType type> GetLiteralFromCacheNoScope(JSThread * thread,JSTaggedValue constpool,uint32_t index,CString entry)648 static JSTaggedValue GetLiteralFromCacheNoScope(JSThread *thread, JSTaggedValue constpool, 649 uint32_t index, [[maybe_unused]] CString entry) 650 { 651 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); 652 auto val = taggedPool->GetObjectFromCache(thread, index); 653 JSPandaFile *jsPandaFile = taggedPool->GetJSPandaFile(); 654 655 bool isLoadedAOT = jsPandaFile->IsLoadedAOT(); 656 if (isLoadedAOT && val.IsAOTLiteralInfo()) { 657 val = JSTaggedValue::Hole(); 658 } 659 return val.IsHole() ? JSTaggedValue::Undefined() : val; 660 } 661 GetIdFromCache(JSTaggedValue constpool,uint32_t index)662 static panda_file::File::EntityId GetIdFromCache(JSTaggedValue constpool, uint32_t index) 663 { 664 const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); 665 panda_file::File::EntityId id = taggedPool->GetEntityId(index); 666 return id; 667 } 668 669 template <ConstPoolType type> GetLiteralFromCache(JSThread * thread,JSTaggedValue constpool,uint32_t index,JSTaggedValue module)670 static JSTaggedValue GetLiteralFromCache(JSThread *thread, JSTaggedValue constpool, 671 uint32_t index, JSTaggedValue module) 672 { 673 CString entry = ModuleManager::GetRecordName(thread, module); 674 return GetLiteralFromCache<type>(thread, constpool, index, entry); 675 } 676 677 static JSTaggedValue PUBLIC_API GetStringFromCacheForJit( 678 JSThread *thread, JSTaggedValue constpool, uint32_t index, bool allowAlloc = true); 679 680 static JSTaggedValue PUBLIC_API GetStringFromCache(JSThread *thread, JSTaggedValue constpool, uint32_t index); 681 682 DECL_VISIT_ARRAY(DATA_OFFSET, GetCacheLength(), GetLength()); 683 DECL_DUMP()684 DECL_DUMP() 685 686 private: 687 inline size_t GetJSPandaFileOffset() const 688 { 689 return JSTaggedValue::TaggedTypeSize() * (GetLength() - JS_PANDA_FILE_INDEX); 690 } 691 GetIndexHeaderOffset()692 inline size_t GetIndexHeaderOffset() const 693 { 694 return JSTaggedValue::TaggedTypeSize() * (GetLength() - INDEX_HEADER_INDEX); 695 } 696 GetConstantIndexInfoOffset()697 inline size_t GetConstantIndexInfoOffset() const 698 { 699 return JSTaggedValue::TaggedTypeSize() * (GetLength() - CONSTANT_INDEX_INFO_INDEX); 700 } 701 GetAotArrayInfoOffset()702 inline size_t GetAotArrayInfoOffset() const 703 { 704 return JSTaggedValue::TaggedTypeSize() * (GetLength() - AOT_ARRAY_INFO_INDEX); 705 } 706 GetAotHClassInfoOffset()707 inline size_t GetAotHClassInfoOffset() const 708 { 709 return JSTaggedValue::TaggedTypeSize() * (GetLength() - AOT_HCLASS_INFO_INDEX); 710 } 711 GetUnsharedConstpoolIndexOffset()712 inline size_t GetUnsharedConstpoolIndexOffset() const 713 { 714 return JSTaggedValue::TaggedTypeSize() * (GetLength() - UNSHARED_CONSTPOOL_INDEX); 715 } 716 GetSharedConstpoolIdOffset()717 inline size_t GetSharedConstpoolIdOffset() const 718 { 719 return JSTaggedValue::TaggedTypeSize() * (GetLength() - SHARED_CONSTPOOL_ID); 720 } 721 GetAotSymbolInfoOffset()722 inline size_t GetAotSymbolInfoOffset() const 723 { 724 return JSTaggedValue::TaggedTypeSize() * (GetLength() - AOT_SYMBOL_INFO_INDEX); 725 } 726 GetProtoTransTableInfoOffset()727 inline size_t GetProtoTransTableInfoOffset() const 728 { 729 return JSTaggedValue::TaggedTypeSize() * (GetLength() - PROTO_TRANS_TABLE_INFO_INDEX); 730 } 731 GetLastOffset()732 inline size_t GetLastOffset() const 733 { 734 return JSTaggedValue::TaggedTypeSize() * GetLength() + DATA_OFFSET; 735 } 736 IsLoadingAOTMethodInfo(const JSPandaFile * pf,JSTaggedValue cachedVal)737 static bool IsLoadingAOTMethodInfo(const JSPandaFile *pf, JSTaggedValue cachedVal) 738 { 739 // Two types of AOT method infos are stored in the constpool: 740 // 1. AOTLiteralInfo which includes function entry index and ihc/chc 741 // 2. An int value(function entry index) if ihc/chc is not needed 742 return pf->IsLoadedAOT() && (cachedVal.IsAOTLiteralInfo() || cachedVal.IsInt()); 743 }; 744 745 static JSHandle<JSTaggedValue> GetDeserializedConstantPool( 746 EcmaVM *vm, const JSPandaFile *jsPandaFile, int32_t cpID); 747 static void MergeObjectLiteralHClassCache(EcmaVM *vm, const JSHandle<JSTaggedValue> &pool); 748 }; 749 } // namespace ecmascript 750 } // namespace panda 751 #endif // ECMASCRIPT_JSPANDAFILE_PROGRAM_OBJECT_H 752