Restucture wasm module, return a normal TSLanguage from load_language

This commit is contained in:
Max Brunsfeld 2022-09-06 22:41:05 -07:00
parent 3f1a7f9cd4
commit 042e6f9d57
26 changed files with 3068 additions and 317 deletions

View file

@ -19,7 +19,7 @@ OBJ := $(SRC:.c=.o)
# define default flags, and override to append mandatory flags
CFLAGS ?= -O3 -Wall -Wextra -Werror
override CFLAGS += -std=gnu99 -fPIC -Ilib/src -Ilib/include
override CFLAGS += -std=gnu99 -fPIC -Ilib/src -Ilib/src/wasm -Ilib/include
# ABI versioning
SONAME_MAJOR := 0

View file

@ -864,40 +864,29 @@ pub type TSWasmEngine = wasm_engine_t;
pub struct TSWasmStore {
_unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TSWasmLanguage {
_unused: [u8; 0],
}
extern "C" {
pub fn ts_wasm_store_new(engine: *mut TSWasmEngine) -> *mut TSWasmStore;
}
extern "C" {
pub fn ts_wasm_store_delete(arg1: *mut TSWasmStore);
}
extern "C" {
pub fn ts_wasm_language_delete(arg1: *const TSWasmLanguage);
}
extern "C" {
pub fn ts_wasm_store_load_language(
arg1: *mut TSWasmStore,
name: *const ::std::os::raw::c_char,
wasm: *const ::std::os::raw::c_char,
wasm_len: u32,
) -> *mut TSWasmLanguage;
) -> *const TSLanguage;
}
extern "C" {
pub fn ts_wasm_store_add_language(arg1: *mut TSWasmStore, arg2: *const TSWasmLanguage);
}
extern "C" {
pub fn ts_parser_set_wasm_language(arg1: *mut TSParser, arg2: *const TSWasmLanguage);
}
extern "C" {
pub fn ts_parser_wasm_language(arg1: *mut TSParser) -> *const TSWasmLanguage;
pub fn ts_language_is_wasm(arg1: *const TSLanguage) -> bool;
}
extern "C" {
pub fn ts_parser_set_wasm_store(arg1: *mut TSParser, arg2: *mut TSWasmStore);
}
extern "C" {
pub fn ts_parser_wasm_store(arg1: *mut TSParser) -> *mut TSWasmStore;
}
extern "C" {
#[doc = " Set the allocation functions used by the library."]
#[doc = ""]

View file

@ -35,6 +35,7 @@ fn main() {
.flag_if_supported("-std=c99")
.flag_if_supported("-Wno-unused-parameter")
.include(src_path)
.include(src_path.join("wasm"))
.include("include")
.file(src_path.join("lib.c"))
.compile("tree-sitter");

View file

@ -1,7 +1,5 @@
use crate::{LanguageError, Parser};
use super::ffi;
use std::{ffi::CString, os::raw::c_char};
use crate::{ffi, Language, LanguageError, Parser};
use std::{ffi::CString, mem, os::raw::c_char};
pub use wasmtime;
#[cfg(feature = "wasm")]
@ -16,18 +14,22 @@ pub struct wasm_engine_t {
}
pub struct WasmStore(*mut ffi::TSWasmStore);
pub struct WasmLanguage(*const ffi::TSWasmLanguage);
impl WasmStore {
pub fn new(engine: wasmtime::Engine) -> Self {
let mut c_engine = wasm_engine_t { engine };
let c_engine = &mut c_engine as *mut _;
WasmStore(unsafe { ffi::ts_wasm_store_new(c_engine as *mut _) })
let mut c_engine = Box::new(wasm_engine_t {
engine: engine.clone(),
});
let result = WasmStore(unsafe {
ffi::ts_wasm_store_new(c_engine.as_mut() as *mut wasm_engine_t as *mut _)
});
mem::forget(c_engine);
result
}
pub fn load_language(&mut self, name: &str, bytes: &[u8]) -> WasmLanguage {
pub fn load_language(&mut self, name: &str, bytes: &[u8]) -> Language {
let name = CString::new(name).unwrap();
WasmLanguage(unsafe {
Language(unsafe {
ffi::ts_wasm_store_load_language(
self.0,
name.as_ptr(),
@ -38,34 +40,19 @@ impl WasmStore {
}
}
impl Parser {
pub fn wasm_language(&self) -> Option<WasmLanguage> {
let language = unsafe { ffi::ts_parser_wasm_language(self.0.as_ptr()) };
if language.is_null() {
None
} else {
Some(WasmLanguage(language))
}
}
pub fn set_wasm_language(&mut self, language: WasmLanguage) -> Result<(), LanguageError> {
unsafe {
ffi::ts_parser_set_wasm_language(self.0.as_ptr(), language.0);
}
Ok(())
}
pub fn set_wasm_store(&mut self, language: WasmStore) -> Result<(), LanguageError> {
unsafe {
ffi::ts_parser_set_wasm_store(self.0.as_ptr(), language.0);
}
Ok(())
impl Language {
pub fn is_wasm(&self) -> bool {
unsafe { ffi::ts_language_is_wasm(self.0) }
}
}
impl Drop for WasmLanguage {
fn drop(&mut self) {
unsafe { ffi::ts_wasm_language_delete(self.0) };
impl Parser {
pub fn set_wasm_store(&mut self, store: WasmStore) -> Result<(), LanguageError> {
unsafe {
ffi::ts_parser_set_wasm_store(self.0.as_ptr(), store.0);
}
mem::forget(store);
Ok(())
}
}

View file

@ -1,3 +1,4 @@
-std=c99
-Isrc
-Iinclude
-Isrc/wasm
-Iinclude
-D TREE_SITTER_FEATURE_WASM

View file

@ -943,23 +943,24 @@ uint32_t ts_language_version(const TSLanguage *);
typedef struct wasm_engine_t TSWasmEngine;
typedef struct TSWasmStore TSWasmStore;
typedef struct TSWasmLanguage TSWasmLanguage;
TSWasmStore *ts_wasm_store_new(TSWasmEngine *engine);
void ts_wasm_store_delete(TSWasmStore *);
void ts_wasm_language_delete(const TSWasmLanguage *);
TSWasmLanguage *ts_wasm_store_load_language(
void ts_wasm_store_delete(TSWasmStore *);
const TSLanguage *ts_wasm_store_load_language(
TSWasmStore *,
const char *name,
const char *wasm,
uint32_t wasm_len
);
void ts_wasm_store_add_language(TSWasmStore *, const TSWasmLanguage *);
void ts_parser_set_wasm_language(TSParser *, const TSWasmLanguage *);
const TSWasmLanguage *ts_parser_wasm_language(TSParser *);
bool ts_language_is_wasm(const TSLanguage *);
void ts_parser_set_wasm_store(TSParser *, TSWasmStore *);
TSWasmStore *ts_parser_wasm_store(TSParser *);
/**********************************/
/* Section - Global Configuration */
/**********************************/

View file

@ -89,7 +89,6 @@ struct TSParser {
Stack *stack;
SubtreePool tree_pool;
const TSLanguage *language;
const TSWasmLanguage *wasm_language;
TSWasmStore *wasm_store;
ReduceActionSet reduce_actions;
Subtree finished_tree;
@ -487,7 +486,7 @@ static Subtree ts_parser__lex(
);
ts_lexer_start(&self->lexer);
found_token = false;
if (self->wasm_language) {
if (ts_language_is_wasm(self->language)) {
found_token = ts_wasm_store_run_main_lex_function(self->wasm_store, lex_mode.lex_state);
} else {
found_token = self->language->lex_fn(&self->lexer.data, lex_mode.lex_state);
@ -553,7 +552,7 @@ static Subtree ts_parser__lex(
ts_lexer_reset(&self->lexer, self->lexer.token_start_position);
ts_lexer_start(&self->lexer);
if (self->wasm_language) {
if (ts_language_is_wasm(self->language)) {
is_keyword = ts_wasm_store_run_keyword_lex_function(self->wasm_store, 0);
} else {
is_keyword = self->language->keyword_lex_fn(&self->lexer.data, 0);
@ -1812,14 +1811,6 @@ bool ts_parser_set_language(TSParser *self, const TSLanguage *language) {
}
self->language = language;
#ifdef TREE_SITTER_FEATURE_WASM
if (self->wasm_language) {
ts_wasm_language_delete(self->wasm_language);
self->wasm_language = NULL;
}
#endif
ts_parser_reset(self);
return true;
}
@ -1900,8 +1891,12 @@ TSTree *ts_parser_parse(
) {
if (!self->language || !input.read) return NULL;
if (self->wasm_store) {
ts_wasm_store_start(self->wasm_store, &self->lexer.data, self->wasm_language);
if (ts_language_is_wasm(self->language)) {
if (self->wasm_store) {
ts_wasm_store_start(self->wasm_store, &self->lexer.data, self->language);
} else {
return NULL;
}
}
ts_lexer_set_input(&self->lexer, input);
@ -2023,28 +2018,8 @@ TSTree *ts_parser_parse_string_encoding(
});
}
#ifdef TREE_SITTER_FEATURE_WASM
void ts_parser_set_wasm_language(TSParser *self, const TSWasmLanguage *language) {
if (language) {
self->language = language->language;
ts_wasm_language_retain(language);
}
self->wasm_language = language;
ts_parser_reset(self);
}
const TSWasmLanguage *ts_parser_wasm_language(TSParser *self) {
if (self->wasm_language) {
ts_wasm_language_retain(self->wasm_language);
}
return self->wasm_language;
}
void ts_parser_set_wasm_store(TSParser *self, TSWasmStore *store) {
self->wasm_store = store;
}
#endif // TREE_SITTER_FEATURE_WASM
#undef LOG

View file

@ -1,13 +1,41 @@
#include <wasmtime.h>
#include <wasm.h>
#include "tree_sitter/api.h"
#include "./wasm/wasm.h"
#include "./alloc.h"
#include "./language.h"
#include "./array.h"
#include "./atomic.h"
#include "./lexer.h"
#include "./wasm.h"
#include "./lexer.h"
static volatile uint32_t NEXT_LANGUAGE_ID;
typedef struct {
wasmtime_module_t *module;
uint32_t language_id;
const char *name;
char *symbol_name_buffer;
char *field_name_buffer;
} LanguageWasmModule;
typedef struct {
uint32_t language_id;
wasmtime_instance_t instance;
uint32_t main_lex_fn_index;
uint32_t keyword_lex_fn_index;
uint32_t external_scan_index;
} LanguageWasmInstance;
struct TSWasmStore {
wasm_engine_t *engine;
wasmtime_store_t *store;
wasmtime_table_t function_table;
wasmtime_memory_t memory;
TSLexer *current_lexer;
LanguageWasmInstance *current_instance;
Array(LanguageWasmInstance) language_instances;
uint32_t current_memory_offset;
uint32_t current_function_table_offset;
};
typedef Array(char) StringData;
@ -58,36 +86,48 @@ typedef struct {
int32_t get_column;
int32_t is_at_included_range_start;
int32_t eof;
void *native_lexer_address;
} LexerInWasmMemory;
static volatile uint32_t NEXT_LANGUAGE_ID;
static const uint32_t LEXER_ADDRESS = 32;
static const uint32_t LEXER_END_ADDRESS = LEXER_ADDRESS + sizeof(LexerInWasmMemory);
static wasm_trap_t *advance_callback(
void *env,
const wasm_val_vec_t *args,
wasm_val_vec_t *results
wasmtime_caller_t *caller,
const wasmtime_val_t *args,
size_t arg_count,
wasmtime_val_t *results,
size_t result_count
) {
assert(args->size == 2);
assert(args->data[0].kind == WASM_I32);
assert(args->data[1].kind == WASM_I32);
wasmtime_context_t *context = wasmtime_caller_context(caller);
assert(arg_count == 2);
assert(args[0].kind == WASMTIME_I32);
assert(args[1].kind == WASMTIME_I32);
int32_t lexer_address = args[0].of.i32;
TSWasmStore *store = env;
TSLexer *lexer = store->current_lexer;
int32_t lexer_address = args->data[0].of.i32;
bool skip = args->data[1].of.i32;
bool skip = args[1].of.i32;
lexer->advance(lexer, skip);
char *memory = wasm_memory_data(store->memory);
uint8_t *memory = wasmtime_memory_data(context, &store->memory);
memcpy(&memory[lexer_address], &lexer->lookahead, sizeof(lexer->lookahead));
return NULL;
}
static wasm_trap_t *mark_end_callback(
void *env,
const wasm_val_vec_t *args,
wasm_val_vec_t *results
wasmtime_caller_t *caller,
const wasmtime_val_t *args,
size_t arg_count,
wasmtime_val_t *results,
size_t result_count
) {
assert(args->size == 1);
assert(args->data[0].kind == WASM_I32);
assert(arg_count == 1);
assert(args[0].kind == WASM_I32);
int32_t lexer_address = args[0].of.i32;
TSWasmStore *store = env;
TSLexer *lexer = store->current_lexer;
lexer->mark_end(lexer);
@ -96,48 +136,73 @@ static wasm_trap_t *mark_end_callback(
static wasm_trap_t *get_column_callback(
void *env,
const wasm_val_vec_t *args,
wasm_val_vec_t *results
wasmtime_caller_t *caller,
const wasmtime_val_t *args,
size_t arg_count,
wasmtime_val_t *results,
size_t result_count
) {
assert(args->size == 1);
assert(args->data[0].kind == WASM_I32);
assert(arg_count == 1);
assert(args[0].kind == WASM_I32);
int32_t lexer_address = args[0].of.i32;
TSWasmStore *store = env;
TSLexer *lexer = store->current_lexer;
wasm_val_t result = WASM_I32_VAL(lexer->get_column(lexer));
results->data[0] = result;
uint32_t result = lexer->get_column(lexer);
results[0] = (wasmtime_val_t) {
.kind = WASMTIME_I32,
.of.i32 = result
};
return NULL;
}
static wasm_trap_t *is_at_included_range_start_callback(
void *env,
const wasm_val_vec_t *args,
wasm_val_vec_t *results
wasmtime_caller_t *caller,
const wasmtime_val_t *args,
size_t arg_count,
wasmtime_val_t *results,
size_t result_count
) {
assert(args->size == 1);
assert(args->data[0].kind == WASM_I32);
assert(arg_count == 1);
assert(args[0].kind == WASM_I32);
int32_t lexer_address = args[0].of.i32;
TSWasmStore *store = env;
TSLexer *lexer = store->current_lexer;
wasm_val_t result = WASM_I32_VAL(lexer->is_at_included_range_start(lexer));
results->data[0] = result;
bool result = lexer->is_at_included_range_start(lexer);
results[0] = (wasmtime_val_t) {
.kind = WASMTIME_I32,
.of.i32 = result
};
return NULL;
}
static wasm_trap_t *eof_callback(
void *env,
const wasm_val_vec_t *args,
wasm_val_vec_t *results
wasmtime_caller_t *caller,
const wasmtime_val_t *args,
size_t arg_count,
wasmtime_val_t *results,
size_t result_count
) {
assert(args->size == 1);
assert(args->data[0].kind == WASM_I32);
assert(arg_count == 1);
assert(args[0].kind == WASM_I32);
int32_t lexer_address = args[0].of.i32;
TSWasmStore *store = env;
TSLexer *lexer = store->current_lexer;
wasm_val_t result = WASM_I32_VAL(lexer->eof(lexer));
results->data[0] = result;
bool result = lexer->eof(lexer);
results[0] = (wasmtime_val_t) {
.kind = WASMTIME_I32,
.of.i32 = result
};
return NULL;
}
typedef struct {
wasm_func_callback_with_env_t callback;
wasmtime_func_callback_t callback;
wasm_functype_t *type;
} FunctionDefinition;
@ -150,7 +215,7 @@ static void *copy(const void *data, size_t size) {
}
static void *copy_strings(
const char *data,
const uint8_t *data,
int32_t array_address,
size_t count,
StringData *string_data
@ -159,13 +224,22 @@ static void *copy_strings(
for (unsigned i = 0; i < count; i++) {
int32_t address;
memcpy(&address, &data[array_address + i * sizeof(address)], sizeof(address));
const char *string = &data[address];
uint32_t len = strlen(string);
result[i] = (const char *)(uintptr_t)string_data->size;
array_extend(string_data, len + 1, string);
if (address == 0) {
result[i] = (const char *)-1;
} else {
const uint8_t *string = &data[address];
uint32_t len = strlen((const char *)string);
result[i] = (const char *)(uintptr_t)string_data->size;
array_extend(string_data, len + 1, string);
}
}
for (unsigned i = 0; i < count; i++) {
result[i] = string_data->contents + (uintptr_t)result[i];
if (result[i] == (const char *)-1) {
result[i] = NULL;
} else {
result[i] = string_data->contents + (uintptr_t)result[i];
}
printf(" string %u: %s\n", i, result[i]);
}
return result;
}
@ -176,15 +250,32 @@ static bool name_eq(const wasm_name_t *name, const char *string) {
TSWasmStore *ts_wasm_store_new(TSWasmEngine *engine) {
TSWasmStore *self = ts_malloc(sizeof(TSWasmStore));
wasm_store_t *store = wasm_store_new(engine);
wasmtime_store_t *store = wasmtime_store_new(engine, self, NULL);
wasmtime_context_t *context = wasmtime_store_context(store);
wasmtime_error_t *error = NULL;
// Memory
wasm_limits_t memory_limits = {.min = 64, .max = wasm_limits_max_default};
// Initialize store's memory
wasm_limits_t memory_limits = {.min = LEXER_END_ADDRESS, .max = wasm_limits_max_default};
wasm_memorytype_t *memory_type = wasm_memorytype_new(&memory_limits);
wasm_memory_t *memory = wasm_memory_new(store, memory_type);
wasmtime_memory_t memory;
error = wasmtime_memory_new(context, memory_type, &memory);
assert(!error);
wasm_memorytype_delete(memory_type);
// Lexer functions
// Initialize lexer struct with function pointers in wasm memory.
uint8_t *memory_data = wasmtime_memory_data(context, &memory);
LexerInWasmMemory lexer = {
.lookahead = 0,
.result_symbol = 0,
.advance = 0,
.mark_end = 1,
.get_column = 2,
.is_at_included_range_start = 3,
.eof = 4,
};
memcpy(&memory_data[LEXER_ADDRESS], &lexer, sizeof(lexer));
// Define lexer functions.
FunctionDefinition definitions[] = {
{advance_callback, wasm_functype_new_2_0(wasm_valtype_new_i32(), wasm_valtype_new_i32())},
{mark_end_callback, wasm_functype_new_1_0(wasm_valtype_new_i32())},
@ -194,66 +285,59 @@ TSWasmStore *ts_wasm_store_new(TSWasmEngine *engine) {
};
unsigned definitions_len = array_len(definitions);
// Function table
// Add lexer functions to the store's function table.
wasmtime_table_t function_table;
wasm_limits_t table_limits = {.min = definitions_len, .max = wasm_limits_max_default};
wasm_tabletype_t *table_type = wasm_tabletype_new(wasm_valtype_new(WASM_FUNCREF), &table_limits);
wasm_table_t *function_table = wasm_table_new(store, table_type, NULL);
wasmtime_val_t initializer = {.kind = WASMTIME_FUNCREF};
error = wasmtime_table_new(context, table_type, &initializer, &function_table);
assert(!error);
wasm_tabletype_delete(table_type);
wasm_table_grow(function_table, definitions_len, NULL);
uint32_t prev_size;
error = wasmtime_table_grow(context, &function_table, definitions_len, &initializer, &prev_size);
assert(!error);
for (unsigned i = 0; i < definitions_len; i++) {
FunctionDefinition *definition = &definitions[i];
wasm_func_t *func = wasm_func_new_with_env(store, definition->type, definition->callback, self, NULL);
wasm_table_set(function_table, i, (wasm_ref_t *)func);
wasmtime_func_t func;
wasmtime_func_new(context, definition->type, definition->callback, self, NULL, &func);
wasmtime_val_t func_val = {.kind = WASMTIME_FUNCREF, .of.funcref = func};
error = wasmtime_table_set(context, &function_table, i, &func_val);
assert(!error);
wasm_functype_delete(definition->type);
}
*self = (TSWasmStore) {
.store = store,
.engine = engine,
.memory = memory,
.language_instances = array_new(),
.function_table = function_table,
.current_memory_offset = LEXER_END_ADDRESS,
.current_function_table_offset = definitions_len,
};
return self;
}
void ts_wasm_store_delete(TSWasmStore *self) {
wasm_memory_delete(self->memory);
wasm_table_delete(self->function_table);
wasm_store_delete(self->store);
wasmtime_store_delete(self->store);
wasm_engine_delete(self->engine);
array_delete(&self->language_instances);
ts_free(self);
}
void ts_wasm_language_delete(const TSWasmLanguage *self) {
assert(self->ref_count > 0);
if (atomic_dec((volatile uint32_t *)&self->ref_count) == 0) {
wasm_shared_module_delete(self->module);
ts_free((void *)self->language->alias_map);
ts_free((void *)self->language->alias_sequences);
ts_free((void *)self->language->parse_table);
ts_free((void *)self->language->parse_actions);
ts_free((void *)self->language->primary_state_ids);
ts_free((void *)self->language->public_symbol_map);
ts_free(self->language);
ts_free(self->symbol_name_buffer);
ts_free(self->field_name_buffer);
ts_free((void *)self);
}
}
void ts_wasm_language_retain(const TSWasmLanguage *self) {
atomic_inc((volatile uint32_t *)&self->ref_count);
}
static bool ts_wasm_store__instantiate(
TSWasmStore *self,
wasm_module_t *module,
wasmtime_module_t *module,
const char *language_name,
wasm_instance_t **result,
wasmtime_instance_t *result,
int32_t *language_address
) {
// Build language function name string.
wasmtime_context_t *context = wasmtime_store_context(self->store);
wasmtime_error_t *error = NULL;
wasm_trap_t *trap = NULL;
// Construct the language function name as string.
unsigned prefix_len = strlen("tree_sitter_");
unsigned name_len = strlen(language_name);
char language_function_name[prefix_len + name_len + 1];
@ -261,32 +345,35 @@ static bool ts_wasm_store__instantiate(
memcpy(&language_function_name[prefix_len], language_name, name_len);
language_function_name[prefix_len + name_len] = '\0';
wasm_importtype_vec_t import_types = WASM_EMPTY_VEC;
wasm_module_imports(module, &import_types);
// Construct globals representing the offset in memory and in the function
// table where the module should be added.
wasmtime_val_t table_base_val = WASM_I32_VAL(self->current_function_table_offset);
wasmtime_val_t memory_base_val = WASM_I32_VAL(self->current_memory_offset);
wasmtime_global_t memory_base_global;
wasmtime_global_t table_base_global;
wasm_globaltype_t *const_i32_type = wasm_globaltype_new(wasm_valtype_new_i32(), WASM_CONST);
wasm_val_t table_base_val = WASM_I32_VAL(5);
wasm_val_t memory_base_val = WASM_I32_VAL(1600);
wasm_global_t *memory_base_global = wasm_global_new(self->store, const_i32_type, &memory_base_val);
wasm_global_t *table_base_global = wasm_global_new(self->store, const_i32_type, &table_base_val);
error = wasmtime_global_new(context, const_i32_type, &memory_base_val, &memory_base_global);
assert(!error);
error = wasmtime_global_new(context, const_i32_type, &table_base_val, &table_base_global);
assert(!error);
wasm_globaltype_delete(const_i32_type);
// Build imports list
printf("import count: %lu\n", import_types.size);
wasm_extern_t *imports_list[import_types.size];
wasm_extern_vec_t imports = WASM_ARRAY_VEC(imports_list);
// Build the imports list for the module.
wasm_importtype_vec_t import_types = WASM_EMPTY_VEC;
wasmtime_module_imports(module, &import_types);
wasmtime_extern_t imports[import_types.size];
for (unsigned i = 0; i < import_types.size; i++) {
const wasm_importtype_t *import_type = import_types.data[i];
const wasm_name_t *import_name = wasm_importtype_name(import_type);
if (name_eq(import_name, "__memory_base")) {
imports.data[i] = wasm_global_as_extern(memory_base_global);
imports[i] = (wasmtime_extern_t) {.kind = WASMTIME_EXTERN_GLOBAL, .of.global = memory_base_global};
} else if (name_eq(import_name, "__table_base")) {
imports.data[i] = wasm_global_as_extern(table_base_global);
imports[i] = (wasmtime_extern_t) {.kind = WASMTIME_EXTERN_GLOBAL, .of.global = table_base_global};
} else if (name_eq(import_name, "memory")) {
imports.data[i] = wasm_memory_as_extern(self->memory);
imports[i] = (wasmtime_extern_t) {.kind = WASMTIME_EXTERN_MEMORY, .of.memory = self->memory};
} else if (name_eq(import_name, "__indirect_function_table")) {
imports.data[i] = wasm_table_as_extern(self->function_table);
imports[i] = (wasmtime_extern_t) {.kind = WASMTIME_EXTERN_TABLE, .of.table = self->function_table};
} else {
printf("unexpected import '%.*s'\n", (int)import_name->size, import_name->data);
return false;
@ -294,88 +381,109 @@ static bool ts_wasm_store__instantiate(
}
wasm_importtype_vec_delete(&import_types);
wasm_trap_t *trap = NULL;
wasm_instance_t *instance = wasm_instance_new(self->store, module, &imports, &trap);
wasmtime_instance_t instance;
error = wasmtime_instance_new(context, module, imports, 4, &instance, &trap);
assert(!error);
if (trap) {
wasm_message_t message;
wasm_trap_message(trap, &message);
printf("error loading wasm: %s\n", message.data);
abort();
printf("error instantiating wasm module: %s\n", message.data);
return false;
}
wasm_extern_vec_t exports = WASM_EMPTY_VEC;
// Process the module's exports.
wasmtime_extern_t language_extern;
wasm_exporttype_vec_t export_types = WASM_EMPTY_VEC;
wasm_module_exports(module, &export_types);
wasm_instance_exports(instance, &exports);
assert(export_types.size == exports.size);
printf("export count: %lu\n", export_types.size);
wasm_extern_t *language_extern = NULL;
for (unsigned i = 0; i < exports.size; i++) {
wasm_extern_t *export = exports.data[i];
wasmtime_module_exports(module, &export_types);
for (unsigned i = 0; i < export_types.size; i++) {
wasm_exporttype_t *export_type = export_types.data[i];
const wasm_name_t *name = wasm_exporttype_name(export_type);
printf(" export name: %.*s\n", (int)name->size, name->data);
char *export_name;
size_t name_len;
wasmtime_extern_t export = {.kind = WASM_EXTERN_GLOBAL};
bool exists = wasmtime_instance_export_nth(context, &instance, i, &export_name, &name_len, &export);
assert(exists);
// Update pointers to reflect memory and function table offsets.
if (name_eq(name, "__wasm_apply_data_relocs")) {
wasm_func_t *apply_relocation_func = wasm_extern_as_func(export);
wasm_val_vec_t arguments = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
wasm_trap_t *trap = wasm_func_call(apply_relocation_func, &arguments, &results);
wasmtime_func_t apply_relocation_func = export.of.func;
error = wasmtime_func_call(context, &apply_relocation_func, NULL, 0, NULL, 0, &trap);
assert(!error);
if (trap) {
wasm_message_t message;
wasm_trap_message(trap, &message);
printf("error calling relocation function: %s\n", message.data);
abort();
}
} else if (name_eq(name, language_function_name)) {
}
// Find the main language function for the module.
else if (name_eq(name, language_function_name)) {
language_extern = export;
}
}
wasm_exporttype_vec_delete(&export_types);
if (!language_extern) {
if (language_extern.kind != WASMTIME_EXTERN_FUNC) {
printf("failed to find function %s\n", language_function_name);
abort();
return false;
}
wasm_func_t *language_func = wasm_extern_as_func(language_extern);
wasm_val_vec_t arguments = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
wasm_val_vec_new_uninitialized(&results, 1);
trap = wasm_func_call(language_func, &arguments, &results);
// Invoke the language function to get the static address of the language object.
wasmtime_func_t language_func = language_extern.of.func;
wasmtime_val_t language_address_val;
error = wasmtime_func_call(context, &language_func, NULL, 0, &language_address_val, 1, &trap);
assert(!error);
if (trap) {
wasm_message_t message;
wasm_trap_message(trap, &message);
printf("error calling language function: %s\n", message.data);
abort();
return false;
}
wasm_val_t language_address_val = results.data[0];
assert(language_address_val.kind == WASM_I32);
assert(language_address_val.kind == WASMTIME_I32);
*result = instance;
*language_address = language_address_val.of.i32;
return true;
}
TSWasmLanguage *ts_wasm_store_load_language(
static bool ts_wasm_store__sentinel_lex_fn(TSLexer *_lexer, TSStateId state) {
return false;
}
const TSLanguage *ts_wasm_store_load_language(
TSWasmStore *self,
const char *language_name,
const char *wasm,
uint32_t wasm_len
) {
// Instantiate module.
wasm_byte_vec_t file = {.size = wasm_len, .data = (char *)wasm};
wasm_module_t *module = wasm_module_new(self->store, &file);
// Compile the wasm code.
wasmtime_module_t *module;
wasmtime_error_t *error = wasmtime_module_new(self->engine, (const uint8_t *)wasm, wasm_len, &module);
if (error) {
wasm_message_t message;
wasmtime_error_message(error, &message);
printf("failed to load wasm language: %s", message.data);
return NULL;
}
wasm_instance_t *instance;
// Instantiate the module in this store.
wasmtime_instance_t instance;
int32_t language_address;
if (!ts_wasm_store__instantiate(self, module, language_name, &instance, &language_address)) return NULL;
if (!ts_wasm_store__instantiate(
self,
module,
language_name,
&instance,
&language_address
)) return NULL;
// Copy all of the static data out of the language object in wasm memory,
// constructing a native language object.
LanguageInWasmMemory wasm_language;
const byte_t *memory = wasm_memory_data(self->memory);
wasmtime_context_t *context = wasmtime_store_context(self->store);
const uint8_t *memory = wasmtime_memory_data(context, &self->memory);
memcpy(&wasm_language, &memory[language_address], sizeof(LanguageInWasmMemory));
TSLanguage *language = ts_malloc(sizeof(TSLanguage));
@ -400,12 +508,12 @@ TSWasmLanguage *ts_wasm_store_load_language(
),
.parse_actions = copy(
&memory[wasm_language.parse_actions],
3000 // TODO - determine number of parse actions
2800 * sizeof(TSParseActionEntry) // TODO - determine number of parse actions
),
.symbol_names = copy_strings(
memory,
wasm_language.symbol_names,
wasm_language.symbol_count,
wasm_language.symbol_count + wasm_language.alias_count,
&symbol_name_buffer
),
.symbol_metadata = copy(
@ -435,7 +543,7 @@ TSWasmLanguage *ts_wasm_store_load_language(
language->field_names = copy_strings(
memory,
wasm_language.field_names,
wasm_language.field_count,
wasm_language.field_count + 1,
&field_name_buffer
);
}
@ -454,7 +562,7 @@ TSWasmLanguage *ts_wasm_store_load_language(
}
language->alias_map = copy(
&memory[wasm_language.alias_map],
alias_map_size
alias_map_size * sizeof(TSSymbol)
);
language->alias_sequences = copy(
&memory[wasm_language.alias_sequences],
@ -475,42 +583,74 @@ TSWasmLanguage *ts_wasm_store_load_language(
);
}
TSWasmLanguage *result = ts_malloc(sizeof(TSWasmLanguage));
*result = (TSWasmLanguage) {
.id = atomic_inc(&NEXT_LANGUAGE_ID),
.ref_count = 1,
.module = wasm_module_share(module),
.language = language,
unsigned name_len = strlen(language_name);
char *name = ts_malloc(name_len + 1);
memcpy(name, language_name, name_len);
name[name_len] = '\0';
LanguageWasmModule *language_module = ts_malloc(sizeof(LanguageWasmModule));
*language_module = (LanguageWasmModule) {
.language_id = atomic_inc(&NEXT_LANGUAGE_ID),
.module = module,
.name = name,
.symbol_name_buffer = symbol_name_buffer.contents,
.field_name_buffer = field_name_buffer.contents,
};
array_push(&self->language_instances, ((LanguageInstance) {
// The lex functions are not used for wasm languages. Use those two fields
// to mark this language as WASM-based and to store the language's
// WASM-specific data.
language->lex_fn = ts_wasm_store__sentinel_lex_fn;
language->keyword_lex_fn = (void *)language_module;
// Store some information about this store's specific instance of this
// language module, keyed by the language's id.
array_push(&self->language_instances, ((LanguageWasmInstance) {
.language_id = language_module->language_id,
.instance = instance,
.external_scan_index = wasm_language.external_scanner.scan,
.keyword_lex_fn_index = wasm_language.keyword_lex_fn,
.main_lex_fn_index = wasm_language.lex_fn,
.keyword_lex_fn_index = wasm_language.keyword_lex_fn,
}));
return result;
return language;
}
bool ts_wasm_store_start(TSWasmStore *self, TSLexer *lexer, const TSWasmLanguage *language) {
bool ts_wasm_store_start(TSWasmStore *self, TSLexer *lexer, const TSLanguage *language) {
if (!ts_language_is_wasm(language)) return false;
wasmtime_context_t *context = wasmtime_store_context(self->store);
const LanguageWasmModule *language_module = (void *)language->keyword_lex_fn;
// Search for the information about this store's instance of the language module.
uint32_t instance_index = 0;
bool exists = false;
array_search_sorted_by(&self->language_instances, .id, language->id, &instance_index, &exists);
array_search_sorted_by(
&self->language_instances,
.language_id,
language_module->language_id,
&instance_index,
&exists
);
// If the language module has not been instantiated in this store, then add
// it to this store.
if (!exists) {
wasm_module_t *module = wasm_module_obtain(self->store, language->module);
wasm_instance_t *instance;
wasmtime_instance_t instance;
int32_t language_address;
if (!ts_wasm_store__instantiate(self, module, language->name, &instance, &language_address)) {
if (!ts_wasm_store__instantiate(
self,
language_module->module,
language_module->name,
&instance,
&language_address
)) {
return false;
}
LanguageInWasmMemory wasm_language;
const byte_t *memory = wasm_memory_data(self->memory);
const uint8_t *memory = wasmtime_memory_data(context, &self->memory);
memcpy(&wasm_language, &memory[language_address], sizeof(LanguageInWasmMemory));
array_insert(&self->language_instances, instance_index, ((LanguageInstance) {
.id = language->id,
array_insert(&self->language_instances, instance_index, ((LanguageWasmInstance) {
.language_id = language_module->language_id,
.instance = instance,
.main_lex_fn_index = wasm_language.lex_fn,
.keyword_lex_fn_index = wasm_language.keyword_lex_fn,
@ -525,4 +665,66 @@ bool ts_wasm_store_start(TSWasmStore *self, TSLexer *lexer, const TSWasmLanguage
void ts_wasm_store_stop(TSWasmStore *self) {
self->current_lexer = NULL;
self->current_instance = NULL;
}
bool ts_wasm_store_run_lex_function(TSWasmStore *self, TSStateId state, unsigned function_index) {
wasmtime_context_t *context = wasmtime_store_context(self->store);
uint8_t *memory_data = wasmtime_memory_data(context, &self->memory);
memcpy(
&memory_data[LEXER_ADDRESS],
&self->current_lexer->lookahead,
sizeof(self->current_lexer->lookahead)
);
wasmtime_val_t lex_val;
bool succeeded = wasmtime_table_get(context, &self->function_table, function_index, &lex_val);
assert(succeeded);
assert(lex_val.kind == WASMTIME_FUNCREF);
wasmtime_func_t lex_func = lex_val.of.funcref;
const wasmtime_val_t args[2] = {
{.kind = WASMTIME_I32, .of.i32 = LEXER_ADDRESS},
{.kind = WASMTIME_I32, .of.i32 = state},
};
wasmtime_val_t results[1] = {
{.kind = WASMTIME_I32, .of.i32 = 0}
};
wasm_trap_t *trap = NULL;
wasmtime_func_call(context, &lex_func, args, 2, results, 1, &trap);
if (trap) {
wasm_message_t message;
wasm_trap_message(trap, &message);
printf("error calling lex function index %u: %s\n", function_index, message.data);
abort();
}
assert(results[0].kind == WASM_I32);
memcpy(
&self->current_lexer->lookahead,
&memory_data[LEXER_ADDRESS],
sizeof(self->current_lexer->lookahead) + sizeof(self->current_lexer->result_symbol)
);
return results[0].of.i32;
}
bool ts_wasm_store_run_main_lex_function(TSWasmStore *self, TSStateId state) {
return ts_wasm_store_run_lex_function(
self,
state,
self->current_instance->main_lex_fn_index
);
}
bool ts_wasm_store_run_keyword_lex_function(TSWasmStore *self, TSStateId state) {
return ts_wasm_store_run_lex_function(
self,
state,
self->current_instance->keyword_lex_fn_index
);
}
bool ts_language_is_wasm(const TSLanguage *self) {
return self->lex_fn == ts_wasm_store__sentinel_lex_fn;
}

View file

@ -5,76 +5,13 @@
extern "C" {
#endif
#include "./array.h"
#include "./wasm/wasm.h"
#include "./lexer.h"
#include "tree_sitter/api.h"
#include "tree_sitter/parser.h"
typedef struct {
uint32_t id;
wasm_instance_t *instance;
uint32_t main_lex_fn_index;
uint32_t keyword_lex_fn_index;
uint32_t external_scan_index;
} LanguageInstance;
struct TSWasmStore {
wasm_store_t *store;
wasm_table_t *function_table;
wasm_memory_t *memory;
TSLexer *current_lexer;
LanguageInstance *current_instance;
Array(LanguageInstance) language_instances;
};
struct TSWasmLanguage {
uint32_t id;
volatile uint32_t ref_count;
wasm_shared_module_t *module;
TSLanguage *language;
const char *name;
char *symbol_name_buffer;
char *field_name_buffer;
};
void ts_wasm_language_retain(const TSWasmLanguage *);
bool ts_wasm_store_start(TSWasmStore *self, TSLexer *lexer, const TSWasmLanguage *language);
bool ts_wasm_store_start(TSWasmStore *self, TSLexer *lexer, const TSLanguage *language);
void ts_wasm_store_stop(TSWasmStore *self);
static inline bool ts_wasm_store_run_main_lex_function(TSWasmStore *self, TSStateId state) {
uint32_t function_index = self->current_instance->main_lex_fn_index;
wasm_ref_t *lex_ref = wasm_table_get(self->function_table, function_index);
wasm_func_t *lex_func = wasm_ref_as_func(lex_ref);
wasm_val_t args_list[2] = {
WASM_I32_VAL(state),
WASM_I32_VAL(state),
};
wasm_val_t results_list[1] = {
WASM_I32_VAL(0),
};
wasm_val_vec_t args = WASM_ARRAY_VEC(args_list);
wasm_val_vec_t results = WASM_ARRAY_VEC(results_list);
wasm_func_call(lex_func, &args, &results);
assert(results_list[0].kind == WASM_I32);
return results_list[0].of.i32;
}
static inline bool ts_wasm_store_run_keyword_lex_function(TSWasmStore *self, TSStateId state) {
uint32_t function_index = self->current_instance->keyword_lex_fn_index;
wasm_ref_t *lex_ref = wasm_table_get(self->function_table, function_index);
wasm_func_t *lex_func = wasm_ref_as_func(lex_ref);
wasm_val_t args_list[2] = {
WASM_I32_VAL(state),
WASM_I32_VAL(state),
};
wasm_val_t results_list[1] = {
WASM_I32_VAL(0),
};
wasm_val_vec_t args = WASM_ARRAY_VEC(args_list);
wasm_val_vec_t results = WASM_ARRAY_VEC(results_list);
wasm_func_call(lex_func, &args, &results);
assert(results_list[0].kind == WASM_I32);
return results_list[0].of.i32;
}
bool ts_wasm_store_run_main_lex_function(TSWasmStore *self, TSStateId state);
bool ts_wasm_store_run_keyword_lex_function(TSWasmStore *self, TSStateId state);
#ifdef __cplusplus
}

View file

@ -1,6 +1,9 @@
## WASM
The `wasm.h` header file contains a standard interface implemented by multiple WASM implementations.
It was taken from here:
The `wasm.h` header file contains a standard interface implemented by multiple WASM implementations. It was taken from here:
https://github.com/WebAssembly/wasm-c-api/blob/c9d31284651b975f05ac27cee0bab1377560b87e/include/wasm.h
https://github.com/WebAssembly/wasm-c-api/blob/c9d31284651b975f05ac27cee0bab1377560b87e/include/wasm.h
The `wasmtime` headers were taken from here:
https://github.com/bytecodealliance/wasmtime/tree/main/crates/c-api/include/wasmtime

155
lib/src/wasm/wasi.h Normal file
View file

@ -0,0 +1,155 @@
/**
* \file wasi.h
*
* C API for WASI
*/
#ifndef WASI_H
#define WASI_H
#include "wasm.h"
#ifndef WASI_API_EXTERN
#ifdef _WIN32
#define WASI_API_EXTERN __declspec(dllimport)
#else
#define WASI_API_EXTERN
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define own
#define WASI_DECLARE_OWN(name) \
typedef struct wasi_##name##_t wasi_##name##_t; \
WASI_API_EXTERN void wasi_##name##_delete(own wasi_##name##_t*);
/**
* \typedef wasi_config_t
* \brief Convenience alias for #wasi_config_t
*
* \struct wasi_config_t
* \brief TODO
*
* \fn void wasi_config_delete(wasi_config_t *);
* \brief Deletes a configuration object.
*/
WASI_DECLARE_OWN(config)
/**
* \brief Creates a new empty configuration object.
*
* The caller is expected to deallocate the returned configuration
*/
WASI_API_EXTERN own wasi_config_t* wasi_config_new();
/**
* \brief Sets the argv list for this configuration object.
*
* By default WASI programs have an empty argv list, but this can be used to
* explicitly specify what the argv list for the program is.
*
* The arguments are copied into the `config` object as part of this function
* call, so the `argv` pointer only needs to stay alive for this function call.
*/
WASI_API_EXTERN void wasi_config_set_argv(wasi_config_t* config, int argc, const char* argv[]);
/**
* \brief Indicates that the argv list should be inherited from this process's
* argv list.
*/
WASI_API_EXTERN void wasi_config_inherit_argv(wasi_config_t* config);
/**
* \brief Sets the list of environment variables available to the WASI instance.
*
* By default WASI programs have a blank environment, but this can be used to
* define some environment variables for them.
*
* It is required that the `names` and `values` lists both have `envc` entries.
*
* The env vars are copied into the `config` object as part of this function
* call, so the `names` and `values` pointers only need to stay alive for this
* function call.
*/
WASI_API_EXTERN void wasi_config_set_env(wasi_config_t* config, int envc, const char* names[], const char* values[]);
/**
* \brief Indicates that the entire environment of the calling process should be
* inherited by this WASI configuration.
*/
WASI_API_EXTERN void wasi_config_inherit_env(wasi_config_t* config);
/**
* \brief Configures standard input to be taken from the specified file.
*
* By default WASI programs have no stdin, but this configures the specified
* file to be used as stdin for this configuration.
*
* If the stdin location does not exist or it cannot be opened for reading then
* `false` is returned. Otherwise `true` is returned.
*/
WASI_API_EXTERN bool wasi_config_set_stdin_file(wasi_config_t* config, const char* path);
/**
* \brief Configures this process's own stdin stream to be used as stdin for
* this WASI configuration.
*/
WASI_API_EXTERN void wasi_config_inherit_stdin(wasi_config_t* config);
/**
* \brief Configures standard output to be written to the specified file.
*
* By default WASI programs have no stdout, but this configures the specified
* file to be used as stdout.
*
* If the stdout location could not be opened for writing then `false` is
* returned. Otherwise `true` is returned.
*/
WASI_API_EXTERN bool wasi_config_set_stdout_file(wasi_config_t* config, const char* path);
/**
* \brief Configures this process's own stdout stream to be used as stdout for
* this WASI configuration.
*/
WASI_API_EXTERN void wasi_config_inherit_stdout(wasi_config_t* config);
/**
* \brief Configures standard output to be written to the specified file.
*
* By default WASI programs have no stderr, but this configures the specified
* file to be used as stderr.
*
* If the stderr location could not be opened for writing then `false` is
* returned. Otherwise `true` is returned.
*/
WASI_API_EXTERN bool wasi_config_set_stderr_file(wasi_config_t* config, const char* path);
/**
* \brief Configures this process's own stderr stream to be used as stderr for
* this WASI configuration.
*/
WASI_API_EXTERN void wasi_config_inherit_stderr(wasi_config_t* config);
/**
* \brief Configures a "preopened directory" to be available to WASI APIs.
*
* By default WASI programs do not have access to anything on the filesystem.
* This API can be used to grant WASI programs access to a directory on the
* filesystem, but only that directory (its whole contents but nothing above it).
*
* The `path` argument here is a path name on the host filesystem, and
* `guest_path` is the name by which it will be known in wasm.
*/
WASI_API_EXTERN bool wasi_config_preopen_dir(wasi_config_t* config, const char* path, const char* guest_path);
#undef own
#ifdef __cplusplus
} // extern "C"
#endif
#endif // #ifdef WASI_H

228
lib/src/wasm/wasmtime.h Normal file
View file

@ -0,0 +1,228 @@
/**
* \mainpage Wasmtime C API
*
* This documentation is an overview and API reference for the C API of
* Wasmtime. The C API is spread between three different header files:
*
* * \ref wasmtime.h
* * \ref wasi.h
* * \ref wasm.h
*
* The \ref wasmtime.h header file includes all the other header files and is
* the main header file you'll likely be using. The \ref wasm.h header file
* comes directly from the
* [WebAssembly/wasm-c-api](https://github.com/WebAssembly/wasm-c-api)
* repository, and at this time the upstream header file does not have
* documentation so Wasmtime provides documentation here. It should be noted
* some semantics may be Wasmtime-specific and may not be portable to other
* engines.
*
* ## Installing the C API
*
* To install the C API from precompiled binaries you can download the
* appropriate binary from the [releases page of
* Wasmtime](https://github.com/bytecodealliance/wasmtime/releases). Artifacts
* for the C API all end in "-c-api" for the filename.
*
* Each archive contains an `include` directory with necessary headers, as well
* as a `lib` directory with both a static archive and a dynamic library of
* Wasmtime. You can link to either of them as you see fit.
*
* ## Installing the C API through CMake
*
* CMake can be used to make the process of linking and compiling easier. An
* example of this if you have wasmtime as a git submodule at
* `third_party/wasmtime`:
* ```
* add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third_party/wasmtime/crates/c-api
* ${CMAKE_CURRENT_BINARY_DIR}/wasmtime)
* ...
* target_include_directories(YourProject PUBLIC wasmtime)
* target_link_libraries(YourProject PUBLIC wasmtime)
* ```
* `BUILD_SHARED_LIBS` is provided as a define if you would like to build a
* shared library instead. You must distribute the appropriate shared library
* for your platform if you do this.
*
* ## Linking against the C API
*
* You'll want to arrange the `include` directory of the C API to be in your
* compiler's header path (e.g. the `-I` flag). If you're compiling for Windows
* and you're using the static library then you'll also need to pass
* `-DWASM_API_EXTERN=` and `-DWASI_API_EXTERN=` to disable dllimport.
*
* Your final artifact can then be linked with `-lwasmtime`. If you're linking
* against the static library you may need to pass other system libraries
* depending on your platform:
*
* * Linux - `-lpthread -ldl -lm`
* * macOS - no extra flags needed
* * Windows - `ws2_32.lib advapi32.lib userenv.lib ntdll.lib shell32.lib ole32.lib bcrypt.lib`
*
* ## Building from Source
*
* The C API is located in the
* [`crates/c-api`](https://github.com/bytecodealliance/wasmtime/tree/main/crates/c-api)
* directory of the [Wasmtime
* repository](https://github.com/bytecodealliance/wasmtime). To build from
* source you'll need a Rust compiler and a checkout of the `wasmtime` project.
* Afterwards you can execute:
*
* ```
* $ cargo build --release -p wasmtime-c-api
* ```
*
* This will place the final artifacts in `target/release`, with names depending
* on what platform you're compiling for.
*
* ## Other resources
*
* Some other handy resources you might find useful when exploring the C API
* documentation are:
*
* * [Rust `wasmtime` crate
* documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/) -
* although this documentation is for Rust and not C, you'll find that many
* functions mirror one another and there may be extra documentation in Rust
* you find helpful. If you find yourself having to frequently do this,
* though, please feel free to [file an
* issue](https://github.com/bytecodealliance/wasmtime/issues/new).
*
* * [C embedding
* examples](https://bytecodealliance.github.io/wasmtime/examples-c-embed.html)
* are available online and are tested from the Wasmtime repository itself.
*
* * [Contribution documentation for
* Wasmtime](https://bytecodealliance.github.io/wasmtime/contributing.html) in
* case you're interested in helping out!
*/
/**
* \file wasmtime.h
*
* \brief Wasmtime's C API
*
* This file is the central inclusion point for Wasmtime's C API. There are a
* number of sub-header files but this file includes them all. The C API is
* based on \ref wasm.h but there are many Wasmtime-specific APIs which are
* tailored to Wasmtime's implementation.
*
* The #wasm_config_t and #wasm_engine_t types are used from \ref wasm.h.
* Additionally all type-level information (like #wasm_functype_t) is also
* used from \ref wasm.h. Otherwise, though, all wasm objects (like
* #wasmtime_store_t or #wasmtime_func_t) are used from this header file.
*
* ### Thread Safety
*
* The multithreading story of the C API very closely follows the
* multithreading story of the Rust API for Wasmtime. All objects are safe to
* send to other threads so long as user-specific data is also safe to send to
* other threads. Functions are safe to call from any thread but some functions
* cannot be called concurrently. For example, functions which correspond to
* `&T` in Rust can be called concurrently with any other methods that take
* `&T`. Functions that take `&mut T` in Rust, however, cannot be called
* concurrently with any other function (but can still be invoked on any
* thread).
*
* This generally equates to mutation of internal state. Functions which don't
* mutate anything, such as learning type information through
* #wasmtime_func_type, can be called concurrently. Functions which do require
* mutation, for example #wasmtime_func_call, cannot be called concurrently.
* This is conveyed in the C API with either `const wasmtime_context_t*`
* (concurrency is ok as it's read-only) or `wasmtime_context_t*` (concurrency
* is not ok, mutation may happen).
*
* When in doubt assume that functions cannot be called concurrently with
* aliasing objects.
*
* ### Aliasing
*
* The C API for Wasmtime is intended to be a relatively thin layer over the
* Rust API for Wasmtime. Rust has much more strict rules about aliasing than C
* does, and the Rust API for Wasmtime is designed around these rules to be
* used safely. These same rules must be upheld when using the C API of
* Wasmtime.
*
* The main consequence of this is that the #wasmtime_context_t pointer into
* the #wasmtime_store_t must be carefully used. Since the context is an
* internal pointer into the store it must be used carefully to ensure you're
* not doing something that Rust would otherwise forbid at compile time. A
* #wasmtime_context_t can only be used when you would otherwise have been
* provided access to it. For example in a host function created with
* #wasmtime_func_new you can use #wasmtime_context_t in the host function
* callback. This is because an argument, a #wasmtime_caller_t, provides access
* to #wasmtime_context_t. On the other hand a destructor passed to
* #wasmtime_externref_new, however, cannot use a #wasmtime_context_t because
* it was not provided access to one. Doing so may lead to memory unsafety.
*
* ### Stores
*
* A foundational construct in this API is the #wasmtime_store_t. A store is a
* collection of host-provided objects and instantiated wasm modules. Stores are
* often treated as a "single unit" and items within a store are all allowed to
* reference one another. References across stores cannot currently be created.
* For example you cannot pass a function from one store into another store.
*
* A store is not intended to be a global long-lived object. Stores provide no
* means of internal garbage collections of wasm objects (such as instances),
* meaning that no memory from a store will be deallocated until you call
* #wasmtime_store_delete. If you're working with a web server, for example,
* then it's recommended to think of a store as a "one per request" sort of
* construct. Globally you'd have one #wasm_engine_t and a cache of
* #wasmtime_module_t instances compiled into that engine. Each request would
* create a new #wasmtime_store_t and then instantiate a #wasmtime_module_t
* into the store. This process of creating a store and instantiating a module
* is expected to be quite fast. When the request is finished you'd delete the
* #wasmtime_store_t keeping memory usage reasonable for the lifetime of the
* server.
*/
#ifndef WASMTIME_API_H
#define WASMTIME_API_H
#include <wasi.h>
#include <wasmtime/config.h>
#include <wasmtime/engine.h>
#include <wasmtime/error.h>
#include <wasmtime/extern.h>
#include <wasmtime/func.h>
#include <wasmtime/global.h>
#include <wasmtime/instance.h>
#include <wasmtime/linker.h>
#include <wasmtime/memory.h>
#include <wasmtime/module.h>
#include <wasmtime/store.h>
#include <wasmtime/table.h>
#include <wasmtime/trap.h>
#include <wasmtime/val.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Converts from the text format of WebAssembly to to the binary format.
*
* \param wat this it the input pointer with the WebAssembly Text Format inside of
* it. This will be parsed and converted to the binary format.
* \param wat_len this it the length of `wat`, in bytes.
* \param ret if the conversion is successful, this byte vector is filled in with
* the WebAssembly binary format.
*
* \return a non-null error if parsing fails, or returns `NULL`. If parsing
* fails then `ret` isn't touched.
*
* This function does not take ownership of `wat`, and the caller is expected to
* deallocate the returned #wasmtime_error_t and #wasm_byte_vec_t.
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_wat2wasm(
const char *wat,
size_t wat_len,
wasm_byte_vec_t *ret
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_API_H

View file

@ -0,0 +1,283 @@
/**
* \file wasmtime/config.h
*
* \brief Wasmtime-specific extensions to #wasm_config_t
*/
#ifndef WASMTIME_CONFIG_H
#define WASMTIME_CONFIG_H
#include <wasm.h>
#include <wasmtime/error.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Specifier for how Wasmtime will compile code, values are in
* #wasmtime_strategy_enum
*/
typedef uint8_t wasmtime_strategy_t;
/**
* \brief Different ways that Wasmtime can compile WebAssembly
*
* The default value is #WASMTIME_STRATEGY_AUTO.
*/
enum wasmtime_strategy_enum { // Strategy
/// Automatically picks the compilation backend, currently always defaulting
/// to Cranelift.
WASMTIME_STRATEGY_AUTO,
/// Indicates that Wasmtime will unconditionally use Cranelift to compile
/// WebAssembly code.
WASMTIME_STRATEGY_CRANELIFT,
};
/**
* \brief Specifier of what optimization level to use for generated JIT code.
*
* See #wasmtime_opt_level_enum for possible values.
*/
typedef uint8_t wasmtime_opt_level_t;
/**
* \brief Different ways Wasmtime can optimize generated code.
*
* The default value is #WASMTIME_OPT_LEVEL_SPEED.
*/
enum wasmtime_opt_level_enum { // OptLevel
/// Generated code will not be optimized at all.
WASMTIME_OPT_LEVEL_NONE,
/// Generated code will be optimized purely for speed.
WASMTIME_OPT_LEVEL_SPEED,
/// Generated code will be optimized, but some speed optimizations are
/// disabled if they cause the generated code to be significantly larger.
WASMTIME_OPT_LEVEL_SPEED_AND_SIZE,
};
/**
* \brief Different ways wasmtime can enable profiling JIT code.
*
* See #wasmtime_profiling_strategy_enum for possible values.
*/
typedef uint8_t wasmtime_profiling_strategy_t;
/**
* \brief Different ways to profile JIT code.
*
* The default is #WASMTIME_PROFILING_STRATEGY_NONE.
*/
enum wasmtime_profiling_strategy_enum { // ProfilingStrategy
/// No profiling is enabled at runtime.
WASMTIME_PROFILING_STRATEGY_NONE,
/// Linux's "jitdump" support in `perf` is enabled and when Wasmtime is run
/// under `perf` necessary calls will be made to profile generated JIT code.
WASMTIME_PROFILING_STRATEGY_JITDUMP,
/// Support for VTune will be enabled and the VTune runtime will be informed,
/// at runtime, about JIT code.
///
/// Note that this isn't always enabled at build time.
WASMTIME_PROFILING_STRATEGY_VTUNE,
};
#define WASMTIME_CONFIG_PROP(ret, name, ty) \
WASM_API_EXTERN ret wasmtime_config_##name##_set(wasm_config_t*, ty);
/**
* \brief Configures whether DWARF debug information is constructed at runtime
* to describe JIT code.
*
* This setting is `false` by default. When enabled it will attempt to inform
* native debuggers about DWARF debugging information for JIT code to more
* easily debug compiled WebAssembly via native debuggers. This can also
* sometimes improve the quality of output when profiling is enabled.
*/
WASMTIME_CONFIG_PROP(void, debug_info, bool)
/**
* \brief Whether or not fuel is enabled for generated code.
*
* This setting is `false` by default. When enabled it will enable fuel counting
* meaning that fuel will be consumed every time a wasm instruction is executed,
* and trap when reaching zero.
*/
WASMTIME_CONFIG_PROP(void, consume_fuel, bool)
/**
* \brief Whether or not epoch-based interruption is enabled for generated code.
*
* This setting is `false` by default. When enabled wasm code will check the
* current epoch periodically and abort if the current epoch is beyond a
* store-configured limit.
*
* Note that when this setting is enabled all stores will immediately trap and
* need to have their epoch deadline otherwise configured with
* #wasmtime_context_set_epoch_deadline.
*
* Note that the current epoch is engine-local and can be incremented with
* #wasmtime_engine_increment_epoch.
*/
WASMTIME_CONFIG_PROP(void, epoch_interruption, bool)
/**
* \brief Configures the maximum stack size, in bytes, that JIT code can use.
*
* This setting is 2MB by default. Configuring this setting will limit the
* amount of native stack space that JIT code can use while it is executing. If
* you're hitting stack overflow you can try making this setting larger, or if
* you'd like to limit wasm programs to less stack you can also configure this.
*
* Note that this setting is not interpreted with 100% precision. Additionally
* the amount of stack space that wasm takes is always relative to the first
* invocation of wasm on the stack, so recursive calls with host frames in the
* middle will all need to fit within this setting.
*/
WASMTIME_CONFIG_PROP(void, max_wasm_stack, size_t)
/**
* \brief Configures whether the WebAssembly threading proposal is enabled.
*
* This setting is `false` by default.
*
* Note that threads are largely unimplemented in Wasmtime at this time.
*/
WASMTIME_CONFIG_PROP(void, wasm_threads, bool)
/**
* \brief Configures whether the WebAssembly reference types proposal is
* enabled.
*
* This setting is `false` by default.
*/
WASMTIME_CONFIG_PROP(void, wasm_reference_types, bool)
/**
* \brief Configures whether the WebAssembly SIMD proposal is
* enabled.
*
* This setting is `false` by default.
*/
WASMTIME_CONFIG_PROP(void, wasm_simd, bool)
/**
* \brief Configures whether the WebAssembly bulk memory proposal is
* enabled.
*
* This setting is `false` by default.
*/
WASMTIME_CONFIG_PROP(void, wasm_bulk_memory, bool)
/**
* \brief Configures whether the WebAssembly multi value proposal is
* enabled.
*
* This setting is `true` by default.
*/
WASMTIME_CONFIG_PROP(void, wasm_multi_value, bool)
/**
* \brief Configures whether the WebAssembly multi-memory proposal is
* enabled.
*
* This setting is `false` by default.
*/
WASMTIME_CONFIG_PROP(void, wasm_multi_memory, bool)
/**
* \brief Configures whether the WebAssembly memory64 proposal is
* enabled.
*
* This setting is `false` by default.
*/
WASMTIME_CONFIG_PROP(void, wasm_memory64, bool)
/**
* \brief Configures how JIT code will be compiled.
*
* This setting is #WASMTIME_STRATEGY_AUTO by default.
*/
WASMTIME_CONFIG_PROP(void, strategy, wasmtime_strategy_t)
/**
* \brief Configures whether Cranelift's debug verifier is enabled.
*
* This setting in `false` by default.
*
* When cranelift is used for compilation this enables expensive debug checks
* within Cranelift itself to verify it's correct.
*/
WASMTIME_CONFIG_PROP(void, cranelift_debug_verifier, bool)
/**
* \brief Configures whether Cranelift should perform a NaN-canonicalization pass.
*
* When Cranelift is used as a code generation backend this will configure
* it to replace NaNs with a single canonical value. This is useful for users
* requiring entirely deterministic WebAssembly computation.
*
* This is not required by the WebAssembly spec, so it is not enabled by default.
*
* The default value for this is `false`
*/
WASMTIME_CONFIG_PROP(void, cranelift_nan_canonicalization, bool)
/**
* \brief Configures Cranelift's optimization level for JIT code.
*
* This setting in #WASMTIME_OPT_LEVEL_SPEED by default.
*/
WASMTIME_CONFIG_PROP(void, cranelift_opt_level, wasmtime_opt_level_t)
/**
* \brief Configures the profiling strategy used for JIT code.
*
* This setting in #WASMTIME_PROFILING_STRATEGY_NONE by default.
*/
WASMTIME_CONFIG_PROP(void, profiler, wasmtime_profiling_strategy_t)
/**
* \brief Configures the maximum size for memory to be considered "static"
*
* For more information see the Rust documentation at
* https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.static_memory_maximum_size.
*/
WASMTIME_CONFIG_PROP(void, static_memory_maximum_size, uint64_t)
/**
* \brief Configures the guard region size for "static" memory.
*
* For more information see the Rust documentation at
* https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.static_memory_guard_size.
*/
WASMTIME_CONFIG_PROP(void, static_memory_guard_size, uint64_t)
/**
* \brief Configures the guard region size for "dynamic" memory.
*
* For more information see the Rust documentation at
* https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Config.html#method.dynamic_memory_guard_size.
*/
WASMTIME_CONFIG_PROP(void, dynamic_memory_guard_size, uint64_t)
/**
* \brief Enables Wasmtime's cache and loads configuration from the specified
* path.
*
* By default the Wasmtime compilation cache is disabled. The configuration path
* here can be `NULL` to use the default settings, and otherwise the argument
* here must be a file on the filesystem with TOML configuration -
* https://bytecodealliance.github.io/wasmtime/cli-cache.html.
*
* An error is returned if the cache configuration could not be loaded or if the
* cache could not be enabled.
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_config_cache_config_load(wasm_config_t*, const char*);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_CONFIG_H

View file

@ -0,0 +1,36 @@
/**
* \file wasmtime/engine.h
*
* Wasmtime-specific extensions to #wasm_engine_t.
*/
#ifndef WASMTIME_ENGINE_H
#define WASMTIME_ENGINE_H
#include <wasm.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Increments the engine-local epoch variable.
*
* This function will increment the engine's current epoch which can be used to
* force WebAssembly code to trap if the current epoch goes beyond the
* #wasmtime_store_t configured epoch deadline.
*
* This function is safe to call from any thread, and it is also
* async-signal-safe.
*
* See also #wasmtime_config_epoch_interruption_set.
*/
WASM_API_EXTERN void wasmtime_engine_increment_epoch(wasm_engine_t *engine);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_ENGINE_H

View file

@ -0,0 +1,55 @@
/**
* \file wasmtime/error.h
*
* \brief Definition and accessors of #wasmtime_error_t
*/
#ifndef WASMTIME_ERROR_H
#define WASMTIME_ERROR_H
#include <wasm.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \typedef wasmtime_error_t
* \brief Convenience alias for #wasmtime_error
*
* \struct wasmtime_error
* \brief Errors generated by Wasmtime.
* \headerfile wasmtime/error.h
*
* This opaque type represents an error that happened as part of one of the
* functions below. Errors primarily have an error message associated with them
* at this time, which you can acquire by calling #wasmtime_error_message.
*
* Errors are safe to share across threads and must be deleted with
* #wasmtime_error_delete.
*/
typedef struct wasmtime_error wasmtime_error_t;
/**
* \brief Deletes an error.
*/
WASM_API_EXTERN void wasmtime_error_delete(wasmtime_error_t *error);
/**
* \brief Returns the string description of this error.
*
* This will "render" the error to a string and then return the string
* representation of the error to the caller. The `message` argument should be
* uninitialized before this function is called and the caller is responsible
* for deallocating it with #wasm_byte_vec_delete afterwards.
*/
WASM_API_EXTERN void wasmtime_error_message(
const wasmtime_error_t *error,
wasm_name_t *message
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_ERROR_H

View file

@ -0,0 +1,145 @@
/**
* \file wasmtime/extern.h
*
* \brief Definition of #wasmtime_extern_t and external items.
*/
#ifndef WASMTIME_EXTERN_H
#define WASMTIME_EXTERN_H
#include <wasmtime/module.h>
#include <wasmtime/store.h>
#ifdef __cplusplus
extern "C" {
#endif
/// \brief Representation of a function in Wasmtime.
///
/// Functions are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Functions cannot
/// interoperate between #wasmtime_store_t instances and if the wrong function
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
typedef struct wasmtime_func {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
} wasmtime_func_t;
/// \brief Representation of a table in Wasmtime.
///
/// Tables are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Tables cannot
/// interoperate between #wasmtime_store_t instances and if the wrong table
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
typedef struct wasmtime_table {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
} wasmtime_table_t;
/// \brief Representation of a memory in Wasmtime.
///
/// Memories are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Memories cannot
/// interoperate between #wasmtime_store_t instances and if the wrong memory
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
typedef struct wasmtime_memory {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
} wasmtime_memory_t;
/// \brief Representation of a global in Wasmtime.
///
/// Globals are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Globals cannot
/// interoperate between #wasmtime_store_t instances and if the wrong global
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
typedef struct wasmtime_global {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
} wasmtime_global_t;
/// \brief Discriminant of #wasmtime_extern_t
typedef uint8_t wasmtime_extern_kind_t;
/// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is a
/// function
#define WASMTIME_EXTERN_FUNC 0
/// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is a
/// global
#define WASMTIME_EXTERN_GLOBAL 1
/// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is a
/// table
#define WASMTIME_EXTERN_TABLE 2
/// \brief Value of #wasmtime_extern_kind_t meaning that #wasmtime_extern_t is a
/// memory
#define WASMTIME_EXTERN_MEMORY 3
/**
* \typedef wasmtime_extern_union_t
* \brief Convenience alias for #wasmtime_extern_union
*
* \union wasmtime_extern_union
* \brief Container for different kinds of extern items.
*
* This type is contained in #wasmtime_extern_t and contains the payload for the
* various kinds of items an extern wasm item can be.
*/
typedef union wasmtime_extern_union {
/// Field used if #wasmtime_extern_t::kind is #WASMTIME_EXTERN_FUNC
wasmtime_func_t func;
/// Field used if #wasmtime_extern_t::kind is #WASMTIME_EXTERN_GLOBAL
wasmtime_global_t global;
/// Field used if #wasmtime_extern_t::kind is #WASMTIME_EXTERN_TABLE
wasmtime_table_t table;
/// Field used if #wasmtime_extern_t::kind is #WASMTIME_EXTERN_MEMORY
wasmtime_memory_t memory;
} wasmtime_extern_union_t;
/**
* \typedef wasmtime_extern_t
* \brief Convenience alias for #wasmtime_extern_t
*
* \union wasmtime_extern
* \brief Container for different kinds of extern items.
*
* Note that this structure may contain an owned value, namely
* #wasmtime_module_t, depending on the context in which this is used. APIs
* which consume a #wasmtime_extern_t do not take ownership, but APIs that
* return #wasmtime_extern_t require that #wasmtime_extern_delete is called to
* deallocate the value.
*/
typedef struct wasmtime_extern {
/// Discriminant of which field of #of is valid.
wasmtime_extern_kind_t kind;
/// Container for the extern item's value.
wasmtime_extern_union_t of;
} wasmtime_extern_t;
/// \brief Deletes a #wasmtime_extern_t.
void wasmtime_extern_delete(wasmtime_extern_t *val);
/// \brief Returns the type of the #wasmtime_extern_t defined within the given
/// store.
///
/// Does not take ownership of `context` or `val`, but the returned
/// #wasm_externtype_t is an owned value that needs to be deleted.
wasm_externtype_t *wasmtime_extern_type(wasmtime_context_t *context, wasmtime_extern_t *val);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_EXTERN_H

View file

@ -0,0 +1,310 @@
/**
* \file wasmtime/func.h
*
* Wasmtime definitions of how to interact with host and wasm functions.
*/
#ifndef WASMTIME_FUNC_H
#define WASMTIME_FUNC_H
#include <wasm.h>
#include <wasmtime/val.h>
#include <wasmtime/store.h>
#include <wasmtime/extern.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \typedef wasmtime_caller_t
* \brief Alias to #wasmtime_caller
*
* \brief Structure used to learn about the caller of a host-defined function.
* \struct wasmtime_caller
*
* This structure is an argument to #wasmtime_func_callback_t. The purpose
* of this structure is acquire a #wasmtime_context_t pointer to interact with
* objects, but it can also be used for inspect the state of the caller (such as
* getting memories and functions) with #wasmtime_caller_export_get.
*
* This object is never owned and does not need to be deleted.
*/
typedef struct wasmtime_caller wasmtime_caller_t;
/**
* \brief Callback signature for #wasmtime_func_new.
*
* This is the function signature for host functions that can be made accessible
* to WebAssembly. The arguments to this function are:
*
* \param env user-provided argument passed to #wasmtime_func_new
* \param caller a temporary object that can only be used during this function
* call. Used to acquire #wasmtime_context_t or caller's state
* \param args the arguments provided to this function invocation
* \param nargs how many arguments are provided
* \param results where to write the results of this function
* \param nresults how many results must be produced
*
* Callbacks are guaranteed to get called with the right types of arguments, but
* they must produce the correct number and types of results. Failure to do so
* will cause traps to get raised on the wasm side.
*
* This callback can optionally return a #wasm_trap_t indicating that a trap
* should be raised in WebAssembly. It's expected that in this case the caller
* relinquishes ownership of the trap and it is passed back to the engine.
*/
typedef wasm_trap_t* (*wasmtime_func_callback_t)(
void *env,
wasmtime_caller_t* caller,
const wasmtime_val_t *args,
size_t nargs,
wasmtime_val_t *results,
size_t nresults);
/**
* \brief Creates a new host-defined function.
*
* Inserts a host-defined function into the `store` provided which can be used
* to then instantiate a module with or define within a #wasmtime_linker_t.
*
* \param store the store in which to create the function
* \param type the wasm type of the function that's being created
* \param callback the host-defined callback to invoke
* \param env host-specific data passed to the callback invocation, can be
* `NULL`
* \param finalizer optional finalizer for `env`, can be `NULL`
* \param ret the #wasmtime_func_t return value to be filled in.
*
* The returned function can only be used with the specified `store`.
*/
WASM_API_EXTERN void wasmtime_func_new(
wasmtime_context_t *store,
const wasm_functype_t* type,
wasmtime_func_callback_t callback,
void *env,
void (*finalizer)(void*),
wasmtime_func_t *ret
);
/**
* \brief Callback signature for #wasmtime_func_new_unchecked.
*
* This is the function signature for host functions that can be made accessible
* to WebAssembly. The arguments to this function are:
*
* \param env user-provided argument passed to #wasmtime_func_new_unchecked
* \param caller a temporary object that can only be used during this function
* call. Used to acquire #wasmtime_context_t or caller's state
* \param args_and_results storage space for both the parameters to the
* function as well as the results of the function. The size of this
* array depends on the function type that the host function is created
* with, but it will be the maximum of the number of parameters and
* number of results.
* \param num_args_and_results the size of the `args_and_results` parameter in
* units of #wasmtime_val_raw_t.
*
* This callback can optionally return a #wasm_trap_t indicating that a trap
* should be raised in WebAssembly. It's expected that in this case the caller
* relinquishes ownership of the trap and it is passed back to the engine.
*
* This differs from #wasmtime_func_callback_t in that the payload of
* `args_and_results` does not have type information, nor does it have sizing
* information. This is especially unsafe because it's only valid within the
* particular #wasm_functype_t that the function was created with. The onus is
* on the embedder to ensure that `args_and_results` are all read correctly
* for parameters and all written for results within the execution of a
* function.
*
* Parameters will be listed starting at index 0 in the `args_and_results`
* array. Results are also written starting at index 0, which will overwrite
* the arguments.
*/
typedef wasm_trap_t* (*wasmtime_func_unchecked_callback_t)(
void *env,
wasmtime_caller_t* caller,
wasmtime_val_raw_t *args_and_results,
size_t num_args_and_results);
/**
* \brief Creates a new host function in the same manner of #wasmtime_func_new,
* but the function-to-call has no type information available at runtime.
*
* This function is very similar to #wasmtime_func_new. The difference is that
* this version is "more unsafe" in that when the host callback is invoked there
* is no type information and no checks that the right types of values are
* produced. The onus is on the consumer of this API to ensure that all
* invariants are upheld such as:
*
* * The host callback reads parameters correctly and interprets their types
* correctly.
* * If a trap doesn't happen then all results are written to the results
* pointer. All results must have the correct type.
* * Types such as `funcref` cannot cross stores.
* * Types such as `externref` have valid reference counts.
*
* It's generally only recommended to use this if your application can wrap
* this in a safe embedding. This should not be frequently used due to the
* number of invariants that must be upheld on the wasm<->host boundary. On the
* upside, though, this flavor of host function will be faster to call than
* those created by #wasmtime_func_new (hence the reason for this function's
* existence).
*/
WASM_API_EXTERN void wasmtime_func_new_unchecked(
wasmtime_context_t *store,
const wasm_functype_t* type,
wasmtime_func_unchecked_callback_t callback,
void *env,
void (*finalizer)(void*),
wasmtime_func_t *ret
);
/**
* \brief Returns the type of the function specified
*
* The returned #wasm_functype_t is owned by the caller.
*/
WASM_API_EXTERN wasm_functype_t* wasmtime_func_type(
const wasmtime_context_t *store,
const wasmtime_func_t *func
);
/**
* \brief Call a WebAssembly function.
*
* This function is used to invoke a function defined within a store. For
* example this might be used after extracting a function from a
* #wasmtime_instance_t.
*
* \param store the store which owns `func`
* \param func the function to call
* \param args the arguments to the function call
* \param nargs the number of arguments provided
* \param results where to write the results of the function call
* \param nresults the number of results expected
* \param trap where to store a trap, if one happens.
*
* There are three possible return states from this function:
*
* 1. The returned error is non-null. This means `results`
* wasn't written to and `trap` will have `NULL` written to it. This state
* means that programmer error happened when calling the function, for
* example when the size of the arguments/results was wrong, the types of the
* arguments were wrong, or arguments may come from the wrong store.
* 2. The trap pointer is filled in. This means the returned error is `NULL` and
* `results` was not written to. This state means that the function was
* executing but hit a wasm trap while executing.
* 3. The error and trap returned are both `NULL` and `results` are written to.
* This means that the function call succeeded and the specified results were
* produced.
*
* The `trap` pointer cannot be `NULL`. The `args` and `results` pointers may be
* `NULL` if the corresponding length is zero.
*
* Does not take ownership of #wasmtime_val_t arguments. Gives ownership of
* #wasmtime_val_t results.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_func_call(
wasmtime_context_t *store,
const wasmtime_func_t *func,
const wasmtime_val_t *args,
size_t nargs,
wasmtime_val_t *results,
size_t nresults,
wasm_trap_t **trap
);
/**
* \brief Call a WebAssembly function in an "unchecked" fashion.
*
* This function is similar to #wasmtime_func_call except that there is no type
* information provided with the arguments (or sizing information). Consequently
* this is less safe to call since it's up to the caller to ensure that `args`
* has an appropriate size and all the parameters are configured with their
* appropriate values/types. Additionally all the results must be interpreted
* correctly if this function returns successfully.
*
* Parameters must be specified starting at index 0 in the `args_and_results`
* array. Results are written starting at index 0, which will overwrite
* the arguments.
*
* Callers must ensure that various correctness variants are upheld when this
* API is called such as:
*
* * The `args_and_results` pointer has enough space to hold all the parameters
* and all the results (but not at the same time).
* * Parameters must all be configured as if they were the correct type.
* * Values such as `externref` and `funcref` are valid within the store being
* called.
*
* When in doubt it's much safer to call #wasmtime_func_call. This function is
* faster than that function, but the tradeoff is that embeddings must uphold
* more invariants rather than relying on Wasmtime to check them for you.
*/
WASM_API_EXTERN wasm_trap_t *wasmtime_func_call_unchecked(
wasmtime_context_t *store,
const wasmtime_func_t *func,
wasmtime_val_raw_t *args_and_results
);
/**
* \brief Loads a #wasmtime_extern_t from the caller's context
*
* This function will attempt to look up the export named `name` on the caller
* instance provided. If it is found then the #wasmtime_extern_t for that is
* returned, otherwise `NULL` is returned.
*
* Note that this only works for exported memories right now for WASI
* compatibility.
*
* \param caller the caller object to look up the export from
* \param name the name that's being looked up
* \param name_len the byte length of `name`
* \param item where to store the return value
*
* Returns a nonzero value if the export was found, or 0 if the export wasn't
* found. If the export wasn't found then `item` isn't written to.
*/
WASM_API_EXTERN bool wasmtime_caller_export_get(
wasmtime_caller_t *caller,
const char *name,
size_t name_len,
wasmtime_extern_t *item
);
/**
* \brief Returns the store context of the caller object.
*/
WASM_API_EXTERN wasmtime_context_t* wasmtime_caller_context(wasmtime_caller_t* caller);
/**
* \brief Converts a `raw` nonzero `funcref` value from #wasmtime_val_raw_t
* into a #wasmtime_func_t.
*
* This function can be used to interpret nonzero values of the `funcref` field
* of the #wasmtime_val_raw_t structure. It is assumed that `raw` does not have
* a value of 0, or otherwise the program will abort.
*
* Note that this function is unchecked and unsafe. It's only safe to pass
* values learned from #wasmtime_val_raw_t with the same corresponding
* #wasmtime_context_t that they were produced from. Providing arbitrary values
* to `raw` here or cross-context values with `context` is UB.
*/
WASM_API_EXTERN void wasmtime_func_from_raw(
wasmtime_context_t* context,
size_t raw,
wasmtime_func_t *ret);
/**
* \brief Converts a `func` which belongs to `context` into a `usize`
* parameter that is suitable for insertion into a #wasmtime_val_raw_t.
*/
WASM_API_EXTERN size_t wasmtime_func_to_raw(
wasmtime_context_t* context,
const wasmtime_func_t *func);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_FUNC_H

View file

@ -0,0 +1,91 @@
/**
* \file wasmtime/global.h
*
* Wasmtime APIs for interacting with WebAssembly globals.
*/
#ifndef WASMTIME_GLOBAL_H
#define WASMTIME_GLOBAL_H
#include <wasm.h>
#include <wasmtime/extern.h>
#include <wasmtime/store.h>
#include <wasmtime/val.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Creates a new global value.
*
* Creates a new host-defined global value within the provided `store`
*
* \param store the store in which to create the global
* \param type the wasm type of the global being created
* \param val the initial value of the global
* \param ret a return pointer for the created global.
*
* This function may return an error if the `val` argument does not match the
* specified type of the global, or if `val` comes from a different store than
* the one provided.
*
* This function does not take ownership of any of its arguments but error is
* owned by the caller.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_global_new(
wasmtime_context_t *store,
const wasm_globaltype_t *type,
const wasmtime_val_t *val,
wasmtime_global_t *ret
);
/**
* \brief Returns the wasm type of the specified global.
*
* The returned #wasm_globaltype_t is owned by the caller.
*/
WASM_API_EXTERN wasm_globaltype_t* wasmtime_global_type(
const wasmtime_context_t *store,
const wasmtime_global_t *global
);
/**
* \brief Get the value of the specified global.
*
* \param store the store that owns `global`
* \param global the global to get
* \param out where to store the value in this global.
*
* This function returns ownership of the contents of `out`, so
* #wasmtime_val_delete may need to be called on the value.
*/
WASM_API_EXTERN void wasmtime_global_get(
wasmtime_context_t *store,
const wasmtime_global_t *global,
wasmtime_val_t *out
);
/**
* \brief Sets a global to a new value.
*
* \param store the store that owns `global`
* \param global the global to set
* \param val the value to store in the global
*
* This function may return an error if `global` is not mutable or if `val` has
* the wrong type for `global`.
*
* THis does not take ownership of any argument but returns ownership of the error.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_global_set(
wasmtime_context_t *store,
const wasmtime_global_t *global,
const wasmtime_val_t *val
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_GLOBAL_H

View file

@ -0,0 +1,128 @@
/**
* \file wasmtime/instance.h
*
* Wasmtime APIs for interacting with wasm instances.
*/
#ifndef WASMTIME_INSTANCE_H
#define WASMTIME_INSTANCE_H
#include <wasm.h>
#include <wasmtime/extern.h>
#include <wasmtime/module.h>
#include <wasmtime/store.h>
#ifdef __cplusplus
extern "C" {
#endif
/// \brief Representation of a instance in Wasmtime.
///
/// Instances are represented with a 64-bit identifying integer in Wasmtime.
/// They do not have any destructor associated with them. Instances cannot
/// interoperate between #wasmtime_store_t instances and if the wrong instance
/// is passed to the wrong store then it may trigger an assertion to abort the
/// process.
typedef struct wasmtime_instance {
/// Internal identifier of what store this belongs to, never zero.
uint64_t store_id;
/// Internal index within the store.
size_t index;
} wasmtime_instance_t;
/**
* \brief Instantiate a wasm module.
*
* This function will instantiate a WebAssembly module with the provided
* imports, creating a WebAssembly instance. The returned instance can then
* afterwards be inspected for exports.
*
* \param store the store in which to create the instance
* \param module the module that's being instantiated
* \param imports the imports provided to the module
* \param nimports the size of `imports`
* \param instance where to store the returned instance
* \param trap where to store the returned trap
*
* This function requires that `imports` is the same size as the imports that
* `module` has. Additionally the `imports` array must be 1:1 lined up with the
* imports of the `module` specified. This is intended to be relatively low
* level, and #wasmtime_linker_instantiate is provided for a more ergonomic
* name-based resolution API.
*
* The states of return values from this function are similar to
* #wasmtime_func_call where an error can be returned meaning something like a
* link error in this context. A trap can be returned (meaning no error or
* instance is returned), or an instance can be returned (meaning no error or
* trap is returned).
*
* Note that this function requires that all `imports` specified must be owned
* by the `store` provided as well.
*
* This function does not take ownership of any of its arguments, but all return
* values are owned by the caller.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_instance_new(
wasmtime_context_t *store,
const wasmtime_module_t *module,
const wasmtime_extern_t* imports,
size_t nimports,
wasmtime_instance_t *instance,
wasm_trap_t **trap
);
/**
* \brief Get an export by name from an instance.
*
* \param store the store that owns `instance`
* \param instance the instance to lookup within
* \param name the export name to lookup
* \param name_len the byte length of `name`
* \param item where to store the returned value
*
* Returns nonzero if the export was found, and `item` is filled in. Otherwise
* returns 0.
*
* Doesn't take ownership of any arguments but does return ownership of the
* #wasmtime_extern_t.
*/
WASM_API_EXTERN bool wasmtime_instance_export_get(
wasmtime_context_t *store,
const wasmtime_instance_t *instance,
const char *name,
size_t name_len,
wasmtime_extern_t *item
);
/**
* \brief Get an export by index from an instance.
*
* \param store the store that owns `instance`
* \param instance the instance to lookup within
* \param index the index to lookup
* \param name where to store the name of the export
* \param name_len where to store the byte length of the name
* \param item where to store the export itself
*
* Returns nonzero if the export was found, and `name`, `name_len`, and `item`
* are filled in. Otherwise returns 0.
*
* Doesn't take ownership of any arguments but does return ownership of the
* #wasmtime_extern_t. The `name` pointer return value is owned by the `store`
* and must be immediately used before calling any other APIs on
* #wasmtime_context_t.
*/
WASM_API_EXTERN bool wasmtime_instance_export_nth(
wasmtime_context_t *store,
const wasmtime_instance_t *instance,
size_t index,
char **name,
size_t *name_len,
wasmtime_extern_t *item
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_INSTANCE_H

View file

@ -0,0 +1,297 @@
/**
* \file wasmtime/linker.h
*
* Wasmtime API for a name-based linker used to instantiate modules.
*/
#ifndef WASMTIME_LINKER_H
#define WASMTIME_LINKER_H
#include <wasm.h>
#include <wasmtime/error.h>
#include <wasmtime/store.h>
#include <wasmtime/extern.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \typedef wasmtime_linker_t
* \brief Alias to #wasmtime_linker
*
* \struct #wasmtime_linker
* \brief Object used to conveniently link together and instantiate wasm
* modules.
*
* This type corresponds to the `wasmtime::Linker` type in Rust. This
* type is intended to make it easier to manage a set of modules that link
* together, or to make it easier to link WebAssembly modules to WASI.
*
* A #wasmtime_linker_t is a higher level way to instantiate a module than
* #wasm_instance_new since it works at the "string" level of imports rather
* than requiring 1:1 mappings.
*/
typedef struct wasmtime_linker wasmtime_linker_t;
/**
* \brief Creates a new linker for the specified engine.
*
* This function does not take ownership of the engine argument, and the caller
* is expected to delete the returned linker.
*/
WASM_API_EXTERN wasmtime_linker_t* wasmtime_linker_new(wasm_engine_t* engine);
/**
* \brief Deletes a linker
*/
WASM_API_EXTERN void wasmtime_linker_delete(wasmtime_linker_t* linker);
/**
* \brief Configures whether this linker allows later definitions to shadow
* previous definitions.
*
* By default this setting is `false`.
*/
WASM_API_EXTERN void wasmtime_linker_allow_shadowing(wasmtime_linker_t* linker, bool allow_shadowing);
/**
* \brief Defines a new item in this linker.
*
* \param linker the linker the name is being defined in.
* \param module the module name the item is defined under.
* \param module_len the byte length of `module`
* \param name the field name the item is defined under
* \param name_len the byte length of `name`
* \param item the item that is being defined in this linker.
*
* \return On success `NULL` is returned, otherwise an error is returned which
* describes why the definition failed.
*
* For more information about name resolution consult the [Rust
* documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Linker.html#name-resolution).
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define(
wasmtime_linker_t *linker,
const char *module,
size_t module_len,
const char *name,
size_t name_len,
const wasmtime_extern_t *item
);
/**
* \brief Defines a new function in this linker.
*
* \param linker the linker the name is being defined in.
* \param module the module name the item is defined under.
* \param module_len the byte length of `module`
* \param name the field name the item is defined under
* \param name_len the byte length of `name`
* \param ty the type of the function that's being defined
* \param cb the host callback to invoke when the function is called
* \param data the host-provided data to provide as the first argument to the callback
* \param finalizer an optional finalizer for the `data` argument.
*
* \return On success `NULL` is returned, otherwise an error is returned which
* describes why the definition failed.
*
* For more information about name resolution consult the [Rust
* documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Linker.html#name-resolution).
*
* Note that this function does not create a #wasmtime_func_t. This creates a
* store-independent function within the linker, allowing this function
* definition to be used with multiple stores.
*
* For more information about host callbacks see #wasmtime_func_new.
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define_func(
wasmtime_linker_t *linker,
const char *module,
size_t module_len,
const char *name,
size_t name_len,
const wasm_functype_t *ty,
wasmtime_func_callback_t cb,
void *data,
void (*finalizer)(void*)
);
/**
* \brief Defines a new function in this linker.
*
* This is the same as #wasmtime_linker_define_func except that it's the analog
* of #wasmtime_func_new_unchecked instead of #wasmtime_func_new. Be sure to
* consult the documentation of #wasmtime_linker_define_func for argument
* information as well as #wasmtime_func_new_unchecked for why this is an
* unsafe API.
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define_func_unchecked(
wasmtime_linker_t *linker,
const char *module,
size_t module_len,
const char *name,
size_t name_len,
const wasm_functype_t *ty,
wasmtime_func_unchecked_callback_t cb,
void *data,
void (*finalizer)(void*)
);
/**
* \brief Defines WASI functions in this linker.
*
* \param linker the linker the name is being defined in.
*
* \return On success `NULL` is returned, otherwise an error is returned which
* describes why the definition failed.
*
* This function will provide WASI function names in the specified linker. Note
* that when an instance is created within a store then the store also needs to
* have its WASI settings configured with #wasmtime_context_set_wasi for WASI
* functions to work, otherwise an assert will be tripped that will abort the
* process.
*
* For more information about name resolution consult the [Rust
* documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Linker.html#name-resolution).
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define_wasi(
wasmtime_linker_t *linker
);
/**
* \brief Defines an instance under the specified name in this linker.
*
* \param linker the linker the name is being defined in.
* \param store the store that owns `instance`
* \param name the module name to define `instance` under.
* \param name_len the byte length of `name`
* \param instance a previously-created instance.
*
* \return On success `NULL` is returned, otherwise an error is returned which
* describes why the definition failed.
*
* This function will take all of the exports of the `instance` provided and
* defined them under a module called `name` with a field name as the export's
* own name.
*
* For more information about name resolution consult the [Rust
* documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Linker.html#name-resolution).
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_define_instance(
wasmtime_linker_t *linker,
wasmtime_context_t *store,
const char *name,
size_t name_len,
const wasmtime_instance_t *instance
);
/**
* \brief Instantiates a #wasm_module_t with the items defined in this linker.
*
* \param linker the linker used to instantiate the provided module.
* \param store the store that is used to instantiate within
* \param module the module that is being instantiated.
* \param instance the returned instance, if successful.
* \param trap a trap returned, if the start function traps.
*
* \return One of three things can happen as a result of this function. First
* the module could be successfully instantiated and returned through
* `instance`, meaning the return value and `trap` are both set to `NULL`.
* Second the start function may trap, meaning the return value and `instance`
* are set to `NULL` and `trap` describes the trap that happens. Finally
* instantiation may fail for another reason, in which case an error is returned
* and `trap` and `instance` are set to `NULL`.
*
* This function will attempt to satisfy all of the imports of the `module`
* provided with items previously defined in this linker. If any name isn't
* defined in the linker than an error is returned. (or if the previously
* defined item is of the wrong type).
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_instantiate(
const wasmtime_linker_t *linker,
wasmtime_context_t *store,
const wasmtime_module_t *module,
wasmtime_instance_t *instance,
wasm_trap_t **trap
);
/**
* \brief Defines automatic instantiations of a #wasm_module_t in this linker.
*
* \param linker the linker the module is being added to
* \param store the store that is used to instantiate `module`
* \param name the name of the module within the linker
* \param name_len the byte length of `name`
* \param module the module that's being instantiated
*
* \return An error if the module could not be instantiated or added or `NULL`
* on success.
*
* This function automatically handles [Commands and
* Reactors](https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi)
* instantiation and initialization.
*
* For more information see the [Rust
* documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Linker.html#method.module).
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_module(
wasmtime_linker_t *linker,
wasmtime_context_t *store,
const char *name,
size_t name_len,
const wasmtime_module_t *module
);
/**
* \brief Acquires the "default export" of the named module in this linker.
*
* \param linker the linker to load from
* \param store the store to load a function into
* \param name the name of the module to get the default export for
* \param name_len the byte length of `name`
* \param func where to store the extracted default function.
*
* \return An error is returned if the default export could not be found, or
* `NULL` is returned and `func` is filled in otherwise.
*
* For more information see the [Rust
* documentation](https://bytecodealliance.github.io/wasmtime/api/wasmtime/struct.Linker.html#method.get_default).
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_linker_get_default(
const wasmtime_linker_t *linker,
wasmtime_context_t *store,
const char *name,
size_t name_len,
wasmtime_func_t *func
);
/**
* \brief Loads an item by name from this linker.
*
* \param linker the linker to load from
* \param store the store to load the item into
* \param module the name of the module to get
* \param module_len the byte length of `module`
* \param name the name of the field to get
* \param name_len the byte length of `name`
* \param item where to store the extracted item
*
* \return A nonzero value if the item is defined, in which case `item` is also
* filled in. Otherwise zero is returned.
*/
WASM_API_EXTERN bool wasmtime_linker_get(
const wasmtime_linker_t *linker,
wasmtime_context_t *store,
const char *module,
size_t module_len,
const char *name,
size_t name_len,
wasmtime_extern_t *item
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_LINKER_H

View file

@ -0,0 +1,123 @@
/**
* \file wasmtime/memory.h
*
* Wasmtime API for interacting with wasm memories.
*/
#ifndef WASMTIME_MEMORY_H
#define WASMTIME_MEMORY_H
#include <wasm.h>
#include <wasmtime/extern.h>
#include <wasmtime/store.h>
#include <wasmtime/error.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Creates a new memory type from the specified parameters.
*
* Note that this function is preferred over #wasm_memorytype_new for
* compatibility with the memory64 proposal.
*/
WASM_API_EXTERN wasm_memorytype_t *wasmtime_memorytype_new(uint64_t min, bool max_present, uint64_t max, bool is_64);
/**
* \brief Returns the minimum size, in pages, of the specified memory type.
*
* Note that this function is preferred over #wasm_memorytype_limits for
* compatibility with the memory64 proposal.
*/
WASM_API_EXTERN uint64_t wasmtime_memorytype_minimum(const wasm_memorytype_t *ty);
/**
* \brief Returns the maximum size, in pages, of the specified memory type.
*
* If this memory type doesn't have a maximum size listed then `false` is
* returned. Otherwise `true` is returned and the `max` pointer is filled in
* with the specified maximum size, in pages.
*
* Note that this function is preferred over #wasm_memorytype_limits for
* compatibility with the memory64 proposal.
*/
WASM_API_EXTERN bool wasmtime_memorytype_maximum(const wasm_memorytype_t *ty, uint64_t *max);
/**
* \brief Returns whether this type of memory represents a 64-bit memory.
*/
WASM_API_EXTERN bool wasmtime_memorytype_is64(const wasm_memorytype_t *ty);
/**
* \brief Creates a new WebAssembly linear memory
*
* \param store the store to create the memory within
* \param ty the type of the memory to create
* \param ret where to store the returned memory
*
* If an error happens when creating the memory it's returned and owned by the
* caller. If an error happens then `ret` is not filled in.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_memory_new(
wasmtime_context_t *store,
const wasm_memorytype_t* ty,
wasmtime_memory_t *ret
);
/**
* \brief Returns the tyep of the memory specified
*/
WASM_API_EXTERN wasm_memorytype_t* wasmtime_memory_type(
const wasmtime_context_t *store,
const wasmtime_memory_t *memory
);
/**
* \brief Returns the base pointer in memory where the linear memory starts.
*/
WASM_API_EXTERN uint8_t *wasmtime_memory_data(
const wasmtime_context_t *store,
const wasmtime_memory_t *memory
);
/**
* \brief Returns the byte length of this linear memory.
*/
WASM_API_EXTERN size_t wasmtime_memory_data_size(
const wasmtime_context_t *store,
const wasmtime_memory_t *memory
);
/**
* \brief Returns the length, in WebAssembly pages, of this linear memory
*/
WASM_API_EXTERN uint64_t wasmtime_memory_size(
const wasmtime_context_t *store,
const wasmtime_memory_t *memory
);
/**
* \brief Attempts to grow the specified memory by `delta` pages.
*
* \param store the store that owns `memory`
* \param memory the memory to grow
* \param delta the number of pages to grow by
* \param prev_size where to store the previous size of memory
*
* If memory cannot be grown then `prev_size` is left unchanged and an error is
* returned. Otherwise `prev_size` is set to the previous size of the memory, in
* WebAssembly pages, and `NULL` is returned.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_memory_grow(
wasmtime_context_t *store,
const wasmtime_memory_t *memory,
uint64_t delta,
uint64_t *prev_size
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_MEMORY_H

View file

@ -0,0 +1,155 @@
/**
* \file wasmtime/module.h
*
* APIs for interacting with modules in Wasmtime
*/
#ifndef WASMTIME_MODULE_H
#define WASMTIME_MODULE_H
#include <wasm.h>
#include <wasmtime/error.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \typedef wasmtime_module_t
* \brief Convenience alias for #wasmtime_module
*
* \struct wasmtime_module
* \brief A compiled Wasmtime module.
*
* This type represents a compiled WebAssembly module. The compiled module is
* ready to be instantiated and can be inspected for imports/exports. It is safe
* to use a module across multiple threads simultaneously.
*/
typedef struct wasmtime_module wasmtime_module_t;
/**
* \brief Compiles a WebAssembly binary into a #wasmtime_module_t
*
* This function will compile a WebAssembly binary into an owned #wasm_module_t.
* This performs the same as #wasm_module_new except that it returns a
* #wasmtime_error_t type to get richer error information.
*
* On success the returned #wasmtime_error_t is `NULL` and the `ret` pointer is
* filled in with a #wasm_module_t. On failure the #wasmtime_error_t is
* non-`NULL` and the `ret` pointer is unmodified.
*
* This function does not take ownership of any of its arguments, but the
* returned error and module are owned by the caller.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_module_new(
wasm_engine_t *engine,
const uint8_t *wasm,
size_t wasm_len,
wasmtime_module_t **ret
);
/**
* \brief Deletes a module.
*/
WASM_API_EXTERN void wasmtime_module_delete(wasmtime_module_t *m);
/**
* \brief Creates a shallow clone of the specified module, increasing the
* internal reference count.
*/
WASM_API_EXTERN wasmtime_module_t *wasmtime_module_clone(wasmtime_module_t *m);
/**
* \brief Same as #wasm_module_imports, but for #wasmtime_module_t.
*/
WASM_API_EXTERN void wasmtime_module_imports(
const wasmtime_module_t *module,
wasm_importtype_vec_t *out
);
/**
* \brief Same as #wasm_module_exports, but for #wasmtime_module_t.
*/
WASM_API_EXTERN void wasmtime_module_exports(
const wasmtime_module_t *module,
wasm_exporttype_vec_t *out
);
/**
* \brief Validate a WebAssembly binary.
*
* This function will validate the provided byte sequence to determine if it is
* a valid WebAssembly binary within the context of the engine provided.
*
* This function does not take ownership of its arguments but the caller is
* expected to deallocate the returned error if it is non-`NULL`.
*
* If the binary validates then `NULL` is returned, otherwise the error returned
* describes why the binary did not validate.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_module_validate(
wasm_engine_t *engine,
const uint8_t *wasm,
size_t wasm_len
);
/**
* \brief This function serializes compiled module artifacts as blob data.
*
* \param module the module
* \param ret if the conversion is successful, this byte vector is filled in with
* the serialized compiled module.
*
* \return a non-null error if parsing fails, or returns `NULL`. If parsing
* fails then `ret` isn't touched.
*
* This function does not take ownership of `module`, and the caller is
* expected to deallocate the returned #wasmtime_error_t and #wasm_byte_vec_t.
*/
WASM_API_EXTERN wasmtime_error_t* wasmtime_module_serialize(
wasmtime_module_t* module,
wasm_byte_vec_t *ret
);
/**
* \brief Build a module from serialized data.
*
* This function does not take ownership of any of its arguments, but the
* returned error and module are owned by the caller.
*
* This function is not safe to receive arbitrary user input. See the Rust
* documentation for more information on what inputs are safe to pass in here
* (e.g. only that of #wasmtime_module_serialize)
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_module_deserialize(
wasm_engine_t *engine,
const uint8_t *bytes,
size_t bytes_len,
wasmtime_module_t **ret
);
/**
* \brief Deserialize a module from an on-disk file.
*
* This function is the same as #wasmtime_module_deserialize except that it
* reads the data for the serialized module from the path on disk. This can be
* faster than the alternative which may require copying the data around.
*
* This function does not take ownership of any of its arguments, but the
* returned error and module are owned by the caller.
*
* This function is not safe to receive arbitrary user input. See the Rust
* documentation for more information on what inputs are safe to pass in here
* (e.g. only that of #wasmtime_module_serialize)
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_module_deserialize_file(
wasm_engine_t *engine,
const char *path,
wasmtime_module_t **ret
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_MODULE_H

View file

@ -0,0 +1,185 @@
/**
* \file wasmtime/store.h
*
* Wasmtime definition of a "store".
*/
#ifndef WASMTIME_STORE_H
#define WASMTIME_STORE_H
#include <wasm.h>
#include <wasi.h>
#include <wasmtime/error.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \typedef wasmtime_store_t
* \brief Convenience alias for #wasmtime_store_t
*
* \struct wasmtime_store
* \brief Storage of WebAssembly objects
*
* A store is the unit of isolation between WebAssembly instances in an
* embedding of Wasmtime. Values in one #wasmtime_store_t cannot flow into
* another #wasmtime_store_t. Stores are cheap to create and cheap to dispose.
* It's expected that one-off stores are common in embeddings.
*
* Objects stored within a #wasmtime_store_t are referenced with integer handles
* rather than interior pointers. This means that most APIs require that the
* store be explicitly passed in, which is done via #wasmtime_context_t. It is
* safe to move a #wasmtime_store_t to any thread at any time. A store generally
* cannot be concurrently used, however.
*/
typedef struct wasmtime_store wasmtime_store_t;
/**
* \typedef wasmtime_context_t
* \brief Convenience alias for #wasmtime_context
*
* \struct wasmtime_context
* \brief An interior pointer into a #wasmtime_store_t which is used as
* "context" for many functions.
*
* This context pointer is used pervasively throught Wasmtime's API. This can be
* acquired from #wasmtime_store_context or #wasmtime_caller_context. The
* context pointer for a store is the same for the entire lifetime of a store,
* so it can safely be stored adjacent to a #wasmtime_store_t itself.
*
* Usage of a #wasmtime_context_t must not outlive the original
* #wasmtime_store_t. Additionally #wasmtime_context_t can only be used in
* situations where it has explicitly been granted access to doing so. For
* example finalizers cannot use #wasmtime_context_t because they are not given
* access to it.
*/
typedef struct wasmtime_context wasmtime_context_t;
/**
* \brief Creates a new store within the specified engine.
*
* \param engine the compilation environment with configuration this store is
* connected to
* \param data user-provided data to store, can later be acquired with
* #wasmtime_context_get_data.
* \param finalizer an optional finalizer for `data`
*
* This function creates a fresh store with the provided configuration settings.
* The returned store must be deleted with #wasmtime_store_delete.
*/
WASM_API_EXTERN wasmtime_store_t *wasmtime_store_new(
wasm_engine_t *engine,
void *data,
void (*finalizer)(void*)
);
/**
* \brief Returns the interior #wasmtime_context_t pointer to this store
*/
WASM_API_EXTERN wasmtime_context_t *wasmtime_store_context(wasmtime_store_t *store);
/**
* \brief Deletes a store.
*/
WASM_API_EXTERN void wasmtime_store_delete(wasmtime_store_t *store);
/**
* \brief Returns the user-specified data associated with the specified store
*/
WASM_API_EXTERN void *wasmtime_context_get_data(const wasmtime_context_t* context);
/**
* \brief Overwrites the user-specified data associated with this store.
*
* Note that this does not execute the original finalizer for the provided data,
* and the original finalizer will be executed for the provided data when the
* store is deleted.
*/
WASM_API_EXTERN void wasmtime_context_set_data(wasmtime_context_t* context, void *data);
/**
* \brief Perform garbage collection within the given context.
*
* Garbage collects `externref`s that are used within this store. Any
* `externref`s that are discovered to be unreachable by other code or objects
* will have their finalizers run.
*
* The `context` argument must not be NULL.
*/
WASM_API_EXTERN void wasmtime_context_gc(wasmtime_context_t* context);
/**
* \brief Adds fuel to this context's store for wasm to consume while executing.
*
* For this method to work fuel consumption must be enabled via
* #wasmtime_config_consume_fuel_set. By default a store starts with 0 fuel
* for wasm to execute with (meaning it will immediately trap).
* This function must be called for the store to have
* some fuel to allow WebAssembly to execute.
*
* Note that at this time when fuel is entirely consumed it will cause
* wasm to trap. More usages of fuel are planned for the future.
*
* If fuel is not enabled within this store then an error is returned. If fuel
* is successfully added then NULL is returned.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_context_add_fuel(wasmtime_context_t *store, uint64_t fuel);
/**
* \brief Returns the amount of fuel consumed by this context's store execution
* so far.
*
* If fuel consumption is not enabled via #wasmtime_config_consume_fuel_set
* then this function will return false. Otherwise true is returned and the
* fuel parameter is filled in with fuel consuemd so far.
*
* Also note that fuel, if enabled, must be originally configured via
* #wasmtime_context_add_fuel.
*/
WASM_API_EXTERN bool wasmtime_context_fuel_consumed(const wasmtime_context_t *context, uint64_t *fuel);
/**
* \brief Attempt to manually consume fuel from the store.
*
* If fuel consumption is not enabled via #wasmtime_config_consume_fuel_set then
* this function will return an error. Otherwise this will attempt to consume
* the specified amount of `fuel` from the store. If successful the remaining
* amount of fuel is stored into `remaining`. If `fuel` couldn't be consumed
* then an error is returned.
*
* Also note that fuel, if enabled, must be originally configured via
* #wasmtime_context_add_fuel.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_context_consume_fuel(wasmtime_context_t *context, uint64_t fuel, uint64_t *remaining);
/**
* \brief Configures WASI state within the specified store.
*
* This function is required if #wasmtime_linker_define_wasi is called. This
* will configure the WASI state for instances defined within this store to the
* configuration specified.
*
* This function does not take ownership of `context` but it does take ownership
* of `wasi`. The caller should no longer use `wasi` after calling this function
* (even if an error is returned).
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_context_set_wasi(wasmtime_context_t *context, wasi_config_t *wasi);
/**
* \brief Configures the relative deadline at which point WebAssembly code will
* trap.
*
* This function configures the store-local epoch deadline after which point
* WebAssembly code will trap.
*
* See also #wasmtime_config_epoch_interruption_set.
*/
WASM_API_EXTERN void wasmtime_context_set_epoch_deadline(wasmtime_context_t *context, uint64_t ticks_beyond_current);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_STORE_H

View file

@ -0,0 +1,126 @@
/**
* \file wasmtime/table.h
*
* Wasmtime APIs for interacting with WebAssembly tables.
*/
#ifndef WASMTIME_TABLE_H
#define WASMTIME_TABLE_H
#include <wasm.h>
#include <wasmtime/extern.h>
#include <wasmtime/store.h>
#include <wasmtime/error.h>
#include <wasmtime/val.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Creates a new host-defined wasm table.
*
* \param store the store to create the table within
* \param ty the type of the table to create
* \param init the initial value for this table's elements
* \param table where to store the returned table
*
* This function does not take ownership of any of its parameters, but yields
* ownership of returned error. This function may return an error if the `init`
* value does not match `ty`, for example.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_table_new(
wasmtime_context_t *store,
const wasm_tabletype_t *ty,
const wasmtime_val_t *init,
wasmtime_table_t *table
);
/**
* \brief Returns the type of this table.
*
* The caller has ownership of the returned #wasm_tabletype_t
*/
WASM_API_EXTERN wasm_tabletype_t* wasmtime_table_type(
const wasmtime_context_t *store,
const wasmtime_table_t *table
);
/**
* \brief Gets a value in a table.
*
* \param store the store that owns `table`
* \param table the table to access
* \param index the table index to access
* \param val where to store the table's value
*
* This function will attempt to access a table element. If a nonzero value is
* returned then `val` is filled in and is owned by the caller. Otherwise zero
* is returned because the `index` is out-of-bounds.
*/
WASM_API_EXTERN bool wasmtime_table_get(
wasmtime_context_t *store,
const wasmtime_table_t *table,
uint32_t index,
wasmtime_val_t *val
);
/**
* \brief Sets a value in a table.
*
* \param store the store that owns `table`
* \param table the table to write to
* \param index the table index to write
* \param value the value to store.
*
* This function will store `value` into the specified index in the table. This
* does not take ownership of any argument but yields ownership of the error.
* This function can fail if `value` has the wrong type for the table, or if
* `index` is out of bounds.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_table_set(
wasmtime_context_t *store,
const wasmtime_table_t *table,
uint32_t index,
const wasmtime_val_t *value
);
/**
* \brief Returns the size, in elements, of the specified table
*/
WASM_API_EXTERN uint32_t wasmtime_table_size(
const wasmtime_context_t *store,
const wasmtime_table_t *table
);
/**
* \brief Grows a table.
*
* \param store the store that owns `table`
* \param table the table to grow
* \param delta the number of elements to grow the table by
* \param init the initial value for new table element slots
* \param prev_size where to store the previous size of the table before growth
*
* This function will attempt to grow the table by `delta` table elements. This
* can fail if `delta` would exceed the maximum size of the table or if `init`
* is the wrong type for this table. If growth is successful then `NULL` is
* returned and `prev_size` is filled in with the previous size of the table, in
* elements, before the growth happened.
*
* This function does not take ownership of any of its arguments.
*/
WASM_API_EXTERN wasmtime_error_t *wasmtime_table_grow(
wasmtime_context_t *store,
const wasmtime_table_t *table,
uint32_t delta,
const wasmtime_val_t *init,
uint32_t *prev_size
);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_TABLE_H

View file

@ -0,0 +1,106 @@
/**
* \file wasmtime/trap.h
*
* Wasmtime APIs for interacting with traps and extensions to #wasm_trap_t.
*/
#ifndef WASMTIME_TRAP_H
#define WASMTIME_TRAP_H
#include <wasm.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Code of an instruction trap.
*
* See #wasmtime_trap_code_enum for possible values.
*/
typedef uint8_t wasmtime_trap_code_t;
/**
* \brief Trap codes for instruction traps.
*/
enum wasmtime_trap_code_enum {
/// The current stack space was exhausted.
WASMTIME_TRAP_CODE_STACK_OVERFLOW,
/// An out-of-bounds memory access.
WASMTIME_TRAP_CODE_MEMORY_OUT_OF_BOUNDS,
/// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
WASMTIME_TRAP_CODE_HEAP_MISALIGNED,
/// An out-of-bounds access to a table.
WASMTIME_TRAP_CODE_TABLE_OUT_OF_BOUNDS,
/// Indirect call to a null table entry.
WASMTIME_TRAP_CODE_INDIRECT_CALL_TO_NULL,
/// Signature mismatch on indirect call.
WASMTIME_TRAP_CODE_BAD_SIGNATURE,
/// An integer arithmetic operation caused an overflow.
WASMTIME_TRAP_CODE_INTEGER_OVERFLOW,
/// An integer division by zero.
WASMTIME_TRAP_CODE_INTEGER_DIVISION_BY_ZERO,
/// Failed float-to-int conversion.
WASMTIME_TRAP_CODE_BAD_CONVERSION_TO_INTEGER,
/// Code that was supposed to have been unreachable was reached.
WASMTIME_TRAP_CODE_UNREACHABLE_CODE_REACHED,
/// Execution has potentially run too long and may be interrupted.
WASMTIME_TRAP_CODE_INTERRUPT,
};
/**
* \brief Creates a new trap.
*
* \param msg the message to associate with this trap
* \param msg_len the byte length of `msg`
*
* The #wasm_trap_t returned is owned by the caller.
*/
WASM_API_EXTERN wasm_trap_t *wasmtime_trap_new(const char *msg, size_t msg_len);
/**
* \brief Attempts to extract the trap code from this trap.
*
* Returns `true` if the trap is an instruction trap triggered while
* executing Wasm. If `true` is returned then the trap code is returned
* through the `code` pointer. If `false` is returned then this is not
* an instruction trap -- traps can also be created using wasm_trap_new,
* or occur with WASI modules exiting with a certain exit code.
*/
WASM_API_EXTERN bool wasmtime_trap_code(const wasm_trap_t*, wasmtime_trap_code_t *code);
/**
* \brief Attempts to extract a WASI-specific exit status from this trap.
*
* Returns `true` if the trap is a WASI "exit" trap and has a return status. If
* `true` is returned then the exit status is returned through the `status`
* pointer. If `false` is returned then this is not a wasi exit trap.
*/
WASM_API_EXTERN bool wasmtime_trap_exit_status(const wasm_trap_t*, int *status);
/**
* \brief Returns a human-readable name for this frame's function.
*
* This function will attempt to load a human-readable name for function this
* frame points to. This function may return `NULL`.
*
* The lifetime of the returned name is the same as the #wasm_frame_t itself.
*/
WASM_API_EXTERN const wasm_name_t *wasmtime_frame_func_name(const wasm_frame_t*);
/**
* \brief Returns a human-readable name for this frame's module.
*
* This function will attempt to load a human-readable name for module this
* frame points to. This function may return `NULL`.
*
* The lifetime of the returned name is the same as the #wasm_frame_t itself.
*/
WASM_API_EXTERN const wasm_name_t *wasmtime_frame_module_name(const wasm_frame_t*);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_TRAP_H

232
lib/src/wasm/wasmtime/val.h Normal file
View file

@ -0,0 +1,232 @@
/**
* \file wasmtime/val.h
*
* APIs for interacting with WebAssembly values in Wasmtime.
*/
#ifndef WASMTIME_VAL_H
#define WASMTIME_VAL_H
#include <wasm.h>
#include <wasmtime/extern.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \typedef wasmtime_externref_t
* \brief Convenience alias for #wasmtime_externref
*
* \struct wasmtime_externref
* \brief A host-defined un-forgeable reference to pass into WebAssembly.
*
* This structure represents an `externref` that can be passed to WebAssembly.
* It cannot be forged by WebAssembly itself and is guaranteed to have been
* created by the host.
*/
typedef struct wasmtime_externref wasmtime_externref_t;
/**
* \brief Create a new `externref` value.
*
* Creates a new `externref` value wrapping the provided data, returning the
* pointer to the externref.
*
* \param data the host-specific data to wrap
* \param finalizer an optional finalizer for `data`
*
* When the reference is reclaimed, the wrapped data is cleaned up with the
* provided `finalizer`.
*
* The returned value must be deleted with #wasmtime_externref_delete
*/
WASM_API_EXTERN wasmtime_externref_t *wasmtime_externref_new(void *data, void (*finalizer)(void*));
/**
* \brief Get an `externref`'s wrapped data
*
* Returns the original `data` passed to #wasmtime_externref_new. It is required
* that `data` is not `NULL`.
*/
WASM_API_EXTERN void *wasmtime_externref_data(wasmtime_externref_t *data);
/**
* \brief Creates a shallow copy of the `externref` argument, returning a
* separately owned pointer (increases the reference count).
*/
WASM_API_EXTERN wasmtime_externref_t *wasmtime_externref_clone(wasmtime_externref_t *ref);
/**
* \brief Decrements the reference count of the `ref`, deleting it if it's the
* last reference.
*/
WASM_API_EXTERN void wasmtime_externref_delete(wasmtime_externref_t *ref);
/**
* \brief Converts a raw `externref` value coming from #wasmtime_val_raw_t into
* a #wasmtime_externref_t.
*
* Note that the returned #wasmtime_externref_t is an owned value that must be
* deleted via #wasmtime_externref_delete by the caller if it is non-null.
*/
WASM_API_EXTERN wasmtime_externref_t *wasmtime_externref_from_raw(wasmtime_context_t *context, size_t raw);
/**
* \brief Converts a #wasmtime_externref_t to a raw value suitable for storing
* into a #wasmtime_val_raw_t.
*
* Note that the returned underlying value is not tracked by Wasmtime's garbage
* collector until it enters WebAssembly. This means that a GC may release the
* context's reference to the raw value, making the raw value invalid within the
* context of the store. Do not perform a GC between calling this function and
* passing it to WebAssembly.
*/
WASM_API_EXTERN size_t wasmtime_externref_to_raw(
wasmtime_context_t *context,
const wasmtime_externref_t *ref);
/// \brief Discriminant stored in #wasmtime_val::kind
typedef uint8_t wasmtime_valkind_t;
/// \brief Value of #wasmtime_valkind_t meaning that #wasmtime_val_t is an i32
#define WASMTIME_I32 0
/// \brief Value of #wasmtime_valkind_t meaning that #wasmtime_val_t is an i64
#define WASMTIME_I64 1
/// \brief Value of #wasmtime_valkind_t meaning that #wasmtime_val_t is a f32
#define WASMTIME_F32 2
/// \brief Value of #wasmtime_valkind_t meaning that #wasmtime_val_t is a f64
#define WASMTIME_F64 3
/// \brief Value of #wasmtime_valkind_t meaning that #wasmtime_val_t is a v128
#define WASMTIME_V128 4
/// \brief Value of #wasmtime_valkind_t meaning that #wasmtime_val_t is a funcref
#define WASMTIME_FUNCREF 5
/// \brief Value of #wasmtime_valkind_t meaning that #wasmtime_val_t is an externref
#define WASMTIME_EXTERNREF 6
/// \brief A 128-bit value representing the WebAssembly `v128` type. Bytes are
/// stored in little-endian order.
typedef uint8_t wasmtime_v128[16];
/**
* \typedef wasmtime_valunion_t
* \brief Convenience alias for #wasmtime_valunion
*
* \union wasmtime_valunion
* \brief Container for different kinds of wasm values.
*
* This type is contained in #wasmtime_val_t and contains the payload for the
* various kinds of items a value can be.
*/
typedef union wasmtime_valunion {
/// Field used if #wasmtime_val_t::kind is #WASMTIME_I32
///
/// Note that this field is always stored in a little-endian format.
int32_t i32;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_I64
///
/// Note that this field is always stored in a little-endian format.
int64_t i64;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_F32
///
/// Note that this field is always stored in a little-endian format.
float32_t f32;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_F64
///
/// Note that this field is always stored in a little-endian format.
float64_t f64;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_FUNCREF
///
/// If this value represents a `ref.null func` value then the `store_id` field
/// is set to zero.
///
/// Note that this field is always stored in a little-endian format.
wasmtime_func_t funcref;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_EXTERNREF
///
/// If this value represents a `ref.null extern` value then this pointer will
/// be `NULL`.
///
/// Note that this field is always stored in a little-endian format.
wasmtime_externref_t *externref;
/// Field used if #wasmtime_val_t::kind is #WASMTIME_V128
///
/// Note that this field is always stored in a little-endian format.
wasmtime_v128 v128;
} wasmtime_valunion_t;
/**
* \typedef wasmtime_val_raw_t
* \brief Convenience alias for #wasmtime_val_raw
*
* \union wasmtime_val_raw
* \brief Container for possible wasm values.
*
* This type is used on conjunction with #wasmtime_func_new_unchecked as well
* as #wasmtime_func_call_unchecked. Instances of this type do not have type
* information associated with them, it's up to the embedder to figure out
* how to interpret the bits contained within, often using some other channel
* to determine the type.
*/
typedef union wasmtime_val_raw {
/// Field for when this val is a WebAssembly `i32` value.
int32_t i32;
/// Field for when this val is a WebAssembly `i64` value.
int64_t i64;
/// Field for when this val is a WebAssembly `f32` value.
float32_t f32;
/// Field for when this val is a WebAssembly `f64` value.
float64_t f64;
/// Field for when this val is a WebAssembly `v128` value.
wasmtime_v128 v128;
/// Field for when this val is a WebAssembly `funcref` value.
///
/// If this is set to 0 then it's a null funcref, otherwise this must be
/// passed to `wasmtime_func_from_raw` to determine the `wasmtime_func_t`.
size_t funcref;
/// Field for when this val is a WebAssembly `externref` value.
///
/// If this is set to 0 then it's a null externref, otherwise this must be
/// passed to `wasmtime_externref_from_raw` to determine the
/// `wasmtime_externref_t`.
size_t externref;
} wasmtime_val_raw_t;
/**
* \typedef wasmtime_val_t
* \brief Convenience alias for #wasmtime_val_t
*
* \union wasmtime_val
* \brief Container for different kinds of wasm values.
*
* Note that this structure may contain an owned value, namely
* #wasmtime_externref_t, depending on the context in which this is used. APIs
* which consume a #wasmtime_val_t do not take ownership, but APIs that return
* #wasmtime_val_t require that #wasmtime_val_delete is called to deallocate
* the value.
*/
typedef struct wasmtime_val {
/// Discriminant of which field of #of is valid.
wasmtime_valkind_t kind;
/// Container for the extern item's value.
wasmtime_valunion_t of;
} wasmtime_val_t;
/**
* \brief Delets an owned #wasmtime_val_t.
*
* Note that this only deletes the contents, not the memory that `val` points to
* itself (which is owned by the caller).
*/
WASM_API_EXTERN void wasmtime_val_delete(wasmtime_val_t *val);
/**
* \brief Copies `src` into `dst`.
*/
WASM_API_EXTERN void wasmtime_val_copy(wasmtime_val_t *dst, const wasmtime_val_t *src);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WASMTIME_VAL_H