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
21 namespace panda::ecmascript {
FrameHandler(const JSThread *thread)22 FrameHandler::FrameHandler(const JSThread *thread)
23 : sp_(const_cast<JSTaggedType *>(thread->GetCurrentFrame())), thread_(thread)
24 {
25 AdvanceToJSFrame();
26 }
27
AdvanceToJSFrame()28 ARK_INLINE void FrameHandler::AdvanceToJSFrame()
29 {
30 if (!thread_->IsAsmInterpreter()) {
31 return;
32 }
33 FrameIterator it(sp_, thread_);
34 for (; !it.Done(); it.Advance()) {
35 FrameType t = it.GetFrameType();
36 if (IsBaselineBuiltinFrame(t)) {
37 FindAndSetBaselineNativePc(it);
38 }
39 if (IsJSFrame(t) || IsJSEntryFrame(t)) {
40 break;
41 }
42 }
43 sp_ = it.GetSp();
44 }
45
PrevJSFrame()46 ARK_INLINE void FrameHandler::PrevJSFrame()
47 {
48 if (!thread_->IsAsmInterpreter()) {
49 FrameIterator it(sp_, thread_);
50 if (IsBaselineBuiltinFrame(it.GetFrameType())) {
51 FindAndSetBaselineNativePc(it);
52 }
53 it.Advance();
54 sp_ = it.GetSp();
55 return;
56 }
57 AdvanceToJSFrame();
58 FrameIterator it(sp_, thread_);
59 FrameType t = it.GetFrameType();
60 if (t == FrameType::ASM_INTERPRETER_FRAME) {
61 auto frame = it.GetFrame<AsmInterpretedFrame>();
62 if (thread_->IsAsmInterpreter()) {
63 fp_ = frame->GetCurrentFramePointer();
64 }
65 }
66 it.Advance();
67 sp_ = it.GetSp();
68 AdvanceToJSFrame();
69 }
70
GetPrevJSFrame()71 JSTaggedType* FrameHandler::GetPrevJSFrame()
72 {
73 PrevJSFrame();
74 return GetSp();
75 }
76
GetNumberArgs()77 uint32_t FrameHandler::GetNumberArgs()
78 {
79 if (thread_->IsAsmInterpreter()) {
80 auto *frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
81 return static_cast<uint32_t>(frame->GetCurrentFramePointer() - sp_);
82 }
83 ASSERT(IsInterpretedFrame());
84 JSTaggedType *prevSp = nullptr;
85 FrameIterator it(sp_, thread_);
86 if (IsAsmInterpretedFrame()) {
87 auto *frame = it.GetFrame<AsmInterpretedFrame>();
88 prevSp = frame->GetPrevFrameFp();
89 } else {
90 auto *frame = it.GetFrame<InterpretedFrame>();
91 prevSp = frame->GetPrevFrameFp();
92 }
93 auto prevSpEnd = reinterpret_cast<JSTaggedType*>(GetInterpretedFrameEnd(prevSp));
94 return static_cast<uint32_t>(prevSpEnd - sp_);
95 }
96
GetVRegValue(size_t index) const97 JSTaggedValue FrameHandler::GetVRegValue(size_t index) const
98 {
99 ASSERT(IsInterpretedFrame());
100 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
101 return JSTaggedValue(sp_[index]);
102 }
103
SetVRegValue(size_t index, JSTaggedValue value)104 void FrameHandler::SetVRegValue(size_t index, JSTaggedValue value)
105 {
106 ASSERT(IsInterpretedFrame());
107 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
108 sp_[index] = value.GetRawData();
109 }
110
FindAndSetBaselineNativePc(FrameIterator it)111 void FrameHandler::FindAndSetBaselineNativePc(FrameIterator it)
112 {
113 ASSERT(IsBaselineBuiltinFrame(it.GetFrameType()));
114 auto *frame = it.GetFrame<BaselineBuiltinFrame>();
115 baselineNativePc_ = frame->GetReturnAddr();
116 }
117
GetAcc() const118 JSTaggedValue FrameHandler::GetAcc() const
119 {
120 ASSERT(IsInterpretedFrame());
121 FrameIterator it(sp_, thread_);
122 if (IsAsmInterpretedFrame()) {
123 auto *frame = it.GetFrame<AsmInterpretedFrame>();
124 return frame->acc;
125 } else {
126 auto *frame = it.GetFrame<InterpretedFrame>();
127 return frame->acc;
128 }
129 }
130
GetBytecodeOffset() const131 uint32_t FrameHandler::GetBytecodeOffset() const
132 {
133 ASSERT(IsInterpretedFrame());
134 Method *method = GetMethod();
135 auto offset = GetPc() - method->GetBytecodeArray();
136 return static_cast<uint32_t>(offset);
137 }
138
GetMethod() const139 Method *FrameHandler::GetMethod() const
140 {
141 ASSERT(IsJSFrame());
142 auto function = GetFunction();
143 return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
144 }
145
GetJSPandaFile() const146 const JSPandaFile* FrameHandler::GetJSPandaFile() const
147 {
148 auto method = GetMethod();
149 return method->GetJSPandaFile();
150 }
151
GetFileName() const152 std::string FrameHandler::GetFileName() const
153 {
154 auto pandaFile = GetJSPandaFile();
155 ASSERT(pandaFile != nullptr);
156 return pandaFile->GetJSPandaFileDesc().c_str();
157 }
158
GetAbcId() const159 uint32_t FrameHandler::GetAbcId() const
160 {
161 std::string abcName = GetFileName();
162 pgo::PGOProfilerManager* pm = pgo::PGOProfilerManager::GetInstance();
163 uint32_t abcId;
164 if (!pm->GetPandaFileId(CString(abcName), abcId) && !abcName.empty()) {
165 LOG_ECMA(ERROR) << "Get method abc id failed. abcName: " << abcName;
166 }
167 return abcId;
168 }
169
GetMethodId() const170 uint32_t FrameHandler::GetMethodId() const
171 {
172 return GetMethod()->GetMethodId().GetOffset();
173 }
174
CheckAndGetMethod() const175 Method *FrameHandler::CheckAndGetMethod() const
176 {
177 ASSERT(IsJSFrame());
178 auto function = GetFunction();
179 if (function.IsJSFunctionBase() || function.IsJSProxy()) {
180 return ECMAObject::Cast(function.GetTaggedObject())->GetCallTarget();
181 }
182 return nullptr;
183 }
184
GetThis() const185 JSTaggedValue FrameHandler::GetThis() const
186 {
187 ASSERT(IsInterpretedFrame());
188 FrameIterator it(sp_, thread_);
189 if (IsAsmInterpretedFrame()) {
190 auto *frame = it.GetFrame<AsmInterpretedFrame>();
191 return frame->thisObj;
192 } else {
193 auto *frame = it.GetFrame<InterpretedFrame>();
194 return frame->thisObj;
195 }
196 }
197
GetFunction() const198 JSTaggedValue FrameHandler::GetFunction() const
199 {
200 ASSERT(IsJSFrame());
201 if (thread_->IsAsmInterpreter()) {
202 FrameType type = GetFrameType();
203 switch (type) {
204 case FrameType::ASM_INTERPRETER_FRAME:
205 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
206 auto frame = AsmInterpretedFrame::GetFrameFromSp(sp_);
207 return frame->function;
208 }
209 case FrameType::BUILTIN_FRAME_WITH_ARGV: {
210 auto *frame = BuiltinWithArgvFrame::GetFrameFromSp(sp_);
211 return frame->GetFunction();
212 }
213 case FrameType::BUILTIN_ENTRY_FRAME:
214 case FrameType::BUILTIN_FRAME: {
215 auto *frame = BuiltinFrame::GetFrameFromSp(sp_);
216 return frame->GetFunction();
217 }
218 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
219 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
220 auto *frame = OptimizedJSFunctionFrame::GetFrameFromSp(sp_);
221 return frame->GetFunction();
222 }
223 case FrameType::FASTJIT_FUNCTION_FRAME:
224 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
225 auto *frame = FASTJITFunctionFrame::GetFrameFromSp(sp_);
226 return frame->GetFunction();
227 }
228 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
229 case FrameType::INTERPRETER_FRAME:
230 case FrameType::INTERPRETER_FAST_NEW_FRAME:
231 case FrameType::INTERPRETER_ENTRY_FRAME:
232 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
233 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
234 case FrameType::INTERPRETER_BUILTIN_FRAME:
235 case FrameType::OPTIMIZED_FRAME:
236 case FrameType::BASELINE_BUILTIN_FRAME:
237 case FrameType::ASM_BRIDGE_FRAME:
238 case FrameType::LEAVE_FRAME:
239 case FrameType::LEAVE_FRAME_WITH_ARGV:
240 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
241 case FrameType::OPTIMIZED_ENTRY_FRAME:
242 default: {
243 LOG_FULL(FATAL) << "frame type error!";
244 UNREACHABLE();
245 }
246 }
247 } else {
248 FrameType type = GetFrameType();
249 if (type == FrameType::INTERPRETER_FRAME || type == FrameType::INTERPRETER_FAST_NEW_FRAME) {
250 auto *frame = InterpretedFrame::GetFrameFromSp(sp_);
251 return frame->function;
252 } else {
253 auto *frame = InterpretedBuiltinFrame::GetFrameFromSp(sp_);
254 return frame->function;
255 }
256 }
257 }
258
GetPc() const259 const uint8_t *FrameHandler::GetPc() const
260 {
261 ASSERT(IsJSFrame());
262 FrameIterator it(sp_, thread_);
263 if (IsAsmInterpretedFrame()) {
264 auto *frame = it.GetFrame<AsmInterpretedFrame>();
265 return frame->GetPc();
266 } else {
267 auto *frame = it.GetFrame<InterpretedFrame>();
268 return frame->GetPc();
269 }
270 }
271
GetConstpool() const272 ConstantPool *FrameHandler::GetConstpool() const
273 {
274 ASSERT(IsInterpretedFrame());
275 auto method = GetMethod();
276 JSTaggedValue constpool = method->GetConstantPool();
277 return ConstantPool::Cast(constpool.GetTaggedObject());
278 }
279
GetEnv() const280 JSTaggedValue FrameHandler::GetEnv() const
281 {
282 ASSERT(IsInterpretedFrame());
283 FrameIterator it(sp_, thread_);
284 if (IsAsmInterpretedFrame()) {
285 auto *frame = it.GetFrame<AsmInterpretedFrame>();
286 return frame->GetEnv();
287 } else {
288 auto *frame = it.GetFrame<InterpretedFrame>();
289 return frame->env;
290 }
291 }
292
DumpStack(std::ostream &os) const293 void FrameHandler::DumpStack(std::ostream &os) const
294 {
295 size_t i = 0;
296 FrameHandler frameHandler(thread_);
297 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
298 os << "[" << i++
299 << "]:" << frameHandler.GetMethod()->ParseFunctionName()
300 << "\n";
301 }
302 }
303
DumpPC(std::ostream &os, const uint8_t *pc) const304 void FrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const
305 {
306 FrameHandler frameHandler(thread_);
307 ASSERT(frameHandler.HasFrame());
308 // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
309 int offset = pc - frameHandler.GetMethod()->GetBytecodeArray();
310 os << "offset: " << offset << "\n";
311 }
312
GetInterpretedFrameEnd(JSTaggedType *prevSp) const313 ARK_INLINE uintptr_t FrameHandler::GetInterpretedFrameEnd(JSTaggedType *prevSp) const
314 {
315 uintptr_t end = 0U;
316 FrameIterator it(prevSp, thread_);
317 FrameType type = it.GetFrameType();
318 switch (type) {
319 case FrameType::ASM_INTERPRETER_FRAME:
320 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
321 auto frame = it.GetFrame<AsmInterpretedFrame>();
322 end = ToUintPtr(frame);
323 break;
324 }
325 case FrameType::INTERPRETER_FRAME:
326 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
327 auto frame = it.GetFrame<InterpretedFrame>();
328 end = ToUintPtr(frame);
329 break;
330 }
331 case FrameType::INTERPRETER_ENTRY_FRAME: {
332 auto frame = it.GetFrame<InterpretedEntryFrame>();
333 end = ToUintPtr(frame);
334 break;
335 }
336 case FrameType::INTERPRETER_BUILTIN_FRAME: {
337 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
338 end = ToUintPtr(frame);
339 break;
340 }
341 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
342 case FrameType::BUILTIN_FRAME_WITH_ARGV:
343 case FrameType::BUILTIN_ENTRY_FRAME:
344 case FrameType::BUILTIN_FRAME:
345 case FrameType::OPTIMIZED_FRAME:
346 case FrameType::ASM_BRIDGE_FRAME:
347 case FrameType::LEAVE_FRAME:
348 case FrameType::BASELINE_BUILTIN_FRAME:
349 case FrameType::LEAVE_FRAME_WITH_ARGV:
350 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
351 case FrameType::OPTIMIZED_ENTRY_FRAME:
352 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
353 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
354 default: {
355 LOG_FULL(FATAL) << "frame type error!";
356 UNREACHABLE();
357 }
358 }
359 return end;
360 }
361
IterateAssembleStack(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor)362 void FrameHandler::IterateAssembleStack(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
363 const RootBaseAndDerivedVisitor &derivedVisitor)
364 {
365 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
366 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor);
367 }
368
369 // We seperate InterpretedEntryFrame from assemble stack when asm interpreter is enable.
370 // To protect EcmaRuntimeCallInfo on InterpretedEntryFrame, we iterate InterpretedEntryFrame on thread sp individually.
371 // And only InterpretedEntryFrame is on thread sp when asm interpreter is enable.
IterateEcmaRuntimeCallInfo(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor)372 void FrameHandler::IterateEcmaRuntimeCallInfo(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor)
373 {
374 ASSERT(thread_->IsAsmInterpreter());
375 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
376 for (FrameIterator it(current, thread_); !it.Done(); it.Advance()) {
377 ASSERT(it.GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
378 auto frame = it.GetFrame<InterpretedEntryFrame>();
379 frame->GCIterate(it, visitor, rangeVisitor);
380 }
381 }
382
Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor)383 void FrameHandler::Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
384 const RootBaseAndDerivedVisitor &derivedVisitor)
385 {
386 if (thread_->IsAsmInterpreter()) {
387 IterateEcmaRuntimeCallInfo(visitor, rangeVisitor);
388 IterateAssembleStack(visitor, rangeVisitor, derivedVisitor);
389 return;
390 }
391 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
392 FrameType frameType = FrameHandler::GetFrameType(current);
393 if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) {
394 auto leaveFrame = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
395 if (leaveFrame != nullptr) {
396 current = leaveFrame;
397 }
398 }
399 // lazy assignment: only Iterate need arkStackMapParser_ in order to high improve performance
400 if (arkStackMapParser_ == nullptr) {
401 arkStackMapParser_ =
402 const_cast<JSThread *>(thread_)->GetEcmaVM()->GetAOTFileManager()->GetStackMapParser();
403 }
404 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor);
405 }
406
IterateFrameChain(JSTaggedType *start, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const407 void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &visitor,
408 const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const
409 {
410 JSTaggedType *current = start;
411 // if the current frame type is BASELINE_BUILTIN_FRAME, the upper frame must be BaselineFrame.
412 // isBaselineFrame is used to differentiate the AsmInterpterFrame and BaselineFrame
413 bool isBaselineFrame = false;
414 for (FrameIterator it(current, thread_); !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
415 FrameType type = it.GetFrameType();
416 switch (type) {
417 case FrameType::OPTIMIZED_FRAME: {
418 auto frame = it.GetFrame<OptimizedFrame>();
419 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor);
420 break;
421 }
422 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
423 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
424 auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
425 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor, type);
426 break;
427 }
428 case FrameType::BASELINE_BUILTIN_FRAME: {
429 isBaselineFrame = true;
430 auto frame = it.GetFrame<BaselineBuiltinFrame>();
431 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor);
432 break;
433 }
434 case FrameType::FASTJIT_FUNCTION_FRAME:
435 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
436 auto frame = it.GetFrame<FASTJITFunctionFrame>();
437 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor, type);
438 break;
439 }
440 case FrameType::ASM_INTERPRETER_FRAME:
441 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
442 auto frame = it.GetFrame<AsmInterpretedFrame>();
443 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor, isBaselineFrame);
444 isBaselineFrame = false;
445 break;
446 }
447 case FrameType::INTERPRETER_FRAME:
448 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
449 auto frame = it.GetFrame<InterpretedFrame>();
450 frame->GCIterate(it, visitor, rangeVisitor);
451 break;
452 }
453 case FrameType::INTERPRETER_BUILTIN_FRAME: {
454 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
455 frame->GCIterate(it, visitor, rangeVisitor);
456 break;
457 }
458 case FrameType::LEAVE_FRAME: {
459 auto frame = it.GetFrame<OptimizedLeaveFrame>();
460 frame->GCIterate(it, visitor, rangeVisitor);
461 break;
462 }
463 case FrameType::LEAVE_FRAME_WITH_ARGV: {
464 auto frame = it.GetFrame<OptimizedWithArgvLeaveFrame>();
465 frame->GCIterate(it, visitor, rangeVisitor);
466 break;
467 }
468 case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
469 auto frame = it.GetFrame<OptimizedBuiltinLeaveFrame>();
470 frame->GCIterate(it, visitor, rangeVisitor);
471 break;
472 }
473 case FrameType::BUILTIN_FRAME_WITH_ARGV: {
474 auto frame = it.GetFrame<BuiltinWithArgvFrame>();
475 frame->GCIterate(it, visitor, rangeVisitor);
476 break;
477 }
478 case FrameType::BUILTIN_ENTRY_FRAME:
479 case FrameType::BUILTIN_FRAME: {
480 auto frame = it.GetFrame<BuiltinFrame>();
481 frame->GCIterate(it, visitor, rangeVisitor);
482 break;
483 }
484 case FrameType::INTERPRETER_ENTRY_FRAME: {
485 auto frame = it.GetFrame<InterpretedEntryFrame>();
486 frame->GCIterate(it, visitor, rangeVisitor);
487 break;
488 }
489 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
490 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
491 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
492 case FrameType::OPTIMIZED_ENTRY_FRAME:
493 case FrameType::ASM_BRIDGE_FRAME:
494 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
495 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: {
496 break;
497 }
498 default: {
499 LOG_FULL(FATAL) << "frame type error!";
500 UNREACHABLE();
501 }
502 }
503 }
504 }
505 } // namespace panda::ecmascript
506