• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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