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 "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 panda {
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 panda::PandArgParser & paParser)58 void PrintHelp(const panda::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(panda::PandArgParser * paParser,const RuntimeOptions & runtimeOptions,const panda::PandArg<std::string> & file,const panda::PandArg<std::string> & entrypoint,const panda::PandArg<bool> & help,int argc,const char ** argv)69 bool PrepareArguments(panda::PandArgParser *paParser, const RuntimeOptions &runtimeOptions,
70 const panda::PandArg<std::string> &file, const panda::PandArg<std::string> &entrypoint,
71 const panda::PandArg<bool> &help, int argc, const char **argv)
72 {
73 auto startTime =
74 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
75 .count();
76
77 if (!paParser->Parse(argc, argv)) {
78 PrintHelp(*paParser);
79 return false;
80 }
81
82 if (runtimeOptions.IsVersion()) {
83 PrintPandaVersion();
84 return false;
85 }
86
87 if (file.GetValue().empty() || entrypoint.GetValue().empty() || help.GetValue()) {
88 PrintHelp(*paParser);
89 return false;
90 }
91
92 if (runtimeOptions.IsStartupTime()) {
93 std::cout << "\n"
94 << "Startup start time: " << startTime << std::endl;
95 }
96
97 auto runtimeOptionsErr = runtimeOptions.Validate();
98 if (runtimeOptionsErr) {
99 std::cerr << "Error: " << runtimeOptionsErr.value().GetMessage() << std::endl;
100 return false;
101 }
102
103 auto compilerOptionsErr = compiler::g_options.Validate();
104 if (compilerOptionsErr) {
105 std::cerr << "Error: " << compilerOptionsErr.value().GetMessage() << std::endl;
106 return false;
107 }
108
109 return true;
110 }
111
Main(int argc,const char ** argv)112 int Main(int argc, const char **argv)
113 {
114 Span<const char *> sp(argv, argc);
115 RuntimeOptions runtimeOptions(sp[0]);
116 base_options::Options baseOptions(sp[0]);
117 panda::PandArgParser paParser;
118
119 panda::PandArg<bool> help("help", false, "Print this message and exit");
120 panda::PandArg<bool> options("options", false, "Print compiler and runtime options");
121 // tail arguments
122 panda::PandArg<std::string> file("file", "", "path to pandafile");
123 panda::PandArg<std::string> entrypoint("entrypoint", "", "full name of entrypoint function or method");
124
125 runtimeOptions.AddOptions(&paParser);
126 baseOptions.AddOptions(&paParser);
127 compiler::g_options.AddOptions(&paParser);
128
129 paParser.Add(&help);
130 paParser.Add(&options);
131 paParser.PushBackTail(&file);
132 paParser.PushBackTail(&entrypoint);
133 paParser.EnableTail();
134 paParser.EnableRemainder();
135
136 if (!panda::PrepareArguments(&paParser, runtimeOptions, file, entrypoint, help, argc, argv)) {
137 return 1;
138 }
139
140 compiler::g_options.AdjustCpuFeatures(false);
141
142 Logger::Initialize(baseOptions);
143
144 runtimeOptions.SetVerificationMode(VerificationModeFromString(
145 static_cast<Options>(runtimeOptions).GetVerificationMode())); // NOLINT(cppcoreguidelines-slicing)
146 if (runtimeOptions.IsVerificationEnabled()) {
147 if (!runtimeOptions.WasSetVerificationMode()) {
148 runtimeOptions.SetVerificationMode(VerificationMode::AHEAD_OF_TIME);
149 }
150 }
151
152 arg_list_t arguments = paParser.GetRemainder();
153
154 panda::compiler::CompilerLogger::SetComponents(panda::compiler::g_options.GetCompilerLog());
155 if (compiler::g_options.IsCompilerEnableEvents()) {
156 panda::compiler::EventWriter::Init(panda::compiler::g_options.GetCompilerEventsPath());
157 }
158
159 auto bootPandaFiles = runtimeOptions.GetBootPandaFiles();
160
161 if (runtimeOptions.GetPandaFiles().empty()) {
162 bootPandaFiles.push_back(file.GetValue());
163 } else {
164 auto pandaFiles = runtimeOptions.GetPandaFiles();
165 auto foundIter = std::find_if(pandaFiles.begin(), pandaFiles.end(),
166 [&](auto &fileName) { return fileName == file.GetValue(); });
167 if (foundIter == pandaFiles.end()) {
168 pandaFiles.push_back(file.GetValue());
169 runtimeOptions.SetPandaFiles(pandaFiles);
170 }
171 }
172
173 runtimeOptions.SetBootPandaFiles(bootPandaFiles);
174
175 if (!Runtime::Create(runtimeOptions)) {
176 std::cerr << "Error: cannot create runtime" << std::endl;
177 return -1;
178 }
179
180 int ret = 0;
181
182 if (options.GetValue()) {
183 std::cout << paParser.GetRegularArgs() << std::endl;
184 }
185
186 std::string fileName = file.GetValue();
187 std::string entry = entrypoint.GetValue();
188
189 auto &runtime = *Runtime::GetCurrent();
190
191 auto res = runtime.ExecutePandaFile(fileName, entry, arguments);
192 if (!res) {
193 std::cerr << "Cannot execute panda file '" << fileName << "' with entry '" << entry << "'" << std::endl;
194 ret = -1;
195 } else {
196 ret = res.Value();
197 }
198
199 if (runtimeOptions.IsPrintMemoryStatistics()) {
200 std::cout << runtime.GetMemoryStatistics();
201 }
202 if (runtimeOptions.IsPrintGcStatistics()) {
203 std::cout << runtime.GetFinalStatistics();
204 }
205 if (!Runtime::Destroy()) {
206 std::cerr << "Error: cannot destroy runtime" << std::endl;
207 return -1;
208 }
209 paParser.DisableTail();
210 return ret;
211 }
212 } // namespace panda
213
main(int argc,const char ** argv)214 int main(int argc, const char **argv)
215 {
216 return panda::Main(argc, argv);
217 }
218