NostrScript is a WebAssembly implementation that interacts with Damus. It enables dynamic scripting that can be used to power custom list views, enabling pluggable algorithms. The web has JavaScript, Damus has NostrScript. NostrScripts can be written in any language that compiles to WASM. This commit adds a WASM interpreter I've written as a mostly-single C file for portability and embeddability. In the future we could JIT-compile these for optimal performance if NostrScripts get large and complicated. For now an interpreter is simple enough for algorithm list view plugins. Changelog-Added: Add initial NostrScript implementation Signed-off-by: William Casarin <jb55@jb55.com>
841 lines
15 KiB
C
841 lines
15 KiB
C
|
|
#ifndef PROTOVERSE_WASM_H
|
|
#define PROTOVERSE_WASM_H
|
|
|
|
static const unsigned char WASM_MAGIC[] = {0,'a','s','m'};
|
|
|
|
#define WASM_VERSION 0x01
|
|
#define MAX_U32_LEB128_BYTES 5
|
|
#define MAX_U64_LEB128_BYTES 10
|
|
#define MAX_CUSTOM_SECTIONS 32
|
|
#define MAX_BUILTINS 64
|
|
#define BUILTIN_SUSPEND 42
|
|
|
|
#define FUNC_TYPE_TAG 0x60
|
|
|
|
|
|
#include "cursor.h"
|
|
#include "error.h"
|
|
|
|
#ifdef NOINLINE
|
|
#define INLINE __attribute__((noinline))
|
|
#else
|
|
#define INLINE inline
|
|
#endif
|
|
|
|
|
|
#define interp_error(p, fmt, ...) note_error(&((p)->errors), interp_codeptr(p), fmt, ##__VA_ARGS__)
|
|
#define parse_err(p, fmt, ...) note_error(&((p)->errs), &(p)->cur, fmt, ##__VA_ARGS__)
|
|
|
|
enum valtype {
|
|
val_i32 = 0x7F,
|
|
val_i64 = 0x7E,
|
|
val_f32 = 0x7D,
|
|
val_f64 = 0x7C,
|
|
val_ref_null = 0xD0,
|
|
val_ref_func = 0x70,
|
|
val_ref_extern = 0x6F,
|
|
};
|
|
|
|
enum const_instr {
|
|
ci_const_i32 = 0x41,
|
|
ci_const_i64 = 0x42,
|
|
ci_const_f32 = 0x43,
|
|
ci_const_f64 = 0x44,
|
|
ci_ref_null = 0xD0,
|
|
ci_ref_func = 0xD2,
|
|
ci_global_get = 0x23,
|
|
ci_end = 0x0B,
|
|
};
|
|
|
|
enum limit_type {
|
|
limit_min = 0x00,
|
|
limit_min_max = 0x01,
|
|
};
|
|
|
|
struct limits {
|
|
u32 min;
|
|
u32 max;
|
|
enum limit_type type;
|
|
};
|
|
|
|
enum section_tag {
|
|
section_custom,
|
|
section_type,
|
|
section_import,
|
|
section_function,
|
|
section_table,
|
|
section_memory,
|
|
section_global,
|
|
section_export,
|
|
section_start,
|
|
section_element,
|
|
section_code,
|
|
section_data,
|
|
section_data_count,
|
|
section_name,
|
|
num_sections,
|
|
};
|
|
|
|
enum name_subsection_tag {
|
|
name_subsection_module,
|
|
name_subsection_funcs,
|
|
name_subsection_locals,
|
|
num_name_subsections,
|
|
};
|
|
|
|
enum reftype {
|
|
funcref = 0x70,
|
|
externref = 0x6F,
|
|
};
|
|
|
|
struct resulttype {
|
|
unsigned char *valtypes; /* enum valtype */
|
|
u32 num_valtypes;
|
|
};
|
|
|
|
struct functype {
|
|
struct resulttype params;
|
|
struct resulttype result;
|
|
};
|
|
|
|
struct table {
|
|
enum reftype reftype;
|
|
struct limits limits;
|
|
};
|
|
|
|
struct tablesec {
|
|
struct table *tables;
|
|
u32 num_tables;
|
|
};
|
|
|
|
enum elem_mode {
|
|
elem_mode_passive,
|
|
elem_mode_active,
|
|
elem_mode_declarative,
|
|
};
|
|
|
|
struct expr {
|
|
u8 *code;
|
|
u32 code_len;
|
|
};
|
|
|
|
struct refval {
|
|
u32 addr;
|
|
};
|
|
|
|
struct table_inst {
|
|
struct refval *refs;
|
|
enum reftype reftype;
|
|
u32 num_refs;
|
|
};
|
|
|
|
struct numval {
|
|
union {
|
|
int i32;
|
|
u32 u32;
|
|
int64_t i64;
|
|
uint64_t u64;
|
|
float f32;
|
|
double f64;
|
|
};
|
|
};
|
|
|
|
struct val {
|
|
enum valtype type;
|
|
union {
|
|
struct numval num;
|
|
struct refval ref;
|
|
};
|
|
};
|
|
|
|
struct elem_inst {
|
|
struct val val;
|
|
u16 elem;
|
|
u16 init;
|
|
};
|
|
|
|
struct elem {
|
|
struct expr offset;
|
|
u32 tableidx;
|
|
struct expr *inits;
|
|
u32 num_inits;
|
|
enum elem_mode mode;
|
|
enum reftype reftype;
|
|
struct val val;
|
|
};
|
|
|
|
struct customsec {
|
|
const char *name;
|
|
unsigned char *data;
|
|
u32 data_len;
|
|
};
|
|
|
|
struct elemsec {
|
|
struct elem *elements;
|
|
u32 num_elements;
|
|
};
|
|
|
|
struct memsec {
|
|
struct limits *mems; /* memtype */
|
|
u32 num_mems;
|
|
};
|
|
|
|
struct funcsec {
|
|
u32 *type_indices;
|
|
u32 num_indices;
|
|
};
|
|
|
|
enum mut {
|
|
mut_const,
|
|
mut_var,
|
|
};
|
|
|
|
struct globaltype {
|
|
enum valtype valtype;
|
|
enum mut mut;
|
|
};
|
|
|
|
struct globalsec {
|
|
struct global *globals;
|
|
u32 num_globals;
|
|
};
|
|
|
|
struct typesec {
|
|
struct functype *functypes;
|
|
u32 num_functypes;
|
|
};
|
|
|
|
enum import_type {
|
|
import_func,
|
|
import_table,
|
|
import_mem,
|
|
import_global,
|
|
};
|
|
|
|
struct importdesc {
|
|
enum import_type type;
|
|
union {
|
|
u32 typeidx;
|
|
struct limits tabletype;
|
|
struct limits memtype;
|
|
struct globaltype globaltype;
|
|
};
|
|
};
|
|
|
|
struct import {
|
|
const char *module_name;
|
|
const char *name;
|
|
struct importdesc desc;
|
|
int resolved_builtin;
|
|
};
|
|
|
|
struct importsec {
|
|
struct import *imports;
|
|
u32 num_imports;
|
|
};
|
|
|
|
struct global {
|
|
struct globaltype type;
|
|
struct expr init;
|
|
struct val val;
|
|
};
|
|
|
|
struct local_def {
|
|
u32 num_types;
|
|
enum valtype type;
|
|
};
|
|
|
|
/* "code" */
|
|
struct wasm_func {
|
|
struct expr code;
|
|
struct local_def *local_defs;
|
|
u32 num_local_defs;
|
|
};
|
|
|
|
enum func_type {
|
|
func_type_wasm,
|
|
func_type_builtin,
|
|
};
|
|
|
|
struct func {
|
|
union {
|
|
struct wasm_func *wasm_func;
|
|
struct builtin *builtin;
|
|
};
|
|
u32 num_locals;
|
|
struct functype *functype;
|
|
enum func_type type;
|
|
const char *name;
|
|
u32 idx;
|
|
};
|
|
|
|
struct codesec {
|
|
struct wasm_func *funcs;
|
|
u32 num_funcs;
|
|
};
|
|
|
|
enum exportdesc {
|
|
export_func,
|
|
export_table,
|
|
export_mem,
|
|
export_global,
|
|
};
|
|
|
|
struct wexport {
|
|
const char *name;
|
|
u32 index;
|
|
enum exportdesc desc;
|
|
};
|
|
|
|
struct exportsec {
|
|
struct wexport *exports;
|
|
u32 num_exports;
|
|
};
|
|
|
|
struct nameassoc {
|
|
u32 index;
|
|
const char *name;
|
|
};
|
|
|
|
struct namemap {
|
|
struct nameassoc *names;
|
|
u32 num_names;
|
|
};
|
|
|
|
struct namesec {
|
|
const char *module_name;
|
|
struct namemap func_names;
|
|
int parsed;
|
|
};
|
|
|
|
struct wsection {
|
|
enum section_tag tag;
|
|
};
|
|
|
|
enum bulk_tag {
|
|
i_memory_copy = 10,
|
|
i_memory_fill = 11,
|
|
i_table_init = 12,
|
|
i_elem_drop = 13,
|
|
i_table_copy = 14,
|
|
i_table_grow = 15,
|
|
i_table_size = 16,
|
|
i_table_fill = 17,
|
|
};
|
|
|
|
enum instr_tag {
|
|
/* control instructions */
|
|
i_unreachable = 0x00,
|
|
i_nop = 0x01,
|
|
i_block = 0x02,
|
|
i_loop = 0x03,
|
|
i_if = 0x04,
|
|
i_else = 0x05,
|
|
i_end = 0x0B,
|
|
i_br = 0x0C,
|
|
i_br_if = 0x0D,
|
|
i_br_table = 0x0E,
|
|
i_return = 0x0F,
|
|
i_call = 0x10,
|
|
i_call_indirect = 0x11,
|
|
|
|
/* parametric instructions */
|
|
i_drop = 0x1A,
|
|
i_select = 0x1B,
|
|
i_selects = 0x1C,
|
|
|
|
/* variable instructions */
|
|
i_local_get = 0x20,
|
|
i_local_set = 0x21,
|
|
i_local_tee = 0x22,
|
|
i_global_get = 0x23,
|
|
i_global_set = 0x24,
|
|
i_table_get = 0x25,
|
|
i_table_set = 0x26,
|
|
|
|
/* memory instructions */
|
|
i_i32_load = 0x28,
|
|
i_i64_load = 0x29,
|
|
i_f32_load = 0x2A,
|
|
i_f64_load = 0x2B,
|
|
i_i32_load8_s = 0x2C,
|
|
i_i32_load8_u = 0x2D,
|
|
i_i32_load16_s = 0x2E,
|
|
i_i32_load16_u = 0x2F,
|
|
i_i64_load8_s = 0x30,
|
|
i_i64_load8_u = 0x31,
|
|
i_i64_load16_s = 0x32,
|
|
i_i64_load16_u = 0x33,
|
|
i_i64_load32_s = 0x34,
|
|
i_i64_load32_u = 0x35,
|
|
i_i32_store = 0x36,
|
|
i_i64_store = 0x37,
|
|
i_f32_store = 0x38,
|
|
i_f64_store = 0x39,
|
|
i_i32_store8 = 0x3A,
|
|
i_i32_store16 = 0x3B,
|
|
i_i64_store8 = 0x3C,
|
|
i_i64_store16 = 0x3D,
|
|
i_i64_store32 = 0x3E,
|
|
i_memory_size = 0x3F,
|
|
i_memory_grow = 0x40,
|
|
|
|
/* numeric instructions */
|
|
i_i32_const = 0x41,
|
|
i_i64_const = 0x42,
|
|
i_f32_const = 0x43,
|
|
i_f64_const = 0x44,
|
|
|
|
i_i32_eqz = 0x45,
|
|
i_i32_eq = 0x46,
|
|
i_i32_ne = 0x47,
|
|
i_i32_lt_s = 0x48,
|
|
i_i32_lt_u = 0x49,
|
|
i_i32_gt_s = 0x4A,
|
|
i_i32_gt_u = 0x4B,
|
|
i_i32_le_s = 0x4C,
|
|
i_i32_le_u = 0x4D,
|
|
i_i32_ge_s = 0x4E,
|
|
i_i32_ge_u = 0x4F,
|
|
|
|
i_i64_eqz = 0x50,
|
|
i_i64_eq = 0x51,
|
|
i_i64_ne = 0x52,
|
|
i_i64_lt_s = 0x53,
|
|
i_i64_lt_u = 0x54,
|
|
i_i64_gt_s = 0x55,
|
|
i_i64_gt_u = 0x56,
|
|
i_i64_le_s = 0x57,
|
|
i_i64_le_u = 0x58,
|
|
i_i64_ge_s = 0x59,
|
|
i_i64_ge_u = 0x5A,
|
|
|
|
i_f32_eq = 0x5B,
|
|
i_f32_ne = 0x5C,
|
|
i_f32_lt = 0x5D,
|
|
i_f32_gt = 0x5E,
|
|
i_f32_le = 0x5F,
|
|
i_f32_ge = 0x60,
|
|
|
|
i_f64_eq = 0x61,
|
|
i_f64_ne = 0x62,
|
|
i_f64_lt = 0x63,
|
|
i_f64_gt = 0x64,
|
|
i_f64_le = 0x65,
|
|
i_f64_ge = 0x66,
|
|
|
|
i_i32_clz = 0x67,
|
|
i_i32_ctz = 0x68,
|
|
i_i32_popcnt = 0x69,
|
|
|
|
i_i32_add = 0x6A,
|
|
i_i32_sub = 0x6B,
|
|
i_i32_mul = 0x6C,
|
|
i_i32_div_s = 0x6D,
|
|
i_i32_div_u = 0x6E,
|
|
i_i32_rem_s = 0x6F,
|
|
i_i32_rem_u = 0x70,
|
|
i_i32_and = 0x71,
|
|
i_i32_or = 0x72,
|
|
i_i32_xor = 0x73,
|
|
i_i32_shl = 0x74,
|
|
i_i32_shr_s = 0x75,
|
|
i_i32_shr_u = 0x76,
|
|
i_i32_rotl = 0x77,
|
|
i_i32_rotr = 0x78,
|
|
|
|
i_i64_clz = 0x79,
|
|
i_i64_ctz = 0x7A,
|
|
i_i64_popcnt = 0x7B,
|
|
i_i64_add = 0x7C,
|
|
i_i64_sub = 0x7D,
|
|
i_i64_mul = 0x7E,
|
|
i_i64_div_s = 0x7F,
|
|
i_i64_div_u = 0x80,
|
|
i_i64_rem_s = 0x81,
|
|
i_i64_rem_u = 0x82,
|
|
i_i64_and = 0x83,
|
|
i_i64_or = 0x84,
|
|
i_i64_xor = 0x85,
|
|
i_i64_shl = 0x86,
|
|
i_i64_shr_s = 0x87,
|
|
i_i64_shr_u = 0x88,
|
|
i_i64_rotl = 0x89,
|
|
i_i64_rotr = 0x8A,
|
|
|
|
i_f32_abs = 0x8b,
|
|
i_f32_neg = 0x8c,
|
|
i_f32_ceil = 0x8d,
|
|
i_f32_floor = 0x8e,
|
|
i_f32_trunc = 0x8f,
|
|
i_f32_nearest = 0x90,
|
|
i_f32_sqrt = 0x91,
|
|
i_f32_add = 0x92,
|
|
i_f32_sub = 0x93,
|
|
i_f32_mul = 0x94,
|
|
i_f32_div = 0x95,
|
|
i_f32_min = 0x96,
|
|
i_f32_max = 0x97,
|
|
i_f32_copysign = 0x98,
|
|
|
|
i_f64_abs = 0x99,
|
|
i_f64_neg = 0x9a,
|
|
i_f64_ceil = 0x9b,
|
|
i_f64_floor = 0x9c,
|
|
i_f64_trunc = 0x9d,
|
|
i_f64_nearest = 0x9e,
|
|
i_f64_sqrt = 0x9f,
|
|
i_f64_add = 0xa0,
|
|
i_f64_sub = 0xa1,
|
|
i_f64_mul = 0xa2,
|
|
i_f64_div = 0xa3,
|
|
i_f64_min = 0xa4,
|
|
i_f64_max = 0xa5,
|
|
i_f64_copysign = 0xa6,
|
|
|
|
i_i32_wrap_i64 = 0xa7,
|
|
i_i32_trunc_f32_s = 0xa8,
|
|
i_i32_trunc_f32_u = 0xa9,
|
|
i_i32_trunc_f64_s = 0xaa,
|
|
i_i32_trunc_f64_u = 0xab,
|
|
i_i64_extend_i32_s = 0xac,
|
|
i_i64_extend_i32_u = 0xad,
|
|
i_i64_trunc_f32_s = 0xae,
|
|
i_i64_trunc_f32_u = 0xaf,
|
|
i_i64_trunc_f64_s = 0xb0,
|
|
i_i64_trunc_f64_u = 0xb1,
|
|
i_f32_convert_i32_s = 0xb2,
|
|
i_f32_convert_i32_u = 0xb3,
|
|
i_f32_convert_i64_s = 0xb4,
|
|
i_f32_convert_i64_u = 0xb5,
|
|
i_f32_demote_f64 = 0xb6,
|
|
i_f64_convert_i32_s = 0xb7,
|
|
i_f64_convert_i32_u = 0xb8,
|
|
i_f64_convert_i64_s = 0xb9,
|
|
i_f64_convert_i64_u = 0xba,
|
|
i_f64_promote_f32 = 0xbb,
|
|
|
|
i_i32_reinterpret_f32 = 0xbc,
|
|
i_i64_reinterpret_f64 = 0xbd,
|
|
i_f32_reinterpret_i32 = 0xbe,
|
|
i_f64_reinterpret_i64 = 0xbf,
|
|
|
|
i_i32_extend8_s = 0xc0,
|
|
i_i32_extend16_s = 0xc1,
|
|
i_i64_extend8_s = 0xc2,
|
|
i_i64_extend16_s = 0xc3,
|
|
i_i64_extend32_s = 0xc4,
|
|
|
|
i_ref_null = 0xD0,
|
|
i_ref_is_null = 0xD1,
|
|
i_ref_func = 0xD2,
|
|
|
|
i_bulk_op = 0xFC,
|
|
/* TODO: more instrs */
|
|
|
|
};
|
|
|
|
enum blocktype_tag {
|
|
blocktype_empty,
|
|
blocktype_valtype,
|
|
blocktype_index,
|
|
};
|
|
|
|
struct blocktype {
|
|
enum blocktype_tag tag;
|
|
union {
|
|
enum valtype valtype;
|
|
int type_index;
|
|
};
|
|
};
|
|
|
|
struct instrs {
|
|
unsigned char *data;
|
|
u32 len;
|
|
};
|
|
|
|
struct block {
|
|
struct blocktype type;
|
|
struct expr instrs;
|
|
};
|
|
|
|
struct memarg {
|
|
u32 offset;
|
|
u32 align;
|
|
};
|
|
|
|
struct br_table {
|
|
u32 num_label_indices;
|
|
u32 label_indices[512];
|
|
u32 default_label;
|
|
};
|
|
|
|
struct call_indirect {
|
|
u32 tableidx;
|
|
u32 typeidx;
|
|
};
|
|
|
|
struct table_init {
|
|
u32 tableidx;
|
|
u32 elemidx;
|
|
};
|
|
|
|
struct table_copy {
|
|
u32 from;
|
|
u32 to;
|
|
};
|
|
|
|
struct bulk_op {
|
|
enum bulk_tag tag;
|
|
union {
|
|
struct table_init table_init;
|
|
struct table_copy table_copy;
|
|
u32 idx;
|
|
};
|
|
};
|
|
|
|
struct select_instr {
|
|
u8 *valtypes;
|
|
u32 num_valtypes;
|
|
};
|
|
|
|
struct instr {
|
|
enum instr_tag tag;
|
|
int pos;
|
|
union {
|
|
struct br_table br_table;
|
|
struct bulk_op bulk_op;
|
|
struct call_indirect call_indirect;
|
|
struct memarg memarg;
|
|
struct select_instr select;
|
|
struct block block;
|
|
struct expr else_block;
|
|
double f64;
|
|
float f32;
|
|
int i32;
|
|
u32 u32;
|
|
int64_t i64;
|
|
u64 u64;
|
|
unsigned char memidx;
|
|
enum reftype reftype;
|
|
};
|
|
};
|
|
|
|
enum datamode {
|
|
datamode_active,
|
|
datamode_passive,
|
|
};
|
|
|
|
struct wdata_active {
|
|
u32 mem_index;
|
|
struct expr offset_expr;
|
|
};
|
|
|
|
struct wdata {
|
|
struct wdata_active active;
|
|
u8 *bytes;
|
|
u32 bytes_len;
|
|
enum datamode mode;
|
|
};
|
|
|
|
struct datasec {
|
|
struct wdata *datas;
|
|
u32 num_datas;
|
|
};
|
|
|
|
struct startsec {
|
|
u32 start_fn;
|
|
};
|
|
|
|
struct module {
|
|
unsigned int parsed;
|
|
unsigned int custom_sections;
|
|
|
|
struct func *funcs;
|
|
|
|
u32 num_funcs;
|
|
|
|
struct customsec custom_section[MAX_CUSTOM_SECTIONS];
|
|
struct typesec type_section;
|
|
struct funcsec func_section;
|
|
struct importsec import_section;
|
|
struct exportsec export_section;
|
|
struct codesec code_section;
|
|
struct tablesec table_section;
|
|
struct memsec memory_section;
|
|
struct globalsec global_section;
|
|
struct startsec start_section;
|
|
struct elemsec element_section;
|
|
struct datasec data_section;
|
|
struct namesec name_section;
|
|
};
|
|
|
|
// make sure the struct is packed so that
|
|
struct label {
|
|
u32 instr_pos; // resolved status is stored in HOB of pos
|
|
u32 jump;
|
|
};
|
|
|
|
struct callframe {
|
|
struct cursor code;
|
|
struct val *locals;
|
|
struct func *func;
|
|
u16 prev_stack_items;
|
|
};
|
|
|
|
struct resolver {
|
|
u16 label;
|
|
u8 end_tag;
|
|
u8 start_tag;
|
|
};
|
|
|
|
struct global_inst {
|
|
struct val val;
|
|
};
|
|
|
|
struct module_inst {
|
|
struct table_inst *tables;
|
|
struct global_inst *globals;
|
|
struct elem_inst *elements;
|
|
|
|
u32 num_tables;
|
|
u32 num_globals;
|
|
u32 num_elements;
|
|
|
|
int start_fn;
|
|
unsigned char *globals_init;
|
|
};
|
|
|
|
struct wasi {
|
|
int argc;
|
|
const char **argv;
|
|
|
|
int environc;
|
|
const char **environ;
|
|
};
|
|
|
|
struct wasm_interp;
|
|
|
|
struct builtin {
|
|
const char *name;
|
|
int (*fn)(struct wasm_interp *);
|
|
int (*prepare_args)(struct wasm_interp *);
|
|
};
|
|
|
|
struct wasm_interp {
|
|
struct module *module;
|
|
struct module_inst module_inst;
|
|
struct wasi wasi;
|
|
void *context;
|
|
|
|
struct builtin builtins[MAX_BUILTINS];
|
|
int num_builtins;
|
|
|
|
int prev_resolvers, quitting;
|
|
|
|
struct errors errors; /* struct error */
|
|
size_t ops;
|
|
|
|
struct cursor callframes; /* struct callframe */
|
|
struct cursor stack; /* struct val */
|
|
struct cursor mem; /* u8/mixed */
|
|
|
|
struct cursor memory; /* memory pages (65536 blocks) */
|
|
|
|
struct cursor locals; /* struct val */
|
|
struct cursor labels; /* struct labels */
|
|
struct cursor num_labels;
|
|
|
|
// resolve stack for the current function. every time a control
|
|
// instruction is encountered, the label index is pushed. When an
|
|
// instruction is popped, we can resolve the label
|
|
struct cursor resolver_stack; /* struct resolver */
|
|
struct cursor resolver_offsets; /* int */
|
|
};
|
|
|
|
struct wasm_parser {
|
|
struct module module;
|
|
struct builtin *builtins;
|
|
u32 num_builtins;
|
|
struct cursor cur;
|
|
struct cursor mem;
|
|
struct errors errs;
|
|
};
|
|
|
|
|
|
int run_wasm(unsigned char *wasm, unsigned long len, int argc, const char **argv, char **env, int *retval);
|
|
int parse_wasm(struct wasm_parser *p);
|
|
int wasm_interp_init(struct wasm_interp *interp, struct module *module);
|
|
void wasm_parser_free(struct wasm_parser *parser);
|
|
void wasm_parser_init(struct wasm_parser *p, u8 *wasm, size_t wasm_len, size_t arena_size, struct builtin *, int num_builtins);
|
|
void wasm_interp_free(struct wasm_interp *interp);
|
|
int interp_wasm_module(struct wasm_interp *interp, int *retval);
|
|
int interp_wasm_module_resume(struct wasm_interp *interp, int *retval);
|
|
void print_error_backtrace(struct errors *errors);
|
|
void setup_wasi(struct wasm_interp *interp, int argc, const char **argv, char **env);
|
|
void print_callstack(struct wasm_interp *interp);
|
|
|
|
// builtin helpers
|
|
int get_params(struct wasm_interp *interp, struct val** vals, u32 num_vals);
|
|
int get_var_params(struct wasm_interp *interp, struct val** vals, u32 *num_vals);
|
|
u8 *interp_mem_ptr(struct wasm_interp *interp, u32 ptr, int size);
|
|
|
|
static INLINE struct callframe *top_callframe(struct cursor *cur)
|
|
{
|
|
return (struct callframe*)cursor_top(cur, sizeof(struct callframe));
|
|
}
|
|
|
|
|
|
static INLINE struct cursor *interp_codeptr(struct wasm_interp *interp)
|
|
{
|
|
struct callframe *frame;
|
|
if (unlikely(!(frame = top_callframe(&interp->callframes))))
|
|
return 0;
|
|
return &frame->code;
|
|
}
|
|
|
|
|
|
static INLINE int mem_ptr_str(struct wasm_interp *interp, u32 ptr,
|
|
const char **str)
|
|
{
|
|
// still technically unsafe if the string runs over the end of memory...
|
|
if (!(*str = (const char*)interp_mem_ptr(interp, ptr, 1))) {
|
|
return interp_error(interp, "int memptr");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static INLINE int mem_ptr_i32(struct wasm_interp *interp, u32 ptr, int **i)
|
|
{
|
|
if (!(*i = (int*)interp_mem_ptr(interp, ptr, sizeof(int))))
|
|
return interp_error(interp, "int memptr");
|
|
return 1;
|
|
}
|
|
|
|
static INLINE int cursor_pushval(struct cursor *cur, struct val *val)
|
|
{
|
|
return cursor_push(cur, (u8*)val, sizeof(*val));
|
|
}
|
|
|
|
static INLINE int cursor_push_i32(struct cursor *stack, int i)
|
|
{
|
|
struct val val;
|
|
val.type = val_i32;
|
|
val.num.i32 = i;
|
|
|
|
return cursor_pushval(stack, &val);
|
|
}
|
|
|
|
static INLINE int stack_push_i32(struct wasm_interp *interp, int i)
|
|
{
|
|
return cursor_push_i32(&interp->stack, i);
|
|
}
|
|
|
|
static INLINE struct callframe *top_callframes(struct cursor *cur, int top)
|
|
{
|
|
return (struct callframe*)cursor_topn(cur, sizeof(struct callframe), top);
|
|
}
|
|
|
|
#endif /* PROTOVERSE_WASM_H */
|