1/*
2 * Copyright (c) 2021-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 "generateBin.h"
17#include "bytecode_optimizer/bytecodeopt_options.h"
18#include "bytecode_optimizer/optimize_bytecode.h"
19#include "compiler/compiler_logger.h"
20#include "compiler/compiler_options.h"
21
22namespace ark::es2panda::util {
23
24[[maybe_unused]] static void InitializeLogging(const util::Options *options)
25{
26    ark::Logger::ComponentMask componentMask;
27    componentMask.set(ark::Logger::Component::ASSEMBLER);
28    componentMask.set(ark::Logger::Component::COMPILER);
29    componentMask.set(ark::Logger::Component::BYTECODE_OPTIMIZER);
30
31    if (!ark::Logger::IsInitialized()) {
32        ark::Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), componentMask);
33    } else {
34        ark::Logger::EnableComponent(componentMask);
35    }
36}
37
38#ifdef PANDA_WITH_BYTECODE_OPTIMIZER
39static int OptimizeBytecode(ark::pandasm::Program *prog, const util::Options *options, const ReporterFun &reporter,
40                            std::map<std::string, size_t> *statp,
41                            ark::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp)
42{
43    if (options->OptLevel() != 0) {
44        InitializeLogging(options);
45        if (!ark::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) {
46            reporter("Failed to emit binary data: " + ark::pandasm::AsmEmitter::GetLastError());
47            return 1;
48        }
49
50        ark::bytecodeopt::g_options.SetOptLevel(options->OptLevel());
51        // Set default value instead of maximum set in ark::bytecodeopt::SetCompilerOptions()
52        ark::compiler::CompilerLogger::Init({"all"});
53        ark::compiler::g_options.SetCompilerMaxBytecodeSize(ark::compiler::g_options.GetCompilerMaxBytecodeSize());
54        ark::bytecodeopt::OptimizeBytecode(prog, mapsp, options->CompilerOutput(), options->IsDynamic(), true);
55    }
56
57    return 0;
58}
59#endif
60
61static int GenerateProgramImpl(ark::pandasm::Program *prog, const util::Options *options, const ReporterFun &reporter,
62                               std::map<std::string, size_t> *statp,
63                               ark::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp)
64{
65    if (options->CompilerOptions().dumpAsm) {
66        es2panda::Compiler::DumpAsm(prog);
67    }
68
69    if (!ark::pandasm::AsmEmitter::AssignProfileInfo(prog)) {
70        reporter("AssignProfileInfo failed");
71        return 1;
72    }
73
74    if (!ark::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) {
75        reporter("Failed to emit binary data: " + ark::pandasm::AsmEmitter::GetLastError());
76        return 1;
77    }
78
79    if (options->SizeStat()) {
80        size_t totalSize = 0;
81        std::cout << "Panda file size statistic:" << std::endl;
82        constexpr std::array<std::string_view, 2> INFO_STATS = {"instructions_number", "codesize"};
83
84        auto &stat = *statp;
85        for (const auto &[name, size] : stat) {
86            if (find(INFO_STATS.begin(), INFO_STATS.end(), name) != INFO_STATS.end()) {
87                continue;
88            }
89            std::cout << name << " section: " << size << std::endl;
90            totalSize += size;
91        }
92
93        for (const auto &name : INFO_STATS) {
94            std::cout << name << ": " << stat.at(std::string(name)) << std::endl;
95        }
96
97        std::cout << "total: " << totalSize << std::endl;
98    }
99
100    return 0;
101}
102
103int GenerateProgram(ark::pandasm::Program *prog, const util::Options *options, const ReporterFun &reporter)
104{
105    std::map<std::string, size_t> stat;
106    std::map<std::string, size_t> *statp = options->OptLevel() != 0 ? &stat : nullptr;
107    ark::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
108    ark::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = options->OptLevel() != 0 ? &maps : nullptr;
109
110#ifdef PANDA_WITH_BYTECODE_OPTIMIZER
111    if (OptimizeBytecode(prog, options, reporter, statp, mapsp) != 0) {
112        return 1;
113    }
114#endif
115    if (GenerateProgramImpl(prog, options, reporter, statp, mapsp) != 0) {
116        return 1;
117    }
118
119    return 0;
120}
121
122}  // namespace ark::es2panda::util
123