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