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_); 57 ASSERT(curAddr_ <= endAddr_); 58 if (LIKELY(curAddr_ > startAddr_)) { 59 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 60 (curAddr_--)->~Record(); 61 return; 62 } 63 InteropFatal("InteropCallStack is empty"); 64 } 65 Current()66 Record *Current() 67 { 68 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 69 return curAddr_ != startAddr_ ? (curAddr_ - 1) : nullptr; 70 } 71 GetRecords()72 Span<Record> GetRecords() 73 { 74 return {startAddr_, (ToUintPtr(curAddr_) - ToUintPtr(startAddr_)) / sizeof(Record)}; 75 } 76 77 private: 78 NO_COPY_SEMANTIC(InteropCallStack); 79 NO_MOVE_SEMANTIC(InteropCallStack); 80 Alloc()81 Record *Alloc() 82 { 83 ASSERT(curAddr_ >= startAddr_); 84 ASSERT(curAddr_ <= endAddr_); 85 if (LIKELY(curAddr_ < endAddr_)) { 86 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 87 return curAddr_++; 88 } 89 InteropFatal("InteropCallStack overflow"); 90 } 91 92 static constexpr uint32_t MAX_FRAMES = 1024; 93 static constexpr size_t POOL_SIZE = MAX_FRAMES * sizeof(Record); 94 95 Record *curAddr_ {}; 96 Record *startAddr_ {}; 97 Record *endAddr_ {}; 98 }; 99 100 class LocalScopesStorage { 101 public: 102 LocalScopesStorage() = default; 103 ~LocalScopesStorage()104 ~LocalScopesStorage() 105 { 106 ASSERT(localScopesStorage_.empty()); 107 } 108 109 NO_COPY_SEMANTIC(LocalScopesStorage); 110 NO_MOVE_SEMANTIC(LocalScopesStorage); 111 CreateLocalScope(napi_env env,Frame * frame)112 void CreateLocalScope(napi_env env, Frame *frame) 113 { 114 napi_handle_scope scope; 115 [[maybe_unused]] auto status = napi_open_handle_scope(env, &scope); 116 ASSERT(status == napi_ok); 117 localScopesStorage_.emplace_back(frame, scope); 118 } 119 DestroyTopLocalScope(napi_env env,Frame * currFrame)120 void DestroyTopLocalScope(napi_env env, [[maybe_unused]] Frame *currFrame) 121 { 122 ASSERT(!localScopesStorage_.empty()); 123 auto &[frame, scope] = localScopesStorage_.back(); 124 ASSERT(currFrame == frame); 125 localScopesStorage_.pop_back(); 126 [[maybe_unused]] auto status = napi_close_handle_scope(env, scope); 127 ASSERT(status == napi_ok); 128 } 129 DestroyLocalScopeForTopFrame(napi_env env,Frame * currFrame)130 void DestroyLocalScopeForTopFrame(napi_env env, Frame *currFrame) 131 { 132 if (localScopesStorage_.empty()) { 133 return; 134 } 135 auto &[frame, scope] = localScopesStorage_.back(); 136 while (frame == currFrame) { 137 localScopesStorage_.pop_back(); 138 [[maybe_unused]] auto status = napi_close_handle_scope(env, scope); 139 ASSERT(status == napi_ok); 140 if (localScopesStorage_.empty()) { 141 return; 142 } 143 std::tie(frame, scope) = localScopesStorage_.back(); 144 } 145 } 146 147 private: 148 std::vector<std::pair<const Frame *, napi_handle_scope>> localScopesStorage_ {}; 149 }; 150 151 } // namespace ark::ets::interop::js 152 153 #endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_STACKS_H 154