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 #include "ecmascript/compiler/bytecodes.h"
17 #include "ecmascript/compiler/pass.h"
18 #include "ecmascript/compiler/compilation_driver.h"
19 #include "ecmascript/ecma_handle_scope.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 #include "ecmascript/jspandafile/panda_file_translator.h"
22 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
23 #include "ecmascript/snapshot/mem/snapshot.h"
24 #include "ecmascript/ts_types/ts_manager.h"
25
26 namespace panda::ecmascript::kungfu {
ShouldCollect() const27 bool PassManager::ShouldCollect() const
28 {
29 return passOptions_->EnableTypeInfer() &&
30 (profilerDecoder_.IsLoaded() || vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->AssertTypes() ||
31 log_->OutputType());
32 }
33
Compile(JSPandaFile * jsPandaFile,const std::string & fileName,AOTFileGenerator & gen)34 bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, AOTFileGenerator &gen)
35 {
36 [[maybe_unused]] EcmaHandleScope handleScope(vm_->GetJSThread());
37
38 if (jsPandaFile == nullptr) {
39 LOG_COMPILER(ERROR) << "Cannot execute panda file '" << fileName << "'";
40 return false;
41 }
42
43 if (!PGOProfilerManager::MergeApFiles(jsPandaFile->GetChecksum(), profilerDecoder_)) {
44 LOG_COMPILER(ERROR) << "Load and verify profiler failure";
45 return false;
46 }
47
48 ResolveModule(jsPandaFile, fileName);
49 BytecodeInfoCollector collector(vm_, jsPandaFile, profilerDecoder_, maxAotMethodSize_, ShouldCollect());
50
51 // Checking released/debuggable pandafile uses method literals, which are initialized in BytecodeInfoCollector,
52 // should after it.
53 if (!IsReleasedPandaFile(jsPandaFile)) {
54 LOG_COMPILER(ERROR) << "The input panda file [" << fileName
55 << "] of AOT Compiler is debuggable version, do not use for performance test!";
56 }
57
58 LOptions lOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_);
59 CompilationDriver cmpDriver(profilerDecoder_,
60 &collector,
61 vm_->GetJSOptions().GetCompilerSelectMethods(),
62 vm_->GetJSOptions().GetCompilerSkipMethods(),
63 &gen,
64 fileName,
65 triple_,
66 &lOptions,
67 log_,
68 log_->OutputASM(),
69 maxMethodsInModule_);
70
71 cmpDriver.Run([this, &fileName, &collector](const CString recordName,
72 const std::string &methodName,
73 MethodLiteral *methodLiteral,
74 uint32_t methodOffset,
75 const MethodPcInfo &methodPCInfo,
76 MethodInfo &methodInfo,
77 Module *m) {
78 PassContext ctx(triple_, log_, &collector, m->GetModule(), &profilerDecoder_);
79 auto jsPandaFile = ctx.GetJSPandaFile();
80 auto cmpCfg = ctx.GetCompilerConfig();
81 auto tsManager = ctx.GetTSManager();
82 auto module = m->GetModule();
83 // note: TSManager need to set current constantpool before all pass
84 tsManager->SetCurConstantPool(jsPandaFile, methodOffset);
85 log_->SetMethodLog(fileName, methodName, logList_);
86
87 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile);
88 bool enableMethodLog = log_->GetEnableMethodLog();
89 if (enableMethodLog) {
90 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName
91 << "] recordName [" << recordName << "] log:" << "\033[0m";
92 }
93 bool hasTypes = jsPandaFile->HasTSTypes(recordName);
94 if (UNLIKELY(!hasTypes)) {
95 LOG_COMPILER(INFO) << "record: " << recordName << " has no types";
96 }
97
98 Circuit circuit(vm_->GetNativeAreaAllocator(), ctx.GetAOTModule()->GetDebugInfo(),
99 fullName.c_str(), cmpCfg->Is64Bit());
100 circuit.SetFrameType(FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
101
102 PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : nullptr;
103
104 BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, tsManager, &circuit,
105 ctx.GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(),
106 passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false,
107 passOptions_->EnableOptTrackField());
108 {
109 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
110 builder.BytecodeToCircuit();
111 }
112
113 PassData data(&builder, &circuit, &ctx, log_, fullName, &methodInfo, hasTypes, recordName,
114 methodLiteral, methodOffset, vm_->GetNativeAreaAllocator(), decoder, passOptions_);
115
116 PassRunner<PassData> pipeline(&data);
117 if (builder.EnableLoopOptimization()) {
118 pipeline.RunPass<LoopOptimizationPass>();
119 }
120 pipeline.RunPass<TypeInferPass>();
121 if (data.IsTypeAbort()) {
122 data.AbortCompilation();
123 return;
124 }
125 pipeline.RunPass<PGOTypeInferPass>();
126 pipeline.RunPass<TSClassAnalysisPass>();
127 pipeline.RunPass<TSInlineLoweringPass>();
128 pipeline.RunPass<AsyncFunctionLoweringPass>();
129 pipeline.RunPass<TSHCRLoweringPass>();
130 pipeline.RunPass<NTypeHCRLoweringPass>();
131 if (data.IsTypeAbort()) {
132 data.AbortCompilation();
133 return;
134 }
135 pipeline.RunPass<EarlyEliminationPass>();
136 pipeline.RunPass<NumberSpeculativePass>();
137 pipeline.RunPass<LaterEliminationPass>();
138 pipeline.RunPass<ValueNumberingPass>();
139 pipeline.RunPass<StateSplitLinearizerPass>();
140 pipeline.RunPass<NTypeMCRLoweringPass>();
141 pipeline.RunPass<TypeMCRLoweringPass>();
142 pipeline.RunPass<LaterEliminationPass>();
143 pipeline.RunPass<EarlyEliminationPass>();
144 pipeline.RunPass<LCRLoweringPass>();
145 pipeline.RunPass<SlowPathLoweringPass>();
146 pipeline.RunPass<VerifierPass>();
147 pipeline.RunPass<GraphLinearizerPass>();
148 pipeline.RunPass<LLVMIRGenPass>();
149 });
150
151 ProcessConstantPool(&collector);
152 return true;
153 }
154
ProcessConstantPool(BytecodeInfoCollector * collector)155 void PassManager::ProcessConstantPool(BytecodeInfoCollector *collector)
156 {
157 LOG_COMPILER(INFO) << collector->GetBytecodeInfo().GetSkippedMethodSize()
158 << " methods have been skipped";
159 vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->ProcessSnapshotConstantPool(collector);
160 }
161
IsReleasedPandaFile(const JSPandaFile * jsPandaFile) const162 bool PassManager::IsReleasedPandaFile(const JSPandaFile *jsPandaFile) const
163 {
164 MethodLiteral* methodLiteral = jsPandaFile->GetMethodLiterals();
165 if (methodLiteral == nullptr) {
166 LOG_COMPILER(ERROR) << "There is no mehtod literal in " << jsPandaFile->GetJSPandaFileDesc();
167 return false;
168 }
169
170 panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
171 ASSERT(methodId.IsValid());
172 DebugInfoExtractor *debugInfoExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
173 LocalVariableTable lvt = debugInfoExtractor->GetLocalVariableTable(methodId);
174 return lvt.empty();
175 }
176
ResolveModule(const JSPandaFile * jsPandaFile,const std::string & fileName)177 void PassManager::ResolveModule(const JSPandaFile *jsPandaFile, const std::string &fileName)
178 {
179 const auto &recordInfo = jsPandaFile->GetJSRecordInfo();
180 JSThread *thread = vm_->GetJSThread();
181 ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
182 [[maybe_unused]] EcmaHandleScope scope(thread);
183 for (auto info: recordInfo) {
184 if (jsPandaFile->IsModule(info.second)) {
185 auto recordName = info.first;
186 JSHandle<JSTaggedValue> moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(fileName.c_str(),
187 recordName);
188 SourceTextModule::Instantiate(thread, moduleRecord);
189 }
190 }
191 }
192 } // namespace panda::ecmascript::kungfu
193