1 /* 2 * Copyright (c) 2023 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 #ifndef ECMASCRIPT_ECMA_CONTEXT_H 16 #define ECMASCRIPT_ECMA_CONTEXT_H 17 18 #include <optional> 19 #include "ecmascript/base/config.h" 20 #include "ecmascript/common.h" 21 #include "ecmascript/dfx/vmstat/opt_code_profiler.h" 22 #include "ecmascript/frames.h" 23 #include "ecmascript/js_handle.h" 24 #include "ecmascript/js_tagged_value.h" 25 #include "ecmascript/mem/c_containers.h" 26 #include "ecmascript/mem/visitor.h" 27 #include "ecmascript/regexp/regexp_parser_cache.h" 28 #include "ecmascript/waiter_list.h" 29 #include "libpandafile/file.h" 30 31 namespace panda { 32 class JSNApi; 33 namespace panda_file { 34 class File; 35 } // namespace panda_file 36 37 namespace ecmascript { 38 class GlobalEnv; 39 class ObjectFactory; 40 class EcmaRuntimeStat; 41 class RegExpParserCache; 42 class JSPandaFileManager; 43 class JSPandaFile; 44 class ConstantPool; 45 class JSPromise; 46 class RegExpExecResultCache; 47 class EcmaHandleScope; 48 enum class PromiseRejectionEvent : uint8_t; 49 50 template<typename T> 51 class JSHandle; 52 class JSThread; 53 class JSFunction; 54 class JSPromise; 55 class JSTaggedValue; 56 class EcmaVM; 57 class ModuleManager; 58 class TSManager; 59 class AOTFileManager; 60 class QuickFixManager; 61 class OptCodeProfiler; 62 struct CJSInfo; 63 64 namespace job { 65 class MicroJobQueue; 66 } // namespace job 67 namespace tooling { 68 class JsDebuggerManager; 69 } // namespace tooling 70 71 enum class IcuFormatterType { 72 SIMPLE_DATE_FORMAT_DEFAULT, 73 SIMPLE_DATE_FORMAT_DATE, 74 SIMPLE_DATE_FORMAT_TIME, 75 NUMBER_FORMATTER, 76 COLLATOR 77 }; 78 79 using HostPromiseRejectionTracker = void (*)(const EcmaVM* vm, 80 const JSHandle<JSPromise> promise, 81 const JSHandle<JSTaggedValue> reason, 82 PromiseRejectionEvent operation, 83 void* data); 84 using PromiseRejectCallback = void (*)(void* info); 85 using IcuDeleteEntry = void(*)(void *pointer, void *data); 86 class EcmaContext { 87 public: 88 static EcmaContext *CreateAndInitialize(JSThread *thread); 89 static void CheckAndDestroy(JSThread *thread, EcmaContext *context); 90 91 static EcmaContext *Create(JSThread *thread); 92 static bool Destroy(EcmaContext *context); 93 94 EcmaContext(JSThread *thread); 95 ~EcmaContext(); 96 GetEcmaVM()97 EcmaVM *GetEcmaVM() const 98 { 99 return vm_; 100 } 101 102 bool Initialize(); 103 104 bool ExecutePromisePendingJob(); 105 ConstCast(const EcmaContext * context)106 static EcmaContext *ConstCast(const EcmaContext *context) 107 { 108 return const_cast<EcmaContext *>(context); 109 } 110 IsInitialized()111 bool IsInitialized() const 112 { 113 return initialized_; 114 } 115 GetModuleManager()116 ModuleManager *GetModuleManager() const 117 { 118 return moduleManager_; 119 } 120 GetTSManager()121 TSManager *GetTSManager() const 122 { 123 return tsManager_; 124 } 125 GetJSThread()126 ARK_INLINE JSThread *GetJSThread() const 127 { 128 return thread_; 129 } GetPromiseRejectCallback()130 PromiseRejectCallback GetPromiseRejectCallback() const 131 { 132 return promiseRejectCallback_; 133 } 134 SetPromiseRejectCallback(PromiseRejectCallback cb)135 void SetPromiseRejectCallback(PromiseRejectCallback cb) 136 { 137 promiseRejectCallback_ = cb; 138 } 139 SetData(void * data)140 void SetData(void* data) 141 { 142 data_ = data; 143 } 144 PromiseRejectionTracker(const JSHandle<JSPromise> & promise,const JSHandle<JSTaggedValue> & reason,PromiseRejectionEvent operation)145 void PromiseRejectionTracker(const JSHandle<JSPromise> &promise, 146 const JSHandle<JSTaggedValue> &reason, PromiseRejectionEvent operation) 147 { 148 if (hostPromiseRejectionTracker_ != nullptr) { 149 hostPromiseRejectionTracker_(vm_, promise, reason, operation, data_); 150 } 151 } 152 SetHostPromiseRejectionTracker(HostPromiseRejectionTracker cb)153 void SetHostPromiseRejectionTracker(HostPromiseRejectionTracker cb) 154 { 155 hostPromiseRejectionTracker_ = cb; 156 } 157 void SetupRegExpResultCache(); GetRegExpCache()158 JSHandle<JSTaggedValue> GetRegExpCache() const 159 { 160 return JSHandle<JSTaggedValue>(reinterpret_cast<uintptr_t>(®expCache_)); 161 } 162 GetRegExpParserCache()163 RegExpParserCache *GetRegExpParserCache() const 164 { 165 ASSERT(regExpParserCache_ != nullptr); 166 return regExpParserCache_; 167 } 168 SetRegExpCache(JSTaggedValue newCache)169 void SetRegExpCache(JSTaggedValue newCache) 170 { 171 regexpCache_ = newCache; 172 } GetExpCacheAddress()173 uintptr_t GetExpCacheAddress() 174 { 175 return reinterpret_cast<uintptr_t>(®expCache_); 176 } 177 GetWaiterListNode()178 WaiterListNode *GetWaiterListNode() 179 { 180 return &waiterListNode_; 181 } 182 SetAllowAtomicWait(bool wait)183 void SetAllowAtomicWait(bool wait) 184 { 185 AllowAtomicWait_ = wait; 186 } 187 GetAllowAtomicWait()188 bool GetAllowAtomicWait() const 189 { 190 return AllowAtomicWait_; 191 } 192 JSHandle<ecmascript::JSTaggedValue> GetAndClearEcmaUncaughtException() const; 193 JSHandle<ecmascript::JSTaggedValue> GetEcmaUncaughtException() const; 194 void EnableUserUncaughtErrorHandler(); 195 196 void AddConstpool(const JSPandaFile *jsPandaFile, JSTaggedValue constpool, int32_t index = 0); 197 198 bool HasCachedConstpool(const JSPandaFile *jsPandaFile) const; 199 200 JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile, int32_t index); 201 // For new version instruction. 202 JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id); 203 std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> FindConstpools( 204 const JSPandaFile *jsPandaFile); 205 206 JSHandle<ConstantPool> PUBLIC_API FindOrCreateConstPool(const JSPandaFile *jsPandaFile, 207 panda_file::File::EntityId id); 208 void CreateAllConstpool(const JSPandaFile *jsPandaFile); 209 210 void HandleUncaughtException(JSTaggedValue exception); 211 void ProcessNativeDelete(const WeakRootVisitor &visitor); 212 void ProcessReferences(const WeakRootVisitor &visitor); 213 JSHandle<GlobalEnv> GetGlobalEnv() const; GlobalEnvIsHole()214 bool GlobalEnvIsHole() 215 { 216 return globalEnv_.IsHole(); 217 } 218 219 JSHandle<job::MicroJobQueue> GetMicroJobQueue() const; 220 221 static void PrintJSErrorInfo(JSThread *thread, const JSHandle<JSTaggedValue> &exceptionInfo); 222 void Iterate(const RootVisitor &v, const RootRangeVisitor &rv); 223 static void MountContext(JSThread *thread); 224 static void UnmountContext(JSThread *thread); 225 void SetMicroJobQueue(job::MicroJobQueue *queue); 226 void SetGlobalEnv(GlobalEnv *global); 227 void PrintOptStat(); 228 GetOptCodeProfiler()229 OptCodeProfiler *GetOptCodeProfiler() const 230 { 231 return optCodeProfiler_; 232 } 233 234 // For icu objects cache 235 void SetIcuFormatterToCache(IcuFormatterType type, const std::string &locale, void *icuObj, 236 IcuDeleteEntry deleteEntry = nullptr) 237 { 238 EcmaContext::IcuFormatter icuFormatter = IcuFormatter(locale, icuObj, deleteEntry); 239 icuObjCache_.insert_or_assign(type, std::move(icuFormatter)); 240 } 241 GetIcuFormatterFromCache(IcuFormatterType type,std::string locale)242 void *GetIcuFormatterFromCache(IcuFormatterType type, std::string locale) 243 { 244 auto iter = icuObjCache_.find(type); 245 if (iter != icuObjCache_.end()) { 246 EcmaContext::IcuFormatter icuFormatter = iter->second; 247 if (icuFormatter.locale == locale) { 248 return icuFormatter.icuObj; 249 } 250 } 251 return nullptr; 252 } 253 ClearIcuCache()254 void ClearIcuCache() 255 { 256 auto iter = icuObjCache_.begin(); 257 while (iter != icuObjCache_.end()) { 258 EcmaContext::IcuFormatter icuFormatter = iter->second; 259 IcuDeleteEntry deleteEntry = icuFormatter.deleteEntry; 260 if (deleteEntry != nullptr) { 261 deleteEntry(icuFormatter.icuObj, vm_); 262 } 263 iter->second = EcmaContext::IcuFormatter{}; 264 iter++; 265 } 266 } 267 GetAOTFileManager()268 AOTFileManager *GetAOTFileManager() const 269 { 270 return aotFileManager_; 271 } 272 GetRuntimeStat()273 EcmaRuntimeStat *GetRuntimeStat() const 274 { 275 return runtimeStat_; 276 } 277 278 void SetRuntimeStatEnable(bool flag); 279 void InitializeEcmaScriptRunStat(); 280 void DumpAOTInfo() const DUMP_API_ATTR; 281 282 JSTaggedValue ExecuteAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp, 283 bool needPushUndefined); 284 void LoadStubFile(); 285 GetHandleScopeStorageNext()286 JSTaggedType *GetHandleScopeStorageNext() const 287 { 288 return handleScopeStorageNext_; 289 } 290 SetHandleScopeStorageNext(JSTaggedType * value)291 void SetHandleScopeStorageNext(JSTaggedType *value) 292 { 293 handleScopeStorageNext_ = value; 294 } 295 GetHandleScopeStorageEnd()296 JSTaggedType *GetHandleScopeStorageEnd() const 297 { 298 return handleScopeStorageEnd_; 299 } 300 SetHandleScopeStorageEnd(JSTaggedType * value)301 void SetHandleScopeStorageEnd(JSTaggedType *value) 302 { 303 handleScopeStorageEnd_ = value; 304 } 305 GetCurrentHandleStorageIndex()306 int GetCurrentHandleStorageIndex() const 307 { 308 return currentHandleStorageIndex_; 309 } 310 HandleScopeCountAdd()311 void HandleScopeCountAdd() 312 { 313 handleScopeCount_++; 314 } 315 HandleScopeCountDec()316 void HandleScopeCountDec() 317 { 318 handleScopeCount_--; 319 } 320 SetLastHandleScope(EcmaHandleScope * scope)321 void SetLastHandleScope(EcmaHandleScope *scope) 322 { 323 lastHandleScope_ = scope; 324 } 325 GetLastHandleScope()326 EcmaHandleScope *GetLastHandleScope() const 327 { 328 return lastHandleScope_; 329 } 330 331 size_t IterateHandle(const RootRangeVisitor &rangeVisitor); 332 uintptr_t *ExpandHandleStorage(); 333 void ShrinkHandleStorage(int prevIndex); 334 GetCurrentFrame()335 JSTaggedType *GetCurrentFrame() const 336 { 337 return currentFrame_; 338 } 339 GetLeaveFrame()340 JSTaggedType *GetLeaveFrame() const 341 { 342 return leaveFrame_; 343 } 344 GetLastFp()345 JSTaggedType *GetLastFp() const 346 { 347 return lastFp_; 348 } 349 SetFramePointers(JSTaggedType * currentFrame,JSTaggedType * leaveFrame,JSTaggedType * lastFp)350 void SetFramePointers(JSTaggedType *currentFrame, JSTaggedType *leaveFrame, JSTaggedType *lastFp) 351 { 352 currentFrame_ = currentFrame; 353 leaveFrame_ = leaveFrame; 354 lastFp_ = lastFp; 355 } SetFrameBase(JSTaggedType * frameBase)356 void SetFrameBase(JSTaggedType *frameBase) 357 { 358 frameBase_ = frameBase; 359 } GetFrameBase()360 JSTaggedType *GetFrameBase() const 361 { 362 return frameBase_; 363 } 364 SetStackStart(uint64_t stackStart)365 void SetStackStart(uint64_t stackStart) 366 { 367 stackStart_ = stackStart; 368 } GetStackStart()369 uint64_t GetStackStart() const 370 { 371 return stackStart_; 372 } SetStackLimit(uint64_t stackLimit)373 void SetStackLimit(uint64_t stackLimit) 374 { 375 stackLimit_ = stackLimit; 376 } GetStackLimit()377 uint64_t GetStackLimit() const 378 { 379 return stackLimit_; 380 } 381 GetPropertiesCache()382 PropertiesCache *GetPropertiesCache() const 383 { 384 return propertiesCache_; 385 } 386 void ClearBufferData(); GlobalConstants()387 const GlobalEnvConstants *GlobalConstants() const 388 { 389 return &globalConst_; 390 } 391 392 bool JoinStackPushFastPath(JSHandle<JSTaggedValue> receiver); 393 bool JoinStackPush(JSHandle<JSTaggedValue> receiver); 394 void JoinStackPopFastPath(JSHandle<JSTaggedValue> receiver); 395 void JoinStackPop(JSHandle<JSTaggedValue> receiver); 396 397 private: 398 void CJSExecution(JSHandle<JSFunction> &func, JSHandle<JSTaggedValue> &thisArg, 399 const JSPandaFile *jsPandaFile, std::string_view entryPoint); 400 JSTaggedValue InvokeEcmaAotEntrypoint(JSHandle<JSFunction> mainFunc, JSHandle<JSTaggedValue> &thisArg, 401 const JSPandaFile *jsPandaFile, std::string_view entryPoint, 402 CJSInfo *cjsInfo = nullptr); 403 Expected<JSTaggedValue, bool> InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, std::string_view entryPoint, 404 bool excuteFromJob = false); 405 bool LoadAOTFiles(const std::string &aotFileName); 406 NO_MOVE_SEMANTIC(EcmaContext); 407 NO_COPY_SEMANTIC(EcmaContext); 408 409 JSThread *thread_ {nullptr}; 410 EcmaVM *vm_ {nullptr}; 411 412 bool isUncaughtExceptionRegistered_ {false}; 413 bool isProcessingPendingJob_ {false}; 414 bool initialized_ {false}; 415 ObjectFactory *factory_ {nullptr}; 416 417 // VM execution states. 418 RegExpParserCache *regExpParserCache_ {nullptr}; 419 JSTaggedValue globalEnv_ {JSTaggedValue::Hole()}; 420 JSTaggedValue regexpCache_ {JSTaggedValue::Hole()}; 421 JSTaggedValue microJobQueue_ {JSTaggedValue::Hole()}; 422 EcmaRuntimeStat *runtimeStat_ {nullptr}; 423 424 CMap<const JSPandaFile *, CMap<int32_t, JSTaggedValue>> cachedConstpools_ {}; 425 426 // VM resources. 427 ModuleManager *moduleManager_ {nullptr}; 428 TSManager *tsManager_ {nullptr}; 429 AOTFileManager *aotFileManager_ {nullptr}; 430 431 // atomics 432 bool AllowAtomicWait_ {true}; 433 WaiterListNode waiterListNode_; 434 435 // Registered Callbacks 436 PromiseRejectCallback promiseRejectCallback_ {nullptr}; 437 HostPromiseRejectionTracker hostPromiseRejectionTracker_ {nullptr}; 438 void* data_{nullptr}; 439 440 // opt code Profiler 441 OptCodeProfiler *optCodeProfiler_ {nullptr}; 442 443 // For icu objects cache 444 struct IcuFormatter { 445 std::string locale; 446 void *icuObj {nullptr}; 447 IcuDeleteEntry deleteEntry {nullptr}; 448 449 IcuFormatter() = default; 450 IcuFormatter(const std::string &locale, void *icuObj, IcuDeleteEntry deleteEntry = nullptr) localeIcuFormatter451 : locale(locale), icuObj(icuObj), deleteEntry(deleteEntry) {} 452 }; 453 std::unordered_map<IcuFormatterType, IcuFormatter> icuObjCache_; 454 455 // Handlescope 456 static const uint32_t NODE_BLOCK_SIZE_LOG2 = 10; 457 static const uint32_t NODE_BLOCK_SIZE = 1U << NODE_BLOCK_SIZE_LOG2; 458 static constexpr int32_t MIN_HANDLE_STORAGE_SIZE = 2; 459 JSTaggedType *handleScopeStorageNext_ {nullptr}; 460 JSTaggedType *handleScopeStorageEnd_ {nullptr}; 461 std::vector<std::array<JSTaggedType, NODE_BLOCK_SIZE> *> handleStorageNodes_ {}; 462 int32_t currentHandleStorageIndex_ {-1}; 463 int32_t handleScopeCount_ {0}; 464 EcmaHandleScope *lastHandleScope_ {nullptr}; 465 // Frame pointer 466 JSTaggedType *currentFrame_ {nullptr}; 467 JSTaggedType *leaveFrame_ {nullptr}; 468 JSTaggedType *lastFp_ {nullptr}; 469 JSTaggedType *frameBase_ {nullptr}; 470 uint64_t stackStart_ {0}; 471 uint64_t stackLimit_ {0}; 472 PropertiesCache *propertiesCache_ {nullptr}; 473 GlobalEnvConstants globalConst_; 474 // Join Stack 475 static constexpr uint32_t MIN_JOIN_STACK_SIZE = 2; 476 CVector<JSTaggedValue> joinStack_ {JSTaggedValue::Hole(), JSTaggedValue::Hole()}; 477 478 friend class EcmaHandleScope; 479 friend class JSPandaFileExecutor; 480 friend class ObjectFactory; 481 friend class panda::JSNApi; 482 friend class AOTFileManager; 483 }; 484 } // namespace ecmascript 485 } // namespace panda 486 #endif // ECMASCRIPT_ECMA_CONTEXT_H 487