Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add wasm2c files
  • Loading branch information
cmichi committed Feb 21, 2019
commit 7f39648d11d6244bb10311979c0c13c2ea23fc12
122 changes: 122 additions & 0 deletions wasm-rt-impl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "wasm-rt-impl.h"

#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define PAGE_SIZE 65536

typedef struct FuncType {
wasm_rt_type_t* params;
wasm_rt_type_t* results;
uint32_t param_count;
uint32_t result_count;
} FuncType;

uint32_t wasm_rt_call_stack_depth;
uint32_t g_saved_call_stack_depth;

jmp_buf g_jmp_buf;
FuncType* g_func_types;
uint32_t g_func_type_count;

void wasm_rt_trap(wasm_rt_trap_t code) {
assert(code != WASM_RT_TRAP_NONE);
wasm_rt_call_stack_depth = g_saved_call_stack_depth;
longjmp(g_jmp_buf, code);
}

static bool func_types_are_equal(FuncType* a, FuncType* b) {
if (a->param_count != b->param_count || a->result_count != b->result_count)
return 0;
int i;
for (i = 0; i < a->param_count; ++i)
if (a->params[i] != b->params[i])
return 0;
for (i = 0; i < a->result_count; ++i)
if (a->results[i] != b->results[i])
return 0;
return 1;
}

uint32_t wasm_rt_register_func_type(uint32_t param_count,
uint32_t result_count,
...) {
FuncType func_type;
func_type.param_count = param_count;
func_type.params = malloc(param_count * sizeof(wasm_rt_type_t));
func_type.result_count = result_count;
func_type.results = malloc(result_count * sizeof(wasm_rt_type_t));

va_list args;
va_start(args, result_count);

uint32_t i;
for (i = 0; i < param_count; ++i)
func_type.params[i] = va_arg(args, wasm_rt_type_t);
for (i = 0; i < result_count; ++i)
func_type.results[i] = va_arg(args, wasm_rt_type_t);
va_end(args);

for (i = 0; i < g_func_type_count; ++i) {
if (func_types_are_equal(&g_func_types[i], &func_type)) {
free(func_type.params);
free(func_type.results);
return i + 1;
}
}

uint32_t idx = g_func_type_count++;
g_func_types = realloc(g_func_types, g_func_type_count * sizeof(FuncType));
g_func_types[idx] = func_type;
return idx + 1;
}

void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
uint32_t initial_pages,
uint32_t max_pages) {
memory->pages = initial_pages;
memory->max_pages = max_pages;
memory->size = initial_pages * PAGE_SIZE;
memory->data = calloc(memory->size, 1);
}

uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
uint32_t old_pages = memory->pages;
uint32_t new_pages = memory->pages + delta;
if (new_pages < old_pages || new_pages > memory->max_pages) {
return (uint32_t)-1;
}
memory->pages = new_pages;
memory->size = new_pages * PAGE_SIZE;
memory->data = realloc(memory->data, memory->size);
memset(memory->data + old_pages * PAGE_SIZE, 0, delta * PAGE_SIZE);
return old_pages;
}

void wasm_rt_allocate_table(wasm_rt_table_t* table,
uint32_t elements,
uint32_t max_elements) {
table->size = elements;
table->max_size = max_elements;
table->data = calloc(table->size, sizeof(wasm_rt_elem_t));
}
56 changes: 56 additions & 0 deletions wasm-rt-impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef WASM_RT_IMPL_H_
#define WASM_RT_IMPL_H_

#include <setjmp.h>

#include "wasm-rt.h"

#ifdef __cplusplus
extern "C" {
#endif

/** A setjmp buffer used for handling traps. */
extern jmp_buf g_jmp_buf;

/** Saved call stack depth that will be restored in case a trap occurs. */
extern uint32_t g_saved_call_stack_depth;

/** Convenience macro to use before calling a wasm function. On first execution
* it will return `WASM_RT_TRAP_NONE` (i.e. 0). If the function traps, it will
* jump back and return the trap that occurred.
*
* ```
* wasm_rt_trap_t code = wasm_rt_impl_try();
* if (code != 0) {
* printf("A trap occurred with code: %d\n", code);
* ...
* }
*
* // Call the potentially-trapping function.
* my_wasm_func();
* ```
*/
#define wasm_rt_impl_try() \
(g_saved_call_stack_depth = wasm_rt_call_stack_depth, setjmp(g_jmp_buf))

#ifdef __cplusplus
}
#endif

