blob: 6bd550cd1b6c3d71281c184beac8fba85798aeaa [file] [log] [blame] [edit]
/*
* Base of all support for wasm2c code.
*/
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// ssize_t detection: usually stdint provides it, but not on windows apparently
#ifdef _WIN32
#ifdef _MSC_VER
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#else // _MSC_VER
#ifdef _WIN64
typedef signed long long ssize_t;
#else // _WIN64
typedef signed long ssize_t;
#endif // _WIN64
#endif // _MSC_VER
#endif // _WIN32
#include "wasm-rt.h"
#include "wasm-rt-impl.h"
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0)
#define MEMACCESS(addr) ((void*)&Z_memory->data[addr])
#undef MEMCHECK
#define MEMCHECK(a, t) \
if (UNLIKELY((a) + sizeof(t) > Z_memory->size)) TRAP(OOB)
#undef DEFINE_LOAD
#define DEFINE_LOAD(name, t1, t2, t3) \
static inline t3 name(u64 addr) { \
MEMCHECK(addr, t1); \
t1 result; \
memcpy(&result, MEMACCESS(addr), sizeof(t1)); \
return (t3)(t2)result; \
}
#undef DEFINE_STORE
#define DEFINE_STORE(name, t1, t2) \
static inline void name(u64 addr, t2 value) { \
MEMCHECK(addr, t1); \
t1 wrapped = (t1)value; \
memcpy(MEMACCESS(addr), &wrapped, sizeof(t1)); \
}
DEFINE_LOAD(wasm_i32_load, u32, u32, u32);
DEFINE_LOAD(wasm_i64_load, u64, u64, u64);
DEFINE_LOAD(wasm_f32_load, f32, f32, f32);
DEFINE_LOAD(wasm_f64_load, f64, f64, f64);
DEFINE_LOAD(wasm_i32_load8_s, s8, s32, u32);
DEFINE_LOAD(wasm_i64_load8_s, s8, s64, u64);
DEFINE_LOAD(wasm_i32_load8_u, u8, u32, u32);
DEFINE_LOAD(wasm_i64_load8_u, u8, u64, u64);
DEFINE_LOAD(wasm_i32_load16_s, s16, s32, u32);
DEFINE_LOAD(wasm_i64_load16_s, s16, s64, u64);
DEFINE_LOAD(wasm_i32_load16_u, u16, u32, u32);
DEFINE_LOAD(wasm_i64_load16_u, u16, u64, u64);
DEFINE_LOAD(wasm_i64_load32_s, s32, s64, u64);
DEFINE_LOAD(wasm_i64_load32_u, u32, u64, u64);
DEFINE_STORE(wasm_i32_store, u32, u32);
DEFINE_STORE(wasm_i64_store, u64, u64);
DEFINE_STORE(wasm_f32_store, f32, f32);
DEFINE_STORE(wasm_f64_store, f64, f64);
DEFINE_STORE(wasm_i32_store8, u8, u32);
DEFINE_STORE(wasm_i32_store16, u16, u32);
DEFINE_STORE(wasm_i64_store8, u8, u64);
DEFINE_STORE(wasm_i64_store16, u16, u64);
DEFINE_STORE(wasm_i64_store32, u32, u64);
// Imports
#ifdef VERBOSE_LOGGING
#define VERBOSE_LOG(...) { printf(__VA_ARGS__); }
#else
#define VERBOSE_LOG(...)
#endif
#define IMPORT_IMPL(ret, name, params, body) \
static ret _##name params { \
VERBOSE_LOG("[import: " #name "]\n"); \
body \
} \
ret (*name) params = _##name;
#define STUB_IMPORT_IMPL(ret, name, params, returncode) IMPORT_IMPL(ret, name, params, { return returncode; });
// Generic abort method for a runtime error in the runtime.
static void abort_with_message(const char* message) {
fprintf(stderr, "%s\n", message);
TRAP(UNREACHABLE);
}
// Maintain a stack of setjmps, each jump taking us back to the last invoke.
#define MAX_SETJMP_STACK 1024
static jmp_buf setjmp_stack[MAX_SETJMP_STACK];
static u32 next_setjmp = 0;
// Declare an export that may be needed and may not be. For example if longjmp
// is included then we need setThrew, but we must declare setThrew so that
// the C compiler can build us without error if longjmp is not actually used.
#define DECLARE_WEAK_EXPORT(ret, name, args) \
__attribute__((weak)) \
ret (*WASM_RT_ADD_PREFIX(name)) args = NULL;
DECLARE_WEAK_EXPORT(void, Z_setThrewZ_vii, (u32, u32));
IMPORT_IMPL(void, Z_envZ_emscripten_longjmpZ_vii, (u32 buf, u32 value), {
if (next_setjmp == 0) {
abort_with_message("longjmp without setjmp");
}
Z_setThrewZ_vii(buf, value ? value : 1);
longjmp(setjmp_stack[next_setjmp - 1], 1);
});
IMPORT_IMPL(void, Z_envZ_emscripten_notify_memory_growthZ_vi, (u32 size), {});
static u32 tempRet0 = 0;
IMPORT_IMPL(u32, Z_envZ_getTempRet0Z_iv, (), {
return tempRet0;
});
IMPORT_IMPL(void, Z_envZ_setTempRet0Z_vi, (u32 x), {
tempRet0 = x;
});
// Shared OS support in both sandboxed and unsandboxed mode
#define WASI_DEFAULT_ERROR 63 /* __WASI_ERRNO_PERM */
#define WASI_EINVAL 28
// Syscalls return a negative error code
#define EM_EACCES -2
STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_fdstat_getZ_iii, (u32 a, u32 b), WASI_DEFAULT_ERROR);
STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_syncZ_ii, (u32 a), WASI_DEFAULT_ERROR);
STUB_IMPORT_IMPL(u32, Z_envZ_dlopenZ_iii, (u32 a, u32 b), 1);
STUB_IMPORT_IMPL(u32, Z_envZ_dlcloseZ_ii, (u32 a), 1);
STUB_IMPORT_IMPL(u32, Z_envZ_dlsymZ_iii, (u32 a, u32 b), 0);
STUB_IMPORT_IMPL(u32, Z_envZ_dlerrorZ_iv, (), 0);
STUB_IMPORT_IMPL(u32, Z_envZ_signalZ_iii, (u32 a, u32 b), -1);
STUB_IMPORT_IMPL(u32, Z_envZ_systemZ_ii, (u32 a), -1);
STUB_IMPORT_IMPL(u32, Z_envZ_utimesZ_iii, (u32 a, u32 b), -1);
STUB_IMPORT_IMPL(u32, Z_envZ___sys_rmdirZ_ii, (u32 a), EM_EACCES);
STUB_IMPORT_IMPL(u32, Z_envZ___sys_renameZ_iii, (u32 a, u32 b), EM_EACCES);
STUB_IMPORT_IMPL(u32, Z_envZ___sys_lstat64Z_iii, (u32 a, u32 b), EM_EACCES);
STUB_IMPORT_IMPL(u32, Z_envZ___sys_dup3Z_iiii, (u32 a, u32 b, u32 c), EM_EACCES);
STUB_IMPORT_IMPL(u32, Z_envZ___sys_dup2Z_iii, (u32 a, u32 b), EM_EACCES);
STUB_IMPORT_IMPL(u32, Z_envZ___sys_getcwdZ_iii, (u32 a, u32 b), EM_EACCES);
STUB_IMPORT_IMPL(u32, Z_envZ___sys_ftruncate64Z_iiiii, (u32 a, u32 b, u32 c, u32 d), EM_EACCES);
STUB_IMPORT_IMPL(u32, Z_envZ_pthread_mutexattr_initZ_ii, (u32 a), 0);
STUB_IMPORT_IMPL(u32, Z_envZ_pthread_mutexattr_settypeZ_iii, (u32 a, u32 b), 0);
STUB_IMPORT_IMPL(u32, Z_envZ_pthread_mutexattr_destroyZ_ii, (u32 a), 0);
STUB_IMPORT_IMPL(u32, Z_envZ_pthread_createZ_iiiii, (u32 a, u32 b, u32 c, u32 d), -1);
STUB_IMPORT_IMPL(u32, Z_envZ_pthread_joinZ_iii, (u32 a, u32 b), -1);
STUB_IMPORT_IMPL(u32, Z_envZ___cxa_thread_atexitZ_iiii, (u32 a, u32 b, u32 c), -1);