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