1 /**
2 * Copyright (c) 2021-2024 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 auto bootPandaFiles = runtimeOptions.GetBootPandaFiles();
101
102 if (runtimeOptions.GetPandaFiles().empty()) {
103 bootPandaFiles.push_back(file.GetValue());
104 } else {
105 auto pandaFiles = runtimeOptions.GetPandaFiles();
106 auto foundIter = std::find_if(pandaFiles.begin(), pandaFiles.end(),
107 [&](auto &fileName) { return fileName == file.GetValue(); });
108 if (foundIter == pandaFiles.end()) {
109 pandaFiles.push_back(file.GetValue());
110 runtimeOptions.SetPandaFiles(pandaFiles);
111 }
112 }
113
114 runtimeOptions.SetBootPandaFiles(bootPandaFiles);
115 }
116
SetVerificationMode(RuntimeOptions & runtimeOptions)117 static void SetVerificationMode(RuntimeOptions &runtimeOptions)
118 {
119 runtimeOptions.SetVerificationMode(VerificationModeFromString(
120 static_cast<Options>(runtimeOptions).GetVerificationMode())); // NOLINT(cppcoreguidelines-slicing)
121 if (runtimeOptions.IsVerificationEnabled()) {
122 if (!runtimeOptions.WasSetVerificationMode()) {
123 runtimeOptions.SetVerificationMode(VerificationMode::AHEAD_OF_TIME);
124 }
125 }
126 }
127
GetPandArgParser(ark::PandArg<bool> & help,ark::PandArg<bool> & options,ark::PandArg<std::string> & file,ark::PandArg<std::string> & entrypoint)128 static ark::PandArgParser GetPandArgParser(ark::PandArg<bool> &help, ark::PandArg<bool> &options,
129 ark::PandArg<std::string> &file, ark::PandArg<std::string> &entrypoint)
130 {
131 ark::PandArgParser paParser;
132
133 paParser.Add(&help);
134 paParser.Add(&options);
135 paParser.PushBackTail(&file);
136 paParser.PushBackTail(&entrypoint);
137 paParser.EnableTail();
138 paParser.EnableRemainder();
139
140 return paParser;
141 }
142
ExecutePandaFile(Runtime & runtime,const std::string & fileName,const std::string & entry,const arg_list_t & arguments)143 static int ExecutePandaFile(Runtime &runtime, const std::string &fileName, const std::string &entry,
144 const arg_list_t &arguments)
145 {
146 auto res = runtime.ExecutePandaFile(fileName, entry, arguments);
147 if (!res) {
148 std::cerr << "Cannot execute panda file '" << fileName << "' with entry '" << entry << "'" << std::endl;
149 return -1;
150 }
151
152 return res.Value();
153 }
154
PrintStatistics(RuntimeOptions & runtimeOptions,Runtime & runtime)155 static void PrintStatistics(RuntimeOptions &runtimeOptions, Runtime &runtime)
156 {
157 if (runtimeOptions.IsPrintMemoryStatistics()) {
158 std::cout << runtime.GetMemoryStatistics();
159 }
160 if (runtimeOptions.IsPrintGcStatistics()) {
161 std::cout << runtime.GetFinalStatistics();
162 }
163 }
164
Main(int argc,const char ** argv)165 int Main(int argc, const char **argv)
166 {
167 Span<const char *> sp(argv, argc);
168 RuntimeOptions runtimeOptions(sp[0]);
169 base_options::Options baseOptions(sp[0]);
170
171 ark::PandArg<bool> help("help", false, "Print this message and exit");
172 ark::PandArg<bool> options("options", false, "Print compiler and runtime options");
173 // tail arguments
174 ark::PandArg<std::string> file("file", "", "path to pandafile");
175 ark::PandArg<std::string> entrypoint("entrypoint", "", "full name of entrypoint function or method");
176
177 ark::PandArgParser paParser = GetPandArgParser(help, options, file, entrypoint);
178
179 runtimeOptions.AddOptions(&paParser);
180 baseOptions.AddOptions(&paParser);
181 compiler::g_options.AddOptions(&paParser);
182
183 auto startTime =
184 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
185 .count();
186
187 if (!paParser.Parse(argc, argv)) {
188 PrintHelp(paParser);
189 return 1;
190 }
191
192 if (runtimeOptions.IsStartupTime()) {
193 // clang-format off
194 std::cout << "\n" << "Startup start time: " << startTime << std::endl;
195 // clang-format on
196 }
197
198 if (!ark::PrepareArguments(&paParser, runtimeOptions, file, entrypoint, help)) {
199 return 1;
200 }
201
202 compiler::g_options.AdjustCpuFeatures(false);
203
204 Logger::Initialize(baseOptions);
205
206 SetVerificationMode(runtimeOptions);
207
208 ark::compiler::CompilerLogger::SetComponents(ark::compiler::g_options.GetCompilerLog());
209 if (compiler::g_options.IsCompilerEnableEvents()) {
210 ark::compiler::EventWriter::Init(ark::compiler::g_options.GetCompilerEventsPath());
211 }
212
213 SetPandaFiles(runtimeOptions, file);
214
215 if (!Runtime::Create(runtimeOptions)) {
216 std::cerr << "Error: cannot create runtime" << std::endl;
217 return -1;
218 }
219
220 if (options.GetValue()) {
221 std::cout << paParser.GetRegularArgs() << std::endl;
222 }
223
224 auto &runtime = *Runtime::GetCurrent();
225
226 int ret = ExecutePandaFile(runtime, file.GetValue(), entrypoint.GetValue(), paParser.GetRemainder());
227 PrintStatistics(runtimeOptions, runtime);
228
229 if (!Runtime::Destroy()) {
230 std::cerr << "Error: cannot destroy runtime" << std::endl;
231 return -1;
232 }
233 paParser.DisableTail();
234 return ret;
235 }
236 } // namespace ark
237
main(int argc,const char ** argv)238 int main(int argc, const char **argv)
239 {
240 return ark::Main(argc, argv);
241 }
242