diff --git a/README.md b/README.md index 54077d7..a48fef4 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ The package has no library dependencies and provides pre-compiled wheels for all ```sh pip install tree-sitter +# For wasm support +pip install tree-sitter[wasm] ``` ## Usage @@ -39,6 +41,22 @@ from tree_sitter import Language, Parser PY_LANGUAGE = Language(tspython.language()) ``` +#### Wasm support + +If you enable the `wasm` extra, then tree-sitter will be able to use wasmtime to load languages compiled to wasm and parse with them. Example: + +```python +from pathlib import Path +from wasmtime import Engine +from tree_sitter import Language, Parser + +engine = Engine() +wasm_bytes = Path("my_language.wasm").read_bytes() +MY_LANGUAGE = Language.from_wasm("my_language", engine, wasm_bytes) +``` + +Languages loaded this way work identically to native-binary languages. + ### Basic parsing Create a `Parser` and configure it to use a language: diff --git a/pyproject.toml b/pyproject.toml index 8ba4cc9..e6b375d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ tests = [ "tree-sitter-python>=0.23.0", "tree-sitter-rust>=0.23.0", ] +wasm = ["wasmtime>=23"] [tool.ruff] target-version = "py39" diff --git a/setup.py b/setup.py index f6876d9..a0c131f 100644 --- a/setup.py +++ b/setup.py @@ -23,29 +23,33 @@ "tree_sitter/binding/range.c", "tree_sitter/binding/tree.c", "tree_sitter/binding/tree_cursor.c", + "tree_sitter/binding/wasmtime.c", "tree_sitter/binding/module.c", ], include_dirs=[ "tree_sitter/binding", "tree_sitter/core/lib/include", "tree_sitter/core/lib/src", + "tree_sitter/core/lib/src/wasm", ], define_macros=[ ("PY_SSIZE_T_CLEAN", None), ("TREE_SITTER_HIDE_SYMBOLS", None), + ("TREE_SITTER_FEATURE_WASM", None), ], - undef_macros=[ - "TREE_SITTER_FEATURE_WASM", - ], - extra_compile_args=[ - "-std=c11", - "-fvisibility=hidden", - "-Wno-cast-function-type", - "-Werror=implicit-function-declaration", - ] if system() != "Windows" else [ - "/std:c11", - "/wd4244", - ], + extra_compile_args=( + [ + "-std=c11", + "-fvisibility=hidden", + "-Wno-cast-function-type", + "-Werror=implicit-function-declaration", + ] + if system() != "Windows" + else [ + "/std:c11", + "/wd4244", + ] + ), ) ], ) diff --git a/tests/test_wasm.py b/tests/test_wasm.py new file mode 100644 index 0000000..d6571c0 --- /dev/null +++ b/tests/test_wasm.py @@ -0,0 +1,36 @@ +import importlib.resources +from unittest import TestCase + +from tree_sitter import Language, Parser, Tree + +try: + import wasmtime + + class TestWasm(TestCase): + @classmethod + def setUpClass(cls): + javascript_wasm = ( + importlib.resources.files("tests") + .joinpath("wasm/tree-sitter-javascript.wasm") + .read_bytes() + ) + engine = wasmtime.Engine() + cls.javascript = Language.from_wasm("javascript", engine, javascript_wasm) + + def test_parser(self): + parser = Parser(self.javascript) + self.assertIsInstance(parser.parse(b"test"), Tree) + + def test_language_is_wasm(self): + self.assertEqual(self.javascript.is_wasm, True) + +except ImportError: + + class TestWasmDisabled(TestCase): + def test_parser(self): + def runtest(): + Language.from_wasm("javascript", None, b"") + + self.assertRaisesRegex( + RuntimeError, "wasmtime module is not loaded", runtest + ) diff --git a/tests/wasm/tree-sitter-javascript.wasm b/tests/wasm/tree-sitter-javascript.wasm new file mode 100644 index 0000000..dfff472 Binary files /dev/null and b/tests/wasm/tree-sitter-javascript.wasm differ diff --git a/tree_sitter/__init__.py b/tree_sitter/__init__.py index 6f148d4..e97e69f 100644 --- a/tree_sitter/__init__.py +++ b/tree_sitter/__init__.py @@ -17,7 +17,10 @@ MIN_COMPATIBLE_LANGUAGE_VERSION, ) -Point.__doc__ = "A position in a multi-line text document, in terms of rows and columns." + +Point.__doc__ = ( + "A position in a multi-line text document, in terms of rows and columns." +) Point.row.__doc__ = "The zero-based row of the document." Point.column.__doc__ = "The zero-based column of the document." diff --git a/tree_sitter/binding/language.c b/tree_sitter/binding/language.c index e942dbd..89beff8 100644 --- a/tree_sitter/binding/language.c +++ b/tree_sitter/binding/language.c @@ -1,5 +1,8 @@ #include "types.h" +extern void wasm_engine_delete(TSWasmEngine *engine); +extern TSWasmEngine *wasmtime_engine_clone(TSWasmEngine *engine); + int language_init(Language *self, PyObject *args, PyObject *Py_UNUSED(kwargs)) { PyObject *language; if (!PyArg_ParseTuple(args, "O:__init__", &language)) { @@ -30,10 +33,119 @@ int language_init(Language *self, PyObject *args, PyObject *Py_UNUSED(kwargs)) { } void language_dealloc(Language *self) { + if (self->wasm_engine != NULL) { + wasm_engine_delete(self->wasm_engine); + } ts_language_delete(self->language); Py_TYPE(self)->tp_free(self); } +// ctypes.cast(managed_pointer.ptr(), ctypes.c_void_p).value +static void *get_managed_pointer(PyObject *cast, PyObject *c_void_p, PyObject *managed_pointer) { + void *ptr = NULL; + PyObject *ptr_method = NULL; + PyObject *ptr_result = NULL; + PyObject *cast_result = NULL; + PyObject *value_attr = NULL; + + // Call .ptr() method on the managed pointer + ptr_method = PyObject_GetAttrString(managed_pointer, "ptr"); + if (ptr_method == NULL) { + goto cleanup; + } + ptr_result = PyObject_CallObject(ptr_method, NULL); + if (ptr_result == NULL) { + goto cleanup; + } + + // Call cast function + cast_result = PyObject_CallFunctionObjArgs(cast, ptr_result, c_void_p, NULL); + if (cast_result == NULL) { + goto cleanup; + } + + // Get the 'value' attribute from the cast result + value_attr = PyObject_GetAttrString(cast_result, "value"); + if (value_attr == NULL) { + goto cleanup; + } + + // Convert the value attribute to a C void pointer + ptr = PyLong_AsVoidPtr(value_attr); + +cleanup: + Py_XDECREF(value_attr); + Py_XDECREF(cast_result); + Py_XDECREF(ptr_result); + Py_XDECREF(ptr_method); + + if (PyErr_Occurred()) { + return NULL; + } + + return ptr; +} + +PyObject *language_from_wasm(PyTypeObject *cls, PyObject *args) { + ModuleState *state = (ModuleState *)PyType_GetModuleState(cls); + TSWasmError error; + TSWasmStore *wasm_store = NULL; + TSLanguage *language = NULL; + Language *self = NULL; + char *name; + PyObject *py_engine = NULL; + char *wasm; + Py_ssize_t wasm_length; + if (state->wasmtime_engine_type == NULL) { + PyErr_SetString(PyExc_RuntimeError, "wasmtime module is not loaded"); + return NULL; + } + if (!PyArg_ParseTuple(args, "sO!y#:from_wasm", &name, state->wasmtime_engine_type, &py_engine, &wasm, &wasm_length)) { + return NULL; + } + + TSWasmEngine *engine = (TSWasmEngine *)get_managed_pointer(state->ctypes_cast, state->c_void_p, py_engine); + if (engine == NULL) { + goto fail; + } + engine = wasmtime_engine_clone(engine); + if (engine == NULL) { + goto fail; + } + + wasm_store = ts_wasm_store_new(engine, &error); + if (wasm_store == NULL) { + PyErr_Format(PyExc_RuntimeError, "Failed to create TSWasmStore: %s", error.message); + goto fail; + } + + language = (TSLanguage *)ts_wasm_store_load_language(wasm_store, name, wasm, wasm_length, &error); + if (language == NULL) { + PyErr_Format(PyExc_RuntimeError, "Failed to load language: %s", error.message); + goto fail; + } + + self = (Language *)cls->tp_alloc(cls, 0); + if (self == NULL) { + goto fail; + } + + self->language = language; + self->wasm_engine = engine; + self->version = ts_language_version(self->language); +#if HAS_LANGUAGE_NAMES + self->name = ts_language_name(self->language); +#endif + return (PyObject *)self; + +fail: + if (engine != NULL) { + wasm_engine_delete(engine); + } + ts_language_delete(language); + return NULL; +} + PyObject *language_repr(Language *self) { #if HAS_LANGUAGE_NAMES if (self->name == NULL) { @@ -82,6 +194,10 @@ PyObject *language_get_field_count(Language *self, void *Py_UNUSED(payload)) { return PyLong_FromUnsignedLong(ts_language_field_count(self->language)); } +PyObject *language_is_wasm(Language *self, void *Py_UNUSED(payload)) { + return PyBool_FromLong(ts_language_is_wasm(self->language)); +} + PyObject *language_node_kind_for_id(Language *self, PyObject *args) { TSSymbol symbol; if (!PyArg_ParseTuple(args, "H:node_kind_for_id", &symbol)) { @@ -190,6 +306,9 @@ PyObject *language_query(Language *self, PyObject *args) { return PyObject_CallFunction((PyObject *)state->query_type, "Os#", self, source, length); } +PyDoc_STRVAR(language_from_wasm_doc, + "from_wasm(self, name, engine, wasm, /)\n--\n\n" + "Load a language compiled as wasm."); PyDoc_STRVAR(language_node_kind_for_id_doc, "node_kind_for_id(self, id, /)\n--\n\n" "Get the name of the node kind for the given numerical id."); @@ -220,6 +339,12 @@ PyDoc_STRVAR( "Create a new :class:`Query` from a string containing one or more S-expression patterns."); static PyMethodDef language_methods[] = { + { + .ml_name = "from_wasm", + .ml_meth = (PyCFunction)language_from_wasm, + .ml_flags = METH_CLASS | METH_VARARGS, + .ml_doc = language_from_wasm_doc, + }, { .ml_name = "node_kind_for_id", .ml_meth = (PyCFunction)language_node_kind_for_id, @@ -291,6 +416,8 @@ static PyGetSetDef language_accessors[] = { PyDoc_STR("The number of valid states in this language."), NULL}, {"field_count", (getter)language_get_field_count, NULL, PyDoc_STR("The number of distinct field names in this language."), NULL}, + {"is_wasm", (getter)language_is_wasm, NULL, + PyDoc_STR("Check if the language came from a wasm module."), NULL}, {NULL}, }; diff --git a/tree_sitter/binding/module.c b/tree_sitter/binding/module.c index 8f7026f..22d730d 100644 --- a/tree_sitter/binding/module.c +++ b/tree_sitter/binding/module.c @@ -1,3 +1,4 @@ +#include #include "types.h" extern PyType_Spec language_type_spec; @@ -15,6 +16,8 @@ extern PyType_Spec range_type_spec; extern PyType_Spec tree_cursor_type_spec; extern PyType_Spec tree_type_spec; +void tsp_load_wasmtime_symbols(); + // TODO(0.24): drop Python 3.9 support #if PY_MINOR_VERSION > 9 #define AddObjectRef PyModule_AddObjectRef @@ -62,6 +65,9 @@ static void module_free(void *self) { Py_XDECREF(state->tree_type); Py_XDECREF(state->query_error); Py_XDECREF(state->re_compile); + Py_XDECREF(state->wasmtime_engine_type); + Py_XDECREF(state->ctypes_cast); + Py_XDECREF(state->c_void_p); } static struct PyModuleDef module_definition = { @@ -147,6 +153,35 @@ PyMODINIT_FUNC PyInit__binding(void) { if (namedtuple == NULL) { goto cleanup; } + + PyObject *wasmtime_engine = import_attribute("wasmtime", "Engine"); + if (wasmtime_engine == NULL) { + // No worries, disable functionality. + PyErr_Clear(); + } else { + // Ensure wasmtime_engine is a PyTypeObject + if (!PyType_Check(wasmtime_engine)) { + PyErr_SetString(PyExc_TypeError, "wasmtime.Engine is not a type"); + goto cleanup; + } + state->wasmtime_engine_type = (PyTypeObject *)wasmtime_engine; + + tsp_load_wasmtime_symbols(); + if (PyErr_Occurred()) { + goto cleanup; + } + + state->ctypes_cast = import_attribute("ctypes", "cast"); + if (state->ctypes_cast == NULL) { + goto cleanup; + } + + state->c_void_p = import_attribute("ctypes", "c_void_p"); + if (state->c_void_p == NULL) { + goto cleanup; + } + } + PyObject *point_args = Py_BuildValue("s[ss]", "Point", "row", "column"); PyObject *point_kwargs = PyDict_New(); PyDict_SetItemString(point_kwargs, "module", PyUnicode_FromString("tree_sitter")); diff --git a/tree_sitter/binding/parser.c b/tree_sitter/binding/parser.c index 5cf4239..4c061b0 100644 --- a/tree_sitter/binding/parser.c +++ b/tree_sitter/binding/parser.c @@ -1,3 +1,4 @@ +#include #include "types.h" #define SET_ATTRIBUTE_ERROR(name) \ @@ -278,6 +279,7 @@ PyObject *parser_get_language(Parser *self, void *Py_UNUSED(payload)) { } int parser_set_language(Parser *self, PyObject *arg, void *Py_UNUSED(payload)) { + ModuleState *state = GET_MODULE_STATE(self); if (arg == NULL || arg == Py_None) { self->language = NULL; return 0; @@ -299,6 +301,24 @@ int parser_set_language(Parser *self, PyObject *arg, void *Py_UNUSED(payload)) { return -1; } + if (state->wasmtime_engine_type != NULL && ts_language_is_wasm(language->language)) { + TSWasmEngine *engine = language->wasm_engine; + if (engine == NULL) { + PyErr_Format(PyExc_RuntimeError, "Language has no WASM engine"); + return -1; + } + // Allocate a new wasm store and assign it before loading this wasm language. + // It would be possible to reuse the existing store if it belonged to the same + // engine, but tree-sitter does not expose an API to verify that. + TSWasmError error; + TSWasmStore *store = ts_wasm_store_new(engine, &error); + if (store == NULL) { + PyErr_Format(PyExc_RuntimeError, "Failed to create TSWasmStore: %s", error.message); + return -1; + } + ts_parser_set_wasm_store(self->parser, store); + } + if (!ts_parser_set_language(self->parser, language->language)) { PyErr_SetString(PyExc_RuntimeError, "Failed to set the parser language"); return -1; diff --git a/tree_sitter/binding/types.h b/tree_sitter/binding/types.h index 4d73ead..5eeb665 100644 --- a/tree_sitter/binding/types.h +++ b/tree_sitter/binding/types.h @@ -30,6 +30,7 @@ typedef struct { typedef struct { PyObject_HEAD TSLanguage *language; + TSWasmEngine *wasm_engine; uint32_t version; #if HAS_LANGUAGE_NAMES const char *name; @@ -40,6 +41,7 @@ typedef struct { PyObject_HEAD TSParser *parser; PyObject *language; + int has_wasm_store; } Parser; typedef struct { @@ -113,6 +115,9 @@ typedef struct { TSTreeCursor default_cursor; PyObject *re_compile; PyObject *query_error; + PyTypeObject *wasmtime_engine_type; + PyObject *ctypes_cast; + PyObject *c_void_p; PyTypeObject *language_type; PyTypeObject *lookahead_iterator_type; PyTypeObject *lookahead_names_iterator_type; diff --git a/tree_sitter/binding/wasmtime.c b/tree_sitter/binding/wasmtime.c new file mode 100644 index 0000000..6d00f5d --- /dev/null +++ b/tree_sitter/binding/wasmtime.c @@ -0,0 +1,104 @@ +#include +#include +#include "types.h" + +#define own // Marker used by wasm declarations + +typedef int (*func_ptr)(); + +static func_ptr get_dll_func(PyObject *dll, PyObject *cast, PyObject *c_void_p, const char *name) { + func_ptr result = NULL; + PyObject *py_func = NULL, *cast_result = NULL, *value_attr = NULL; + + // Get the function attribute from the dll object + py_func = PyObject_GetAttrString(dll, name); + if (py_func == NULL) { + PyErr_Format(PyExc_AttributeError, "%s", name); + goto cleanup; + } + + // Call cast(py_func, c_void_p) + cast_result = PyObject_CallFunctionObjArgs(cast, py_func, c_void_p, NULL); + if (cast_result == NULL) { + PyErr_SetString(PyExc_AttributeError, "Failed cast to c_void_p"); + goto cleanup; + } + + // Get the 'value' attribute from the cast result + value_attr = PyObject_GetAttrString(cast_result, "value"); + if (value_attr == NULL) { + PyErr_SetString(PyExc_AttributeError, "c_void_p has no value"); + goto cleanup; + } + + // Convert the value attribute to a C pointer + result = (func_ptr)PyLong_AsVoidPtr(value_attr); + +cleanup: + Py_XDECREF(py_func); + Py_XDECREF(cast_result); + Py_XDECREF(value_attr); + return result; +} + +int wasmtime_available = 0; + +// Declare placeholders for functions +#define WASMTIME_TRAMPOLINE(type, return, name, args, call) \ + static type (*real_##name) args = NULL; \ + type name args { return (*real_##name) call; } +#include "wasmtime_symbols.txt" +#undef WASMTIME_TRAMPOLINE + +/// Loads wasmtime as an optional dependency. +void tsp_load_wasmtime_symbols() { + PyObject *ctypes = NULL, *cast = NULL, *c_void_p = NULL, *wasmtime = NULL, *_ffi = NULL, *dll = NULL; + ctypes = PyImport_ImportModule("ctypes"); + if (ctypes == NULL) { + PyErr_SetString(PyExc_RuntimeError, "ctypes module is missing"); + goto cleanup; + } + cast = PyObject_GetAttrString(ctypes, "cast"); + if (cast == NULL) { + PyErr_SetString(PyExc_AttributeError, "ctypes module has no cast"); + goto cleanup; + } + c_void_p = PyObject_GetAttrString(ctypes, "c_void_p"); + if (c_void_p == NULL) { + PyErr_SetString(PyExc_AttributeError, "ctypes module has no c_void_p"); + goto cleanup; + } + wasmtime = PyImport_ImportModule("wasmtime"); + if (wasmtime == NULL) { + goto cleanup; + } + _ffi = PyObject_GetAttrString(wasmtime, "_ffi"); + if (_ffi == NULL) { + PyErr_SetString(PyExc_AttributeError, "wasmtime module has no _ffi"); + goto cleanup; + } + dll = PyObject_GetAttrString(_ffi, "dll"); + if (dll == NULL) { + PyErr_SetString(PyExc_AttributeError, "wasmtime._ffi module has no dll"); + goto cleanup; + } + +#define WASMTIME_TRAMPOLINE(type, return, name, args, call) do { \ + real_##name = (type (*) args) get_dll_func(dll, cast, c_void_p, #name); \ + if (real_##name == NULL) { \ + goto cleanup; \ + } \ + } while (false); +#include "wasmtime_symbols.txt" +#undef WASMTIME_TRAMPOLINE + + wasmtime_available = 1; + +cleanup: + Py_XDECREF(dll); + Py_XDECREF(_ffi); + Py_XDECREF(wasmtime); + Py_XDECREF(c_void_p); + Py_XDECREF(cast); + Py_XDECREF(ctypes); +} diff --git a/tree_sitter/binding/wasmtime_symbols.txt b/tree_sitter/binding/wasmtime_symbols.txt new file mode 100644 index 0000000..25afa3e --- /dev/null +++ b/tree_sitter/binding/wasmtime_symbols.txt @@ -0,0 +1,49 @@ +WASMTIME_TRAMPOLINE(void,, wasm_byte_vec_delete, (wasm_byte_vec_t *a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_engine_delete, (own wasm_engine_t *a), (a)) +WASMTIME_TRAMPOLINE(wasm_engine_t *, return, wasm_engine_new, (void), ()) +WASMTIME_TRAMPOLINE(const wasm_name_t*, return, wasm_exporttype_name, (const wasm_exporttype_t* a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_exporttype_vec_delete, (own wasm_exporttype_vec_t *a), (a)) +WASMTIME_TRAMPOLINE(const wasm_memorytype_t*, return, wasm_externtype_as_memorytype_const, (const wasm_externtype_t* a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_functype_delete, (own wasm_functype_t *a), (a)) +WASMTIME_TRAMPOLINE(wasm_functype_t*, return, wasm_functype_new, (wasm_valtype_vec_t* a, wasm_valtype_vec_t* b), (a, b)) +WASMTIME_TRAMPOLINE(void,, wasm_globaltype_delete, (own wasm_globaltype_t *a), (a)) +WASMTIME_TRAMPOLINE(wasm_globaltype_t*, return, wasm_globaltype_new, (wasm_valtype_t* a, wasm_mutability_t b), (a, b)) +WASMTIME_TRAMPOLINE(const wasm_name_t*, return, wasm_importtype_name, (const wasm_importtype_t* a), (a)) +WASMTIME_TRAMPOLINE(const wasm_externtype_t*, return, wasm_importtype_type, (const wasm_importtype_t* a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_importtype_vec_delete, (own wasm_importtype_vec_t *a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_memorytype_delete, (own wasm_memorytype_t *a), (a)) +WASMTIME_TRAMPOLINE(wasm_memorytype_t*, return, wasm_memorytype_new, (const wasm_limits_t* a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_tabletype_delete, (own wasm_tabletype_t *a), (a)) +WASMTIME_TRAMPOLINE(wasm_tabletype_t*, return, wasm_tabletype_new, (wasm_valtype_t* a, const wasm_limits_t* b), (a, b)) +WASMTIME_TRAMPOLINE(void,, wasm_trap_delete, (own wasm_trap_t *a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_trap_message, (const wasm_trap_t* a, own wasm_message_t* out), (a, out)) +WASMTIME_TRAMPOLINE(wasm_valtype_t*, return, wasm_valtype_new, (wasm_valkind_t a), (a)) +WASMTIME_TRAMPOLINE(void,, wasm_valtype_vec_new, (wasm_valtype_vec_t* out, size_t size, wasm_valtype_t* const data[]), (out, size, data)) +WASMTIME_TRAMPOLINE(void,, wasm_valtype_vec_new_empty, (wasm_valtype_vec_t* out), (out)) +WASMTIME_TRAMPOLINE(wasmtime_context_t*, return, wasmtime_caller_context, (wasmtime_caller_t* caller), (caller)) +WASMTIME_TRAMPOLINE(wasm_engine_t*, return, wasmtime_engine_clone, (wasm_engine_t* engine), (engine)) +WASMTIME_TRAMPOLINE(void,, wasmtime_error_delete, (wasmtime_error_t* error), (error)) +WASMTIME_TRAMPOLINE(void,, wasmtime_error_message, (const wasmtime_error_t* error, wasm_name_t* message), (error, message)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, 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), (store, func, args, nargs, results, nresults, trap)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_func_call_unchecked, (wasmtime_context_t* store, const wasmtime_func_t* func, wasmtime_val_raw_t* args_and_results, size_t args_and_results_len, wasm_trap_t** trap), (store, func, args_and_results, args_and_results_len, trap)) +WASMTIME_TRAMPOLINE(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), (store, type, callback, env, finalizer, ret)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_global_new, (wasmtime_context_t* store, const wasm_globaltype_t* type, const wasmtime_val_t* val, wasmtime_global_t* ret), (store, type, val, ret)) +WASMTIME_TRAMPOLINE(bool, return, 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), (store, instance, index, name, name_len, item)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, 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), (store, module, imports, nimports, instance, trap)) +WASMTIME_TRAMPOLINE(uint8_t*, return, wasmtime_memory_data, (const wasmtime_context_t* store, const wasmtime_memory_t* memory), (store, memory)) +WASMTIME_TRAMPOLINE(size_t, return, wasmtime_memory_data_size, (const wasmtime_context_t* store, const wasmtime_memory_t* memory), (store, memory)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_memory_grow, (wasmtime_context_t* store, const wasmtime_memory_t* memory, uint64_t delta, uint64_t* prev_size), (store, memory, delta, prev_size)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_memory_new, (wasmtime_context_t* store, const wasm_memorytype_t* ty, wasmtime_memory_t* ret), (store, ty, ret)) +WASMTIME_TRAMPOLINE(uint64_t, return, wasmtime_memorytype_minimum, (const wasm_memorytype_t* ty), (ty)) +WASMTIME_TRAMPOLINE(void,, wasmtime_module_delete, (wasmtime_module_t* module), (module)) +WASMTIME_TRAMPOLINE(void,, wasmtime_module_exports, (const wasmtime_module_t* module, wasm_exporttype_vec_t* out), (module, out)) +WASMTIME_TRAMPOLINE(void,, wasmtime_module_imports, (const wasmtime_module_t* module, wasm_importtype_vec_t* out), (module, out)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_module_new, (wasm_engine_t* engine, const uint8_t* wasm, size_t wasm_len, wasmtime_module_t** ret), (engine, wasm, wasm_len, ret)) +WASMTIME_TRAMPOLINE(wasmtime_context_t*, return, wasmtime_store_context, (wasmtime_store_t* store), (store)) +WASMTIME_TRAMPOLINE(void,, wasmtime_store_delete, (wasmtime_store_t* store), (store)) +WASMTIME_TRAMPOLINE(wasmtime_store_t*, return, wasmtime_store_new, (wasm_engine_t* engine, void* data, void (*finalizer)(void*)), (engine, data, finalizer)) +WASMTIME_TRAMPOLINE(bool, return, wasmtime_table_get, (wasmtime_context_t* store, const wasmtime_table_t* table, uint32_t index, wasmtime_val_t* val), (store, table, index, val)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_table_grow, (wasmtime_context_t* store, const wasmtime_table_t* table, uint32_t delta, const wasmtime_val_t* init, uint32_t* prev_size), (store, table, delta, init, prev_size)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_table_new, (wasmtime_context_t* store, const wasm_tabletype_t* ty, const wasmtime_val_t* init, wasmtime_table_t* table), (store, ty, init, table)) +WASMTIME_TRAMPOLINE(wasmtime_error_t*, return, wasmtime_table_set, (wasmtime_context_t* store, const wasmtime_table_t* table, uint32_t index, const wasmtime_val_t* value), (store, table, index, value)) +WASMTIME_TRAMPOLINE(wasm_trap_t*, return, wasmtime_trap_new, (const char* msg, size_t msg_len), (msg, msg_len))