1/* 2 * Copyright (c) 2023-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#include "ecmascript/ecma_context.h" 17 18#include "ecmascript/builtins/builtins.h" 19#include "ecmascript/builtins/builtins_regexp.h" 20#include "ecmascript/builtins/builtins_number.h" 21#include "ecmascript/compiler/pgo_type/pgo_type_manager.h" 22#include "ecmascript/dfx/vmstat/opt_code_profiler.h" 23#include "ecmascript/jit/jit.h" 24#include "ecmascript/linked_hash_table.h" 25#include "ecmascript/module/module_logger.h" 26#include "ecmascript/jspandafile/abc_buffer_cache.h" 27#include "ecmascript/platform/aot_crash_info.h" 28#include "ecmascript/platform/log.h" 29#include "ecmascript/regexp/regexp_parser_cache.h" 30#include "ecmascript/require/js_require_manager.h" 31#include "ecmascript/runtime.h" 32#include "ecmascript/snapshot/mem/snapshot.h" 33#include "ecmascript/stubs/runtime_stubs.h" 34#include "ecmascript/sustaining_js_handle.h" 35 36namespace panda::ecmascript { 37using PathHelper = base::PathHelper; 38 39EcmaContext::EcmaContext(JSThread *thread) 40 : thread_(thread), 41 vm_(thread->GetEcmaVM()), 42 factory_(vm_->GetFactory()), 43 aotFileManager_(vm_->GetAOTFileManager()) 44{ 45} 46 47/* static */ 48EcmaContext *EcmaContext::Create(JSThread *thread) 49{ 50 LOG_ECMA(INFO) << "EcmaContext::Create"; 51 auto context = new EcmaContext(thread); 52 return context; 53} 54 55// static 56bool EcmaContext::Destroy(EcmaContext *context) 57{ 58 if (context != nullptr) { 59 delete context; 60 context = nullptr; 61 return true; 62 } 63 return false; 64} 65 66bool EcmaContext::Initialize() 67{ 68 LOG_ECMA(DEBUG) << "EcmaContext::Initialize"; 69 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "EcmaContext::Initialize"); 70 [[maybe_unused]] EcmaHandleScope scope(thread_); 71 propertiesCache_ = new PropertiesCache(); 72 regExpParserCache_ = new RegExpParserCache(); 73 unsharedConstpools_.fill(JSTaggedValue::Hole()); 74 thread_->SetUnsharedConstpools(reinterpret_cast<uintptr_t>(unsharedConstpools_.data())); 75 76 thread_->SetGlobalConst(&globalConst_); 77 globalConst_.Init(thread_); 78 JSHandle<JSHClass> hClassHandle = JSHandle<JSHClass>(thread_, globalConst_.GetHClassClass()); 79 JSHandle<JSHClass> globalEnvClass = factory_->NewEcmaHClass( 80 *hClassHandle, 81 GlobalEnv::SIZE, 82 JSType::GLOBAL_ENV); 83 auto arrayHClassIndexMaps = Elements::InitializeHClassMap(); 84 thread_->SetArrayHClassIndexMap(arrayHClassIndexMaps); 85 JSHandle<GlobalEnv> globalEnv = factory_->NewGlobalEnv(*globalEnvClass); 86 globalEnv->Init(thread_); 87 globalEnv_ = globalEnv.GetTaggedValue(); 88 Builtins builtins; 89 bool builtinsLazyEnabled = vm_->GetJSOptions().IsWorker() && vm_->GetJSOptions().GetEnableBuiltinsLazy(); 90 thread_->SetEnableLazyBuiltins(builtinsLazyEnabled); 91 builtins.Initialize(globalEnv, thread_, builtinsLazyEnabled); 92 93 InitializeDefaultLocale(); 94 InitializeDefaultCompareStringsOption(); 95 SetupRegExpResultCache(); 96 SetupRegExpGlobalResult(); 97 SetupNumberToStringResultCache(); 98 SetupStringSplitResultCache(); 99 SetupStringToListResultCache(); 100 microJobQueue_ = factory_->NewMicroJobQueue().GetTaggedValue(); 101 moduleManager_ = new ModuleManager(vm_); 102 ptManager_ = new kungfu::PGOTypeManager(vm_); 103 optCodeProfiler_ = new OptCodeProfiler(); 104 abcBufferCache_ = new AbcBufferCache(); 105 if (vm_->GetJSOptions().GetTypedOpProfiler()) { 106 typedOpProfiler_ = new TypedOpProfiler(); 107 } 108 if (vm_->GetJSOptions().EnableModuleLog() && !vm_->GetJSOptions().IsWorker()) { 109 moduleLogger_ = new ModuleLogger(vm_); 110 } 111 functionProtoTransitionTable_ = new FunctionProtoTransitionTable(thread_); 112 sustainingJSHandleList_ = new SustainingJSHandleList(); 113 initialized_ = true; 114 return true; 115} 116 117void EcmaContext::InitializeEcmaScriptRunStat() 118{ 119 // NOLINTNEXTLINE(modernize-avoid-c-arrays) 120 static const char *runtimeCallerNames[] = { 121// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 122#define INTERPRETER_CALLER_NAME(name) "Interpreter::" #name, 123 INTERPRETER_CALLER_LIST(INTERPRETER_CALLER_NAME) // NOLINTNEXTLINE(bugprone-suspicious-missing-comma) 124#undef INTERPRETER_CALLER_NAME 125// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 126#define BUILTINS_API_NAME(class, name) "BuiltinsApi::" #class "_" #name, 127 BUILTINS_API_LIST(BUILTINS_API_NAME) 128#undef BUILTINS_API_NAME 129#define ABSTRACT_OPERATION_NAME(class, name) "AbstractOperation::" #class "_" #name, 130 ABSTRACT_OPERATION_LIST(ABSTRACT_OPERATION_NAME) 131#undef ABSTRACT_OPERATION_NAME 132#define MEM_ALLOCATE_AND_GC_NAME(name) "Memory::" #name, 133 MEM_ALLOCATE_AND_GC_LIST(MEM_ALLOCATE_AND_GC_NAME) 134#undef MEM_ALLOCATE_AND_GC_NAME 135#define DEF_RUNTIME_ID(name) "Runtime::" #name, 136 RUNTIME_STUB_WITH_GC_LIST(DEF_RUNTIME_ID) 137#undef DEF_RUNTIME_ID 138 }; 139 static_assert(sizeof(runtimeCallerNames) == sizeof(const char *) * ecmascript::RUNTIME_CALLER_NUMBER, 140 "Invalid runtime caller number"); 141 runtimeStat_ = vm_->GetChunk()->New<EcmaRuntimeStat>(runtimeCallerNames, ecmascript::RUNTIME_CALLER_NUMBER); 142 if (UNLIKELY(runtimeStat_ == nullptr)) { 143 LOG_FULL(FATAL) << "alloc runtimeStat_ failed"; 144 UNREACHABLE(); 145 } 146} 147 148void EcmaContext::ClearIcuCache(JSThread *thread) 149{ 150 for (uint32_t i = 0; i < static_cast<uint32_t>(IcuFormatterType::ICU_FORMATTER_TYPE_COUNT); i++) { 151 auto &icuFormatter = icuObjCache_[i]; 152 NativePointerCallback deleteEntry = icuFormatter.deleteEntry; 153 if (deleteEntry != nullptr) { 154 deleteEntry(thread->GetEnv(), icuFormatter.icuObj, vm_); 155 } 156 icuFormatter = EcmaContext::IcuFormatter{}; 157 } 158} 159 160void EcmaContext::SetRuntimeStatEnable(bool flag) 161{ 162 static uint64_t start = 0; 163 if (flag) { 164 start = PandaRuntimeTimer::Now(); 165 if (runtimeStat_ == nullptr) { 166 InitializeEcmaScriptRunStat(); 167 } 168 } else { 169 LOG_ECMA(INFO) << "Runtime State duration:" << PandaRuntimeTimer::Now() - start << "(ns)"; 170 if (runtimeStat_ != nullptr && runtimeStat_->IsRuntimeStatEnabled()) { 171 runtimeStat_->Print(); 172 runtimeStat_->ResetAllCount(); 173 } 174 } 175 if (runtimeStat_ != nullptr) { 176 runtimeStat_->SetRuntimeStatEnabled(flag); 177 } 178} 179 180EcmaContext::~EcmaContext() 181{ 182 if (runtimeStat_ != nullptr && runtimeStat_->IsRuntimeStatEnabled()) { 183 runtimeStat_->Print(); 184 } 185 for (auto n : handleStorageNodes_) { 186 delete n; 187 } 188 handleStorageNodes_.clear(); 189 currentHandleStorageIndex_ = -1; 190#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK 191 handleScopeCount_ = 0; 192 primitiveScopeCount_ = 0; 193#endif 194 handleScopeStorageNext_ = handleScopeStorageEnd_ = nullptr; 195 196 for (auto n : primitiveStorageNodes_) { 197 delete n; 198 } 199 primitiveStorageNodes_.clear(); 200 currentPrimitiveStorageIndex_ = -1; 201 primitiveScopeStorageNext_ = primitiveScopeStorageEnd_ = nullptr; 202 203 if (vm_->IsEnableBaselineJit() || vm_->IsEnableFastJit()) { 204 // clear jit task 205 vm_->GetJit()->ClearTask(this); 206 } 207 208 ClearBufferData(); 209 // clear c_address: c++ pointer delete 210 if (!vm_->IsBundlePack()) { 211 std::shared_ptr<JSPandaFile> jsPandaFile = 212 JSPandaFileManager::GetInstance()->FindJSPandaFile(vm_->GetAssetPath()); 213 if (jsPandaFile != nullptr) { 214 jsPandaFile->DeleteParsedConstpoolVM(vm_); 215 } 216 } 217 ClearDefaultLocale(); 218 ClearDefaultComapreStringsOption(); 219 // clear icu cache 220 ClearIcuCache(thread_); 221 222 if (runtimeStat_ != nullptr) { 223 vm_->GetChunk()->Delete(runtimeStat_); 224 runtimeStat_ = nullptr; 225 } 226 if (optCodeProfiler_ != nullptr) { 227 delete optCodeProfiler_; 228 optCodeProfiler_ = nullptr; 229 } 230 if (typedOpProfiler_ != nullptr) { 231 delete typedOpProfiler_; 232 typedOpProfiler_ = nullptr; 233 } 234 if (moduleManager_ != nullptr) { 235 delete moduleManager_; 236 moduleManager_ = nullptr; 237 } 238 if (moduleLogger_ != nullptr) { 239 delete moduleLogger_; 240 moduleLogger_ = nullptr; 241 } 242 if (ptManager_ != nullptr) { 243 delete ptManager_; 244 ptManager_ = nullptr; 245 } 246 if (regExpParserCache_ != nullptr) { 247 delete regExpParserCache_; 248 regExpParserCache_ = nullptr; 249 } 250 if (aotFileManager_ != nullptr) { 251 aotFileManager_ = nullptr; 252 } 253 if (propertiesCache_ != nullptr) { 254 delete propertiesCache_; 255 propertiesCache_ = nullptr; 256 } 257 if (sustainingJSHandleList_ != nullptr) { 258 delete sustainingJSHandleList_; 259 sustainingJSHandleList_ = nullptr; 260 } 261 if (functionProtoTransitionTable_ != nullptr) { 262 delete functionProtoTransitionTable_; 263 functionProtoTransitionTable_ = nullptr; 264 } 265 if (abcBufferCache_ != nullptr) { 266 delete abcBufferCache_; 267 abcBufferCache_ = nullptr; 268 } 269 // clear join stack 270 joinStack_.clear(); 271 272 for (auto v : stringifyCache_) { 273 v.clear(); 274 } 275} 276 277JSTaggedValue EcmaContext::InvokeEcmaAotEntrypoint(JSHandle<JSFunction> mainFunc, JSHandle<JSTaggedValue> &thisArg, 278 const JSPandaFile *jsPandaFile, std::string_view entryPoint, 279 CJSInfo* cjsInfo) 280{ 281 aotFileManager_->SetAOTMainFuncEntry(mainFunc, jsPandaFile, entryPoint); 282 return JSFunction::InvokeOptimizedEntrypoint(thread_, mainFunc, thisArg, cjsInfo); 283} 284 285JSTaggedValue EcmaContext::ExecuteAot(size_t actualNumArgs, JSTaggedType *args, 286 const JSTaggedType *prevFp, bool needPushArgv) 287{ 288 INTERPRETER_TRACE(thread_, ExecuteAot); 289 ASSERT(thread_->IsInManagedState()); 290 auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_JSFunctionEntry); 291 // entry of aot 292 auto res = reinterpret_cast<JSFunctionEntryType>(entry)(thread_->GetGlueAddr(), 293 actualNumArgs, 294 args, 295 reinterpret_cast<uintptr_t>(prevFp), 296 needPushArgv); 297 return res; 298} 299 300Expected<JSTaggedValue, bool> EcmaContext::CommonInvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, 301 std::string_view entryPoint, JSHandle<JSFunction> &func, bool executeFromJob) 302{ 303 ASSERT(thread_->IsInManagedState()); 304 JSHandle<JSTaggedValue> global = GlobalEnv::Cast(globalEnv_.GetTaggedObject())->GetJSGlobalObject(); 305 JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined(); 306 CString entry = entryPoint.data(); 307 JSRecordInfo *recordInfo = nullptr; 308 bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entry, &recordInfo); 309 if (!hasRecord) { 310 CString msg = "Cannot find module '" + entry + "' , which is application Entry Point"; 311 THROW_REFERENCE_ERROR_AND_RETURN(thread_, msg.c_str(), Unexpected(false)); 312 } 313 if (jsPandaFile->IsModule(recordInfo)) { 314 global = undefined; 315 CString moduleName = jsPandaFile->GetJSPandaFileDesc(); 316 if (!jsPandaFile->IsBundlePack()) { 317 moduleName = entry; 318 } 319 JSHandle<SourceTextModule> module; 320 if (jsPandaFile->IsSharedModule(recordInfo)) { 321 module = SharedModuleManager::GetInstance()->GetSModule(thread_, entry); 322 } else { 323 module = moduleManager_->HostGetImportedModule(moduleName); 324 } 325 // esm -> SourceTextModule; cjs or script -> string of recordName 326 module->SetSendableEnv(thread_, JSTaggedValue::Undefined()); 327 func->SetModule(thread_, module); 328 } else { 329 // if it is Cjs at present, the module slot of the function is not used. We borrow it to store the recordName, 330 // which can avoid the problem of larger memory caused by the new slot 331 JSHandle<EcmaString> recordName = factory_->NewFromUtf8(entry); 332 func->SetModule(thread_, recordName); 333 } 334 vm_->CheckStartCpuProfiler(); 335 336 JSTaggedValue result; 337 if (jsPandaFile->IsCjs(recordInfo)) { 338 CJSExecution(func, global, jsPandaFile, entryPoint); 339 } else { 340 if (aotFileManager_->IsLoadMain(jsPandaFile, entry)) { 341 EcmaRuntimeStatScope runtimeStatScope(vm_); 342 result = InvokeEcmaAotEntrypoint(func, global, jsPandaFile, entryPoint); 343 } else if (vm_->GetJSOptions().IsEnableForceJitCompileMain()) { 344 Jit::Compile(vm_, func, CompilerTier::FAST); 345 EcmaRuntimeStatScope runtimeStatScope(vm_); 346 result = JSFunction::InvokeOptimizedEntrypoint(thread_, func, global, nullptr); 347 } else if (vm_->GetJSOptions().IsEnableForceBaselineCompileMain()) { 348 Jit::Compile(vm_, func, CompilerTier::BASELINE); 349 EcmaRuntimeCallInfo *info = 350 EcmaInterpreter::NewRuntimeCallInfo(thread_, JSHandle<JSTaggedValue>(func), global, undefined, 0); 351 EcmaRuntimeStatScope runtimeStatScope(vm_); 352 result = EcmaInterpreter::Execute(info); 353 } else { 354 EcmaRuntimeCallInfo *info = 355 EcmaInterpreter::NewRuntimeCallInfo(thread_, JSHandle<JSTaggedValue>(func), global, undefined, 0); 356 EcmaRuntimeStatScope runtimeStatScope(vm_); 357 result = EcmaInterpreter::Execute(info); 358 } 359 360 if (!thread_->HasPendingException() && !executeFromJob) { 361 JSHandle<JSTaggedValue> handleResult(thread_, result); 362 job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); 363 result = handleResult.GetTaggedValue(); 364 } 365 } 366 if (thread_->HasPendingException()) { 367#ifdef PANDA_TARGET_OHOS 368 return result; 369#else 370 return Unexpected(false); 371#endif 372 } 373 return result; 374} 375 376Expected<JSTaggedValue, bool> EcmaContext::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, 377 std::string_view entryPoint, bool executeFromJob) 378{ 379 [[maybe_unused]] EcmaHandleScope scope(thread_); 380 auto &options = const_cast<EcmaVM *>(thread_->GetEcmaVM())->GetJSOptions(); 381 if (options.EnableModuleLog()) { 382 LOG_FULL(INFO) << "current executing file's name " << entryPoint.data(); 383 } 384 ModuleLogger *moduleLogger = GetModuleLogger(); 385 if (moduleLogger != nullptr) { 386 moduleLogger->SetStartTime(CString(entryPoint)); 387 } 388 JSHandle<Program> program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint); 389 if (program.IsEmpty()) { 390 LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed"; 391 return Unexpected(false); 392 } 393 // for debugger 394 vm_->GetJsDebuggerManager()->GetNotificationManager()->LoadModuleEvent( 395 jsPandaFile->GetJSPandaFileDesc(), entryPoint); 396 397 JSHandle<JSFunction> func(thread_, program->GetMainFunction()); 398 Expected<JSTaggedValue, bool> result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func, executeFromJob); 399 400#ifdef PANDA_TARGET_OHOS 401 if (thread_->HasPendingException()) { 402 HandleUncaughtException(); 403 } 404#endif 405 406 if (moduleLogger != nullptr) { 407 moduleLogger->SetEndTime(CString(entryPoint)); 408 } 409 return result; 410} 411 412Expected<JSTaggedValue, bool> EcmaContext::InvokeEcmaEntrypointForHotReload( 413 const JSPandaFile *jsPandaFile, std::string_view entryPoint, bool executeFromJob) 414{ 415 [[maybe_unused]] EcmaHandleScope scope(thread_); 416 JSHandle<Program> program = JSPandaFileManager::GetInstance()->GenerateProgram(vm_, jsPandaFile, entryPoint); 417 418 JSHandle<JSFunction> func(thread_, program->GetMainFunction()); 419 Expected<JSTaggedValue, bool> result = CommonInvokeEcmaEntrypoint(jsPandaFile, entryPoint, func, executeFromJob); 420 421 JSHandle<JSTaggedValue> finalModuleRecord(thread_, func->GetModule()); 422 // avoid GC problems. 423 GlobalHandleCollection gloalHandleCollection(thread_); 424 JSHandle<JSTaggedValue> moduleRecordHandle = 425 gloalHandleCollection.NewHandle<JSTaggedValue>(finalModuleRecord->GetRawData()); 426 CString recordName = entryPoint.data(); 427 AddPatchModule(recordName, moduleRecordHandle); 428 429 // print exception information 430 if (thread_->HasPendingException() && 431 Method::Cast(func->GetMethod())->GetMethodName() != JSPandaFile::PATCH_FUNCTION_NAME_0) { 432 return Unexpected(false); 433 } 434 return result; 435} 436 437void EcmaContext::CJSExecution(JSHandle<JSFunction> &func, JSHandle<JSTaggedValue> &thisArg, 438 const JSPandaFile *jsPandaFile, std::string_view entryPoint) 439{ 440 // create "module", "exports", "require", "filename", "dirname" 441 JSHandle<CjsModule> module = factory_->NewCjsModule(); 442 JSHandle<JSTaggedValue> require = GetGlobalEnv()->GetCjsRequireFunction(); 443 JSHandle<CjsExports> exports = factory_->NewCjsExports(); 444 CString fileNameStr; 445 CString dirNameStr; 446 if (jsPandaFile->IsBundlePack()) { 447 ModulePathHelper::ResolveCurrentPath(dirNameStr, fileNameStr, jsPandaFile); 448 } else { 449 JSTaggedValue funcFileName = func->GetModule(); 450 ASSERT(funcFileName.IsString()); 451 fileNameStr = ModulePathHelper::Utf8ConvertToString(funcFileName); 452 dirNameStr = PathHelper::ResolveDirPath(fileNameStr); 453 } 454 JSHandle<JSTaggedValue> fileName = JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf8(fileNameStr)); 455 JSHandle<JSTaggedValue> dirName = JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf8(dirNameStr)); 456 CJSInfo cjsInfo(module, require, exports, fileName, dirName); 457 RequireManager::InitializeCommonJS(thread_, cjsInfo); 458 if (aotFileManager_->IsLoadMain(jsPandaFile, entryPoint.data())) { 459 EcmaRuntimeStatScope runtimeStateScope(vm_); 460 isAotEntry_ = true; 461 InvokeEcmaAotEntrypoint(func, thisArg, jsPandaFile, entryPoint, &cjsInfo); 462 } else { 463 // Execute main function 464 JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined(); 465 EcmaRuntimeCallInfo *info = 466 EcmaInterpreter::NewRuntimeCallInfo(thread_, 467 JSHandle<JSTaggedValue>(func), 468 thisArg, undefined, 5); // 5 : argument numbers 469 RETURN_IF_ABRUPT_COMPLETION(thread_); 470 if (info == nullptr) { 471 LOG_ECMA(ERROR) << "CJSExecution Stack overflow!"; 472 return; 473 } 474 info->SetCallArg(cjsInfo.exportsHdl.GetTaggedValue(), 475 cjsInfo.requireHdl.GetTaggedValue(), 476 cjsInfo.moduleHdl.GetTaggedValue(), 477 cjsInfo.filenameHdl.GetTaggedValue(), 478 cjsInfo.dirnameHdl.GetTaggedValue()); 479 EcmaRuntimeStatScope runtimeStatScope(vm_); 480 EcmaInterpreter::Execute(info); 481 } 482 if (!thread_->HasPendingException()) { 483 // Collecting module.exports : exports ---> module.exports --->Module._cache 484 RequireManager::CollectExecutedExp(thread_, cjsInfo); 485 } 486} 487 488void EcmaContext::LoadProtoTransitionTable(JSTaggedValue constpool) 489{ 490 JSTaggedValue protoTransitionTable = ConstantPool::Cast(constpool.GetTaggedObject())->GetProtoTransTableInfo(); 491 functionProtoTransitionTable_->UpdateProtoTransitionTable( 492 thread_, JSHandle<PointerToIndexDictionary>(thread_, protoTransitionTable)); 493} 494 495void EcmaContext::ResetProtoTransitionTableOnConstpool(JSTaggedValue constpool) 496{ 497 ConstantPool::Cast(constpool.GetTaggedObject())->SetProtoTransTableInfo(thread_, JSTaggedValue::Undefined()); 498} 499 500// just find unshared constpool, not create 501JSTaggedValue EcmaContext::FindUnsharedConstpool(JSTaggedValue sharedConstpool) 502{ 503 ConstantPool *shareCp = ConstantPool::Cast(sharedConstpool.GetTaggedObject()); 504 int32_t constpoolIndex = shareCp->GetUnsharedConstpoolIndex(); 505 // unshared constpool index is default INT32_MAX. 506 ASSERT(0 <= constpoolIndex && constpoolIndex != ConstantPool::CONSTPOOL_TYPE_FLAG && 507 constpoolIndex < UNSHARED_CONSTANTPOOL_COUNT); 508 return unsharedConstpools_[constpoolIndex]; 509} 510 511JSTaggedValue EcmaContext::FindOrCreateUnsharedConstpool(JSTaggedValue sharedConstpool) 512{ 513 JSTaggedValue unsharedConstpool = FindUnsharedConstpool(sharedConstpool); 514 if (unsharedConstpool.IsHole()) { 515 ConstantPool *shareCp = ConstantPool::Cast(sharedConstpool.GetTaggedObject()); 516 int32_t constpoolIndex = shareCp->GetUnsharedConstpoolIndex(); 517 // unshared constpool index is default INT32_MAX. 518 ASSERT(0 <= constpoolIndex && constpoolIndex != ConstantPool::CONSTPOOL_TYPE_FLAG && 519 constpoolIndex < UNSHARED_CONSTANTPOOL_COUNT); 520 ASSERT(constpoolIndex != INT32_MAX); 521 JSHandle<ConstantPool> unshareCp = 522 ConstantPool::CreateUnSharedConstPoolBySharedConstpool(vm_, shareCp->GetJSPandaFile(), shareCp); 523 unsharedConstpool = unshareCp.GetTaggedValue(); 524 SetUnsharedConstpool(constpoolIndex, unsharedConstpool); 525 } 526 return unsharedConstpool; 527} 528 529void EcmaContext::EraseUnusedConstpool(const JSPandaFile *jsPandaFile, int32_t index, int32_t constpoolIndex) 530{ 531 // unshared constpool index is default INT32_MAX. 532 ASSERT(constpoolIndex != ConstantPool::CONSTPOOL_TYPE_FLAG); 533 534 SetUnsharedConstpool(constpoolIndex, JSTaggedValue::Hole()); 535 auto iter = cachedSharedConstpools_.find(jsPandaFile); 536 if (iter == cachedSharedConstpools_.end()) { 537 return; 538 } 539 auto constpoolIter = iter->second.find(index); 540 if (constpoolIter == iter->second.end()) { 541 return; 542 } 543 544 iter->second.erase(constpoolIter); 545 if (iter->second.size() == 0) { 546 cachedSharedConstpools_.erase(iter); 547 } 548} 549 550std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> EcmaContext::FindConstpools( 551 const JSPandaFile *jsPandaFile) 552{ 553 return Runtime::GetInstance()->FindConstpools(jsPandaFile); 554} 555 556// For new version instruction. 557JSTaggedValue EcmaContext::FindConstpool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id) 558{ 559 panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id); 560 int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex()); 561 return FindConstpool(jsPandaFile, index); 562} 563 564JSTaggedValue EcmaContext::FindConstpool(const JSPandaFile *jsPandaFile, int32_t index) 565{ 566 JSTaggedValue contextCache = FindConstpoolFromContextCache(jsPandaFile, index); 567 if (!contextCache.IsHole()) { 568 return contextCache; 569 } 570 return Runtime::GetInstance()->FindConstpool(jsPandaFile, index); 571} 572 573JSTaggedValue EcmaContext::FindConstpoolFromContextCache(const JSPandaFile *jsPandaFile, int32_t index) 574{ 575 auto iter = cachedSharedConstpools_.find(jsPandaFile); 576 if (iter != cachedSharedConstpools_.end()) { 577 auto constpoolIter = iter->second.find(index); 578 if (constpoolIter != iter->second.end()) { 579 return constpoolIter->second; 580 } 581 } 582 return JSTaggedValue::Hole(); 583} 584 585bool EcmaContext::HasCachedConstpool(const JSPandaFile *jsPandaFile) const 586{ 587 if (cachedSharedConstpools_.find(jsPandaFile) != cachedSharedConstpools_.end()) { 588 return true; 589 } 590 591 return Runtime::GetInstance()->HasCachedConstpool(jsPandaFile); 592} 593 594JSHandle<ConstantPool> EcmaContext::AddOrUpdateConstpool(const JSPandaFile *jsPandaFile, 595 JSHandle<ConstantPool> constpool, 596 int32_t index) 597{ 598 constpool = Runtime::GetInstance()->AddOrUpdateConstpool(jsPandaFile, constpool, index); 599 AddContextConstpoolCache(jsPandaFile, constpool, index); 600 return constpool; 601} 602 603void EcmaContext::AddContextConstpoolCache(const JSPandaFile *jsPandaFile, 604 JSHandle<ConstantPool> constpool, 605 int32_t index) 606{ 607 if (cachedSharedConstpools_.find(jsPandaFile) == cachedSharedConstpools_.end()) { 608 cachedSharedConstpools_[jsPandaFile] = CMap<int32_t, JSTaggedValue>(); 609 } 610 auto &constpoolMap = cachedSharedConstpools_[jsPandaFile]; 611 ASSERT(constpoolMap.find(index) == constpoolMap.end()); 612 constpoolMap.insert({index, constpool.GetTaggedValue()}); 613} 614 615void EcmaContext::SetUnsharedConstpool(JSHandle<ConstantPool> sharedConstpool, JSTaggedValue unsharedConstpool) 616{ 617 int32_t constpoolIndex = sharedConstpool->GetUnsharedConstpoolIndex(); 618 SetUnsharedConstpool(constpoolIndex, unsharedConstpool); 619} 620 621void EcmaContext::SetUnsharedConstpool(int32_t constpoolIndex, JSTaggedValue unsharedConstpool) 622{ 623 CheckUnsharedConstpoolArrayLimit(constpoolIndex); 624 ASSERT(0 <= constpoolIndex && constpoolIndex < UNSHARED_CONSTANTPOOL_COUNT); 625 unsharedConstpools_[constpoolIndex] = unsharedConstpool; 626} 627 628void EcmaContext::UpdateConstpoolWhenDeserialAI(const std::string& fileName, 629 JSHandle<ConstantPool> aiCP, int32_t index) 630{ 631 auto pf = JSPandaFileManager::GetInstance()->FindJSPandaFile(fileName.c_str()); 632 if (pf == nullptr) { 633 return; 634 } 635 JSTaggedValue sharedConstpool = FindConstpool(pf.get(), index); 636 JSHandle<ConstantPool> sharedCPHandle = JSHandle<ConstantPool>(thread_, sharedConstpool); 637 if (sharedConstpool.IsHole()) { 638 return; 639 } 640 JSTaggedValue unsharedConstpool = FindOrCreateUnsharedConstpool(sharedCPHandle.GetTaggedValue()); 641 JSHandle<ConstantPool> unsharedCP = JSHandle<ConstantPool>(thread_, unsharedConstpool); 642 JSHandle<ConstantPool> sharedCP = JSHandle<ConstantPool>(thread_, sharedCPHandle.GetTaggedValue()); 643 ConstantPool::UpdateConstpoolWhenDeserialAI(vm_, aiCP, sharedCP, unsharedCP); 644} 645 646JSTaggedValue EcmaContext::FindCachedConstpoolAndLoadAiIfNeeded(const JSPandaFile *jsPandaFile, int32_t index) 647{ 648 JSTaggedValue constpool = FindConstpoolFromContextCache(jsPandaFile, index); 649 if (!constpool.IsHole()) { 650 return constpool; 651 } 652 constpool = Runtime::GetInstance()->FindConstpool(jsPandaFile, index); 653 if (!constpool.IsHole()) { 654 AddContextConstpoolCache(jsPandaFile, JSHandle<ConstantPool>(thread_, constpool), index); 655 } 656 // Getting the cached constpool in runtime means the ai data has not been loaded in current thread. 657 // And we need to reload it 658 aotFileManager_->LoadAiFile(jsPandaFile); 659 return constpool; 660} 661 662JSHandle<ConstantPool> EcmaContext::FindOrCreateConstPool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id) 663{ 664 panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id); 665 int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex()); 666 JSTaggedValue constpool = FindCachedConstpoolAndLoadAiIfNeeded(jsPandaFile, index); 667 if (constpool.IsHole()) { 668 JSHandle<ConstantPool> newConstpool = ConstantPool::CreateUnSharedConstPool(vm_, jsPandaFile, id); 669 JSHandle<ConstantPool> newSConstpool; 670 if (jsPandaFile->IsLoadedAOT()) { 671 newSConstpool = ConstantPool::CreateSharedConstPoolForAOT(vm_, newConstpool, index); 672 } else { 673 newSConstpool = ConstantPool::CreateSharedConstPool(vm_, jsPandaFile, id, index); 674 } 675 newSConstpool = AddOrUpdateConstpool(jsPandaFile, newSConstpool, index); 676 SetUnsharedConstpool(newSConstpool, newConstpool.GetTaggedValue()); 677 return newSConstpool; 678 } else if (jsPandaFile->IsLoadedAOT()) { 679 // For aot, after getting the cached shared constpool, 680 // worker thread need to create and bind the correspoding unshared constpool. 681 FindOrCreateUnsharedConstpool(constpool); 682 } 683 return JSHandle<ConstantPool>(thread_, constpool); 684} 685 686void EcmaContext::CreateAllConstpool(const JSPandaFile *jsPandaFile) 687{ 688 auto headers = jsPandaFile->GetPandaFile()->GetIndexHeaders(); 689 uint32_t index = 0; 690 for (const auto &header : headers) { 691 auto constpoolSize = header.method_idx_size; 692 JSHandle<ConstantPool> sconstpool = factory_->NewSConstantPool(constpoolSize); 693 sconstpool->SetJSPandaFile(jsPandaFile); 694 sconstpool->SetIndexHeader(&header); 695 sconstpool->SetSharedConstpoolId(JSTaggedValue(index)); 696 sconstpool = AddOrUpdateConstpool(jsPandaFile, sconstpool, index); 697 index++; 698 699 JSHandle<ConstantPool> constpool = factory_->NewConstantPool(constpoolSize); 700 constpool->SetJSPandaFile(jsPandaFile); 701 constpool->SetIndexHeader(&header); 702 SetUnsharedConstpool(sconstpool, constpool.GetTaggedValue()); 703 } 704} 705 706JSHandle<JSTaggedValue> EcmaContext::GetAndClearEcmaUncaughtException() const 707{ 708 JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException(); 709 thread_->ClearException(); // clear for ohos app 710 return exceptionHandle; 711} 712 713void EcmaContext::RelocateConstantString(const JSPandaFile *jsPandaFile) 714{ 715 if (!jsPandaFile->IsFirstMergedAbc()) { 716 return; 717 } 718 vm_->GetEcmaStringTable()->RelocateConstantData(vm_, jsPandaFile); 719} 720 721JSHandle<JSTaggedValue> EcmaContext::GetEcmaUncaughtException() const 722{ 723 if (!thread_->HasPendingException()) { 724 return JSHandle<JSTaggedValue>(); 725 } 726 JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException()); 727 return exceptionHandle; 728} 729 730void EcmaContext::EnableUserUncaughtErrorHandler() 731{ 732 isUncaughtExceptionRegistered_ = true; 733} 734 735void EcmaContext::HandleUncaughtException(JSTaggedValue exception) 736{ 737 if (isUncaughtExceptionRegistered_) { 738 return; 739 } 740 [[maybe_unused]] EcmaHandleScope handleScope(thread_); 741 JSHandle<JSTaggedValue> exceptionHandle(thread_, exception); 742 // if caught exceptionHandle type is JSError 743 thread_->ClearException(); 744 if (exceptionHandle->IsJSError()) { 745 PrintJSErrorInfo(thread_, exceptionHandle); 746 return; 747 } 748 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread_, exceptionHandle); 749 CString string = ConvertToString(*result); 750 LOG_NO_TAG(ERROR) << string; 751} 752 753void EcmaContext::HandleUncaughtException() 754{ 755 if (!thread_->HasPendingException()) { 756 return; 757 } 758 JSTaggedValue exception = thread_->GetException(); 759 HandleUncaughtException(exception); 760} 761 762// static 763void EcmaContext::PrintJSErrorInfo(JSThread *thread, const JSHandle<JSTaggedValue> &exceptionInfo) 764{ 765 JSHandle<JSTaggedValue> nameKey = thread->GlobalConstants()->GetHandledNameString(); 766 JSHandle<JSTaggedValue> nameValue = JSObject::GetProperty(thread, exceptionInfo, nameKey).GetValue(); 767 RETURN_IF_ABRUPT_COMPLETION(thread); 768 JSHandle<EcmaString> name = JSTaggedValue::ToString(thread, nameValue); 769 // JSTaggedValue::ToString may cause exception. In this case, do not return, use "<error>" instead. 770 if (thread->HasPendingException()) { 771 thread->ClearException(); 772 name = thread->GetEcmaVM()->GetFactory()->NewFromStdString("<error>"); 773 } 774 JSHandle<JSTaggedValue> msgKey = thread->GlobalConstants()->GetHandledMessageString(); 775 JSHandle<JSTaggedValue> msgValue = JSObject::GetProperty(thread, exceptionInfo, msgKey).GetValue(); 776 RETURN_IF_ABRUPT_COMPLETION(thread); 777 JSHandle<EcmaString> msg = JSTaggedValue::ToString(thread, msgValue); 778 // JSTaggedValue::ToString may cause exception. In this case, do not return, use "<error>" instead. 779 if (thread->HasPendingException()) { 780 thread->ClearException(); 781 msg = thread->GetEcmaVM()->GetFactory()->NewFromStdString("<error>"); 782 } 783 JSHandle<JSTaggedValue> stackKey = thread->GlobalConstants()->GetHandledStackString(); 784 JSHandle<JSTaggedValue> stackValue = JSObject::GetProperty(thread, exceptionInfo, stackKey).GetValue(); 785 RETURN_IF_ABRUPT_COMPLETION(thread); 786 JSHandle<EcmaString> stack = JSTaggedValue::ToString(thread, stackValue); 787 // JSTaggedValue::ToString may cause exception. In this case, do not return, use "<error>" instead. 788 if (thread->HasPendingException()) { 789 thread->ClearException(); 790 stack = thread->GetEcmaVM()->GetFactory()->NewFromStdString("<error>"); 791 } 792 793 CString nameBuffer = ConvertToString(*name); 794 CString msgBuffer = ConvertToString(*msg); 795 CString stackBuffer = ConvertToString(*stack); 796 LOG_NO_TAG(ERROR) << panda::ecmascript::previewerTag << nameBuffer << ": " << msgBuffer << "\n" 797 << (panda::ecmascript::previewerTag.empty() 798 ? stackBuffer 799 : std::regex_replace(stackBuffer, std::regex(".+(\n|$)"), 800 panda::ecmascript::previewerTag + "$0")); 801} 802 803bool EcmaContext::HasPendingJob() 804{ 805 // This interface only determines whether PromiseJobQueue is empty, rather than ScriptJobQueue. 806 if (UNLIKELY(thread_->HasTerminated())) { 807 return false; 808 } 809 TaggedQueue* promiseQueue = TaggedQueue::Cast(GetMicroJobQueue()->GetPromiseJobQueue().GetTaggedObject()); 810 return !promiseQueue->Empty(); 811} 812 813bool EcmaContext::ExecutePromisePendingJob() 814{ 815 if (isProcessingPendingJob_) { 816 LOG_ECMA(DEBUG) << "EcmaVM::ExecutePromisePendingJob can not reentrant"; 817 return false; 818 } 819 if (!thread_->HasPendingException()) { 820 isProcessingPendingJob_ = true; 821 job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); 822 if (thread_->HasPendingException()) { 823 JsStackInfo::BuildCrashInfo(thread_); 824 } 825 isProcessingPendingJob_ = false; 826 return true; 827 } 828 return false; 829} 830 831void EcmaContext::ClearBufferData() 832{ 833 cachedSharedConstpools_.clear(); 834 thread_->SetUnsharedConstpools(reinterpret_cast<uintptr_t>(nullptr)); 835} 836 837void EcmaContext::SetGlobalEnv(GlobalEnv *global) 838{ 839 // In jsthread iteration, SwitchCurrentContext is called to iterate each context. 840 // If the target context is not fully initialized, the variable "global" will be nullptr. 841 if (global != nullptr) { 842 globalEnv_ = JSTaggedValue(global); 843 } 844} 845 846void EcmaContext::SetMicroJobQueue(job::MicroJobQueue *queue) 847{ 848 ASSERT(queue != nullptr); 849 microJobQueue_ = JSTaggedValue(queue); 850} 851 852JSHandle<GlobalEnv> EcmaContext::GetGlobalEnv() const 853{ 854 return JSHandle<GlobalEnv>(reinterpret_cast<uintptr_t>(&globalEnv_)); 855} 856 857JSHandle<job::MicroJobQueue> EcmaContext::GetMicroJobQueue() const 858{ 859 return JSHandle<job::MicroJobQueue>(reinterpret_cast<uintptr_t>(µJobQueue_)); 860} 861 862void EcmaContext::MountContext(JSThread *thread) 863{ 864 EcmaContext *context = EcmaContext::CreateAndInitialize(thread); 865 thread->SwitchCurrentContext(context); 866} 867 868void EcmaContext::UnmountContext(JSThread *thread) 869{ 870 EcmaContext *context = thread->GetCurrentEcmaContext(); 871 thread->PopContext(); 872 Destroy(context); 873} 874 875EcmaContext *EcmaContext::CreateAndInitialize(JSThread *thread) 876{ 877 EcmaContext *context = EcmaContext::Create(thread); 878 thread->PushContext(context); 879 context->Initialize(); 880 return context; 881} 882 883void EcmaContext::CheckAndDestroy(JSThread *thread, EcmaContext *context) 884{ 885 if (thread->EraseContext(context)) { 886 Destroy(context); 887 return; 888 } 889 LOG_ECMA(FATAL) << "CheckAndDestroy a nonexistent context."; 890} 891 892void EcmaContext::SetupRegExpResultCache() 893{ 894 regexpCache_ = builtins::RegExpExecResultCache::CreateCacheTable(thread_); 895} 896 897void EcmaContext::SetupRegExpGlobalResult() 898{ 899 regexpGlobal_ = builtins::RegExpGlobalResult::CreateGlobalResultTable(thread_); 900} 901 902void EcmaContext::SetupNumberToStringResultCache() 903{ 904 numberToStringResultCache_ = builtins::NumberToStringResultCache::CreateCacheTable(thread_); 905} 906 907void EcmaContext::SetupStringSplitResultCache() 908{ 909 stringSplitResultCache_ = builtins::StringSplitResultCache::CreateCacheTable(thread_); 910} 911 912void EcmaContext::SetupStringToListResultCache() 913{ 914 stringToListResultCache_ = builtins::StringToListResultCache::CreateCacheTable(thread_); 915} 916 917void EcmaContext::Iterate(const RootVisitor &v, const RootRangeVisitor &rv) 918{ 919 // visit global Constant 920 globalConst_.VisitRangeSlot(rv); 921 922 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&globalEnv_))); 923 if (!regexpCache_.IsHole()) { 924 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(®expCache_))); 925 } 926 if (!regexpGlobal_.IsHole()) { 927 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(®expGlobal_))); 928 } 929 if (!numberToStringResultCache_.IsHole()) { 930 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&numberToStringResultCache_))); 931 } 932 if (!stringSplitResultCache_.IsHole()) { 933 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&stringSplitResultCache_))); 934 } 935 if (!stringToListResultCache_.IsHole()) { 936 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&stringToListResultCache_))); 937 } 938 if (!microJobQueue_.IsHole()) { 939 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(µJobQueue_))); 940 } 941 if (!pointerToIndexDictionary_.IsHole()) { 942 v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&pointerToIndexDictionary_))); 943 } 944 945 if (functionProtoTransitionTable_) { 946 functionProtoTransitionTable_->Iterate(v); 947 } 948 if (moduleManager_) { 949 moduleManager_->Iterate(v); 950 } 951 if (ptManager_) { 952 ptManager_->Iterate(v); 953 } 954 if (propertiesCache_ != nullptr) { 955 propertiesCache_->Clear(); 956 } 957 if (regExpParserCache_ != nullptr) { 958 regExpParserCache_->Clear(); 959 } 960 if (!vm_->GetJSOptions().EnableGlobalLeakCheck() && currentHandleStorageIndex_ != -1) { 961 // IterateHandle when disableGlobalLeakCheck. 962 int32_t nid = currentHandleStorageIndex_; 963 for (int32_t i = 0; i <= nid; ++i) { 964 auto node = handleStorageNodes_.at(i); 965 auto start = node->data(); 966 auto end = (i != nid) ? &(node->data()[NODE_BLOCK_SIZE]) : handleScopeStorageNext_; 967 rv(ecmascript::Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(start)), ObjectSlot(ToUintPtr(end))); 968 } 969 } 970 971 if (sustainingJSHandleList_) { 972 sustainingJSHandleList_->Iterate(rv); 973 } 974 975 if (!joinStack_.empty()) { 976 rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&joinStack_.front())), 977 ObjectSlot(ToUintPtr(&joinStack_.back()) + JSTaggedValue::TaggedTypeSize())); 978 } 979 980 auto start = ObjectSlot(ToUintPtr(unsharedConstpools_.data())); 981 auto end = ObjectSlot(ToUintPtr(&unsharedConstpools_[UNSHARED_CONSTANTPOOL_COUNT - 1]) + 982 JSTaggedValue::TaggedTypeSize()); 983 rv(Root::ROOT_VM, start, end); 984} 985 986size_t EcmaContext::IterateHandle(const RootRangeVisitor &rangeVisitor) 987{ 988 // EnableGlobalLeakCheck. 989 size_t handleCount = 0; 990 if (currentHandleStorageIndex_ != -1) { 991 int32_t nid = currentHandleStorageIndex_; 992 for (int32_t i = 0; i <= nid; ++i) { 993 auto node = handleStorageNodes_.at(i); 994 auto start = node->data(); 995 auto end = (i != nid) ? &(node->data()[NODE_BLOCK_SIZE]) : handleScopeStorageNext_; 996 rangeVisitor(ecmascript::Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(start)), ObjectSlot(ToUintPtr(end))); 997 handleCount += (ToUintPtr(end) - ToUintPtr(start)) / sizeof(JSTaggedType); 998 } 999 } 1000 return handleCount; 1001} 1002 1003uintptr_t *EcmaContext::ExpandHandleStorage() 1004{ 1005 uintptr_t *result = nullptr; 1006 int32_t lastIndex = static_cast<int32_t>(handleStorageNodes_.size()) - 1; 1007 if (currentHandleStorageIndex_ == lastIndex) { 1008 auto n = new std::array<JSTaggedType, NODE_BLOCK_SIZE>(); 1009 handleStorageNodes_.push_back(n); 1010 currentHandleStorageIndex_++; 1011 result = reinterpret_cast<uintptr_t *>(&n->data()[0]); 1012 handleScopeStorageEnd_ = &n->data()[NODE_BLOCK_SIZE]; 1013 } else { 1014 currentHandleStorageIndex_++; 1015 auto lastNode = handleStorageNodes_[currentHandleStorageIndex_]; 1016 result = reinterpret_cast<uintptr_t *>(&lastNode->data()[0]); 1017 handleScopeStorageEnd_ = &lastNode->data()[NODE_BLOCK_SIZE]; 1018 } 1019 1020 return result; 1021} 1022 1023void EcmaContext::ShrinkHandleStorage(int prevIndex) 1024{ 1025 currentHandleStorageIndex_ = prevIndex; 1026 int32_t lastIndex = static_cast<int32_t>(handleStorageNodes_.size()) - 1; 1027#if ECMASCRIPT_ENABLE_ZAP_MEM 1028 uintptr_t size = ToUintPtr(handleScopeStorageEnd_) - ToUintPtr(handleScopeStorageNext_); 1029 if (currentHandleStorageIndex_ != -1) { 1030 if (memset_s(handleScopeStorageNext_, size, 0, size) != EOK) { 1031 LOG_FULL(FATAL) << "memset_s failed"; 1032 UNREACHABLE(); 1033 } 1034 } 1035 for (int32_t i = currentHandleStorageIndex_ + 1; i < lastIndex; i++) { 1036 if (memset_s(handleStorageNodes_[i], 1037 NODE_BLOCK_SIZE * sizeof(JSTaggedType), 0, 1038 NODE_BLOCK_SIZE * sizeof(JSTaggedType)) != 1039 EOK) { 1040 LOG_FULL(FATAL) << "memset_s failed"; 1041 UNREACHABLE(); 1042 } 1043 } 1044#endif 1045 1046 if (lastIndex > MIN_HANDLE_STORAGE_SIZE && currentHandleStorageIndex_ < MIN_HANDLE_STORAGE_SIZE) { 1047 for (int i = MIN_HANDLE_STORAGE_SIZE; i < lastIndex; i++) { 1048 auto node = handleStorageNodes_.back(); 1049 delete node; 1050 handleStorageNodes_.pop_back(); 1051 } 1052 } 1053} 1054 1055uintptr_t *EcmaContext::ExpandPrimitiveStorage() 1056{ 1057 uintptr_t *result = nullptr; 1058 int32_t lastIndex = static_cast<int32_t>(primitiveStorageNodes_.size()) - 1; 1059 if (currentPrimitiveStorageIndex_ == lastIndex) { 1060 auto n = new std::array<JSTaggedType, NODE_BLOCK_SIZE>(); 1061 primitiveStorageNodes_.push_back(n); 1062 currentPrimitiveStorageIndex_++; 1063 result = reinterpret_cast<uintptr_t *>(&n->data()[0]); 1064 primitiveScopeStorageEnd_ = &n->data()[NODE_BLOCK_SIZE]; 1065 } else { 1066 currentPrimitiveStorageIndex_++; 1067 auto lastNode = primitiveStorageNodes_[currentPrimitiveStorageIndex_]; 1068 result = reinterpret_cast<uintptr_t *>(&lastNode->data()[0]); 1069 primitiveScopeStorageEnd_ = &lastNode->data()[NODE_BLOCK_SIZE]; 1070 } 1071 1072 return result; 1073} 1074 1075void EcmaContext::ShrinkPrimitiveStorage(int prevIndex) 1076{ 1077 currentPrimitiveStorageIndex_ = prevIndex; 1078 int32_t lastIndex = static_cast<int32_t>(primitiveStorageNodes_.size()) - 1; 1079#if ECMASCRIPT_ENABLE_ZAP_MEM 1080 uintptr_t size = ToUintPtr(primitiveScopeStorageEnd_) - ToUintPtr(primitiveScopeStorageNext_); 1081 if (currentPrimitiveStorageIndex_ != -1) { 1082 if (memset_s(primitiveScopeStorageNext_, size, 0, size) != EOK) { 1083 LOG_FULL(FATAL) << "memset_s failed"; 1084 UNREACHABLE(); 1085 } 1086 } 1087 for (int32_t i = currentPrimitiveStorageIndex_ + 1; i < lastIndex; i++) { 1088 if (memset_s(primitiveStorageNodes_[i], 1089 NODE_BLOCK_SIZE * sizeof(JSTaggedType), 0, 1090 NODE_BLOCK_SIZE * sizeof(JSTaggedType)) != 1091 EOK) { 1092 LOG_FULL(FATAL) << "memset_s failed"; 1093 UNREACHABLE(); 1094 } 1095 } 1096#endif 1097 1098 if (lastIndex > MIN_PRIMITIVE_STORAGE_SIZE && currentPrimitiveStorageIndex_ < MIN_PRIMITIVE_STORAGE_SIZE) { 1099 for (int i = MIN_PRIMITIVE_STORAGE_SIZE; i < lastIndex; i++) { 1100 auto node = primitiveStorageNodes_.back(); 1101 delete node; 1102 primitiveStorageNodes_.pop_back(); 1103 } 1104 } 1105} 1106 1107void EcmaContext::LoadStubFile() 1108{ 1109 std::string stubFile = ""; 1110 if (vm_->GetJSOptions().WasStubFileSet()) { 1111 stubFile = vm_->GetJSOptions().GetStubFile(); 1112 } 1113 aotFileManager_->LoadStubFile(stubFile); 1114} 1115 1116bool EcmaContext::LoadAOTFilesInternal(const std::string& aotFileName) 1117{ 1118#ifdef AOT_ESCAPE_ENABLE 1119 std::string bundleName = pgo::PGOProfilerManager::GetInstance()->GetBundleName(); 1120 if (AotCrashInfo::GetInstance().IsAotEscapedOrNotInEnableList(vm_, bundleName)) { 1121 return false; 1122 } 1123#endif 1124 std::string anFile = aotFileName + AOTFileManager::FILE_EXTENSION_AN; 1125 if (!aotFileManager_->LoadAnFile(anFile)) { 1126 LOG_ECMA(WARN) << "Load " << anFile << " failed. Destroy aot data and rollback to interpreter"; 1127 ecmascript::AnFileDataManager::GetInstance()->SafeDestroyAnData(anFile); 1128 return false; 1129 } 1130 1131 std::string aiFile = aotFileName + AOTFileManager::FILE_EXTENSION_AI; 1132 if (!aotFileManager_->LoadAiFile(aiFile)) { 1133 LOG_ECMA(WARN) << "Load " << aiFile << " failed. Destroy aot data and rollback to interpreter"; 1134 ecmascript::AnFileDataManager::GetInstance()->SafeDestroyAnData(anFile); 1135 return false; 1136 } 1137 return true; 1138} 1139 1140bool EcmaContext::LoadAOTFiles(const std::string& aotFileName) 1141{ 1142 return LoadAOTFilesInternal(aotFileName); 1143} 1144 1145#if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM) 1146bool EcmaContext::LoadAOTFiles(const std::string& aotFileName, 1147 std::function<bool(std::string fileName, uint8_t **buff, size_t *buffSize)> cb) 1148{ 1149 aotFileManager_->SetJsAotReader(cb); 1150 return LoadAOTFilesInternal(aotFileName); 1151} 1152#endif 1153 1154void EcmaContext::PrintOptStat() 1155{ 1156 if (optCodeProfiler_ != nullptr) { 1157 optCodeProfiler_->PrintAndReset(); 1158 } 1159} 1160 1161void EcmaContext::DumpAOTInfo() const 1162{ 1163 aotFileManager_->DumpAOTInfo(); 1164} 1165 1166bool EcmaContext::JoinStackPushFastPath(JSHandle<JSTaggedValue> receiver) 1167{ 1168 if (JSTaggedValue::SameValue(joinStack_[0], JSTaggedValue::Hole())) { 1169 joinStack_[0] = receiver.GetTaggedValue(); 1170 return true; 1171 } 1172 return JoinStackPush(receiver); 1173} 1174 1175bool EcmaContext::JoinStackPush(JSHandle<JSTaggedValue> receiver) 1176{ 1177 uint32_t capacity = joinStack_.size(); 1178 JSTaggedValue receiverValue = receiver.GetTaggedValue(); 1179 for (size_t i = 0; i < capacity; ++i) { 1180 if (JSTaggedValue::SameValue(joinStack_[i], JSTaggedValue::Hole())) { 1181 joinStack_[i] = receiverValue; 1182 return true; 1183 } 1184 if (JSTaggedValue::SameValue(joinStack_[i], receiverValue)) { 1185 return false; 1186 } 1187 } 1188 joinStack_.emplace_back(receiverValue); 1189 return true; 1190} 1191 1192void EcmaContext::JoinStackPopFastPath(JSHandle<JSTaggedValue> receiver) 1193{ 1194 uint32_t length = joinStack_.size(); 1195 if (JSTaggedValue::SameValue(joinStack_[0], receiver.GetTaggedValue()) && length == MIN_JOIN_STACK_SIZE) { 1196 joinStack_[0] = JSTaggedValue::Hole(); 1197 } else { 1198 JoinStackPop(receiver); 1199 } 1200} 1201 1202void EcmaContext::JoinStackPop(JSHandle<JSTaggedValue> receiver) 1203{ 1204 uint32_t length = joinStack_.size(); 1205 for (size_t i = 0; i < length; ++i) { 1206 if (JSTaggedValue::SameValue(joinStack_[i], receiver.GetTaggedValue())) { 1207 if (i == 0 && length > MIN_JOIN_STACK_SIZE) { 1208 joinStack_ = {JSTaggedValue::Hole(), JSTaggedValue::Hole()}; 1209 break; 1210 } else { 1211 joinStack_[i] = JSTaggedValue::Hole(); 1212 break; 1213 } 1214 } 1215 } 1216} 1217 1218std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec> EcmaContext::CalCallSiteInfo( 1219 uintptr_t retAddr, bool isDeopt) const 1220{ 1221 auto loader = aotFileManager_; 1222 return loader->CalCallSiteInfo(retAddr, isDeopt); 1223} 1224 1225void EcmaContext::AddSustainingJSHandle(SustainingJSHandle *sustainingHandle) 1226{ 1227 if (sustainingJSHandleList_) { 1228 sustainingJSHandleList_->AddSustainingJSHandle(sustainingHandle); 1229 } 1230} 1231 1232void EcmaContext::RemoveSustainingJSHandle(SustainingJSHandle *sustainingHandle) 1233{ 1234 if (sustainingJSHandleList_) { 1235 sustainingJSHandleList_->RemoveSustainingJSHandle(sustainingHandle); 1236 } 1237} 1238 1239void EcmaContext::ClearKeptObjects() 1240{ 1241 if (LIKELY(GetGlobalEnv()->GetTaggedWeakRefKeepObjects().IsUndefined())) { 1242 return; 1243 } 1244 GetGlobalEnv()->SetWeakRefKeepObjects(thread_, JSTaggedValue::Undefined()); 1245 hasKeptObjects_ = false; 1246} 1247 1248void EcmaContext::AddToKeptObjects(JSHandle<JSTaggedValue> value) 1249{ 1250 if (value->IsInSharedHeap()) { 1251 return; 1252 } 1253 1254 JSHandle<GlobalEnv> globalEnv = GetGlobalEnv(); 1255 JSHandle<LinkedHashSet> linkedSet; 1256 if (globalEnv->GetWeakRefKeepObjects()->IsUndefined()) { 1257 linkedSet = LinkedHashSet::Create(thread_); 1258 } else { 1259 linkedSet = JSHandle<LinkedHashSet>(thread_, 1260 LinkedHashSet::Cast(globalEnv->GetWeakRefKeepObjects()->GetTaggedObject())); 1261 } 1262 linkedSet = LinkedHashSet::Add(thread_, linkedSet, value); 1263 globalEnv->SetWeakRefKeepObjects(thread_, linkedSet); 1264 hasKeptObjects_ = true; 1265} 1266} // namespace panda::ecmascript 1267