• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "include/runtime.h"
17 #include "include/thread.h"
18 #include "include/thread_scopes.h"
19 #include "runtime/include/locks.h"
20 #include "runtime/include/method-inl.h"
21 #include "runtime/include/class.h"
22 #include "utils/pandargs.h"
23 #include "compiler/compiler_options.h"
24 #include "compiler/compiler_logger.h"
25 #include "compiler_events_gen.h"
26 #include "mem/mem_stats.h"
27 #include "libpandabase/os/mutex.h"
28 #include "libpandabase/os/native_stack.h"
29 #include "generated/base_options.h"
30 
31 #include "ark_version.h"
32 
33 #include "utils/span.h"
34 
35 #include "utils/logger.h"
36 
37 #include <limits>
38 #include <iostream>
39 #include <vector>
40 #include <chrono>
41 #include <ctime>
42 #include <csignal>
43 
44 namespace ark {
GetPandaFile(const ClassLinker & classLinker,std::string_view fileName)45 const panda_file::File *GetPandaFile(const ClassLinker &classLinker, std::string_view fileName)
46 {
47     const panda_file::File *res = nullptr;
48     classLinker.EnumerateBootPandaFiles([&res, fileName](const panda_file::File &pf) {
49         if (pf.GetFilename() == fileName) {
50             res = &pf;
51             return false;
52         }
53         return true;
54     });
55     return res;
56 }
57 
PrintHelp(const ark::PandArgParser & paParser)58 static void PrintHelp(const ark::PandArgParser &paParser)
59 {
60     std::cerr << paParser.GetErrorString() << std::endl;
61     std::cerr << "Usage: "
62               << "panda"
63               << " [OPTIONS] [file] [entrypoint] -- [arguments]" << std::endl;
64     std::cerr << std::endl;
65     std::cerr << "optional arguments:" << std::endl;
66     std::cerr << paParser.GetHelpString() << std::endl;
67 }
68 
PrepareArguments(ark::PandArgParser * paParser,const RuntimeOptions & runtimeOptions,const ark::PandArg<std::string> & file,const ark::PandArg<std::string> & entrypoint,const ark::PandArg<bool> & help)69 static bool PrepareArguments(ark::PandArgParser *paParser, const RuntimeOptions &runtimeOptions,
70                              const ark::PandArg<std::string> &file, const ark::PandArg<std::string> &entrypoint,
71                              const ark::PandArg<bool> &help)
72 {
73     if (runtimeOptions.IsVersion()) {
74         PrintPandaVersion();
75         return false;
76     }
77 
78     if (file.GetValue().empty() || entrypoint.GetValue().empty() || help.GetValue()) {
79         PrintHelp(*paParser);
80         return false;
81     }
82 
83     auto runtimeOptionsErr = runtimeOptions.Validate();
84     if (runtimeOptionsErr) {
85         std::cerr << "Error: " << runtimeOptionsErr.value().GetMessage() << std::endl;
86         return false;
87     }
88 
89     auto compilerOptionsErr = compiler::g_options.Validate();
90     if (compilerOptionsErr) {
91         std::cerr << "Error: " << compilerOptionsErr.value().GetMessage() << std::endl;
92         return false;
93     }
94 
95     return true;
96 }
97 
SetPandaFiles(RuntimeOptions & runtimeOptions,ark::PandArg<std::string> & file)98 static void SetPandaFiles(RuntimeOptions &runtimeOptions, ark::PandArg<std::string> &file)
99 {
100     const std::string &fileName = file.GetValue();
101     auto bootPandaFiles = runtimeOptions.GetBootPandaFiles();
102     auto pandaFiles = runtimeOptions.GetPandaFiles();
103     auto bootFoundIter = std::find(bootPandaFiles.begin(), bootPandaFiles.end(), fileName);
104     if (runtimeOptions.IsLoadInBoot() && bootFoundIter == bootPandaFiles.end()) {
105         bootPandaFiles.push_back(fileName);
106         runtimeOptions.SetBootPandaFiles(bootPandaFiles);
107         return;
108     }
109 
110     if (pandaFiles.empty() && bootFoundIter == bootPandaFiles.end()) {
111         pandaFiles.push_back(fileName);
112         runtimeOptions.SetPandaFiles(pandaFiles);
113         return;
114     }
115 
116     auto pandaFoundIter = std::find(pandaFiles.begin(), pandaFiles.end(), fileName);
117     if (pandaFoundIter == pandaFiles.end()) {
118         pandaFiles.push_back(fileName);
119         runtimeOptions.SetPandaFiles(pandaFiles);
120     }
121 }
122 
GetPandArgParser(ark::PandArg<bool> & help,ark::PandArg<bool> & options,ark::PandArg<std::string> & file,ark::PandArg<std::string> & entrypoint)123 static ark::PandArgParser GetPandArgParser(ark::PandArg<bool> &help, ark::PandArg<bool> &options,
124                                            ark::PandArg<std::string> &file, ark::PandArg<std::string> &entrypoint)
125 {
126     ark::PandArgParser paParser;
127 
128     paParser.Add(&help);
129     paParser.Add(&options);
130     paParser.PushBackTail(&file);
131     paParser.PushBackTail(&entrypoint);
132     paParser.EnableTail();
133     paParser.EnableRemainder();
134 
135     return paParser;
136 }
137 
ExecutePandaFile(Runtime & runtime,const std::string & fileName,const std::string & entry,const arg_list_t & arguments)138 static int ExecutePandaFile(Runtime &runtime, const std::string &fileName, const std::string &entry,
139                             const arg_list_t &arguments)
140 {
141     auto res = runtime.ExecutePandaFile(fileName, entry, arguments);
142     if (!res) {
143         std::cerr << "Cannot execute panda file '" << fileName << "' with entry '" << entry << "'" << std::endl;
144         return -1;
145     }
146 
147     return res.Value();
148 }
149 
PrintStatistics(RuntimeOptions & runtimeOptions,Runtime & runtime)150 static void PrintStatistics(RuntimeOptions &runtimeOptions, Runtime &runtime)
151 {
152     if (runtimeOptions.IsPrintMemoryStatistics()) {
153         std::cout << runtime.GetMemoryStatistics();
154     }
155     if (runtimeOptions.IsPrintGcStatistics()) {
156         std::cout << runtime.GetFinalStatistics();
157     }
158 }
159 
Main(int argc,const char ** argv)160 int Main(int argc, const char **argv)
161 {
162     Span<const char *> sp(argv, argc);
163     RuntimeOptions runtimeOptions(sp[0]);
164     base_options::Options baseOptions(sp[0]);
165 
166     ark::PandArg<bool> help("help", false, "Print this message and exit");
167     ark::PandArg<bool> options("options", false, "Print compiler and runtime options");
168     // tail arguments
169     ark::PandArg<std::string> file("file", "", "path to pandafile");
170     ark::PandArg<std::string> entrypoint("entrypoint", "", "full name of entrypoint function or method");
171 
172     ark::PandArgParser paParser = GetPandArgParser(help, options, file, entrypoint);
173 
174     runtimeOptions.AddOptions(&paParser);
175     baseOptions.AddOptions(&paParser);
176     compiler::g_options.AddOptions(&paParser);
177 
178     auto startTime =
179         std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
180             .count();
181 
182     if (!paParser.Parse(argc, argv)) {
183         PrintHelp(paParser);
184         return 1;
185     }
186 
187     if (runtimeOptions.IsStartupTime()) {
188         // clang-format off
189         std::cout << "\n" << "Startup start time: " << startTime << std::endl;
190         // clang-format on
191     }
192 
193     if (!ark::PrepareArguments(&paParser, runtimeOptions, file, entrypoint, help)) {
194         return 1;
195     }
196 
197     compiler::g_options.AdjustCpuFeatures(false);
198 
199     Logger::Initialize(baseOptions);
200 
201     ark::compiler::CompilerLogger::SetComponents(ark::compiler::g_options.GetCompilerLog());
202     if (compiler::g_options.IsCompilerEnableEvents()) {
203         ark::compiler::EventWriter::Init(ark::compiler::g_options.GetCompilerEventsPath());
204     }
205 
206     SetPandaFiles(runtimeOptions, file);
207 
208     if (!Runtime::Create(runtimeOptions)) {
209         std::cerr << "Error: cannot create runtime" << std::endl;
210         return -1;
211     }
212 
213     if (options.GetValue()) {
214         std::cout << paParser.GetRegularArgs() << std::endl;
215     }
216 
217     auto &runtime = *Runtime::GetCurrent();
218 
219     int ret = ExecutePandaFile(runtime, file.GetValue(), entrypoint.GetValue(), paParser.GetRemainder());
220     PrintStatistics(runtimeOptions, runtime);
221 
222     if (!Runtime::Destroy()) {
223         std::cerr << "Error: cannot destroy runtime" << std::endl;
224         return -1;
225     }
226     paParser.DisableTail();
227     return ret;
228 }
229 }  // namespace ark
230 
main(int argc,const char ** argv)231 int main(int argc, const char **argv)
232 {
233     return ark::Main(argc, argv);
234 }
235