• 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 #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