• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "compilerImpl.h"
17 
18 #include "ast_verifier/ASTVerifier.h"
19 #include "es2panda.h"
20 #include "checker/ETSAnalyzer.h"
21 #include "checker/TSAnalyzer.h"
22 #include "compiler/core/compileQueue.h"
23 #include "compiler/core/compilerImpl.h"
24 #include "compiler/core/pandagen.h"
25 #include "compiler/core/ETSCompiler.h"
26 #include "compiler/core/ETSGen.h"
27 #include "compiler/core/JSCompiler.h"
28 #include "compiler/core/JSemitter.h"
29 #include "compiler/core/ETSemitter.h"
30 #include "compiler/lowering/phase.h"
31 #include "parser/parserImpl.h"
32 #include "parser/JSparser.h"
33 #include "parser/ASparser.h"
34 #include "parser/TSparser.h"
35 #include "parser/ETSparser.h"
36 #include "parser/program/program.h"
37 #include "varbinder/JSBinder.h"
38 #include "varbinder/ASBinder.h"
39 #include "varbinder/TSBinder.h"
40 #include "varbinder/ETSBinder.h"
41 #include "checker/TSchecker.h"
42 #include "checker/ETSchecker.h"
43 #include "checker/ASchecker.h"
44 #include "checker/JSchecker.h"
45 #include "public/public.h"
46 
47 namespace ark::es2panda::compiler {
48 
HandleContextLiterals(public_lib::Context * context)49 void CompilerImpl::HandleContextLiterals(public_lib::Context *context)
50 {
51     auto *emitter = context->emitter;
52 
53     uint32_t index = 0;
54     for (const auto &buff : context->contextLiterals) {
55         emitter->AddLiteralBuffer(buff, index++);
56     }
57 
58     emitter->LiteralBufferIndex() += context->contextLiterals.size();
59 }
60 
Emit(public_lib::Context * context)61 ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context)
62 {
63     HandleContextLiterals(context);
64 
65     queue_.Schedule(context);
66 
67     /* Main thread can also be used instead of idling */
68     queue_.Consume();
69     auto *emitter = context->emitter;
70     queue_.Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); });
71 
72     return emitter->Finalize(context->config->options->CompilerOptions().dumpDebugInfo, Signatures::ETS_GLOBAL);
73 }
74 
75 class ASTVerificationRunner {
76 public:
77     class Result {
78     public:
Result(JsonArrayBuilder && warnings,JsonArrayBuilder && errors)79         explicit Result(JsonArrayBuilder &&warnings, JsonArrayBuilder &&errors)
80             : warnings_ {std::move(warnings)}, errors_ {std::move(errors)}
81         {
82         }
83 
Warnings()84         JsonArrayBuilder &&Warnings()
85         {
86             return std::move(warnings_);
87         }
88 
Errors()89         JsonArrayBuilder &&Errors()
90         {
91             return std::move(errors_);
92         }
93 
94     private:
95         JsonArrayBuilder warnings_;
96         JsonArrayBuilder errors_;
97     };
98 
99     using AstPath = std::string;
100     using PhaseName = std::string;
101     using Source = std::tuple<AstPath, PhaseName>;
102     using AstToCheck = ArenaMap<AstPath, const ir::AstNode *>;
103     using GroupedMessages = std::map<Source, ast_verifier::Messages>;
104 
ASTVerificationRunner(ArenaAllocator & allocator,const public_lib::Context & context)105     ASTVerificationRunner(ArenaAllocator &allocator, const public_lib::Context &context)
106         : checkFullProgram_ {context.config->options->CompilerOptions().verifierFullProgram},
107           verifier_ {&allocator},
108           treatAsWarnings_ {context.config->options->CompilerOptions().verifierWarnings},
109           treatAsErrors_ {context.config->options->CompilerOptions().verifierErrors}
110     {
111     }
112 
Verify(const AstToCheck & astToCheck,const PhaseName & phaseName,const ast_verifier::InvariantNameSet & accumulatedChecks)113     void Verify(const AstToCheck &astToCheck, const PhaseName &phaseName,
114                 const ast_verifier::InvariantNameSet &accumulatedChecks)
115     {
116         for (const auto &[sourceName, ast] : astToCheck) {
117             const auto source = Source(sourceName, phaseName);
118             auto messages = verifier_.Verify(ast, accumulatedChecks);
119             auto &sourcedReport = report_[source];
120             std::copy(messages.begin(), messages.end(), std::back_inserter(sourcedReport));
121         }
122     }
123 
DumpMessages()124     Result DumpMessages()
125     {
126         auto warnings = JsonArrayBuilder {};
127         auto errors = JsonArrayBuilder {};
128         const auto filterMessages = [this, &warnings, &errors](const ast_verifier::CheckMessage &message,
129                                                                const std::string &sourceName,
130                                                                const std::string &phaseName) {
131             auto invariant = message.Invariant();
132             if (auto found = treatAsWarnings_.find(invariant); found != treatAsWarnings_.end()) {
133                 warnings.Add(message.DumpJSON(ast_verifier::CheckSeverity::WARNING, sourceName, phaseName));
134                 return;
135             }
136             if (auto found = treatAsErrors_.find(invariant); found != treatAsErrors_.end()) {
137                 errors.Add(message.DumpJSON(ast_verifier::CheckSeverity::ERROR, sourceName, phaseName));
138             }
139         };
140 
141         for (const auto &[source, messages] : report_) {
142             const auto &[sourceName, phaseName] = source;
143             for (const auto &message : messages) {
144                 filterMessages(message, sourceName, phaseName);
145             }
146         }
147 
148         return Result {std::move(warnings), std::move(errors)};
149     }
150 
ExtractAst(const parser::Program & p)151     ASTVerificationRunner::AstToCheck ExtractAst(const parser::Program &p)
152     {
153         auto &allocator = *p.Allocator();
154         auto astToCheck = ASTVerificationRunner::AstToCheck {allocator.Adapter()};
155         astToCheck.insert(std::make_pair(p.SourceFilePath(), p.Ast()));
156         if (checkFullProgram_) {
157             for (const auto &externalSource : p.ExternalSources()) {
158                 for (auto *external : externalSource.second) {
159                     astToCheck.insert(std::make_pair(external->SourceFilePath(), external->Ast()));
160                 }
161             }
162         }
163         return astToCheck;
164     }
165 
166 private:
167     bool checkFullProgram_;
168     GroupedMessages report_;
169     ast_verifier::ASTVerifier verifier_;
170     std::unordered_set<std::string> treatAsWarnings_;
171     std::unordered_set<std::string> treatAsErrors_;
172 };
173 
174 template <typename CodeGen, typename RegSpiller, typename FunctionEmitter, typename Emitter, typename AstCompiler>
MakeCompileJob()175 static public_lib::Context::CodeGenCb MakeCompileJob()
176 {
177     return [](public_lib::Context *context, varbinder::FunctionScope *scope,
178               compiler::ProgramElement *programElement) -> void {
179         RegSpiller regSpiller;
180         ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
181         AstCompiler astcompiler;
182         CodeGen cg(&allocator, &regSpiller, context, std::make_tuple(scope, programElement, &astcompiler));
183         FunctionEmitter funcEmitter(&cg, programElement);
184         funcEmitter.Generate();
185     };
186 }
187 
188 #ifndef NDEBUG
189 
RunVerifierAndPhases(CompilerImpl * compilerImpl,public_lib::Context & context,const std::vector<Phase * > & phases,parser::Program & program)190 static bool RunVerifierAndPhases(CompilerImpl *compilerImpl, public_lib::Context &context,
191                                  const std::vector<Phase *> &phases, parser::Program &program)
192 {
193     auto runner = ASTVerificationRunner(*context.allocator, context);
194     auto verificationCtx = ast_verifier::VerificationContext {};
195     const auto runAllChecks = context.config->options->CompilerOptions().verifierAllChecks;
196 
197     for (auto *phase : phases) {
198         if (!phase->Apply(&context, &program)) {
199             compilerImpl->SetIsAnyError(context.checker->ErrorLogger()->IsAnyError());
200             return false;
201         }
202 
203         if (runAllChecks) {
204             auto ast = runner.ExtractAst(program);
205             runner.Verify(ast, std::string {phase->Name()}, verificationCtx.AccumulatedChecks());
206         }
207         verificationCtx.IntroduceNewInvariants(phase->Name());
208     }
209 
210     if (!runAllChecks) {
211         auto ast = runner.ExtractAst(program);
212         runner.Verify(ast, "AfterAllPhases", verificationCtx.AccumulatedChecks());
213     }
214 
215     auto result = runner.DumpMessages();
216     if (auto warnings = result.Warnings().Build(); warnings != "[]") {
217         LOG(WARNING, ES2PANDA) << warnings;
218     }
219 
220     if (auto errors = result.Errors().Build(); errors != "[]") {
221         ASSERT_PRINT(false, errors);
222     }
223 
224     return true;
225 }
226 #endif
227 
RunPhases(CompilerImpl * compilerImpl,public_lib::Context & context,const std::vector<Phase * > & phases,parser::Program & program)228 static bool RunPhases(CompilerImpl *compilerImpl, public_lib::Context &context, const std::vector<Phase *> &phases,
229                       parser::Program &program)
230 {
231     for (auto *phase : phases) {
232         if (!phase->Apply(&context, &program)) {
233             compilerImpl->SetIsAnyError(context.checker->ErrorLogger()->IsAnyError());
234             return false;
235         }
236     }
237     return true;
238 }
239 
240 using EmitCb = std::function<pandasm::Program *(public_lib::Context *)>;
241 using PhaseListGetter = std::function<std::vector<compiler::Phase *>(ScriptExtension)>;
242 
243 template <typename Parser, typename VarBinder, typename Checker, typename Analyzer, typename AstCompiler,
244           typename CodeGen, typename RegSpiller, typename FunctionEmitter, typename Emitter>
CreateCompiler(const CompilationUnit & unit,const PhaseListGetter & getPhases,CompilerImpl * compilerImpl)245 static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const PhaseListGetter &getPhases,
246                                         CompilerImpl *compilerImpl)
247 {
248     ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
249     auto program = parser::Program::NewProgram<VarBinder>(&allocator);
250     program.MarkEntry();
251     auto parser =
252         Parser(&program, unit.options.CompilerOptions(), static_cast<parser::ParserStatus>(unit.rawParserStatus));
253     auto checker = Checker();
254     auto analyzer = Analyzer(&checker);
255     checker.SetAnalyzer(&analyzer);
256 
257     auto *varbinder = program.VarBinder();
258     varbinder->SetProgram(&program);
259 
260     public_lib::Context context;
261 
262     auto config = public_lib::ConfigImpl {};
263     context.config = &config;
264     context.config->options = &unit.options;
265     context.sourceFile = &unit.input;
266     context.allocator = &allocator;
267     context.queue = compilerImpl->Queue();
268     context.plugins = &compilerImpl->Plugins();
269     context.parser = &parser;
270     context.checker = &checker;
271     context.analyzer = checker.GetAnalyzer();
272     context.parserProgram = &program;
273     context.codeGenCb = MakeCompileJob<CodeGen, RegSpiller, FunctionEmitter, Emitter, AstCompiler>();
274 
275     auto emitter = Emitter(&context);
276     context.emitter = &emitter;
277 
278     varbinder->SetContext(&context);
279 
280     parser.ParseScript(unit.input, unit.options.CompilerOptions().compilationMode == CompilationMode::GEN_STD_LIB);
281 #ifndef NDEBUG
282     if (unit.ext == ScriptExtension::ETS) {
283         if (!RunVerifierAndPhases(compilerImpl, context, getPhases(unit.ext), program)) {
284             return nullptr;
285         }
286     } else if (!RunPhases(compilerImpl, context, getPhases(unit.ext), program)) {
287         return nullptr;
288     }
289 #else
290     if (!RunPhases(compilerImpl, context, getPhases(unit.ext), program)) {
291         return nullptr;
292     }
293 #endif
294 
295     emitter.GenAnnotation();
296 
297     return compilerImpl->Emit(&context);
298 }
299 
Compile(const CompilationUnit & unit)300 pandasm::Program *CompilerImpl::Compile(const CompilationUnit &unit)
301 {
302     switch (unit.ext) {
303         case ScriptExtension::TS: {
304             return CreateCompiler<parser::TSParser, varbinder::TSBinder, checker::TSChecker, checker::TSAnalyzer,
305                                   compiler::JSCompiler, compiler::PandaGen, compiler::DynamicRegSpiller,
306                                   compiler::JSFunctionEmitter, compiler::JSEmitter>(unit, compiler::GetPhaseList, this);
307         }
308         case ScriptExtension::AS: {
309             return CreateCompiler<parser::ASParser, varbinder::ASBinder, checker::ASChecker, checker::TSAnalyzer,
310                                   compiler::JSCompiler, compiler::PandaGen, compiler::DynamicRegSpiller,
311                                   compiler::JSFunctionEmitter, compiler::JSEmitter>(unit, compiler::GetPhaseList, this);
312         }
313         case ScriptExtension::ETS: {
314             return CreateCompiler<parser::ETSParser, varbinder::ETSBinder, checker::ETSChecker, checker::ETSAnalyzer,
315                                   compiler::ETSCompiler, compiler::ETSGen, compiler::StaticRegSpiller,
316                                   compiler::ETSFunctionEmitter, compiler::ETSEmitter>(unit, compiler::GetPhaseList,
317                                                                                       this);
318         }
319         case ScriptExtension::JS: {
320             return CreateCompiler<parser::JSParser, varbinder::JSBinder, checker::JSChecker, checker::TSAnalyzer,
321                                   compiler::JSCompiler, compiler::PandaGen, compiler::DynamicRegSpiller,
322                                   compiler::JSFunctionEmitter, compiler::JSEmitter>(unit, compiler::GetPhaseList, this);
323         }
324         default: {
325             UNREACHABLE();
326             return nullptr;
327         }
328     }
329 }
330 
DumpAsm(const ark::pandasm::Program * prog)331 void CompilerImpl::DumpAsm(const ark::pandasm::Program *prog)
332 {
333     Emitter::DumpAsm(prog);
334 }
335 }  // namespace ark::es2panda::compiler
336