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