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