1 /* 2 * Copyright (c) 2021 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_HANDLE_SCOPE_H 17 #define ECMASCRIPT_HANDLE_SCOPE_H 18 19 #include "ecmascript/js_tagged_value.h" 20 #include "ecmascript/js_thread.h" 21 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK 22 #include "ecmascript/platform/backtrace.h" 23 #include "ecmascript/log_wrapper.h" 24 #include "ecmascript/mem/clock_scope.h" 25 #endif 26 27 namespace panda::ecmascript { 28 /* 29 * Handles are only valid within a HandleScope. When a handle is created for an object a cell is allocated in the 30 * current HandleScope. 31 */ 32 class EcmaHandleScope { 33 public: EcmaHandleScope(JSThread * thread)34 inline explicit EcmaHandleScope(JSThread *thread) : 35 thread_(thread), prevNext_(thread->handleScopeStorageNext_), prevEnd_(thread->handleScopeStorageEnd_), 36 prevHandleStorageIndex_(thread->currentHandleStorageIndex_) 37 { 38 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK 39 thread_->HandleScopeCountAdd(); 40 prevHandleScope_ = thread->GetLastHandleScope(); 41 thread_->SetLastHandleScope(this); 42 #endif 43 } 44 ~EcmaHandleScope()45 inline ~EcmaHandleScope() 46 { 47 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK 48 thread_->HandleScopeCountDec(); 49 thread_->SetLastHandleScope(prevHandleScope_); 50 prevHandleScope_ = nullptr; 51 #endif 52 thread_->handleScopeStorageNext_ = prevNext_; 53 if (thread_->handleScopeStorageEnd_ != prevEnd_) { 54 thread_->handleScopeStorageEnd_ = prevEnd_; 55 thread_->ShrinkHandleStorage(prevHandleStorageIndex_); 56 } 57 } 58 NewHandle(JSThread * thread,JSTaggedType value)59 static inline uintptr_t PUBLIC_API NewHandle(JSThread *thread, JSTaggedType value) 60 { 61 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK 62 // Each Handle must be managed by HandleScope, otherwise it may cause Handle leakage. 63 if (thread->handleScopeCount_ <= 0) { 64 LOG_ECMA(ERROR) << "New handle must be in handlescope" << thread->handleScopeCount_; 65 } 66 static const long MAYBE_HANDLE_LEAK_TIME_MS = 5000; 67 if (thread->GetLastHandleScope() != nullptr) { 68 float totalSpentTime = thread->GetLastHandleScope()->scope_.TotalSpentTime(); 69 if (totalSpentTime >= MAYBE_HANDLE_LEAK_TIME_MS) { 70 LOG_ECMA(INFO) << "New handle in scope count:" << thread->handleScopeCount_ 71 << ", time:" << totalSpentTime << "ms"; 72 std::ostringstream stack; 73 Backtrace(stack, true); 74 LOG_ECMA(INFO) << stack.str(); 75 } 76 } 77 #endif 78 #if ECMASCRIPT_ENABLE_NEW_HANDLE_CHECK 79 thread->CheckJSTaggedType(value); 80 #endif 81 auto result = thread->handleScopeStorageNext_; 82 if (result == thread->handleScopeStorageEnd_) { 83 result = reinterpret_cast<JSTaggedType *>(thread->ExpandHandleStorage()); 84 } 85 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 86 thread->handleScopeStorageNext_ = result + 1; 87 *result = value; 88 return reinterpret_cast<uintptr_t>(result); 89 } 90 GetThread()91 JSThread *GetThread() const 92 { 93 return thread_; 94 } 95 96 private: 97 JSThread *thread_; 98 JSTaggedType *prevNext_; 99 JSTaggedType *prevEnd_; 100 int prevHandleStorageIndex_ {-1}; 101 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK 102 ClockScope scope_; 103 EcmaHandleScope *prevHandleScope_ {nullptr}; 104 #endif 105 106 NO_COPY_SEMANTIC(EcmaHandleScope); 107 NO_MOVE_SEMANTIC(EcmaHandleScope); 108 }; 109 } // namespace panda::ecmascript 110 #endif // ECMASCRIPT_HANDLE_SCOPE_H 111