start calling into wasm2c version of platform
This commit is contained in:
8
Makefile
8
Makefile
@@ -1,7 +1,7 @@
|
|||||||
WASM3_C := $(wildcard wasm3/source/*.c)
|
WASM3_C := $(wildcard wasm3/source/*.c)
|
||||||
WASM3_O := $(WASM3_C:.c=.o)
|
WASM3_O := $(WASM3_C:.c=.o)
|
||||||
|
|
||||||
uw8-wasm3: main.o $(WASM3_O)
|
uw8-wasm3: main.o $(WASM3_O) platform.o wasm-rt-impl.o
|
||||||
gcc -g -lm -lSDL2 -o uw8-wasm3 $^
|
gcc -g -lm -lSDL2 -o uw8-wasm3 $^
|
||||||
|
|
||||||
run: uw8-wasm3 .PHONY
|
run: uw8-wasm3 .PHONY
|
||||||
@@ -11,10 +11,10 @@ run-ts:
|
|||||||
deno run --allow-read main.ts
|
deno run --allow-read main.ts
|
||||||
|
|
||||||
wasm3/source/%.o: wasm3/source/%.c
|
wasm3/source/%.o: wasm3/source/%.c
|
||||||
gcc -g -O2 -c -o $@ $^
|
gcc -g -O2 -c -o $@ $<
|
||||||
|
|
||||||
main.o: main.c
|
%.o: %.c platform.h wasm-rt.h wasm-rt-impl.h
|
||||||
gcc -g -O2 -c -o main.o main.c
|
gcc -g -O2 -c -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm uw8-wasm3 main.o $(WASM3_O)
|
rm uw8-wasm3 main.o $(WASM3_O)
|
||||||
|
|||||||
BIN
loader.wasm
BIN
loader.wasm
Binary file not shown.
65
main.c
65
main.c
@@ -1,5 +1,6 @@
|
|||||||
#include "wasm3/source/wasm3.h"
|
#include "wasm3/source/wasm3.h"
|
||||||
#include "wasm3/source/m3_env.h"
|
#include "wasm3/source/m3_env.h"
|
||||||
|
#include "platform.h"
|
||||||
#include "SDL2/SDL.h"
|
#include "SDL2/SDL.h"
|
||||||
#include "SDL2/SDL_video.h"
|
#include "SDL2/SDL_video.h"
|
||||||
#include "SDL2/SDL_render.h"
|
#include "SDL2/SDL_render.h"
|
||||||
@@ -21,6 +22,27 @@ void* loadFile(size_t* sizeOut, const char* filename) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MATH1(name) \
|
||||||
|
f32 Z_envZ_##name(struct Z_env_instance_t* i, f32 v) { \
|
||||||
|
return name##f(v); \
|
||||||
|
}
|
||||||
|
#define MATH2(name) \
|
||||||
|
f32 Z_envZ_##name(struct Z_env_instance_t* i, f32 a, f32 b) { \
|
||||||
|
return name##f(a, b); \
|
||||||
|
}
|
||||||
|
MATH1(acos); MATH1(asin); MATH1(atan); MATH2(atan2);
|
||||||
|
MATH1(cos); MATH1(sin); MATH1(tan);
|
||||||
|
MATH1(exp); MATH2(pow);
|
||||||
|
void Z_envZ_logChar(struct Z_env_instance_t* i, u32 c) {}
|
||||||
|
|
||||||
|
u32 reservedGlobal;
|
||||||
|
#define G_RESERVED(n) u32* Z_envZ_g_reserved##n(struct Z_env_instance_t* i) { return &reservedGlobal; }
|
||||||
|
G_RESERVED(0); G_RESERVED(1); G_RESERVED(2); G_RESERVED(3);
|
||||||
|
G_RESERVED(4); G_RESERVED(5); G_RESERVED(6); G_RESERVED(7);
|
||||||
|
G_RESERVED(8); G_RESERVED(9); G_RESERVED(10); G_RESERVED(11);
|
||||||
|
G_RESERVED(12); G_RESERVED(13); G_RESERVED(14); G_RESERVED(15);
|
||||||
|
wasm_rt_memory_t* Z_envZ_memory(struct Z_env_instance_t* i) { return (wasm_rt_memory_t*)i; }
|
||||||
|
|
||||||
void verifyM3(IM3Runtime runtime, M3Result result) {
|
void verifyM3(IM3Runtime runtime, M3Result result) {
|
||||||
if (result != m3Err_none) {
|
if (result != m3Err_none) {
|
||||||
M3ErrorInfo info;
|
M3ErrorInfo info;
|
||||||
@@ -86,6 +108,25 @@ m3ApiRawFunction(platformTrampoline) {
|
|||||||
m3ApiSuccess();
|
m3ApiSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m3ApiRawFunction(callCircle) {
|
||||||
|
Z_platformZ_circle((Z_platform_instance_t*)_ctx->userdata, *(f32*)&_sp[0], *(f32*)&_sp[1], *(f32*)&_sp[2], _sp[3]);
|
||||||
|
m3ApiSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
m3ApiRawFunction(callBlitSprite) {
|
||||||
|
Z_platformZ_blitSprite((Z_platform_instance_t*)_ctx->userdata, _sp[0], _sp[1], _sp[2], _sp[3], _sp[4]);
|
||||||
|
m3ApiSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const char* name;
|
||||||
|
const char* signature;
|
||||||
|
M3RawCall function;
|
||||||
|
} cPlatformFunctions[] = {
|
||||||
|
{ "circle", "v(fffi)", callCircle },
|
||||||
|
{ "blitSprite", "v(iiiii)", callBlitSprite }
|
||||||
|
};
|
||||||
|
|
||||||
void appendType(char* signature, M3ValueType type) {
|
void appendType(char* signature, M3ValueType type) {
|
||||||
if(type == c_m3Type_i32) {
|
if(type == c_m3Type_i32) {
|
||||||
strcat(signature, "i");
|
strcat(signature, "i");
|
||||||
@@ -99,10 +140,18 @@ void appendType(char* signature, M3ValueType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void linkPlatformFunctions(IM3Runtime runtime, IM3Module cartMod, IM3Module platformMod) {
|
void linkPlatformFunctions(IM3Runtime runtime, IM3Module cartMod, IM3Module platformMod, Z_platform_instance_t* platformInstance) {
|
||||||
for(u32 functionIndex = 0; functionIndex < platformMod->numFunctions; ++functionIndex) {
|
for(u32 functionIndex = 0; functionIndex < platformMod->numFunctions; ++functionIndex) {
|
||||||
M3Function function = platformMod->functions[functionIndex];
|
M3Function function = platformMod->functions[functionIndex];
|
||||||
if(function.export_name != NULL) {
|
if(function.export_name != NULL) {
|
||||||
|
bool foundCImpl = false;
|
||||||
|
for(int i = 0; i * sizeof(cPlatformFunctions[0]) < sizeof(cPlatformFunctions); ++i) {
|
||||||
|
if(strcmp(function.export_name, cPlatformFunctions[i].name) == 0) {
|
||||||
|
m3_LinkRawFunctionEx(cartMod, "env", function.export_name, cPlatformFunctions[i].signature, cPlatformFunctions[i].function, platformInstance);
|
||||||
|
foundCImpl = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!foundCImpl) {
|
||||||
IM3Function iFunc;
|
IM3Function iFunc;
|
||||||
verifyM3(runtime, m3_FindFunction(&iFunc, runtime, function.export_name));
|
verifyM3(runtime, m3_FindFunction(&iFunc, runtime, function.export_name));
|
||||||
char signature[128] = { 0 };
|
char signature[128] = { 0 };
|
||||||
@@ -120,6 +169,7 @@ void linkPlatformFunctions(IM3Runtime runtime, IM3Module cartMod, IM3Module plat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* loadUw8(uint32_t* sizeOut, IM3Runtime runtime, IM3Function loadFunc, const char* filename) {
|
void* loadUw8(uint32_t* sizeOut, IM3Runtime runtime, IM3Function loadFunc, const char* filename) {
|
||||||
size_t uw8Size;
|
size_t uw8Size;
|
||||||
@@ -141,6 +191,8 @@ const uint32_t uw8buttonScanCodes[] = {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
IM3Runtime runtime;
|
IM3Runtime runtime;
|
||||||
IM3Module platform;
|
IM3Module platform;
|
||||||
|
wasm_rt_memory_t memory_c;
|
||||||
|
Z_platform_instance_t platform_c;
|
||||||
IM3Module cart;
|
IM3Module cart;
|
||||||
} Uw8Runtime;
|
} Uw8Runtime;
|
||||||
|
|
||||||
@@ -150,6 +202,12 @@ void initRuntime(Uw8Runtime* runtime, IM3Environment env,
|
|||||||
runtime->runtime->memory.maxPages = 4;
|
runtime->runtime->memory.maxPages = 4;
|
||||||
verifyM3(runtime->runtime, ResizeMemory(runtime->runtime, 4));
|
verifyM3(runtime->runtime, ResizeMemory(runtime->runtime, 4));
|
||||||
|
|
||||||
|
runtime->memory_c.data = m3_GetMemory(runtime->runtime, NULL, 0);
|
||||||
|
runtime->memory_c.max_pages = 4;
|
||||||
|
runtime->memory_c.pages = 4;
|
||||||
|
runtime->memory_c.size = 256*1024;
|
||||||
|
Z_platform_instantiate(&runtime->platform_c, (struct Z_env_instance_t*)&runtime->memory_c);
|
||||||
|
|
||||||
verifyM3(runtime->runtime, m3_ParseModule(env, &runtime->platform, platform, platformSize));
|
verifyM3(runtime->runtime, m3_ParseModule(env, &runtime->platform, platform, platformSize));
|
||||||
runtime->platform->memoryImported = true;
|
runtime->platform->memoryImported = true;
|
||||||
verifyM3(runtime->runtime, m3_LoadModule(runtime->runtime, runtime->platform));
|
verifyM3(runtime->runtime, m3_LoadModule(runtime->runtime, runtime->platform));
|
||||||
@@ -161,7 +219,7 @@ void initRuntime(Uw8Runtime* runtime, IM3Environment env,
|
|||||||
runtime->platform->memoryImported = true;
|
runtime->platform->memoryImported = true;
|
||||||
verifyM3(runtime->runtime, m3_LoadModule(runtime->runtime, runtime->cart));
|
verifyM3(runtime->runtime, m3_LoadModule(runtime->runtime, runtime->cart));
|
||||||
linkSystemFunctions(runtime->runtime, runtime->cart);
|
linkSystemFunctions(runtime->runtime, runtime->cart);
|
||||||
linkPlatformFunctions(runtime->runtime, runtime->cart, runtime->platform);
|
linkPlatformFunctions(runtime->runtime, runtime->cart, runtime->platform, &runtime->platform_c);
|
||||||
verifyM3(runtime->runtime, m3_CompileModule(runtime->cart));
|
verifyM3(runtime->runtime, m3_CompileModule(runtime->cart));
|
||||||
verifyM3(runtime->runtime, m3_RunStart(runtime->cart));
|
verifyM3(runtime->runtime, m3_RunStart(runtime->cart));
|
||||||
}
|
}
|
||||||
@@ -226,6 +284,9 @@ int main(int argc, const char** argv) {
|
|||||||
|
|
||||||
m3_FreeRuntime(loaderRuntime);
|
m3_FreeRuntime(loaderRuntime);
|
||||||
|
|
||||||
|
wasm_rt_init();
|
||||||
|
Z_platform_init_module();
|
||||||
|
|
||||||
bool quit = false;
|
bool quit = false;
|
||||||
while(!quit) {
|
while(!quit) {
|
||||||
Uw8Runtime runtime;
|
Uw8Runtime runtime;
|
||||||
|
|||||||
4242
platform.c
Normal file
4242
platform.c
Normal file
File diff suppressed because it is too large
Load Diff
147
platform.h
Normal file
147
platform.h
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/* Automatically generated by wasm2c */
|
||||||
|
#ifndef PLATFORM_H_GENERATED_
|
||||||
|
#define PLATFORM_H_GENERATED_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "wasm-rt.h"
|
||||||
|
|
||||||
|
/* TODO(binji): only use stdint.h types in header */
|
||||||
|
#ifndef WASM_RT_CORE_TYPES_DEFINED
|
||||||
|
#define WASM_RT_CORE_TYPES_DEFINED
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef int8_t s8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef int16_t s16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef int32_t s32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef int64_t s64;
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Z_env_instance_t;
|
||||||
|
extern wasm_rt_memory_t* Z_envZ_memory(struct Z_env_instance_t*);
|
||||||
|
|
||||||
|
typedef struct Z_platform_instance_t {
|
||||||
|
struct Z_env_instance_t* Z_env_instance;
|
||||||
|
/* import: 'env' 'memory' */
|
||||||
|
wasm_rt_memory_t *Z_envZ_memory;
|
||||||
|
u64 w2c_g0;
|
||||||
|
u32 w2c_g1;
|
||||||
|
u32 w2c_g2;
|
||||||
|
u32 w2c_g3;
|
||||||
|
u32 w2c_g4;
|
||||||
|
u32 w2c_g5;
|
||||||
|
u32 w2c_g6;
|
||||||
|
} Z_platform_instance_t;
|
||||||
|
|
||||||
|
void Z_platform_init_module(void);
|
||||||
|
void Z_platform_instantiate(Z_platform_instance_t*, struct Z_env_instance_t*);
|
||||||
|
void Z_platform_free(Z_platform_instance_t*);
|
||||||
|
|
||||||
|
/* import: 'env' 'cos' */
|
||||||
|
f32 Z_envZ_cos(struct Z_env_instance_t*, f32);
|
||||||
|
/* import: 'env' 'exp' */
|
||||||
|
f32 Z_envZ_exp(struct Z_env_instance_t*, f32);
|
||||||
|
/* import: 'env' 'logChar' */
|
||||||
|
void Z_envZ_logChar(struct Z_env_instance_t*, u32);
|
||||||
|
/* import: 'env' 'pow' */
|
||||||
|
f32 Z_envZ_pow(struct Z_env_instance_t*, f32, f32);
|
||||||
|
/* import: 'env' 'sin' */
|
||||||
|
f32 Z_envZ_sin(struct Z_env_instance_t*, f32);
|
||||||
|
|
||||||
|
/* export: 'time' */
|
||||||
|
f32 Z_platformZ_time(Z_platform_instance_t*);
|
||||||
|
|
||||||
|
/* export: 'isButtonPressed' */
|
||||||
|
u32 Z_platformZ_isButtonPressed(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'isButtonTriggered' */
|
||||||
|
u32 Z_platformZ_isButtonTriggered(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'random' */
|
||||||
|
u32 Z_platformZ_random(Z_platform_instance_t*);
|
||||||
|
|
||||||
|
/* export: 'random64' */
|
||||||
|
u64 Z_platformZ_random64(Z_platform_instance_t*);
|
||||||
|
|
||||||
|
/* export: 'randomf' */
|
||||||
|
f32 Z_platformZ_randomf(Z_platform_instance_t*);
|
||||||
|
|
||||||
|
/* export: 'randomSeed' */
|
||||||
|
void Z_platformZ_randomSeed(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'fmod' */
|
||||||
|
f32 Z_platformZ_fmod(Z_platform_instance_t*, f32, f32);
|
||||||
|
|
||||||
|
/* export: 'cls' */
|
||||||
|
void Z_platformZ_cls(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'setPixel' */
|
||||||
|
void Z_platformZ_setPixel(Z_platform_instance_t*, u32, u32, u32);
|
||||||
|
|
||||||
|
/* export: 'getPixel' */
|
||||||
|
u32 Z_platformZ_getPixel(Z_platform_instance_t*, u32, u32);
|
||||||
|
|
||||||
|
/* export: 'hline' */
|
||||||
|
void Z_platformZ_hline(Z_platform_instance_t*, u32, u32, u32, u32);
|
||||||
|
|
||||||
|
/* export: 'rectangle' */
|
||||||
|
void Z_platformZ_rectangle(Z_platform_instance_t*, f32, f32, f32, f32, u32);
|
||||||
|
|
||||||
|
/* export: 'rectangleOutline' */
|
||||||
|
void Z_platformZ_rectangleOutline(Z_platform_instance_t*, f32, f32, f32, f32, u32);
|
||||||
|
|
||||||
|
/* export: 'circle' */
|
||||||
|
void Z_platformZ_circle(Z_platform_instance_t*, f32, f32, f32, u32);
|
||||||
|
|
||||||
|
/* export: 'circleOutline' */
|
||||||
|
void Z_platformZ_circleOutline(Z_platform_instance_t*, f32, f32, f32, u32);
|
||||||
|
|
||||||
|
/* export: 'line' */
|
||||||
|
void Z_platformZ_line(Z_platform_instance_t*, f32, f32, f32, f32, u32);
|
||||||
|
|
||||||
|
/* export: 'blitSprite' */
|
||||||
|
void Z_platformZ_blitSprite(Z_platform_instance_t*, u32, u32, u32, u32, u32);
|
||||||
|
|
||||||
|
/* export: 'grabSprite' */
|
||||||
|
void Z_platformZ_grabSprite(Z_platform_instance_t*, u32, u32, u32, u32, u32);
|
||||||
|
|
||||||
|
/* export: 'printChar' */
|
||||||
|
void Z_platformZ_printChar(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'printString' */
|
||||||
|
void Z_platformZ_printString(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'printInt' */
|
||||||
|
void Z_platformZ_printInt(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'setTextColor' */
|
||||||
|
void Z_platformZ_setTextColor(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'setBackgroundColor' */
|
||||||
|
void Z_platformZ_setBackgroundColor(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
/* export: 'setCursorPosition' */
|
||||||
|
void Z_platformZ_setCursorPosition(Z_platform_instance_t*, u32, u32);
|
||||||
|
|
||||||
|
/* export: 'playNote' */
|
||||||
|
void Z_platformZ_playNote(Z_platform_instance_t*, u32, u32);
|
||||||
|
|
||||||
|
/* export: 'endFrame' */
|
||||||
|
void Z_platformZ_endFrame(Z_platform_instance_t*);
|
||||||
|
|
||||||
|
/* export: 'sndGes' */
|
||||||
|
f32 Z_platformZ_sndGes(Z_platform_instance_t*, u32);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* PLATFORM_H_GENERATED_ */
|
||||||
BIN
platform.uw8
BIN
platform.uw8
Binary file not shown.
504
wasm-rt-impl.c
Normal file
504
wasm-rt-impl.c
Normal file
@@ -0,0 +1,504 @@
|
|||||||
|
/*
|
||||||
|
* 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 <math.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY && \
|
||||||
|
!defined(_WIN32)
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
#include <malloc.h>
|
||||||
|
#define alloca _alloca
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PAGE_SIZE 65536
|
||||||
|
#define MAX_EXCEPTION_SIZE PAGE_SIZE
|
||||||
|
|
||||||
|
typedef struct FuncType {
|
||||||
|
wasm_rt_type_t* params;
|
||||||
|
wasm_rt_type_t* results;
|
||||||
|
uint32_t param_count;
|
||||||
|
uint32_t result_count;
|
||||||
|
} FuncType;
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
|
||||||
|
static bool g_signal_handler_installed = false;
|
||||||
|
#ifdef _WIN32
|
||||||
|
static void* g_sig_handler_handle = 0;
|
||||||
|
#else
|
||||||
|
static char* g_alt_stack = 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WASM_RT_USE_STACK_DEPTH_COUNT
|
||||||
|
uint32_t wasm_rt_call_stack_depth;
|
||||||
|
uint32_t wasm_rt_saved_call_stack_depth;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static FuncType* g_func_types;
|
||||||
|
static uint32_t g_func_type_count;
|
||||||
|
|
||||||
|
jmp_buf wasm_rt_jmp_buf;
|
||||||
|
|
||||||
|
static uint32_t g_active_exception_tag;
|
||||||
|
static uint8_t g_active_exception[MAX_EXCEPTION_SIZE];
|
||||||
|
static uint32_t g_active_exception_size;
|
||||||
|
|
||||||
|
static jmp_buf* g_unwind_target;
|
||||||
|
|
||||||
|
void wasm_rt_trap(wasm_rt_trap_t code) {
|
||||||
|
assert(code != WASM_RT_TRAP_NONE);
|
||||||
|
#if WASM_RT_USE_STACK_DEPTH_COUNT
|
||||||
|
wasm_rt_call_stack_depth = wasm_rt_saved_call_stack_depth;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WASM_RT_TRAP_HANDLER
|
||||||
|
WASM_RT_TRAP_HANDLER(code);
|
||||||
|
wasm_rt_unreachable();
|
||||||
|
#else
|
||||||
|
WASM_RT_LONGJMP(wasm_rt_jmp_buf, code);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
uint32_t 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,
|
||||||
|
...) {
|
||||||
|
size_t param_size = param_count * sizeof(wasm_rt_type_t);
|
||||||
|
size_t result_size = result_count * sizeof(wasm_rt_type_t);
|
||||||
|
FuncType func_type;
|
||||||
|
func_type.param_count = param_count;
|
||||||
|
func_type.params = alloca(param_size);
|
||||||
|
func_type.result_count = result_count;
|
||||||
|
func_type.results = alloca(result_size);
|
||||||
|
|
||||||
|
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))
|
||||||
|
return i + 1;
|
||||||
|
|
||||||
|
// This is a new/unseed type. Copy our stack allocated params/results into
|
||||||
|
// permanent heap allocated space.
|
||||||
|
wasm_rt_type_t* params = malloc(param_size);
|
||||||
|
wasm_rt_type_t* results = malloc(result_size);
|
||||||
|
memcpy(params, func_type.params, param_size);
|
||||||
|
memcpy(results, func_type.results, result_size);
|
||||||
|
func_type.params = params;
|
||||||
|
func_type.results = results;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wasm_rt_register_tag(uint32_t size) {
|
||||||
|
static uint32_t s_tag_count = 0;
|
||||||
|
|
||||||
|
if (size > MAX_EXCEPTION_SIZE) {
|
||||||
|
wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION);
|
||||||
|
}
|
||||||
|
return s_tag_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wasm_rt_load_exception(uint32_t tag, uint32_t size, const void* values) {
|
||||||
|
assert(size <= MAX_EXCEPTION_SIZE);
|
||||||
|
|
||||||
|
g_active_exception_tag = tag;
|
||||||
|
g_active_exception_size = size;
|
||||||
|
|
||||||
|
if (size) {
|
||||||
|
memcpy(g_active_exception, values, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WASM_RT_NO_RETURN void wasm_rt_throw(void) {
|
||||||
|
WASM_RT_LONGJMP(*g_unwind_target, WASM_RT_TRAP_UNCAUGHT_EXCEPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void) {
|
||||||
|
return g_unwind_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target) {
|
||||||
|
g_unwind_target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wasm_rt_exception_tag(void) {
|
||||||
|
return g_active_exception_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wasm_rt_exception_size(void) {
|
||||||
|
return g_active_exception_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* wasm_rt_exception(void) {
|
||||||
|
return g_active_exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static void* os_mmap(size_t size) {
|
||||||
|
void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int os_munmap(void* addr, size_t size) {
|
||||||
|
// Windows can only unmap the whole mapping
|
||||||
|
(void)size; /* unused */
|
||||||
|
BOOL succeeded = VirtualFree(addr, 0, MEM_RELEASE);
|
||||||
|
return succeeded ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int os_mprotect(void* addr, size_t size) {
|
||||||
|
if (size == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void* ret = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (ret == addr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
VirtualFree(addr, 0, MEM_RELEASE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_print_last_error(const char* msg) {
|
||||||
|
DWORD errorMessageID = GetLastError();
|
||||||
|
if (errorMessageID != 0) {
|
||||||
|
LPSTR messageBuffer = 0;
|
||||||
|
// The api creates the buffer that holds the message
|
||||||
|
size_t size = FormatMessageA(
|
||||||
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPSTR)&messageBuffer, 0, NULL);
|
||||||
|
(void)size;
|
||||||
|
printf("%s. %s\n", msg, messageBuffer);
|
||||||
|
LocalFree(messageBuffer);
|
||||||
|
} else {
|
||||||
|
printf("%s. No error code.\n", msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
|
||||||
|
|
||||||
|
static LONG os_signal_handler(PEXCEPTION_POINTERS info) {
|
||||||
|
if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
|
||||||
|
wasm_rt_trap(WASM_RT_TRAP_OOB);
|
||||||
|
} else if (info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
|
||||||
|
wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION);
|
||||||
|
}
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_install_signal_handler(void) {
|
||||||
|
g_sig_handler_handle =
|
||||||
|
AddVectoredExceptionHandler(1 /* CALL_FIRST */, os_signal_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_cleanup_signal_handler(void) {
|
||||||
|
RemoveVectoredExceptionHandler(g_sig_handler_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
static void* os_mmap(size_t size) {
|
||||||
|
int map_prot = PROT_NONE;
|
||||||
|
int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
|
||||||
|
uint8_t* addr = mmap(NULL, size, map_prot, map_flags, -1, 0);
|
||||||
|
if (addr == MAP_FAILED)
|
||||||
|
return NULL;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int os_munmap(void* addr, size_t size) {
|
||||||
|
return munmap(addr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int os_mprotect(void* addr, size_t size) {
|
||||||
|
return mprotect(addr, size, PROT_READ | PROT_WRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_print_last_error(const char* msg) {
|
||||||
|
perror(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
|
||||||
|
static void os_signal_handler(int sig, siginfo_t* si, void* unused) {
|
||||||
|
if (si->si_code == SEGV_ACCERR) {
|
||||||
|
wasm_rt_trap(WASM_RT_TRAP_OOB);
|
||||||
|
} else {
|
||||||
|
wasm_rt_trap(WASM_RT_TRAP_EXHAUSTION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_install_signal_handler(void) {
|
||||||
|
/* Use alt stack to handle SIGSEGV from stack overflow */
|
||||||
|
g_alt_stack = malloc(SIGSTKSZ);
|
||||||
|
if (g_alt_stack == NULL) {
|
||||||
|
perror("malloc failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_t ss;
|
||||||
|
ss.ss_sp = g_alt_stack;
|
||||||
|
ss.ss_flags = 0;
|
||||||
|
ss.ss_size = SIGSTKSZ;
|
||||||
|
if (sigaltstack(&ss, NULL) != 0) {
|
||||||
|
perror("sigaltstack failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_sigaction = os_signal_handler;
|
||||||
|
|
||||||
|
/* Install SIGSEGV and SIGBUS handlers, since macOS seems to use SIGBUS. */
|
||||||
|
if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL) != 0) {
|
||||||
|
perror("sigaction failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void os_cleanup_signal_handler(void) {
|
||||||
|
/* Undo what was done in os_install_signal_handler */
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = SIG_DFL;
|
||||||
|
if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL)) {
|
||||||
|
perror("sigaction failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sigaltstack(NULL, NULL) != 0) {
|
||||||
|
perror("sigaltstack failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
free(g_alt_stack);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void wasm_rt_init(void) {
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
|
||||||
|
if (!g_signal_handler_installed) {
|
||||||
|
g_signal_handler_installed = true;
|
||||||
|
os_install_signal_handler();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasm_rt_is_initialized(void) {
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
|
||||||
|
return g_signal_handler_installed;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void wasm_rt_free(void) {
|
||||||
|
for (uint32_t i = 0; i < g_func_type_count; ++i) {
|
||||||
|
free(g_func_types[i].params);
|
||||||
|
free(g_func_types[i].results);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_func_type_count = 0;
|
||||||
|
free(g_func_types);
|
||||||
|
g_func_types = NULL;
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY
|
||||||
|
os_cleanup_signal_handler();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
|
||||||
|
uint32_t initial_pages,
|
||||||
|
uint32_t max_pages) {
|
||||||
|
uint32_t byte_length = initial_pages * PAGE_SIZE;
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||||
|
/* Reserve 8GiB. */
|
||||||
|
void* addr = os_mmap(0x200000000ul);
|
||||||
|
|
||||||
|
if (!addr) {
|
||||||
|
os_print_last_error("os_mmap failed.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
int ret = os_mprotect(addr, byte_length);
|
||||||
|
if (ret != 0) {
|
||||||
|
os_print_last_error("os_mprotect failed.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
memory->data = addr;
|
||||||
|
#else
|
||||||
|
memory->data = calloc(byte_length, 1);
|
||||||
|
#endif
|
||||||
|
memory->size = byte_length;
|
||||||
|
memory->pages = initial_pages;
|
||||||
|
memory->max_pages = max_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (new_pages < old_pages || new_pages > memory->max_pages) {
|
||||||
|
return (uint32_t)-1;
|
||||||
|
}
|
||||||
|
uint32_t old_size = old_pages * PAGE_SIZE;
|
||||||
|
uint32_t new_size = new_pages * PAGE_SIZE;
|
||||||
|
uint32_t delta_size = delta * PAGE_SIZE;
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||||
|
uint8_t* new_data = memory->data;
|
||||||
|
int ret = os_mprotect(new_data + old_size, delta_size);
|
||||||
|
if (ret != 0) {
|
||||||
|
return (uint32_t)-1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
uint8_t* new_data = realloc(memory->data, new_size);
|
||||||
|
if (new_data == NULL) {
|
||||||
|
return (uint32_t)-1;
|
||||||
|
}
|
||||||
|
#if !WABT_BIG_ENDIAN
|
||||||
|
memset(new_data + old_size, 0, delta_size);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if WABT_BIG_ENDIAN
|
||||||
|
memmove(new_data + new_size - old_size, new_data, old_size);
|
||||||
|
memset(new_data, 0, delta_size);
|
||||||
|
#endif
|
||||||
|
memory->pages = new_pages;
|
||||||
|
memory->size = new_size;
|
||||||
|
memory->data = new_data;
|
||||||
|
return old_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wasm_rt_free_memory(wasm_rt_memory_t* memory) {
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||||
|
os_munmap(memory->data, memory->size); // ignore error?
|
||||||
|
#else
|
||||||
|
free(memory->data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_TABLE_OPS(type) \
|
||||||
|
void wasm_rt_allocate_##type##_table(wasm_rt_##type##_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_##type##_t)); \
|
||||||
|
} \
|
||||||
|
void wasm_rt_free_##type##_table(wasm_rt_##type##_table_t* table) { \
|
||||||
|
free(table->data); \
|
||||||
|
} \
|
||||||
|
uint32_t wasm_rt_grow_##type##_table(wasm_rt_##type##_table_t* table, \
|
||||||
|
uint32_t delta, \
|
||||||
|
wasm_rt_##type##_t init) { \
|
||||||
|
uint32_t old_elems = table->size; \
|
||||||
|
uint64_t new_elems = (uint64_t)table->size + delta; \
|
||||||
|
if (new_elems == 0) { \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
if ((new_elems < old_elems) || (new_elems > table->max_size)) { \
|
||||||
|
return (uint32_t)-1; \
|
||||||
|
} \
|
||||||
|
void* new_data = \
|
||||||
|
realloc(table->data, new_elems * sizeof(wasm_rt_##type##_t)); \
|
||||||
|
if (!new_data) { \
|
||||||
|
return (uint32_t)-1; \
|
||||||
|
} \
|
||||||
|
table->data = new_data; \
|
||||||
|
table->size = new_elems; \
|
||||||
|
for (uint32_t i = old_elems; i < new_elems; i++) { \
|
||||||
|
table->data[i] = init; \
|
||||||
|
} \
|
||||||
|
return old_elems; \
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_TABLE_OPS(funcref)
|
||||||
|
DEFINE_TABLE_OPS(externref)
|
||||||
|
|
||||||
|
const char* wasm_rt_strerror(wasm_rt_trap_t trap) {
|
||||||
|
switch (trap) {
|
||||||
|
case WASM_RT_TRAP_NONE:
|
||||||
|
return "No error";
|
||||||
|
case WASM_RT_TRAP_OOB:
|
||||||
|
#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS
|
||||||
|
return "Out-of-bounds access in linear memory or a table, or call stack "
|
||||||
|
"exhausted";
|
||||||
|
#else
|
||||||
|
return "Out-of-bounds access in linear memory or a table";
|
||||||
|
case WASM_RT_TRAP_EXHAUSTION:
|
||||||
|
return "Call stack exhausted";
|
||||||
|
#endif
|
||||||
|
case WASM_RT_TRAP_INT_OVERFLOW:
|
||||||
|
return "Integer overflow on divide or truncation";
|
||||||
|
case WASM_RT_TRAP_DIV_BY_ZERO:
|
||||||
|
return "Integer divide by zero";
|
||||||
|
case WASM_RT_TRAP_INVALID_CONVERSION:
|
||||||
|
return "Conversion from NaN to integer";
|
||||||
|
case WASM_RT_TRAP_UNREACHABLE:
|
||||||
|
return "Unreachable instruction executed";
|
||||||
|
case WASM_RT_TRAP_CALL_INDIRECT:
|
||||||
|
return "Invalid call_indirect";
|
||||||
|
case WASM_RT_TRAP_UNCAUGHT_EXCEPTION:
|
||||||
|
return "Uncaught exception";
|
||||||
|
}
|
||||||
|
return "invalid trap code";
|
||||||
|
}
|
||||||
72
wasm-rt-impl.h
Normal file
72
wasm-rt-impl.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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 "wasm-rt.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** A setjmp buffer used for handling traps. */
|
||||||
|
extern jmp_buf wasm_rt_jmp_buf;
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !defined(_WIN32)
|
||||||
|
#define WASM_RT_LONGJMP(buf, val) siglongjmp(buf, val)
|
||||||
|
#else
|
||||||
|
#define WASM_RT_LONGJMP(buf, val) longjmp(buf, val)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WASM_RT_USE_STACK_DEPTH_COUNT
|
||||||
|
/** Saved call stack depth that will be restored in case a trap occurs. */
|
||||||
|
extern uint32_t wasm_rt_saved_call_stack_depth;
|
||||||
|
#define WASM_RT_SAVE_STACK_DEPTH() \
|
||||||
|
wasm_rt_saved_call_stack_depth = wasm_rt_call_stack_depth
|
||||||
|
#else
|
||||||
|
#define WASM_RT_SAVE_STACK_DEPTH() (void)0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() \
|
||||||
|
(WASM_RT_SAVE_STACK_DEPTH(), wasm_rt_set_unwind_target(&wasm_rt_jmp_buf), \
|
||||||
|
WASM_RT_SETJMP(wasm_rt_jmp_buf))
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WASM_RT_IMPL_H_ */
|
||||||
409
wasm-rt.h
Normal file
409
wasm-rt.h
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
/*
|
||||||
|
* 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 <setjmp.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __has_builtin
|
||||||
|
#define __has_builtin(x) 0 // Compatibility with non-clang compilers.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_builtin(__builtin_expect)
|
||||||
|
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
|
#define LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
|
#else
|
||||||
|
#define UNLIKELY(x) (x)
|
||||||
|
#define LIKELY(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_builtin(__builtin_memcpy)
|
||||||
|
#define wasm_rt_memcpy __builtin_memcpy
|
||||||
|
#else
|
||||||
|
#define wasm_rt_memcpy memcpy
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_builtin(__builtin_unreachable)
|
||||||
|
#define wasm_rt_unreachable __builtin_unreachable
|
||||||
|
#else
|
||||||
|
#define wasm_rt_unreachable abort
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable memory checking via a signal handler via the following definition:
|
||||||
|
*
|
||||||
|
* #define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
|
||||||
|
*
|
||||||
|
* This is usually 10%-25% faster, but requires OS-specific support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WASM_RT_SKIP_SIGNAL_RECOVERY
|
||||||
|
#define WASM_RT_SKIP_SIGNAL_RECOVERY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Signal handler not supported on 32-bit platforms. */
|
||||||
|
#if UINTPTR_MAX > 0xffffffff
|
||||||
|
|
||||||
|
#define WASM_RT_SIGNAL_RECOVERY_SUPPORTED 1
|
||||||
|
|
||||||
|
/* Signal handler is supported. Use it by default. */
|
||||||
|
#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||||
|
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define WASM_RT_SIGNAL_RECOVERY_SUPPORTED 0
|
||||||
|
|
||||||
|
/* Signal handler is not supported. */
|
||||||
|
#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||||
|
#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && \
|
||||||
|
(!WASM_RT_SKIP_SIGNAL_RECOVERY && !WASM_RT_SIGNAL_RECOVERY_SUPPORTED)
|
||||||
|
/* The signal handler is not supported, error out if the user was trying to
|
||||||
|
* enable it. */
|
||||||
|
#error "Signal handler is not supported for this OS/Architecture!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WASM_RT_USE_STACK_DEPTH_COUNT
|
||||||
|
/* The signal handler on POSIX can detect call stack overflows. On windows, or
|
||||||
|
* platforms without a signal handler, we use stack depth counting. */
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !defined(_WIN32)
|
||||||
|
#define WASM_RT_USE_STACK_DEPTH_COUNT 0
|
||||||
|
#else
|
||||||
|
#define WASM_RT_USE_STACK_DEPTH_COUNT 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WASM_RT_USE_STACK_DEPTH_COUNT
|
||||||
|
/**
|
||||||
|
* When the signal handler cannot be used to detect stack overflows, stack depth
|
||||||
|
* is limited explicitly. The maximum stack depth before trapping 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
|
||||||
|
|
||||||
|
/** Current call stack depth. */
|
||||||
|
extern uint32_t wasm_rt_call_stack_depth;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define WASM_RT_NO_RETURN __declspec(noreturn)
|
||||||
|
#else
|
||||||
|
#define WASM_RT_NO_RETURN __attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && WASM_RT_MEMCHECK_SIGNAL_HANDLER
|
||||||
|
#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1
|
||||||
|
#else
|
||||||
|
#define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0
|
||||||
|
#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 or a table. */
|
||||||
|
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_UNCAUGHT_EXCEPTION, /* Exception thrown and not caught */
|
||||||
|
#if WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS
|
||||||
|
WASM_RT_TRAP_EXHAUSTION = WASM_RT_TRAP_OOB,
|
||||||
|
#else
|
||||||
|
WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */
|
||||||
|
#endif
|
||||||
|
} 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_FUNCREF,
|
||||||
|
WASM_RT_EXTERNREF,
|
||||||
|
} wasm_rt_type_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic function pointer type, both for Wasm functions (`code`)
|
||||||
|
* and host functions (`hostcode`). All function pointers are stored
|
||||||
|
* in this canonical form, but must be cast to their proper signature
|
||||||
|
* to call.
|
||||||
|
*/
|
||||||
|
typedef void (*wasm_rt_function_ptr_t)(void);
|
||||||
|
|
||||||
|
/** A function instance (the runtime representation of a function).
|
||||||
|
* These can be stored in tables of type funcref, or used as values. */
|
||||||
|
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_function_ptr_t func;
|
||||||
|
/** A function instance is a closure of the function over an instance
|
||||||
|
* of the originating module. The module_instance element will be passed into
|
||||||
|
* the function at runtime. */
|
||||||
|
void* module_instance;
|
||||||
|
} wasm_rt_funcref_t;
|
||||||
|
|
||||||
|
/** Default (null) value of a funcref */
|
||||||
|
static const wasm_rt_funcref_t wasm_rt_funcref_null_value = {0, NULL, NULL};
|
||||||
|
|
||||||
|
/** The type of an external reference (opaque to WebAssembly). */
|
||||||
|
typedef void* wasm_rt_externref_t;
|
||||||
|
|
||||||
|
/** Default (null) value of an externref */
|
||||||
|
static const wasm_rt_externref_t wasm_rt_externref_null_value = NULL;
|
||||||
|
|
||||||
|
/** 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 of type funcref. */
|
||||||
|
typedef struct {
|
||||||
|
/** The table element data, with an element count of `size`. */
|
||||||
|
wasm_rt_funcref_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_funcref_table_t;
|
||||||
|
|
||||||
|
/** A Table of type externref. */
|
||||||
|
typedef struct {
|
||||||
|
/** The table element data, with an element count of `size`. */
|
||||||
|
wasm_rt_externref_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_externref_table_t;
|
||||||
|
|
||||||
|
/** Initialize the runtime. */
|
||||||
|
void wasm_rt_init(void);
|
||||||
|
|
||||||
|
/** Is the runtime initialized? */
|
||||||
|
bool wasm_rt_is_initialized(void);
|
||||||
|
|
||||||
|
/** Free the runtime's state. */
|
||||||
|
void wasm_rt_free(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop execution immediately and jump back to the call to `wasm_rt_impl_try`.
|
||||||
|
* The result of `wasm_rt_impl_try` will be the provided trap reason.
|
||||||
|
*
|
||||||
|
* This is typically called by the generated code, and not the embedder.
|
||||||
|
*/
|
||||||
|
WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a human readable error string based on a trap type.
|
||||||
|
*/
|
||||||
|
const char* wasm_rt_strerror(wasm_rt_trap_t trap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a tag with the given size. Returns the tag.
|
||||||
|
*/
|
||||||
|
uint32_t wasm_rt_register_tag(uint32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the active exception to given tag, size, and contents.
|
||||||
|
*/
|
||||||
|
void wasm_rt_load_exception(uint32_t tag, uint32_t size, const void* values);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw the active exception.
|
||||||
|
*/
|
||||||
|
WASM_RT_NO_RETURN void wasm_rt_throw(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of an unwind target if an exception is thrown and caught.
|
||||||
|
*/
|
||||||
|
#define WASM_RT_UNWIND_TARGET jmp_buf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current unwind target if an exception is thrown.
|
||||||
|
*/
|
||||||
|
WASM_RT_UNWIND_TARGET* wasm_rt_get_unwind_target(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the unwind target if an exception is thrown.
|
||||||
|
*/
|
||||||
|
void wasm_rt_set_unwind_target(WASM_RT_UNWIND_TARGET* target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag of the active exception.
|
||||||
|
*/
|
||||||
|
uint32_t wasm_rt_exception_tag(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of the active exception.
|
||||||
|
*/
|
||||||
|
uint32_t wasm_rt_exception_size(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contents of the active exception.
|
||||||
|
*/
|
||||||
|
void* wasm_rt_exception(void);
|
||||||
|
|
||||||
|
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !defined(_WIN32)
|
||||||
|
#define WASM_RT_SETJMP(buf) sigsetjmp(buf, 1)
|
||||||
|
#else
|
||||||
|
#define WASM_RT_SETJMP(buf) setjmp(buf)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define wasm_rt_try(target) WASM_RT_SETJMP(target)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a Memory object.
|
||||||
|
*/
|
||||||
|
void wasm_rt_free_memory(wasm_rt_memory_t*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a funcref Table object with an element count of `elements` and a
|
||||||
|
* maximum size of `max_elements`.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* wasm_rt_funcref_table_t my_table;
|
||||||
|
* // 5 elements and a maximum of 10 elements.
|
||||||
|
* wasm_rt_allocate_funcref_table(&my_table, 5, 10);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
void wasm_rt_allocate_funcref_table(wasm_rt_funcref_table_t*,
|
||||||
|
uint32_t elements,
|
||||||
|
uint32_t max_elements);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a funcref Table object.
|
||||||
|
*/
|
||||||
|
void wasm_rt_free_funcref_table(wasm_rt_funcref_table_t*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an externref Table object with an element count
|
||||||
|
* of `elements` and a maximum size of `max_elements`.
|
||||||
|
* Usage as per wasm_rt_allocate_funcref_table.
|
||||||
|
*/
|
||||||
|
void wasm_rt_allocate_externref_table(wasm_rt_externref_table_t*,
|
||||||
|
uint32_t elements,
|
||||||
|
uint32_t max_elements);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free an externref Table object.
|
||||||
|
*/
|
||||||
|
void wasm_rt_free_externref_table(wasm_rt_externref_table_t*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grow a Table object by `delta` elements (giving the new elements the value
|
||||||
|
* `init`), and return the previous element count. If this new element count is
|
||||||
|
* greater than the maximum element count, the grow fails and 0xffffffffu
|
||||||
|
* (UINT32_MAX) is returned instead.
|
||||||
|
*/
|
||||||
|
uint32_t wasm_rt_grow_funcref_table(wasm_rt_funcref_table_t*,
|
||||||
|
uint32_t delta,
|
||||||
|
wasm_rt_funcref_t init);
|
||||||
|
uint32_t wasm_rt_grow_externref_table(wasm_rt_externref_table_t*,
|
||||||
|
uint32_t delta,
|
||||||
|
wasm_rt_externref_t init);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WASM_RT_H_ */
|
||||||
Reference in New Issue
Block a user