• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>(&regexpCache_));
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>(&regexpCache_);
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