1 /* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_ECMA_VM_H 17 #define ECMASCRIPT_ECMA_VM_H 18 19 #include <mutex> 20 21 #include "ecmascript/base/config.h" 22 #include "ecmascript/builtins/builtins_method_index.h" 23 #include "ecmascript/ecma_context.h" 24 #include "ecmascript/js_runtime_options.h" 25 #include "ecmascript/js_thread.h" 26 #include "ecmascript/mem/c_containers.h" 27 #include "ecmascript/mem/c_string.h" 28 #include "ecmascript/mem/gc_stats.h" 29 #include "ecmascript/napi/include/dfx_jsnapi.h" 30 #include "ecmascript/napi/include/jsnapi.h" 31 #include "ecmascript/pgo_profiler/pgo_profiler.h" 32 #include "ecmascript/taskpool/taskpool.h" 33 34 namespace panda { 35 class JSNApi; 36 struct HmsMap; 37 namespace panda_file { 38 class File; 39 } // namespace panda_file 40 41 namespace ecmascript { 42 class GlobalEnv; 43 class ObjectFactory; 44 class RegExpParserCache; 45 class EcmaRuntimeStat; 46 class Heap; 47 class HeapTracker; 48 class JSNativePointer; 49 class Program; 50 class GCStats; 51 class CpuProfiler; 52 class Tracing; 53 class RegExpExecResultCache; 54 class JSPromise; 55 enum class PromiseRejectionEvent : uint8_t; 56 class JSPandaFileManager; 57 class JSPandaFile; 58 class EcmaStringTable; 59 class SnapshotEnv; 60 class SnapshotSerialize; 61 class SnapshotProcessor; 62 using PGOProfiler = pgo::PGOProfiler; 63 #if !WIN_OR_MAC_OR_IOS_PLATFORM 64 class HeapProfilerInterface; 65 class HeapProfiler; 66 #endif 67 namespace job { 68 class MicroJobQueue; 69 } // namespace job 70 71 namespace tooling { 72 class JsDebuggerManager; 73 } // namespace tooling 74 75 template<typename T> 76 class JSHandle; 77 class JSArrayBuffer; 78 class JSFunction; 79 class SourceTextModule; 80 class Program; 81 class TSManager; 82 class AOTFileManager; 83 class SlowRuntimeStub; 84 class RequireManager; 85 class QuickFixManager; 86 class ConstantPool; 87 class FunctionCallTimer; 88 class EcmaStringTable; 89 class JSObjectResizingStrategy; 90 class Jit; 91 92 using NativePtrGetter = void* (*)(void* info); 93 using SourceMapCallback = std::function<std::string(const std::string& rawStack)>; 94 using SourceMapTranslateCallback = std::function<bool(std::string& url, int& line, int& column)>; 95 using ResolveBufferCallback = std::function<bool(std::string dirPath, uint8_t **buff, size_t *buffSize)>; 96 using UnloadNativeModuleCallback = std::function<bool(const std::string &moduleKey)>; 97 using RequestAotCallback = 98 std::function<int32_t(const std::string &bundleName, const std::string &moduleName, int32_t triggerMode)>; 99 using SearchHapPathCallBack = std::function<bool(const std::string moduleName, std::string &hapPath)>; 100 using DeviceDisconnectCallback = std::function<bool()>; 101 using UncatchableErrorHandler = std::function<void(panda::TryCatch&)>; 102 class EcmaVM { 103 public: 104 static EcmaVM *Create(const JSRuntimeOptions &options, EcmaParamConfiguration &config); 105 106 static bool Destroy(EcmaVM *vm); 107 108 EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config); 109 110 EcmaVM(); 111 112 ~EcmaVM(); 113 SetLoop(void * loop)114 void SetLoop(void *loop) 115 { 116 loop_ = loop; 117 } 118 GetLoop()119 void *GetLoop() const 120 { 121 return loop_; 122 } 123 IsInitialized()124 bool IsInitialized() const 125 { 126 return initialized_; 127 } 128 GetFactory()129 ObjectFactory *GetFactory() const 130 { 131 return factory_; 132 } 133 134 void InitializePGOProfiler(); 135 void ResetPGOProfiler(); 136 137 bool IsEnablePGOProfiler() const; 138 bool IsEnableElementsKind() const; 139 140 bool Initialize(); 141 GetEcmaGCStats()142 GCStats *GetEcmaGCStats() const 143 { 144 return gcStats_; 145 } 146 GetAssociatedJSThread()147 JSThread *GetAssociatedJSThread() const 148 { 149 return thread_; 150 } 151 GetJSOptions()152 JSRuntimeOptions &GetJSOptions() 153 { 154 return options_; 155 } 156 GetEcmaParamConfiguration()157 const EcmaParamConfiguration &GetEcmaParamConfiguration() const 158 { 159 return ecmaParamConfiguration_; 160 } 161 162 JSHandle<GlobalEnv> GetGlobalEnv() const; 163 ConstCast(const EcmaVM * vm)164 static EcmaVM *ConstCast(const EcmaVM *vm) 165 { 166 return const_cast<EcmaVM *>(vm); 167 } 168 CheckThread()169 void CheckThread() const 170 { 171 // Exclude GC thread 172 if (thread_ == nullptr) { 173 LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this; 174 } 175 if (!Taskpool::GetCurrentTaskpool()->IsInThreadPool(std::this_thread::get_id()) && 176 thread_->GetThreadId() != JSThread::GetCurrentThreadId() && !thread_->IsCrossThreadExecutionEnable()) { 177 LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!" 178 << " thread:" << thread_->GetThreadId() 179 << " currentThread:" << JSThread::GetCurrentThreadId(); 180 } 181 } 182 GetAndFastCheckJSThread()183 JSThread *GetAndFastCheckJSThread() const 184 { 185 if (thread_ == nullptr) { 186 LOG_FULL(FATAL) << "Fatal: ecma_vm has been destructed! vm address is: " << this; 187 } 188 if (thread_->GetThreadId() != JSThread::GetCurrentThreadId() && !thread_->IsCrossThreadExecutionEnable()) { 189 LOG_FULL(FATAL) << "Fatal: ecma_vm cannot run in multi-thread!" 190 << " thread:" << thread_->GetThreadId() 191 << " currentThread:" << JSThread::GetCurrentThreadId(); 192 } 193 return thread_; 194 } 195 GetJSThread()196 ARK_INLINE JSThread *GetJSThread() const 197 { 198 if (options_.EnableThreadCheck()) { 199 CheckThread(); 200 } 201 return thread_; 202 } 203 ICEnabled()204 bool ICEnabled() const 205 { 206 return icEnabled_; 207 } 208 209 void PushToNativePointerList(JSNativePointer *pointer); 210 void RemoveFromNativePointerList(JSNativePointer *pointer); 211 void PushToDeregisterModuleList(CString module); 212 void RemoveFromDeregisterModuleList(CString module); 213 bool ContainInDeregisterModuleList(CString module); 214 JSHandle<ecmascript::JSTaggedValue> GetAndClearEcmaUncaughtException() const; 215 JSHandle<ecmascript::JSTaggedValue> GetEcmaUncaughtException() const; IsOptionalLogEnabled()216 bool IsOptionalLogEnabled() const 217 { 218 return optionalLogEnabled_; 219 } 220 221 void Iterate(const RootVisitor &v, const RootRangeVisitor &rv); 222 GetHeap()223 const Heap *GetHeap() const 224 { 225 return heap_; 226 } 227 void CollectGarbage(TriggerGCType gcType, GCReason reason = GCReason::OTHER) const; 228 GetNativeAreaAllocator()229 NativeAreaAllocator *GetNativeAreaAllocator() const 230 { 231 return nativeAreaAllocator_.get(); 232 } 233 GetHeapRegionAllocator()234 HeapRegionAllocator *GetHeapRegionAllocator() const 235 { 236 return heapRegionAllocator_.get(); 237 } 238 GetChunk()239 Chunk *GetChunk() const 240 { 241 return const_cast<Chunk *>(&chunk_); 242 } 243 void ProcessNativeDelete(const WeakRootVisitor &visitor); 244 void ProcessReferences(const WeakRootVisitor &visitor); 245 GetSnapshotEnv()246 SnapshotEnv *GetSnapshotEnv() const 247 { 248 return snapshotEnv_; 249 } 250 GetJsDebuggerManager()251 tooling::JsDebuggerManager *GetJsDebuggerManager() const 252 { 253 return debuggerManager_; 254 } 255 SetDeviceDisconnectCallback(DeviceDisconnectCallback cb)256 void SetDeviceDisconnectCallback(DeviceDisconnectCallback cb) 257 { 258 deviceDisconnectCallback_ = cb; 259 } 260 GetDeviceDisconnectCallback()261 DeviceDisconnectCallback GetDeviceDisconnectCallback() const 262 { 263 return deviceDisconnectCallback_; 264 } 265 SetEnableForceGC(bool enable)266 void SetEnableForceGC(bool enable) 267 { 268 options_.SetEnableForceGC(enable); 269 } 270 SetNativePtrGetter(NativePtrGetter cb)271 void SetNativePtrGetter(NativePtrGetter cb) 272 { 273 nativePtrGetter_ = cb; 274 } 275 GetNativePtrGetter()276 NativePtrGetter GetNativePtrGetter() const 277 { 278 return nativePtrGetter_; 279 } 280 SetSourceMapCallback(SourceMapCallback cb)281 void SetSourceMapCallback(SourceMapCallback cb) 282 { 283 sourceMapCallback_ = cb; 284 } 285 GetSourceMapCallback()286 SourceMapCallback GetSourceMapCallback() const 287 { 288 return sourceMapCallback_; 289 } 290 SetSourceMapTranslateCallback(SourceMapTranslateCallback cb)291 void SetSourceMapTranslateCallback(SourceMapTranslateCallback cb) 292 { 293 sourceMapTranslateCallback_ = cb; 294 } 295 GetSourceMapTranslateCallback()296 SourceMapTranslateCallback GetSourceMapTranslateCallback() const 297 { 298 return sourceMapTranslateCallback_; 299 } 300 GetNativePointerListSize()301 size_t GetNativePointerListSize() 302 { 303 return nativePointerList_.size(); 304 } 305 GetNativePointerList()306 const CList<JSNativePointer *> GetNativePointerList() const 307 { 308 return nativePointerList_; 309 } 310 SetResolveBufferCallback(ResolveBufferCallback cb)311 void SetResolveBufferCallback(ResolveBufferCallback cb) 312 { 313 resolveBufferCallback_ = cb; 314 } 315 GetResolveBufferCallback()316 ResolveBufferCallback GetResolveBufferCallback() const 317 { 318 return resolveBufferCallback_; 319 } 320 SetSearchHapPathCallBack(SearchHapPathCallBack cb)321 void SetSearchHapPathCallBack(SearchHapPathCallBack cb) 322 { 323 SearchHapPathCallBack_ = cb; 324 } 325 GetSearchHapPathCallBack()326 SearchHapPathCallBack GetSearchHapPathCallBack() const 327 { 328 return SearchHapPathCallBack_; 329 } 330 SetUnloadNativeModuleCallback(const UnloadNativeModuleCallback & cb)331 void SetUnloadNativeModuleCallback(const UnloadNativeModuleCallback &cb) 332 { 333 unloadNativeModuleCallback_ = cb; 334 } 335 GetUnloadNativeModuleCallback()336 UnloadNativeModuleCallback GetUnloadNativeModuleCallback() const 337 { 338 return unloadNativeModuleCallback_; 339 } 340 SetConcurrentCallback(ConcurrentCallback callback,void * data)341 void SetConcurrentCallback(ConcurrentCallback callback, void *data) 342 { 343 concurrentCallback_ = callback; 344 concurrentData_ = data; 345 } 346 347 void TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint); 348 349 void WorkersetInfo(EcmaVM *workerVm); 350 351 EcmaVM *GetWorkerVm(uint32_t tid); 352 353 bool DeleteWorker(EcmaVM *workerVm); 354 355 bool SuspendWorkerVm(uint32_t tid); 356 357 void ResumeWorkerVm(uint32_t tid); 358 359 template<typename Callback> EnumerateWorkerVm(Callback cb)360 void EnumerateWorkerVm(Callback cb) 361 { 362 // since there is a lock, so cannot mark function const 363 LockHolder lock(mutex_); 364 for (const auto &item : workerList_) { 365 cb(item.second); 366 } 367 } 368 IsWorkerThread()369 bool IsWorkerThread() const 370 { 371 return options_.IsWorker(); 372 } 373 IsBundlePack()374 bool IsBundlePack() const 375 { 376 return isBundlePack_; 377 } 378 SetIsBundlePack(bool value)379 void SetIsBundlePack(bool value) 380 { 381 isBundlePack_ = value; 382 } 383 SetMockModuleList(const std::map<std::string,std::string> & list)384 void SetMockModuleList(const std::map<std::string, std::string> &list) 385 { 386 for (auto it = list.begin(); it != list.end(); ++it) { 387 mockModuleList_.emplace(it->first.c_str(), it->second.c_str()); 388 } 389 } 390 IsMockModule(const CString & moduleStr)391 inline bool IsMockModule(const CString &moduleStr) const 392 { 393 if (mockModuleList_.empty()) { 394 return false; 395 } 396 auto it = mockModuleList_.find(moduleStr); 397 if (it == mockModuleList_.end()) { 398 return false; 399 } 400 return true; 401 } 402 GetMockModule(const CString & module)403 inline CString GetMockModule(const CString &module) const 404 { 405 auto it = mockModuleList_.find(module); 406 if (it == mockModuleList_.end()) { 407 LOG_ECMA(FATAL) << " Get Mock Module failed"; 408 } 409 return it->second; 410 } 411 412 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER) 413 void DeleteHeapProfile(); 414 HeapProfilerInterface *GetHeapProfile(); 415 HeapProfilerInterface *GetOrNewHeapProfile(); 416 void StartHeapTracking(); 417 void StopHeapTracking(); 418 #endif 419 EnableReportModuleResolvingFailure()420 bool EnableReportModuleResolvingFailure() const 421 { 422 return options_.EnableReportModuleResolvingFailure(); 423 } 424 SetAssetPath(const CString & assetPath)425 void SetAssetPath(const CString &assetPath) 426 { 427 assetPath_ = assetPath; 428 } 429 GetAssetPath()430 CString GetAssetPath() const 431 { 432 return assetPath_; 433 } 434 SetBundleName(const CString & bundleName)435 void SetBundleName(const CString &bundleName) 436 { 437 bundleName_ = bundleName; 438 } 439 GetBundleName()440 CString GetBundleName() const 441 { 442 return bundleName_; 443 } 444 SetModuleName(const CString & moduleName)445 void SetModuleName(const CString &moduleName) 446 { 447 moduleName_ = moduleName; 448 } 449 GetModuleName()450 CString GetModuleName() const 451 { 452 return moduleName_; 453 } 454 455 std::pair<std::string, std::string> GetCurrentModuleInfo(bool needRecordName = false); 456 457 void SetHmsModuleList(const std::vector<panda::HmsMap> &list); 458 459 bool IsHmsModule(const CString &moduleStr) const; 460 461 CString GetHmsModule(const CString &module) const; 462 463 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) GetProfiler()464 CpuProfiler *GetProfiler() const 465 { 466 return profiler_; 467 } 468 SetProfiler(CpuProfiler * profiler)469 void SetProfiler(CpuProfiler *profiler) 470 { 471 profiler_ = profiler; 472 } 473 #endif 474 475 #if defined(ECMASCRIPT_SUPPORT_TRACING) GetTracing()476 Tracing *GetTracing() const 477 { 478 return tracing_; 479 } 480 SetTracing(Tracing * tracing)481 void SetTracing(Tracing *tracing) 482 { 483 tracing_ = tracing; 484 } 485 #endif 486 GetPGOProfiler()487 std::shared_ptr<PGOProfiler> GetPGOProfiler() const 488 { 489 return pgoProfiler_; 490 } 491 492 void PreFork(); 493 void PostFork(); 494 495 // For Internal Native MethodLiteral. 496 JSTaggedValue GetMethodByIndex(MethodIndex idx); 497 GetQuickFixManager()498 QuickFixManager *GetQuickFixManager() const 499 { 500 return quickFixManager_; 501 } 502 503 JSTaggedValue FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp); 504 505 void HandleUncaughtException(JSTaggedValue exception); RegisterUncatchableErrorHandler(const UncatchableErrorHandler & uncatchableErrorHandler)506 void RegisterUncatchableErrorHandler(const UncatchableErrorHandler &uncatchableErrorHandler) 507 { 508 uncatchableErrorHandler_ = uncatchableErrorHandler; 509 } 510 511 // handle uncatchable errors, such as oom HandleUncatchableError()512 void HandleUncatchableError() 513 { 514 if (uncatchableErrorHandler_ != nullptr) { 515 panda::TryCatch trycatch(this); 516 uncatchableErrorHandler_(trycatch); 517 } 518 } 519 520 void DumpCallTimeInfo(); 521 GetCallTimer()522 FunctionCallTimer *GetCallTimer() const 523 { 524 return callTimer_; 525 } 526 GetEcmaStringTable()527 EcmaStringTable *GetEcmaStringTable() const 528 { 529 ASSERT(stringTable_ != nullptr); 530 return stringTable_; 531 } 532 IncreaseCallDepth()533 void IncreaseCallDepth() 534 { 535 callDepth_++; 536 } 537 DecreaseCallDepth()538 void DecreaseCallDepth() 539 { 540 ASSERT(callDepth_ > 0); 541 callDepth_--; 542 } 543 IsTopLevelCallDepth()544 bool IsTopLevelCallDepth() 545 { 546 return callDepth_ == 0; 547 } 548 SetProfilerState(bool state)549 void SetProfilerState(bool state) 550 { 551 isProfiling_ = state; 552 } 553 GetProfilerState()554 bool GetProfilerState() 555 { 556 return isProfiling_; 557 } 558 GetJSObjectResizingStrategy()559 JSObjectResizingStrategy *GetJSObjectResizingStrategy() 560 { 561 return strategy_; 562 } 563 GetJit()564 Jit *GetJit() 565 { 566 return jit_; 567 } 568 IsEnableJit()569 bool IsEnableJit() const 570 { 571 return isEnableJit_; 572 } 573 GetWorkList()574 CMap<uint32_t, EcmaVM *> GetWorkList() const 575 { 576 return workerList_; 577 } 578 SetEnableJit(bool state)579 void SetEnableJit(bool state) 580 { 581 isEnableJit_ = state; 582 } 583 isOverLimit()584 bool isOverLimit() const 585 { 586 return overLimit_; 587 } 588 SetOverLimit(bool state)589 void SetOverLimit(bool state) 590 { 591 overLimit_ = state; 592 } 593 protected: 594 595 void PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo) const; 596 597 private: 598 void ClearBufferData(); 599 void CheckStartCpuProfiler(); 600 601 // For Internal Native MethodLiteral. 602 void GenerateInternalNativeMethods(); 603 604 NO_MOVE_SEMANTIC(EcmaVM); 605 NO_COPY_SEMANTIC(EcmaVM); 606 607 // VM startup states. 608 JSRuntimeOptions options_; 609 bool icEnabled_ {true}; 610 bool initialized_ {false}; 611 GCStats *gcStats_ {nullptr}; 612 EcmaStringTable *stringTable_; 613 614 // VM memory management. 615 std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_; 616 std::unique_ptr<HeapRegionAllocator> heapRegionAllocator_; 617 Chunk chunk_; 618 Heap *heap_ {nullptr}; 619 ObjectFactory *factory_ {nullptr}; 620 CList<JSNativePointer *> nativePointerList_; 621 // VM execution states. 622 JSThread *thread_ {nullptr}; 623 624 // VM resources. 625 SnapshotEnv *snapshotEnv_ {nullptr}; 626 bool optionalLogEnabled_ {false}; 627 // Debugger 628 tooling::JsDebuggerManager *debuggerManager_ {nullptr}; 629 // merge abc 630 bool isBundlePack_ {true}; // isBundle means app compile mode is JSBundle 631 #if !WIN_OR_MAC_OR_IOS_PLATFORM 632 HeapProfilerInterface *heapProfile_ {nullptr}; 633 #endif 634 CString assetPath_; 635 CString bundleName_; 636 CString moduleName_; 637 CList<CString> deregisterModuleList_; 638 CMap<CString, CString> mockModuleList_; 639 CMap<CString, HmsMap> hmsModuleList_; 640 641 NativePtrGetter nativePtrGetter_ {nullptr}; 642 SourceMapCallback sourceMapCallback_ {nullptr}; 643 SourceMapTranslateCallback sourceMapTranslateCallback_ {nullptr}; 644 void *loop_ {nullptr}; 645 646 // resolve path to get abc's buffer 647 ResolveBufferCallback resolveBufferCallback_ {nullptr}; 648 649 // delete the native module and dlclose so from NativeModuleManager 650 UnloadNativeModuleCallback unloadNativeModuleCallback_ {nullptr}; 651 652 // Concurrent taskpool callback and data 653 ConcurrentCallback concurrentCallback_ {nullptr}; 654 void *concurrentData_ {nullptr}; 655 656 // serch happath callback 657 SearchHapPathCallBack SearchHapPathCallBack_ {nullptr}; 658 659 // vm parameter configurations 660 EcmaParamConfiguration ecmaParamConfiguration_; 661 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 662 CpuProfiler *profiler_ {nullptr}; 663 #endif 664 #if defined(ECMASCRIPT_SUPPORT_TRACING) 665 Tracing *tracing_ {nullptr}; 666 #endif 667 FunctionCallTimer *callTimer_ {nullptr}; 668 JSObjectResizingStrategy *strategy_ {nullptr}; 669 670 // For Native MethodLiteral 671 static void *InternalMethodTable[static_cast<uint8_t>(MethodIndex::METHOD_END)]; 672 CVector<JSTaggedValue> internalNativeMethods_; 673 674 // For repair patch. 675 QuickFixManager *quickFixManager_ {nullptr}; 676 677 // PGO Profiler 678 std::shared_ptr<PGOProfiler> pgoProfiler_ {nullptr}; 679 // c++ call js 680 size_t callDepth_ {0}; 681 682 bool isProfiling_ {false}; 683 684 DeviceDisconnectCallback deviceDisconnectCallback_ {nullptr}; 685 686 UncatchableErrorHandler uncatchableErrorHandler_ {nullptr}; 687 688 friend class Snapshot; 689 friend class SnapshotProcessor; 690 friend class ObjectFactory; 691 friend class ValueSerializer; 692 friend class panda::JSNApi; 693 friend class JSPandaFileExecutor; 694 friend class EcmaContext; 695 CMap<uint32_t, EcmaVM *> workerList_ {}; 696 Mutex mutex_; 697 Jit *jit_ {nullptr}; 698 bool isEnableJit_ {false}; 699 bool overLimit_ {false}; 700 }; 701 } // namespace ecmascript 702 } // namespace panda 703 704 #endif 705