1/*
2 * Copyright (c) 2023 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/compiler/codegen/maple/litecg_codegen.h"
17#if defined(PANDA_TARGET_MACOS) || defined(PANDA_TARGET_IOS)
18#include "ecmascript/base/llvm_helper.h"
19#endif
20
21#include <cstring>
22#include <iomanip>
23#include <vector>
24
25#include "ecmascript/compiler/call_signature.h"
26#include "ecmascript/compiler/codegen/maple/litecg_ir_builder.h"
27#include "ecmascript/compiler/codegen/maple/maple_be/include/litecg/litecg.h"
28#include "ecmascript/compiler/codegen/maple/maple_be/include/litecg/lmir_builder.h"
29#include "ecmascript/compiler/compiler_log.h"
30#include "ecmascript/ecma_macros.h"
31#include "ecmascript/mem/region.h"
32#include "ecmascript/object_factory.h"
33#include "ecmascript/stackmap/litecg/litecg_stackmap_type.h"
34#include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h"
35#ifdef JIT_ENABLE_CODE_SIGN
36#include "jit_buffer_integrity.h"
37#include "ecmascript/compiler/jit_signcode.h"
38#endif
39
40namespace panda::ecmascript::kungfu {
41#ifdef JIT_ENABLE_CODE_SIGN
42using namespace panda::ecmascript::kungfu;
43using namespace OHOS::Security::CodeSign;
44#endif
45class CompilerLog;
46
47using namespace panda::ecmascript;
48
49LiteCGAssembler::LiteCGAssembler(LMIRModule &module, CodeInfo::CodeSpaceOnDemand &codeSpaceOnDemand,
50                                 const std::vector<std::string> &litecgOptions)
51    : Assembler(codeSpaceOnDemand), lmirModule(module), litecgOptions(litecgOptions) {}
52
53static uint8_t *AllocateCodeSection(void *object, uint32_t size, [[maybe_unused]] uint32_t alignment,
54                                    const std::string &sectionName)
55{
56    struct CodeInfo &state = *static_cast<struct CodeInfo *>(object);
57    return state.AllocaCodeSection(size, sectionName.c_str());
58}
59
60static uint8_t *AllocateCodeSectionOnDemand(void *object, uint32_t size, [[maybe_unused]] uint32_t alignment,
61                                            const std::string &sectionName)
62{
63    struct CodeInfo &state = *static_cast<struct CodeInfo *>(object);
64    return state.AllocaCodeSectionOnDemand(size, sectionName.c_str());
65}
66
67static void SaveFunc2Addr(void *object, std::string funcName, uint32_t address)
68{
69    struct CodeInfo &state = *static_cast<struct CodeInfo *>(object);
70    state.SaveFunc2Addr(funcName, address);
71}
72
73static void SaveFunc2FPtoPrevSPDelta(void *object, std::string funcName, int32_t fp2PrevSpDelta)
74{
75    struct CodeInfo &state = *static_cast<struct CodeInfo *>(object);
76    state.SaveFunc2FPtoPrevSPDelta(funcName, fp2PrevSpDelta);
77}
78
79static void SaveFunc2CalleeOffsetInfo(void *object, std::string funcName, kungfu::CalleeRegAndOffsetVec calleeRegInfo)
80{
81    struct CodeInfo &state = *static_cast<struct CodeInfo *>(object);
82    state.SaveFunc2CalleeOffsetInfo(funcName, calleeRegInfo);
83}
84
85static void SavePC2DeoptInfo(void *object, uint64_t pc, std::vector<uint8_t> deoptInfo)
86{
87    struct CodeInfo &state = *static_cast<struct CodeInfo *>(object);
88    state.SavePC2DeoptInfo(pc, deoptInfo);
89}
90
91void SavePC2CallSiteInfo(void *object, uint64_t pc, std::vector<uint8_t> callSiteInfo)
92{
93    struct CodeInfo &state = *static_cast<struct CodeInfo *>(object);
94    state.SavePC2CallSiteInfo(pc, callSiteInfo);
95}
96
97void LiteCGAssembler::Run(const CompilerLog &log, [[maybe_unused]] bool fastCompileMode, bool isJit)
98{
99    std::vector<std::string> options(litecgOptions);
100    if (log.OutputASM()) {
101        options.push_back("--verbose-asm");
102    }
103    if (log.OutputLLIR()) {
104        options.push_back("-verbose");
105    }
106    maple::litecg::LiteCG liteCG(*lmirModule.GetModule(), options);
107#ifdef ARK_LITECG_DEBUG
108    if (log.OutputLLIR()) {
109        std::string irFileName = lmirModule.GetModule()->GetFileName() + ".mpl";
110        liteCG.DumpIRToFile(irFileName);
111    }
112#endif
113    liteCG.SetupLiteCGEmitMemoryManager(&codeInfo_, isJit ? AllocateCodeSectionOnDemand : AllocateCodeSection,
114                                        SaveFunc2Addr, SaveFunc2FPtoPrevSPDelta, SaveFunc2CalleeOffsetInfo,
115                                        SavePC2DeoptInfo, SavePC2CallSiteInfo);
116#ifdef JIT_ENABLE_CODE_SIGN
117    isJit &= JitFort::IsResourceAvailable();
118    if (isJit) {
119        JitCodeSignerBase *jitSigner = CreateJitCodeSigner(JitBufferIntegrityLevel::Level0);
120        JitSignCode *singleton = JitSignCode::GetInstance();
121        singleton->Reset();
122        singleton->SetCodeSigner(jitSigner);
123        singleton->SetKind(1);
124    }
125#endif
126    liteCG.DoCG(isJit);
127}
128
129void LiteCGIRGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
130                                                const CompilationConfig *cfg)
131{
132    (void)circuit;
133    (void)graph;
134    (void)index;
135    (void)cfg;
136}
137
138void LiteCGIRGeneratorImpl::GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
139                                         const panda::ecmascript::MethodLiteral *methodLiteral,
140                                         const JSPandaFile *jsPandaFile, const std::string &methodName,
141                                         const FrameType frameType,
142                                         bool enableOptInlining, [[maybe_unused]]bool enableBranchProfiling)
143{
144    circuit->SetFrameType(frameType);
145    CallSignature::CallConv conv;
146    if (methodLiteral->IsFastCall()) {
147        conv = CallSignature::CallConv::CCallConv;
148    } else {
149        conv = CallSignature::CallConv::WebKitJSCallConv;
150    }
151    LiteCGIRBuilder builder(&graph, circuit, module_, cfg, conv, enableLog_, enableOptInlining, methodLiteral,
152                            jsPandaFile, methodName);
153    builder.Build();
154}
155
156void LiteCGAssembler::CollectAnStackMap(CGStackMapInfo &stackMapInfo)
157{
158    auto &liteCGStackMapInfo = static_cast<LiteCGStackMapInfo&>(stackMapInfo);
159    const auto &codeInfo = GetCodeInfo();
160    liteCGStackMapInfo.AppendCallSiteInfo(codeInfo.GetPC2CallsiteInfo());
161    liteCGStackMapInfo.AppendDeoptInfo(codeInfo.GetPC2DeoptInfo());
162}
163}  // namespace panda::ecmascript::kungfu
164