• 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 
112     auto *compileAbcClassQueue = new compiler::CompileAbcClassQueue(options.abcClassThreadCount,
113                                                                     options,
114                                                                     *abcToAsmCompiler_,
115                                                                     progsInfo,
116                                                                     allocator,
117                                                                     src);
118     try {
119         compileAbcClassQueue->Schedule();
120         compileAbcClassQueue->Consume();
121         compileAbcClassQueue->Wait();
122     } catch (const class Error &e) {
123         throw e;
124     }
125 
126     delete compileAbcClassQueue;
127     compileAbcClassQueue = nullptr;
128 }
129 
Compile(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)130 panda::pandasm::Program *Compiler::Compile(const SourceFile &input, const CompilerOptions &options,
131     util::SymbolTable *symbolTable)
132 {
133     ASSERT(input.isSourceMode);
134     /* TODO(dbatyai): pass string view */
135     std::string fname(input.fileName);
136     std::string src(input.source);
137     std::string rname(input.recordName);
138     std::string sourcefile(input.sourcefile);
139     std::string pkgName(input.pkgName);
140 
141     auto *patchFixHelper = InitPatchFixHelper(input, options, symbolTable);
142 
143     if (fname.substr(fname.find_last_of(".") + 1) == "json") {
144         return CreateJsonContentProgram(src, rname, patchFixHelper);
145     }
146 
147     try {
148         auto ast = parser_->Parse(input, options);
149         ast.Binder()->SetProgram(&ast);
150 
151         if (options.dumpAst) {
152             std::cout << ast.Dump() << std::endl;
153         }
154 
155         if (ast.Extension() == ScriptExtension::TS && options.enableTypeCheck) {
156             ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
157             auto checker = std::make_unique<checker::Checker>(&localAllocator, ast.Binder());
158             checker->StartChecker();
159         }
160 
161         if (ast.Extension() == ScriptExtension::TS) {
162             transformer_->Transform(&ast);
163             ast.Binder()->IdentifierAnalysis(binder::ResolveBindingFlags::TS_AFTER_TRANSFORM);
164             if (options.dumpTransformedAst) {
165                 std::cout << ast.Dump() << std::endl;
166             }
167             if (options.checkTransformedAstStructure) {
168                 transformer_->CheckTransformedAstStructure(&ast);
169             }
170         }
171 
172         if (options.parseOnly) {
173             return nullptr;
174         }
175 
176         std::string debugInfoSourceFile = options.debugInfoSourceFile.empty() ?
177                                           sourcefile : options.debugInfoSourceFile;
178         auto *prog = compiler_->Compile(&ast, options, debugInfoSourceFile, pkgName);
179 
180         CleanPatchFixHelper(patchFixHelper);
181         return prog;
182     } catch (const class Error &e) {
183         error_ = e;
184 
185         CleanPatchFixHelper(patchFixHelper);
186         return nullptr;
187     }
188 }
189 
InitPatchFixHelper(const SourceFile & input,const CompilerOptions & options,util::SymbolTable * symbolTable)190 util::PatchFix *Compiler::InitPatchFixHelper(const SourceFile &input, const CompilerOptions &options,
191                                              util::SymbolTable *symbolTable)
192 {
193     util::PatchFix *patchFixHelper = nullptr;
194     bool needDumpSymbolFile = !options.patchFixOptions.dumpSymbolTable.empty();
195     bool needGeneratePatch = options.patchFixOptions.generatePatch && !options.patchFixOptions.symbolTable.empty();
196     bool isHotReload = options.patchFixOptions.hotReload;
197     bool isColdReload = options.patchFixOptions.coldReload;
198     bool isColdFix = options.patchFixOptions.coldFix;
199     if (symbolTable && (needDumpSymbolFile || needGeneratePatch || isHotReload || isColdReload)) {
200         util::PatchFixKind patchFixKind = util::PatchFixKind::DUMPSYMBOLTABLE;
201         if (needGeneratePatch) {
202             patchFixKind = isColdFix ? util::PatchFixKind::COLDFIX : util::PatchFixKind::HOTFIX;
203         }
204         if (isHotReload) {
205             patchFixKind = util::PatchFixKind::HOTRELOAD;
206         }
207         if (isColdReload) {
208             patchFixKind = util::PatchFixKind::COLDRELOAD;
209         }
210         patchFixHelper = new util::PatchFix(needDumpSymbolFile, needGeneratePatch, patchFixKind, input.recordName,
211             symbolTable);
212         parser_->AddPatchFixHelper(patchFixHelper);
213         compiler_->AddPatchFixHelper(patchFixHelper);
214     }
215     return patchFixHelper;
216 }
217 
CleanPatchFixHelper(const util::PatchFix * patchFixHelper)218 void Compiler::CleanPatchFixHelper(const util::PatchFix *patchFixHelper)
219 {
220     if (patchFixHelper) {
221         delete patchFixHelper;
222         patchFixHelper = nullptr;
223     }
224 }
225 
DumpAsm(const panda::pandasm::Program * prog)226 void Compiler::DumpAsm(const panda::pandasm::Program *prog)
227 {
228     compiler::CompilerImpl::DumpAsm(prog);
229 }
230 
CompileFiles(CompilerOptions & options,std::map<std::string,panda::es2panda::util::ProgramCache * > & progsInfo,panda::ArenaAllocator * allocator)231 int Compiler::CompileFiles(CompilerOptions &options,
232     std::map<std::string, panda::es2panda::util::ProgramCache*> &progsInfo, panda::ArenaAllocator *allocator)
233 {
234     util::SymbolTable *symbolTable = nullptr;
235     if (!options.patchFixOptions.symbolTable.empty() || !options.patchFixOptions.dumpSymbolTable.empty()) {
236         symbolTable = new util::SymbolTable(options.patchFixOptions.symbolTable,
237             options.patchFixOptions.dumpSymbolTable);
238         if (!symbolTable->Initialize(options.targetApiVersion, options.targetApiSubVersion)) {
239             std::cerr << "Failed to initialize for Hotfix." << std::endl;
240             return 1;
241         }
242     }
243 
244     bool failed = false;
245     std::unordered_set<std::string> optimizationPendingProgs;
246     auto queue = new compiler::CompileFileQueue(options.fileThreadCount, &options, progsInfo,
247                                                 optimizationPendingProgs, symbolTable, allocator);
248 
249     try {
250         queue->Schedule();
251         queue->Consume();
252         queue->Wait();
253     } catch (const class Error &e) {
254         if (!e.Reported()) {
255             std::cerr << e.TypeString() << ": " << e.Message() << std::endl;
256         }
257         failed = true;
258     }
259 
260     delete queue;
261     queue = nullptr;
262 
263     if (symbolTable) {
264         if (!options.patchFixOptions.dumpSymbolTable.empty()) {
265             symbolTable->WriteSymbolTable();
266         }
267         delete symbolTable;
268         symbolTable = nullptr;
269     }
270 
271     if (options.requireGlobalOptimization) {
272         auto postAnalysisOptimizeQueue = new compiler::PostAnalysisOptimizeFileQueue(options.fileThreadCount,
273                                                                                      progsInfo,
274                                                                                      optimizationPendingProgs);
275         try {
276             postAnalysisOptimizeQueue->Schedule();
277             postAnalysisOptimizeQueue->Consume();
278             postAnalysisOptimizeQueue->Wait();
279         } catch (const class Error &e) {
280             // Optimization failed, but the program can still be used as unoptimized
281         }
282         delete postAnalysisOptimizeQueue;
283     }
284 
285     return failed ? 1 : 0;
286 }
287 
CompileFile(const CompilerOptions & options,SourceFile * src,util::SymbolTable * symbolTable)288 panda::pandasm::Program *Compiler::CompileFile(const CompilerOptions &options, SourceFile *src,
289                                                util::SymbolTable *symbolTable)
290 {
291     auto *program = Compile(*src, options, symbolTable);
292     if (!program) {
293         auto &err = GetError();
294         if (err.Message().empty() && options.parseOnly) {
295             return nullptr;
296         }
297 
298         std::cerr << err.TypeString() << ": " << err.Message();
299         std::cerr << " [" << util::Helpers::BaseName(src->fileName) << ":"
300                   << err.Line() << ":" << err.Col() << "]" << std::endl;
301         err.SetReported(true);
302 
303         throw err;
304     }
305     return program;
306 }
307 
308 }  // namespace panda::es2panda
309