1 /*
2 * Copyright (c) 2023 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
20 namespace panda::ecmascript {
EcmaHandleScope(JSThread * thread)21 EcmaHandleScope::EcmaHandleScope(JSThread *thread) : thread_(thread)
22 {
23 auto context = thread_->GetCurrentEcmaContext();
24 prevNext_ = context->handleScopeStorageNext_;
25 prevEnd_ = context->handleScopeStorageEnd_;
26 prevHandleStorageIndex_ = context->currentHandleStorageIndex_;
27 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK
28 context->HandleScopeCountAdd();
29 prevHandleScope_ = context->GetLastHandleScope();
30 context->SetLastHandleScope(this);
31 #endif
32 }
33
~EcmaHandleScope()34 EcmaHandleScope::~EcmaHandleScope()
35 {
36 auto context = thread_->GetCurrentEcmaContext();
37 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK
38 context->HandleScopeCountDec();
39 context->SetLastHandleScope(prevHandleScope_);
40 prevHandleScope_ = nullptr;
41 #endif
42 context->handleScopeStorageNext_ = prevNext_;
43 if (context->handleScopeStorageEnd_ != prevEnd_) {
44 context->handleScopeStorageEnd_ = prevEnd_;
45 context->ShrinkHandleStorage(prevHandleStorageIndex_);
46 }
47 }
48
NewHandle(JSThread * thread,JSTaggedType value)49 uintptr_t EcmaHandleScope::NewHandle(JSThread *thread, JSTaggedType value)
50 {
51 auto context = thread->GetCurrentEcmaContext();
52 #ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK
53 // Each Handle must be managed by HandleScope, otherwise it may cause Handle leakage.
54 if (context->handleScopeCount_ <= 0) {
55 LOG_ECMA(ERROR) << "New handle must be in handlescope" << context->handleScopeCount_;
56 }
57 static const long MAYBE_HANDLE_LEAK_TIME_MS = 5000;
58 if (context->GetLastHandleScope() != nullptr) {
59 float totalSpentTime = context->GetLastHandleScope()->scope_.TotalSpentTime();
60 if (totalSpentTime >= MAYBE_HANDLE_LEAK_TIME_MS) {
61 LOG_ECMA(INFO) << "New handle in scope count:" << context->handleScopeCount_
62 << ", time:" << totalSpentTime << "ms";
63 std::ostringstream stack;
64 Backtrace(stack, true);
65 LOG_ECMA(INFO) << stack.str();
66 }
67 }
68 #endif
69 auto result = context->handleScopeStorageNext_;
70 if (result == context->handleScopeStorageEnd_) {
71 result = reinterpret_cast<JSTaggedType *>(context->ExpandHandleStorage());
72 }
73 #if ECMASCRIPT_ENABLE_NEW_HANDLE_CHECK
74 thread->CheckJSTaggedType(value);
75 if (result == nullptr) {
76 LOG_ECMA(ERROR) << "result is nullptr, New handle fail!";
77 return nullptr;
78 }
79 #endif
80 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
81 context->handleScopeStorageNext_ = result + 1;
82 *result = value;
83 return reinterpret_cast<uintptr_t>(result);
84 }
85 } // namespace panda::ecmascript