wasm.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. /*
  2. * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/GenericLexer.h>
  8. #include <AK/Hex.h>
  9. #include <AK/MemoryStream.h>
  10. #include <AK/StackInfo.h>
  11. #include <LibCore/ArgsParser.h>
  12. #include <LibCore/File.h>
  13. #include <LibCore/MappedFile.h>
  14. #include <LibFileSystem/FileSystem.h>
  15. #include <LibLine/Editor.h>
  16. #include <LibMain/Main.h>
  17. #include <LibWasm/AbstractMachine/AbstractMachine.h>
  18. #include <LibWasm/AbstractMachine/BytecodeInterpreter.h>
  19. #include <LibWasm/Printer/Printer.h>
  20. #include <LibWasm/Types.h>
  21. #include <LibWasm/Wasi.h>
  22. #include <signal.h>
  23. #include <unistd.h>
  24. RefPtr<Line::Editor> g_line_editor;
  25. static OwnPtr<Stream> g_stdout {};
  26. static OwnPtr<Wasm::Printer> g_printer {};
  27. static bool g_continue { false };
  28. static void (*old_signal)(int);
  29. static StackInfo g_stack_info;
  30. static Wasm::DebuggerBytecodeInterpreter g_interpreter(g_stack_info);
  31. struct ParsedValue {
  32. Wasm::Value value;
  33. Wasm::ValueType type;
  34. };
  35. static void sigint_handler(int)
  36. {
  37. if (!g_continue) {
  38. signal(SIGINT, old_signal);
  39. kill(getpid(), SIGINT);
  40. }
  41. g_continue = false;
  42. }
  43. static Optional<u128> convert_to_uint(StringView string)
  44. {
  45. if (string.is_empty())
  46. return {};
  47. u128 value = 0;
  48. auto const characters = string.characters_without_null_termination();
  49. for (size_t i = 0; i < string.length(); i++) {
  50. if (characters[i] < '0' || characters[i] > '9')
  51. return {};
  52. value *= 10;
  53. value += u128 { static_cast<u64>(characters[i] - '0'), 0 };
  54. }
  55. return value;
  56. }
  57. static Optional<u128> convert_to_uint_from_hex(StringView string)
  58. {
  59. if (string.is_empty())
  60. return {};
  61. u128 value = 0;
  62. auto const count = string.length();
  63. auto const upper_bound = NumericLimits<u128>::max();
  64. for (size_t i = 0; i < count; i++) {
  65. char digit = string[i];
  66. if (value > (upper_bound >> 4))
  67. return {};
  68. auto digit_val = decode_hex_digit(digit);
  69. if (digit_val == 255)
  70. return {};
  71. value = (value << 4) + digit_val;
  72. }
  73. return value;
  74. }
  75. static ErrorOr<ParsedValue> parse_value(StringView spec)
  76. {
  77. constexpr auto is_sep = [](char c) { return is_ascii_space(c) || c == ':'; };
  78. // Scalar: 'T.const[:\s]v' (i32.const 42)
  79. auto parse_scalar = []<typename T>(StringView text) -> ErrorOr<Wasm::Value> {
  80. if constexpr (IsFloatingPoint<T>) {
  81. if (text.trim_whitespace().equals_ignoring_ascii_case("nan"sv)) {
  82. if constexpr (IsSame<T, float>)
  83. return Wasm::Value { nanf("") };
  84. else
  85. return Wasm::Value { nan("") };
  86. }
  87. if (text.trim_whitespace().equals_ignoring_ascii_case("inf"sv)) {
  88. if constexpr (IsSame<T, float>)
  89. return Wasm::Value { HUGE_VALF };
  90. else
  91. return Wasm::Value { HUGE_VAL };
  92. }
  93. }
  94. if (auto v = text.to_number<T>(); v.has_value())
  95. return Wasm::Value { *v };
  96. return Error::from_string_literal("Invalid scalar value");
  97. };
  98. // Vector: 'v128.const[:\s]v' (v128.const 0x01000000020000000300000004000000) or 'v(T.const[:\s]v, ...)' (v(i32.const 1, i32.const 2, i32.const 3, i32.const 4))
  99. auto parse_u128 = [](StringView text) -> ErrorOr<Wasm::Value> {
  100. u128 value;
  101. if (text.starts_with("0x"sv)) {
  102. if (auto v = convert_to_uint_from_hex(text); v.has_value())
  103. value = *v;
  104. else
  105. return Error::from_string_literal("Invalid hex v128 value");
  106. } else {
  107. if (auto v = convert_to_uint(text); v.has_value())
  108. value = *v;
  109. else
  110. return Error::from_string_literal("Invalid v128 value");
  111. }
  112. return Wasm::Value { value };
  113. };
  114. GenericLexer lexer(spec);
  115. if (lexer.consume_specific("v128.const"sv)) {
  116. lexer.ignore_while(is_sep);
  117. // The rest of the string is the value
  118. auto text = lexer.consume_all();
  119. return ParsedValue {
  120. .value = TRY(parse_u128(text)),
  121. .type = Wasm::ValueType(Wasm::ValueType::Kind::V128)
  122. };
  123. }
  124. if (lexer.consume_specific("i8.const"sv)) {
  125. lexer.ignore_while(is_sep);
  126. auto text = lexer.consume_all();
  127. return ParsedValue {
  128. .value = TRY(parse_scalar.operator()<i8>(text)),
  129. .type = Wasm::ValueType(Wasm::ValueType::Kind::I32)
  130. };
  131. }
  132. if (lexer.consume_specific("i16.const"sv)) {
  133. lexer.ignore_while(is_sep);
  134. auto text = lexer.consume_all();
  135. return ParsedValue {
  136. .value = TRY(parse_scalar.operator()<i16>(text)),
  137. .type = Wasm::ValueType(Wasm::ValueType::Kind::I32)
  138. };
  139. }
  140. if (lexer.consume_specific("i32.const"sv)) {
  141. lexer.ignore_while(is_sep);
  142. auto text = lexer.consume_all();
  143. return ParsedValue {
  144. .value = TRY(parse_scalar.operator()<i32>(text)),
  145. .type = Wasm::ValueType(Wasm::ValueType::Kind::I32)
  146. };
  147. }
  148. if (lexer.consume_specific("i64.const"sv)) {
  149. lexer.ignore_while(is_sep);
  150. auto text = lexer.consume_all();
  151. return ParsedValue {
  152. .value = TRY(parse_scalar.operator()<i64>(text)),
  153. .type = Wasm::ValueType(Wasm::ValueType::Kind::I64)
  154. };
  155. }
  156. if (lexer.consume_specific("f32.const"sv)) {
  157. lexer.ignore_while(is_sep);
  158. auto text = lexer.consume_all();
  159. return ParsedValue {
  160. .value = TRY(parse_scalar.operator()<float>(text)),
  161. .type = Wasm::ValueType(Wasm::ValueType::Kind::F32)
  162. };
  163. }
  164. if (lexer.consume_specific("f64.const"sv)) {
  165. lexer.ignore_while(is_sep);
  166. auto text = lexer.consume_all();
  167. return ParsedValue {
  168. .value = TRY(parse_scalar.operator()<double>(text)),
  169. .type = Wasm::ValueType(Wasm::ValueType::Kind::F64)
  170. };
  171. }
  172. if (lexer.consume_specific("v("sv)) {
  173. Vector<ParsedValue> values;
  174. for (;;) {
  175. lexer.ignore_while(is_sep);
  176. if (lexer.consume_specific(")"sv))
  177. break;
  178. if (lexer.is_eof()) {
  179. warnln("Expected ')' to close vector");
  180. break;
  181. }
  182. auto value = parse_value(lexer.consume_until(is_any_of(",)"sv)));
  183. if (value.is_error())
  184. return value.release_error();
  185. lexer.consume_specific(',');
  186. values.append(value.release_value());
  187. }
  188. if (values.is_empty())
  189. return Error::from_string_literal("Empty vector");
  190. auto element_type = values.first().type;
  191. for (auto& value : values) {
  192. if (value.type != element_type)
  193. return Error::from_string_literal("Mixed types in vector");
  194. }
  195. unsigned total_size = 0;
  196. unsigned width = 0;
  197. u128 result = 0;
  198. u128 last_value = 0;
  199. for (auto& parsed : values) {
  200. if (total_size >= 128)
  201. return Error::from_string_literal("Vector too large");
  202. switch (parsed.type.kind()) {
  203. case Wasm::ValueType::F32:
  204. case Wasm::ValueType::I32:
  205. width = sizeof(u32);
  206. break;
  207. case Wasm::ValueType::F64:
  208. case Wasm::ValueType::I64:
  209. width = sizeof(u64);
  210. break;
  211. case Wasm::ValueType::V128:
  212. case Wasm::ValueType::FunctionReference:
  213. case Wasm::ValueType::ExternReference:
  214. VERIFY_NOT_REACHED();
  215. }
  216. last_value = parsed.value.value();
  217. result |= last_value << total_size;
  218. total_size += width * 8;
  219. }
  220. if (total_size < 128)
  221. warnln("Vector value '{}' is only {} bytes wide, repeating last element", spec, total_size);
  222. while (total_size < 128) {
  223. // Repeat the last value until we fill the 128 bits
  224. result |= last_value << total_size;
  225. total_size += width * 8;
  226. }
  227. return ParsedValue {
  228. .value = Wasm::Value { result },
  229. .type = Wasm::ValueType(Wasm::ValueType::Kind::V128)
  230. };
  231. }
  232. return Error::from_string_literal("Invalid value");
  233. }
  234. static bool post_interpret_hook(Wasm::Configuration&, Wasm::InstructionPointer& ip, Wasm::Instruction const& instr, Wasm::Interpreter const& interpreter)
  235. {
  236. if (interpreter.did_trap()) {
  237. g_continue = false;
  238. warnln("Trapped when executing ip={}", ip);
  239. g_printer->print(instr);
  240. warnln("Trap reason: {}", interpreter.trap_reason());
  241. const_cast<Wasm::Interpreter&>(interpreter).clear_trap();
  242. }
  243. return true;
  244. }
  245. static bool pre_interpret_hook(Wasm::Configuration& config, Wasm::InstructionPointer& ip, Wasm::Instruction const& instr)
  246. {
  247. static bool always_print_stack = false;
  248. static bool always_print_instruction = false;
  249. if (always_print_stack)
  250. config.dump_stack();
  251. if (always_print_instruction) {
  252. g_stdout->write_until_depleted(ByteString::formatted("{:0>4} ", ip.value())).release_value_but_fixme_should_propagate_errors();
  253. g_printer->print(instr);
  254. }
  255. if (g_continue)
  256. return true;
  257. g_stdout->write_until_depleted(ByteString::formatted("{:0>4} ", ip.value())).release_value_but_fixme_should_propagate_errors();
  258. g_printer->print(instr);
  259. ByteString last_command = "";
  260. for (;;) {
  261. auto result = g_line_editor->get_line("> ");
  262. if (result.is_error()) {
  263. return false;
  264. }
  265. auto str = result.release_value();
  266. g_line_editor->add_to_history(str);
  267. if (str.is_empty())
  268. str = last_command;
  269. else
  270. last_command = str;
  271. auto args = str.split_view(' ');
  272. if (args.is_empty())
  273. continue;
  274. auto& cmd = args[0];
  275. if (cmd.is_one_of("h", "help")) {
  276. warnln("Wasm shell commands");
  277. warnln("Toplevel:");
  278. warnln("- [s]tep Run one instruction");
  279. warnln("- next Alias for step");
  280. warnln("- [c]ontinue Execute until a trap or the program exit point");
  281. warnln("- [p]rint <args...> Print various things (see section on print)");
  282. warnln("- call <fn> <args...> Call the function <fn> with the given arguments");
  283. warnln("- set <args...> Set shell option (see section on settings)");
  284. warnln("- unset <args...> Unset shell option (see section on settings)");
  285. warnln("- [h]elp Print this help");
  286. warnln();
  287. warnln("Print:");
  288. warnln("- print [s]tack Print the contents of the stack, including frames and labels");
  289. warnln("- print [[m]em]ory <index> Print the contents of the memory identified by <index>");
  290. warnln("- print [[i]nstr]uction Print the current instruction");
  291. warnln("- print [[f]unc]tion <index> Print the function identified by <index>");
  292. warnln();
  293. warnln("Settings:");
  294. warnln("- set print stack Make the shell print the stack on every instruction executed");
  295. warnln("- set print [instr]uction Make the shell print the instruction that will be executed next");
  296. warnln();
  297. continue;
  298. }
  299. if (cmd.is_one_of("s", "step", "next")) {
  300. return true;
  301. }
  302. if (cmd.is_one_of("p", "print")) {
  303. if (args.size() < 2) {
  304. warnln("Print what?");
  305. continue;
  306. }
  307. auto& what = args[1];
  308. if (what.is_one_of("s", "stack")) {
  309. config.dump_stack();
  310. continue;
  311. }
  312. if (what.is_one_of("m", "mem", "memory")) {
  313. if (args.size() < 3) {
  314. warnln("print what memory?");
  315. continue;
  316. }
  317. auto value = args[2].to_number<u64>();
  318. if (!value.has_value()) {
  319. warnln("invalid memory index {}", args[2]);
  320. continue;
  321. }
  322. auto mem = config.store().get(Wasm::MemoryAddress(value.value()));
  323. if (!mem) {
  324. warnln("invalid memory index {} (not found)", args[2]);
  325. continue;
  326. }
  327. warnln("{:>32hex-dump}", mem->data().bytes());
  328. continue;
  329. }
  330. if (what.is_one_of("i", "instr", "instruction")) {
  331. g_printer->print(instr);
  332. continue;
  333. }
  334. if (what.is_one_of("f", "func", "function")) {
  335. if (args.size() < 3) {
  336. warnln("print what function?");
  337. continue;
  338. }
  339. auto value = args[2].to_number<u64>();
  340. if (!value.has_value()) {
  341. warnln("invalid function index {}", args[2]);
  342. continue;
  343. }
  344. auto fn = config.store().get(Wasm::FunctionAddress(value.value()));
  345. if (!fn) {
  346. warnln("invalid function index {} (not found)", args[2]);
  347. continue;
  348. }
  349. if (auto* fn_value = fn->get_pointer<Wasm::HostFunction>()) {
  350. warnln("Host function at {:p}", &fn_value->function());
  351. continue;
  352. }
  353. if (auto* fn_value = fn->get_pointer<Wasm::WasmFunction>()) {
  354. g_printer->print(fn_value->code());
  355. continue;
  356. }
  357. }
  358. }
  359. if (cmd == "call"sv) {
  360. if (args.size() < 2) {
  361. warnln("call what?");
  362. continue;
  363. }
  364. Optional<Wasm::FunctionAddress> address;
  365. auto index = args[1].to_number<u64>();
  366. if (index.has_value()) {
  367. address = config.frame().module().functions()[index.value()];
  368. } else {
  369. auto& name = args[1];
  370. for (auto& export_ : config.frame().module().exports()) {
  371. if (export_.name() == name) {
  372. if (auto addr = export_.value().get_pointer<Wasm::FunctionAddress>()) {
  373. address = *addr;
  374. break;
  375. }
  376. }
  377. }
  378. }
  379. if (!address.has_value()) {
  380. failed_to_find:;
  381. warnln("Could not find a function {}", args[1]);
  382. continue;
  383. }
  384. auto fn = config.store().get(*address);
  385. if (!fn)
  386. goto failed_to_find;
  387. auto type = fn->visit([&](auto& value) { return value.type(); });
  388. if (type.parameters().size() + 2 != args.size()) {
  389. warnln("Expected {} arguments for call, but found only {}", type.parameters().size(), args.size() - 2);
  390. continue;
  391. }
  392. Vector<ParsedValue> values_to_push;
  393. Vector<Wasm::Value> values;
  394. auto ok = true;
  395. for (size_t index = 2; index < args.size(); ++index) {
  396. auto r = parse_value(args[index]);
  397. if (r.is_error()) {
  398. warnln("Failed to parse argument {}: {}", args[index], r.error());
  399. ok = false;
  400. break;
  401. }
  402. values_to_push.append(r.release_value());
  403. }
  404. if (!ok)
  405. continue;
  406. for (auto& param : type.parameters()) {
  407. auto v = values_to_push.take_last();
  408. if (v.type != param) {
  409. warnln("Type mismatch in argument: expected {}, but got {}", Wasm::ValueType::kind_name(param.kind()), Wasm::ValueType::kind_name(v.type.kind()));
  410. ok = false;
  411. break;
  412. }
  413. values.append(v.value);
  414. }
  415. if (!ok)
  416. continue;
  417. Wasm::Result result { Wasm::Trap {} };
  418. {
  419. Wasm::BytecodeInterpreter::CallFrameHandle handle { g_interpreter, config };
  420. result = config.call(g_interpreter, *address, move(values)).assert_wasm_result();
  421. }
  422. if (result.is_trap()) {
  423. warnln("Execution trapped: {}", result.trap().reason);
  424. } else {
  425. if (!result.values().is_empty())
  426. warnln("Returned:");
  427. size_t index = 0;
  428. for (auto& value : result.values()) {
  429. g_stdout->write_until_depleted(" -> "sv.bytes()).release_value_but_fixme_should_propagate_errors();
  430. g_printer->print(value, type.results()[index]);
  431. ++index;
  432. }
  433. }
  434. continue;
  435. }
  436. if (cmd.is_one_of("set", "unset")) {
  437. auto value = !cmd.starts_with('u');
  438. if (args.size() < 3) {
  439. warnln("(un)set what (to what)?");
  440. continue;
  441. }
  442. if (args[1] == "print"sv) {
  443. if (args[2] == "stack"sv)
  444. always_print_stack = value;
  445. else if (args[2].is_one_of("instr", "instruction"))
  446. always_print_instruction = value;
  447. else
  448. warnln("Unknown print category '{}'", args[2]);
  449. continue;
  450. }
  451. warnln("Unknown set category '{}'", args[1]);
  452. continue;
  453. }
  454. if (cmd.is_one_of("c", "continue")) {
  455. g_continue = true;
  456. return true;
  457. }
  458. warnln("Command not understood: {}", cmd);
  459. }
  460. }
  461. static RefPtr<Wasm::Module> parse(StringView filename)
  462. {
  463. auto result = Core::MappedFile::map(filename);
  464. if (result.is_error()) {
  465. warnln("Failed to open {}: {}", filename, result.error());
  466. return {};
  467. }
  468. auto parse_result = Wasm::Module::parse(*result.value());
  469. if (parse_result.is_error()) {
  470. warnln("Something went wrong, either the file is invalid, or there's a bug with LibWasm!");
  471. warnln("The parse error was {}", Wasm::parse_error_to_byte_string(parse_result.error()));
  472. return {};
  473. }
  474. return parse_result.release_value();
  475. }
  476. static void print_link_error(Wasm::LinkError const& error)
  477. {
  478. for (auto const& missing : error.missing_imports)
  479. warnln("Missing import '{}'", missing);
  480. }
  481. ErrorOr<int> serenity_main(Main::Arguments arguments)
  482. {
  483. StringView filename;
  484. bool print = false;
  485. bool attempt_instantiate = false;
  486. bool debug = false;
  487. bool export_all_imports = false;
  488. bool shell_mode = false;
  489. bool wasi = false;
  490. ByteString exported_function_to_execute;
  491. Vector<ParsedValue> values_to_push;
  492. Vector<ByteString> modules_to_link_in;
  493. Vector<StringView> args_if_wasi;
  494. Vector<StringView> wasi_preopened_mappings;
  495. Core::ArgsParser parser;
  496. parser.add_positional_argument(filename, "File name to parse", "file");
  497. parser.add_option(debug, "Open a debugger", "debug", 'd');
  498. parser.add_option(print, "Print the parsed module", "print", 'p');
  499. parser.add_option(attempt_instantiate, "Attempt to instantiate the module", "instantiate", 'i');
  500. parser.add_option(exported_function_to_execute, "Attempt to execute the named exported function from the module (implies -i)", "execute", 'e', "name");
  501. parser.add_option(export_all_imports, "Export noop functions corresponding to imports", "export-noop");
  502. parser.add_option(shell_mode, "Launch a REPL in the module's context (implies -i)", "shell", 's');
  503. parser.add_option(wasi, "Enable WASI", "wasi", 'w');
  504. parser.add_option(Core::ArgsParser::Option {
  505. .argument_mode = Core::ArgsParser::OptionArgumentMode::Required,
  506. .help_string = "Directory mappings to expose via WASI",
  507. .long_name = "wasi-map-dir",
  508. .short_name = 0,
  509. .value_name = "path[:path]",
  510. .accept_value = [&](StringView str) {
  511. if (!str.is_empty()) {
  512. wasi_preopened_mappings.append(str);
  513. return true;
  514. }
  515. return false;
  516. },
  517. });
  518. parser.add_option(Core::ArgsParser::Option {
  519. .argument_mode = Core::ArgsParser::OptionArgumentMode::Required,
  520. .help_string = "Extra modules to link with, use to resolve imports",
  521. .long_name = "link",
  522. .short_name = 'l',
  523. .value_name = "file",
  524. .accept_value = [&](StringView str) {
  525. if (!str.is_empty()) {
  526. modules_to_link_in.append(str);
  527. return true;
  528. }
  529. return false;
  530. },
  531. });
  532. parser.add_option(Core::ArgsParser::Option {
  533. .argument_mode = Core::ArgsParser::OptionArgumentMode::Required,
  534. .help_string = "Supply arguments to the function (default=0) (T.const:v or v(T.const:v, ...))",
  535. .long_name = "arg",
  536. .short_name = 0,
  537. .value_name = "value",
  538. .accept_value = [&](StringView str) -> bool {
  539. auto result = parse_value(str);
  540. if (result.is_error()) {
  541. warnln("Failed to parse value: {}", result.error());
  542. return false;
  543. }
  544. values_to_push.append(result.release_value());
  545. return true;
  546. },
  547. });
  548. parser.add_positional_argument(args_if_wasi, "Arguments to pass to the WASI module", "args", Core::ArgsParser::Required::No);
  549. parser.parse(arguments);
  550. if (shell_mode) {
  551. debug = true;
  552. attempt_instantiate = true;
  553. }
  554. if (!shell_mode && debug && exported_function_to_execute.is_empty()) {
  555. warnln("Debug what? (pass -e fn)");
  556. return 1;
  557. }
  558. if (debug || shell_mode) {
  559. old_signal = signal(SIGINT, sigint_handler);
  560. }
  561. if (!exported_function_to_execute.is_empty())
  562. attempt_instantiate = true;
  563. auto parse_result = parse(filename);
  564. if (parse_result.is_null())
  565. return 1;
  566. g_stdout = TRY(Core::File::standard_output());
  567. g_printer = TRY(try_make<Wasm::Printer>(*g_stdout));
  568. if (print && !attempt_instantiate) {
  569. Wasm::Printer printer(*g_stdout);
  570. printer.print(*parse_result);
  571. }
  572. if (attempt_instantiate) {
  573. Wasm::AbstractMachine machine;
  574. Optional<Wasm::Wasi::Implementation> wasi_impl;
  575. if (wasi) {
  576. wasi_impl.emplace(Wasm::Wasi::Implementation::Details {
  577. .provide_arguments = [&] {
  578. Vector<String> strings;
  579. for (auto& string : args_if_wasi)
  580. strings.append(String::from_utf8(string).release_value_but_fixme_should_propagate_errors());
  581. return strings; },
  582. .provide_environment = {},
  583. .provide_preopened_directories = [&] {
  584. Vector<Wasm::Wasi::Implementation::MappedPath> paths;
  585. for (auto& string : wasi_preopened_mappings) {
  586. auto split_index = string.find(':');
  587. if (split_index.has_value()) {
  588. LexicalPath host_path { FileSystem::real_path(string.substring_view(0, *split_index)).release_value_but_fixme_should_propagate_errors() };
  589. LexicalPath mapped_path { string.substring_view(*split_index + 1) };
  590. paths.append({move(host_path), move(mapped_path)});
  591. } else {
  592. LexicalPath host_path { FileSystem::real_path(string).release_value_but_fixme_should_propagate_errors() };
  593. LexicalPath mapped_path { string };
  594. paths.append({move(host_path), move(mapped_path)});
  595. }
  596. }
  597. return paths; },
  598. });
  599. }
  600. Core::EventLoop main_loop;
  601. if (debug) {
  602. g_line_editor = Line::Editor::construct();
  603. g_interpreter.pre_interpret_hook = pre_interpret_hook;
  604. g_interpreter.post_interpret_hook = post_interpret_hook;
  605. }
  606. // First, resolve the linked modules
  607. Vector<NonnullOwnPtr<Wasm::ModuleInstance>> linked_instances;
  608. Vector<NonnullRefPtr<Wasm::Module>> linked_modules;
  609. for (auto& name : modules_to_link_in) {
  610. auto parse_result = parse(name);
  611. if (parse_result.is_null()) {
  612. warnln("Failed to parse linked module '{}'", name);
  613. return 1;
  614. }
  615. linked_modules.append(parse_result.release_nonnull());
  616. Wasm::Linker linker { linked_modules.last() };
  617. for (auto& instance : linked_instances)
  618. linker.link(*instance);
  619. auto link_result = linker.finish();
  620. if (link_result.is_error()) {
  621. warnln("Linking imported module '{}' failed", name);
  622. print_link_error(link_result.error());
  623. return 1;
  624. }
  625. auto instantiation_result = machine.instantiate(linked_modules.last(), link_result.release_value());
  626. if (instantiation_result.is_error()) {
  627. warnln("Instantiation of imported module '{}' failed: {}", name, instantiation_result.error().error);
  628. return 1;
  629. }
  630. linked_instances.append(instantiation_result.release_value());
  631. }
  632. Wasm::Linker linker { *parse_result };
  633. for (auto& instance : linked_instances)
  634. linker.link(*instance);
  635. if (wasi) {
  636. HashMap<Wasm::Linker::Name, Wasm::ExternValue> wasi_exports;
  637. for (auto& entry : linker.unresolved_imports()) {
  638. if (entry.module != "wasi_snapshot_preview1"sv)
  639. continue;
  640. auto function = wasi_impl->function_by_name(entry.name);
  641. if (function.is_error()) {
  642. dbgln("wasi function {} not implemented :(", entry.name);
  643. continue;
  644. }
  645. auto address = machine.store().allocate(function.release_value());
  646. wasi_exports.set(entry, *address);
  647. }
  648. linker.link(wasi_exports);
  649. }
  650. if (export_all_imports) {
  651. HashMap<Wasm::Linker::Name, Wasm::ExternValue> exports;
  652. for (auto& entry : linker.unresolved_imports()) {
  653. if (!entry.type.has<Wasm::TypeIndex>())
  654. continue;
  655. auto type = parse_result->type_section().types()[entry.type.get<Wasm::TypeIndex>().value()];
  656. auto address = machine.store().allocate(Wasm::HostFunction(
  657. [name = entry.name, type = type](auto&, auto& arguments) -> Wasm::Result {
  658. StringBuilder argument_builder;
  659. bool first = true;
  660. size_t index = 0;
  661. for (auto& argument : arguments) {
  662. AllocatingMemoryStream stream;
  663. auto value_type = type.parameters()[index];
  664. Wasm::Printer { stream }.print(argument, value_type);
  665. if (first)
  666. first = false;
  667. else
  668. argument_builder.append(", "sv);
  669. auto buffer = ByteBuffer::create_uninitialized(stream.used_buffer_size()).release_value_but_fixme_should_propagate_errors();
  670. stream.read_until_filled(buffer).release_value_but_fixme_should_propagate_errors();
  671. argument_builder.append(StringView(buffer).trim_whitespace());
  672. ++index;
  673. }
  674. dbgln("[wasm runtime] Stub function {} was called with the following arguments: {}", name, argument_builder.to_byte_string());
  675. Vector<Wasm::Value> result;
  676. result.ensure_capacity(type.results().size());
  677. for (auto expect_result : type.results())
  678. result.append(Wasm::Value(expect_result));
  679. return Wasm::Result { move(result) };
  680. },
  681. type,
  682. entry.name));
  683. exports.set(entry, *address);
  684. }
  685. linker.link(exports);
  686. }
  687. auto link_result = linker.finish();
  688. if (link_result.is_error()) {
  689. warnln("Linking main module failed");
  690. print_link_error(link_result.error());
  691. return 1;
  692. }
  693. auto result = machine.instantiate(*parse_result, link_result.release_value());
  694. if (result.is_error()) {
  695. warnln("Module instantiation failed: {}", result.error().error);
  696. return 1;
  697. }
  698. auto module_instance = result.release_value();
  699. auto launch_repl = [&] {
  700. Wasm::Configuration config { machine.store() };
  701. Wasm::Expression expression { {} };
  702. config.set_frame(Wasm::Frame {
  703. *module_instance,
  704. Vector<Wasm::Value> {},
  705. expression,
  706. 0,
  707. });
  708. Wasm::Instruction instr { Wasm::Instructions::nop };
  709. Wasm::InstructionPointer ip { 0 };
  710. g_continue = false;
  711. pre_interpret_hook(config, ip, instr);
  712. };
  713. auto print_func = [&](auto const& address) {
  714. Wasm::FunctionInstance* fn = machine.store().get(address);
  715. g_stdout->write_until_depleted(ByteString::formatted("- Function with address {}, ptr = {}\n", address.value(), fn)).release_value_but_fixme_should_propagate_errors();
  716. if (fn) {
  717. g_stdout->write_until_depleted(ByteString::formatted(" wasm function? {}\n", fn->has<Wasm::WasmFunction>())).release_value_but_fixme_should_propagate_errors();
  718. fn->visit(
  719. [&](Wasm::WasmFunction const& func) {
  720. Wasm::Printer printer { *g_stdout, 3 };
  721. g_stdout->write_until_depleted(" type:\n"sv).release_value_but_fixme_should_propagate_errors();
  722. printer.print(func.type());
  723. g_stdout->write_until_depleted(" code:\n"sv).release_value_but_fixme_should_propagate_errors();
  724. printer.print(func.code());
  725. },
  726. [](Wasm::HostFunction const&) {});
  727. }
  728. };
  729. if (print) {
  730. // Now, let's dump the functions!
  731. for (auto& address : module_instance->functions()) {
  732. print_func(address);
  733. }
  734. }
  735. if (shell_mode) {
  736. launch_repl();
  737. return 0;
  738. }
  739. if (!exported_function_to_execute.is_empty()) {
  740. Optional<Wasm::FunctionAddress> run_address;
  741. Vector<Wasm::Value> values;
  742. for (auto& entry : module_instance->exports()) {
  743. if (entry.name() == exported_function_to_execute) {
  744. if (auto addr = entry.value().get_pointer<Wasm::FunctionAddress>())
  745. run_address = *addr;
  746. }
  747. }
  748. if (!run_address.has_value()) {
  749. warnln("No such exported function, sorry :(");
  750. return 1;
  751. }
  752. auto instance = machine.store().get(*run_address);
  753. VERIFY(instance);
  754. if (instance->has<Wasm::HostFunction>()) {
  755. warnln("Exported function is a host function, cannot run that yet");
  756. return 1;
  757. }
  758. for (auto& param : instance->get<Wasm::WasmFunction>().type().parameters()) {
  759. if (values_to_push.is_empty()) {
  760. values.append(Wasm::Value(param));
  761. } else if (param == values_to_push.last().type) {
  762. values.append(values_to_push.take_last().value);
  763. } else {
  764. warnln("Type mismatch in argument: expected {}, but got {}", Wasm::ValueType::kind_name(param.kind()), Wasm::ValueType::kind_name(values_to_push.last().type.kind()));
  765. return 1;
  766. }
  767. }
  768. if (print) {
  769. outln("Executing ");
  770. print_func(*run_address);
  771. outln();
  772. }
  773. auto result = machine.invoke(g_interpreter, run_address.value(), move(values)).assert_wasm_result();
  774. if (debug)
  775. launch_repl();
  776. if (result.is_trap()) {
  777. if (result.trap().reason.starts_with("exit:"sv))
  778. return -result.trap().reason.substring_view(5).to_number<i32>().value_or(-1);
  779. warnln("Execution trapped: {}", result.trap().reason);
  780. } else {
  781. if (!result.values().is_empty())
  782. warnln("Returned:");
  783. auto result_type = instance->get<Wasm::WasmFunction>().type().results();
  784. size_t index = 0;
  785. for (auto& value : result.values()) {
  786. g_stdout->write_until_depleted(" -> "sv.bytes()).release_value_but_fixme_should_propagate_errors();
  787. g_printer->print(value, result_type[index]);
  788. ++index;
  789. }
  790. }
  791. }
  792. }
  793. return 0;
  794. }