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 
ExecutePandaFile(panda::PandArg<bool> &options, panda::PandArgParser &pa_parser, panda::PandArg<std::string> &file, panda::PandArg<std::string> &entrypoint, RuntimeOptions &runtime_options)141 int ExecutePandaFile(panda::PandArg<bool> &options, panda::PandArgParser &pa_parser, panda::PandArg<std::string> &file,
142                      panda::PandArg<std::string> &entrypoint, RuntimeOptions &runtime_options)
143 {
144     if (!Runtime::Create(runtime_options)) {
145         std::cerr << "Error: cannot create runtime" << std::endl;
146         return -1;
147     }
148 
149     int ret = 0;
150 
151     if (options.GetValue()) {
152         std::cout << pa_parser.GetRegularArgs() << std::endl;
153     }
154 
155     std::string file_name = file.GetValue();
156     std::string entry = entrypoint.GetValue();
157 
158     auto &runtime = *Runtime::GetCurrent();
159     auto &verif_opts = runtime.GetVerificationOptions();
160     ASSERT(!verif_opts.IsOnlyVerify());
161 
162     if (verif_opts.IsEnabled()) {
163         verifier::ThreadPool::GetCache()->FastAPI().ProcessFiles(runtime.GetClassLinker()->GetBootPandaFiles());
164     }
165 
166     arg_list_t arguments = pa_parser.GetRemainder();
167     auto res = runtime.ExecutePandaFile(file_name, entry, arguments);
168     if (!res) {
169         std::cerr << "Cannot execute panda file '" << file_name << "' with entry '" << entry << "'" << std::endl;
170         ret = -1;
171     } else {
172         ret = res.Value();
173     }
174 
175     if (runtime_options.IsPrintMemoryStatistics()) {
176         std::cout << runtime.GetMemoryStatistics();
177     }
178     if (runtime_options.IsPrintGcStatistics()) {
179         std::cout << runtime.GetFinalStatistics();
180     }
181     if (!Runtime::Destroy()) {
182         std::cerr << "Error: cannot destroy runtime" << std::endl;
183         return -1;
184     }
185     pa_parser.DisableTail();
186     return ret;
187 }
188 
Main(int argc, const char **argv)189 int Main(int argc, const char **argv)
190 {
191     BlockSignals();
192     Span<const char *> sp(argv, argc);
193     RuntimeOptions runtime_options(sp[0]);
194     base_options::Options base_options(sp[0]);
195     panda::PandArgParser pa_parser;
196 
197     panda::PandArg<bool> help("help", false, "Print this message and exit");
198     panda::PandArg<bool> options("options", false, "Print compiler and runtime options");
199     // tail arguments
200     panda::PandArg<std::string> file("file", "", "path to pandafile");
201     panda::PandArg<std::string> entrypoint("entrypoint", "", "full name of entrypoint function or method");
202 
203     runtime_options.AddOptions(&pa_parser);
204     base_options.AddOptions(&pa_parser);
205     compiler::options.AddOptions(&pa_parser);
206 
207     pa_parser.Add(&help);
208     pa_parser.Add(&options);
209     pa_parser.PushBackTail(&file);
210     pa_parser.PushBackTail(&entrypoint);
211     pa_parser.EnableTail();
212     pa_parser.EnableRemainder();
213 
214     if (!panda::PrepareArguments(&pa_parser, runtime_options, file, entrypoint, help, argc, argv)) {
215         return 1;
216     }
217 
218     compiler::options.AdjustCpuFeatures(false);
219 
220     Logger::Initialize(base_options);
221 
222     runtime_options.SetVerificationMode(runtime_options.IsVerificationEnabled() ? VerificationMode::ON_THE_FLY
223                                                                                 : VerificationMode::DISABLED);
224 
225     panda::compiler::CompilerLogger::SetComponents(panda::compiler::options.GetCompilerLog());
226     if (compiler::options.IsCompilerEnableEvents()) {
227         panda::compiler::EventWriter::Init(panda::compiler::options.GetCompilerEventsPath());
228     }
229 
230     auto boot_panda_files = runtime_options.GetBootPandaFiles();
231 
232     if (runtime_options.GetPandaFiles().empty()) {
233         boot_panda_files.push_back(file.GetValue());
234     } else {
235         auto panda_files = runtime_options.GetPandaFiles();
236         auto found_iter = std::find_if(panda_files.begin(), panda_files.end(),
237                                        [&](auto &file_name) { return file_name == file.GetValue(); });
238         if (found_iter == panda_files.end()) {
239             panda_files.push_back(file.GetValue());
240             runtime_options.SetPandaFiles(panda_files);
241         }
242     }
243 
244     runtime_options.SetBootPandaFiles(boot_panda_files);
245 
246     return ExecutePandaFile(options, pa_parser, file, entrypoint, runtime_options);
247 }
248 }  // namespace panda
249 
main(int argc, const char **argv)250 int main(int argc, const char **argv)
251 {
252     return panda::Main(argc, argv);
253 }
254