xref: /arkcompiler/runtime_core/panda/panda.cpp (revision b1994897)
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
47namespace panda {
48const 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
61void 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
87void 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
98bool 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
141int 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
189int 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
250int main(int argc, const char **argv)
251{
252    return panda::Main(argc, argv);
253}
254