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::LEAVE_FRAME:
198 case FrameType::LEAVE_FRAME_WITH_ARGV:
199 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
200 case FrameType::OPTIMIZED_ENTRY_FRAME:
201 default: {
202 LOG_FULL(FATAL) << "frame type error!";
203 UNREACHABLE();
204 }
205 }
206 } else {
207 FrameType type = GetFrameType();
208 if (type == FrameType::INTERPRETER_FRAME || type == FrameType::INTERPRETER_FAST_NEW_FRAME) {
209 auto *frame = InterpretedFrame::GetFrameFromSp(sp_);
210 return frame->function;
211 } else {
212 auto *frame = InterpretedBuiltinFrame::GetFrameFromSp(sp_);
213 return frame->function;
214 }
215 }
216 }
217
GetPc() const218 const uint8_t *FrameHandler::GetPc() const
219 {
220 ASSERT(IsJSFrame());
221 FrameIterator it(sp_, thread_);
222 if (IsAsmInterpretedFrame()) {
223 auto *frame = it.GetFrame<AsmInterpretedFrame>();
224 return frame->GetPc();
225 } else {
226 auto *frame = it.GetFrame<InterpretedFrame>();
227 return frame->GetPc();
228 }
229 }
230
GetConstpool() const231 ConstantPool *FrameHandler::GetConstpool() const
232 {
233 ASSERT(IsInterpretedFrame());
234 auto method = GetMethod();
235 JSTaggedValue constpool = method->GetConstantPool();
236 return ConstantPool::Cast(constpool.GetTaggedObject());
237 }
238
GetEnv() const239 JSTaggedValue FrameHandler::GetEnv() const
240 {
241 ASSERT(IsInterpretedFrame());
242 FrameIterator it(sp_, thread_);
243 if (IsAsmInterpretedFrame()) {
244 auto *frame = it.GetFrame<AsmInterpretedFrame>();
245 return frame->GetEnv();
246 } else {
247 auto *frame = it.GetFrame<InterpretedFrame>();
248 return frame->env;
249 }
250 }
251
DumpStack(std::ostream & os) const252 void FrameHandler::DumpStack(std::ostream &os) const
253 {
254 size_t i = 0;
255 FrameHandler frameHandler(thread_);
256 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
257 os << "[" << i++
258 << "]:" << frameHandler.GetMethod()->ParseFunctionName()
259 << "\n";
260 }
261 }
262
DumpPC(std::ostream & os,const uint8_t * pc) const263 void FrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const
264 {
265 FrameHandler frameHandler(thread_);
266 ASSERT(frameHandler.HasFrame());
267 // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
268 int offset = pc - frameHandler.GetMethod()->GetBytecodeArray();
269 os << "offset: " << offset << "\n";
270 }
271
GetInterpretedFrameEnd(JSTaggedType * prevSp) const272 ARK_INLINE uintptr_t FrameHandler::GetInterpretedFrameEnd(JSTaggedType *prevSp) const
273 {
274 uintptr_t end = 0U;
275 FrameIterator it(prevSp, thread_);
276 FrameType type = it.GetFrameType();
277 switch (type) {
278 case FrameType::ASM_INTERPRETER_FRAME:
279 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
280 auto frame = it.GetFrame<AsmInterpretedFrame>();
281 end = ToUintPtr(frame);
282 break;
283 }
284 case FrameType::INTERPRETER_FRAME:
285 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
286 auto frame = it.GetFrame<InterpretedFrame>();
287 end = ToUintPtr(frame);
288 break;
289 }
290 case FrameType::INTERPRETER_ENTRY_FRAME: {
291 auto frame = it.GetFrame<InterpretedEntryFrame>();
292 end = ToUintPtr(frame);
293 break;
294 }
295 case FrameType::INTERPRETER_BUILTIN_FRAME: {
296 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
297 end = ToUintPtr(frame);
298 break;
299 }
300 case FrameType::BUILTIN_FRAME_WITH_ARGV:
301 case FrameType::BUILTIN_ENTRY_FRAME:
302 case FrameType::BUILTIN_FRAME:
303 case FrameType::OPTIMIZED_FRAME:
304 case FrameType::LEAVE_FRAME:
305 case FrameType::LEAVE_FRAME_WITH_ARGV:
306 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
307 case FrameType::OPTIMIZED_ENTRY_FRAME:
308 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
309 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
310 default: {
311 LOG_FULL(FATAL) << "frame type error!";
312 UNREACHABLE();
313 }
314 }
315 return end;
316 }
317
IterateAssembleStack(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor,const RootBaseAndDerivedVisitor & derivedVisitor)318 void FrameHandler::IterateAssembleStack(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
319 const RootBaseAndDerivedVisitor &derivedVisitor)
320 {
321 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
322 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor);
323 }
324
325 // We seperate InterpretedEntryFrame from assemble stack when asm interpreter is enable.
326 // To protect EcmaRuntimeCallInfo on InterpretedEntryFrame, we iterate InterpretedEntryFrame on thread sp individually.
327 // And only InterpretedEntryFrame is on thread sp when asm interpreter is enable.
IterateEcmaRuntimeCallInfo(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor)328 void FrameHandler::IterateEcmaRuntimeCallInfo(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor)
329 {
330 ASSERT(thread_->IsAsmInterpreter());
331 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
332 for (FrameIterator it(current, thread_); !it.Done(); it.Advance()) {
333 ASSERT(it.GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
334 auto frame = it.GetFrame<InterpretedEntryFrame>();
335 frame->GCIterate(it, visitor, rangeVisitor);
336 }
337 }
338
Iterate(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor,const RootBaseAndDerivedVisitor & derivedVisitor)339 void FrameHandler::Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
340 const RootBaseAndDerivedVisitor &derivedVisitor)
341 {
342 if (thread_->IsAsmInterpreter()) {
343 IterateEcmaRuntimeCallInfo(visitor, rangeVisitor);
344 IterateAssembleStack(visitor, rangeVisitor, derivedVisitor);
345 return;
346 }
347 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
348 FrameType frameType = FrameHandler::GetFrameType(current);
349 if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) {
350 auto leaveFrame = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
351 if (leaveFrame != nullptr) {
352 current = leaveFrame;
353 }
354 }
355 // lazy assignment: only Iterate need arkStackMapParser_ in order to high improve performance
356 if (arkStackMapParser_ == nullptr) {
357 arkStackMapParser_ = thread_->GetEcmaVM()->GetAOTFileManager()->GetStackMapParser();
358 }
359 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor);
360 }
361
IterateFrameChain(JSTaggedType * start,const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor,const RootBaseAndDerivedVisitor & derivedVisitor) const362 void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &visitor,
363 const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const
364 {
365 JSTaggedType *current = start;
366 for (FrameIterator it(current, thread_); !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
367 FrameType type = it.GetFrameType();
368 switch (type) {
369 case FrameType::OPTIMIZED_FRAME: {
370 auto frame = it.GetFrame<OptimizedFrame>();
371 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor);
372 break;
373 }
374 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
375 auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
376 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor);
377 break;
378 }
379 case FrameType::ASM_INTERPRETER_FRAME:
380 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
381 auto frame = it.GetFrame<AsmInterpretedFrame>();
382 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor);
383 break;
384 }
385 case FrameType::INTERPRETER_FRAME:
386 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
387 auto frame = it.GetFrame<InterpretedFrame>();
388 frame->GCIterate(it, visitor, rangeVisitor);
389 break;
390 }
391 case FrameType::INTERPRETER_BUILTIN_FRAME: {
392 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
393 frame->GCIterate(it, visitor, rangeVisitor);
394 break;
395 }
396 case FrameType::LEAVE_FRAME: {
397 auto frame = it.GetFrame<OptimizedLeaveFrame>();
398 frame->GCIterate(it, visitor, rangeVisitor);
399 break;
400 }
401 case FrameType::LEAVE_FRAME_WITH_ARGV: {
402 auto frame = it.GetFrame<OptimizedWithArgvLeaveFrame>();
403 frame->GCIterate(it, visitor, rangeVisitor);
404 break;
405 }
406 case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
407 auto frame = it.GetFrame<OptimizedBuiltinLeaveFrame>();
408 frame->GCIterate(it, visitor, rangeVisitor);
409 break;
410 }
411 case FrameType::BUILTIN_FRAME_WITH_ARGV: {
412 auto frame = it.GetFrame<BuiltinWithArgvFrame>();
413 frame->GCIterate(it, visitor, rangeVisitor);
414 break;
415 }
416 case FrameType::BUILTIN_ENTRY_FRAME:
417 case FrameType::BUILTIN_FRAME: {
418 auto frame = it.GetFrame<BuiltinFrame>();
419 frame->GCIterate(it, visitor, rangeVisitor);
420 break;
421 }
422 case FrameType::INTERPRETER_ENTRY_FRAME: {
423 auto frame = it.GetFrame<InterpretedEntryFrame>();
424 frame->GCIterate(it, visitor, rangeVisitor);
425 break;
426 }
427 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
428 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
429 case FrameType::OPTIMIZED_ENTRY_FRAME:
430 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
431 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: {
432 break;
433 }
434 default: {
435 LOG_FULL(FATAL) << "frame type error!";
436 UNREACHABLE();
437 }
438 }
439 }
440 }
441
GetAotExceptionFuncName(JSTaggedType * argv) const442 std::string FrameBcCollector::GetAotExceptionFuncName(JSTaggedType* argv) const
443 {
444 JSTaggedValue func = JSTaggedValue(*(argv)); // 3: skip returnaddr and argc
445 Method *method = JSFunction::Cast(func.GetTaggedObject())->GetCallTarget();
446 return method->GetMethodName();
447 }
448
CollectBCOffsetInfo()449 void FrameBcCollector::CollectBCOffsetInfo()
450 {
451 thread_->GetEcmaVM()->ClearExceptionBCList();
452 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
453 FrameIterator it(current, thread_);
454 it.Advance<GCVisitedFlag::VISITED>();
455
456 for (; !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
457 FrameType type = it.GetFrameType();
458 switch (type) {
459 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
460 auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
461 kungfu::ConstInfo constInfo;
462 frame->CollectBCOffsetInfo(it, constInfo);
463 if (!constInfo.empty()) {
464 auto name = GetAotExceptionFuncName(frame->GetArgv(it));
465 thread_->GetEcmaVM()->StoreBCOffsetInfo(name, constInfo[0]);
466 }
467 break;
468 }
469 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
470 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
471 case FrameType::LEAVE_FRAME:
472 case FrameType::OPTIMIZED_ENTRY_FRAME:
473 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
474 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
475 case FrameType::ASM_INTERPRETER_FRAME:
476 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME:
477 case FrameType::INTERPRETER_FRAME:
478 case FrameType::INTERPRETER_FAST_NEW_FRAME:
479 case FrameType::OPTIMIZED_FRAME:
480 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
481 case FrameType::LEAVE_FRAME_WITH_ARGV:
482 case FrameType::BUILTIN_FRAME_WITH_ARGV:
483 case FrameType::BUILTIN_ENTRY_FRAME:
484 case FrameType::BUILTIN_FRAME:
485 case FrameType::INTERPRETER_ENTRY_FRAME: {
486 break;
487 }
488 default: {
489 LOG_FULL(FATAL) << "frame type error!";
490 UNREACHABLE();
491 }
492 }
493 }
494 }
495 } // namespace panda::ecmascript
496