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 #include "ecmascript/compiler/pass_manager.h"
16
17 #include "ecmascript/compiler/bytecode_info_collector.h"
18 #include "ecmascript/compiler/bytecodes.h"
19 #include "ecmascript/compiler/pass.h"
20 #include "ecmascript/compiler/compilation_driver.h"
21 #include "ecmascript/ecma_handle_scope.h"
22 #include "ecmascript/jspandafile/js_pandafile_manager.h"
23 #include "ecmascript/jspandafile/panda_file_translator.h"
24 #include "ecmascript/snapshot/mem/snapshot.h"
25 #include "ecmascript/ts_types/ts_manager.h"
26
27 namespace panda::ecmascript::kungfu {
28
Compile(const std::string & fileName,AOTFileGenerator & generator)29 bool PassManager::Compile(const std::string &fileName, AOTFileGenerator &generator)
30 {
31 [[maybe_unused]] EcmaHandleScope handleScope(vm_->GetJSThread());
32 JSPandaFile *jsPandaFile = CreateAndVerifyJSPandaFile(fileName.c_str());
33 if (jsPandaFile == nullptr) {
34 LOG_COMPILER(ERROR) << "Cannot execute panda file '" << fileName << "'";
35 return false;
36 }
37
38 if (!profilerLoader_.LoadAndVerify(jsPandaFile->GetChecksum())) {
39 LOG_COMPILER(ERROR) << "Load and verify profiler failure";
40 return false;
41 }
42 bool enableCollectLiteralInfo = EnableTypeInfer() &&
43 (profilerLoader_.IsLoaded() || vm_->GetTSManager()->AssertTypes());
44 BytecodeInfoCollector bcInfoCollector(vm_, jsPandaFile, maxAotMethodSize_,
45 enableCollectLiteralInfo);
46
47 if (!IsReleasedPandaFile(jsPandaFile)) {
48 LOG_COMPILER(ERROR) << "The input panda file [" << fileName
49 << "] of AOT Compiler is debuggable version, do not use for performance test!";
50 }
51
52 ResolveModule(jsPandaFile, fileName);
53 auto aotModule = new LLVMModule(fileName, triple_);
54 auto aotModuleAssembler = new LLVMAssembler(aotModule->GetModule(),
55 LOptions(optLevel_, true, relocMode_));
56
57 CompilationConfig cmpCfg(triple_, false, log_->IsTraceBC(), vm_->GetJSOptions().GetOptCodeProfiler());
58 Bytecodes bytecodes;
59 auto &bytecodeInfo = bcInfoCollector.GetBytecodeInfo();
60 auto lexEnvManager = LexEnvManager(bytecodeInfo);
61
62 CompilationDriver cmpDriver(jsPandaFile, profilerLoader_, bytecodeInfo);
63 // ts type system
64 TSManager *tsManager = vm_->GetTSManager();
65 tsManager->SetCompilationDriver(&cmpDriver);
66 PassInfo info(tsManager, &bytecodes, &lexEnvManager, &cmpCfg, log_,
67 jsPandaFile, &bcInfoCollector, aotModule);
68
69 cmpDriver.Run([this, &fileName, &info]
70 (const CString recordName, const std::string &methodName, MethodLiteral *methodLiteral,
71 uint32_t methodOffset, const MethodPcInfo &methodPCInfo, size_t methodInfoIndex) {
72 auto jsPandaFile = info.GetJSPandaFile();
73 auto cmpCfg = info.GetCompilerConfig();
74 auto tsManager = info.GetTSManager();
75 // note: TSManager need to set current constantpool before all pass
76 tsManager->SetCurConstantPool(jsPandaFile, methodOffset);
77
78 log_->SetMethodLog(fileName, recordName, methodName, logList_);
79
80 std::string fullName = methodName + "@" + fileName;
81 bool enableMethodLog = log_->GetEnableMethodLog();
82 if (enableMethodLog) {
83 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName << "] log:" << "\033[0m";
84 }
85
86 bool hasTypes = jsPandaFile->HasTSTypes(recordName);
87 if (UNLIKELY(!hasTypes)) {
88 LOG_COMPILER(INFO) << "record: " << recordName << " has no types";
89 }
90
91 Circuit circuit(vm_->GetNativeAreaAllocator(), cmpCfg->Is64Bit());
92 BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, tsManager, &circuit,
93 info.GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(),
94 EnableTypeLowering(), fullName, recordName);
95 {
96 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
97 builder.BytecodeToCircuit();
98 }
99
100 PassData data(&builder, &circuit, &info, log_, fullName,
101 methodInfoIndex, hasTypes, recordName,
102 methodLiteral, methodOffset, vm_->GetNativeAreaAllocator());
103 PassRunner<PassData> pipeline(&data);
104 if (EnableTypeInfer()) {
105 pipeline.RunPass<TypeInferPass>();
106 }
107 pipeline.RunPass<AsyncFunctionLoweringPass>();
108 if (EnableTypeLowering()) {
109 pipeline.RunPass<TSTypeLoweringPass>();
110 pipeline.RunPass<EarlyEliminationPass>();
111 pipeline.RunPass<TypeLoweringPass>();
112 }
113 pipeline.RunPass<SlowPathLoweringPass>();
114 pipeline.RunPass<VerifierPass>();
115 pipeline.RunPass<SchedulingPass>();
116 pipeline.RunPass<LLVMIRGenPass>();
117 });
118 LOG_COMPILER(INFO) << bytecodeInfo.GetSkippedMethodSize() << " methods in "
119 << fileName << " have been skipped";
120 generator.AddModule(aotModule, aotModuleAssembler, &bcInfoCollector);
121 return true;
122 }
123
CreateAndVerifyJSPandaFile(const CString & fileName)124 JSPandaFile *PassManager::CreateAndVerifyJSPandaFile(const CString &fileName)
125 {
126 JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance();
127 JSPandaFile *jsPandaFile = jsPandaFileManager->OpenJSPandaFile(fileName);
128 if (jsPandaFile == nullptr) {
129 LOG_ECMA(ERROR) << "open file " << fileName << " error";
130 return nullptr;
131 }
132
133 if (!jsPandaFile->IsNewVersion()) {
134 LOG_COMPILER(ERROR) << "AOT only support panda file with new ISA, while the '" <<
135 fileName << "' file is the old version";
136 return nullptr;
137 }
138
139 JSPandaFileManager::GetInstance()->InsertJSPandaFile(jsPandaFile);
140 return jsPandaFile;
141 }
142
IsReleasedPandaFile(const JSPandaFile * jsPandaFile) const143 bool PassManager::IsReleasedPandaFile(const JSPandaFile *jsPandaFile) const
144 {
145 MethodLiteral* methodLiteral = jsPandaFile->GetMethodLiterals();
146 if (methodLiteral == nullptr) {
147 LOG_COMPILER(ERROR) << "There is no mehtod literal in " << jsPandaFile->GetJSPandaFileDesc();
148 return false;
149 }
150
151 panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
152 DebugInfoExtractor *debugInfoExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
153 LocalVariableTable lvt = debugInfoExtractor->GetLocalVariableTable(methodId);
154 return lvt.empty();
155 }
156
ResolveModule(const JSPandaFile * jsPandaFile,const std::string & fileName)157 void PassManager::ResolveModule(const JSPandaFile *jsPandaFile, const std::string &fileName)
158 {
159 const auto &recordInfo = jsPandaFile->GetJSRecordInfo();
160 ModuleManager *moduleManager = vm_->GetModuleManager();
161 JSThread *thread = vm_->GetJSThread();
162 for (auto info: recordInfo) {
163 auto recordName = info.first;
164 if (jsPandaFile->IsModule(thread, recordName)) {
165 ASSERT(!thread->HasPendingException());
166 moduleManager->HostResolveImportedModuleWithMerge(fileName.c_str(), recordName);
167 }
168 }
169 }
170 } // namespace panda::ecmascript::kungfu
171