diff options
author | Michaël Zasso <targos@protonmail.com> | 2019-08-16 11:32:46 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2019-08-19 09:25:23 +0200 |
commit | e31f0a7d25668d3c1531294d2ef44a9f3bde4ef4 (patch) | |
tree | 6c6bed9804be9df6162b2483f0a56f371f66464d /deps/v8/third_party/wasm-api | |
parent | ec16fdae540adaf710b1a86c620170b2880088f0 (diff) | |
download | android-node-v8-e31f0a7d25668d3c1531294d2ef44a9f3bde4ef4.tar.gz android-node-v8-e31f0a7d25668d3c1531294d2ef44a9f3bde4ef4.tar.bz2 android-node-v8-e31f0a7d25668d3c1531294d2ef44a9f3bde4ef4.zip |
deps: update V8 to 7.7.299.4
PR-URL: https://github.com/nodejs/node/pull/28918
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'deps/v8/third_party/wasm-api')
45 files changed, 4634 insertions, 0 deletions
diff --git a/deps/v8/third_party/wasm-api/LICENSE b/deps/v8/third_party/wasm-api/LICENSE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/deps/v8/third_party/wasm-api/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/deps/v8/third_party/wasm-api/OWNERS b/deps/v8/third_party/wasm-api/OWNERS new file mode 100644 index 0000000000..596440f532 --- /dev/null +++ b/deps/v8/third_party/wasm-api/OWNERS @@ -0,0 +1,2 @@ +jkummerow@chromium.org +mstarzinger@chromium.org diff --git a/deps/v8/third_party/wasm-api/README.v8 b/deps/v8/third_party/wasm-api/README.v8 new file mode 100644 index 0000000000..ea957620b0 --- /dev/null +++ b/deps/v8/third_party/wasm-api/README.v8 @@ -0,0 +1,17 @@ +Name: Wasm C/C++ API +Short Name: wasm-c-api +URL: https://github.com/WebAssembly/wasm-c-api/ +Version: 0 +Revision: 5c742b048f7766a0c00be3a7af23fb71ba816026 +Date: 2019-03-18 +License: Apache 2.0 +License File: LICENSE +Security Critical: yes + +Description: +Provides a "black box" API for embedding a Wasm engine in C/C++ applications. + +Local modifications: +None. +The contents of the upstream "include/" directory are directly in here. +The upstream "example/" directory is copied as-is. diff --git a/deps/v8/third_party/wasm-api/example/callback.c b/deps/v8/third_party/wasm-api/example/callback.c new file mode 100644 index 0000000000..f3b9018594 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/callback.c @@ -0,0 +1,167 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +// Print a Wasm value +void wasm_val_print(wasm_val_t val) { + switch (val.kind) { + case WASM_I32: { + printf("%" PRIu32, val.of.i32); + } break; + case WASM_I64: { + printf("%" PRIu64, val.of.i64); + } break; + case WASM_F32: { + printf("%f", val.of.f32); + } break; + case WASM_F64: { + printf("%g", val.of.f64); + } break; + case WASM_ANYREF: + case WASM_FUNCREF: { + if (val.of.ref == NULL) { + printf("null"); + } else { + printf("ref(%p)", val.of.ref); + } + } break; + } +} + +// A function to be called from Wasm code. +own wasm_trap_t* print_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n> "); + wasm_val_print(args[0]); + printf("\n"); + + wasm_val_copy(&results[0], &args[0]); + return NULL; +} + + +// A function closure. +own wasm_trap_t* closure_callback( + void* env, const wasm_val_t args[], wasm_val_t results[] +) { + int i = *(int*)env; + printf("Calling back closure...\n"); + printf("> %d\n", i); + + results[0].kind = WASM_I32; + results[0].of.i32 = (int32_t)i; + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("callback.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* print_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + own wasm_func_t* print_func = wasm_func_new(store, print_type, print_callback); + + int i = 42; + own wasm_functype_t* closure_type = wasm_functype_new_0_1(wasm_valtype_new_i32()); + own wasm_func_t* closure_func = wasm_func_new_with_env(store, closure_type, closure_callback, &i, NULL); + + wasm_functype_delete(print_type); + wasm_functype_delete(closure_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { + wasm_func_as_extern(print_func), wasm_func_as_extern(closure_func) + }; + own wasm_instance_t* instance = wasm_instance_new(store, module, imports); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(print_func); + wasm_func_delete(closure_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + wasm_val_t args[2]; + args[0].kind = WASM_I32; + args[0].of.i32 = 3; + args[1].kind = WASM_I32; + args[1].of.i32 = 4; + wasm_val_t results[1]; + if (wasm_func_call(run_func, args, results)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Print result. + printf("Printing result...\n"); + printf("> %u\n", results[0].of.i32); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/callback.cc b/deps/v8/third_party/wasm-api/example/callback.cc new file mode 100644 index 0000000000..a9ee9aa919 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/callback.cc @@ -0,0 +1,145 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + +// Print a Wasm value +auto operator<<(std::ostream& out, const wasm::Val& val) -> std::ostream& { + switch (val.kind()) { + case wasm::I32: { + out << val.i32(); + } break; + case wasm::I64: { + out << val.i64(); + } break; + case wasm::F32: { + out << val.f32(); + } break; + case wasm::F64: { + out << val.f64(); + } break; + case wasm::ANYREF: + case wasm::FUNCREF: { + if (val.ref() == nullptr) { + out << "null"; + } else { + out << "ref(" << val.ref() << ")"; + } + } break; + } + return out; +} + +// A function to be called from Wasm code. +auto print_callback( + const wasm::Val args[], wasm::Val results[] +) -> wasm::own<wasm::Trap*> { + std::cout << "Calling back..." << std::endl << "> " << args[0] << std::endl; + results[0] = args[0].copy(); + return nullptr; +} + + +// A function closure. +auto closure_callback( + void* env, const wasm::Val args[], wasm::Val results[] +) -> wasm::own<wasm::Trap*> { + auto i = *reinterpret_cast<int*>(env); + std::cout << "Calling back closure..." << std::endl; + std::cout << "> " << i << std::endl; + results[0] = wasm::Val::i32(static_cast<int32_t>(i)); + return nullptr; +} + + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("callback.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Create external print functions. + std::cout << "Creating callback..." << std::endl; + auto print_type = wasm::FuncType::make( + wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)), + wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)) + ); + auto print_func = wasm::Func::make(store, print_type.get(), print_callback); + + // Creating closure. + std::cout << "Creating closure..." << std::endl; + int i = 42; + auto closure_type = wasm::FuncType::make( + wasm::vec<wasm::ValType*>::make(), + wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)) + ); + auto closure_func = wasm::Func::make(store, closure_type.get(), closure_callback, &i); + + // Instantiate. + std::cout << "Instantiating module..." << std::endl; + wasm::Extern* imports[] = {print_func.get(), closure_func.get()}; + auto instance = wasm::Instance::make(store, module.get(), imports); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + std::cout << "Extracting export..." << std::endl; + auto exports = instance->exports(); + if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) { + std::cout << "> Error accessing export!" << std::endl; + return; + } + auto run_func = exports[0]->func(); + + // Call. + std::cout << "Calling export..." << std::endl; + wasm::Val args[] = {wasm::Val::i32(3), wasm::Val::i32(4)}; + wasm::Val results[1]; + if (run_func->call(args, results)) { + std::cout << "> Error calling function!" << std::endl; + return; + } + + // Print result. + std::cout << "Printing result..." << std::endl; + std::cout << "> " << results[0].i32() << std::endl; + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/callback.wasm b/deps/v8/third_party/wasm-api/example/callback.wasm Binary files differnew file mode 100644 index 0000000000..7e00b58014 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/callback.wasm diff --git a/deps/v8/third_party/wasm-api/example/callback.wat b/deps/v8/third_party/wasm-api/example/callback.wat new file mode 100644 index 0000000000..d86195f51d --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/callback.wat @@ -0,0 +1,10 @@ +(module + (func $print (import "" "print") (param i32) (result i32)) + (func $closure (import "" "closure") (result i32)) + (func (export "run") (param $x i32) (param $y i32) (result i32) + (i32.add + (call $print (i32.add (local.get $x) (local.get $y))) + (call $closure) + ) + ) +) diff --git a/deps/v8/third_party/wasm-api/example/finalize.c b/deps/v8/third_party/wasm-api/example/finalize.c new file mode 100644 index 0000000000..6841617262 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/finalize.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +const int iterations = 100000; + +void finalize(void* data) { + int i = (int)data; + if (i % (iterations / 10) == 0) printf("Finalizing #%d...\n", i); +} + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("finalize.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Instantiate. + printf("Instantiating modules...\n"); + for (int i = 0; i <= iterations; ++i) { + if (i % (iterations / 10) == 0) printf("%d\n", i); + own wasm_instance_t* instance = wasm_instance_new(store, module, NULL); + if (!instance) { + printf("> Error instantiating module %d!\n", i); + return 1; + } + void* data = (void*)(intptr_t)i; + wasm_instance_set_host_info_with_finalizer(instance, data, &finalize); + wasm_instance_delete(instance); + } + + wasm_module_delete(module); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/finalize.cc b/deps/v8/third_party/wasm-api/example/finalize.cc new file mode 100644 index 0000000000..a354a2601d --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/finalize.cc @@ -0,0 +1,70 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + + +const int iterations = 100000; + +void finalize(void* data) { + intptr_t i = reinterpret_cast<intptr_t>(data); + if (i % (iterations / 10) == 0) { + std::cout << "Finalizing #" << i << "..." << std::endl; + } +} + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("finalize.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Instantiate. + std::cout << "Instantiating modules..." << std::endl; + for (int i = 0; i <= iterations; ++i) { + if (i % (iterations / 10) == 0) std::cout << i << std::endl; + auto instance = wasm::Instance::make(store, module.get(), nullptr); + if (!instance) { + std::cout << "> Error instantiating module " << i << "!" << std::endl; + return; + } + instance->set_host_info(reinterpret_cast<void*>(i), &finalize); + } + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/finalize.wasm b/deps/v8/third_party/wasm-api/example/finalize.wasm Binary files differnew file mode 100644 index 0000000000..74f9c56624 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/finalize.wasm diff --git a/deps/v8/third_party/wasm-api/example/finalize.wat b/deps/v8/third_party/wasm-api/example/finalize.wat new file mode 100644 index 0000000000..6237e734ac --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/finalize.wat @@ -0,0 +1,5 @@ +(module + (func (export "f")) + (func (export "g")) + (func (export "h")) +) diff --git a/deps/v8/third_party/wasm-api/example/global.c b/deps/v8/third_party/wasm-api/example/global.c new file mode 100644 index 0000000000..b82d86242e --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/global.c @@ -0,0 +1,222 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +wasm_global_t* get_export_global(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_global(exports->data[i])) { + printf("> Error accessing global export %zu!\n", i); + exit(1); + } + return wasm_extern_as_global(exports->data[i]); +} + +wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) { + printf("> Error accessing function export %zu!\n", i); + exit(1); + } + return wasm_extern_as_func(exports->data[i]); +} + + +#define check(val, type, expected) \ + if (val.of.type != expected) { \ + printf("> Error reading value\n"); \ + exit(1); \ + } + +#define check_global(global, type, expected) \ + { \ + wasm_val_t val; \ + wasm_global_get(global, &val); \ + check(val, type, expected); \ + } + +#define check_call(func, type, expected) \ + { \ + wasm_val_t results[1]; \ + wasm_func_call(func, NULL, results); \ + check(results[0], type, expected); \ + } + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("global.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external globals. + printf("Creating globals...\n"); + own wasm_globaltype_t* const_f32_type = wasm_globaltype_new( + wasm_valtype_new(WASM_F32), WASM_CONST); + own wasm_globaltype_t* const_i64_type = wasm_globaltype_new( + wasm_valtype_new(WASM_I64), WASM_CONST); + own wasm_globaltype_t* var_f32_type = wasm_globaltype_new( + wasm_valtype_new(WASM_F32), WASM_VAR); + own wasm_globaltype_t* var_i64_type = wasm_globaltype_new( + wasm_valtype_new(WASM_I64), WASM_VAR); + + wasm_val_t val_f32_1 = {.kind = WASM_F32, .of = {.f32 = 1}}; + own wasm_global_t* const_f32_import = wasm_global_new(store, const_f32_type, &val_f32_1); + wasm_val_t val_i64_2 = {.kind = WASM_I64, .of = {.i64 = 2}}; + own wasm_global_t* const_i64_import = wasm_global_new(store, const_i64_type, &val_i64_2); + wasm_val_t val_f32_3 = {.kind = WASM_F32, .of = {.f32 = 3}}; + own wasm_global_t* var_f32_import = wasm_global_new(store, var_f32_type, &val_f32_3); + wasm_val_t val_i64_4 = {.kind = WASM_I64, .of = {.i64 = 4}}; + own wasm_global_t* var_i64_import = wasm_global_new(store, var_i64_type, &val_i64_4); + + wasm_globaltype_delete(const_f32_type); + wasm_globaltype_delete(const_i64_type); + wasm_globaltype_delete(var_f32_type); + wasm_globaltype_delete(var_i64_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { + wasm_global_as_extern(const_f32_import), + wasm_global_as_extern(const_i64_import), + wasm_global_as_extern(var_f32_import), + wasm_global_as_extern(var_i64_import) + }; + own wasm_instance_t* instance = wasm_instance_new(store, module, imports); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_module_delete(module); + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + size_t i = 0; + wasm_global_t* const_f32_export = get_export_global(&exports, i++); + wasm_global_t* const_i64_export = get_export_global(&exports, i++); + wasm_global_t* var_f32_export = get_export_global(&exports, i++); + wasm_global_t* var_i64_export = get_export_global(&exports, i++); + wasm_func_t* get_const_f32_import = get_export_func(&exports, i++); + wasm_func_t* get_const_i64_import = get_export_func(&exports, i++); + wasm_func_t* get_var_f32_import = get_export_func(&exports, i++); + wasm_func_t* get_var_i64_import = get_export_func(&exports, i++); + wasm_func_t* get_const_f32_export = get_export_func(&exports, i++); + wasm_func_t* get_const_i64_export = get_export_func(&exports, i++); + wasm_func_t* get_var_f32_export = get_export_func(&exports, i++); + wasm_func_t* get_var_i64_export = get_export_func(&exports, i++); + wasm_func_t* set_var_f32_import = get_export_func(&exports, i++); + wasm_func_t* set_var_i64_import = get_export_func(&exports, i++); + wasm_func_t* set_var_f32_export = get_export_func(&exports, i++); + wasm_func_t* set_var_i64_export = get_export_func(&exports, i++); + + // Interact. + printf("Accessing globals...\n"); + + // Check initial values. + check_global(const_f32_import, f32, 1); + check_global(const_i64_import, i64, 2); + check_global(var_f32_import, f32, 3); + check_global(var_i64_import, i64, 4); + check_global(const_f32_export, f32, 5); + check_global(const_i64_export, i64, 6); + check_global(var_f32_export, f32, 7); + check_global(var_i64_export, i64, 8); + + check_call(get_const_f32_import, f32, 1); + check_call(get_const_i64_import, i64, 2); + check_call(get_var_f32_import, f32, 3); + check_call(get_var_i64_import, i64, 4); + check_call(get_const_f32_export, f32, 5); + check_call(get_const_i64_export, i64, 6); + check_call(get_var_f32_export, f32, 7); + check_call(get_var_i64_export, i64, 8); + + // Modify variables through API and check again. + wasm_val_t val33 = {.kind = WASM_F32, .of = {.f32 = 33}}; + wasm_global_set(var_f32_import, &val33); + wasm_val_t val34 = {.kind = WASM_I64, .of = {.i64 = 34}}; + wasm_global_set(var_i64_import, &val34); + wasm_val_t val37 = {.kind = WASM_F32, .of = {.f32 = 37}}; + wasm_global_set(var_f32_export, &val37); + wasm_val_t val38 = {.kind = WASM_I64, .of = {.i64 = 38}}; + wasm_global_set(var_i64_export, &val38); + + check_global(var_f32_import, f32, 33); + check_global(var_i64_import, i64, 34); + check_global(var_f32_export, f32, 37); + check_global(var_i64_export, i64, 38); + + check_call(get_var_f32_import, f32, 33); + check_call(get_var_i64_import, i64, 34); + check_call(get_var_f32_export, f32, 37); + check_call(get_var_i64_export, i64, 38); + + // Modify variables through calls and check again. + wasm_val_t args73[] = { {.kind = WASM_F32, .of = {.f32 = 73}} }; + wasm_func_call(set_var_f32_import, args73, NULL); + wasm_val_t args74[] = { {.kind = WASM_I64, .of = {.i64 = 74}} }; + wasm_func_call(set_var_i64_import, args74, NULL); + wasm_val_t args77[] = { {.kind = WASM_F32, .of = {.f32 = 77}} }; + wasm_func_call(set_var_f32_export, args77, NULL); + wasm_val_t args78[] = { {.kind = WASM_I64, .of = {.i64 = 78}} }; + wasm_func_call(set_var_i64_export, args78, NULL); + + check_global(var_f32_import, f32, 73); + check_global(var_i64_import, i64, 74); + check_global(var_f32_export, f32, 77); + check_global(var_i64_export, i64, 78); + + check_call(get_var_f32_import, f32, 73); + check_call(get_var_i64_import, i64, 74); + check_call(get_var_f32_export, f32, 77); + check_call(get_var_i64_export, i64, 78); + + wasm_global_delete(const_f32_import); + wasm_global_delete(const_i64_import); + wasm_global_delete(var_f32_import); + wasm_global_delete(var_i64_import); + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/global.cc b/deps/v8/third_party/wasm-api/example/global.cc new file mode 100644 index 0000000000..75a2513c82 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/global.cc @@ -0,0 +1,193 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + + +auto get_export_global(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Global* { + if (exports.size() <= i || !exports[i]->global()) { + std::cout << "> Error accessing global export " << i << "!" << std::endl; + exit(1); + } + return exports[i]->global(); +} + +auto get_export_func(const wasm::vec<wasm::Extern*>& exports, size_t i) -> const wasm::Func* { + if (exports.size() <= i || !exports[i]->func()) { + std::cout << "> Error accessing function export " << i << "!" << std::endl; + exit(1); + } + return exports[i]->func(); +} + +template<class T, class U> +void check(T actual, U expected) { + if (actual != expected) { + std::cout << "> Error reading value, expected " << expected << ", got " << actual << std::endl; + exit(1); + } +} + +auto call(const wasm::Func* func) -> wasm::Val { + wasm::Val results[1]; + if (func->call(nullptr, results)) { + std::cout << "> Error calling function!" << std::endl; + exit(1); + } + return results[0].copy(); +} + +void call(const wasm::Func* func, wasm::Val&& arg) { + wasm::Val args[1] = {std::move(arg)}; + if (func->call(args)) { + std::cout << "> Error calling function!" << std::endl; + exit(1); + } +} + + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("global.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Create external globals. + std::cout << "Creating globals..." << std::endl; + auto const_f32_type = wasm::GlobalType::make( + wasm::ValType::make(wasm::F32), wasm::CONST); + auto const_i64_type = wasm::GlobalType::make( + wasm::ValType::make(wasm::I64), wasm::CONST); + auto var_f32_type = wasm::GlobalType::make( + wasm::ValType::make(wasm::F32), wasm::VAR); + auto var_i64_type = wasm::GlobalType::make( + wasm::ValType::make(wasm::I64), wasm::VAR); + auto const_f32_import = wasm::Global::make(store, const_f32_type.get(), wasm::Val::f32(1)); + auto const_i64_import = wasm::Global::make(store, const_i64_type.get(), wasm::Val::i64(2)); + auto var_f32_import = wasm::Global::make(store, var_f32_type.get(), wasm::Val::f32(3)); + auto var_i64_import = wasm::Global::make(store, var_i64_type.get(), wasm::Val::i64(4)); + + // Instantiate. + std::cout << "Instantiating module..." << std::endl; + wasm::Extern* imports[] = { + const_f32_import.get(), const_i64_import.get(), + var_f32_import.get(), var_i64_import.get() + }; + auto instance = wasm::Instance::make(store, module.get(), imports); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + std::cout << "Extracting exports..." << std::endl; + auto exports = instance->exports(); + size_t i = 0; + auto const_f32_export = get_export_global(exports, i++); + auto const_i64_export = get_export_global(exports, i++); + auto var_f32_export = get_export_global(exports, i++); + auto var_i64_export = get_export_global(exports, i++); + auto get_const_f32_import = get_export_func(exports, i++); + auto get_const_i64_import = get_export_func(exports, i++); + auto get_var_f32_import = get_export_func(exports, i++); + auto get_var_i64_import = get_export_func(exports, i++); + auto get_const_f32_export = get_export_func(exports, i++); + auto get_const_i64_export = get_export_func(exports, i++); + auto get_var_f32_export = get_export_func(exports, i++); + auto get_var_i64_export = get_export_func(exports, i++); + auto set_var_f32_import = get_export_func(exports, i++); + auto set_var_i64_import = get_export_func(exports, i++); + auto set_var_f32_export = get_export_func(exports, i++); + auto set_var_i64_export = get_export_func(exports, i++); + + // Interact. + std::cout << "Accessing globals..." << std::endl; + + // Check initial values. + check(const_f32_import->get().f32(), 1); + check(const_i64_import->get().i64(), 2); + check(var_f32_import->get().f32(), 3); + check(var_i64_import->get().i64(), 4); + check(const_f32_export->get().f32(), 5); + check(const_i64_export->get().i64(), 6); + check(var_f32_export->get().f32(), 7); + check(var_i64_export->get().i64(), 8); + + check(call(get_const_f32_import).f32(), 1); + check(call(get_const_i64_import).i64(), 2); + check(call(get_var_f32_import).f32(), 3); + check(call(get_var_i64_import).i64(), 4); + check(call(get_const_f32_export).f32(), 5); + check(call(get_const_i64_export).i64(), 6); + check(call(get_var_f32_export).f32(), 7); + check(call(get_var_i64_export).i64(), 8); + + // Modify variables through API and check again. + var_f32_import->set(wasm::Val::f32(33)); + var_i64_import->set(wasm::Val::i64(34)); + var_f32_export->set(wasm::Val::f32(37)); + var_i64_export->set(wasm::Val::i64(38)); + + check(var_f32_import->get().f32(), 33); + check(var_i64_import->get().i64(), 34); + check(var_f32_export->get().f32(), 37); + check(var_i64_export->get().i64(), 38); + + check(call(get_var_f32_import).f32(), 33); + check(call(get_var_i64_import).i64(), 34); + check(call(get_var_f32_export).f32(), 37); + check(call(get_var_i64_export).i64(), 38); + + // Modify variables through calls and check again. + call(set_var_f32_import, wasm::Val::f32(73)); + call(set_var_i64_import, wasm::Val::i64(74)); + call(set_var_f32_export, wasm::Val::f32(77)); + call(set_var_i64_export, wasm::Val::i64(78)); + + check(var_f32_import->get().f32(), 73); + check(var_i64_import->get().i64(), 74); + check(var_f32_export->get().f32(), 77); + check(var_i64_export->get().i64(), 78); + + check(call(get_var_f32_import).f32(), 73); + check(call(get_var_i64_import).i64(), 74); + check(call(get_var_f32_export).f32(), 77); + check(call(get_var_i64_export).i64(), 78); + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/global.wasm b/deps/v8/third_party/wasm-api/example/global.wasm Binary files differnew file mode 100644 index 0000000000..0e76863278 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/global.wasm diff --git a/deps/v8/third_party/wasm-api/example/global.wat b/deps/v8/third_party/wasm-api/example/global.wat new file mode 100644 index 0000000000..dea085772b --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/global.wat @@ -0,0 +1,27 @@ +(module + (global $f32_import (import "" "const f32") f32) + (global $i64_import (import "" "const i64") i64) + (global $mut_f32_import (import "" "var f32") (mut f32)) + (global $mut_i64_import (import "" "var i64") (mut i64)) + + (global $f32_export (export "const f32") f32 (f32.const 5)) + (global $i64_export (export "const i64") i64 (i64.const 6)) + (global $mut_f32_export (export "var f32") (mut f32) (f32.const 7)) + (global $mut_i64_export (export "var i64") (mut i64) (i64.const 8)) + + (func (export "get const f32 import") (result f32) (global.get $f32_import)) + (func (export "get const i64 import") (result i64) (global.get $i64_import)) + (func (export "get var f32 import") (result f32) (global.get $mut_f32_import)) + (func (export "get var i64 import") (result i64) (global.get $mut_i64_import)) + + (func (export "get const f32 export") (result f32) (global.get $f32_export)) + (func (export "get const i64 export") (result i64) (global.get $i64_export)) + (func (export "get var f32 export") (result f32) (global.get $mut_f32_export)) + (func (export "get var i64 export") (result i64) (global.get $mut_i64_export)) + + (func (export "set var f32 import") (param f32) (global.set $mut_f32_import (local.get 0))) + (func (export "set var i64 import") (param i64) (global.set $mut_i64_import (local.get 0))) + + (func (export "set var f32 export") (param f32) (global.set $mut_f32_export (local.get 0))) + (func (export "set var f64 export") (param i64) (global.set $mut_i64_export (local.get 0))) +) diff --git a/deps/v8/third_party/wasm-api/example/hello.c b/deps/v8/third_party/wasm-api/example/hello.c new file mode 100644 index 0000000000..b1c8c5fee5 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/hello.c @@ -0,0 +1,107 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* hello_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n"); + printf("> Hello World!\n"); + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("hello.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* hello_type = wasm_functype_new_0_0(); + own wasm_func_t* hello_func = + wasm_func_new(store, hello_type, hello_callback); + + wasm_functype_delete(hello_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) }; + own wasm_instance_t* instance = wasm_instance_new(store, module, imports); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(hello_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + if (wasm_func_call(run_func, NULL, NULL)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/hello.cc b/deps/v8/third_party/wasm-api/example/hello.cc new file mode 100644 index 0000000000..4956be885f --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/hello.cc @@ -0,0 +1,91 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + + +// A function to be called from Wasm code. +auto hello_callback( + const wasm::Val args[], wasm::Val results[] +) -> wasm::own<wasm::Trap*> { + std::cout << "Calling back..." << std::endl; + std::cout << "> Hello world!" << std::endl; + return nullptr; +} + + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("hello.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Create external print functions. + std::cout << "Creating callback..." << std::endl; + auto hello_type = wasm::FuncType::make( + wasm::vec<wasm::ValType*>::make(), wasm::vec<wasm::ValType*>::make() + ); + auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback); + + // Instantiate. + std::cout << "Instantiating module..." << std::endl; + wasm::Extern* imports[] = {hello_func.get()}; + auto instance = wasm::Instance::make(store, module.get(), imports); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + std::cout << "Extracting export..." << std::endl; + auto exports = instance->exports(); + if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) { + std::cout << "> Error accessing export!" << std::endl; + return; + } + auto run_func = exports[0]->func(); + + // Call. + std::cout << "Calling export..." << std::endl; + if (run_func->call()) { + std::cout << "> Error calling function!" << std::endl; + return; + } + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/hello.wasm b/deps/v8/third_party/wasm-api/example/hello.wasm Binary files differnew file mode 100644 index 0000000000..2207c03eea --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/hello.wasm diff --git a/deps/v8/third_party/wasm-api/example/hello.wat b/deps/v8/third_party/wasm-api/example/hello.wat new file mode 100644 index 0000000000..1c56c55822 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/hello.wat @@ -0,0 +1,4 @@ +(module + (func $hello (import "" "hello")) + (func (export "run") (call $hello)) +) diff --git a/deps/v8/third_party/wasm-api/example/memory.c b/deps/v8/third_party/wasm-api/example/memory.c new file mode 100644 index 0000000000..64b0f86b51 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/memory.c @@ -0,0 +1,217 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + + +wasm_memory_t* get_export_memory(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_memory(exports->data[i])) { + printf("> Error accessing memory export %zu!\n", i); + exit(1); + } + return wasm_extern_as_memory(exports->data[i]); +} + +wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) { + printf("> Error accessing function export %zu!\n", i); + exit(1); + } + return wasm_extern_as_func(exports->data[i]); +} + + +void check(bool success) { + if (!success) { + printf("> Error, expected success\n"); + exit(1); + } +} + +void check_call(wasm_func_t* func, wasm_val_t args[], int32_t expected) { + wasm_val_t results[1]; + if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) { + printf("> Error on result\n"); + exit(1); + } +} + +void check_call0(wasm_func_t* func, int32_t expected) { + check_call(func, NULL, expected); +} + +void check_call1(wasm_func_t* func, int32_t arg, int32_t expected) { + wasm_val_t args[] = { {.kind = WASM_I32, .of = {.i32 = arg}} }; + check_call(func, args, expected); +} + +void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { + wasm_val_t args[2] = { + {.kind = WASM_I32, .of = {.i32 = arg1}}, + {.kind = WASM_I32, .of = {.i32 = arg2}} + }; + check_call(func, args, expected); +} + +void check_ok(wasm_func_t* func, wasm_val_t args[]) { + if (wasm_func_call(func, args, NULL)) { + printf("> Error on result, expected empty\n"); + exit(1); + } +} + +void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) { + wasm_val_t args[2] = { + {.kind = WASM_I32, .of = {.i32 = arg1}}, + {.kind = WASM_I32, .of = {.i32 = arg2}} + }; + check_ok(func, args); +} + +void check_trap(wasm_func_t* func, wasm_val_t args[]) { + wasm_val_t results[1]; + own wasm_trap_t* trap = wasm_func_call(func, args, results); + if (! trap) { + printf("> Error on result, expected trap\n"); + exit(1); + } + wasm_trap_delete(trap); +} + +void check_trap1(wasm_func_t* func, int32_t arg) { + wasm_val_t args[1] = { {.kind = WASM_I32, .of = {.i32 = arg}} }; + check_trap(func, args); +} + +void check_trap2(wasm_func_t* func, int32_t arg1, int32_t arg2) { + wasm_val_t args[2] = { + {.kind = WASM_I32, .of = {.i32 = arg1}}, + {.kind = WASM_I32, .of = {.i32 = arg2}} + }; + check_trap(func, args); +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("memory.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Instantiate. + printf("Instantiating module...\n"); + own wasm_instance_t* instance = wasm_instance_new(store, module, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + size_t i = 0; + wasm_memory_t* memory = get_export_memory(&exports, i++); + wasm_func_t* size_func = get_export_func(&exports, i++); + wasm_func_t* load_func = get_export_func(&exports, i++); + wasm_func_t* store_func = get_export_func(&exports, i++); + + wasm_module_delete(module); + + // Check initial memory. + printf("Checking memory...\n"); + check(wasm_memory_size(memory) == 2); + check(wasm_memory_data_size(memory) == 0x20000); + check(wasm_memory_data(memory)[0] == 0); + check(wasm_memory_data(memory)[0x1000] == 1); + check(wasm_memory_data(memory)[0x1003] == 4); + + check_call0(size_func, 2); + check_call1(load_func, 0, 0); + check_call1(load_func, 0x1000, 1); + check_call1(load_func, 0x1003, 4); + check_call1(load_func, 0x1ffff, 0); + check_trap1(load_func, 0x20000); + + // Mutate memory. + printf("Mutating memory...\n"); + wasm_memory_data(memory)[0x1003] = 5; + check_ok2(store_func, 0x1002, 6); + check_trap2(store_func, 0x20000, 0); + + check(wasm_memory_data(memory)[0x1002] == 6); + check(wasm_memory_data(memory)[0x1003] == 5); + check_call1(load_func, 0x1002, 6); + check_call1(load_func, 0x1003, 5); + + // Grow memory. + printf("Growing memory...\n"); + check(wasm_memory_grow(memory, 1)); + check(wasm_memory_size(memory) == 3); + check(wasm_memory_data_size(memory) == 0x30000); + + check_call1(load_func, 0x20000, 0); + check_ok2(store_func, 0x20000, 0); + check_trap1(load_func, 0x30000); + check_trap2(store_func, 0x30000, 0); + + check(! wasm_memory_grow(memory, 1)); + check(wasm_memory_grow(memory, 0)); + + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + + // Create stand-alone memory. + // TODO(wasm+): Once Wasm allows multiple memories, turn this into import. + printf("Creating stand-alone memory...\n"); + wasm_limits_t limits = {5, 5}; + own wasm_memorytype_t* memorytype = wasm_memorytype_new(&limits); + own wasm_memory_t* memory2 = wasm_memory_new(store, memorytype); + check(wasm_memory_size(memory2) == 5); + check(! wasm_memory_grow(memory2, 1)); + check(wasm_memory_grow(memory2, 0)); + + wasm_memorytype_delete(memorytype); + wasm_memory_delete(memory2); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/memory.cc b/deps/v8/third_party/wasm-api/example/memory.cc new file mode 100644 index 0000000000..fb50565c85 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/memory.cc @@ -0,0 +1,169 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + + +auto get_export_memory(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Memory* { + if (exports.size() <= i || !exports[i]->memory()) { + std::cout << "> Error accessing memory export " << i << "!" << std::endl; + exit(1); + } + return exports[i]->memory(); +} + +auto get_export_func(const wasm::vec<wasm::Extern*>& exports, size_t i) -> const wasm::Func* { + if (exports.size() <= i || !exports[i]->func()) { + std::cout << "> Error accessing function export " << i << "!" << std::endl; + exit(1); + } + return exports[i]->func(); +} + +template<class T, class U> +void check(T actual, U expected) { + if (actual != expected) { + std::cout << "> Error on result, expected " << expected << ", got " << actual << std::endl; + exit(1); + } +} + +template<class... Args> +void check_ok(const wasm::Func* func, Args... xs) { + wasm::Val args[] = {wasm::Val::i32(xs)...}; + if (func->call(args)) { + std::cout << "> Error on result, expected return" << std::endl; + exit(1); + } +} + +template<class... Args> +void check_trap(const wasm::Func* func, Args... xs) { + wasm::Val args[] = {wasm::Val::i32(xs)...}; + if (! func->call(args)) { + std::cout << "> Error on result, expected trap" << std::endl; + exit(1); + } +} + +template<class... Args> +auto call(const wasm::Func* func, Args... xs) -> int32_t { + wasm::Val args[] = {wasm::Val::i32(xs)...}; + wasm::Val results[1]; + if (func->call(args, results)) { + std::cout << "> Error on result, expected return" << std::endl; + exit(1); + } + return results[0].i32(); +} + + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("memory.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Instantiate. + std::cout << "Instantiating module..." << std::endl; + auto instance = wasm::Instance::make(store, module.get(), nullptr); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + std::cout << "Extracting exports..." << std::endl; + auto exports = instance->exports(); + size_t i = 0; + auto memory = get_export_memory(exports, i++); + auto size_func = get_export_func(exports, i++); + auto load_func = get_export_func(exports, i++); + auto store_func = get_export_func(exports, i++); + + // Check initial memory. + std::cout << "Checking memory..." << std::endl; + check(memory->size(), 2u); + check(memory->data_size(), 0x20000u); + check(memory->data()[0], 0); + check(memory->data()[0x1000], 1); + check(memory->data()[0x1003], 4); + + check(call(size_func), 2); + check(call(load_func, 0), 0); + check(call(load_func, 0x1000), 1); + check(call(load_func, 0x1003), 4); + check(call(load_func, 0x1ffff), 0); + check_trap(load_func, 0x20000); + + // Mutate memory. + std::cout << "Mutating memory..." << std::endl; + memory->data()[0x1003] = 5; + check_ok(store_func, 0x1002, 6); + check_trap(store_func, 0x20000, 0); + + check(memory->data()[0x1002], 6); + check(memory->data()[0x1003], 5); + check(call(load_func, 0x1002), 6); + check(call(load_func, 0x1003), 5); + + // Grow memory. + std::cout << "Growing memory..." << std::endl; + check(memory->grow(1), true); + check(memory->size(), 3u); + check(memory->data_size(), 0x30000u); + + check(call(load_func, 0x20000), 0); + check_ok(store_func, 0x20000, 0); + check_trap(load_func, 0x30000); + check_trap(store_func, 0x30000, 0); + + check(memory->grow(1), false); + check(memory->grow(0), true); + + // Create stand-alone memory. + // TODO(wasm+): Once Wasm allows multiple memories, turn this into import. + std::cout << "Creating stand-alone memory..." << std::endl; + auto memorytype = wasm::MemoryType::make(wasm::Limits(5, 5)); + auto memory2 = wasm::Memory::make(store, memorytype.get()); + check(memory2->size(), 5u); + check(memory2->grow(1), false); + check(memory2->grow(0), true); + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/memory.wasm b/deps/v8/third_party/wasm-api/example/memory.wasm Binary files differnew file mode 100644 index 0000000000..6f6518b187 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/memory.wasm diff --git a/deps/v8/third_party/wasm-api/example/memory.wat b/deps/v8/third_party/wasm-api/example/memory.wat new file mode 100644 index 0000000000..4cf43e2c7d --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/memory.wat @@ -0,0 +1,11 @@ +(module + (memory (export "memory") 2 3) + + (func (export "size") (result i32) (memory.size)) + (func (export "load") (param i32) (result i32) (i32.load8_s (local.get 0))) + (func (export "store") (param i32 i32) + (i32.store8 (local.get 0) (local.get 1)) + ) + + (data (i32.const 0x1000) "\01\02\03\04") +) diff --git a/deps/v8/third_party/wasm-api/example/reflect.c b/deps/v8/third_party/wasm-api/example/reflect.c new file mode 100644 index 0000000000..a210a85c15 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/reflect.c @@ -0,0 +1,164 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +void print_mutability(wasm_mutability_t mut) { + switch (mut) { + case WASM_VAR: printf("var"); break; + case WASM_CONST: printf("const"); break; + } +} + +void print_limits(const wasm_limits_t* limits) { + printf("%ud", limits->min); + if (limits->max < wasm_limits_max_default) printf(" %ud", limits->max); +} + +void print_valtype(const wasm_valtype_t* type) { + switch (wasm_valtype_kind(type)) { + case WASM_I32: printf("i32"); break; + case WASM_I64: printf("i64"); break; + case WASM_F32: printf("f32"); break; + case WASM_F64: printf("f64"); break; + case WASM_ANYREF: printf("anyref"); break; + case WASM_FUNCREF: printf("funcref"); break; + } +} + +void print_valtypes(const wasm_valtype_vec_t* types) { + bool first = true; + for (size_t i = 0; i < types->size; ++i) { + if (first) { + first = false; + } else { + printf(" "); + } + print_valtype(types->data[i]); + } +} + +void print_externtype(const wasm_externtype_t* type) { + switch (wasm_externtype_kind(type)) { + case WASM_EXTERN_FUNC: { + const wasm_functype_t* functype = wasm_externtype_as_functype_const(type); + printf("func "); + print_valtypes(wasm_functype_params(functype)); + printf(" -> "); + print_valtypes(wasm_functype_results(functype)); + } break; + case WASM_EXTERN_GLOBAL: { + const wasm_globaltype_t* globaltype = wasm_externtype_as_globaltype_const(type); + printf("global "); + print_mutability(wasm_globaltype_mutability(globaltype)); + printf(" "); + print_valtype(wasm_globaltype_content(globaltype)); + } break; + case WASM_EXTERN_TABLE: { + const wasm_tabletype_t* tabletype = wasm_externtype_as_tabletype_const(type); + printf("table "); + print_limits(wasm_tabletype_limits(tabletype)); + printf(" "); + print_valtype(wasm_tabletype_element(tabletype)); + } break; + case WASM_EXTERN_MEMORY: { + const wasm_memorytype_t* memorytype = wasm_externtype_as_memorytype_const(type); + printf("memory "); + print_limits(wasm_memorytype_limits(memorytype)); + } break; + } +} + +void print_name(const wasm_name_t* name) { + printf("\"%.*s\"", (int)name->size, name->data); +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("reflect.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Instantiate. + printf("Instantiating module...\n"); + own wasm_instance_t* instance = wasm_instance_new(store, module, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + // Extract export. + printf("Extracting export...\n"); + own wasm_exporttype_vec_t export_types; + own wasm_extern_vec_t exports; + wasm_module_exports(module, &export_types); + wasm_instance_exports(instance, &exports); + assert(exports.size == export_types.size); + + for (size_t i = 0; i < exports.size; ++i) { + assert(wasm_extern_kind(exports.data[i]) == wasm_externtype_kind(wasm_exporttype_type(export_types.data[i]))); + printf("> export %zu ", i); + print_name(wasm_exporttype_name(export_types.data[i])); + printf("\n"); + printf(">> initial: "); + print_externtype(wasm_exporttype_type(export_types.data[i])); + printf("\n"); + printf(">> current: "); + own wasm_externtype_t* current = wasm_extern_type(exports.data[i]); + print_externtype(current); + wasm_externtype_delete(current); + printf("\n"); + if (wasm_extern_kind(exports.data[i]) == WASM_EXTERN_FUNC) { + wasm_func_t* func = wasm_extern_as_func(exports.data[i]); + printf(">> in-arity: %zu", wasm_func_param_arity(func)); + printf(", out-arity: %zu\n", wasm_func_result_arity(func)); + } + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + wasm_extern_vec_delete(&exports); + wasm_exporttype_vec_delete(&export_types); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/reflect.cc b/deps/v8/third_party/wasm-api/example/reflect.cc new file mode 100644 index 0000000000..c04b9e4d4e --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/reflect.cc @@ -0,0 +1,138 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + + +auto operator<<(std::ostream& out, wasm::Mutability mut) -> std::ostream& { + switch (mut) { + case wasm::VAR: return out << "var"; + case wasm::CONST: return out << "const"; + } + return out; +} + +auto operator<<(std::ostream& out, wasm::Limits limits) -> std::ostream& { + out << limits.min; + if (limits.max < wasm::Limits(0).max) out << " " << limits.max; + return out; +} + +auto operator<<(std::ostream& out, const wasm::ValType& type) -> std::ostream& { + switch (type.kind()) { + case wasm::I32: return out << "i32"; + case wasm::I64: return out << "i64"; + case wasm::F32: return out << "f32"; + case wasm::F64: return out << "f64"; + case wasm::ANYREF: return out << "anyref"; + case wasm::FUNCREF: return out << "funcref"; + } + return out; +} + +auto operator<<(std::ostream& out, const wasm::vec<wasm::ValType*>& types) -> std::ostream& { + bool first = true; + for (size_t i = 0; i < types.size(); ++i) { + if (first) { + first = false; + } else { + out << " "; + } + out << *types[i].get(); + } + return out; +} + +auto operator<<(std::ostream& out, const wasm::ExternType& type) -> std::ostream& { + switch (type.kind()) { + case wasm::EXTERN_FUNC: { + out << "func " << type.func()->params() << " -> " << type.func()->results(); + } break; + case wasm::EXTERN_GLOBAL: { + out << "global " << type.global()->mutability() << " " << *type.global()->content(); + } break; + case wasm::EXTERN_TABLE: { + out << "table " << type.table()->limits() << " " << *type.table()->element(); + } break; + case wasm::EXTERN_MEMORY: { + out << "memory " << type.memory()->limits(); + } break; + } + return out; +} + +auto operator<<(std::ostream& out, const wasm::Name& name) -> std::ostream& { + out << "\"" << std::string(name.get(), name.size()) << "\""; + return out; +} + + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("reflect.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Instantiate. + std::cout << "Instantiating module..." << std::endl; + auto instance = wasm::Instance::make(store, module.get(), nullptr); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract exports. + std::cout << "Extracting export..." << std::endl; + auto export_types = module->exports(); + auto exports = instance->exports(); + assert(exports.size() == export_types.size()); + + for (size_t i = 0; i < exports.size(); ++i) { + assert(exports[i]->kind() == export_types[i]->type()->kind()); + std::cout << "> export " << i << " " << export_types[i]->name() << std::endl; + std::cout << ">> initial: " << *export_types[i]->type() << std::endl; + std::cout << ">> current: " << *exports[i]->type() << std::endl; + if (exports[i]->kind() == wasm::EXTERN_FUNC) { + auto func = exports[i]->func(); + std::cout << ">> in-arity: " << func->param_arity(); + std::cout << ", out-arity: " << func->result_arity() << std::endl; + } + } + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/reflect.wasm b/deps/v8/third_party/wasm-api/example/reflect.wasm Binary files differnew file mode 100644 index 0000000000..15a68fe8f7 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/reflect.wasm diff --git a/deps/v8/third_party/wasm-api/example/reflect.wat b/deps/v8/third_party/wasm-api/example/reflect.wat new file mode 100644 index 0000000000..261dfd3c33 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/reflect.wat @@ -0,0 +1,6 @@ +(module + (func (export "func") (param i32 f64 f32) (result i32) (unreachable)) + (global (export "global") f64 (f64.const 0)) + (table (export "table") 0 50 anyfunc) + (memory (export "memory") 1) +) diff --git a/deps/v8/third_party/wasm-api/example/serialize.c b/deps/v8/third_party/wasm-api/example/serialize.c new file mode 100644 index 0000000000..8c7efc2ee9 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/serialize.c @@ -0,0 +1,122 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* hello_callback(const wasm_val_t args[], wasm_val_t results[]) { + printf("Calling back...\n"); + printf("> Hello World!\n"); + return NULL; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("serialize.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Serialize module. + printf("Serializing module...\n"); + own wasm_byte_vec_t serialized; + wasm_module_serialize(module, &serialized); + + wasm_module_delete(module); + + // Deserialize module. + printf("Deserializing module...\n"); + own wasm_module_t* deserialized = wasm_module_deserialize(store, &serialized); + if (!deserialized) { + printf("> Error deserializing module!\n"); + return 1; + } + + wasm_byte_vec_delete(&serialized); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* hello_type = wasm_functype_new_0_0(); + own wasm_func_t* hello_func = + wasm_func_new(store, hello_type, hello_callback); + + wasm_functype_delete(hello_type); + + // Instantiate. + printf("Instantiating deserialized module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(hello_func) }; + own wasm_instance_t* instance = wasm_instance_new(store, deserialized, imports); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(hello_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t* run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(deserialized); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + if (wasm_func_call(run_func, NULL, NULL)) { + printf("> Error calling function!\n"); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/serialize.cc b/deps/v8/third_party/wasm-api/example/serialize.cc new file mode 100644 index 0000000000..895ef396e0 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/serialize.cc @@ -0,0 +1,103 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + + +// A function to be called from Wasm code. +auto hello_callback( + const wasm::Val args[], wasm::Val results[] +) -> wasm::own<wasm::Trap*> { + std::cout << "Calling back..." << std::endl; + std::cout << "> Hello world!" << std::endl; + return nullptr; +} + + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("serialize.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Serialize module. + std::cout << "Serializing module..." << std::endl; + auto serialized = module->serialize(); + + // Deserialize module. + std::cout << "Deserializing module..." << std::endl; + auto deserialized = wasm::Module::deserialize(store, serialized); + if (!deserialized) { + std::cout << "> Error deserializing module!" << std::endl; + return; + } + + // Create external print functions. + std::cout << "Creating callback..." << std::endl; + auto hello_type = wasm::FuncType::make( + wasm::vec<wasm::ValType*>::make(), wasm::vec<wasm::ValType*>::make() + ); + auto hello_func = wasm::Func::make(store, hello_type.get(), hello_callback); + + // Instantiate. + std::cout << "Instantiating deserialized module..." << std::endl; + wasm::Extern* imports[] = {hello_func.get()}; + auto instance = wasm::Instance::make(store, deserialized.get(), imports); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + std::cout << "Extracting export..." << std::endl; + auto exports = instance->exports(); + if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) { + std::cout << "> Error accessing export!" << std::endl; + return; + } + auto run_func = exports[0]->func(); + + // Call. + std::cout << "Calling export..." << std::endl; + if (! run_func->call()) { + std::cout << "> Error calling function!" << std::endl; + return; + } + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/serialize.wasm b/deps/v8/third_party/wasm-api/example/serialize.wasm Binary files differnew file mode 100644 index 0000000000..2207c03eea --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/serialize.wasm diff --git a/deps/v8/third_party/wasm-api/example/serialize.wat b/deps/v8/third_party/wasm-api/example/serialize.wat new file mode 100644 index 0000000000..1c56c55822 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/serialize.wat @@ -0,0 +1,4 @@ +(module + (func $hello (import "" "hello")) + (func (export "run") (call $hello)) +) diff --git a/deps/v8/third_party/wasm-api/example/table.c b/deps/v8/third_party/wasm-api/example/table.c new file mode 100644 index 0000000000..8fec71f23f --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/table.c @@ -0,0 +1,208 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* neg_callback( + const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n"); + results[0].kind = WASM_I32; + results[0].of.i32 = -args[0].of.i32; + return NULL; +} + + +wasm_table_t* get_export_table(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_table(exports->data[i])) { + printf("> Error accessing table export %zu!\n", i); + exit(1); + } + return wasm_extern_as_table(exports->data[i]); +} + +wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { + if (exports->size <= i || !wasm_extern_as_func(exports->data[i])) { + printf("> Error accessing function export %zu!\n", i); + exit(1); + } + return wasm_extern_as_func(exports->data[i]); +} + + +void check(bool success) { + if (!success) { + printf("> Error, expected success\n"); + exit(1); + } +} + +void check_table(wasm_table_t* table, int32_t i, bool expect_set) { + own wasm_ref_t* ref = wasm_table_get(table, i); + check((ref != NULL) == expect_set); + if (ref) wasm_ref_delete(ref); +} + +void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) { + wasm_val_t args[2] = { + {.kind = WASM_I32, .of = {.i32 = arg1}}, + {.kind = WASM_I32, .of = {.i32 = arg2}} + }; + wasm_val_t results[1]; + if (wasm_func_call(func, args, results) || results[0].of.i32 != expected) { + printf("> Error on result\n"); + exit(1); + } +} + +void check_trap(wasm_func_t* func, int32_t arg1, int32_t arg2) { + wasm_val_t args[2] = { + {.kind = WASM_I32, .of = {.i32 = arg1}}, + {.kind = WASM_I32, .of = {.i32 = arg2}} + }; + own wasm_trap_t* trap = wasm_func_call(func, args, NULL); + if (! trap) { + printf("> Error on result, expected trap\n"); + exit(1); + } + wasm_trap_delete(trap); +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("table.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Instantiate. + printf("Instantiating module...\n"); + own wasm_instance_t* instance = wasm_instance_new(store, module, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + size_t i = 0; + wasm_table_t* table = get_export_table(&exports, i++); + wasm_func_t* call_indirect = get_export_func(&exports, i++); + wasm_func_t* f = get_export_func(&exports, i++); + wasm_func_t* g = get_export_func(&exports, i++); + + wasm_module_delete(module); + + // Create external function. + printf("Creating callback...\n"); + own wasm_functype_t* neg_type = wasm_functype_new_1_1(wasm_valtype_new_i32(), wasm_valtype_new_i32()); + own wasm_func_t* h = wasm_func_new(store, neg_type, neg_callback); + + wasm_functype_delete(neg_type); + + // Check initial table. + printf("Checking table...\n"); + check(wasm_table_size(table) == 2); + check_table(table, 0, false); + check_table(table, 1, true); + check_trap(call_indirect, 0, 0); + check_call(call_indirect, 7, 1, 7); + check_trap(call_indirect, 0, 2); + + // Mutate table. + printf("Mutating table...\n"); + check(wasm_table_set(table, 0, wasm_func_as_ref(g))); + check(wasm_table_set(table, 1, NULL)); + check(! wasm_table_set(table, 2, wasm_func_as_ref(f))); + check_table(table, 0, true); + check_table(table, 1, false); + check_call(call_indirect, 7, 0, 666); + check_trap(call_indirect, 0, 1); + check_trap(call_indirect, 0, 2); + + // Grow table. + printf("Growing table...\n"); + check(wasm_table_grow(table, 3, NULL)); + check(wasm_table_size(table) == 5); + check(wasm_table_set(table, 2, wasm_func_as_ref(f))); + check(wasm_table_set(table, 3, wasm_func_as_ref(h))); + check(! wasm_table_set(table, 5, NULL)); + check_table(table, 2, true); + check_table(table, 3, true); + check_table(table, 4, false); + check_call(call_indirect, 5, 2, 5); + check_call(call_indirect, 6, 3, -6); + check_trap(call_indirect, 0, 4); + check_trap(call_indirect, 0, 5); + + check(wasm_table_grow(table, 2, wasm_func_as_ref(f))); + check(wasm_table_size(table) == 7); + check_table(table, 5, true); + check_table(table, 6, true); + + check(! wasm_table_grow(table, 5, NULL)); + check(wasm_table_grow(table, 3, NULL)); + check(wasm_table_grow(table, 0, NULL)); + + wasm_func_delete(h); + wasm_extern_vec_delete(&exports); + wasm_instance_delete(instance); + + // Create stand-alone table. + // TODO(wasm+): Once Wasm allows multiple tables, turn this into import. + printf("Creating stand-alone table...\n"); + wasm_limits_t limits = {5, 5}; + own wasm_tabletype_t* tabletype = + wasm_tabletype_new(wasm_valtype_new(WASM_FUNCREF), &limits); + own wasm_table_t* table2 = wasm_table_new(store, tabletype, NULL); + check(wasm_table_size(table2) == 5); + check(! wasm_table_grow(table2, 1, NULL)); + check(wasm_table_grow(table2, 0, NULL)); + + wasm_tabletype_delete(tabletype); + wasm_table_delete(table2); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/table.cc b/deps/v8/third_party/wasm-api/example/table.cc new file mode 100644 index 0000000000..cb669cdb16 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/table.cc @@ -0,0 +1,189 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + + +// A function to be called from Wasm code. +auto neg_callback( + const wasm::Val args[], wasm::Val results[] +) -> wasm::own<wasm::Trap*> { + std::cout << "Calling back..." << std::endl; + results[0] = wasm::Val(-args[0].i32()); + return nullptr; +} + + +auto get_export_table(wasm::vec<wasm::Extern*>& exports, size_t i) -> wasm::Table* { + if (exports.size() <= i || !exports[i]->table()) { + std::cout << "> Error accessing table export " << i << "!" << std::endl; + exit(1); + } + return exports[i]->table(); +} + +auto get_export_func(const wasm::vec<wasm::Extern*>& exports, size_t i) -> const wasm::Func* { + if (exports.size() <= i || !exports[i]->func()) { + std::cout << "> Error accessing function export " << i << "!" << std::endl; + exit(1); + } + return exports[i]->func(); +} + +template<class T, class U> +void check(T actual, U expected) { + if (actual != expected) { + std::cout << "> Error on result, expected " << expected << ", got " << actual << std::endl; + exit(1); + } +} + +void check(bool success) { + if (! success) { + std::cout << "> Error, expected success" << std::endl; + exit(1); + } +} + +auto call( + const wasm::Func* func, wasm::Val&& arg1, wasm::Val&& arg2 +) -> wasm::Val { + wasm::Val args[2] = {std::move(arg1), std::move(arg2)}; + wasm::Val results[1]; + if (func->call(args, results)) { + std::cout << "> Error on result, expected return" << std::endl; + exit(1); + } + return results[0].copy(); +} + +void check_trap(const wasm::Func* func, wasm::Val&& arg1, wasm::Val&& arg2) { + wasm::Val args[2] = {std::move(arg1), std::move(arg2)}; + wasm::Val results[1]; + if (! func->call(args, results)) { + std::cout << "> Error on result, expected trap" << std::endl; + exit(1); + } +} + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("table.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Instantiate. + std::cout << "Instantiating module..." << std::endl; + auto instance = wasm::Instance::make(store, module.get(), nullptr); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + std::cout << "Extracting exports..." << std::endl; + auto exports = instance->exports(); + size_t i = 0; + auto table = get_export_table(exports, i++); + auto call_indirect = get_export_func(exports, i++); + auto f = get_export_func(exports, i++); + auto g = get_export_func(exports, i++); + + // Create external function. + std::cout << "Creating callback..." << std::endl; + auto neg_type = wasm::FuncType::make( + wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)), + wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)) + ); + auto h = wasm::Func::make(store, neg_type.get(), neg_callback); + + // Check initial table. + std::cout << "Checking table..." << std::endl; + check(table->size(), 2u); + check(table->get(0) == nullptr); + check(table->get(1) != nullptr); + check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(0)); + check(call(call_indirect, wasm::Val::i32(7), wasm::Val::i32(1)).i32(), 7); + check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(2)); + + // Mutate table. + std::cout << "Mutating table..." << std::endl; + check(table->set(0, g)); + check(table->set(1, nullptr)); + check(! table->set(2, f)); + check(table->get(0) != nullptr); + check(table->get(1) == nullptr); + check(call(call_indirect, wasm::Val::i32(7), wasm::Val::i32(0)).i32(), 666); + check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(1)); + check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(2)); + + // Grow table. + std::cout << "Growing table..." << std::endl; + check(table->grow(3)); + check(table->size(), 5u); + check(table->set(2, f)); + check(table->set(3, h.get())); + check(! table->set(5, nullptr)); + check(table->get(2) != nullptr); + check(table->get(3) != nullptr); + check(table->get(4) == nullptr); + check(call(call_indirect, wasm::Val::i32(5), wasm::Val::i32(2)).i32(), 5); + check(call(call_indirect, wasm::Val::i32(6), wasm::Val::i32(3)).i32(), -6); + check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(4)); + check_trap(call_indirect, wasm::Val::i32(0), wasm::Val::i32(5)); + + check(table->grow(2, f)); + check(table->size(), 7u); + check(table->get(5) != nullptr); + check(table->get(6) != nullptr); + + check(! table->grow(5)); + check(table->grow(3)); + check(table->grow(0)); + + // Create stand-alone table. + // TODO(wasm+): Once Wasm allows multiple tables, turn this into import. + std::cout << "Creating stand-alone table..." << std::endl; + auto tabletype = wasm::TableType::make( + wasm::ValType::make(wasm::FUNCREF), wasm::Limits(5, 5)); + auto table2 = wasm::Table::make(store, tabletype.get()); + check(table2->size() == 5); + check(! table2->grow(1)); + check(table2->grow(0)); + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/table.wasm b/deps/v8/third_party/wasm-api/example/table.wasm Binary files differnew file mode 100644 index 0000000000..cdc0d8c35d --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/table.wasm diff --git a/deps/v8/third_party/wasm-api/example/table.wat b/deps/v8/third_party/wasm-api/example/table.wat new file mode 100644 index 0000000000..d3e3a945aa --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/table.wat @@ -0,0 +1,12 @@ +(module + (table (export "table") 2 10 funcref) + + (func (export "call_indirect") (param i32 i32) (result i32) + (call_indirect (param i32) (result i32) (local.get 0) (local.get 1)) + ) + + (func $f (export "f") (param i32) (result i32) (local.get 0)) + (func (export "g") (param i32) (result i32) (i32.const 666)) + + (elem (i32.const 1) $f) +) diff --git a/deps/v8/third_party/wasm-api/example/threads.c b/deps/v8/third_party/wasm-api/example/threads.c new file mode 100644 index 0000000000..2f5b0f3c1f --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/threads.c @@ -0,0 +1,152 @@ +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <unistd.h> + +#include "wasm.h" + +#define own + +const int N_THREADS = 10; +const int N_REPS = 3; + +// A function to be called from Wasm code. +own wasm_trap_t* callback(const wasm_val_t args[], wasm_val_t results[]) { + assert(args[0].kind == WASM_I32); + printf("> Thread %d running\n", args[0].of.i32); + return NULL; +} + + +typedef struct { + wasm_engine_t* engine; + wasm_shared_module_t* module; + int id; +} thread_args; + +void* run(void* args_abs) { + thread_args* args = (thread_args*)args_abs; + + // Rereate store and module. + own wasm_store_t* store = wasm_store_new(args->engine); + own wasm_module_t* module = wasm_module_obtain(store, args->module); + + // Run the example N times. + for (int i = 0; i < N_REPS; ++i) { + usleep(100000); + + // Create imports. + own wasm_functype_t* func_type = wasm_functype_new_1_0(wasm_valtype_new_i32()); + own wasm_func_t* func = wasm_func_new(store, func_type, callback); + wasm_functype_delete(func_type); + + wasm_val_t val = {.kind = WASM_I32, .of = {.i32 = (int32_t)args->id}}; + own wasm_globaltype_t* global_type = + wasm_globaltype_new(wasm_valtype_new_i32(), WASM_CONST); + own wasm_global_t* global = wasm_global_new(store, global_type, &val); + wasm_globaltype_delete(global_type); + + // Instantiate. + const wasm_extern_t* imports[] = { + wasm_func_as_extern(func), wasm_global_as_extern(global), + }; + own wasm_instance_t* instance = wasm_instance_new(store, module, imports); + if (!instance) { + printf("> Error instantiating module!\n"); + return NULL; + } + + wasm_func_delete(func); + wasm_global_delete(global); + + // Extract export. + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return NULL; + } + const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return NULL; + } + + wasm_instance_delete(instance); + + // Call. + if (wasm_func_call(run_func, NULL, NULL)) { + printf("> Error calling function!\n"); + return NULL; + } + + wasm_extern_vec_delete(&exports); + } + + wasm_module_delete(module); + wasm_store_delete(store); + + free(args_abs); + + return NULL; +} + +int main(int argc, const char *argv[]) { + // Initialize. + wasm_engine_t* engine = wasm_engine_new(); + + // Load binary. + FILE* file = fopen("threads.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile and share. + own wasm_store_t* store = wasm_store_new(engine); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + own wasm_shared_module_t* shared = wasm_module_share(module); + + wasm_module_delete(module); + wasm_store_delete(store); + + // Spawn threads. + pthread_t threads[N_THREADS]; + for (int i = 0; i < N_THREADS; i++) { + thread_args* args = malloc(sizeof(thread_args)); + args->id = i; + args->engine = engine; + args->module = shared; + printf("Initializing thread %d...\n", i); + pthread_create(&threads[i], NULL, &run, args); + } + + for (int i = 0; i < N_THREADS; i++) { + printf("Waiting for thread: %d\n", i); + pthread_join(threads[i], NULL); + } + + wasm_shared_module_delete(shared); + wasm_engine_delete(engine); + + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/threads.cc b/deps/v8/third_party/wasm-api/example/threads.cc new file mode 100644 index 0000000000..48b4fcd486 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/threads.cc @@ -0,0 +1,124 @@ +#include <iostream> +#include <fstream> +#include <thread> +#include <mutex> + +#include "wasm.hh" + +const int N_THREADS = 10; +const int N_REPS = 3; + +// A function to be called from Wasm code. +auto callback( + void* env, const wasm::Val args[], wasm::Val results[] +) -> wasm::own<wasm::Trap*> { + assert(args[0].kind() == wasm::I32); + std::lock_guard<std::mutex>(*reinterpret_cast<std::mutex*>(env)); + std::cout << "Thread " << args[0].i32() << " running..." << std::endl; + std::cout.flush(); + return nullptr; +} + + +void run( + wasm::Engine* engine, const wasm::Shared<wasm::Module>* shared, + std::mutex* mutex, int id +) { + // Create store. + auto store_ = wasm::Store::make(engine); + auto store = store_.get(); + + // Obtain. + auto module = wasm::Module::obtain(store, shared); + if (!module) { + std::lock_guard<std::mutex> lock(*mutex); + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Run the example N times. + for (int i = 0; i < N_REPS; ++i) { + std::this_thread::sleep_for(std::chrono::nanoseconds(100000)); + + // Create imports. + auto func_type = wasm::FuncType::make( + wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)), + wasm::vec<wasm::ValType*>::make() + ); + auto func = wasm::Func::make(store, func_type.get(), callback, mutex); + + auto global_type = wasm::GlobalType::make( + wasm::ValType::make(wasm::I32), wasm::CONST); + auto global = wasm::Global::make( + store, global_type.get(), wasm::Val::i32(i)); + + // Instantiate. + wasm::Extern* imports[] = {func.get(), global.get()}; + auto instance = wasm::Instance::make(store, module.get(), imports); + if (!instance) { + std::lock_guard<std::mutex> lock(*mutex); + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + auto exports = instance->exports(); + if (exports.size() == 0 || exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func()) { + std::lock_guard<std::mutex> lock(*mutex); + std::cout << "> Error accessing export!" << std::endl; + return; + } + auto run_func = exports[0]->func(); + + // Call. + run_func->call(); + } +} + +int main(int argc, const char *argv[]) { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("threads.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return 1; + } + + // Compile and share. + std::cout << "Compiling and sharing module..." << std::endl; + auto store = wasm::Store::make(engine.get()); + auto module = wasm::Module::make(store.get(), binary); + auto shared = module->share(); + + // Spawn threads. + std::cout << "Spawning threads..." << std::endl; + std::mutex mutex; + std::thread threads[N_THREADS]; + for (int i = 0; i < N_THREADS; ++i) { + { + std::lock_guard<std::mutex> lock(mutex); + std::cout << "Initializing thread " << i << "..." << std::endl; + } + threads[i] = std::thread(run, engine.get(), shared.get(), &mutex, i); + } + + for (int i = 0; i < N_THREADS; ++i) { + { + std::lock_guard<std::mutex> lock(mutex); + std::cout << "Waiting for thread " << i << "..." << std::endl; + } + threads[i].join(); + } + + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/threads.wasm b/deps/v8/third_party/wasm-api/example/threads.wasm Binary files differnew file mode 100644 index 0000000000..9a5c19d0ac --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/threads.wasm diff --git a/deps/v8/third_party/wasm-api/example/threads.wat b/deps/v8/third_party/wasm-api/example/threads.wat new file mode 100644 index 0000000000..29a3bbcc1a --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/threads.wat @@ -0,0 +1,5 @@ +(module + (func $message (import "" "hello") (param i32)) + (global $id (import "" "id") i32) + (func (export "run") (call $message (global.get $id))) +) diff --git a/deps/v8/third_party/wasm-api/example/trap.c b/deps/v8/third_party/wasm-api/example/trap.c new file mode 100644 index 0000000000..74620dce3b --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/trap.c @@ -0,0 +1,121 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "wasm.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t* fail_callback( + void* env, const wasm_val_t args[], wasm_val_t results[] +) { + printf("Calling back...\n"); + own wasm_name_t message; + wasm_name_new_from_string(&message, "callback abort"); + own wasm_trap_t* trap = wasm_trap_new((wasm_store_t*)env, &message); + wasm_name_delete(&message); + return trap; +} + + +int main(int argc, const char* argv[]) { + // Initialize. + printf("Initializing...\n"); + wasm_engine_t* engine = wasm_engine_new(); + wasm_store_t* store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE* file = fopen("trap.wasm", "r"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t* module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t* fail_type = wasm_functype_new_0_1(wasm_valtype_new_i32()); + own wasm_func_t* fail_func = wasm_func_new_with_env(store, fail_type, fail_callback, store, NULL); + + wasm_functype_delete(fail_type); + + // Instantiate. + printf("Instantiating module...\n"); + const wasm_extern_t* imports[] = { wasm_func_as_extern(fail_func) }; + own wasm_instance_t* instance = wasm_instance_new(store, module, imports); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(fail_func); + + // Extract export. + printf("Extracting exports...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size < 2) { + printf("> Error accessing exports!\n"); + return 1; + } + + wasm_module_delete(module); + wasm_instance_delete(instance); + + // Call. + for (int i = 0; i < 2; ++i) { + const wasm_func_t* func = wasm_extern_as_func(exports.data[i]); + if (func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + printf("Calling export %d...\n", i); + own wasm_trap_t* trap = wasm_func_call(func, NULL, NULL); + if (! trap) { + printf("> Error calling function!\n"); + return 1; + } + + printf("Printing message...\n"); + own wasm_name_t message; + wasm_trap_message(trap, &message); + printf("> %s\n", message.data); + + wasm_trap_delete(trap); + wasm_name_delete(&message); + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/deps/v8/third_party/wasm-api/example/trap.cc b/deps/v8/third_party/wasm-api/example/trap.cc new file mode 100644 index 0000000000..3311621724 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/trap.cc @@ -0,0 +1,100 @@ +#include <iostream> +#include <fstream> +#include <cstdlib> +#include <string> +#include <cinttypes> + +#include "wasm.hh" + +// A function to be called from Wasm code. +auto fail_callback( + void* env, const wasm::Val args[], wasm::Val results[] +) -> wasm::own<wasm::Trap*> { + std::cout << "Calling back..." << std::endl; + auto store = reinterpret_cast<wasm::Store*>(env); + auto message = wasm::Name::make(std::string("callback abort")); + return wasm::Trap::make(store, message); +} + + +void run() { + // Initialize. + std::cout << "Initializing..." << std::endl; + auto engine = wasm::Engine::make(); + auto store_ = wasm::Store::make(engine.get()); + auto store = store_.get(); + + // Load binary. + std::cout << "Loading binary..." << std::endl; + std::ifstream file("trap.wasm"); + file.seekg(0, std::ios_base::end); + auto file_size = file.tellg(); + file.seekg(0); + auto binary = wasm::vec<byte_t>::make_uninitialized(file_size); + file.read(binary.get(), file_size); + file.close(); + if (file.fail()) { + std::cout << "> Error loading module!" << std::endl; + return; + } + + // Compile. + std::cout << "Compiling module..." << std::endl; + auto module = wasm::Module::make(store, binary); + if (!module) { + std::cout << "> Error compiling module!" << std::endl; + return; + } + + // Create external print functions. + std::cout << "Creating callback..." << std::endl; + auto fail_type = wasm::FuncType::make( + wasm::vec<wasm::ValType*>::make(), + wasm::vec<wasm::ValType*>::make(wasm::ValType::make(wasm::I32)) + ); + auto fail_func = + wasm::Func::make(store, fail_type.get(), fail_callback, store); + + // Instantiate. + std::cout << "Instantiating module..." << std::endl; + wasm::Extern* imports[] = {fail_func.get()}; + auto instance = wasm::Instance::make(store, module.get(), imports); + if (!instance) { + std::cout << "> Error instantiating module!" << std::endl; + return; + } + + // Extract export. + std::cout << "Extracting exports..." << std::endl; + auto exports = instance->exports(); + if (exports.size() < 2 || + exports[0]->kind() != wasm::EXTERN_FUNC || !exports[0]->func() || + exports[1]->kind() != wasm::EXTERN_FUNC || !exports[1]->func()) { + std::cout << "> Error accessing exports!" << std::endl; + return; + } + + // Call. + for (size_t i = 0; i < 2; ++i) { + std::cout << "Calling export " << i << "..." << std::endl; + auto trap = exports[i]->func()->call(); + if (!trap) { + std::cout << "> Error calling function!" << std::endl; + return; + } + + std::cout << "Printing message..." << std::endl; + std::cout << "> " << trap->message().get() << std::endl; + } + + // Shut down. + std::cout << "Shutting down..." << std::endl; +} + + +int main(int argc, const char* argv[]) { + run(); + std::cout << "Done." << std::endl; + return 0; +} + diff --git a/deps/v8/third_party/wasm-api/example/trap.wasm b/deps/v8/third_party/wasm-api/example/trap.wasm Binary files differnew file mode 100644 index 0000000000..eeed14c897 --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/trap.wasm diff --git a/deps/v8/third_party/wasm-api/example/trap.wat b/deps/v8/third_party/wasm-api/example/trap.wat new file mode 100644 index 0000000000..dfd20fb12a --- /dev/null +++ b/deps/v8/third_party/wasm-api/example/trap.wat @@ -0,0 +1,5 @@ +(module + (func $callback (import "" "callback") (result i32)) + (func (export "callback") (result i32) (call $callback)) + (func (export "unreachable") (result i32) (unreachable) (i32.const 1)) +) diff --git a/deps/v8/third_party/wasm-api/wasm.h b/deps/v8/third_party/wasm-api/wasm.h new file mode 100644 index 0000000000..bb66c042d9 --- /dev/null +++ b/deps/v8/third_party/wasm-api/wasm.h @@ -0,0 +1,677 @@ +// WebAssembly C API + +#ifndef __WASM_H +#define __WASM_H + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> + + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auxiliaries + +// Machine types + +inline void assertions() { + static_assert(sizeof(float) == sizeof(uint32_t), "incompatible float type"); + static_assert(sizeof(double) == sizeof(uint64_t), "incompatible double type"); + static_assert(sizeof(intptr_t) == sizeof(uint32_t) || + sizeof(intptr_t) == sizeof(uint64_t), + "incompatible pointer type"); +} + +typedef char byte_t; +typedef float float32_t; +typedef double float64_t; + + +// Ownership + +#define own + +// The qualifier `own` is used to indicate ownership of data in this API. +// It is intended to be interpreted similar to a `const` qualifier: +// +// - `own wasm_xxx_t*` owns the pointed-to data +// - `own wasm_xxx_t` distributes to all fields of a struct or union `xxx` +// - `own wasm_xxx_vec_t` owns the vector as well as its elements(!) +// - an `own` function parameter passes ownership from caller to callee +// - an `own` function result passes ownership from callee to caller +// - an exception are `own` pointer parameters named `out`, which are copy-back +// output parameters passing back ownership from callee to caller +// +// Own data is created by `wasm_xxx_new` functions and some others. +// It must be released with the corresponding `wasm_xxx_delete` function. +// +// Deleting a reference does not necessarily delete the underlying object, +// it merely indicates that this owner no longer uses it. +// +// For vectors, `const wasm_xxx_vec_t` is used informally to indicate that +// neither the vector nor its elements should be modified. +// TODO: introduce proper `wasm_xxx_const_vec_t`? + + +#define WASM_DECLARE_OWN(name) \ + typedef struct wasm_##name##_t wasm_##name##_t; \ + \ + void wasm_##name##_delete(own wasm_##name##_t*); + + +// Vectors + +#define WASM_DECLARE_VEC(name, ptr_or_none) \ + typedef struct wasm_##name##_vec_t { \ + size_t size; \ + wasm_##name##_t ptr_or_none* data; \ + } wasm_##name##_vec_t; \ + \ + void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \ + void wasm_##name##_vec_new_uninitialized( \ + own wasm_##name##_vec_t* out, size_t); \ + void wasm_##name##_vec_new( \ + own wasm_##name##_vec_t* out, \ + size_t, own wasm_##name##_t ptr_or_none const[]); \ + void wasm_##name##_vec_copy( \ + own wasm_##name##_vec_t* out, wasm_##name##_vec_t*); \ + void wasm_##name##_vec_delete(own wasm_##name##_vec_t*); + + +// Byte vectors + +typedef byte_t wasm_byte_t; +WASM_DECLARE_VEC(byte, ) + +typedef wasm_byte_vec_t wasm_name_t; + +#define wasm_name wasm_byte_vec +#define wasm_name_new wasm_byte_vec_new +#define wasm_name_new_empty wasm_byte_vec_new_empty +#define wasm_name_new_new_uninitialized wasm_byte_vec_new_uninitialized +#define wasm_name_copy wasm_byte_vec_copy +#define wasm_name_delete wasm_byte_vec_delete + +static inline void wasm_name_new_from_string( + own wasm_name_t* out, const char* s +) { + wasm_name_new(out, strlen(s) + 1, s); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Environment + +// Configuration + +WASM_DECLARE_OWN(config) + +own wasm_config_t* wasm_config_new(); + +// Embedders may provide custom functions for manipulating configs. + + +// Engine + +WASM_DECLARE_OWN(engine) + +own wasm_engine_t* wasm_engine_new(); +own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*); + + +// Store + +WASM_DECLARE_OWN(store) + +own wasm_store_t* wasm_store_new(wasm_engine_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Type Representations + +// Type attributes + +typedef enum wasm_mutability_t { + WASM_CONST, + WASM_VAR +} wasm_mutability_t; + +typedef struct wasm_limits_t { + uint32_t min; + uint32_t max; +} wasm_limits_t; + +static const uint32_t wasm_limits_max_default = 0xffffffff; + + +// Generic + +#define WASM_DECLARE_TYPE(name) \ + WASM_DECLARE_OWN(name) \ + WASM_DECLARE_VEC(name, *) \ + \ + own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t*); + + +// Value Types + +WASM_DECLARE_TYPE(valtype) + +typedef enum wasm_valkind_t { + WASM_I32, + WASM_I64, + WASM_F32, + WASM_F64, + WASM_ANYREF, + WASM_FUNCREF +} wasm_valkind_t; + +own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t); + +wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t*); + +static inline bool wasm_valkind_is_num(wasm_valkind_t k) { + return k < WASM_ANYREF; +} +static inline bool wasm_valkind_is_ref(wasm_valkind_t k) { + return k >= WASM_ANYREF; +} + +static inline bool wasm_valtype_is_num(const wasm_valtype_t* t) { + return wasm_valkind_is_num(wasm_valtype_kind(t)); +} +static inline bool wasm_valtype_is_ref(const wasm_valtype_t* t) { + return wasm_valkind_is_ref(wasm_valtype_kind(t)); +} + + +// Function Types + +WASM_DECLARE_TYPE(functype) + +own wasm_functype_t* wasm_functype_new( + own wasm_valtype_vec_t* params, own wasm_valtype_vec_t* results); + +const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t*); +const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t*); + + +// Global Types + +WASM_DECLARE_TYPE(globaltype) + +own wasm_globaltype_t* wasm_globaltype_new( + own wasm_valtype_t*, wasm_mutability_t); + +const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t*); +wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t*); + + +// Table Types + +WASM_DECLARE_TYPE(tabletype) + +own wasm_tabletype_t* wasm_tabletype_new( + own wasm_valtype_t*, const wasm_limits_t*); + +const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t*); +const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t*); + + +// Memory Types + +WASM_DECLARE_TYPE(memorytype) + +own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t*); + +const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t*); + + +// Extern Types + +WASM_DECLARE_TYPE(externtype) + +typedef enum wasm_externkind_t { + WASM_EXTERN_FUNC, + WASM_EXTERN_GLOBAL, + WASM_EXTERN_TABLE, + WASM_EXTERN_MEMORY +} wasm_externkind_t; + +wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t*); + +wasm_externtype_t* wasm_functype_as_externtype(wasm_functype_t*); +wasm_externtype_t* wasm_globaltype_as_externtype(wasm_globaltype_t*); +wasm_externtype_t* wasm_tabletype_as_externtype(wasm_tabletype_t*); +wasm_externtype_t* wasm_memorytype_as_externtype(wasm_memorytype_t*); + +wasm_functype_t* wasm_externtype_as_functype(wasm_externtype_t*); +wasm_globaltype_t* wasm_externtype_as_globaltype(wasm_externtype_t*); +wasm_tabletype_t* wasm_externtype_as_tabletype(wasm_externtype_t*); +wasm_memorytype_t* wasm_externtype_as_memorytype(wasm_externtype_t*); + +const wasm_externtype_t* wasm_functype_as_externtype_const(const wasm_functype_t*); +const wasm_externtype_t* wasm_globaltype_as_externtype_const(const wasm_globaltype_t*); +const wasm_externtype_t* wasm_tabletype_as_externtype_const(const wasm_tabletype_t*); +const wasm_externtype_t* wasm_memorytype_as_externtype_const(const wasm_memorytype_t*); + +const wasm_functype_t* wasm_externtype_as_functype_const(const wasm_externtype_t*); +const wasm_globaltype_t* wasm_externtype_as_globaltype_const(const wasm_externtype_t*); +const wasm_tabletype_t* wasm_externtype_as_tabletype_const(const wasm_externtype_t*); +const wasm_memorytype_t* wasm_externtype_as_memorytype_const(const wasm_externtype_t*); + + +// Import Types + +WASM_DECLARE_TYPE(importtype) + +own wasm_importtype_t* wasm_importtype_new( + own wasm_name_t* module, own wasm_name_t* name, own wasm_externtype_t*); + +const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*); +const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*); +const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*); + + +// Export Types + +WASM_DECLARE_TYPE(exporttype) + +own wasm_exporttype_t* wasm_exporttype_new( + own wasm_name_t*, own wasm_externtype_t*); + +const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t*); +const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t*); + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Objects + +// Values + +struct wasm_ref_t; + +typedef struct wasm_val_t { + wasm_valkind_t kind; + union { + int32_t i32; + int64_t i64; + float32_t f32; + float64_t f64; + struct wasm_ref_t* ref; + } of; +} wasm_val_t; + +void wasm_val_delete(own wasm_val_t* v); +void wasm_val_copy(own wasm_val_t* out, const wasm_val_t*); + +WASM_DECLARE_VEC(val, ) + + +// References + +#define WASM_DECLARE_REF_BASE(name) \ + WASM_DECLARE_OWN(name) \ + \ + own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t*); \ + \ + void* wasm_##name##_get_host_info(const wasm_##name##_t*); \ + void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \ + void wasm_##name##_set_host_info_with_finalizer( \ + wasm_##name##_t*, void*, void (*)(void*)); + +#define WASM_DECLARE_REF(name) \ + WASM_DECLARE_REF_BASE(name) \ + \ + wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \ + wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \ + const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \ + const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*); + +#define WASM_DECLARE_SHARABLE_REF(name) \ + WASM_DECLARE_REF(name) \ + WASM_DECLARE_OWN(shared_##name) \ + \ + own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \ + own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*); + + +WASM_DECLARE_REF_BASE(ref) + + +// Traps + +typedef wasm_name_t wasm_message_t; // null terminated + +WASM_DECLARE_REF(trap) + +own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t*); + +void wasm_trap_message(const wasm_trap_t*, own wasm_message_t* out); + + +// Foreign Objects + +WASM_DECLARE_REF(foreign) + +own wasm_foreign_t* wasm_foreign_new(wasm_store_t*); + + +// Modules + +WASM_DECLARE_SHARABLE_REF(module) + +own wasm_module_t* wasm_module_new( + wasm_store_t*, const wasm_byte_vec_t* binary); + +bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); + +void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); +void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out); + +void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); +own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); + + +// Function Instances + +WASM_DECLARE_REF(func) + +typedef own wasm_trap_t* (*wasm_func_callback_t)( + const wasm_val_t args[], wasm_val_t results[]); +typedef own wasm_trap_t* (*wasm_func_callback_with_env_t)( + void* env, const wasm_val_t args[], wasm_val_t results[]); + +own wasm_func_t* wasm_func_new( + wasm_store_t*, const wasm_functype_t*, wasm_func_callback_t); +own wasm_func_t* wasm_func_new_with_env( + wasm_store_t*, const wasm_functype_t* type, wasm_func_callback_with_env_t, + void* env, void (*finalizer)(void*)); + +own wasm_functype_t* wasm_func_type(const wasm_func_t*); +size_t wasm_func_param_arity(const wasm_func_t*); +size_t wasm_func_result_arity(const wasm_func_t*); + +own wasm_trap_t* wasm_func_call( + const wasm_func_t*, const wasm_val_t args[], wasm_val_t results[]); + + +// Global Instances + +WASM_DECLARE_REF(global) + +own wasm_global_t* wasm_global_new( + wasm_store_t*, const wasm_globaltype_t*, const wasm_val_t*); + +own wasm_globaltype_t* wasm_global_type(const wasm_global_t*); + +void wasm_global_get(const wasm_global_t*, own wasm_val_t* out); +void wasm_global_set(wasm_global_t*, const wasm_val_t*); + + +// Table Instances + +WASM_DECLARE_REF(table) + +typedef uint32_t wasm_table_size_t; + +own wasm_table_t* wasm_table_new( + wasm_store_t*, const wasm_tabletype_t*, wasm_ref_t* init); + +own wasm_tabletype_t* wasm_table_type(const wasm_table_t*); + +own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index); +bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*); + +wasm_table_size_t wasm_table_size(const wasm_table_t*); +bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init); + + +// Memory Instances + +WASM_DECLARE_REF(memory) + +typedef uint32_t wasm_memory_pages_t; + +static const size_t MEMORY_PAGE_SIZE = 0x10000; + +own wasm_memory_t* wasm_memory_new(wasm_store_t*, const wasm_memorytype_t*); + +own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t*); + +byte_t* wasm_memory_data(wasm_memory_t*); +size_t wasm_memory_data_size(const wasm_memory_t*); + +wasm_memory_pages_t wasm_memory_size(const wasm_memory_t*); +bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); + + +// Externals + +WASM_DECLARE_REF(extern) +WASM_DECLARE_VEC(extern, *) + +wasm_externkind_t wasm_extern_kind(const wasm_extern_t*); +own wasm_externtype_t* wasm_extern_type(const wasm_extern_t*); + +wasm_extern_t* wasm_func_as_extern(wasm_func_t*); +wasm_extern_t* wasm_global_as_extern(wasm_global_t*); +wasm_extern_t* wasm_table_as_extern(wasm_table_t*); +wasm_extern_t* wasm_memory_as_extern(wasm_memory_t*); + +wasm_func_t* wasm_extern_as_func(wasm_extern_t*); +wasm_global_t* wasm_extern_as_global(wasm_extern_t*); +wasm_table_t* wasm_extern_as_table(wasm_extern_t*); +wasm_memory_t* wasm_extern_as_memory(wasm_extern_t*); + +const wasm_extern_t* wasm_func_as_extern_const(const wasm_func_t*); +const wasm_extern_t* wasm_global_as_extern_const(const wasm_global_t*); +const wasm_extern_t* wasm_table_as_extern_const(const wasm_table_t*); +const wasm_extern_t* wasm_memory_as_extern_const(const wasm_memory_t*); + +const wasm_func_t* wasm_extern_as_func_const(const wasm_extern_t*); +const wasm_global_t* wasm_extern_as_global_const(const wasm_extern_t*); +const wasm_table_t* wasm_extern_as_table_const(const wasm_extern_t*); +const wasm_memory_t* wasm_extern_as_memory_const(const wasm_extern_t*); + + +// Module Instances + +WASM_DECLARE_REF(instance) + +own wasm_instance_t* wasm_instance_new( + wasm_store_t*, const wasm_module_t*, const wasm_extern_t* const imports[]); + +void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out); + + +/////////////////////////////////////////////////////////////////////////////// +// Convenience + +// Value Type construction short-hands + +static inline own wasm_valtype_t* wasm_valtype_new_i32() { + return wasm_valtype_new(WASM_I32); +} +static inline own wasm_valtype_t* wasm_valtype_new_i64() { + return wasm_valtype_new(WASM_I64); +} +static inline own wasm_valtype_t* wasm_valtype_new_f32() { + return wasm_valtype_new(WASM_F32); +} +static inline own wasm_valtype_t* wasm_valtype_new_f64() { + return wasm_valtype_new(WASM_F64); +} + +static inline own wasm_valtype_t* wasm_valtype_new_anyref() { + return wasm_valtype_new(WASM_ANYREF); +} +static inline own wasm_valtype_t* wasm_valtype_new_funcref() { + return wasm_valtype_new(WASM_FUNCREF); +} + + +// Function Types construction short-hands + +static inline own wasm_functype_t* wasm_functype_new_0_0() { + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_0( + own wasm_valtype_t* p +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_0( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new_empty(&results); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_1( + own wasm_valtype_t* r +) { + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_1( + own wasm_valtype_t* p, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* r +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_1( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[1] = {r}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 1, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_0_2( + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new_empty(¶ms); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_1_2( + own wasm_valtype_t* p, own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[1] = {p}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 1, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_2_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[2] = {p1, p2}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 2, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + +static inline own wasm_functype_t* wasm_functype_new_3_2( + own wasm_valtype_t* p1, own wasm_valtype_t* p2, own wasm_valtype_t* p3, + own wasm_valtype_t* r1, own wasm_valtype_t* r2 +) { + wasm_valtype_t* ps[3] = {p1, p2, p3}; + wasm_valtype_t* rs[2] = {r1, r2}; + wasm_valtype_vec_t params, results; + wasm_valtype_vec_new(¶ms, 3, ps); + wasm_valtype_vec_new(&results, 2, rs); + return wasm_functype_new(¶ms, &results); +} + + +// Value construction short-hands + +static inline void wasm_val_init_ptr(own wasm_val_t* out, void* p) { +#if UINTPTR_MAX == UINT32_MAX + out->kind = WASM_I32; + out->of.i32 = (intptr_t)p; +#elif UINTPTR_MAX == UINT64_MAX + out->kind = WASM_I64; + out->of.i64 = (intptr_t)p; +#endif +} + +static inline void* wasm_val_ptr(const wasm_val_t* val) { +#if UINTPTR_MAX == UINT32_MAX + return (void*)(intptr_t)val->of.i32; +#elif UINTPTR_MAX == UINT64_MAX + return (void*)(intptr_t)val->of.i64; +#endif +} + + +/////////////////////////////////////////////////////////////////////////////// + +#undef own + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // #ifdef __WASM_H diff --git a/deps/v8/third_party/wasm-api/wasm.hh b/deps/v8/third_party/wasm-api/wasm.hh new file mode 100644 index 0000000000..c153d4b9df --- /dev/null +++ b/deps/v8/third_party/wasm-api/wasm.hh @@ -0,0 +1,770 @@ +// WebAssembly C++ API + +#ifndef __WASM_HH +#define __WASM_HH + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <memory> +#include <limits> +#include <string> + + +/////////////////////////////////////////////////////////////////////////////// +// Auxiliaries + +// Machine types + +static_assert(sizeof(float) == sizeof(int32_t), "incompatible float type"); +static_assert(sizeof(double) == sizeof(int64_t), "incompatible double type"); +static_assert(sizeof(intptr_t) == sizeof(int32_t) || + sizeof(intptr_t) == sizeof(int64_t), "incompatible pointer type"); + +using byte_t = char; +using float32_t = float; +using float64_t = double; + + +namespace wasm { + +// Ownership + +template<class T> struct owner { using type = T; }; +template<class T> struct owner<T*> { using type = std::unique_ptr<T>; }; + +template<class T> +using own = typename owner<T>::type; + +template<class T> +auto make_own(T x) -> own<T> { return own<T>(std::move(x)); } + + +// Vectors + +template<class T> +struct vec_traits { + static void construct(size_t size, T data[]) {} + static void destruct(size_t size, T data[]) {} + static void move(size_t size, T* data, T init[]) { + for (size_t i = 0; i < size; ++i) data[i] = std::move(init[i]); + } + static void copy(size_t size, T data[], const T init[]) { + for (size_t i = 0; i < size; ++i) data[i] = init[i]; + } + + using proxy = T&; +}; + +template<class T> +struct vec_traits<T*> { + static void construct(size_t size, T* data[]) { + for (size_t i = 0; i < size; ++i) data[i] = nullptr; + } + static void destruct(size_t size, T* data[]) { + for (size_t i = 0; i < size; ++i) { + if (data[i]) delete data[i]; + } + } + static void move(size_t size, T* data[], own<T*> init[]) { + for (size_t i = 0; i < size; ++i) data[i] = init[i].release(); + } + static void copy(size_t size, T* data[], const T* const init[]) { + for (size_t i = 0; i < size; ++i) { + if (init[i]) data[i] = init[i]->copy().release(); + } + } + + class proxy { + T*& elem_; + public: + proxy(T*& elem) : elem_(elem) {} + operator T*() { return elem_; } + operator const T*() const { return elem_; } + auto operator=(own<T*>&& elem) -> proxy& { + reset(std::move(elem)); + return *this; + } + void reset(own<T*>&& val = own<T*>()) { + if (elem_) delete elem_; + elem_ = val.release(); + } + auto release() -> T* { + auto elem = elem_; + elem_ = nullptr; + return elem; + } + auto move() -> own<T*> { return make_own(release()); } + auto get() -> T* { return elem_; } + auto get() const -> const T* { return elem_; } + auto operator->() -> T* { return elem_; } + auto operator->() const -> const T* { return elem_; } + }; +}; + + +template<class T> +class vec { + static const size_t invalid_size = SIZE_MAX; + + size_t size_; + std::unique_ptr<T[]> data_; + +#ifdef DEBUG + void make_data(); + void free_data(); +#else + void make_data() {} + void free_data() {} +#endif + + vec(size_t size) : vec(size, size ? new(std::nothrow) T[size] : nullptr) { + make_data(); + } + + vec(size_t size, T* data) : size_(size), data_(data) { + assert(!!size_ == !!data_ || size_ == invalid_size); + } + +public: + template<class U> + vec(vec<U>&& that) : vec(that.size_, that.data_.release()) {} + + ~vec() { + if (data_) vec_traits<T>::destruct(size_, data_.get()); + free_data(); + } + + operator bool() const { + return bool(size_ != invalid_size); + } + + auto size() const -> size_t { + return size_; + } + + auto get() const -> const T* { + return data_.get(); + } + + auto get() -> T* { + return data_.get(); + } + + auto release() -> T* { + return data_.release(); + } + + void reset() { + if (data_) vec_traits<T>::destruct(size_, data_.get()); + free_data(); + size_ = 0; + data_.reset(); + } + + void reset(vec& that) { + reset(); + size_ = that.size_; + data_.reset(that.data_.release()); + } + + auto operator=(vec&& that) -> vec& { + reset(that); + return *this; + } + + auto operator[](size_t i) -> typename vec_traits<T>::proxy { + assert(i < size_); + return typename vec_traits<T>::proxy(data_[i]); + } + + auto operator[](size_t i) const -> const typename vec_traits<T>::proxy { + assert(i < size_); + return typename vec_traits<T>::proxy(data_[i]); + } + + auto copy() const -> vec { + auto v = vec(size_); + if (v) vec_traits<T>::copy(size_, v.data_.get(), data_.get()); + return v; + } + + static auto make_uninitialized(size_t size = 0) -> vec { + auto v = vec(size); + if (v) vec_traits<T>::construct(size, v.data_.get()); + return v; + } + + static auto make(size_t size, own<T> init[]) -> vec { + auto v = vec(size); + if (v) vec_traits<T>::move(size, v.data_.get(), init); + return v; + } + + static auto make(std::string s) -> vec<char> { + auto v = vec(s.length() + 1); + if (v) std::strcpy(v.get(), s.data()); + return v; + } + + static auto make() -> vec { + return vec(0); + } + + template<class... Ts> + static auto make(Ts&&... args) -> vec { + own<T> data[] = { make_own(std::move(args))... }; + return make(sizeof...(Ts), data); + } + + static auto adopt(size_t size, T data[]) -> vec { + return vec(size, data); + } + + static auto invalid() -> vec { + return vec(invalid_size, nullptr); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Environment + +// Configuration + +class Config { +public: + Config() = delete; + ~Config(); + void operator delete(void*); + + static auto make() -> own<Config*>; + + // Implementations may provide custom methods for manipulating Configs. +}; + + +// Engine + +class Engine { +public: + Engine() = delete; + ~Engine(); + void operator delete(void*); + + static auto make(own<Config*>&& = Config::make()) -> own<Engine*>; +}; + + +// Store + +class Store { +public: + Store() = delete; + ~Store(); + void operator delete(void*); + + static auto make(Engine*) -> own<Store*>; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Type Representations + +// Type attributes + +enum Mutability { CONST, VAR }; + +struct Limits { + uint32_t min; + uint32_t max; + + Limits(uint32_t min, uint32_t max = std::numeric_limits<uint32_t>::max()) : + min(min), max(max) {} +}; + + +// Value Types + +enum ValKind { I32, I64, F32, F64, ANYREF, FUNCREF }; + +inline bool is_num(ValKind k) { return k < ANYREF; } +inline bool is_ref(ValKind k) { return k >= ANYREF; } + + +class ValType { +public: + ValType() = delete; + ~ValType(); + void operator delete(void*); + + static auto make(ValKind) -> own<ValType*>; + auto copy() const -> own<ValType*>; + + auto kind() const -> ValKind; + auto is_num() const -> bool { return wasm::is_num(kind()); } + auto is_ref() const -> bool { return wasm::is_ref(kind()); } +}; + + +// External Types + +enum ExternKind { + EXTERN_FUNC, EXTERN_GLOBAL, EXTERN_TABLE, EXTERN_MEMORY +}; + +class FuncType; +class GlobalType; +class TableType; +class MemoryType; + +class ExternType { +public: + ExternType() = delete; + ~ExternType(); + void operator delete(void*); + + auto copy() const-> own<ExternType*>; + + auto kind() const -> ExternKind; + + auto func() -> FuncType*; + auto global() -> GlobalType*; + auto table() -> TableType*; + auto memory() -> MemoryType*; + + auto func() const -> const FuncType*; + auto global() const -> const GlobalType*; + auto table() const -> const TableType*; + auto memory() const -> const MemoryType*; +}; + + +// Function Types + +enum class arrow { ARROW }; + +class FuncType : public ExternType { +public: + FuncType() = delete; + ~FuncType(); + + static auto make( + vec<ValType*>&& params = vec<ValType*>::make(), + vec<ValType*>&& results = vec<ValType*>::make() + ) -> own<FuncType*>; + + auto copy() const -> own<FuncType*>; + + auto params() const -> const vec<ValType*>&; + auto results() const -> const vec<ValType*>&; +}; + + +// Global Types + +class GlobalType : public ExternType { +public: + GlobalType() = delete; + ~GlobalType(); + + static auto make(own<ValType*>&&, Mutability) -> own<GlobalType*>; + auto copy() const -> own<GlobalType*>; + + auto content() const -> const ValType*; + auto mutability() const -> Mutability; +}; + + +// Table Types + +class TableType : public ExternType { +public: + TableType() = delete; + ~TableType(); + + static auto make(own<ValType*>&&, Limits) -> own<TableType*>; + auto copy() const -> own<TableType*>; + + auto element() const -> const ValType*; + auto limits() const -> const Limits&; +}; + + +// Memory Types + +class MemoryType : public ExternType { +public: + MemoryType() = delete; + ~MemoryType(); + + static auto make(Limits) -> own<MemoryType*>; + auto copy() const -> own<MemoryType*>; + + auto limits() const -> const Limits&; +}; + + +// Import Types + +using Name = vec<byte_t>; + +class ImportType { +public: + ImportType() = delete; + ~ImportType(); + void operator delete(void*); + + static auto make(Name&& module, Name&& name, own<ExternType*>&&) -> + own<ImportType*>; + auto copy() const -> own<ImportType*>; + + auto module() const -> const Name&; + auto name() const -> const Name&; + auto type() const -> const ExternType*; +}; + + +// Export Types + +class ExportType { +public: + ExportType() = delete; + ~ExportType(); + void operator delete(void*); + + static auto make(Name&&, own<ExternType*>&&) -> own<ExportType*>; + auto copy() const -> own<ExportType*>; + + auto name() const -> const Name&; + auto type() const -> const ExternType*; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Runtime Objects + +// References + +class Ref { +public: + Ref() = delete; + ~Ref(); + void operator delete(void*); + + auto copy() const -> own<Ref*>; + + auto get_host_info() const -> void*; + void set_host_info(void* info, void (*finalizer)(void*) = nullptr); +}; + + +// Values + +class Val { + ValKind kind_; + union impl { + int32_t i32; + int64_t i64; + float32_t f32; + float64_t f64; + Ref* ref; + } impl_; + + Val(ValKind kind, impl impl) : kind_(kind), impl_(impl) {} + +public: + Val() : kind_(ANYREF) { impl_.ref = nullptr; } + Val(int32_t i) : kind_(I32) { impl_.i32 = i; } + Val(int64_t i) : kind_(I64) { impl_.i64 = i; } + Val(float32_t z) : kind_(F32) { impl_.f32 = z; } + Val(float64_t z) : kind_(F64) { impl_.f64 = z; } + Val(own<Ref*>&& r) : kind_(ANYREF) { impl_.ref = r.release(); } + + Val(Val&& that) : kind_(that.kind_), impl_(that.impl_) { + if (is_ref()) that.impl_.ref = nullptr; + } + + ~Val() { + reset(); + } + + auto is_num() const -> bool { return wasm::is_num(kind_); } + auto is_ref() const -> bool { return wasm::is_ref(kind_); } + + static auto i32(int32_t x) -> Val { return Val(x); } + static auto i64(int64_t x) -> Val { return Val(x); } + static auto f32(float32_t x) -> Val { return Val(x); } + static auto f64(float64_t x) -> Val { return Val(x); } + static auto ref(own<Ref*>&& x) -> Val { return Val(std::move(x)); } + template<class T> inline static auto make(T x) -> Val; + template<class T> inline static auto make(own<T>&& x) -> Val; + + void reset() { + if (is_ref() && impl_.ref) { + delete impl_.ref; + impl_.ref = nullptr; + } + } + + void reset(Val& that) { + reset(); + kind_ = that.kind_; + impl_ = that.impl_; + if (is_ref()) that.impl_.ref = nullptr; + } + + auto operator=(Val&& that) -> Val& { + reset(that); + return *this; + } + + auto kind() const -> ValKind { return kind_; } + auto i32() const -> int32_t { assert(kind_ == I32); return impl_.i32; } + auto i64() const -> int64_t { assert(kind_ == I64); return impl_.i64; } + auto f32() const -> float32_t { assert(kind_ == F32); return impl_.f32; } + auto f64() const -> float64_t { assert(kind_ == F64); return impl_.f64; } + auto ref() const -> Ref* { assert(is_ref()); return impl_.ref; } + template<class T> inline auto get() const -> T; + + auto release_ref() -> own<Ref*> { + assert(is_ref()); + auto ref = impl_.ref; + ref = nullptr; + return own<Ref*>(ref); + } + + auto copy() const -> Val { + if (is_ref() && impl_.ref != nullptr) { + impl impl; + impl.ref = impl_.ref->copy().release(); + return Val(kind_, impl); + } else { + return Val(kind_, impl_); + } + } +}; + + +template<> inline auto Val::make<int32_t>(int32_t x) -> Val { return Val(x); } +template<> inline auto Val::make<int64_t>(int64_t x) -> Val { return Val(x); } +template<> inline auto Val::make<float32_t>(float32_t x) -> Val { return Val(x); } +template<> inline auto Val::make<float64_t>(float64_t x) -> Val { return Val(x); } +template<> inline auto Val::make<Ref*>(own<Ref*>&& x) -> Val { + return Val(std::move(x)); +} + +template<> inline auto Val::make<uint32_t>(uint32_t x) -> Val { + return Val(static_cast<int32_t>(x)); +} +template<> inline auto Val::make<uint64_t>(uint64_t x) -> Val { + return Val(static_cast<int64_t>(x)); +} + +template<> inline auto Val::get<int32_t>() const -> int32_t { return i32(); } +template<> inline auto Val::get<int64_t>() const -> int64_t { return i64(); } +template<> inline auto Val::get<float32_t>() const -> float32_t { return f32(); } +template<> inline auto Val::get<float64_t>() const -> float64_t { return f64(); } +template<> inline auto Val::get<Ref*>() const -> Ref* { return ref(); } + +template<> inline auto Val::get<uint32_t>() const -> uint32_t { + return static_cast<uint32_t>(i32()); +} +template<> inline auto Val::get<uint64_t>() const -> uint64_t { + return static_cast<uint64_t>(i64()); +} + + +// Traps + +using Message = vec<byte_t>; // null terminated + +class Trap : public Ref { +public: + Trap() = delete; + ~Trap(); + + static auto make(Store*, const Message& msg) -> own<Trap*>; + auto copy() const -> own<Trap*>; + + auto message() const -> Message; +}; + + +// Shared objects + +template<class T> +class Shared { +public: + Shared() = delete; + ~Shared(); + void operator delete(void*); +}; + + +// Modules + +class Module : public Ref { +public: + Module() = delete; + ~Module(); + + static auto validate(Store*, const vec<byte_t>& binary) -> bool; + static auto make(Store*, const vec<byte_t>& binary) -> own<Module*>; + auto copy() const -> own<Module*>; + + auto imports() const -> vec<ImportType*>; + auto exports() const -> vec<ExportType*>; + + auto share() const -> own<Shared<Module>*>; + static auto obtain(Store*, const Shared<Module>*) -> own<Module*>; + + auto serialize() const -> vec<byte_t>; + static auto deserialize(Store*, const vec<byte_t>&) -> own<Module*>; +}; + + +// Foreign Objects + +class Foreign : public Ref { +public: + Foreign() = delete; + ~Foreign(); + + static auto make(Store*) -> own<Foreign*>; + auto copy() const -> own<Foreign*>; +}; + + +// Externals + +class Func; +class Global; +class Table; +class Memory; + +class Extern : public Ref { +public: + Extern() = delete; + ~Extern(); + + auto copy() const -> own<Extern*>; + + auto kind() const -> ExternKind; + auto type() const -> own<ExternType*>; + + auto func() -> Func*; + auto global() -> Global*; + auto table() -> Table*; + auto memory() -> Memory*; + + auto func() const -> const Func*; + auto global() const -> const Global*; + auto table() const -> const Table*; + auto memory() const -> const Memory*; +}; + + +// Function Instances + +class Func : public Extern { +public: + Func() = delete; + ~Func(); + + using callback = auto (*)(const Val[], Val[]) -> own<Trap*>; + using callback_with_env = auto (*)(void*, const Val[], Val[]) -> own<Trap*>; + + static auto make(Store*, const FuncType*, callback) -> own<Func*>; + static auto make(Store*, const FuncType*, callback_with_env, + void*, void (*finalizer)(void*) = nullptr) -> own<Func*>; + auto copy() const -> own<Func*>; + + auto type() const -> own<FuncType*>; + auto param_arity() const -> size_t; + auto result_arity() const -> size_t; + + auto call(const Val[] = nullptr, Val[] = nullptr) const -> own<Trap*>; +}; + + +// Global Instances + +class Global : public Extern { +public: + Global() = delete; + ~Global(); + + static auto make(Store*, const GlobalType*, const Val&) -> own<Global*>; + auto copy() const -> own<Global*>; + + auto type() const -> own<GlobalType*>; + auto get() const -> Val; + void set(const Val&); +}; + + +// Table Instances + +class Table : public Extern { +public: + Table() = delete; + ~Table(); + + using size_t = uint32_t; + + static auto make( + Store*, const TableType*, const Ref* init = nullptr) -> own<Table*>; + auto copy() const -> own<Table*>; + + auto type() const -> own<TableType*>; + auto get(size_t index) const -> own<Ref*>; + auto set(size_t index, const Ref*) -> bool; + auto size() const -> size_t; + auto grow(size_t delta, const Ref* init = nullptr) -> bool; +}; + + +// Memory Instances + +class Memory : public Extern { +public: + Memory() = delete; + ~Memory(); + + static auto make(Store*, const MemoryType*) -> own<Memory*>; + auto copy() const -> own<Memory*>; + + using pages_t = uint32_t; + + static const size_t page_size = 0x10000; + + auto type() const -> own<MemoryType*>; + auto data() const -> byte_t*; + auto data_size() const -> size_t; + auto size() const -> pages_t; + auto grow(pages_t delta) -> bool; +}; + + +// Module Instances + +class Instance : public Ref { +public: + Instance() = delete; + ~Instance(); + + static auto make( + Store*, const Module*, const Extern* const[]) -> own<Instance*>; + auto copy() const -> own<Instance*>; + + auto exports() const -> vec<Extern*>; +}; + + +/////////////////////////////////////////////////////////////////////////////// + +} // namespave wasm + +#endif // #ifdef __WASM_HH |