• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_STACKS_H
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_INTEROP_STACKS_H
18 
19 #include "plugins/ets/runtime/interop_js/interop_common.h"
20 
21 namespace ark::ets::interop::js {
22 
23 class InteropCallStack {
24 public:
InteropCallStack()25     InteropCallStack()
26     {
27         void *pool = ark::os::mem::MapRWAnonymousWithAlignmentRaw(POOL_SIZE, ark::os::mem::GetPageSize());
28         if (pool == nullptr) {
29             InteropFatal("InteropCallStack alloc failed");
30         }
31         startAddr_ = reinterpret_cast<Record *>(pool);
32         endAddr_ = reinterpret_cast<Record *>(ToUintPtr(pool) + POOL_SIZE);
33         curAddr_ = startAddr_;
34     }
35 
~InteropCallStack()36     ~InteropCallStack()
37     {
38         ark::os::mem::UnmapRaw(startAddr_, POOL_SIZE);
39     }
40 
41     struct Record {
RecordRecord42         Record(void *etsCurFrame, char const *codeDescr) : etsFrame(etsCurFrame), descr(codeDescr) {}
43 
44         void *etsFrame {};     // NOLINT(misc-non-private-member-variables-in-classes)
45         char const *descr {};  // NOLINT(misc-non-private-member-variables-in-classes)
46     };
47 
48     template <typename... Args>
AllocRecord(Args &&...args)49     Record *AllocRecord(Args &&...args)
50     {
51         return new (Alloc()) Record(args...);
52     }
53 
PopRecord()54     void PopRecord()
55     {
56         ASSERT(curAddr_ >= startAddr_ && curAddr_ <= endAddr_);
57         if (LIKELY(curAddr_ > startAddr_)) {
58             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
59             (curAddr_--)->~Record();
60             return;
61         }
62         InteropFatal("InteropCallStack is empty");
63     }
64 
Current()65     Record *Current()
66     {
67         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
68         return curAddr_ != startAddr_ ? (curAddr_ - 1) : nullptr;
69     }
70 
GetRecords()71     Span<Record> GetRecords()
72     {
73         return {startAddr_, (ToUintPtr(curAddr_) - ToUintPtr(startAddr_)) / sizeof(Record)};
74     }
75 
76 private:
77     NO_COPY_SEMANTIC(InteropCallStack);
78     NO_MOVE_SEMANTIC(InteropCallStack);
79 
Alloc()80     Record *Alloc()
81     {
82         ASSERT(curAddr_ >= startAddr_ && curAddr_ <= endAddr_);
83         if (LIKELY(curAddr_ < endAddr_)) {
84             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
85             return curAddr_++;
86         }
87         InteropFatal("InteropCallStack overflow");
88     }
89 
90     static constexpr uint32_t MAX_FRAMES = 1024;
91     static constexpr size_t POOL_SIZE = MAX_FRAMES * sizeof(Record);
92 
93     Record *curAddr_ {};
94     Record *startAddr_ {};
95     Record *endAddr_ {};
96 };
97 
98 class LocalScopesStorage {
99 public:
100     LocalScopesStorage() = default;
101 
~LocalScopesStorage()102     ~LocalScopesStorage()
103     {
104         ASSERT(localScopesStorage_.empty());
105     }
106 
107     NO_COPY_SEMANTIC(LocalScopesStorage);
108     NO_MOVE_SEMANTIC(LocalScopesStorage);
109 
CreateLocalScope(napi_env env,Frame * frame)110     void CreateLocalScope(napi_env env, Frame *frame)
111     {
112         napi_handle_scope scope;
113         [[maybe_unused]] auto status = napi_open_handle_scope(env, &scope);
114         ASSERT(status == napi_ok);
115         localScopesStorage_.emplace_back(frame, scope);
116     }
117 
DestroyTopLocalScope(napi_env env,Frame * currFrame)118     void DestroyTopLocalScope(napi_env env, [[maybe_unused]] Frame *currFrame)
119     {
120         ASSERT(!localScopesStorage_.empty());
121         auto &[frame, scope] = localScopesStorage_.back();
122         ASSERT(currFrame == frame);
123         localScopesStorage_.pop_back();
124         [[maybe_unused]] auto status = napi_close_handle_scope(env, scope);
125         ASSERT(status == napi_ok);
126     }
127 
DestroyLocalScopeForTopFrame(napi_env env,Frame * currFrame)128     void DestroyLocalScopeForTopFrame(napi_env env, Frame *currFrame)
129     {
130         if (localScopesStorage_.empty()) {
131             return;
132         }
133         auto &[frame, scope] = localScopesStorage_.back();
134         while (frame == currFrame) {
135             localScopesStorage_.pop_back();
136             [[maybe_unused]] auto status = napi_close_handle_scope(env, scope);
137             ASSERT(status == napi_ok);
138             if (localScopesStorage_.empty()) {
139                 return;
140             }
141             std::tie(frame, scope) = localScopesStorage_.back();
142         }
143     }
144 
145 private:
146     std::vector<std::pair<const Frame *, napi_handle_scope>> localScopesStorage_ {};
147 };
148 
149 }  // namespace ark::ets::interop::js
150 
151 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_STACKS_H
152