• 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 #include "ecmascript/js_thread.h"
17 #include "ecmascript/log_wrapper.h"
18 #include "ecmascript/platform/file.h"
19 #if defined(ENABLE_EXCEPTION_BACKTRACE)
20 #include "ecmascript/platform/backtrace.h"
21 #endif
22 #include "ecmascript/ecma_global_storage.h"
23 #include "ecmascript/ecma_param_configuration.h"
24 #include "ecmascript/global_env_constants-inl.h"
25 #include "ecmascript/ic/properties_cache.h"
26 #include "ecmascript/interpreter/interpreter-inl.h"
27 #include "ecmascript/mem/mark_word.h"
28 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
29 
30 namespace panda::ecmascript {
31 using CommonStubCSigns = panda::ecmascript::kungfu::CommonStubCSigns;
32 using BytecodeStubCSigns = panda::ecmascript::kungfu::BytecodeStubCSigns;
33 
34 // static
Create(EcmaVM * vm)35 JSThread *JSThread::Create(EcmaVM *vm)
36 {
37     auto jsThread = new JSThread(vm);
38     AsmInterParsedOption asmInterOpt = vm->GetJSOptions().GetAsmInterParsedOption();
39     if (asmInterOpt.enableAsm) {
40         jsThread->EnableAsmInterpreter();
41     }
42 
43     jsThread->nativeAreaAllocator_ = vm->GetNativeAreaAllocator();
44     jsThread->heapRegionAllocator_ = vm->GetHeapRegionAllocator();
45     // algin with 16
46     size_t maxStackSize = vm->GetEcmaParamConfiguration().GetMaxStackSize();
47     jsThread->glueData_.frameBase_ = static_cast<JSTaggedType *>(
48         vm->GetNativeAreaAllocator()->Allocate(sizeof(JSTaggedType) * maxStackSize));
49     jsThread->glueData_.currentFrame_ = jsThread->glueData_.frameBase_ + maxStackSize;
50     EcmaInterpreter::InitStackFrame(jsThread);
51 
52     if (jsThread->IsAsmInterpreter()) {
53         jsThread->glueData_.stackLimit_ = GetAsmStackLimit();
54         jsThread->glueData_.stackStart_ = GetCurrentStackPosition();
55     }
56     return jsThread;
57 }
58 
JSThread(EcmaVM * vm)59 JSThread::JSThread(EcmaVM *vm) : id_(os::thread::GetCurrentThreadId()), vm_(vm)
60 {
61     auto chunk = vm->GetChunk();
62     if (!vm_->GetJSOptions().EnableGlobalLeakCheck()) {
63         globalStorage_ = chunk->New<EcmaGlobalStorage<Node>>(this, vm->GetNativeAreaAllocator());
64         newGlobalHandle_ = std::bind(&EcmaGlobalStorage<Node>::NewGlobalHandle, globalStorage_, std::placeholders::_1);
65         disposeGlobalHandle_ = std::bind(&EcmaGlobalStorage<Node>::DisposeGlobalHandle, globalStorage_,
66             std::placeholders::_1);
67         setWeak_ = std::bind(&EcmaGlobalStorage<Node>::SetWeak, globalStorage_, std::placeholders::_1,
68             std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
69         clearWeak_ = std::bind(&EcmaGlobalStorage<Node>::ClearWeak, globalStorage_, std::placeholders::_1);
70         isWeak_ = std::bind(&EcmaGlobalStorage<Node>::IsWeak, globalStorage_, std::placeholders::_1);
71     } else {
72         globalDebugStorage_ =
73             chunk->New<EcmaGlobalStorage<DebugNode>>(this, vm->GetNativeAreaAllocator());
74         newGlobalHandle_ = std::bind(&EcmaGlobalStorage<DebugNode>::NewGlobalHandle, globalDebugStorage_,
75             std::placeholders::_1);
76         disposeGlobalHandle_ = std::bind(&EcmaGlobalStorage<DebugNode>::DisposeGlobalHandle, globalDebugStorage_,
77             std::placeholders::_1);
78         setWeak_ = std::bind(&EcmaGlobalStorage<DebugNode>::SetWeak, globalDebugStorage_, std::placeholders::_1,
79             std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
80         clearWeak_ = std::bind(&EcmaGlobalStorage<DebugNode>::ClearWeak, globalDebugStorage_, std::placeholders::_1);
81         isWeak_ = std::bind(&EcmaGlobalStorage<DebugNode>::IsWeak, globalDebugStorage_, std::placeholders::_1);
82     }
83     propertiesCache_ = new PropertiesCache();
84     vmThreadControl_ = new VmThreadControl();
85 }
86 
~JSThread()87 JSThread::~JSThread()
88 {
89     for (auto n : handleStorageNodes_) {
90         delete n;
91     }
92     handleStorageNodes_.clear();
93     currentHandleStorageIndex_ = -1;
94     handleScopeCount_ = 0;
95     handleScopeStorageNext_ = handleScopeStorageEnd_ = nullptr;
96     if (globalStorage_ != nullptr) {
97         GetEcmaVM()->GetChunk()->Delete(globalStorage_);
98         globalStorage_ = nullptr;
99     }
100     if (globalDebugStorage_) {
101         GetEcmaVM()->GetChunk()->Delete(globalDebugStorage_);
102         globalDebugStorage_ = nullptr;
103     }
104 
105     GetNativeAreaAllocator()->Free(glueData_.frameBase_, sizeof(JSTaggedType) *
106         vm_->GetEcmaParamConfiguration().GetMaxStackSize());
107     glueData_.frameBase_ = nullptr;
108     nativeAreaAllocator_ = nullptr;
109     heapRegionAllocator_ = nullptr;
110     if (propertiesCache_ != nullptr) {
111         delete propertiesCache_;
112         propertiesCache_ = nullptr;
113     }
114     if (vmThreadControl_ != nullptr) {
115         delete vmThreadControl_;
116         vmThreadControl_ = nullptr;
117     }
118 }
119 
SetException(JSTaggedValue exception)120 void JSThread::SetException(JSTaggedValue exception)
121 {
122     glueData_.exception_ = exception;
123 #if defined(ENABLE_EXCEPTION_BACKTRACE)
124     if (vm_->GetJSOptions().EnableExceptionBacktrace()) {
125         LOG_ECMA(INFO) << "SetException:" << exception.GetRawData();
126         std::ostringstream stack;
127         Backtrace(stack);
128         LOG_ECMA(INFO) << stack.str();
129     }
130 #endif
131 }
132 
ClearException()133 void JSThread::ClearException()
134 {
135     glueData_.exception_ = JSTaggedValue::Hole();
136 }
137 
GetCurrentLexenv() const138 JSTaggedValue JSThread::GetCurrentLexenv() const
139 {
140     FrameHandler frameHandler(this);
141     return frameHandler.GetEnv();
142 }
143 
GetCurrentFrame() const144 const JSTaggedType *JSThread::GetCurrentFrame() const
145 {
146     if (IsAsmInterpreter()) {
147         return GetLastLeaveFrame();
148     }
149     return GetCurrentSPFrame();
150 }
151 
SetCurrentFrame(JSTaggedType * sp)152 void JSThread::SetCurrentFrame(JSTaggedType *sp)
153 {
154     if (IsAsmInterpreter()) {
155         return SetLastLeaveFrame(sp);
156     }
157     return SetCurrentSPFrame(sp);
158 }
159 
GetCurrentInterpretedFrame() const160 const JSTaggedType *JSThread::GetCurrentInterpretedFrame() const
161 {
162     if (IsAsmInterpreter()) {
163         auto frameHandler = FrameHandler(this);
164         return frameHandler.GetSp();
165     }
166     return GetCurrentSPFrame();
167 }
168 
IsStartGlobalLeakCheck() const169 bool JSThread::IsStartGlobalLeakCheck() const
170 {
171     return GetEcmaVM()->GetJSOptions().IsStartGlobalLeakCheck();
172 }
173 
EnableGlobalObjectLeakCheck() const174 bool JSThread::EnableGlobalObjectLeakCheck() const
175 {
176     return GetEcmaVM()->GetJSOptions().EnableGlobalObjectLeakCheck();
177 }
178 
EnableGlobalPrimitiveLeakCheck() const179 bool JSThread::EnableGlobalPrimitiveLeakCheck() const
180 {
181     return GetEcmaVM()->GetJSOptions().EnableGlobalPrimitiveLeakCheck();
182 }
183 
WriteToStackTraceFd(std::ostringstream & buffer) const184 void JSThread::WriteToStackTraceFd(std::ostringstream &buffer) const
185 {
186     if (stackTraceFd_ < 0) {
187         return;
188     }
189     buffer << std::endl;
190     DPrintf(reinterpret_cast<fd_t>(stackTraceFd_), buffer.str());
191     buffer.str("");
192 }
193 
SetStackTraceFd(int32_t fd)194 void JSThread::SetStackTraceFd(int32_t fd)
195 {
196     stackTraceFd_ = fd;
197 }
198 
CloseStackTraceFd()199 void JSThread::CloseStackTraceFd()
200 {
201     if (stackTraceFd_ != -1) {
202         FSync(reinterpret_cast<fd_t>(stackTraceFd_));
203         Close(reinterpret_cast<fd_t>(stackTraceFd_));
204         stackTraceFd_ = -1;
205     }
206 }
207 
Iterate(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor,const RootBaseAndDerivedVisitor & derivedVisitor)208 void JSThread::Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
209     const RootBaseAndDerivedVisitor &derivedVisitor)
210 {
211     if (propertiesCache_ != nullptr) {
212         propertiesCache_->Clear();
213     }
214 
215     if (!glueData_.exception_.IsHole()) {
216         visitor(Root::ROOT_VM, ObjectSlot(ToUintPtr(&glueData_.exception_)));
217     }
218     // visit global Constant
219     glueData_.globalConst_.VisitRangeSlot(rangeVisitor);
220     // visit stack roots
221     FrameHandler frameHandler(this);
222     frameHandler.Iterate(visitor, rangeVisitor, derivedVisitor);
223     // visit tagged handle storage roots
224     if (vm_->GetJSOptions().EnableGlobalLeakCheck()) {
225         IterateHandleWithCheck(visitor, rangeVisitor);
226     } else {
227         if (currentHandleStorageIndex_ != -1) {
228             int32_t nid = currentHandleStorageIndex_;
229             for (int32_t i = 0; i <= nid; ++i) {
230                 auto node = handleStorageNodes_.at(i);
231                 auto start = node->data();
232                 auto end = (i != nid) ? &(node->data()[NODE_BLOCK_SIZE]) : handleScopeStorageNext_;
233                 rangeVisitor(ecmascript::Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(start)), ObjectSlot(ToUintPtr(end)));
234             }
235         }
236 
237         globalStorage_->IterateUsageGlobal([visitor](Node *node) {
238             JSTaggedValue value(node->GetObject());
239             if (value.IsHeapObject()) {
240                 visitor(ecmascript::Root::ROOT_HANDLE, ecmascript::ObjectSlot(node->GetObjectAddress()));
241             }
242         });
243     }
244 }
245 
IterateHandleWithCheck(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor)246 void JSThread::IterateHandleWithCheck(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor)
247 {
248     size_t handleCount = 0;
249     if (currentHandleStorageIndex_ != -1) {
250         int32_t nid = currentHandleStorageIndex_;
251         for (int32_t i = 0; i <= nid; ++i) {
252             auto node = handleStorageNodes_.at(i);
253             auto start = node->data();
254             auto end = (i != nid) ? &(node->data()[NODE_BLOCK_SIZE]) : handleScopeStorageNext_;
255             rangeVisitor(ecmascript::Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(start)), ObjectSlot(ToUintPtr(end)));
256             handleCount += (ToUintPtr(end) - ToUintPtr(start)) / sizeof(JSTaggedType);
257         }
258     }
259 
260     size_t globalCount = 0;
261     static const int JS_TYPE_LAST = static_cast<int>(JSType::TYPE_LAST);
262     int typeCount[JS_TYPE_LAST] = { 0 };
263     int primitiveCount = 0;
264     bool isStopObjectLeakCheck = EnableGlobalObjectLeakCheck() && !IsStartGlobalLeakCheck() && stackTraceFd_ > 0;
265     bool isStopPrimitiveLeakCheck = EnableGlobalPrimitiveLeakCheck() && !IsStartGlobalLeakCheck() && stackTraceFd_ > 0;
266     std::ostringstream buffer;
267     globalDebugStorage_->IterateUsageGlobal([this, visitor, &globalCount, &typeCount, &primitiveCount,
268         isStopObjectLeakCheck, isStopPrimitiveLeakCheck, &buffer](DebugNode *node) {
269         node->MarkCount();
270         JSTaggedValue value(node->GetObject());
271         if (value.IsHeapObject()) {
272             visitor(ecmascript::Root::ROOT_HANDLE, ecmascript::ObjectSlot(node->GetObjectAddress()));
273             TaggedObject *object = value.GetTaggedObject();
274             MarkWord word(value.GetTaggedObject());
275             if (word.IsForwardingAddress()) {
276                 object = word.ToForwardingAddress();
277             }
278             typeCount[static_cast<int>(object->GetClass()->GetObjectType())]++;
279 
280             // Print global information about possible memory leaks.
281             // You can print the global new stack within the range of the leaked global number.
282             if (isStopObjectLeakCheck && node->GetGlobalNumber() > 0 && node->GetMarkCount() > 0) {
283                 buffer << "Global maybe leak object address:" << std::hex << object <<
284                     ", type:" << JSHClass::DumpJSType(JSType(object->GetClass()->GetObjectType())) <<
285                     ", node address:" << node << ", number:" << std::dec <<  node->GetGlobalNumber() <<
286                     ", markCount:" << node->GetMarkCount();
287                 WriteToStackTraceFd(buffer);
288             }
289         } else {
290             primitiveCount++;
291             if (isStopPrimitiveLeakCheck && node->GetGlobalNumber() > 0 && node->GetMarkCount() > 0) {
292                 buffer << "Global maybe leak primitive:" << std::hex << value.GetRawData() <<
293                     ", node address:" << node << ", number:" << std::dec <<  node->GetGlobalNumber() <<
294                     ", markCount:" << node->GetMarkCount();
295                 WriteToStackTraceFd(buffer);
296             }
297         }
298         globalCount++;
299     });
300 
301     if (isStopObjectLeakCheck || isStopPrimitiveLeakCheck) {
302         buffer << "Global leak check success!";
303         WriteToStackTraceFd(buffer);
304         CloseStackTraceFd();
305     }
306     // Determine whether memory leakage by checking handle and global count.
307     LOG_ECMA(INFO) << "Iterate root handle count:" << handleCount << ", global handle count:" << globalCount;
308     OPTIONAL_LOG(GetEcmaVM(), INFO) << "Global type Primitive count:" << primitiveCount;
309     // Print global object type statistic.
310     static const int MIN_COUNT_THRESHOLD = 50;
311     for (int i = 0; i < JS_TYPE_LAST; i++) {
312         if (typeCount[i] > MIN_COUNT_THRESHOLD) {
313             OPTIONAL_LOG(GetEcmaVM(), INFO) << "Global type " << JSHClass::DumpJSType(JSType(i))
314                                             << " count:" << typeCount[i];
315         }
316     }
317 }
318 
IterateWeakEcmaGlobalStorage(const WeakRootVisitor & visitor)319 void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor)
320 {
321     auto callBack = [this, visitor](WeakNode *node) {
322         JSTaggedValue value(node->GetObject());
323         if (!value.IsHeapObject()) {
324             return;
325         }
326         auto object = value.GetTaggedObject();
327         auto fwd = visitor(object);
328         if (fwd == nullptr) {
329             // undefind
330             node->SetObject(JSTaggedValue::Undefined().GetRawData());
331             auto secondPassCallback = node->GetSecondPassCallback();
332             if (secondPassCallback) {
333                 weakNodeSecondPassCallbacks_.push_back(std::make_pair(secondPassCallback,
334                                                                       node->GetReference()));
335             }
336             if (!node->CallFirstPassCallback()) {
337                 DisposeGlobalHandle(ToUintPtr(node));
338             }
339         } else if (fwd != object) {
340             // update
341             node->SetObject(JSTaggedValue(fwd).GetRawData());
342         }
343     };
344     if (!vm_->GetJSOptions().EnableGlobalLeakCheck()) {
345         globalStorage_->IterateWeakUsageGlobal(callBack);
346     } else {
347         globalDebugStorage_->IterateWeakUsageGlobal(callBack);
348     }
349 }
350 
DoStackOverflowCheck(const JSTaggedType * sp)351 bool JSThread::DoStackOverflowCheck(const JSTaggedType *sp)
352 {
353     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
354     if (UNLIKELY(sp <= glueData_.frameBase_ + RESERVE_STACK_SIZE)) {
355         LOG_ECMA(ERROR) << "Stack overflow! Remaining stack size is: " << (sp - glueData_.frameBase_);
356         if (LIKELY(!HasPendingException())) {
357             ObjectFactory *factory = GetEcmaVM()->GetFactory();
358             JSHandle<JSObject> error = factory->GetJSError(base::ErrorType::RANGE_ERROR, "Stack overflow!", false);
359             SetException(error.GetTaggedValue());
360         }
361         return true;
362     }
363     return false;
364 }
365 
ExpandHandleStorage()366 uintptr_t *JSThread::ExpandHandleStorage()
367 {
368     uintptr_t *result = nullptr;
369     int32_t lastIndex = static_cast<int32_t>(handleStorageNodes_.size() - 1);
370     if (currentHandleStorageIndex_ == lastIndex) {
371         auto n = new std::array<JSTaggedType, NODE_BLOCK_SIZE>();
372         handleStorageNodes_.push_back(n);
373         currentHandleStorageIndex_++;
374         result = reinterpret_cast<uintptr_t *>(&n->data()[0]);
375         handleScopeStorageEnd_ = &n->data()[NODE_BLOCK_SIZE];
376     } else {
377         currentHandleStorageIndex_++;
378         auto lastNode = handleStorageNodes_[currentHandleStorageIndex_];
379         result = reinterpret_cast<uintptr_t *>(&lastNode->data()[0]);
380         handleScopeStorageEnd_ = &lastNode->data()[NODE_BLOCK_SIZE];
381     }
382 
383     return result;
384 }
385 
ShrinkHandleStorage(int prevIndex)386 void JSThread::ShrinkHandleStorage(int prevIndex)
387 {
388     currentHandleStorageIndex_ = prevIndex;
389     int32_t lastIndex = static_cast<int32_t>(handleStorageNodes_.size() - 1);
390 #if ECMASCRIPT_ENABLE_ZAP_MEM
391     uintptr_t size = ToUintPtr(handleScopeStorageEnd_) - ToUintPtr(handleScopeStorageNext_);
392     if (memset_s(handleScopeStorageNext_, size, 0, size) != EOK) {
393         LOG_FULL(FATAL) << "memset_s failed";
394         UNREACHABLE();
395     }
396     for (int32_t i = currentHandleStorageIndex_ + 1; i < lastIndex; i++) {
397         if (memset_s(handleStorageNodes_[i],
398                      NODE_BLOCK_SIZE * sizeof(JSTaggedType), 0,
399                      NODE_BLOCK_SIZE * sizeof(JSTaggedType)) !=
400                      EOK) {
401             LOG_FULL(FATAL) << "memset_s failed";
402             UNREACHABLE();
403         }
404     }
405 #endif
406 
407     if (lastIndex > MIN_HANDLE_STORAGE_SIZE && currentHandleStorageIndex_ < MIN_HANDLE_STORAGE_SIZE) {
408         for (int i = MIN_HANDLE_STORAGE_SIZE; i < lastIndex; i++) {
409             auto node = handleStorageNodes_.back();
410             delete node;
411             handleStorageNodes_.pop_back();
412         }
413     }
414 }
415 
NotifyStableArrayElementsGuardians(JSHandle<JSObject> receiver)416 void JSThread::NotifyStableArrayElementsGuardians(JSHandle<JSObject> receiver)
417 {
418     if (!receiver->GetJSHClass()->IsPrototype()) {
419         return;
420     }
421     if (!stableArrayElementsGuardians_) {
422         return;
423     }
424     auto env = GetEcmaVM()->GetGlobalEnv();
425     if (receiver.GetTaggedValue() == env->GetObjectFunctionPrototype().GetTaggedValue() ||
426         receiver.GetTaggedValue() == env->GetArrayPrototype().GetTaggedValue()) {
427         SetStableArrayElementsGuardians(JSTaggedValue::False());
428         stableArrayElementsGuardians_ = false;
429     }
430 }
431 
ResetGuardians()432 void JSThread::ResetGuardians()
433 {
434     SetStableArrayElementsGuardians(JSTaggedValue::True());
435     stableArrayElementsGuardians_ = true;
436 }
437 
CheckSwitchDebuggerBCStub()438 void JSThread::CheckSwitchDebuggerBCStub()
439 {
440     auto isDebug = GetEcmaVM()->GetJsDebuggerManager()->IsDebugMode();
441     if (isDebug &&
442         glueData_.bcDebuggerStubEntries_.Get(0) == glueData_.bcDebuggerStubEntries_.Get(1)) {
443         for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) {
444             auto stubEntry = glueData_.bcStubEntries_.Get(i);
445             auto debuggerStubEbtry = glueData_.bcDebuggerStubEntries_.Get(i);
446             glueData_.bcDebuggerStubEntries_.Set(i, stubEntry);
447             glueData_.bcStubEntries_.Set(i, debuggerStubEbtry);
448         }
449     } else if (!isDebug &&
450         glueData_.bcStubEntries_.Get(0) == glueData_.bcStubEntries_.Get(1)) {
451         for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) {
452             auto stubEntry = glueData_.bcDebuggerStubEntries_.Get(i);
453             auto debuggerStubEbtry = glueData_.bcStubEntries_.Get(i);
454             glueData_.bcStubEntries_.Set(i, stubEntry);
455             glueData_.bcDebuggerStubEntries_.Set(i, debuggerStubEbtry);
456         }
457     }
458 }
459 
CheckSafepoint() const460 bool JSThread::CheckSafepoint() const
461 {
462     if (vmThreadControl_->VMNeedSuspension()) {
463         vmThreadControl_->SuspendVM();
464     }
465 #ifndef NDEBUG
466     if (vm_->GetJSOptions().EnableForceGC()) {
467         GetEcmaVM()->CollectGarbage(TriggerGCType::FULL_GC);
468         return true;
469     }
470 #endif
471     if (IsMarkFinished()) {
472         auto heap = GetEcmaVM()->GetHeap();
473         heap->GetConcurrentMarker()->HandleMarkingFinished();
474         return true;
475     }
476     return false;
477 }
478 
CheckJSTaggedType(JSTaggedType value) const479 void JSThread::CheckJSTaggedType(JSTaggedType value) const
480 {
481     if (JSTaggedValue(value).IsHeapObject() &&
482         !GetEcmaVM()->GetHeap()->IsAlive(reinterpret_cast<TaggedObject *>(value))) {
483         LOG_FULL(FATAL) << "value:" << value << " is invalid!";
484     }
485 }
486 
CpuProfilerCheckJSTaggedType(JSTaggedType value) const487 bool JSThread::CpuProfilerCheckJSTaggedType(JSTaggedType value) const
488 {
489     if (JSTaggedValue(value).IsHeapObject() &&
490         !GetEcmaVM()->GetHeap()->IsAlive(reinterpret_cast<TaggedObject *>(value))) {
491         return false;
492     }
493     return true;
494 }
495 
CollectBCOffsetInfo()496 void JSThread::CollectBCOffsetInfo()
497 {
498     FrameBcCollector collector(this);
499     collector.CollectBCOffsetInfo();
500 }
501 
502 // static
GetAsmStackLimit()503 size_t JSThread::GetAsmStackLimit()
504 {
505 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
506     // js stack limit
507     size_t result = GetCurrentStackPosition() - EcmaParamConfiguration::GetDefalutStackSize();
508     pthread_attr_t attr;
509     int ret = pthread_getattr_np(pthread_self(), &attr);
510     if (ret != 0) {
511         LOG_ECMA(ERROR) << "Get current thread attr failed";
512         return result;
513     }
514 
515     void *stackAddr = nullptr;
516     size_t size = 0;
517     ret = pthread_attr_getstack(&attr, &stackAddr, &size);
518     if (ret != 0) {
519         LOG_ECMA(ERROR) << "Get current thread stack size failed";
520         if (pthread_attr_destroy(&attr) != 0) {
521             LOG_ECMA(ERROR) << "Destroy current thread attr failed";
522         }
523         return result;
524     }
525 
526     uintptr_t threadStackLimit = reinterpret_cast<uintptr_t>(stackAddr);
527     if (result < threadStackLimit) {
528         result = threadStackLimit;
529     }
530 
531     uintptr_t threadStackStart = threadStackLimit + size;
532     LOG_INTERPRETER(INFO) << "Current thread stack start: " << reinterpret_cast<void *>(threadStackStart);
533     LOG_INTERPRETER(INFO) << "Used stack before js stack start: "
534                           << reinterpret_cast<void *>(threadStackStart - GetCurrentStackPosition());
535     LOG_INTERPRETER(INFO) << "Current thread asm stack limit: " << reinterpret_cast<void *>(result);
536     ret = pthread_attr_destroy(&attr);
537     if (ret != 0) {
538         LOG_ECMA(ERROR) << "Destroy current thread attr failed";
539     }
540 
541     // To avoid too much times of stack overflow checking, we only check stack overflow before push vregs or
542     // parameters of variable length. So we need a reserved size of stack to make sure stack won't be overflowed
543     // when push other data.
544     result += EcmaParamConfiguration::GetDefaultReservedStackSize();
545     if (threadStackStart <= result) {
546         LOG_FULL(FATAL) << "Too small stackSize to run jsvm";
547     }
548     return result;
549 #else
550     return 0;
551 #endif
552 }
553 
IsLegalAsmSp(uintptr_t sp) const554 bool JSThread::IsLegalAsmSp(uintptr_t sp) const
555 {
556     uint64_t bottom = GetStackLimit() - EcmaParamConfiguration::GetDefaultReservedStackSize();
557     uint64_t top = GetStackStart();
558     return (bottom <= sp && sp <= top);
559 }
560 
IsLegalThreadSp(uintptr_t sp) const561 bool JSThread::IsLegalThreadSp(uintptr_t sp) const
562 {
563     uintptr_t bottom = reinterpret_cast<uintptr_t>(glueData_.frameBase_);
564     size_t maxStackSize = vm_->GetEcmaParamConfiguration().GetMaxStackSize();
565     uintptr_t top = bottom + maxStackSize;
566     return (bottom <= sp && sp <= top);
567 }
568 
IsLegalSp(uintptr_t sp) const569 bool JSThread::IsLegalSp(uintptr_t sp) const
570 {
571     return IsLegalAsmSp(sp) || IsLegalThreadSp(sp);
572 }
573 }  // namespace panda::ecmascript
574