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