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 
16 #include <chrono>
17 #include <iostream>
18 #include <memory>
19 
20 #include "ecmascript/base/string_helper.h"
21 #include "ecmascript/checkpoint/thread_state_transition.h"
22 #include "ecmascript/compiler/aot_compilation_env.h"
23 #include "ecmascript/compiler/aot_compiler_preprocessor.h"
24 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
25 #include "ecmascript/compiler/pass_manager.h"
26 #include "ecmascript/ecma_string.h"
27 #include "ecmascript/js_runtime_options.h"
28 #include "ecmascript/log.h"
29 #include "ecmascript/log_wrapper.h"
30 #include "ecmascript/napi/include/jsnapi.h"
31 #include "ecmascript/ohos/enable_aot_list_helper.h"
32 #include "ecmascript/ohos/ohos_pkg_args.h"
33 #include "ecmascript/platform/aot_crash_info.h"
34 #include "ecmascript/platform/file.h"
35 #include "ecmascript/platform/filesystem.h"
36 
37 #include "ecmascript/compiler/aot_compiler_stats.h"
38 
39 namespace panda::ecmascript::kungfu {
40 namespace {
41 /**
42  * @param ErrCode return code of ark_aot_compiler
43  * @attention it must sync with RetStatusOfCompiler of
44  *            "ets_runtime/compiler_service/include/aot_compiler_constants.h"
45  */
46 enum ErrCode {
47     ERR_OK = (0),   // IMPORTANT: Only if aot compiler SUCCESS and save an/ai SUCCESS, return ERR_OK.
48     ERR_FAIL = (-1),
49     ERR_HELP = (1),
50     ERR_NO_AP = (2),
51     ERR_MERGE_AP = (3),
52     ERR_CHECK_VERSION = (4),
53     ERR_AN_EMPTY = (5),
54     ERR_AN_FAIL = (6),
55     ERR_AI_FAIL = (7),
56 };
57 
CheckVersion(JSRuntimeOptions& runtimeOptions, AotCompilerStats& compilerStats, bool isPgoMerged)58 bool CheckVersion(JSRuntimeOptions& runtimeOptions, AotCompilerStats& compilerStats, bool isPgoMerged)
59 {
60     if (runtimeOptions.IsCheckPgoVersion()) {
61         if (!isPgoMerged) {
62             LOG_COMPILER(ERROR) << "CheckVersion ap and abc may not match";
63             compilerStats.SetPgoFileLegal(false);
64         }
65         if (runtimeOptions.IsTargetCompilerMode()) {
66             compilerStats.PrintCompilerStatsLog();
67         }
68         return true;
69     }
70     return false;
71 }
72 
IsExistsPkgInfo(AotCompilerPreprocessor &cPreprocessor)73 bool IsExistsPkgInfo(AotCompilerPreprocessor &cPreprocessor)
74 {
75     if (cPreprocessor.GetMainPkgArgs()) {
76         return true;
77     }
78     return false;
79 }
80 } // namespace
81 
Main(const int argc, const char **argv)82 int Main(const int argc, const char **argv)
83 {
84     if (argc < 2) { // 2: at least have two arguments
85         LOG_COMPILER(ERROR) << AotCompilerPreprocessor::GetHelper();
86         return ERR_FAIL;
87     }
88 
89     JSRuntimeOptions runtimeOptions;
90     bool retOpt = runtimeOptions.ParseCommand(argc, argv);
91     if (!retOpt) {
92         LOG_COMPILER(ERROR) << AotCompilerPreprocessor::GetHelper();
93         return ERR_HELP;
94     }
95 
96     bool ret = true;
97     // ark_aot_compiler running need disable asm interpreter to disable the loading of AOT files.
98     runtimeOptions.SetEnableAsmInterpreter(false);
99     runtimeOptions.SetOptionsForTargetCompilation();
100     EcmaVM *vm = JSNApi::CreateEcmaVM(runtimeOptions);
101     if (vm == nullptr) {
102         LOG_COMPILER(ERROR) << "Cannot Create vm";
103         return ERR_FAIL;
104     }
105 
106     {
107         AOTCompilationEnv aotCompilationEnv(vm);
108         ecmascript::ThreadManagedScope managedScope(vm->GetJSThread());
109         LocalScope scope(vm);
110         arg_list_t pandaFileNames {};
111         std::map<std::string, std::shared_ptr<OhosPkgArgs>> pkgArgsMap;
112         CompilationOptions cOptions(runtimeOptions);
113 
114         CompilerLog log(cOptions.logOption_);
115         log.SetEnableCompilerLogTime(cOptions.compilerLogTime_);
116         AotMethodLogList logList(cOptions.logMethodsList_);
117         PGOProfilerDecoder profilerDecoder;
118 
119         AotCompilerPreprocessor cPreprocessor(vm, runtimeOptions, pkgArgsMap, profilerDecoder, pandaFileNames);
120         if (!cPreprocessor.HandleTargetCompilerMode(cOptions) || !cPreprocessor.HandlePandaFileNames(argc, argv)) {
121             return ERR_HELP;
122         }
123 
124         if (IsExistsPkgInfo(cPreprocessor)) {
125             if (AotCrashInfo::IsAotEscaped(cPreprocessor.GetMainPkgArgs()->GetPgoDir())) {
126                 LOG_COMPILER(ERROR) << "Stop compile AOT because there are multiple crashes";
127                 return ERR_FAIL;
128             }
129         }
130         if (runtimeOptions.IsPartialCompilerMode() && cOptions.profilerIn_.empty()) {
131             // no need to compile in partial mode without any ap files.
132             return ERR_NO_AP;
133         }
134 
135         AotCompilerStats compilerStats;
136         std::string bundleName = "";
137         if (cPreprocessor.GetMainPkgArgs()) {
138             bundleName = cPreprocessor.GetMainPkgArgs()->GetBundleName();
139         }
140         compilerStats.SetBundleName(bundleName);
141         compilerStats.SetAotFilePath(cOptions.outputFileName_);
142         compilerStats.SetPgoPath(cOptions.profilerIn_);
143         compilerStats.StartCompiler();
144         profilerDecoder.SetHotnessThreshold(cOptions.hotnessThreshold_);
145         profilerDecoder.SetInPath(cOptions.profilerIn_);
146         cPreprocessor.AOTInitialize();
147         uint32_t checksum = cPreprocessor.GenerateAbcFileInfos();
148 
149         if (runtimeOptions.IsTargetCompilerMode() && (cPreprocessor.HasExistsAOTFiles(cOptions) ||
150             cPreprocessor.HasPreloadAotFile())) {
151             LOG_COMPILER(ERROR) << "The AOT file already exists and will not be compiled anymore";
152             return ERR_OK;
153         }
154 
155         ret = cPreprocessor.GetCompilerResult();
156         // Notice: lx move load pandaFileHead and verify before GeneralAbcFileInfos.
157         // need support multiple abc
158         auto isPgoMerged = cPreprocessor.HandleMergedPgoFile(checksum);
159         if (CheckVersion(runtimeOptions, compilerStats, isPgoMerged)) {
160             return ERR_CHECK_VERSION;
161         }
162         std::string appSignature = cPreprocessor.GetMainPkgArgsAppSignature();
163         if (!isPgoMerged) {
164             AOTFileGenerator::SaveEmptyAOTFile(
165                 cOptions.outputFileName_ + AOTFileManager::FILE_EXTENSION_AN, appSignature, true);
166             AOTFileGenerator::SaveEmptyAOTFile(
167                 cOptions.outputFileName_ + AOTFileManager::FILE_EXTENSION_AI, appSignature, false);
168             return ERR_MERGE_AP;
169         }
170         cPreprocessor.Process(cOptions);
171 
172         PassOptions::Builder optionsBuilder;
173         PassOptions passOptions =
174             optionsBuilder.EnableArrayBoundsCheckElimination(cOptions.isEnableArrayBoundsCheckElimination_)
175                 .EnableTypeLowering(cOptions.isEnableTypeLowering_)
176                 .EnableEarlyElimination(cOptions.isEnableEarlyElimination_)
177                 .EnableLaterElimination(cOptions.isEnableLaterElimination_)
178                 .EnableValueNumbering(cOptions.isEnableValueNumbering_)
179                 .EnableOptInlining(cOptions.isEnableOptInlining_)
180                 .EnableOptString(cOptions.isEnableOptString_)
181                 .EnableOptPGOType(cOptions.isEnableOptPGOType_)
182                 .EnableOptTrackField(cOptions.isEnableOptTrackField_)
183                 .EnableOptLoopPeeling(cOptions.isEnableOptLoopPeeling_)
184                 .EnableOptLoopInvariantCodeMotion(cOptions.isEnableOptLoopInvariantCodeMotion_)
185                 .EnableOptConstantFolding(cOptions.isEnableOptConstantFolding_)
186                 .EnableLexenvSpecialization(cOptions.isEnableLexenvSpecialization_)
187                 .EnableInlineNative(cOptions.isEnableNativeInline_)
188                 .EnableLoweringBuiltin(cOptions.isEnableLoweringBuiltin_)
189                 .EnableOptBranchProfiling(cOptions.isEnableOptBranchProfiling_)
190                 .EnableEscapeAnalysis(cOptions.isEnableEscapeAnalysis_)
191                 .EnableInductionVariableAnalysis(cOptions.isEnableInductionVariableAnalysis_)
192                 .EnableVerifierPass(cOptions.isEnableVerifierPass_)
193                 .Build();
194 
195         PassManager passManager(&aotCompilationEnv,
196                                 cOptions.triple_,
197                                 cOptions.optLevel_,
198                                 cOptions.relocMode_,
199                                 &log,
200                                 &logList,
201                                 cOptions.maxAotMethodSize_,
202                                 cOptions.maxMethodsInModule_,
203                                 profilerDecoder,
204                                 &passOptions,
205                                 cPreprocessor.GetCallMethodFlagMap(),
206                                 cPreprocessor.GetAbcFileInfo(),
207                                 cPreprocessor.GetBcInfoCollectors(),
208                                 cOptions.optBCRange_);
209 
210         bool isEnableLiteCG = runtimeOptions.IsCompilerEnableLiteCG();
211         if (ohos::EnableAotJitListHelper::GetInstance()->IsEnableAot(bundleName)) {
212             isEnableLiteCG = true;
213         }
214         vm->GetJSOptions().SetCompilerEnableLiteCG(isEnableLiteCG);
215         compilerStats.SetIsLiteCg(isEnableLiteCG);
216 
217         AOTFileGenerator generator(&log, &logList, &aotCompilationEnv, cOptions.triple_, isEnableLiteCG);
218 
219         passManager.CompileValidFiles(generator, ret, compilerStats);
220         if (compilerStats.GetCompilerMethodCount() == 0) {
221             return runtimeOptions.IsPartialCompilerMode() ? ERR_AN_EMPTY : ERR_OK;
222         }
223         if (!generator.SaveAOTFile(cOptions.outputFileName_ + AOTFileManager::FILE_EXTENSION_AN, appSignature)) {
224             return ERR_AN_FAIL;
225         }
226         if (!generator.SaveSnapshotFile()) {
227             return ERR_AI_FAIL;
228         }
229         log.Print();
230         if (runtimeOptions.IsTargetCompilerMode()) {
231             compilerStats.PrintCompilerStatsLog();
232         }
233         if (IsExistsPkgInfo(cPreprocessor)) {
234             ohos::EnableAotJitListHelper::GetInstance()->AddEnableListCount(
235                 ret, cPreprocessor.GetMainPkgArgs()->GetPgoDir());
236         }
237     }
238 
239     if (vm->GetJSOptions().IsEnableCompilerLogSnapshot()) {
240         vm->PrintAOTSnapShotStats();
241     }
242     LOG_COMPILER(INFO) << (ret ? "ts aot compile success" : "ts aot compile failed");
243     JSNApi::DestroyJSVM(vm);
244     return ret ? ERR_OK : ERR_FAIL;
245 }
246 } // namespace panda::ecmascript::kungfu
247 
main(const int argc, const char **argv)248 int main(const int argc, const char **argv)
249 {
250     auto result = panda::ecmascript::kungfu::Main(argc, argv);
251     return result;
252 }
253