-
Notifications
You must be signed in to change notification settings - Fork 824
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement C++ API and reimplement C on top (#7)
* Add a C++ version of the API * Refactor wasm-v8 to implement C++ API, which is safer * Reimplement C API on top of C++ API * Various fixes, additions, and clean-ups * Some minor changes to C API: * Enforce `const` correctness in various places * Replace `init`, `deinit` global functions with `engine` object to be created * Store creation requires `engine` argument * Add `wasm_*_vec_new_empty` functions for creating *own* vectors of size 0 * Changed `wasm_limits_t` from `size_t` to `uint32_t` * Changed `wasm_val_t` from `uint32_t`, `uint64_t` to `int32_t`, `int64_t` * Removed `wasm_numkind_t`, `wasm_refkind_t` and `wasm_numtype_t` `wasm_reftype_t` type aliases * Renamed `wasm_valkind_is_numkind`, `wasm_valkind_is_refkind` to `wasm_valkind_is_num`, `wasm_valkind_is_ref` and `wasm_valtype_is_numtype`, `wasm_valtype_is_reftype` to `wasm_valtype_is_num`, `wasm_valtype_is_ref` * Removed `wasm_ref_null` and `wasm_ref_is_null` (use NULL pointer) * Extended `wasm_func_new_with_env` function to take finalizer for env (which may be NULL) * Turned `wasm_extern_t` into an abstract type `wasm_external_t` and added conversion functions * Removed `wasm_instance_export` function * Add comprehensive TODO list to README
- Loading branch information
Showing
11 changed files
with
2,914 additions
and
1,250 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
out | ||
v8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,50 @@ | ||
# WebAssembly C API | ||
# WebAssembly C and C++ API | ||
|
||
Work in progress. No docs yet. | ||
|
||
* See `example/hello.c` for example usage. | ||
* C API: | ||
|
||
* See `include/wasm.h` for interface. | ||
* See `example/hello.c` for example usage. | ||
|
||
* See `include/wasm.h` for interface. | ||
|
||
* C++ API: | ||
|
||
* See `example/hello.cc` for example usage. | ||
|
||
* See `include/wasm.hh` for interface. | ||
|
||
* A half-complete implementation based on V8 is in `src`. | ||
|
||
* C API is build on top of C++ API. | ||
|
||
* See `Makefile` for build recipe. | ||
|
||
* TODO in V8 implementation: | ||
|
||
* Replace use of JS API with V8 internal | ||
|
||
* Implement missing functionality through V8 internals | ||
|
||
* global::get, global::set | ||
* table::get, table::set, table::size, table::grow | ||
* memory::data, memory::data_size, memory::size, memory::grow | ||
* module::serialize, module::deserialize | ||
* multiple return values | ||
|
||
* Simplify reference wrappers to be plain persistent handles | ||
|
||
* Move host information to V8 object (func callback & env) | ||
* Compute reflection on demand | ||
|
||
* Possible API tweaks: | ||
|
||
* Find a way to perform C callbacks through C++ without extra wrapper? | ||
|
||
* Possible renamings? | ||
|
||
* `externkind`, `externtype` to `externalkind`, `externaltype`? | ||
* `memtype` to `memorytype`? | ||
* CamlCase class names in C++ API? | ||
|
||
* Add iterators to `vec` class? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#include <iostream> | ||
#include <fstream> | ||
#include <cstdlib> | ||
#include <string> | ||
#include <cinttypes> | ||
|
||
#include "wasm.hh" | ||
|
||
// Print a Wasm value | ||
void val_print(const wasm::val& val) { | ||
switch (val.kind()) { | ||
case wasm::I32: { | ||
std::cout << val.i32(); | ||
} break; | ||
case wasm::I64: { | ||
std::cout << val.i64(); | ||
} break; | ||
case wasm::F32: { | ||
std::cout << val.f32(); | ||
} break; | ||
case wasm::F64: { | ||
std::cout << val.f64(); | ||
} break; | ||
case wasm::ANYREF: | ||
case wasm::FUNCREF: { | ||
if (val.ref() == nullptr) { | ||
std::cout << "null"; | ||
} else { | ||
std::cout << "ref(" << val.ref() << ")"; | ||
} | ||
} break; | ||
} | ||
} | ||
|
||
// A function to be called from Wasm code. | ||
auto print_wasm(const wasm::vec<wasm::val>& args) -> wasm::vec<wasm::val> { | ||
std::cout << "Calling back..." << std::endl << ">"; | ||
for (size_t i = 0; i < args.size(); ++i) { | ||
std::cout << " "; | ||
val_print(args[i]); | ||
} | ||
std::cout << std::endl; | ||
|
||
int32_t n = args.size(); | ||
return wasm::vec<wasm::val>::make(wasm::val(n)); | ||
} | ||
|
||
|
||
void run(int argc, const char* argv[]) { | ||
// Initialize. | ||
std::cout << "Initializing..." << std::endl; | ||
auto engine = wasm::engine::make(argc, argv); | ||
auto store = wasm::store::make(engine); | ||
|
||
// 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 callbacks..." << std::endl; | ||
auto print_type1 = 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_func1 = wasm::func::make(store, print_type1, print_wasm); | ||
|
||
auto print_type2 = wasm::functype::make( | ||
wasm::vec<wasm::valtype*>::make(wasm::valtype::make(wasm::I32), wasm::valtype::make(wasm::I32)), | ||
wasm::vec<wasm::valtype*>::make(wasm::valtype::make(wasm::I32)) | ||
); | ||
auto print_func2 = wasm::func::make(store, print_type2, print_wasm); | ||
|
||
// Instantiate. | ||
std::cout << "Instantiating module..." << std::endl; | ||
auto imports = wasm::vec<wasm::external*>::make(print_func1, print_func2); | ||
auto instance = wasm::instance::make(store, module, 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() == 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 exports..." << std::endl; | ||
auto results = run_func->call(wasm::val(3), wasm::val(4)); | ||
|
||
// 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(argc, argv); | ||
std::cout << "Done." << std::endl; | ||
return 0; | ||
} | ||
|
Oops, something went wrong.