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