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