1 /**
2 * Copyright (c) 2021-2022 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 "verification/jobs/thread_pool.h"
34 #include "verification/jobs/cache.h"
35
36 #include "utils/span.h"
37
38 #include "utils/logger.h"
39
40 #include <limits>
41 #include <iostream>
42 #include <vector>
43 #include <chrono>
44 #include <ctime>
45 #include <csignal>
46
47 namespace panda {
GetPandaFile(const ClassLinker & class_linker,std::string_view file_name)48 const panda_file::File *GetPandaFile(const ClassLinker &class_linker, std::string_view file_name)
49 {
50 const panda_file::File *res = nullptr;
51 class_linker.EnumerateBootPandaFiles([&res, file_name](const panda_file::File &pf) {
52 if (pf.GetFilename() == file_name) {
53 res = &pf;
54 return false;
55 }
56 return true;
57 });
58 return res;
59 }
60
BlockSignals()61 void BlockSignals()
62 {
63 #if defined(PANDA_TARGET_UNIX)
64 sigset_t set;
65 if (sigemptyset(&set) == -1) {
66 LOG(ERROR, RUNTIME) << "sigemptyset failed";
67 return;
68 }
69 int rc = 0;
70 #ifdef PANDA_TARGET_MOBILE
71 rc += sigaddset(&set, SIGPIPE);
72 rc += sigaddset(&set, SIGQUIT);
73 rc += sigaddset(&set, SIGUSR1);
74 rc += sigaddset(&set, SIGUSR2);
75 #endif // PANDA_TARGET_MOBILE
76 if (rc < 0) {
77 LOG(ERROR, RUNTIME) << "sigaddset failed";
78 return;
79 }
80
81 if (os::native_stack::g_PandaThreadSigmask(SIG_BLOCK, &set, nullptr) != 0) {
82 LOG(ERROR, RUNTIME) << "g_PandaThreadSigmask failed";
83 }
84 #endif // PANDA_TARGET_UNIX
85 }
86
PrintHelp(const panda::PandArgParser & pa_parser)87 void PrintHelp(const panda::PandArgParser &pa_parser)
88 {
89 std::cerr << pa_parser.GetErrorString() << std::endl;
90 std::cerr << "Usage: "
91 << "panda"
92 << " [OPTIONS] [file] [entrypoint] -- [arguments]" << std::endl;
93 std::cerr << std::endl;
94 std::cerr << "optional arguments:" << std::endl;
95 std::cerr << pa_parser.GetHelpString() << std::endl;
96 }
97
PrepareArguments(panda::PandArgParser * pa_parser,const RuntimeOptions & runtime_options,const panda::PandArg<std::string> & file,const panda::PandArg<std::string> & entrypoint,const panda::PandArg<bool> & help,int argc,const char ** argv)98 bool PrepareArguments(panda::PandArgParser *pa_parser, const RuntimeOptions &runtime_options,
99 const panda::PandArg<std::string> &file, const panda::PandArg<std::string> &entrypoint,
100 const panda::PandArg<bool> &help, int argc, const char **argv)
101 {
102 auto start_time =
103 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
104 .count();
105
106 if (!pa_parser->Parse(argc, argv)) {
107 PrintHelp(*pa_parser);
108 return false;
109 }
110
111 if (runtime_options.IsVersion()) {
112 PrintPandaVersion();
113 return false;
114 }
115
116 if (file.GetValue().empty() || entrypoint.GetValue().empty() || help.GetValue()) {
117 PrintHelp(*pa_parser);
118 return false;
119 }
120
121 if (runtime_options.IsStartupTime()) {
122 std::cout << "\n"
123 << "Startup start time: " << start_time << std::endl;
124 }
125
126 auto runtime_options_err = runtime_options.Validate();
127 if (runtime_options_err) {
128 std::cerr << "Error: " << runtime_options_err.value().GetMessage() << std::endl;
129 return false;
130 }
131
132 auto compiler_options_err = compiler::options.Validate();
133 if (compiler_options_err) {
134 std::cerr << "Error: " << compiler_options_err.value().GetMessage() << std::endl;
135 return false;
136 }
137
138 return true;
139 }
140
Main(int argc,const char ** argv)141 int Main(int argc, const char **argv)
142 {
143 BlockSignals();
144 Span<const char *> sp(argv, argc);
145 RuntimeOptions runtime_options(sp[0]);
146 base_options::Options base_options(sp[0]);
147 panda::PandArgParser pa_parser;
148
149 panda::PandArg<bool> help("help", false, "Print this message and exit");
150 panda::PandArg<bool> options("options", false, "Print compiler and runtime options");
151 // tail arguments
152 panda::PandArg<std::string> file("file", "", "path to pandafile");
153 panda::PandArg<std::string> entrypoint("entrypoint", "", "full name of entrypoint function or method");
154
155 runtime_options.AddOptions(&pa_parser);
156 base_options.AddOptions(&pa_parser);
157 compiler::options.AddOptions(&pa_parser);
158
159 pa_parser.Add(&help);
160 pa_parser.Add(&options);
161 pa_parser.PushBackTail(&file);
162 pa_parser.PushBackTail(&entrypoint);
163 pa_parser.EnableTail();
164 pa_parser.EnableRemainder();
165
166 if (!panda::PrepareArguments(&pa_parser, runtime_options, file, entrypoint, help, argc, argv)) {
167 return 1;
168 }
169
170 compiler::options.AdjustCpuFeatures(false);
171
172 Logger::Initialize(base_options);
173
174 runtime_options.SetVerificationMode(runtime_options.IsVerificationEnabled() ? VerificationMode::ON_THE_FLY
175 : VerificationMode::DISABLED);
176
177 arg_list_t arguments = pa_parser.GetRemainder();
178
179 panda::compiler::CompilerLogger::SetComponents(panda::compiler::options.GetCompilerLog());
180 if (compiler::options.IsCompilerEnableEvents()) {
181 panda::compiler::EventWriter::Init(panda::compiler::options.GetCompilerEventsPath());
182 }
183
184 auto boot_panda_files = runtime_options.GetBootPandaFiles();
185
186 if (runtime_options.GetPandaFiles().empty()) {
187 boot_panda_files.push_back(file.GetValue());
188 } else {
189 auto panda_files = runtime_options.GetPandaFiles();
190 auto found_iter = std::find_if(panda_files.begin(), panda_files.end(),
191 [&](auto &file_name) { return file_name == file.GetValue(); });
192 if (found_iter == panda_files.end()) {
193 panda_files.push_back(file.GetValue());
194 runtime_options.SetPandaFiles(panda_files);
195 }
196 }
197
198 runtime_options.SetBootPandaFiles(boot_panda_files);
199
200 if (!Runtime::Create(runtime_options)) {
201 std::cerr << "Error: cannot create runtime" << std::endl;
202 return -1;
203 }
204
205 int ret = 0;
206
207 if (options.GetValue()) {
208 std::cout << pa_parser.GetRegularArgs() << std::endl;
209 }
210
211 std::string file_name = file.GetValue();
212 std::string entry = entrypoint.GetValue();
213
214 auto &runtime = *Runtime::GetCurrent();
215 auto &verif_opts = runtime.GetVerificationOptions();
216 ASSERT(!verif_opts.IsOnlyVerify());
217
218 if (verif_opts.IsEnabled()) {
219 verifier::ThreadPool::GetCache()->FastAPI().ProcessFiles(runtime.GetClassLinker()->GetBootPandaFiles());
220 }
221
222 auto res = runtime.ExecutePandaFile(file_name, entry, arguments);
223 if (!res) {
224 std::cerr << "Cannot execute panda file '" << file_name << "' with entry '" << entry << "'" << std::endl;
225 ret = -1;
226 } else {
227 ret = res.Value();
228 }
229
230 if (runtime_options.IsPrintMemoryStatistics()) {
231 std::cout << runtime.GetMemoryStatistics();
232 }
233 if (runtime_options.IsPrintGcStatistics()) {
234 std::cout << runtime.GetFinalStatistics();
235 }
236 if (!Runtime::Destroy()) {
237 std::cerr << "Error: cannot destroy runtime" << std::endl;
238 return -1;
239 }
240 pa_parser.DisableTail();
241 return ret;
242 }
243 } // namespace panda
244
main(int argc,const char ** argv)245 int main(int argc, const char **argv)
246 {
247 return panda::Main(argc, argv);
248 }
249