1 /**
2 * Copyright (c) 2021-2025 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 "bytecode_optimizer/bytecodeopt_options.h"
17 #include "bytecode_optimizer/optimize_bytecode.h"
18 #include "compiler/compiler_logger.h"
19 #include "mem/arena_allocator.h"
20 #include "mem/pool_manager.h"
21 #include "es2panda.h"
22 #include "util/arktsconfig.h"
23 #include "util/diagnosticEngine.h"
24 #include "util/generateBin.h"
25 #include "util/options.h"
26 #include "util/plugin.h"
27 #include "libpandabase/os/stacktrace.h"
28 #include "generated/diagnostic.h"
29
30 #include <iostream>
31 #include <memory>
32 #include <optional>
33
34 namespace ark::es2panda::aot {
35 using mem::MemConfig;
36
37 class MemManager {
38 public:
MemManager()39 explicit MemManager()
40 {
41 MemConfig::Initialize(0, 0, COMPILER_SIZE, 0, 0, 0);
42 PoolManager::Initialize(PoolType::MMAP);
43 }
44
45 NO_COPY_SEMANTIC(MemManager);
46 NO_MOVE_SEMANTIC(MemManager);
47
~MemManager()48 ~MemManager()
49 {
50 PoolManager::Finalize();
51 MemConfig::Finalize();
52 }
53 };
54
CompileFromSource(es2panda::Compiler & compiler,es2panda::SourceFile & input,const util::Options & options,util::DiagnosticEngine & diagnosticEngine)55 static int CompileFromSource(es2panda::Compiler &compiler, es2panda::SourceFile &input, const util::Options &options,
56 util::DiagnosticEngine &diagnosticEngine)
57 {
58 auto program = std::unique_ptr<pandasm::Program> {compiler.Compile(input, options, diagnosticEngine)};
59 if (program == nullptr) {
60 const auto &err = compiler.GetError();
61
62 if (err.Type() == util::DiagnosticType::INVALID) {
63 if (diagnosticEngine.IsAnyError()) {
64 return 1;
65 }
66 // Intentional exit or --parse-only option usage.
67 return 0;
68 }
69 diagnosticEngine.Log(err);
70 return 1;
71 }
72
73 return util::GenerateProgram(
74 program.get(), options,
75 [&diagnosticEngine](const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams ¶ms) {
76 diagnosticEngine.LogDiagnostic(kind, params);
77 });
78 }
79
80 using StringPairVector = std::vector<std::pair<std::string, std::string>>;
81
CompileMultipleFiles(es2panda::Compiler & compiler,std::vector<SourceFile> & inputs,util::Options * options,util::DiagnosticEngine & diagnosticEngine)82 static int CompileMultipleFiles(es2panda::Compiler &compiler, std::vector<SourceFile> &inputs, util::Options *options,
83 util::DiagnosticEngine &diagnosticEngine)
84 {
85 std::vector<pandasm::Program *> result;
86 auto overallRes = compiler.CompileM(inputs, *options, diagnosticEngine, result);
87 for (size_t i = 0; i < result.size(); i++) {
88 auto *program = result[i];
89 if (program == nullptr) {
90 overallRes |= 1U;
91 continue;
92 }
93 options->SetOutput(std::string(inputs[i].dest));
94 overallRes |= (unsigned int)util::GenerateProgram(
95 program, *options,
96 [&diagnosticEngine](const diagnostic::DiagnosticKind &kind, const util::DiagnosticMessageParams ¶ms) {
97 diagnosticEngine.LogDiagnostic(kind, params);
98 });
99 }
100 return overallRes;
101 }
102
ReleaseInputsAndReturn(std::vector<std::string * > & parserInputs,unsigned int returnCode)103 static unsigned int ReleaseInputsAndReturn(std::vector<std::string *> &parserInputs, unsigned int returnCode)
104 {
105 for (auto *input : parserInputs) {
106 delete input;
107 }
108 parserInputs.clear();
109 return returnCode;
110 }
111
CompileFromConfig(es2panda::Compiler & compiler,util::Options * options,util::DiagnosticEngine & diagnosticEngine)112 static unsigned int CompileFromConfig(es2panda::Compiler &compiler, util::Options *options,
113 util::DiagnosticEngine &diagnosticEngine)
114 {
115 auto compilationList = FindProjectSources(options->ArkTSConfig());
116 if (compilationList.empty()) {
117 diagnosticEngine.LogDiagnostic(diagnostic::NO_INPUT, util::DiagnosticMessageParams {});
118 return 1;
119 }
120
121 std::vector<SourceFile> inputs {};
122 std::vector<std::string *> parserInputs;
123 unsigned int overallRes = 0;
124 for (auto &[src, dst] : compilationList) {
125 std::ifstream inputStream(src);
126 if (inputStream.fail()) {
127 diagnosticEngine.LogDiagnostic(diagnostic::OPEN_FAILED, util::DiagnosticMessageParams {src});
128 return 1;
129 }
130 std::stringstream ss;
131 ss << inputStream.rdbuf();
132 parserInputs.push_back(new std::string(ss.str()));
133 inputStream.close();
134 es2panda::SourceFile input(src, *parserInputs.back(), options->IsModule(), std::string_view(dst));
135 inputs.push_back(input);
136 }
137
138 if (options->IsPermArena() && (options->GetExtension() == util::gen::extension::ETS)) {
139 return ReleaseInputsAndReturn(parserInputs, CompileMultipleFiles(compiler, inputs, options, diagnosticEngine));
140 }
141
142 for (auto &input : inputs) {
143 LOG_IF(options->IsListFiles(), INFO, ES2PANDA)
144 << "> es2panda: compiling from '" << input.filePath << "' to '" << input.dest << "'";
145 options->SetOutput(std::string(input.dest));
146 auto res = CompileFromSource(compiler, input, *options, diagnosticEngine);
147 if (res != 0) {
148 diagnosticEngine.LogDiagnostic(diagnostic::COMPILE_FAILED,
149 util::DiagnosticMessageParams {input.filePath, input.dest});
150 overallRes |= static_cast<unsigned>(res);
151 }
152 }
153 return ReleaseInputsAndReturn(parserInputs, overallRes);
154 }
155
InitializePlugins(std::vector<std::string> const & names,util::DiagnosticEngine & diagnosticEngine)156 static std::optional<std::vector<util::Plugin>> InitializePlugins(std::vector<std::string> const &names,
157 util::DiagnosticEngine &diagnosticEngine)
158 {
159 std::vector<util::Plugin> res;
160 for (auto &name : names) {
161 auto plugin = util::Plugin(util::StringView {name});
162 if (!plugin.IsOk()) {
163 diagnosticEngine.LogDiagnostic(diagnostic::PLUGIN_LOAD_FAILED,
164 util::DiagnosticMessageParams {util::StringView(name)});
165 return std::nullopt;
166 }
167 plugin.Initialize();
168 res.push_back(std::move(plugin));
169 }
170 return {std::move(res)};
171 }
172
Run(Span<const char * const> args)173 static int Run(Span<const char *const> args)
174 {
175 auto diagnosticEngine = util::DiagnosticEngine();
176 auto options = std::make_unique<util::Options>(args[0], diagnosticEngine);
177 if (!options->Parse(args)) {
178 diagnosticEngine.FlushDiagnostic();
179 return 1;
180 }
181 diagnosticEngine.SetWError(options->IsEtsWarningsWerror());
182 ark::Logger::ComponentMask mask {};
183 mask.set(ark::Logger::Component::ES2PANDA);
184 ark::Logger::InitializeStdLogging(options->LogLevel(), mask);
185 util::DiagnosticEngine::InitializeSignalHandlers();
186
187 auto pluginsOpt = InitializePlugins(options->GetPlugins(), diagnosticEngine);
188 if (!pluginsOpt.has_value()) {
189 diagnosticEngine.FlushDiagnostic();
190 return 1;
191 }
192
193 es2panda::Compiler compiler(options->GetExtension(), options->GetThread(), std::move(pluginsOpt.value()));
194 if (options->IsListPhases()) {
195 std::cerr << "Available phases:" << std::endl;
196 std::cerr << compiler.GetPhasesList();
197 diagnosticEngine.FlushDiagnostic();
198 return 1;
199 }
200
201 int res;
202 if (options->GetCompilationMode() == CompilationMode::PROJECT) {
203 res = CompileFromConfig(compiler, options.get(), diagnosticEngine);
204 } else {
205 std::string sourceFile;
206 std::string_view parserInput;
207 if (options->GetCompilationMode() == CompilationMode::GEN_STD_LIB) {
208 sourceFile = "etsstdlib.ets";
209 parserInput = "";
210 } else {
211 sourceFile = options->SourceFileName();
212 auto [buf, size] = options->CStrParserInputContents();
213 parserInput = std::string_view(buf, size);
214 }
215 es2panda::SourceFile input(sourceFile, parserInput, options->IsModule(), options->GetOutput());
216 res = CompileFromSource(compiler, input, *options.get(), diagnosticEngine);
217 }
218 diagnosticEngine.FlushDiagnostic();
219 return res;
220 }
221 } // namespace ark::es2panda::aot
222
main(int argc,const char * argv[])223 int main(int argc, const char *argv[])
224 {
225 ark::es2panda::aot::MemManager mm;
226 return ark::es2panda::aot::Run(ark::Span<const char *const>(argv, argc));
227 }
228