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
39namespace panda::ecmascript::kungfu {
40namespace {
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 */
46enum 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
58bool 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
73bool IsExistsPkgInfo(AotCompilerPreprocessor &cPreprocessor)
74{
75    if (cPreprocessor.GetMainPkgArgs()) {
76        return true;
77    }
78    return false;
79}
80} // namespace
81
82int 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
248int main(const int argc, const char **argv)
249{
250    auto result = panda::ecmascript::kungfu::Main(argc, argv);
251    return result;
252}
253