1 /**
2 * Copyright (c) 2021-2022 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 <assembly-program.h>
17 #include <assembly-emitter.h>
18 #include <emitFiles.h>
19 #include <es2panda.h>
20 #include <mem/arena_allocator.h>
21 #include <mem/pool_manager.h>
22 #include <options.h>
23 #include <protobufSnapshotGenerator.h>
24 #include <util/dumper.h>
25 #include <util/moduleHelpers.h>
26 #include <util/programCache.h>
27 #include <util/workerQueue.h>
28
29 #include <iostream>
30
31 namespace panda::es2panda::aot {
32 using mem::MemConfig;
33 class MemManager {
34 public:
MemManager()35 explicit MemManager()
36 {
37 constexpr auto COMPILER_SIZE = 8192_MB;
38
39 MemConfig::Initialize(0, 0, COMPILER_SIZE, 0);
40 PoolManager::Initialize(PoolType::MMAP);
41 }
42
43 NO_COPY_SEMANTIC(MemManager);
44 NO_MOVE_SEMANTIC(MemManager);
45
~MemManager()46 ~MemManager()
47 {
48 PoolManager::Finalize();
49 MemConfig::Finalize();
50 }
51 };
52
GenerateBase64Output(panda::pandasm::Program * prog)53 static void GenerateBase64Output(panda::pandasm::Program *prog)
54 {
55 auto pandaFile = panda::pandasm::AsmEmitter::Emit(*prog);
56 const uint8_t *buffer = pandaFile->GetBase();
57 size_t size = pandaFile->GetPtr().GetSize();
58 std::string content(reinterpret_cast<const char*>(buffer), size);
59 std::string base64Output = util::Base64Encode(content);
60 std::cout << base64Output << std::endl;
61 }
62
DumpPandaFileSizeStatistic(std::map<std::string,size_t> & stat)63 static void DumpPandaFileSizeStatistic(std::map<std::string, size_t> &stat)
64 {
65 size_t totalSize = 0;
66 std::cout << "Panda file size statistic:" << std::endl;
67 constexpr std::array<std::string_view, 2> INFO_STATS = {"instructions_number", "codesize"};
68
69 for (const auto &[name, size] : stat) {
70 if (find(INFO_STATS.begin(), INFO_STATS.end(), name) != INFO_STATS.end()) {
71 continue;
72 }
73 std::cout << name << " section: " << size << std::endl;
74 totalSize += size;
75 }
76
77 for (const auto &name : INFO_STATS) {
78 std::cout << name << ": " << stat.at(std::string(name)) << std::endl;
79 }
80
81 std::cout << "total: " << totalSize << std::endl;
82 }
83
GenerateProgramsByWorkers(const std::map<std::string,panda::es2panda::util::ProgramCache * > & programsInfo,const std::unique_ptr<panda::es2panda::aot::Options> & options,std::map<std::string,size_t> * statp)84 static bool GenerateProgramsByWorkers(const std::map<std::string, panda::es2panda::util::ProgramCache*> &programsInfo,
85 const std::unique_ptr<panda::es2panda::aot::Options> &options, std::map<std::string, size_t> *statp)
86 {
87 auto queue = new panda::es2panda::aot::EmitFileQueue(options, statp, programsInfo);
88
89 bool emitResult = true;
90 try {
91 queue->Schedule();
92 queue->Consume();
93 queue->Wait();
94 } catch (const class Error &e) {
95 emitResult = false;
96 std::cerr << e.Message() << std::endl;
97 }
98
99 delete queue;
100 queue = nullptr;
101
102 return emitResult;
103 }
104
DumpProgramInfos(const std::map<std::string,panda::es2panda::util::ProgramCache * > & programsInfo,const std::unique_ptr<panda::es2panda::aot::Options> & options)105 static void DumpProgramInfos(const std::map<std::string, panda::es2panda::util::ProgramCache*> &programsInfo,
106 const std::unique_ptr<panda::es2panda::aot::Options> &options)
107 {
108 const es2panda::CompilerOptions &compilerOptions = options->CompilerOptions();
109 if (compilerOptions.dumpAsm || compilerOptions.dumpLiteralBuffer) {
110 for (const auto &progInfo : programsInfo) {
111 if (compilerOptions.dumpAsm) {
112 es2panda::Compiler::DumpAsm(&(progInfo.second->program));
113 }
114
115 if (compilerOptions.dumpLiteralBuffer) {
116 panda::es2panda::util::Dumper::DumpLiterals(progInfo.second->program.literalarray_table);
117 }
118 }
119 }
120 }
121
GenerateProgram(const std::map<std::string,panda::es2panda::util::ProgramCache * > & programsInfo,const std::unique_ptr<panda::es2panda::aot::Options> & options)122 static bool GenerateProgram(const std::map<std::string, panda::es2panda::util::ProgramCache*> &programsInfo,
123 const std::unique_ptr<panda::es2panda::aot::Options> &options)
124 {
125 DumpProgramInfos(programsInfo, options);
126
127 if (programsInfo.size() == 1) {
128 auto *prog = &(programsInfo.begin()->second->program);
129 if (options->OutputFiles().empty() && options->CompilerOutput().empty()) {
130 GenerateBase64Output(prog);
131 return true;
132 }
133
134 if (options->compilerProtoOutput().size() > 0) {
135 panda::proto::ProtobufSnapshotGenerator::GenerateSnapshot(*prog, options->compilerProtoOutput());
136 return true;
137 }
138 }
139
140 bool dumpSize = options->SizeStat();
141 std::map<std::string, size_t> stat;
142 std::map<std::string, size_t> *statp = dumpSize ? &stat : nullptr;
143
144 if (!GenerateProgramsByWorkers(programsInfo, options, statp)) {
145 return false;
146 }
147
148 if (dumpSize) {
149 DumpPandaFileSizeStatistic(stat);
150 }
151
152 return true;
153 }
154
GenerateAbcFiles(const std::map<std::string,panda::es2panda::util::ProgramCache * > & programsInfo,const std::unique_ptr<panda::es2panda::aot::Options> & options,size_t expectedProgsCount)155 static bool GenerateAbcFiles(const std::map<std::string, panda::es2panda::util::ProgramCache*> &programsInfo,
156 const std::unique_ptr<panda::es2panda::aot::Options> &options, size_t expectedProgsCount)
157 {
158 if (programsInfo.size() != expectedProgsCount) {
159 std::cerr << "the size of programs is expected to be " << expectedProgsCount
160 << ", but is " << programsInfo.size() << std::endl;
161 return false;
162 }
163
164 if (!GenerateProgram(programsInfo, options)) {
165 std::cerr << "GenerateProgram Failed!" << std::endl;
166 return false;
167 }
168
169 return true;
170 }
171
Run(int argc,const char ** argv)172 int Run(int argc, const char **argv)
173 {
174 auto options = std::make_unique<Options>();
175 if (!options->Parse(argc, argv)) {
176 std::cerr << options->ErrorMsg() << std::endl;
177 return 1;
178 }
179
180 if (options->CompilerOptions().bcVersion || options->CompilerOptions().bcMinVersion) {
181 std::string version = options->CompilerOptions().bcVersion ?
182 panda::panda_file::GetVersion(panda::panda_file::version) :
183 panda::panda_file::GetVersion(panda::panda_file::minVersion);
184 std::cout << version << std::endl;
185 return 0;
186 }
187
188 std::map<std::string, panda::es2panda::util::ProgramCache*> programsInfo;
189 size_t expectedProgsCount = options->CompilerOptions().sourceFiles.size();
190 panda::ArenaAllocator allocator(panda::SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
191
192 int ret = Compiler::CompileFiles(options->CompilerOptions(), programsInfo, &allocator);
193 if (options->ParseOnly()) {
194 return ret;
195 }
196
197 if (!options->NpmModuleEntryList().empty()) {
198 es2panda::util::ModuleHelpers::CompileNpmModuleEntryList(options->NpmModuleEntryList(),
199 options->CompilerOptions(), programsInfo, &allocator);
200 expectedProgsCount++;
201 }
202
203 if (!GenerateAbcFiles(programsInfo, options, expectedProgsCount)) {
204 return 1;
205 }
206
207 return 0;
208 }
209 } // namespace panda::es2panda::aot
210
main(int argc,const char ** argv)211 int main(int argc, const char **argv)
212 {
213 panda::es2panda::aot::MemManager mm;
214 return panda::es2panda::aot::Run(argc, argv);
215 }
216