#endif // WASM_RT_IMPL_H_
168 changes: 168 additions & 0 deletions wasm-rt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Copyright 2018 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef WASM_RT_H_
#define WASM_RT_H_

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/** Maximum stack depth before trapping. This can be configured by defining
* this symbol before including wasm-rt when building the generated c files,
* for example:
*
* ```
* cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o
* ```
* */
#ifndef WASM_RT_MAX_CALL_STACK_DEPTH
#define WASM_RT_MAX_CALL_STACK_DEPTH 500
#endif

/** Reason a trap occurred. Provide this to `wasm_rt_trap`. */
typedef enum {
WASM_RT_TRAP_NONE, /** No error. */
WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory. */
WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */
WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */
WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */
WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */
WASM_RT_TRAP_CALL_INDIRECT, /** Invalid call_indirect, for any reason. */
WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */
} wasm_rt_trap_t;

/** Value types. Used to define function signatures. */
typedef enum {
WASM_RT_I32,
WASM_RT_I64,
WASM_RT_F32,
WASM_RT_F64,
} wasm_rt_type_t;

/** A function type for all `anyfunc` functions in a Table. All functions are
* stored in this canonical form, but must be cast to their proper signature to
* call. */
typedef void (*wasm_rt_anyfunc_t)(void);

/** A single element of a Table. */
typedef struct {
/** The index as returned from `wasm_rt_register_func_type`. */
uint32_t func_type;
/** The function. The embedder must know the actual C signature of the
* function and cast to it before calling. */
wasm_rt_anyfunc_t func;
} wasm_rt_elem_t;

/** A Memory object. */
typedef struct {
/** The linear memory data, with a byte length of `size`. */
uint8_t* data;
/** The current and maximum page count for this Memory object. If there is no
* maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */
uint32_t pages, max_pages;
/** The current size of the linear memory, in bytes. */
uint32_t size;
} wasm_rt_memory_t;

/** A Table object. */
typedef struct {
/** The table element data, with an element count of `size`. */
wasm_rt_elem_t* data;
/** The maximum element count of this Table object. If there is no maximum,
* `max_size` is 0xffffffffu (i.e. UINT32_MAX). */
uint32_t max_size;
/** The current element count of the table. */
uint32_t size;
} wasm_rt_table_t;

/** Stop execution immediately and jump back to the call to `wasm_rt_try`.
* The result of `wasm_rt_try` will be the provided trap reason.
*
* This is typically called by the generated code, and not the embedder. */
extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));

/** Register a function type with the given signature. The returned function
* index is guaranteed to be the same for all calls with the same signature.
* The following varargs must all be of type `wasm_rt_type_t`, first the
* params` and then the `results`.
*
* ```
* // Register (func (param i32 f32) (result i64)).
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
* => returns 1
*
* // Register (func (result i64)).
* wasm_rt_register_func_type(0, 1, WASM_RT_I32);
* => returns 2
*
* // Register (func (param i32 f32) (result i64)) again.
* wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64);
* => returns 1
* ``` */
extern uint32_t wasm_rt_register_func_type(uint32_t params,
uint32_t results,
...);

/** Initialize a Memory object with an initial page size of `initial_pages` and
* a maximum page size of `max_pages`.
*
* ```
* wasm_rt_memory_t my_memory;
* // 1 initial page (65536 bytes), and a maximum of 2 pages.
* wasm_rt_allocate_memory(&my_memory, 1, 2);
* ``` */
extern void wasm_rt_allocate_memory(wasm_rt_memory_t*,
uint32_t initial_pages,
uint32_t max_pages);

/** Grow a Memory object by `pages`, and return the previous page count. If
* this new page count is greater than the maximum page count, the grow fails
* and 0xffffffffu (UINT32_MAX) is returned instead.
*
* ```
* wasm_rt_memory_t my_memory;
* ...
* // Grow memory by 10 pages.
* uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10);
* if (old_page_size == UINT32_MAX) {
* // Failed to grow memory.
* }
* ``` */
extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);

/** Initialize a Table object with an element count of `elements` and a maximum
* page size of `max_elements`.
*
* ```
* wasm_rt_table_t my_table;
* // 5 elemnets and a maximum of 10 elements.
* wasm_rt_allocate_table(&my_table, 5, 10);
* ``` */
extern void wasm_rt_allocate_table(wasm_rt_table_t*,
uint32_t elements,
uint32_t max_elements);

/** Current call stack depth. */
extern uint32_t wasm_rt_call_stack_depth;

#ifdef __cplusplus
}
#endif

#endif /* WASM_RT_H_ */