• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(JSThread * thread)22 FrameHandler::FrameHandler(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(thread_);
144 }
145 
GetJSPandaFile() const146 const JSPandaFile* FrameHandler::GetJSPandaFile() const
147 {
148     auto method = GetMethod();
149     return method->GetJSPandaFile(thread_);
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(thread_);
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(thread_);
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(thread_)
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(RootVisitor & visitor)362 void FrameHandler::IterateAssembleStack(RootVisitor &visitor)
363 {
364     JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
365     IterateFrameChain(current, visitor);
366     if (thread_->IsInSubStack() && thread_->GetMainStackInfo().lastLeaveFrame != 0) {
367         JSTaggedType *mainCurrent = reinterpret_cast<JSTaggedType *>(thread_->GetMainStackInfo().lastLeaveFrame);
368         IterateFrameChain(mainCurrent, visitor);
369     }
370 }
371 
372 // We seperate InterpretedEntryFrame from assemble stack when asm interpreter is enable.
373 // To protect EcmaRuntimeCallInfo on InterpretedEntryFrame, we iterate InterpretedEntryFrame on thread sp individually.
374 // And only InterpretedEntryFrame is on thread sp when asm interpreter is enable.
IterateEcmaRuntimeCallInfo(RootVisitor & visitor)375 void FrameHandler::IterateEcmaRuntimeCallInfo(RootVisitor &visitor)
376 {
377     ASSERT(thread_->IsAsmInterpreter());
378     JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
379     for (FrameIterator it(current, thread_); !it.Done(); it.Advance()) {
380         ASSERT(it.GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
381         auto frame = it.GetFrame<InterpretedEntryFrame>();
382         frame->GCIterate(it, visitor);
383     }
384 }
385 
Iterate(RootVisitor & visitor)386 void FrameHandler::Iterate(RootVisitor &visitor)
387 {
388     if (thread_->IsAsmInterpreter()) {
389         IterateEcmaRuntimeCallInfo(visitor);
390         IterateAssembleStack(visitor);
391         return;
392     }
393     JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
394     FrameType frameType = FrameHandler::GetFrameType(current);
395     if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) {
396         auto leaveFrame = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
397         if (leaveFrame != nullptr) {
398             current = leaveFrame;
399         }
400     }
401     // lazy assignment: only Iterate need arkStackMapParser_ in order to high improve performance
402     if (arkStackMapParser_ == nullptr) {
403         arkStackMapParser_ =
404             const_cast<JSThread *>(thread_)->GetEcmaVM()->GetAOTFileManager()->GetStackMapParser();
405     }
406     IterateFrameChain(current, visitor);
407 }
408 
IterateFrameChain(JSTaggedType * start,RootVisitor & visitor) const409 void FrameHandler::IterateFrameChain(JSTaggedType *start, RootVisitor &visitor) const
410 {
411     JSTaggedType *current = start;
412     // if the current frame type is BASELINE_BUILTIN_FRAME, the upper frame must be BaselineFrame.
413     // isBaselineFrame is used to differentiate the AsmInterpterFrame and BaselineFrame
414     bool isBaselineFrame = false;
415     for (FrameIterator it(current, thread_); !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
416         FrameType type = it.GetFrameType();
417         switch (type) {
418             case FrameType::OPTIMIZED_FRAME: {
419                 auto frame = it.GetFrame<OptimizedFrame>();
420                 frame->GCIterate(it, visitor);
421                 break;
422             }
423             case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
424             case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
425                 auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
426                 frame->GCIterate(it, visitor, type);
427                 break;
428             }
429             case FrameType::BASELINE_BUILTIN_FRAME: {
430                 isBaselineFrame = true;
431                 auto frame = it.GetFrame<BaselineBuiltinFrame>();
432                 frame->GCIterate(it, visitor);
433                 break;
434             }
435             case FrameType::FASTJIT_FUNCTION_FRAME:
436             case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: {
437                 auto frame = it.GetFrame<FASTJITFunctionFrame>();
438                 frame->GCIterate(it, visitor, type);
439                 break;
440             }
441             case FrameType::ASM_INTERPRETER_FRAME:
442             case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
443                 auto frame = it.GetFrame<AsmInterpretedFrame>();
444                 frame->GCIterate(it, visitor, isBaselineFrame);
445                 isBaselineFrame = false;
446                 break;
447             }
448             case FrameType::INTERPRETER_FRAME:
449             case FrameType::INTERPRETER_FAST_NEW_FRAME: {
450                 auto frame = it.GetFrame<InterpretedFrame>();
451                 frame->GCIterate(it, visitor);
452                 break;
453             }
454             case FrameType::INTERPRETER_BUILTIN_FRAME: {
455                 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
456                 frame->GCIterate(it, visitor);
457                 break;
458             }
459             case FrameType::LEAVE_FRAME: {
460                 auto frame = it.GetFrame<OptimizedLeaveFrame>();
461                 frame->GCIterate(it, visitor);
462                 break;
463             }
464             case FrameType::LEAVE_FRAME_WITH_ARGV: {
465                 auto frame = it.GetFrame<OptimizedWithArgvLeaveFrame>();
466                 frame->GCIterate(it, visitor);
467                 break;
468             }
469             case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
470                 auto frame = it.GetFrame<OptimizedBuiltinLeaveFrame>();
471                 frame->GCIterate(it, visitor);
472                 break;
473             }
474             case FrameType::BUILTIN_FRAME_WITH_ARGV: {
475                 auto frame = it.GetFrame<BuiltinWithArgvFrame>();
476                 frame->GCIterate(it, visitor);
477                 break;
478             }
479             case FrameType::BUILTIN_ENTRY_FRAME:
480             case FrameType::BUILTIN_FRAME: {
481                 auto frame = it.GetFrame<BuiltinFrame>();
482                 frame->GCIterate(it, visitor);
483                 break;
484             }
485             case FrameType::INTERPRETER_ENTRY_FRAME: {
486                 auto frame = it.GetFrame<InterpretedEntryFrame>();
487                 frame->GCIterate(it, visitor);
488                 break;
489             }
490             case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
491             case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
492             case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
493             case FrameType::OPTIMIZED_ENTRY_FRAME:
494             case FrameType::ASM_BRIDGE_FRAME:
495             case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
496             case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: {
497                 break;
498             }
499             default: {
500                 LOG_FULL(FATAL) << "frame type error!";
501                 UNREACHABLE();
502             }
503         }
504     }
505 }
506 }  // namespace panda::ecmascript
507