• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021 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 "es2panda.h"
17 
18 #include <compiler/core/compileQueue.h>
19 #include <compiler/core/compilerContext.h>
20 #include <compiler/core/compilerImpl.h>
21 #include <compiler/core/emitter/emitter.h>
22 #include <parser/parserImpl.h>
23 #include <parser/program/program.h>
24 #include <parser/transformer/transformer.h>
25 #include <typescript/checker.h>
26 #include <util/commonUtil.h>
27 #include <util/helpers.h>
28 
29 #include <iostream>
30 
31 namespace panda::es2panda {
32 // Compiler
33 
34 constexpr size_t DEFAULT_THREAD_COUNT = 2;
35 size_t Compiler::expectedProgsCount_ = 0;
36 
Compiler(ScriptExtension ext)37 Compiler::Compiler(ScriptExtension ext) : Compiler(ext, DEFAULT_THREAD_COUNT) {}
38 
Compiler(ScriptExtension ext,size_t threadCount)39 Compiler::Compiler(ScriptExtension ext, size_t threadCount)
40     : parser_(new parser::ParserImpl(ext)), compiler_(new compiler::CompilerImpl(threadCount)),
41     abcToAsmCompiler_(new panda::abc2program::Abc2ProgramCompiler)
42 {
43     if (parser_->Extension() == ScriptExtension::TS) {
44         transformer_ = std::make_unique<parser::Transformer>(parser_->Allocator());
45     }
46 }
47 
~Compiler()48 Compiler::~Compiler()
49 {
50     delete parser_;
51     delete compiler_;
52     delete abcToAsmCompiler_;
53 }
54 
CreateJsonContentProgram(std::string src,std::string rname,util::PatchFix * patchFixHelper)55 panda::pandasm::Program *CreateJsonContentProgram(std::string src, std::string rname, util::PatchFix *patchFixHelper)
56 {
57     panda::es2panda::compiler::CompilerContext context(nullptr, false, false, false, true, false,
58                                                        src, "", util::StringView(rname), patchFixHelper);
59     context.GetEmitter()->GenRecordNameInfo();
60     return context.GetEmitter()->Finalize(false, nullptr);
61 }
62 
CheckOptionsAndFileForAbcInput(const std::string & fname,const CompilerOptions & options)63 void Compiler::CheckOptionsAndFileForAbcInput(const std::string &fname, const CompilerOptions &options)
64 {
65     if (!options.enableAbcInput) {
66         throw Error(ErrorType::GENERIC, "\"--enable-abc-input\" is not enabled, abc file " + fname +
67             "could not be used as the input.");
68     }
69     if (options.targetApiVersion < util::Helpers::ABC_TO_PROGRAM_MIN_SUPPORTED_API_VERSION) {
70         throw Error(ErrorType::GENERIC, "Target api version '" + std::to_string(options.targetApiVersion) +
71                     "' should be greater than or equal to '" +
72                     std::to_string(util::Helpers::ABC_TO_PROGRAM_MIN_SUPPORTED_API_VERSION) + "'.");
73     }
74     if (!options.mergeAbc && options.sourceFiles.size() != 1) {
75         throw Error(ErrorType::GENERIC, "If an abc file is used as input, it must be the only input file "
76                     "when the option '--merge-abc' is not enabled.");
77     }
78     if (!abcToAsmCompiler_->OpenAbcFile(fname)) {
79         throw Error(ErrorType::GENERIC, "Open abc file " + fname + " failed.");
80     }
81     if (!abcToAsmCompiler_->CheckFileVersionIsSupported(util::Helpers::ABC_TO_PROGRAM_MIN_SUPPORTED_BYTECODE_VERSION,
82                                                         options.targetApiVersion, options.targetApiSubVersion)) {
83         throw Error(ErrorType::GENERIC, "The input abc file '" + fname + "' owns a higher api version or a higher " +
84                     "sdkReleaseType compared to current compilation process.");
85     }
86 }
87 
CompileAbcFile(const std::string & fname,const CompilerOptions & options)88 panda::pandasm::Program *Compiler::CompileAbcFile(const std::string &fname, const CompilerOptions &options)
89 {
90     try {
91         CheckOptionsAndFileForAbcInput(fname, options);
92         return abcToAsmCompiler_->CompileAbcFile();
93     } catch (const class Error &e) {
94         std::cerr << e.TypeString() << ": " << e.Message();
95         std::cerr << " [" << fname << "]" << std::endl;
96         throw;
97     }
98 }
99 
CompileAbcFileInParallel(SourceFile * src,const CompilerOptions & options,std::map<std::string,panda::es2panda::util::ProgramCache * > & progsInfo,panda::ArenaAllocator * allocator)100 void Compiler::CompileAbcFileInParallel(SourceFile *src, const CompilerOptions &options,
101                                         std::map<std::string, panda::es2panda::util::ProgramCache*> &progsInfo,
102                                         panda::ArenaAllocator *allocator)
103 {
104     try {
105         CheckOptionsAndFileForAbcInput(src->fileName, options);
106     } catch (const class Error &e) {
107         std::cerr << e.TypeString() << ": " << e.Message();
108         std::cerr << " [" << src->fileName << "]" << std::endl;
109         throw;
110     }
111     if (options.compileContextInfo.needModifyRecord) {
112         abcToAsmCompiler_->SetBundleName(options.compileContextInfo.bundleName);
113     }
114 
115     auto *compileAbcClassQueue = new compiler::CompileAbcClassQueue(options.abcClassThreadCount,
116                                                                     options,
117                                                                     *abcToAsmCompiler_,
118                                                                     progsInfo,
119                                                                     allocator,
120                                                                     src);
121     try {
122         compileAbcClassQueue->Schedule();
123         compileAbcClassQueue->Consume();
124         compileAbcClassQueue->Wait();
125     } catch (const class Error &e) {
126         throw e;
127     }
128 
129     delete compileAbcClassQueue;
130     compileAbcClassQueue = nullptr;
131 }
132 
Compile(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)133 panda::pandasm::Program *Compiler::Compile(const SourceFile &input, const CompilerOptions &options,
134     util::SymbolTable *symbolTable)
135 {
136     ASSERT(input.isSourceMode);
137     /* TODO(dbatyai): pass string view */
138     std::string fname(input.fileName);
139     std::string src(input.source);
140     std::string rname(input.recordName);
141     std::string sourcefile(input.sourcefile);
142     std::string pkgName(input.pkgName);
143 
144     auto *patchFixHelper = InitPatchFixHelper(input, options, symbolTable);
145 
146     if (fname.substr(fname.find_last_of(".") + 1) == "json") {
147         return CreateJsonContentProgram(src, rname, patchFixHelper);
148     }
149 
150     try {
151         auto ast = parser_->Parse(input, options);
152         ast.Binder()->SetProgram(&ast);
153 
154         if (options.dumpAst) {
155             std::cout << ast.Dump() << std::endl;
156         }
157 
158         if (ast.Extension() == ScriptExtension::TS && options.enableTypeCheck) {
159             ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
160             auto checker = std::make_unique<checker::Checker>(&localAllocator, ast.Binder());
161             checker->StartChecker();
162         }
163 
164         if (ast.Extension() == ScriptExtension::TS) {
165             transformer_->Transform(&ast);
166             ast.Binder()->IdentifierAnalysis(binder::ResolveBindingFlags::TS_AFTER_TRANSFORM);
167             if (options.dumpTransformedAst) {
168                 std::cout << ast.Dump() << std::endl;
169             }
170             if (options.checkTransformedAstStructure) {
171                 transformer_->CheckTransformedAstStructure(&ast);
172             }
173         }
174 
175         if (options.parseOnly) {
176             return nullptr;
177         }
178 
179         std::string debugInfoSourceFile = options.debugInfoSourceFile.empty() ?
180                                           sourcefile : options.debugInfoSourceFile;
181         auto *prog = compiler_->Compile(&ast, options, debugInfoSourceFile, pkgName);
182 
183         CleanPatchFixHelper(patchFixHelper);
184         return prog;
185     } catch (const class Error &e) {
186         error_ = e;
187 
188         CleanPatchFixHelper(patchFixHelper);
189         return nullptr;
190     }
191 }
192 
InitPatchFixHelper(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)193 util::PatchFix *Compiler::InitPatchFixHelper(const SourceFile &input, const CompilerOptions &options,
194                                              util::SymbolTable *symbolTable)
195 {
196     util::PatchFix *patchFixHelper = nullptr;
197     bool needDumpSymbolFile = !options.patchFixOptions.dumpSymbolTable.empty();
198     bool needGeneratePatch = options.patchFixOptions.generatePatch && !options.patchFixOptions.symbolTable.empty();
199     bool isHotReload = options.patchFixOptions.hotReload;
200     bool isColdReload = options.patchFixOptions.coldReload;
201     bool isColdFix = options.patchFixOptions.coldFix;
202     if (symbolTable && (needDumpSymbolFile || needGeneratePatch || isHotReload || isColdReload)) {
203         util::PatchFixKind patchFixKind = util::PatchFixKind::DUMPSYMBOLTABLE;
204         if (needGeneratePatch) {
205             patchFixKind = isColdFix ? util::PatchFixKind::COLDFIX : util::PatchFixKind::HOTFIX;
206         }
207         if (isHotReload) {
208             patchFixKind = util::PatchFixKind::HOTRELOAD;
209         }
210         if (isColdReload) {
211             patchFixKind = util::PatchFixKind::COLDRELOAD;
212         }
213         patchFixHelper = new util::PatchFix(needDumpSymbolFile, needGeneratePatch, patchFixKind, input.recordName,
214             symbolTable);
215         parser_->AddPatchFixHelper(patchFixHelper);
216         compiler_->AddPatchFixHelper(patchFixHelper);
217     }
218     return patchFixHelper;
219 }
220 
CleanPatchFixHelper(const util::PatchFix * patchFixHelper)221 void Compiler::CleanPatchFixHelper(const util::PatchFix *patchFixHelper)
222 {
223     if (patchFixHelper) {
224         delete patchFixHelper;
225         patchFixHelper = nullptr;
226     }
227 }
228 
DumpAsm(const panda::pandasm::Program * prog)229 void Compiler::DumpAsm(const panda::pandasm::Program *prog)
230 {
231     compiler::CompilerImpl::DumpAsm(prog);
232 }
233 
CompileFiles(CompilerOptions & options,std::map<std::string,panda::es2panda::util::ProgramCache * > & progsInfo,panda::ArenaAllocator * allocator)234 int Compiler::CompileFiles(CompilerOptions &options,
235     std::map<std::string, panda::es2panda::util::ProgramCache*> &progsInfo, panda::ArenaAllocator *allocator)
236 {
237     util::SymbolTable *symbolTable = nullptr;
238     if (!options.patchFixOptions.symbolTable.empty() || !options.patchFixOptions.dumpSymbolTable.empty()) {
239         symbolTable = new util::SymbolTable(options.patchFixOptions.symbolTable,
240             options.patchFixOptions.dumpSymbolTable);
241         if (!symbolTable->Initialize(options.targetApiVersion, options.targetApiSubVersion)) {
242             std::cerr << "Failed to initialize for Hotfix." << std::endl;
243             return 1;
244         }
245     }
246 
247     bool failed = false;
248     std::unordered_set<std::string> optimizationPendingProgs;
249     auto queue = new compiler::CompileFileQueue(options.fileThreadCount, &options, progsInfo,
250                                                 optimizationPendingProgs, symbolTable, allocator);
251 
252     try {
253         queue->Schedule();
254         queue->Consume();
255         queue->Wait();
256     } catch (const class Error &e) {
257         if (!e.Reported()) {
258             std::cerr << e.TypeString() << ": " << e.Message() << std::endl;
259         }
260         failed = true;
261     }
262 
263     delete queue;
264     queue = nullptr;
265 
266     if (symbolTable) {
267         if (!options.patchFixOptions.dumpSymbolTable.empty()) {
268             symbolTable->WriteSymbolTable();
269         }
270         delete symbolTable;
271         symbolTable = nullptr;
272     }
273 
274     if (options.requireGlobalOptimization) {
275         auto postAnalysisOptimizeQueue = new compiler::PostAnalysisOptimizeFileQueue(options.fileThreadCount,
276                                                                                      progsInfo,
277                                                                                      optimizationPendingProgs);
278         try {
279             postAnalysisOptimizeQueue->Schedule();
280             postAnalysisOptimizeQueue->Consume();
281             postAnalysisOptimizeQueue->Wait();
282         } catch (const class Error &e) {
283             // Optimization failed, but the program can still be used as unoptimized
284         }
285         delete postAnalysisOptimizeQueue;
286     }
287 
288     return failed ? 1 : 0;
289 }
290 
CompileFile(const CompilerOptions & options,SourceFile * src,util::SymbolTable * symbolTable)291 panda::pandasm::Program *Compiler::CompileFile(const CompilerOptions &options, SourceFile *src,
292                                                util::SymbolTable *symbolTable)
293 {
294     auto *program = Compile(*src, options, symbolTable);
295     if (!program) {
296         auto &err = GetError();
297         if (err.Message().empty() && options.parseOnly) {
298             return nullptr;
299         }
300 
301         std::cerr << err.TypeString() << ": " << err.Message();
302         std::cerr << " [" << util::Helpers::BaseName(src->fileName) << ":"
303                   << err.Line() << ":" << err.Col() << "]" << std::endl;
304         err.SetReported(true);
305 
306         throw err;
307     }
308     return program;
309 }
310 
311 }  // namespace panda::es2panda
312