wasm.cpp 32 KB

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