• 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 #include "ecmascript/ecma_handle_scope.h"
17 
18 #include "ecmascript/ecma_context.h"
19 #if defined(ENABLE_LOCAL_HANDLE_LEAK_DETECT)
20 #include "ecmascript/dfx/hprof/heap_profiler.h"
21 #endif
22 
23 namespace panda::ecmascript {
EcmaHandleScope(JSThread * thread)24 EcmaHandleScope::EcmaHandleScope(JSThread *thread) : thread_(thread)
25 {
26     auto context = thread_->GetCurrentEcmaContext();
27     OpenHandleScope(context);
28     OpenPrimitiveScope(context);
29 #if defined(ENABLE_LOCAL_HANDLE_LEAK_DETECT)
30     auto vm = thread_->GetEcmaVM();
31     auto heapProfiler = reinterpret_cast<HeapProfiler *>(HeapProfilerInterface::GetInstance(vm));
32     heapProfiler->IncreaseScopeCount();
33     heapProfiler->PushToActiveScopeStack(nullptr, this);
34 #endif
35 }
36 
OpenHandleScope(EcmaContext * context)37 void EcmaHandleScope::OpenHandleScope(EcmaContext *context)
38 {
39     prevNext_ = context->handleScopeStorageNext_;
40     prevEnd_ = context->handleScopeStorageEnd_;
41     prevHandleStorageIndex_ = context->currentHandleStorageIndex_;
42 }
43 
OpenPrimitiveScope(EcmaContext * context)44 void EcmaHandleScope::OpenPrimitiveScope(EcmaContext *context)
45 {
46     prevPrimitiveNext_ = context->primitiveScopeStorageNext_;
47     prevPrimitiveEnd_ = context->primitiveScopeStorageEnd_;
48     prevPrimitiveStorageIndex_ = context->currentPrimitiveStorageIndex_;
49 }
50 
~EcmaHandleScope()51 EcmaHandleScope::~EcmaHandleScope()
52 {
53     auto context = thread_->GetCurrentEcmaContext();
54     CloseHandleScope(context);
55     ClosePrimitiveScope(context);
56 #if defined(ENABLE_LOCAL_HANDLE_LEAK_DETECT)
57     auto vm = thread_->GetEcmaVM();
58     auto heapProfiler = reinterpret_cast<HeapProfiler *>(HeapProfilerInterface::GetInstance(vm));
59     heapProfiler->DecreaseScopeCount();
60     heapProfiler->PopFromActiveScopeStack();
61 #endif
62 }
63 
CloseHandleScope(EcmaContext * context)64 void EcmaHandleScope::CloseHandleScope(EcmaContext *context)
65 {
66     context->handleScopeStorageNext_ = prevNext_;
67     if (context->handleScopeStorageEnd_ != prevEnd_) {
68         context->handleScopeStorageEnd_ = prevEnd_;
69         context->ShrinkHandleStorage(prevHandleStorageIndex_);
70     }
71 }
72 
ClosePrimitiveScope(EcmaContext * context)73 void EcmaHandleScope::ClosePrimitiveScope(EcmaContext *context)
74 {
75     context->primitiveScopeStorageNext_ = prevPrimitiveNext_;
76     if (context->primitiveScopeStorageEnd_ != prevPrimitiveEnd_) {
77         context->primitiveScopeStorageEnd_ = prevPrimitiveEnd_;
78         context->ShrinkPrimitiveStorage(prevPrimitiveStorageIndex_);
79     }
80 }
81 
NewHandle(JSThread * thread,JSTaggedType value)82 uintptr_t EcmaHandleScope::NewHandle(JSThread *thread, JSTaggedType value)
83 {
84     CHECK_NO_HANDLE_ALLOC;
85 #if ECMASCRIPT_ENABLE_THREAD_STATE_CHECK
86     if (UNLIKELY(!thread->IsInRunningStateOrProfiling())) {
87         LOG_ECMA(FATAL) << "New handle must be in jsthread running state";
88         UNREACHABLE();
89     }
90 #endif
91     // Handle is a kind of GC_ROOT, and should only directly hold Obejct or Primitive, not a weak reference.
92     ASSERT(!JSTaggedValue(value).IsWeak());
93     auto context = thread->GetCurrentEcmaContext();
94     auto result = context->handleScopeStorageNext_;
95     if (result == context->handleScopeStorageEnd_) {
96         result = reinterpret_cast<JSTaggedType *>(context->ExpandHandleStorage());
97     }
98 #if ECMASCRIPT_ENABLE_NEW_HANDLE_CHECK
99     thread->CheckJSTaggedType(value);
100     if (result == nullptr) {
101         LOG_ECMA(ERROR) << "result is nullptr, New handle fail!";
102         return 0U;
103     }
104 #endif
105     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
106     context->handleScopeStorageNext_ = result + 1;
107     *result = value;
108 #if defined(ENABLE_LOCAL_HANDLE_LEAK_DETECT)
109     EcmaVM *vm = thread->GetEcmaVM();
110     auto heapProfiler = reinterpret_cast<HeapProfiler *>(HeapProfilerInterface::GetInstance(vm));
111     if (heapProfiler->IsStartLocalHandleLeakDetect()) {
112         heapProfiler->StorePotentiallyLeakHandles(reinterpret_cast<uintptr_t>(result));
113     }
114 #endif  // ENABLE_LOCAL_HANDLE_LEAK_DETECT
115     return reinterpret_cast<uintptr_t>(result);
116 }
117 
NewPrimitiveHandle(JSThread * thread,JSTaggedType value)118 uintptr_t EcmaHandleScope::NewPrimitiveHandle(JSThread *thread, JSTaggedType value)
119 {
120     CHECK_NO_HANDLE_ALLOC;
121     auto context = thread->GetCurrentEcmaContext();
122     auto result = context->primitiveScopeStorageNext_;
123     if (result == context->primitiveScopeStorageEnd_) {
124         result = reinterpret_cast<JSTaggedType *>(context->ExpandPrimitiveStorage());
125     }
126 #if ECMASCRIPT_ENABLE_NEW_HANDLE_CHECK
127     thread->CheckJSTaggedType(value);
128     if (result == nullptr) {
129         LOG_ECMA(ERROR) << "result is nullptr, New primitiveHandle fail!";
130         return 0U;
131     }
132 #endif
133     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
134     context->primitiveScopeStorageNext_ = result + 1;
135     *result = value;
136 #if defined(ENABLE_LOCAL_HANDLE_LEAK_DETECT)
137     EcmaVM *vm = thread->GetEcmaVM();
138     auto heapProfiler = reinterpret_cast<HeapProfiler *>(HeapProfilerInterface::GetInstance(vm));
139     if (heapProfiler->IsStartLocalHandleLeakDetect()) {
140         heapProfiler->StorePotentiallyLeakHandles(reinterpret_cast<uintptr_t>(result));
141     }
142 #endif  // ENABLE_LOCAL_HANDLE_LEAK_DETECT
143     return reinterpret_cast<uintptr_t>(result);
144 }
145 }  // namespace panda::ecmascript