1
2 /*
3 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ecmascript/interpreter/frame_handler.h"
18
19 #include "ecmascript/jspandafile/program_object.h"
20 #include "ecmascript/stubs/runtime_stubs-inl.h"
21
22 namespace panda::ecmascript {
FrameHandler(const JSThread * thread)23 FrameHandler::FrameHandler(const JSThread *thread)
24 : sp_(const_cast<JSTaggedType *>(thread->GetCurrentFrame())), thread_(thread)
25 {
26 AdvanceToJSFrame();
27 }
28
AdvanceToJSFrame()29 ARK_INLINE void FrameHandler::AdvanceToJSFrame()
30 {
31 if (!thread_->IsAsmInterpreter()) {
32 return;
33 }
34 FrameIterator it(sp_, thread_);
35 for (; !it.Done(); it.Advance()) {
36 FrameType t = it.GetFrameType();
37 if (IsBaselineBuiltinFrame(t)) {
38 FindAndSetBaselineNativePc(it);
39 }
40 if (IsJSFrame(t) || IsJSEntryFrame(t)) {
41 break;
42 }
43 }
44 sp_ = it.GetSp();
45 }
46
PrevJSFrame()47 ARK_INLINE void FrameHandler::PrevJSFrame()
48 {
49 if (!thread_->IsAsmInterpreter()) {
50 FrameIterator it(sp_, thread_);
51 if (IsBaselineBuiltinFrame(it.GetFrameType())) {
52 FindAndSetBaselineNativePc(it);
53 }
54 it.Advance();
55 sp_ = it.GetSp();
56 return;
57 }
58 AdvanceToJSFrame();
59 FrameIterator it(sp_, thread_);
60 FrameType t = it.GetFrameType();
61 if (t == FrameType::ASM_INTERPRETER_FRAME) {
62 auto frame = it.GetFrame<AsmInterpretedFrame>();
63 if (thread_->IsAsmInterpreter()) {
64 fp_ = frame->GetCurrentFramePointer();
65 }
66 }
67 it.Advance();
68 sp_ = it.GetSp();
69 AdvanceToJSFrame();
70 }
71
GetPrevJSFrame()72 JSTaggedType* FrameHandler::GetPrevJSFrame()
73 {
74 PrevJSFrame();
75 return GetSp();
76 }
77
GetNumberArgs()78 uint32_t FrameHandler::GetNumberArgs()
79 {
80 if (thread_->IsAsmInterpreter()) {
81 auto *frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
82 return static_cast<uint32_t>(frame->GetCurrentFramePointer() - sp_);
83 }
84 ASSERT(IsInterpretedFrame());
85 JSTaggedType *prevSp = nullptr;
86 FrameIterator it(sp_, thread_);
87 if (IsAsmInterpretedFrame()) {
88 auto *frame = it.GetFrame<AsmInterpretedFrame>();
89 prevSp = frame->GetPrevFrameFp();
90 } else {
91 auto *frame = it.GetFrame<InterpretedFrame>();
92 prevSp = frame->GetPrevFrameFp();
93 }
94 auto prevSpEnd = reinterpret_cast<JSTaggedType*>(GetInterpretedFrameEnd(prevSp));
95 return static_cast<uint32_t>(prevSpEnd - sp_);
96 }
97
GetVRegValue(size_t index) const98 JSTaggedValue FrameHandler::GetVRegValue(size_t index) const
99 {
100 ASSERT(IsInterpretedFrame());
101 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
102 return JSTaggedValue(sp_[index]);
103 }
104
SetVRegValue(size_t index,JSTaggedValue value)105 void FrameHandler::SetVRegValue(size_t index, JSTaggedValue value)
106 {
107 ASSERT(IsInterpretedFrame());
108 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
109 sp_[index] = value.GetRawData();
110 }
111
FindAndSetBaselineNativePc(FrameIterator it)112 void FrameHandler::FindAndSetBaselineNativePc(FrameIterator it)
113 {
114 ASSERT(IsBaselineBuiltinFrame(it.GetFrameType()));
115 auto *frame = it.GetFrame<BaselineBuiltinFrame>();
116 baselineNativePc_ = frame->GetReturnAddr();
117 }
118
GetAcc() const119 JSTaggedValue FrameHandler::GetAcc() const
120 {
121 ASSERT(IsInterpretedFrame());
122 FrameIterator it(sp_, thread_);
123 if (IsAsmInterpretedFrame()) {
124 auto *frame = it.GetFrame<AsmInterpretedFrame>();
125 return frame->acc;
126 } else {
127 auto *frame = it.GetFrame<InterpretedFrame>();
128 return frame->acc;
129 }
130 }
131
GetBytecodeOffset() const132 uint32_t FrameHandler::GetBytecodeOffset() const
133 {
134 ASSERT(IsInterpretedFrame());
135 auto pc = GetPc();
136 if (reinterpret_cast<uintptr_t>(pc) != std::numeric_limits<uintptr_t>::max()) {
137 // interpreter frame
138 Method *method = GetMethod();
139 auto offset = pc - method->GetBytecodeArray();
140 return static_cast<uint32_t>(offset);
141 } else {
142 // baseline frame
143 uintptr_t curNativePc = GetBaselineNativePc();
144 ASSERT(curNativePc != 0);
145 LOG_BASELINEJIT(DEBUG) << "current native pc in UpFrame: " << std::hex <<
146 reinterpret_cast<void*>(curNativePc);
147 JSHandle<JSTaggedValue> funcVal = JSHandle<JSTaggedValue>(thread_, GetFunction());
148 JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(funcVal);
149 uint32_t curBytecodePcOfst = RuntimeStubs::RuntimeGetBytecodePcOfstForBaseline(func, curNativePc);
150 return curBytecodePcOfst;
151 }
152 }
153
GetMethod() const154 Method *FrameHandler::GetMethod() const
155 {
156 ASSERT(IsJSFrame());
157 auto function = GetFunction();
158 return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
159 }
160
GetJSPandaFile() const161 const JSPandaFile* FrameHandler::GetJSPandaFile() const
162 {
163 auto method = GetMethod();
164 return method->GetJSPandaFile();
165 }
166
GetFileName() const167 std::string FrameHandler::GetFileName() const
168 {
169 auto pandaFile = GetJSPandaFile();
170 ASSERT(pandaFile != nullptr);
171 return pandaFile->GetJSPandaFileDesc().c_str();
172 }
173
GetAbcId() const174 uint32_t FrameHandler::GetAbcId() const
175 {
176 std::string abcName = GetFileName();
177 pgo::PGOProfilerManager* pm = pgo::PGOProfilerManager::GetInstance();
178 uint32_t abcId;
179 if (!pm->GetPandaFileId(CString(abcName), abcId) && !abcName.empty()) {
180 LOG_ECMA(ERROR) << "Get method abc id failed. abcName: " << abcName;
181 }
182 return abcId;
183 }
184
GetMethodId() const185 uint32_t FrameHandler::GetMethodId() const
186 {
187 return GetMethod()->GetMethodId().GetOffset();
188 }
189
CheckAndGetMethod() const190 Method *FrameHandler::CheckAndGetMethod() const
191 {
192 ASSERT(IsJSFrame());
193 auto function = GetFunction();
194 if (function.IsJSFunctionBase() || function.IsJSProxy()) {
195 return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
196 }
197 return nullptr;
198 }
199
GetThis() const200 JSTaggedValue FrameHandler::GetThis() const
201 {
202 ASSERT(IsInterpretedFrame());
203 FrameIterator it(sp_, thread_);
204 if (IsAsmInterpretedFrame()) {
205 auto *frame = it.GetFrame<AsmInterpretedFrame>();
206 return frame->thisObj;
207 } else {
208 auto *frame = it.GetFrame<InterpretedFrame>();
209 return frame->thisObj;
210 }
211 }
212
GetFunction() const213 JSTaggedValue FrameHandler::GetFunction() const
214 {
215 ASSERT(IsJSFrame());
216 if (thread_->IsAsmInterpreter()) {
217 FrameType type = GetFrameType();
218 switch (type) {
219 case FrameType::ASM_INTERPRETER_FRAME:
220 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
221 auto frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
222 return frame->function;
223 }
224 case FrameType::BUILTIN_FRAME_WITH_ARGV: {
225 auto *frame = BuiltinWithArgvFrame::GetFrameFromSp(sp_);
226 return frame->GetFunction();
227 }
228 case FrameType::BUILTIN_ENTRY_FRAME:
229 case FrameType::BUILTIN_FRAME: {
230 auto *frame = BuiltinFrame::GetFrameFromSp(sp_);
231 return frame->GetFunction();
232 }
233 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
234 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
235 auto *frame = OptimizedJSFunctionFrame::GetFrameFromSp(sp_);
236 return frame->GetFunction();
237 }
238 case FrameType::FASTJIT_FUNCTION_FRAME:
239 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
240 auto *frame = FASTJITFunctionFrame::GetFrameFromSp(sp_);
241 return frame->GetFunction();
242 }
243 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
244 case FrameType::INTERPRETER_FRAME:
245 case FrameType::INTERPRETER_FAST_NEW_FRAME:
246 case FrameType::INTERPRETER_ENTRY_FRAME:
247 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
248 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
249 case FrameType::INTERPRETER_BUILTIN_FRAME:
250 case FrameType::OPTIMIZED_FRAME:
251 case FrameType::BASELINE_BUILTIN_FRAME:
252 case FrameType::ASM_BRIDGE_FRAME:
253 case FrameType::LEAVE_FRAME:
254 case FrameType::LEAVE_FRAME_WITH_ARGV:
255 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
256 case FrameType::OPTIMIZED_ENTRY_FRAME:
257 default: {
258 LOG_FULL(FATAL) << "frame type error!";
259 UNREACHABLE();
260 }
261 }
262 } else {
263 FrameType type = GetFrameType();
264 if (type == FrameType::INTERPRETER_FRAME || type == FrameType::INTERPRETER_FAST_NEW_FRAME) {
265 auto *frame = InterpretedFrame::GetFrameFromSp(sp_);
266 return frame->function;
267 } else {
268 auto *frame = InterpretedBuiltinFrame::GetFrameFromSp(sp_);
269 return frame->function;
270 }
271 }
272 }
273
GetPc() const274 const uint8_t *FrameHandler::GetPc() const
275 {
276 ASSERT(IsJSFrame());
277 FrameIterator it(sp_, thread_);
278 if (IsAsmInterpretedFrame()) {
279 auto *frame = it.GetFrame<AsmInterpretedFrame>();
280 return frame->GetPc();
281 } else {
282 auto *frame = it.GetFrame<InterpretedFrame>();
283 return frame->GetPc();
284 }
285 }
286
GetConstpool() const287 ConstantPool *FrameHandler::GetConstpool() const
288 {
289 ASSERT(IsInterpretedFrame());
290 auto method = GetMethod();
291 JSTaggedValue constpool = method->GetConstantPool();
292 return ConstantPool::Cast(constpool.GetTaggedObject());
293 }
294
GetEnv() const295 JSTaggedValue FrameHandler::GetEnv() const
296 {
297 ASSERT(IsInterpretedFrame());
298 FrameIterator it(sp_, thread_);
299 if (IsAsmInterpretedFrame()) {
300 auto *frame = it.GetFrame<AsmInterpretedFrame>();
301 return frame->GetEnv();
302 } else {
303 auto *frame = it.GetFrame<InterpretedFrame>();
304 return frame->env;
305 }
306 }
307
DumpStack(std::ostream & os) const308 void FrameHandler::DumpStack(std::ostream &os) const
309 {
310 size_t i = 0;
311 FrameHandler frameHandler(thread_);
312 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
313 os << "[" << i++
314 << "]:" << frameHandler.GetMethod()->ParseFunctionName()
315 << "\n";
316 }
317 }
318
DumpPC(std::ostream & os,const uint8_t * pc) const319 void FrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const
320 {
321 FrameHandler frameHandler(thread_);
322 ASSERT(frameHandler.HasFrame());
323 // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
324 int offset = pc - frameHandler.GetMethod()->GetBytecodeArray();
325 os << "offset: " << offset << "\n";
326 }
327
GetInterpretedFrameEnd(JSTaggedType * prevSp) const328 ARK_INLINE uintptr_t FrameHandler::GetInterpretedFrameEnd(JSTaggedType *prevSp) const
329 {
330 uintptr_t end = 0U;
331 FrameIterator it(prevSp, thread_);
332 FrameType type = it.GetFrameType();
333 switch (type) {
334 case FrameType::ASM_INTERPRETER_FRAME:
335 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
336 auto frame = it.GetFrame<AsmInterpretedFrame>();
337 end = ToUintPtr(frame);
338 break;
339 }
340 case FrameType::INTERPRETER_FRAME:
341 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
342 auto frame = it.GetFrame<InterpretedFrame>();
343 end = ToUintPtr(frame);
344 break;
345 }
346 case FrameType::INTERPRETER_ENTRY_FRAME: {
347 auto frame = it.GetFrame<InterpretedEntryFrame>();
348 end = ToUintPtr(frame);
349 break;
350 }
351 case FrameType::INTERPRETER_BUILTIN_FRAME: {
352 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
353 end = ToUintPtr(frame);
354 break;
355 }
356 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
357 case FrameType::BUILTIN_FRAME_WITH_ARGV:
358 case FrameType::BUILTIN_ENTRY_FRAME:
359 case FrameType::BUILTIN_FRAME:
360 case FrameType::OPTIMIZED_FRAME:
361 case FrameType::ASM_BRIDGE_FRAME:
362 case FrameType::LEAVE_FRAME:
363 case FrameType::BASELINE_BUILTIN_FRAME:
364 case FrameType::LEAVE_FRAME_WITH_ARGV:
365 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
366 case FrameType::OPTIMIZED_ENTRY_FRAME:
367 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
368 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
369 default: {
370 LOG_FULL(FATAL) << "frame type error!";
371 UNREACHABLE();
372 }
373 }
374 return end;
375 }
376
IterateAssembleStack(RootVisitor & visitor)377 void FrameHandler::IterateAssembleStack(RootVisitor &visitor)
378 {
379 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
380 IterateFrameChain(current, visitor);
381 if (thread_->IsInSubStack() && thread_->GetMainStackInfo().lastLeaveFrame != 0) {
382 JSTaggedType *mainCurrent = reinterpret_cast<JSTaggedType *>(thread_->GetMainStackInfo().lastLeaveFrame);
383 IterateFrameChain(mainCurrent, visitor);
384 }
385 }
386
387 // We seperate InterpretedEntryFrame from assemble stack when asm interpreter is enable.
388 // To protect EcmaRuntimeCallInfo on InterpretedEntryFrame, we iterate InterpretedEntryFrame on thread sp individually.
389 // And only InterpretedEntryFrame is on thread sp when asm interpreter is enable.
IterateEcmaRuntimeCallInfo(RootVisitor & visitor)390 void FrameHandler::IterateEcmaRuntimeCallInfo(RootVisitor &visitor)
391 {
392 ASSERT(thread_->IsAsmInterpreter());
393 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
394 for (FrameIterator it(current, thread_); !it.Done(); it.Advance()) {
395 ASSERT(it.GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
396 auto frame = it.GetFrame<InterpretedEntryFrame>();
397 frame->GCIterate(it, visitor);
398 }
399 }
400
Iterate(RootVisitor & visitor)401 void FrameHandler::Iterate(RootVisitor &visitor)
402 {
403 if (thread_->IsAsmInterpreter()) {
404 IterateEcmaRuntimeCallInfo(visitor);
405 IterateAssembleStack(visitor);
406 return;
407 }
408 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
409 FrameType frameType = FrameHandler::GetFrameType(current);
410 if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) {
411 auto leaveFrame = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
412 if (leaveFrame != nullptr) {
413 current = leaveFrame;
414 }
415 }
416 // lazy assignment: only Iterate need arkStackMapParser_ in order to high improve performance
417 if (arkStackMapParser_ == nullptr) {
418 arkStackMapParser_ =
419 const_cast<JSThread *>(thread_)->GetEcmaVM()->GetAOTFileManager()->GetStackMapParser();
420 }
421 IterateFrameChain(current, visitor);
422 }
423
IterateFrameChain(JSTaggedType * start,RootVisitor & visitor) const424 void FrameHandler::IterateFrameChain(JSTaggedType *start, RootVisitor &visitor) const
425 {
426 JSTaggedType *current = start;
427 // if the current frame type is BASELINE_BUILTIN_FRAME, the upper frame must be BaselineFrame.
428 // isBaselineFrame is used to differentiate the AsmInterpterFrame and BaselineFrame
429 bool isBaselineFrame = false;
430 for (FrameIterator it(current, thread_); !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
431 FrameType type = it.GetFrameType();
432 switch (type) {
433 case FrameType::OPTIMIZED_FRAME: {
434 auto frame = it.GetFrame<OptimizedFrame>();
435 frame->GCIterate(it, visitor);
436 break;
437 }
438 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
439 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
440 auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
441 frame->GCIterate(it, visitor, type);
442 break;
443 }
444 case FrameType::BASELINE_BUILTIN_FRAME: {
445 isBaselineFrame = true;
446 auto frame = it.GetFrame<BaselineBuiltinFrame>();
447 frame->GCIterate(it, visitor);
448 break;
449 }
450 case FrameType::FASTJIT_FUNCTION_FRAME:
451 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
452 auto frame = it.GetFrame<FASTJITFunctionFrame>();
453 frame->GCIterate(it, visitor, type);
454 break;
455 }
456 case FrameType::ASM_INTERPRETER_FRAME:
457 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
458 auto frame = it.GetFrame<AsmInterpretedFrame>();
459 frame->GCIterate(it, visitor, isBaselineFrame);
460 isBaselineFrame = false;
461 break;
462 }
463 case FrameType::INTERPRETER_FRAME:
464 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
465 auto frame = it.GetFrame<InterpretedFrame>();
466 frame->GCIterate(it, visitor);
467 break;
468 }
469 case FrameType::INTERPRETER_BUILTIN_FRAME: {
470 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
471 frame->GCIterate(it, visitor);
472 break;
473 }
474 case FrameType::LEAVE_FRAME: {
475 auto frame = it.GetFrame<OptimizedLeaveFrame>();
476 frame->GCIterate(it, visitor);
477 break;
478 }
479 case FrameType::LEAVE_FRAME_WITH_ARGV: {
480 auto frame = it.GetFrame<OptimizedWithArgvLeaveFrame>();
481 frame->GCIterate(it, visitor);
482 break;
483 }
484 case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
485 auto frame = it.GetFrame<OptimizedBuiltinLeaveFrame>();
486 frame->GCIterate(it, visitor);
487 break;
488 }
489 case FrameType::BUILTIN_FRAME_WITH_ARGV: {
490 auto frame = it.GetFrame<BuiltinWithArgvFrame>();
491 frame->GCIterate(it, visitor);
492 break;
493 }
494 case FrameType::BUILTIN_ENTRY_FRAME:
495 case FrameType::BUILTIN_FRAME: {
496 auto frame = it.GetFrame<BuiltinFrame>();
497 frame->GCIterate(it, visitor);
498 break;
499 }
500 case FrameType::INTERPRETER_ENTRY_FRAME: {
501 auto frame = it.GetFrame<InterpretedEntryFrame>();
502 frame->GCIterate(it, visitor);
503 break;
504 }
505 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
506 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
507 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
508 case FrameType::OPTIMIZED_ENTRY_FRAME:
509 case FrameType::ASM_BRIDGE_FRAME:
510 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
511 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: {
512 break;
513 }
514 default: {
515 LOG_FULL(FATAL) << "frame type error!";
516 UNREACHABLE();
517 }
518 }
519 }
520 }
521 } // namespace panda::ecmascript
522