1/*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/method.h"
17
18#include "ecmascript/jspandafile/program_object.h"
19
20namespace panda::ecmascript {
21std::string Method::ParseFunctionName() const
22{
23    const JSPandaFile *jsPandaFile = GetJSPandaFile();
24    return MethodLiteral::ParseFunctionName(jsPandaFile, GetMethodId());
25}
26
27std::pair<std::string_view, bool> Method::ParseFunctionNameView() const
28{
29    const JSPandaFile *jsPandaFile = GetJSPandaFile();
30    return MethodLiteral::ParseFunctionNameView(jsPandaFile, GetMethodId());
31}
32
33const char *Method::GetMethodName() const
34{
35    const JSPandaFile *jsPandaFile = GetJSPandaFile();
36    return MethodLiteral::GetMethodName(jsPandaFile, GetMethodId());
37}
38
39const char *Method::GetMethodName(const JSPandaFile *file) const
40{
41    return MethodLiteral::GetMethodName(file, GetMethodId());
42}
43
44const CString Method::GetRecordNameStr() const
45{
46    const JSPandaFile *jsPandaFile = GetJSPandaFile();
47    return MethodLiteral::GetRecordName(jsPandaFile, GetMethodId());
48}
49
50uint32_t Method::GetCodeSize() const
51{
52    const JSPandaFile *jsPandaFile = GetJSPandaFile();
53    return MethodLiteral::GetCodeSize(jsPandaFile, GetMethodId());
54}
55
56const JSPandaFile *Method::GetJSPandaFile() const
57{
58    JSTaggedValue constpool = GetConstantPool();
59    if (constpool.IsUndefined()) {
60        return nullptr;
61    }
62
63    const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
64    return taggedPool->GetJSPandaFile();
65}
66
67MethodLiteral *Method::GetMethodLiteral() const
68{
69    if (IsAotWithCallField() || IsDeoptimized()) {
70        ASSERT(!IsNativeWithCallField());
71        const JSPandaFile *jsPandaFile = GetJSPandaFile();
72        ASSERT(jsPandaFile != nullptr);
73        return jsPandaFile->FindMethodLiteral(GetMethodId().GetOffset());
74    }
75    return reinterpret_cast<MethodLiteral *>(GetCodeEntryOrLiteral());
76}
77
78bool Method::IsDeoptimized() const
79{
80    return GetDeoptType() != kungfu::DeoptType::NONE;
81}
82
83uint32_t Method::FindCatchBlock(uint32_t pc) const
84{
85    ASSERT(!IsNativeWithCallField());
86    ASSERT(GetJSPandaFile() != nullptr);
87    auto *pandaFile = GetJSPandaFile()->GetPandaFile();
88    ASSERT(pandaFile != nullptr);
89    panda_file::MethodDataAccessor mda(*pandaFile, GetMethodId());
90    panda_file::CodeDataAccessor cda(*pandaFile, mda.GetCodeId().value());
91
92    uint32_t pcOffset = INVALID_INDEX;
93    cda.EnumerateTryBlocks([&pcOffset, pc](panda_file::CodeDataAccessor::TryBlock &tryBlock) {
94        if ((tryBlock.GetStartPc() <= pc) && ((tryBlock.GetStartPc() + tryBlock.GetLength()) > pc)) {
95            tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
96                pcOffset = catchBlock.GetHandlerPc();
97                return false;
98            });
99        }
100        return pcOffset == INVALID_INDEX;
101    });
102    return pcOffset;
103}
104
105bool Method::HasCatchBlock() const
106{
107    ASSERT(GetJSPandaFile() != nullptr);
108    auto *pandaFile = GetJSPandaFile()->GetPandaFile();
109    ASSERT(pandaFile != nullptr);
110    panda_file::MethodDataAccessor mda(*pandaFile, GetMethodId());
111    panda_file::CodeDataAccessor cda(*pandaFile, mda.GetCodeId().value());
112    return cda.GetTriesSize() != 0;
113}
114
115JSHandle<Method> Method::Create(JSThread *thread, const JSPandaFile *jsPandaFile, MethodLiteral *methodLiteral)
116{
117    EcmaVM *vm = thread->GetEcmaVM();
118    EntityId methodId = methodLiteral->GetMethodId();
119    JSTaggedValue patchVal = vm->GetQuickFixManager()->CheckAndGetPatch(thread, jsPandaFile, methodId);
120    if (!patchVal.IsHole()) {
121        return JSHandle<Method>(thread, patchVal);
122    }
123
124    JSHandle<Method> method;
125    method = vm->GetFactory()->NewSMethod(methodLiteral);
126    JSHandle<ConstantPool> newConstpool = thread->GetCurrentEcmaContext()->FindOrCreateConstPool(jsPandaFile, methodId);
127    method->SetConstantPool(thread, newConstpool);
128    return method;
129}
130
131void Method::SetCodeEntryAndMarkAOTWhenBinding(uintptr_t codeEntry)
132{
133    SetAotCodeBit(true);
134    SetNativeBit(false);
135    SetCodeEntryOrLiteral(codeEntry);
136}
137
138void Method::ClearAOTStatusWhenDeopt(uintptr_t entry)
139{
140    ClearAOTFlagsWhenInit();
141    // Do not clear deopt type, which records a method has deoptimized before
142    SetCodeEntryOrLiteral(entry);
143}
144
145void Method::ClearAOTFlagsWhenInit()
146{
147    SetAotCodeBit(false);
148    SetIsFastCall(false);
149}
150
151void Method::InitInterpreterStatusForCompiledMethod(const JSThread *thread)
152{
153    if (!IsAotWithCallField()) {
154        return;
155    }
156    bool isFastCall = IsFastCall();
157    uintptr_t entry =
158        isFastCall ? thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_FastCallToAsmInterBridge)
159                   : thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_AOTCallToAsmInterBridge);
160    SetCodeEntryOrLiteral(entry);
161    ClearAOTFlagsWhenInit();
162    SetDeoptType(kungfu::DeoptType::INIT_AOT_FAILED);
163}
164} // namespace panda::ecmascript
165