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#include "ecmascript/compiler/pass_manager.h" 16 17#include "ecmascript/compiler/bytecodes.h" 18#include "ecmascript/compiler/compilation_driver.h" 19#include "ecmascript/compiler/pass.h" 20#include "ecmascript/ecma_handle_scope.h" 21#include "ecmascript/jspandafile/js_pandafile_manager.h" 22#include "ecmascript/jspandafile/method_literal.h" 23#include "ecmascript/jspandafile/panda_file_translator.h" 24#include "ecmascript/log.h" 25#include "ecmascript/log_wrapper.h" 26#include "ecmascript/pgo_profiler/pgo_profiler.h" 27#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" 28#include "ecmascript/pgo_profiler/pgo_utils.h" 29#include "ecmascript/jit/jit.h" 30#include "jsnapi_expo.h" 31 32namespace panda::ecmascript::kungfu { 33using PGOProfilerManager = pgo::PGOProfilerManager; 34 35PassContext::PassContext(const std::string &triple, CompilerLog *log, BytecodeInfoCollector* collector, 36 IRModule *aotModule, PGOProfilerDecoder *decoder) 37 : compilationEnv_(collector->GetCompilationEnv()), 38 bcInfoCollector_(collector), 39 bytecodes_(collector->GetByteCodes()), 40 cmpCfg_(triple, &compilationEnv_->GetJSOptions()), 41 log_(log), 42 jsPandaFile_(collector->GetJSPandaFile()), 43 aotModule_(aotModule), 44 decoder_(decoder) 45{ 46} 47 48 49bool JitPassManager::Compile(JSHandle<ProfileTypeInfo> &profileTypeInfo, 50 AOTFileGenerator &gen, int32_t osrOffset) 51{ 52 const JSPandaFile *jsPandaFile = compilationEnv_->GetJSPandaFile(); 53 ASSERT(jsPandaFile != nullptr); 54 MethodLiteral *methodLiteral = compilationEnv_->GetMethodLiteral(); 55 const uint8_t *pcStart = compilationEnv_->GetMethodPcStart(); 56 const panda_file::File::Header *header = jsPandaFile->GetPandaFile()->GetHeader(); 57 ApEntityId abcId = compilationEnv_->GetMethodAbcId(); 58 std::string fileName(jsPandaFile->GetJSPandaFileDesc()); 59 60 collector_ = new BytecodeInfoCollector(compilationEnv_, const_cast<JSPandaFile*>(jsPandaFile), 61 profilerDecoder_); 62 63 gen.SetCurrentCompileFileName(jsPandaFile->GetNormalizedFileDesc()); 64 lOptions_ = new LOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_); 65 cmpDriver_ = new JitCompilationDriver(profilerDecoder_, 66 collector_, 67 &gen, 68 fileName, 69 triple_, 70 lOptions_, 71 log_, 72 log_->OutputASM(), 73 maxMethodsInModule_); 74 return cmpDriver_->CompileMethod(jsPandaFile, methodLiteral, profileTypeInfo, pcStart, header, abcId, 75 [this, &fileName, &osrOffset] ( 76 const CString &recordName, 77 const std::string &methodName, 78 MethodLiteral *methodLiteral, 79 JSHandle<ProfileTypeInfo> &profileTypeInfo, 80 uint32_t methodOffset, 81 const MethodPcInfo &methodPCInfo, 82 MethodInfo &methodInfo, 83 Module *m, 84 const uint8_t *pcStart, 85 const panda_file::File::Header *header, 86 ApEntityId abcId) -> bool { 87 if (compilationEnv_->GetJSOptions().GetTraceJIT()) { 88 LOG_COMPILER(INFO) << "JIT Compile Method Start: " << methodName << ", " << methodOffset << "\n"; 89 } 90 ctx_ = new PassContext(triple_, log_, collector_, m->GetModule(), &profilerDecoder_); 91 92 auto jsPandaFile = ctx_->GetJSPandaFile(); 93 auto cmpCfg = ctx_->GetCompilerConfig(); 94 auto module = m->GetModule(); 95 log_->SetMethodLog(fileName, methodName, logList_); 96 97 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile); 98 bool enableMethodLog = log_->GetEnableMethodLog(); 99 if (enableMethodLog) { 100 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName 101 << "] recordName [" << recordName << "] log:" << "\033[0m"; 102 } 103 Chunk chunk(compilationEnv_->GetNativeAreaAllocator()); 104 if (compilationEnv_->GetJSOptions().IsEnableJITPGO()) { 105 jitProfiler_ = compilationEnv_->GetPGOProfiler()->GetJITProfile(); 106 static_cast<JitCompilationEnv*>(compilationEnv_)->SetProfileTypeInfo(profileTypeInfo); 107 jitProfiler_->SetCompilationEnv(compilationEnv_); 108 jitProfiler_->InitChunk(&chunk); 109 jitProfiler_->ProfileBytecode(compilationEnv_->GetJSThread(), profileTypeInfo, nullptr, 110 methodLiteral->GetMethodId(), abcId, pcStart, 111 methodLiteral->GetCodeSize(jsPandaFile, methodLiteral->GetMethodId()), 112 header); 113 } else { 114 jitProfiler_ = nullptr; 115 } 116 117 if (compilationEnv_->GetJSOptions().IsEnableJitFrame()) { 118 circuit_ = new Circuit(compilationEnv_->GetNativeAreaAllocator(), ctx_->GetAOTModule()->GetDebugInfo(), 119 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::FASTJIT_FUNCTION_FRAME); 120 } else { 121 circuit_ = new Circuit(compilationEnv_->GetNativeAreaAllocator(), ctx_->GetAOTModule()->GetDebugInfo(), 122 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME); 123 } 124 125 PGOProfilerDecoder defDecoder; 126 PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : &defDecoder; 127 128 builder_ = new BytecodeCircuitBuilder(jsPandaFile, methodLiteral, methodPCInfo, 129 circuit_, ctx_->GetByteCodes(), enableMethodLog && log_->OutputCIR(), 130 passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false, jitProfiler_); 131 builder_->SetOsrOffset(osrOffset); 132 { 133 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_); 134 builder_->SetJitCompile(); 135 builder_->BytecodeToCircuit(); 136 if (builder_->HasIrreducibleLoop()) { 137 LOG_JIT(DEBUG) << "compile fail as has irreducible loop:" << methodName; 138 return false; 139 } 140 } 141 142 CallMethodFlagMap methodFlagMap; 143 data_ = new PassData(builder_, circuit_, ctx_, log_, fullName, &methodInfo, recordName, 144 methodLiteral, methodOffset, &methodFlagMap, CVector<AbcFileInfo> {}, 145 compilationEnv_->GetNativeAreaAllocator(), decoder, passOptions_); 146 PassRunner<PassData> pipeline(data_); 147 148 pipeline.RunPass<RunFlowCyclesVerifierPass>(); 149 pipeline.RunPass<RedundantPhiEliminationPass>(); 150 if (builder_->EnableLoopOptimization()) { 151 pipeline.RunPass<LoopOptimizationPass>(); 152 pipeline.RunPass<RedundantPhiEliminationPass>(); 153 } 154 if (passOptions_->EnableTypeLowering()) { 155 pipeline.RunPass<PGOTypeInferPass>(); 156 } 157 { 158 Jit::JitLockHolder lock(compilationEnv_, "TSInlineLoweringPass"); 159 pipeline.RunPass<TSInlineLoweringPass>(); 160 } 161 162 pipeline.RunPass<RedundantPhiEliminationPass>(); 163 pipeline.RunPass<AsyncFunctionLoweringPass>(); 164 pipeline.RunPass<TypeBytecodeLoweringPass>(); 165 pipeline.RunPass<UselessGateEliminationPass>(); 166 pipeline.RunPass<InductionVariableAnalysisPass>(); 167 pipeline.RunPass<RedundantPhiEliminationPass>(); 168 pipeline.RunPass<NTypeBytecodeLoweringPass>(); 169 pipeline.RunPass<UselessGateEliminationPass>(); 170 pipeline.RunPass<EarlyEliminationPass>(); 171 pipeline.RunPass<NumberSpeculativePass>(); 172 pipeline.RunPass<UselessGateEliminationPass>(); 173 pipeline.RunPass<LaterEliminationPass>(); 174 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) { 175 pipeline.RunPass<ValueNumberingPass>(); 176 } 177 pipeline.RunPass<StateSplitLinearizerPass>(); 178 pipeline.RunPass<EscapeAnalysisPass>(); 179 pipeline.RunPass<StringOptimizationPass>(); 180 pipeline.RunPass<NTypeHCRLoweringPass>(); 181 pipeline.RunPass<TypeHCRLoweringPass>(); 182 pipeline.RunPass<UselessGateEliminationPass>(); 183 pipeline.RunPass<LaterEliminationPass>(); 184 pipeline.RunPass<EarlyEliminationPass>(); 185 pipeline.RunPass<LCRLoweringPass>(); 186 pipeline.RunPass<UselessGateEliminationPass>(); 187 pipeline.RunPass<ConstantFoldingPass>(); 188 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) { 189 pipeline.RunPass<ValueNumberingPass>(); 190 } 191 pipeline.RunPass<SlowPathLoweringPass>(); 192 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) { 193 pipeline.RunPass<ValueNumberingPass>(); 194 } 195 pipeline.RunPass<InstructionCombinePass>(); 196 pipeline.RunPass<EarlyEliminationPass>(); 197 pipeline.RunPass<UselessGateEliminationPass>(); 198 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) { 199 pipeline.RunPass<VerifierPass>(); 200 } 201 pipeline.RunPass<GraphLinearizerPass>(); 202 return true; 203 }); 204} 205 206bool JitPassManager::RunCg() 207{ 208 PassRunner<PassData> pipeline(data_); 209 pipeline.RunPass<CGIRGenPass>(); 210 return cmpDriver_->RunCg(); 211} 212 213JitPassManager::~JitPassManager() 214{ 215 if (data_ != nullptr) { 216 delete data_; 217 data_ = nullptr; 218 } 219 if (builder_ != nullptr) { 220 delete builder_; 221 builder_ = nullptr; 222 } 223 if (circuit_ != nullptr) { 224 delete circuit_; 225 circuit_ = nullptr; 226 } 227 if (ctx_ != nullptr) { 228 delete ctx_; 229 ctx_ = nullptr; 230 } 231 if (cmpDriver_ != nullptr) { 232 delete cmpDriver_; 233 cmpDriver_ = nullptr; 234 } 235 if (lOptions_ != nullptr) { 236 delete lOptions_; 237 lOptions_ = nullptr; 238 } 239 if (collector_ != nullptr) { 240 delete collector_; 241 collector_ = nullptr; 242 } 243} 244 245void PassManager::CompileValidFiles(AOTFileGenerator &generator, bool &ret, AotCompilerStats &compilerStats) 246{ 247 for (uint32_t i = 0 ; i < fileInfos_.size(); ++i) { 248 JSPandaFile *jsPandaFile = fileInfos_[i].jsPandaFile_.get(); 249 auto &collector = *bcInfoCollectors_[i]; 250 const std::string &extendedFilePath = fileInfos_[i].extendedFilePath_; 251 LOG_COMPILER(INFO) << "AOT compile: " << extendedFilePath; 252 generator.SetCurrentCompileFileName(jsPandaFile->GetNormalizedFileDesc()); 253 if (!Compile(jsPandaFile, extendedFilePath, generator, compilerStats, collector)) { 254 ret = false; 255 continue; 256 } 257 } 258} 259 260bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, AOTFileGenerator &gen, 261 AotCompilerStats &compilerStats, BytecodeInfoCollector &collector) 262{ 263 [[maybe_unused]] EcmaHandleScope handleScope(compilationEnv_->GetJSThread()); 264 265 // Checking released/debuggable pandafile uses method literals, which are initialized in BytecodeInfoCollector, 266 // should after it. 267 if (!IsReleasedPandaFile(jsPandaFile)) { 268 LOG_COMPILER(ERROR) << "The input panda file [" << fileName 269 << "] of AOT Compiler is debuggable version, do not use for performance test!"; 270 } 271 LOptions lOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_); 272 CompilationDriver cmpDriver(profilerDecoder_, 273 &collector, 274 &gen, 275 fileName, 276 triple_, 277 &lOptions, 278 log_, 279 log_->OutputASM(), 280 maxMethodsInModule_); 281 282 cmpDriver.Run(*callMethodFlagMap_, [this, &fileName, &collector](const CString recordName, 283 const std::string &methodName, 284 MethodLiteral *methodLiteral, 285 uint32_t methodOffset, 286 const MethodPcInfo &methodPCInfo, 287 MethodInfo &methodInfo, 288 Module *m) { 289 PassContext ctx(triple_, log_, &collector, m->GetModule(), &profilerDecoder_); 290 auto jsPandaFile = ctx.GetJSPandaFile(); 291 auto cmpCfg = ctx.GetCompilerConfig(); 292 auto module = m->GetModule(); 293 log_->SetMethodLog(fileName, methodName, logList_); 294 295 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile); 296 bool enableMethodLog = log_->GetEnableMethodLog(); 297 if (enableMethodLog) { 298 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName 299 << "] recordName [" << recordName << "] log:" << "\033[0m"; 300 } 301 302 Circuit circuit(compilationEnv_->GetNativeAreaAllocator(), ctx.GetAOTModule()->GetDebugInfo(), 303 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME); 304 305 PGOProfilerDecoder defDecoder; 306 PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : &defDecoder; 307 308 BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, &circuit, 309 ctx.GetByteCodes(), enableMethodLog && log_->OutputCIR(), 310 passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false); 311 { 312 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_); 313 builder.BytecodeToCircuit(); 314 } 315 316 PassData data(&builder, &circuit, &ctx, log_, fullName, &methodInfo, recordName, 317 methodLiteral, methodOffset, callMethodFlagMap_, fileInfos_, 318 compilationEnv_->GetNativeAreaAllocator(), decoder, passOptions_, 319 optBCRange_); 320 PassRunner<PassData> pipeline(&data); 321 if (!pipeline.RunPass<PreCompileCheckPass>()) { 322 return; 323 } 324 pipeline.RunPass<RunFlowCyclesVerifierPass>(); 325 pipeline.RunPass<RedundantPhiEliminationPass>(); 326 if (builder.EnableLoopOptimization()) { 327 pipeline.RunPass<LoopOptimizationPass>(); 328 pipeline.RunPass<RedundantPhiEliminationPass>(); 329 } 330 pipeline.RunPass<PGOTypeInferPass>(); 331 pipeline.RunPass<TSInlineLoweringPass>(); 332 pipeline.RunPass<RedundantPhiEliminationPass>(); 333 pipeline.RunPass<AsyncFunctionLoweringPass>(); 334 pipeline.RunPass<TypeBytecodeLoweringPass>(); 335 pipeline.RunPass<UselessGateEliminationPass>(); 336 pipeline.RunPass<InductionVariableAnalysisPass>(); 337 pipeline.RunPass<RedundantPhiEliminationPass>(); 338 pipeline.RunPass<NTypeBytecodeLoweringPass>(); 339 pipeline.RunPass<UselessGateEliminationPass>(); 340 pipeline.RunPass<EarlyEliminationPass>(); 341 pipeline.RunPass<NumberSpeculativePass>(); 342 pipeline.RunPass<UselessGateEliminationPass>(); 343 pipeline.RunPass<LaterEliminationPass>(); 344 pipeline.RunPass<ValueNumberingPass>(); 345 pipeline.RunPass<StateSplitLinearizerPass>(); 346 pipeline.RunPass<EscapeAnalysisPass>(); 347 pipeline.RunPass<StringOptimizationPass>(); 348 pipeline.RunPass<NTypeHCRLoweringPass>(); 349 pipeline.RunPass<TypeHCRLoweringPass>(); 350 pipeline.RunPass<UselessGateEliminationPass>(); 351 pipeline.RunPass<LaterEliminationPass>(); 352 pipeline.RunPass<EarlyEliminationPass>(); 353 pipeline.RunPass<LCRLoweringPass>(); 354 pipeline.RunPass<UselessGateEliminationPass>(); 355 pipeline.RunPass<ConstantFoldingPass>(); 356 pipeline.RunPass<ValueNumberingPass>(); 357 pipeline.RunPass<SlowPathLoweringPass>(); 358 pipeline.RunPass<ValueNumberingPass>(); 359 pipeline.RunPass<InstructionCombinePass>(); 360 pipeline.RunPass<EarlyEliminationPass>(); 361 pipeline.RunPass<UselessGateEliminationPass>(); 362 if (passOptions_->EnableVerifierPass()) { 363 pipeline.RunPass<VerifierPass>(); 364 } 365 pipeline.RunPass<GraphLinearizerPass>(); 366 pipeline.RunPass<CGIRGenPass>(); 367 }); 368 369 compilerStats.SetCompilerMethodCount(cmpDriver.GetCompilerMethodCount()); 370 LOG_COMPILER(INFO) << collector.GetBytecodeInfo().GetSkippedMethodSize() 371 << " methods have been skipped"; 372 return true; 373} 374 375bool PassManager::IsReleasedPandaFile(const JSPandaFile *jsPandaFile) const 376{ 377 MethodLiteral* methodLiteral = jsPandaFile->GetMethodLiterals(); 378 if (methodLiteral == nullptr) { 379 LOG_COMPILER(ERROR) << "There is no mehtod literal in " << jsPandaFile->GetJSPandaFileDesc(); 380 return false; 381 } 382 383 panda_file::File::EntityId methodId = methodLiteral->GetMethodId(); 384 ASSERT(methodId.IsValid()); 385 DebugInfoExtractor *debugInfoExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); 386 LocalVariableTable lvt = debugInfoExtractor->GetLocalVariableTable(methodId); 387 return lvt.empty(); 388} 389} // namespace panda::ecmascript::kungfu 390