• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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/aot_compiler_preprocessor.h"
16 #include "ecmascript/compiler/pgo_type/pgo_type_parser.h"
17 #include "ecmascript/jspandafile/program_object.h"
18 #include "ecmascript/module/js_module_manager.h"
19 #include "ecmascript/ohos/ohos_pgo_processor.h"
20 #include "ecmascript/ohos/ohos_pkg_args.h"
21 
22 namespace panda::ecmascript::kungfu {
23 namespace {
24 constexpr int32_t DEFAULT_OPT_LEVEL = 3;  // 3: default opt level
25 }  // namespace
26 using PGOProfilerManager = pgo::PGOProfilerManager;
27 
CompilationOptions(EcmaVM * vm,JSRuntimeOptions & runtimeOptions)28 CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions)
29 {
30     triple_ = runtimeOptions.GetTargetTriple();
31     if (runtimeOptions.GetAOTOutputFile().empty()) {
32         runtimeOptions.SetAOTOutputFile("aot_file");
33     }
34     outputFileName_ = runtimeOptions.GetAOTOutputFile();
35     optLevel_ = runtimeOptions.GetOptLevel();
36     relocMode_ = runtimeOptions.GetRelocMode();
37     logOption_ = runtimeOptions.GetCompilerLogOption();
38     logMethodsList_ = runtimeOptions.GetMethodsListForLog();
39     compilerLogTime_ = runtimeOptions.IsEnableCompilerLogTime();
40     maxAotMethodSize_ = runtimeOptions.GetMaxAotMethodSize();
41     maxMethodsInModule_ = runtimeOptions.GetCompilerModuleMethods();
42     hotnessThreshold_ = runtimeOptions.GetPGOHotnessThreshold();
43     profilerIn_ = std::string(runtimeOptions.GetPGOProfilerPath());
44     needMerge_ = false;
45     isEnableArrayBoundsCheckElimination_ = runtimeOptions.IsEnableArrayBoundsCheckElimination();
46     isEnableTypeLowering_ = runtimeOptions.IsEnableTypeLowering();
47     isEnableEarlyElimination_ = runtimeOptions.IsEnableEarlyElimination();
48     isEnableLaterElimination_ = runtimeOptions.IsEnableLaterElimination();
49     isEnableValueNumbering_ = runtimeOptions.IsEnableValueNumbering();
50     isEnableOptInlining_ = runtimeOptions.IsEnableOptInlining();
51     isEnableOptString_ = runtimeOptions.IsEnableOptString();
52     isEnableTypeInfer_ = isEnableTypeLowering_ ||
53         vm->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->AssertTypes();
54     isEnableOptPGOType_ = runtimeOptions.IsEnableOptPGOType();
55     isEnableOptTrackField_ = runtimeOptions.IsEnableOptTrackField();
56     isEnableOptLoopPeeling_ = runtimeOptions.IsEnableOptLoopPeeling();
57     isEnableOptLoopInvariantCodeMotion_ = runtimeOptions.IsEnableOptLoopInvariantCodeMotion();
58     isEnableOptConstantFolding_ = runtimeOptions.IsEnableOptConstantFolding();
59     isEnableCollectLiteralInfo_ = false;
60     isEnableLexenvSpecialization_ = runtimeOptions.IsEnableLexenvSpecialization();
61     isEnableNativeInline_ = runtimeOptions.IsEnableNativeInline();
62     isEnableLoweringBuiltin_ = runtimeOptions.IsEnableLoweringBuiltin();
63     isEnableOptBranchProfiling_ = runtimeOptions.IsEnableBranchProfiling();
64 }
65 
HandleTargetCompilerMode(CompilationOptions & cOptions)66 bool AotCompilerPreprocessor::HandleTargetCompilerMode(CompilationOptions &cOptions)
67 {
68     if (runtimeOptions_.IsTargetCompilerMode()) {
69         if (!OhosPkgArgs::ParseArgs(*this, cOptions)) {
70             LOG_COMPILER(ERROR) << GetHelper();
71             LOG_COMPILER(ERROR) << "Parse pkg info failed, exit.";
72             return false;
73         }
74         const auto& mainPkgArgs = GetMainPkgArgs();
75         if (!mainPkgArgs) {
76             LOG_COMPILER(ERROR) << "No main pkg args found, exit";
77             return false;
78         }
79         if (!OhosPgoProcessor::MergeAndRemoveRuntimeAp(cOptions, mainPkgArgs)) {
80             LOG_COMPILER(ERROR) << "Fusion runtime ap failed, exit";
81             return false;
82         }
83         HandleTargetModeInfo(cOptions);
84     }
85     return true;
86 }
87 
HandleTargetModeInfo(CompilationOptions & cOptions)88 void AotCompilerPreprocessor::HandleTargetModeInfo(CompilationOptions &cOptions)
89 {
90     JSRuntimeOptions &vmOpt = vm_->GetJSOptions();
91     ASSERT(vmOpt.IsTargetCompilerMode());
92     // target need fast compiler mode
93     vmOpt.SetFastAOTCompileMode(true);
94     vmOpt.SetOptLevel(DEFAULT_OPT_LEVEL);
95     cOptions.optLevel_ = DEFAULT_OPT_LEVEL;
96 }
97 
HandlePandaFileNames(const int argc,const char ** argv)98 bool AotCompilerPreprocessor::HandlePandaFileNames(const int argc, const char **argv)
99 {
100     if (runtimeOptions_.GetCompilerPkgJsonInfo().empty() || pkgsArgs_.empty()) {
101         // if no pkgArgs, last param must be abc file
102         std::string files = argv[argc - 1];
103         if (!base::StringHelper::EndsWith(files, ".abc")) {
104             LOG_COMPILER(ERROR) << "The last argument must be abc file" << std::endl;
105             LOG_COMPILER(ERROR) << GetHelper();
106             return false;
107         }
108         std::string delimiter = GetFileDelimiter();
109         pandaFileNames_ = base::StringHelper::SplitString(files, delimiter);
110     }
111     return true;
112 }
113 
AOTInitialize()114 void AotCompilerPreprocessor::AOTInitialize()
115 {
116     BytecodeStubCSigns::Initialize();
117     CommonStubCSigns::Initialize();
118     RuntimeStubCSigns::Initialize();
119     vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->Initialize();
120 }
121 
SetShouldCollectLiteralInfo(CompilationOptions & cOptions,const CompilerLog * log)122 void AotCompilerPreprocessor::SetShouldCollectLiteralInfo(CompilationOptions &cOptions, const CompilerLog *log)
123 {
124     TSManager *tsManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager();
125     cOptions.isEnableCollectLiteralInfo_ = cOptions.isEnableTypeInfer_ &&
126         (profilerDecoder_.IsLoaded() || tsManager->AssertTypes() || log->OutputType());
127 }
128 
GenerateAbcFileInfos()129 bool AotCompilerPreprocessor::GenerateAbcFileInfos()
130 {
131     size_t size = pandaFileNames_.size();
132     uint32_t checksum = 0;
133     for (size_t i = 0; i < size; ++i) {
134         const auto &fileName = pandaFileNames_.at(i);
135         auto extendedFilePath = panda::os::file::File::GetExtendedFilePath(fileName);
136         std::shared_ptr<JSPandaFile> jsPandaFile = CreateAndVerifyJSPandaFile(extendedFilePath);
137         AbcFileInfo fileInfo(extendedFilePath, jsPandaFile);
138         if (jsPandaFile == nullptr) {
139             LOG_COMPILER(ERROR) << "Cannot execute panda file '" << extendedFilePath << "'";
140             continue;
141         }
142         checksum = jsPandaFile->GetChecksum();
143         ResolveModule(jsPandaFile.get(), extendedFilePath);
144         fileInfos_.emplace_back(fileInfo);
145     }
146 
147     return PGOProfilerManager::MergeApFiles(checksum, profilerDecoder_);
148 }
149 
CreateAndVerifyJSPandaFile(const std::string & fileName)150 std::shared_ptr<JSPandaFile> AotCompilerPreprocessor::CreateAndVerifyJSPandaFile(const std::string &fileName)
151 {
152     JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance();
153     std::shared_ptr<JSPandaFile> jsPandaFile = nullptr;
154     if (runtimeOptions_.IsTargetCompilerMode()) {
155         auto pkgArgsIter = pkgsArgs_.find(fileName);
156         if (pkgArgsIter == pkgsArgs_.end()) {
157             LOG_COMPILER(ERROR) << "Can not find file in ohos pkgs args. file name: " << fileName;
158             return nullptr;
159         }
160         if (!(pkgArgsIter->second->GetJSPandaFile(runtimeOptions_, jsPandaFile))) {
161             return nullptr;
162         }
163     } else {
164         jsPandaFile = jsPandaFileManager->OpenJSPandaFile(fileName.c_str());
165     }
166     if (jsPandaFile == nullptr) {
167         LOG_ECMA(ERROR) << "open file " << fileName << " error";
168         return nullptr;
169     }
170 
171     if (!jsPandaFile->IsNewVersion()) {
172         LOG_COMPILER(ERROR) << "AOT only support panda file with new ISA, while the '" <<
173             fileName << "' file is the old version";
174         return nullptr;
175     }
176 
177     jsPandaFileManager->AddJSPandaFileVm(vm_, jsPandaFile);
178     return jsPandaFile;
179 }
180 
ResolveModule(const JSPandaFile * jsPandaFile,const std::string & fileName)181 void AotCompilerPreprocessor::ResolveModule(const JSPandaFile *jsPandaFile, const std::string &fileName)
182 {
183     const auto &recordInfo = jsPandaFile->GetJSRecordInfo();
184     JSThread *thread = vm_->GetJSThread();
185     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
186     [[maybe_unused]] EcmaHandleScope scope(thread);
187     for (auto info: recordInfo) {
188         if (jsPandaFile->IsModule(info.second)) {
189             auto recordName = info.first;
190             JSHandle<JSTaggedValue> moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(fileName.c_str(),
191                 recordName);
192             RETURN_IF_ABRUPT_COMPLETION(thread);
193             SourceTextModule::Instantiate(thread, moduleRecord);
194         }
195     }
196 }
197 
GenerateGlobalTypes(const CompilationOptions & cOptions)198 void AotCompilerPreprocessor::GenerateGlobalTypes(const CompilationOptions &cOptions)
199 {
200     for (const AbcFileInfo &fileInfo : fileInfos_) {
201         JSPandaFile *jsPandaFile = fileInfo.jsPandaFile_.get();
202         TSManager *tsManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager();
203         PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager();
204         BytecodeInfoCollector collector(vm_, jsPandaFile, profilerDecoder_, cOptions.maxAotMethodSize_,
205                                         cOptions.isEnableCollectLiteralInfo_);
206         BCInfo &bytecodeInfo = collector.GetBytecodeInfo();
207         const PGOBCInfo *bcInfo = collector.GetPGOBCInfo();
208         const auto &methodPcInfos = bytecodeInfo.GetMethodPcInfos();
209         auto &methodList = bytecodeInfo.GetMethodList();
210         for (const auto &method : methodList) {
211             uint32_t methodOffset = method.first;
212             tsManager->SetCurConstantPool(jsPandaFile, methodOffset);
213             CString recordName = MethodLiteral::GetRecordName(jsPandaFile, EntityId(methodOffset));
214             auto methodLiteral = jsPandaFile->FindMethodLiteral(methodOffset);
215             auto &methodInfo = methodList.at(methodOffset);
216             auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()];
217             TypeRecorder typeRecorder(jsPandaFile, methodLiteral, tsManager, recordName, &profilerDecoder_,
218                                       methodPcInfo, collector.GetByteCodes(), cOptions.isEnableOptTrackField_);
219             typeRecorder.BindPgoTypeToGateType(jsPandaFile, tsManager, methodLiteral);
220 
221             bcInfo->IterateInfoByType(methodOffset, PGOBCInfo::Type::ARRAY_LITERAL,
222                                       [this, tsManager, ptManager,
223                                        &recordName]([[maybe_unused]] const uint32_t bcIdx,
224                                                     [[maybe_unused]] const uint32_t bcOffset, const uint32_t cpIdx) {
225                                             JSHandle<ConstantPool> constpoolHandle(tsManager->GetConstantPool());
226                                             JSThread *thread = vm_->GetJSThread();
227                                             JSTaggedValue arr =
228                                                 ConstantPool::GetLiteralFromCache<ConstPoolType::ARRAY_LITERAL>(
229                                                     thread, constpoolHandle.GetTaggedValue(), cpIdx, recordName);
230                                             JSHandle<JSArray> arrayHandle(thread, arr);
231                                             panda_file::File::EntityId id =
232                                                 ConstantPool::GetIdFromCache(constpoolHandle.GetTaggedValue(), cpIdx);
233                                             ptManager->RecordElements(id, arrayHandle->GetElements());
234                                         });
235         }
236     }
237 }
238 
GeneratePGOTypes(const CompilationOptions & cOptions)239 void AotCompilerPreprocessor::GeneratePGOTypes(const CompilationOptions &cOptions)
240 {
241     PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager();
242     for (const AbcFileInfo &fileInfo : fileInfos_) {
243         JSPandaFile *jsPandaFile = fileInfo.jsPandaFile_.get();
244         BytecodeInfoCollector collector(vm_, jsPandaFile, profilerDecoder_, cOptions.maxAotMethodSize_,
245                                         cOptions.isEnableCollectLiteralInfo_);
246         PGOTypeParser parser(profilerDecoder_, ptManager);
247         parser.CreatePGOType(collector);
248     }
249 }
250 
SnapshotInitialize()251 void AotCompilerPreprocessor::SnapshotInitialize()
252 {
253     PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager();
254     ptManager->InitAOTSnapshot(fileInfos_.size());
255 }
256 
GetMainPkgArgsAppSignature() const257 std::string AotCompilerPreprocessor::GetMainPkgArgsAppSignature() const
258 {
259     return GetMainPkgArgs() == nullptr ? "" : GetMainPkgArgs()->GetAppSignature();
260 }
261 } // namespace panda::ecmascript::kungfu