• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 "optimize_bytecode.h"
17 
18 #include "assembler/assembly-emitter.h"
19 #include "assembler/extensions/extensions.h"
20 #include "bytecode_instruction.h"
21 #include "bytecodeopt_options.h"
22 #include "bytecode_analysis_results.h"
23 #include "codegen.h"
24 #include "common.h"
25 #include "compiler/optimizer/ir/constants.h"
26 #include "compiler/optimizer/ir_builder/ir_builder.h"
27 #include "compiler/optimizer/ir_builder/pbc_iterator.h"
28 #include "compiler/optimizer/optimizations/branch_elimination.h"
29 #include "compiler/optimizer/optimizations/cleanup.h"
30 #include "compiler/optimizer/optimizations/lowering.h"
31 #include "compiler/optimizer/optimizations/move_constants.h"
32 #include "compiler/optimizer/optimizations/regalloc/reg_alloc.h"
33 #include "compiler/optimizer/optimizations/vn.h"
34 #include "constant_propagation/constant_propagation.h"
35 #include "libpandabase/mem/arena_allocator.h"
36 #include "libpandabase/mem/pool_manager.h"
37 #include "libpandafile/class_data_accessor.h"
38 #include "libpandafile/class_data_accessor-inl.h"
39 #include "libpandafile/method_data_accessor.h"
40 #include "libpandafile/field_data_accessor.h"
41 #include "libpandafile/module_data_accessor-inl.h"
42 #include "module_constant_analyzer.h"
43 #include "reg_acc_alloc.h"
44 #include "reg_encoder.h"
45 #include "runtime_adapter.h"
46 
47 #include <regex>
48 
49 namespace panda::bytecodeopt {
50 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
51 panda::bytecodeopt::Options options("");
52 
53 template <typename T>
RunOpts(compiler::Graph * graph)54 constexpr void RunOpts(compiler::Graph *graph)
55 {
56     graph->RunPass<compiler::Cleanup>();
57     graph->RunPass<T>();
58 }
59 
60 template <typename First, typename Second, typename... Rest>
RunOpts(compiler::Graph * graph)61 constexpr void RunOpts(compiler::Graph *graph)
62 {
63     RunOpts<First>(graph);
64     RunOpts<Second, Rest...>(graph);
65 }
66 
RunOptimizations(compiler::Graph * graph,BytecodeOptIrInterface * iface)67 bool RunOptimizations(compiler::Graph *graph, BytecodeOptIrInterface *iface)
68 {
69     constexpr int OPT_LEVEL_0 = 0;
70 
71     if (panda::bytecodeopt::options.GetOptLevel() == OPT_LEVEL_0) {
72         return false;
73     }
74 
75     graph->RunPass<compiler::Cleanup>();
76     ASSERT(graph->IsDynamicMethod());
77 
78     if (compiler::options.IsCompilerBranchElimination()) {
79         graph->RunPass<ConstantPropagation>(iface);
80         RunOpts<compiler::BranchElimination>(graph);
81     }
82 
83     RunOpts<compiler::ValNum, compiler::Lowering, compiler::MoveConstants>(graph);
84 
85     // this pass should run just before register allocator
86     graph->RunPass<compiler::Cleanup>();
87     graph->RunPass<RegAccAlloc>();
88 
89     graph->RunPass<compiler::Cleanup>();
90     if (!RegAlloc(graph)) {
91         LOG(ERROR, BYTECODE_OPTIMIZER) << "Failed compiler::RegAlloc";
92         return false;
93     }
94 
95     graph->RunPass<compiler::Cleanup>();
96     if (!graph->RunPass<RegEncoder>()) {
97         LOG(ERROR, BYTECODE_OPTIMIZER) << "Failed RegEncoder";
98         return false;
99     }
100 
101     return true;
102 }
103 
BuildMapFromPcToIns(pandasm::Function & function,BytecodeOptIrInterface & ir_interface,const compiler::Graph * graph,compiler::RuntimeInterface::MethodPtr method_ptr)104 void BuildMapFromPcToIns(pandasm::Function &function, BytecodeOptIrInterface &ir_interface,
105                          const compiler::Graph *graph, compiler::RuntimeInterface::MethodPtr method_ptr)
106 {
107     CHECK_NOT_NULL(graph);
108     function.local_variable_debug.clear();
109     auto *pc_ins_map = ir_interface.GetPcInsMap();
110     pc_ins_map->reserve(function.ins.size());
111     auto instructions_buf = graph->GetRuntime()->GetMethodCode(method_ptr);
112     compiler::BytecodeInstructions instructions(instructions_buf, graph->GetRuntime()->GetMethodCodeSize(method_ptr));
113     compiler::BytecodeIterator insn_iter = instructions.begin();
114     for (pandasm::Ins &ins : function.ins) {
115         /**
116          * pc_ins_map is built with instructions data from the emitted abc file and the original function assembly.
117          * Instructions of invalid opcode will be removed during emitter, but kept within function assembly structure,
118          * therefore these instructions need to be skipped here
119          **/
120         if (ins.opcode == pandasm::Opcode::INVALID) {
121             continue;
122         }
123         pc_ins_map->emplace(instructions.GetPc(*insn_iter), &ins);
124         ++insn_iter;
125         if (insn_iter == instructions.end()) {
126             break;
127         }
128     }
129 }
130 
ColumnNumberPropagate(pandasm::Function * function)131 static void ColumnNumberPropagate(pandasm::Function *function)
132 {
133     auto &ins_vec = function->ins;
134     uint32_t cn = compiler::INVALID_COLUMN_NUM;
135     // handle the instructions that are at the beginning of code but do not have column number
136     size_t k = 0;
137     while (k < ins_vec.size() && cn == compiler::INVALID_COLUMN_NUM) {
138         cn = ins_vec[k++].ins_debug.column_number;
139     }
140     if (cn == compiler::INVALID_COLUMN_NUM) {
141         LOG(DEBUG, BYTECODE_OPTIMIZER) << "Failed ColumnNumberPropagate: All insts have invalid column number";
142         return;
143     }
144     for (size_t j = 0; j < k - 1; j++) {
145         ins_vec[j].ins_debug.SetColumnNumber(cn);
146     }
147 
148     // handle other instructions that do not have column number
149     for (; k < ins_vec.size(); k++) {
150         if (ins_vec[k].ins_debug.column_number != compiler::INVALID_COLUMN_NUM) {
151             cn = ins_vec[k].ins_debug.column_number;
152         } else {
153             ins_vec[k].ins_debug.SetColumnNumber(cn);
154         }
155     }
156 }
157 
LineNumberPropagate(pandasm::Function * function)158 static void LineNumberPropagate(pandasm::Function *function)
159 {
160     if (function == nullptr || function->ins.empty()) {
161         return;
162     }
163     size_t ln = 0;
164     auto &ins_vec = function->ins;
165 
166     // handle the instructions that are at the beginning of code but do not have line number
167     size_t i = 0;
168     while (i < ins_vec.size() && ln == 0) {
169         ln = ins_vec[i++].ins_debug.line_number;
170     }
171     if (ln == 0) {
172         LOG(DEBUG, BYTECODE_OPTIMIZER) << "Failed LineNumberPropagate: All insts have invalid line number";
173         return;
174     }
175     for (size_t j = 0; j < i - 1; j++) {
176         ins_vec[j].ins_debug.SetLineNumber(ln);
177     }
178 
179     // handle other instructions that do not have line number
180     for (; i < ins_vec.size(); i++) {
181         if (ins_vec[i].ins_debug.line_number != 0) {
182             ln = ins_vec[i].ins_debug.line_number;
183         } else {
184             ins_vec[i].ins_debug.SetLineNumber(ln);
185         }
186     }
187 }
188 
DebugInfoPropagate(pandasm::Function & function,const compiler::Graph * graph,BytecodeOptIrInterface & ir_interface)189 static void DebugInfoPropagate(pandasm::Function &function, const compiler::Graph *graph,
190                                BytecodeOptIrInterface &ir_interface)
191 {
192     LineNumberPropagate(&function);
193     if (graph->IsDynamicMethod()) {
194         ColumnNumberPropagate(&function);
195     }
196     ir_interface.ClearPcInsMap();
197 }
198 
SkipFunction(const pandasm::Function & function,const std::string & func_name)199 static bool SkipFunction(const pandasm::Function &function, const std::string &func_name)
200 {
201     if (panda::bytecodeopt::options.WasSetMethodRegex()) {
202         static std::regex rgx(panda::bytecodeopt::options.GetMethodRegex());
203         if (!std::regex_match(func_name, rgx)) {
204             LOG(INFO, BYTECODE_OPTIMIZER) << "Skip Function " << func_name << ": Function's name doesn't match regex";
205             return true;
206         }
207     }
208 
209     if (panda::bytecodeopt::options.IsSkipMethodsWithEh() && !function.catch_blocks.empty()) {
210         LOG(INFO, BYTECODE_OPTIMIZER) << "Was not optimized " << func_name << ": Function has catch blocks";
211         return true;
212     }
213 
214     if ((function.regs_num + function.GetParamsNum()) > compiler::VIRTUAL_FRAME_SIZE) {
215         LOG(ERROR, BYTECODE_OPTIMIZER) << "Unable to optimize " << func_name
216                                        << ": Function frame size is larger than allowed one";
217         return true;
218     }
219     return false;
220 }
221 
SetCompilerOptions()222 static void SetCompilerOptions()
223 {
224     compiler::options.SetCompilerUseSafepoint(false);
225     compiler::options.SetCompilerSupportInitObjectInst(true);
226     if (!compiler::options.WasSetCompilerMaxBytecodeSize()) {
227         compiler::options.SetCompilerMaxBytecodeSize(MAX_BYTECODE_SIZE);
228     }
229 }
230 
StringStartsWith(const std::string & str,const std::string & prefix)231 static bool StringStartsWith(const std::string &str, const std::string &prefix)
232 {
233     return (str.size() >= prefix.size()) &&
234         std::equal(prefix.begin(), prefix.end(), str.begin());
235 }
236 
ModuleRequestOffsetToRecordName(const panda_file::File & pfile,uint32_t module_request_offset)237 static std::string ModuleRequestOffsetToRecordName(const panda_file::File &pfile,
238                                                    uint32_t module_request_offset)
239 {
240     constexpr char AND_TOKEN = '&';
241     const std::string BUNDLE_PREFIX = "@bundle:";
242     const std::string PACKAGE_PREFIX = "@package:";
243     const std::string NORMALIZED_NON_NATIVE_PREFIX = "@normalized:N&";
244 
245     auto record_ohmurl = GetStringFromPandaFile(pfile, module_request_offset);
246     // Assumptions of the current possible ohmurl formats:
247     // @bundle:record_name
248     // @package:record_name
249     // @normalized:N&xxxx&record_name
250     // Extract record_name from each possible cases.
251     if (StringStartsWith(record_ohmurl, BUNDLE_PREFIX)) {
252         return record_ohmurl.substr(BUNDLE_PREFIX.size());
253     } else if (StringStartsWith(record_ohmurl, PACKAGE_PREFIX)) {
254         return record_ohmurl.substr(PACKAGE_PREFIX.size());
255     } else if (StringStartsWith(record_ohmurl, NORMALIZED_NON_NATIVE_PREFIX)) {
256         size_t second_and_pos = record_ohmurl.find(AND_TOKEN, NORMALIZED_NON_NATIVE_PREFIX.size());
257         if (second_and_pos != std::string::npos) {
258             return record_ohmurl.substr(second_and_pos + 1);
259         }
260     }
261     // Otherwise, return empty string to represent no ohmurl is found
262     return "";
263 }
264 
AnalysisModuleRecordInfoOfModuleDataAccessor(const panda_file::File & pfile,panda_file::ModuleDataAccessor & mda,BytecodeAnalysisResult & result)265 static void AnalysisModuleRecordInfoOfModuleDataAccessor(const panda_file::File &pfile,
266                                                          panda_file::ModuleDataAccessor &mda,
267                                                          BytecodeAnalysisResult &result)
268 {
269     const auto &request_modules_offsets = mda.getRequestModules();
270     int regular_import_idx = 0;
271     std::unordered_set<std::string> local_export_local_names;
272     mda.EnumerateModuleRecord([&](panda_file::ModuleTag tag, uint32_t export_name_offset,
273                                   uint32_t request_module_idx, uint32_t import_name_offset,
274                                   uint32_t local_name_offset) {
275         switch (tag) {
276             case panda_file::ModuleTag::LOCAL_EXPORT: {
277                 std::string export_name = GetStringFromPandaFile(pfile, export_name_offset);
278                 std::string local_name = GetStringFromPandaFile(pfile, local_name_offset);
279                 // Slot of stmodulevar/ldlocalmodulevar is the index of its local name, while
280                 // one local name can match multiple external names with "export...as...".
281                 // Local export entries are sorted by their local name, thus using an unrodered_set
282                 // can get the correct index form (size - 1) (starts from 0).
283                 // See SourceTextModuleRecord::AssignIndexToModuleVariable for more details
284                 local_export_local_names.insert(local_name);
285                 result.SetLocalExportInfo(local_export_local_names.size() - 1, export_name);
286                 break;
287             }
288             case panda_file::ModuleTag::REGULAR_IMPORT: {
289                 std::string request_module_name =
290                     ModuleRequestOffsetToRecordName(pfile, request_modules_offsets[request_module_idx]);
291                 if (!request_module_name.empty()) {
292                     std::string import_name = GetStringFromPandaFile(pfile, import_name_offset);
293                     result.SetRegularImportInfo(regular_import_idx, import_name, request_module_name);
294                 }
295                 regular_import_idx++;
296                 break;
297             }
298             case panda_file::ModuleTag::NAMESPACE_IMPORT: {
299                 // Slot of getmodulenamespace bytecode is its request_module_idx
300                 std::string namespace_name =
301                     ModuleRequestOffsetToRecordName(pfile, request_modules_offsets[request_module_idx]);
302                 if (!namespace_name.empty()) {
303                     result.SetNamespaceImportInfo(request_module_idx, namespace_name);
304                 }
305                 break;
306             }
307             default:
308                 break;
309         }
310     });
311 }
312 
AnalysisModuleRecordInfo(const panda_file::File & pfile,panda_file::ClassDataAccessor & cda,BytecodeAnalysisResult & result)313 static void AnalysisModuleRecordInfo(const panda_file::File &pfile,
314                                      panda_file::ClassDataAccessor &cda,
315                                      BytecodeAnalysisResult &result)
316 {
317     const std::string MODULE_RECORD_IDX_FIELD_NAME = "moduleRecordIdx";
318     // RequireGlobalOptimization is true only under mergeAbc mode, where module record is stored
319     // in the moduleRecordIdx field according to Emitter::AddSourceTextModuleRecord
320     cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) -> void {
321         if (fda.IsExternal()) {
322             return;
323         }
324         std::string field_name = GetStringFromPandaFile(pfile, fda.GetNameId().GetOffset());
325         if (field_name == MODULE_RECORD_IDX_FIELD_NAME) {
326             panda_file::File::EntityId module_entity_id(fda.GetValue<uint32_t>().value());
327             panda_file::ModuleDataAccessor mda(pfile, module_entity_id);
328             AnalysisModuleRecordInfoOfModuleDataAccessor(pfile, mda, result);
329         }
330     });
331 }
332 
AnalysisModuleConstantValue(panda_file::ClassDataAccessor & cda,const std::string & record_name,bool is_dynamic,const BytecodeOptIrInterface & ir_interface,BytecodeAnalysisResult & result)333 static void AnalysisModuleConstantValue(panda_file::ClassDataAccessor &cda, const std::string &record_name,
334                                         bool is_dynamic, const BytecodeOptIrInterface &ir_interface,
335                                         BytecodeAnalysisResult &result)
336 {
337     const std::string MAIN_METHOD_NAME = ".func_main_0";
338     cda.EnumerateMethods([MAIN_METHOD_NAME, record_name, is_dynamic, ir_interface, &result](
339             panda_file::MethodDataAccessor &mda) {
340         if (mda.IsExternal()) {
341             return false;
342         }
343 
344         // Only analysis func_main_0 for now, since the assignment instruction of all exported constants
345         // are in func_main_0, and the bytecode analysis phase only contains analysing initial value of
346         // module constants for branch-elimination for now
347         auto func_name = ir_interface.GetMethodIdByOffset(mda.GetMethodId().GetOffset());
348         if (func_name != record_name + MAIN_METHOD_NAME) {
349             return true;
350         }
351 
352         ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
353         ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
354 
355         auto *prog = ir_interface.GetProgram();
356         auto it = prog->function_table.find(func_name);
357         if (it == prog->function_table.end()) {
358             LOG(ERROR, BYTECODE_OPTIMIZER) << "Cannot find function: " << func_name;
359             return false;
360         }
361 
362         panda::pandasm::Function &function = it->second;
363         if (SkipFunction(function, func_name)) {
364             return false;
365         }
366 
367         auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(mda.GetMethodId().GetOffset());
368         panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
369         auto graph = allocator.New<compiler::Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
370                                                     false, nullptr, is_dynamic, true);
371         if ((graph == nullptr) || !graph->RunPass<panda::compiler::IrBuilder>()) {
372             LOG(ERROR, BYTECODE_OPTIMIZER) << "Analysis " << func_name << ": IR builder failed!";
373             return false;
374         }
375 
376         ModuleConstantAnalysisResult module_constant_results;
377         ModuleConstantAnalyzer analyzer(graph, result.GetConstantLocalExportSlots(),
378                                         module_constant_results, &ir_interface);
379         graph->RunPass<ModuleConstantAnalyzer>(&analyzer);
380         result.SetModuleConstantAnalysisResult(module_constant_results);
381         return true;
382     });
383 }
384 
AnalysisBytecode(pandasm::Program * prog,const pandasm::AsmEmitter::PandaFileToPandaAsmMaps * maps,const std::string & pfile_name,bool is_dynamic,bool has_memory_pool)385 bool AnalysisBytecode(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
386                       const std::string &pfile_name, bool is_dynamic, bool has_memory_pool)
387 {
388     if (!has_memory_pool) {
389         PoolManager::Initialize(PoolType::MALLOC);
390     }
391 
392     auto pfile = panda_file::OpenPandaFile(pfile_name);
393     if (!pfile) {
394         LOG(FATAL, BYTECODE_OPTIMIZER) << "Can not open binary file: " << pfile_name;
395         return false;
396     }
397 
398     for (uint32_t id : pfile->GetClasses()) {
399         panda_file::File::EntityId record_id {id};
400 
401         if (pfile->IsExternal(record_id)) {
402             continue;
403         }
404 
405         panda_file::ClassDataAccessor cda {*pfile, record_id};
406         // Skip annotation records since they do not contain real code for now
407         if (cda.IsAnnotation()) {
408             continue;
409         }
410         std::string record_type_descriptor(utf::Mutf8AsCString(cda.GetName().data));
411         std::string record_name = pandasm::Type::FromDescriptor(record_type_descriptor).GetName();
412 
413         bool exists = false;
414         auto &result = BytecodeAnalysisResults::GetOrCreateBytecodeAnalysisResult(record_name, exists);
415         if (exists) {
416             return true;
417         }
418         auto ir_interface = BytecodeOptIrInterface(maps, prog);
419         AnalysisModuleRecordInfo(*pfile, cda, result);
420         AnalysisModuleConstantValue(cda, record_name, is_dynamic, ir_interface, result);
421     }
422 
423     if (!has_memory_pool) {
424         PoolManager::Finalize();
425     }
426 
427     return true;
428 }
429 
OptimizeFunction(pandasm::Program * prog,const pandasm::AsmEmitter::PandaFileToPandaAsmMaps * maps,const panda_file::MethodDataAccessor & mda,bool is_dynamic)430 bool OptimizeFunction(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
431                       const panda_file::MethodDataAccessor &mda, bool is_dynamic)
432 {
433     ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
434     ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
435 
436     SetCompilerOptions();
437 
438     auto ir_interface = BytecodeOptIrInterface(maps, prog);
439 
440     auto func_name = ir_interface.GetMethodIdByOffset(mda.GetMethodId().GetOffset());
441     LOG(INFO, BYTECODE_OPTIMIZER) << "Optimizing function: " << func_name;
442 
443     auto it = prog->function_table.find(func_name);
444     if (it == prog->function_table.end()) {
445         LOG(ERROR, BYTECODE_OPTIMIZER) << "Cannot find function: " << func_name;
446         return false;
447     }
448     auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(mda.GetMethodId().GetOffset());
449 
450     panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
451     auto graph = allocator.New<compiler::Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter, false,
452                                                 nullptr, is_dynamic, true);
453 
454     panda::pandasm::Function &function = it->second;
455 
456     if (SkipFunction(function, func_name)) {
457         return false;
458     }
459 
460     // build map from pc to pandasm::ins (to re-build line-number info in BytecodeGen)
461     BuildMapFromPcToIns(function, ir_interface, graph, method_ptr);
462 
463     if ((graph == nullptr) || !graph->RunPass<panda::compiler::IrBuilder>()) {
464         LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": IR builder failed!";
465         return false;
466     }
467 
468     if (graph->HasIrreducibleLoop()) {
469         LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Graph has irreducible loop!";
470         return false;
471     }
472 
473     if (!RunOptimizations(graph, &ir_interface)) {
474         LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Running optimizations failed!";
475         return false;
476     }
477 
478     if (!graph->RunPass<BytecodeGen>(&function, &ir_interface, prog)) {
479         LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Code generation failed!";
480         return false;
481     }
482 
483     DebugInfoPropagate(function, graph, ir_interface);
484 
485     function.value_of_first_param =
486         static_cast<int64_t>(graph->GetStackSlotsCount()) - 1;  // Work-around promotion rules
487     function.regs_num = static_cast<size_t>(function.value_of_first_param + 1);
488 
489     if (auto frame_size = function.regs_num + function.GetParamsNum(); frame_size >= NUM_COMPACTLY_ENCODED_REGS) {
490         LOG(INFO, BYTECODE_OPTIMIZER) << "Function " << func_name << " has frame size " << frame_size;
491     }
492 
493     LOG(DEBUG, BYTECODE_OPTIMIZER) << "Optimized " << func_name;
494 
495     return true;
496 }
497 
OptimizePandaFile(pandasm::Program * prog,const pandasm::AsmEmitter::PandaFileToPandaAsmMaps * maps,const std::string & pfile_name,bool is_dynamic)498 bool OptimizePandaFile(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
499                        const std::string &pfile_name, bool is_dynamic)
500 {
501     auto pfile = panda_file::OpenPandaFile(pfile_name);
502     if (!pfile) {
503         LOG(FATAL, BYTECODE_OPTIMIZER) << "Can not open binary file: " << pfile_name;
504     }
505 
506     bool result = true;
507 
508     for (uint32_t id : pfile->GetClasses()) {
509         panda_file::File::EntityId record_id {id};
510 
511         if (pfile->IsExternal(record_id)) {
512             continue;
513         }
514 
515         panda_file::ClassDataAccessor cda {*pfile, record_id};
516         cda.EnumerateMethods([prog, maps, is_dynamic, &result](panda_file::MethodDataAccessor &mda) {
517             if (!mda.IsExternal()) {
518                 result = OptimizeFunction(prog, maps, mda, is_dynamic) && result;
519             }
520         });
521     }
522 
523     return result;
524 }
525 
OptimizeBytecode(pandasm::Program * prog,const pandasm::AsmEmitter::PandaFileToPandaAsmMaps * maps,const std::string & pandafile_name,bool is_dynamic,bool has_memory_pool)526 bool OptimizeBytecode(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
527                       const std::string &pandafile_name, bool is_dynamic, bool has_memory_pool)
528 {
529     ASSERT(prog != nullptr);
530     ASSERT(maps != nullptr);
531 
532     if (!has_memory_pool) {
533         PoolManager::Initialize(PoolType::MALLOC);
534     }
535 
536     auto res = OptimizePandaFile(prog, maps, pandafile_name, is_dynamic);
537 
538     if (!has_memory_pool) {
539         PoolManager::Finalize();
540     }
541 
542     return res;
543 }
544 }  // namespace panda::bytecodeopt
545