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/compiler/aot_file/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(IsInterpretedFrame());
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_FAST_CALL_FUNCTION_FRAME:
187 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
188 auto *frame = OptimizedJSFunctionFrame::GetFrameFromSp(sp_);
189 return frame->GetFunction();
190 }
191 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
192 case FrameType::INTERPRETER_FRAME:
193 case FrameType::INTERPRETER_FAST_NEW_FRAME:
194 case FrameType::INTERPRETER_ENTRY_FRAME:
195 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
196 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
197 case FrameType::INTERPRETER_BUILTIN_FRAME:
198 case FrameType::OPTIMIZED_FRAME:
199 case FrameType::ASM_BRIDGE_FRAME:
200 case FrameType::LEAVE_FRAME:
201 case FrameType::LEAVE_FRAME_WITH_ARGV:
202 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
203 case FrameType::OPTIMIZED_ENTRY_FRAME:
204 default: {
205 LOG_FULL(FATAL) << "frame type error!";
206 UNREACHABLE();
207 }
208 }
209 } else {
210 FrameType type = GetFrameType();
211 if (type == FrameType::INTERPRETER_FRAME || type == FrameType::INTERPRETER_FAST_NEW_FRAME) {
212 auto *frame = InterpretedFrame::GetFrameFromSp(sp_);
213 return frame->function;
214 } else {
215 auto *frame = InterpretedBuiltinFrame::GetFrameFromSp(sp_);
216 return frame->function;
217 }
218 }
219 }
220
GetPc() const221 const uint8_t *FrameHandler::GetPc() const
222 {
223 ASSERT(IsJSFrame());
224 FrameIterator it(sp_, thread_);
225 if (IsAsmInterpretedFrame()) {
226 auto *frame = it.GetFrame<AsmInterpretedFrame>();
227 return frame->GetPc();
228 } else {
229 auto *frame = it.GetFrame<InterpretedFrame>();
230 return frame->GetPc();
231 }
232 }
233
GetConstpool() const234 ConstantPool *FrameHandler::GetConstpool() const
235 {
236 ASSERT(IsInterpretedFrame());
237 auto method = GetMethod();
238 JSTaggedValue constpool = method->GetConstantPool();
239 return ConstantPool::Cast(constpool.GetTaggedObject());
240 }
241
GetEnv() const242 JSTaggedValue FrameHandler::GetEnv() const
243 {
244 ASSERT(IsInterpretedFrame());
245 FrameIterator it(sp_, thread_);
246 if (IsAsmInterpretedFrame()) {
247 auto *frame = it.GetFrame<AsmInterpretedFrame>();
248 return frame->GetEnv();
249 } else {
250 auto *frame = it.GetFrame<InterpretedFrame>();
251 return frame->env;
252 }
253 }
254
DumpStack(std::ostream & os) const255 void FrameHandler::DumpStack(std::ostream &os) const
256 {
257 size_t i = 0;
258 FrameHandler frameHandler(thread_);
259 for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) {
260 os << "[" << i++
261 << "]:" << frameHandler.GetMethod()->ParseFunctionName()
262 << "\n";
263 }
264 }
265
DumpPC(std::ostream & os,const uint8_t * pc) const266 void FrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const
267 {
268 FrameHandler frameHandler(thread_);
269 ASSERT(frameHandler.HasFrame());
270 // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
271 int offset = pc - frameHandler.GetMethod()->GetBytecodeArray();
272 os << "offset: " << offset << "\n";
273 }
274
GetInterpretedFrameEnd(JSTaggedType * prevSp) const275 ARK_INLINE uintptr_t FrameHandler::GetInterpretedFrameEnd(JSTaggedType *prevSp) const
276 {
277 uintptr_t end = 0U;
278 FrameIterator it(prevSp, thread_);
279 FrameType type = it.GetFrameType();
280 switch (type) {
281 case FrameType::ASM_INTERPRETER_FRAME:
282 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
283 auto frame = it.GetFrame<AsmInterpretedFrame>();
284 end = ToUintPtr(frame);
285 break;
286 }
287 case FrameType::INTERPRETER_FRAME:
288 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
289 auto frame = it.GetFrame<InterpretedFrame>();
290 end = ToUintPtr(frame);
291 break;
292 }
293 case FrameType::INTERPRETER_ENTRY_FRAME: {
294 auto frame = it.GetFrame<InterpretedEntryFrame>();
295 end = ToUintPtr(frame);
296 break;
297 }
298 case FrameType::INTERPRETER_BUILTIN_FRAME: {
299 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
300 end = ToUintPtr(frame);
301 break;
302 }
303 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME :
304 case FrameType::BUILTIN_FRAME_WITH_ARGV:
305 case FrameType::BUILTIN_ENTRY_FRAME:
306 case FrameType::BUILTIN_FRAME:
307 case FrameType::OPTIMIZED_FRAME:
308 case FrameType::ASM_BRIDGE_FRAME:
309 case FrameType::LEAVE_FRAME:
310 case FrameType::LEAVE_FRAME_WITH_ARGV:
311 case FrameType::BUILTIN_CALL_LEAVE_FRAME:
312 case FrameType::OPTIMIZED_ENTRY_FRAME:
313 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
314 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME:
315 default: {
316 LOG_FULL(FATAL) << "frame type error!";
317 UNREACHABLE();
318 }
319 }
320 return end;
321 }
322
IterateAssembleStack(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor,const RootBaseAndDerivedVisitor & derivedVisitor)323 void FrameHandler::IterateAssembleStack(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
324 const RootBaseAndDerivedVisitor &derivedVisitor)
325 {
326 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
327 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor);
328 }
329
330 // We seperate InterpretedEntryFrame from assemble stack when asm interpreter is enable.
331 // To protect EcmaRuntimeCallInfo on InterpretedEntryFrame, we iterate InterpretedEntryFrame on thread sp individually.
332 // And only InterpretedEntryFrame is on thread sp when asm interpreter is enable.
IterateEcmaRuntimeCallInfo(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor)333 void FrameHandler::IterateEcmaRuntimeCallInfo(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor)
334 {
335 ASSERT(thread_->IsAsmInterpreter());
336 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
337 for (FrameIterator it(current, thread_); !it.Done(); it.Advance()) {
338 ASSERT(it.GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
339 auto frame = it.GetFrame<InterpretedEntryFrame>();
340 frame->GCIterate(it, visitor, rangeVisitor);
341 }
342 }
343
Iterate(const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor,const RootBaseAndDerivedVisitor & derivedVisitor)344 void FrameHandler::Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
345 const RootBaseAndDerivedVisitor &derivedVisitor)
346 {
347 if (thread_->IsAsmInterpreter()) {
348 IterateEcmaRuntimeCallInfo(visitor, rangeVisitor);
349 IterateAssembleStack(visitor, rangeVisitor, derivedVisitor);
350 return;
351 }
352 JSTaggedType *current = const_cast<JSTaggedType *>(thread_->GetCurrentSPFrame());
353 FrameType frameType = FrameHandler::GetFrameType(current);
354 if (frameType != FrameType::INTERPRETER_ENTRY_FRAME) {
355 auto leaveFrame = const_cast<JSTaggedType *>(thread_->GetLastLeaveFrame());
356 if (leaveFrame != nullptr) {
357 current = leaveFrame;
358 }
359 }
360 // lazy assignment: only Iterate need arkStackMapParser_ in order to high improve performance
361 if (arkStackMapParser_ == nullptr) {
362 arkStackMapParser_ =
363 const_cast<JSThread *>(thread_)->GetCurrentEcmaContext()->GetAOTFileManager()->GetStackMapParser();
364 }
365 IterateFrameChain(current, visitor, rangeVisitor, derivedVisitor);
366 }
367
IterateFrameChain(JSTaggedType * start,const RootVisitor & visitor,const RootRangeVisitor & rangeVisitor,const RootBaseAndDerivedVisitor & derivedVisitor) const368 void FrameHandler::IterateFrameChain(JSTaggedType *start, const RootVisitor &visitor,
369 const RootRangeVisitor &rangeVisitor, const RootBaseAndDerivedVisitor &derivedVisitor) const
370 {
371 JSTaggedType *current = start;
372 for (FrameIterator it(current, thread_); !it.Done(); it.Advance<GCVisitedFlag::VISITED>()) {
373 FrameType type = it.GetFrameType();
374 switch (type) {
375 case FrameType::OPTIMIZED_FRAME: {
376 auto frame = it.GetFrame<OptimizedFrame>();
377 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor);
378 break;
379 }
380 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME:
381 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: {
382 auto frame = it.GetFrame<OptimizedJSFunctionFrame>();
383 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor, type);
384 break;
385 }
386 case FrameType::ASM_INTERPRETER_FRAME:
387 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: {
388 auto frame = it.GetFrame<AsmInterpretedFrame>();
389 frame->GCIterate(it, visitor, rangeVisitor, derivedVisitor);
390 break;
391 }
392 case FrameType::INTERPRETER_FRAME:
393 case FrameType::INTERPRETER_FAST_NEW_FRAME: {
394 auto frame = it.GetFrame<InterpretedFrame>();
395 frame->GCIterate(it, visitor, rangeVisitor);
396 break;
397 }
398 case FrameType::INTERPRETER_BUILTIN_FRAME: {
399 auto frame = it.GetFrame<InterpretedBuiltinFrame>();
400 frame->GCIterate(it, visitor, rangeVisitor);
401 break;
402 }
403 case FrameType::LEAVE_FRAME: {
404 auto frame = it.GetFrame<OptimizedLeaveFrame>();
405 frame->GCIterate(it, visitor, rangeVisitor);
406 break;
407 }
408 case FrameType::LEAVE_FRAME_WITH_ARGV: {
409 auto frame = it.GetFrame<OptimizedWithArgvLeaveFrame>();
410 frame->GCIterate(it, visitor, rangeVisitor);
411 break;
412 }
413 case FrameType::BUILTIN_CALL_LEAVE_FRAME: {
414 auto frame = it.GetFrame<OptimizedBuiltinLeaveFrame>();
415 frame->GCIterate(it, visitor, rangeVisitor);
416 break;
417 }
418 case FrameType::BUILTIN_FRAME_WITH_ARGV: {
419 auto frame = it.GetFrame<BuiltinWithArgvFrame>();
420 frame->GCIterate(it, visitor, rangeVisitor);
421 break;
422 }
423 case FrameType::BUILTIN_ENTRY_FRAME:
424 case FrameType::BUILTIN_FRAME: {
425 auto frame = it.GetFrame<BuiltinFrame>();
426 frame->GCIterate(it, visitor, rangeVisitor);
427 break;
428 }
429 case FrameType::INTERPRETER_ENTRY_FRAME: {
430 auto frame = it.GetFrame<InterpretedEntryFrame>();
431 frame->GCIterate(it, visitor, rangeVisitor);
432 break;
433 }
434 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME:
435 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME:
436 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME:
437 case FrameType::OPTIMIZED_ENTRY_FRAME:
438 case FrameType::ASM_BRIDGE_FRAME:
439 case FrameType::ASM_INTERPRETER_ENTRY_FRAME:
440 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: {
441 break;
442 }
443 default: {
444 LOG_FULL(FATAL) << "frame type error!";
445 UNREACHABLE();
446 }
447 }
448 }
449 }
450 } // namespace panda::ecmascript
451