Compare commits

...

18 Commits

Author SHA1 Message Date
Steven Massey f73ee05023 no message
3 years ago
Steven Massey 7c55aceaef no message
3 years ago
Steven Massey 25214b4104 CloseWASI function
3 years ago
Steven Massey c6ab1f799c Merge branch 'extensions' of https://github.com/wasm3/wasm3 into extensions
3 years ago
Steven Massey 5895192a03 no message
3 years ago
Volodymyr Shymanskyy 5cc6747fda Align main and extensions branches
3 years ago
Volodymyr Shymanskyy 4091736237 Tabs -> Spaces
3 years ago
Volodymyr Shymanskyy 3ad8b27955 Tabs -> Spaces
3 years ago
Steven Massey 433e7d71a3 m3Ext_ReserveFunctions
3 years ago
Steven Massey 92c220407e sync
3 years ago
Steven Massey a26615cf99 uhg. git confusion.
3 years ago
Steven Massey 870537563d Merge branch 'main' into extensions
3 years ago
Steven Massey d16ca5bacc trace bug fixes
3 years ago
Steven Massey ee96c34869 no message
3 years ago
Steven Massey d0be6607d1 null var bug fixes
3 years ago
Steven Massey c18deeb86e no message
3 years ago
Steven Massey 5615ff0d84 remove unnecessary? local parsing
3 years ago
Steven Massey ded4cfafc4 no message
3 years ago

@ -139,7 +139,7 @@ M3Result repl_load (const char* fn)
fclose (f);
f = NULL;
result = m3_ParseModule (env, &module, wasm, fsize);
result = m3_ParseModule (env, &module, wasm, fsize, false);
if (result) goto on_error;
result = m3_LoadModule (runtime, module);
@ -198,7 +198,7 @@ M3Result repl_load_hex (u32 fsize)
}
IM3Module module;
result = m3_ParseModule (env, &module, wasm, fsize);
result = m3_ParseModule (env, &module, wasm, fsize, false);
if (result) return result;
result = m3_LoadModule (runtime, module);

@ -12,35 +12,62 @@
#include "m3_exception.h"
IM3Module m3_NewModule (IM3Environment i_environment)
M3Result m3Ext_ReserveFunctions (IM3Module i_module,
uint32_t i_numFunctions)
{
IM3Module module = m3_AllocStruct (M3Module);
M3Result result = m3Err_none;
if (module)
{
module->name = ".unnamed";
module->startFunction = -1;
module->environment = i_environment;
if (i_module)
{ d_m3Assert (i_module->table0Size == 0);
if (i_module->table0Size == 0)
{
i_module->numReservedFunctions = i_numFunctions;
module->wasmStart = NULL;
module->wasmEnd = NULL;
u32 totalFunctions = i_module->numFunctions + i_numFunctions;
i_module->functions = m3_ReallocArray (M3Function, i_module->functions, totalFunctions, i_module->numFunctions);
_throwifnull (i_module->functions);
}
else _throw ("ReserveFunctions must come before LoadModule");
}
else _throw (m3Err_nullArgument);
return module;
_catch:
return result;
}
i32 Module_HasFuncType (IM3Module i_module, IM3FuncType i_funcType)
{
if (i_module->funcTypes)
{
for (u32 i = 0; i < i_module->numFuncTypes; ++i)
{
if (AreFuncTypesEqual (i_module->funcTypes [i], i_funcType))
return i;
}
}
return -1;
}
M3Result m3_InjectFunction (IM3Module i_module,
int32_t * io_functionIndex,
const char * const i_signature,
const uint8_t * const i_wasmBytes,
bool i_doCompilation)
M3Result m3Ext_InjectFunction (IM3Module i_module,
int32_t * io_functionIndex,
const char * const i_signature,
const uint8_t * const i_wasmBytes,
bool i_doCompilation)
{
M3Result result = m3Err_none; d_m3Assert (io_functionIndex);
IM3FuncType ftype = NULL;
_try {
if (not i_module)
_throw (m3Err_nullArgument);
IM3Function function = NULL;
IM3FuncType ftype = NULL;
_ (SignatureToFuncType (& ftype, i_signature));
i32 index = * io_functionIndex;
@ -63,15 +90,19 @@ _ (ReadLEB_u32 (& size, & bytes, end));
}
else
{
// add slot to function type table in the module
u32 funcTypeIndex = i_module->numFuncTypes++;
i_module->funcTypes = m3_ReallocArray (IM3FuncType, i_module->funcTypes, i_module->numFuncTypes, funcTypeIndex);
_throwifnull (i_module->funcTypes);
// add functype object to the environment
Environment_AddFuncType (i_module->environment, & ftype);
i_module->funcTypes [funcTypeIndex] = ftype;
ftype = NULL; // prevent freeing below
i32 funcTypeIndex = Module_HasFuncType (i_module, ftype);
if (funcTypeIndex < 0)
{
// add slot to function type table in the module
funcTypeIndex = i_module->numFuncTypes++;
i_module->funcTypes = m3_ReallocArray (IM3FuncType, i_module->funcTypes, i_module->numFuncTypes, funcTypeIndex);
_throwifnull (i_module->funcTypes);
// add functype object to the environment
Environment_AddFuncType (i_module->environment, & ftype);
i_module->funcTypes [funcTypeIndex] = ftype;
ftype = NULL; // prevent freeing below
}
index = (i32) i_module->numFunctions;
_ (Module_AddFunction (i_module, funcTypeIndex, NULL));
@ -93,20 +124,96 @@ _ (Module_AddFunction (i_module, funcTypeIndex, NULL));
function->ownsWasmCode = true;
function->module = i_module;
if (i_doCompilation and not i_module->runtime)
_throw ("module must be loaded into runtime to compile function");
_ (CompileFunction (function));
_catch:
} _catch:
m3_Free (ftype);
return result;
}
M3Result m3Ext_AddFunctionToTable (IM3Function i_function,
uint32_t * o_elementIndex,
uint32_t i_tableIndex)
{
M3Result result = m3Err_none;
if (i_function and o_elementIndex)
{
IM3Module module = i_function->module;
if (module)
{
u32 previousSize = module->table0Size;
u32 newTableSize = previousSize + 1;
module->table0 = m3_ReallocArray (IM3Function, module->table0, newTableSize, previousSize);
_throwifnull (module->table0);
* o_elementIndex = previousSize;
module->table0 [previousSize] = i_function;
module->table0Size = newTableSize;
}
else _throw ("null module");
}
else _throw (m3Err_nullArgument);
_catch: return result;
}
IM3Function m3_GetFunctionByIndex (IM3Module i_module, uint32_t i_index)
{
return Module_GetFunction (i_module, i_index);
}
M3Result m3_GetFunctionIndex (IM3Function i_function,
uint32_t * o_index)
{
if (i_function and o_index)
{
* o_index = i_function->index;
return m3Err_none;
}
else return m3Err_functionLookupFailed;
}
M3Result m3_GetDataSegmentOffset (IM3Module i_module,
uint32_t i_index)
{
M3Result result = m3Err_none; d_m3Assert (i_module);
if (i_module)
{
d_m3Assert (false); // TODO: finish
}
else _throw (m3Err_nullArgument);
_catch: return result;
}
M3Result m3_RegisterCustomOpcode (IM3Module i_module,
uint16_t i_opcode,
uint8_t i_numImmediates,
IM3Operation i_operation)
{
M3Result result = m3Err_none; d_m3Assert (i_module);
if (i_module)
{
}
else _throw (m3Err_nullArgument);
_catch: return result;
}

@ -10,36 +10,77 @@
#ifndef wasm3_ext_h
#define wasm3_ext_h
#include "wasm3.h"
#include "m3_exec_defs.h"
#include <stdbool.h>
#if defined(__cplusplus)
extern "C" {
#endif
//-------------------------------------------------------------------------------------------------------------------------------
// API extensions
//-------------------------------------------------------------------------------------------------------------------------------
/*
These extensions allow for unconventional uses of Wasm3 -- mainly dynamic modification of modules to inject new Wasm
functions during runtime.
*/
//-------------------------------------------------------------------------------------------------------------------------------
// Creates an empty module.
IM3Module m3_NewModule (IM3Environment i_environment);
IM3Module m3Ext_NewModule (IM3Environment i_environment);
// ReserveFunctions must be called prior to LoadModule. This reserves extra empty function slots that InjectFunction
// can rely upon.
M3Result m3Ext_ReserveFunctions (IM3Module i_module,
uint32_t i_numFunctions);
// To append a new function, set io_functionIndex to negative. On return, the new function index will be set.
// To overwrite an existing function, set io_functionIndex to the desired element. i_signature must match the existing
// function signature.
// ** InjectFunction invalidates any existing IM3Function pointers
M3Result m3_InjectFunction (IM3Module i_module,
// function signature. TODO: failure result is?
M3Result m3Ext_InjectFunction (IM3Module i_module,
int32_t * io_functionIndex,
// const char * const i_name,
const char * const i_signature,
const uint8_t * const i_wasmBytes, // i_wasmBytes is copied
bool i_doCompilation);
M3Result m3Ext_AddFunctionToTable (IM3Function i_function,
uint32_t * o_elementIndex,
uint32_t i_tableIndex); // i_tableIndex must be zero
IM3Function m3_GetFunctionByIndex (IM3Module i_module,
uint32_t i_index);
M3Result m3_GetFunctionIndex (IM3Function i_function,
uint32_t * o_index);
M3Result m3_GetDataSegmentOffset (IM3Module i_module,
uint32_t i_index);
//-------------------------------------------------------------------------------------------------------------------------------
M3Result m3_RegisterCustomOpcode (IM3Module i_module,
uint16_t i_opcode,
uint8_t i_numImmediates,
IM3Operation i_operation);
//-------------------------------------------------------------------------------------------------------------------------------
#if 0
M3Result m3_SetStackGlobalIndex (IM3Module io_module,
uint32_t i_index);
M3Result m3_StackAllocate (IM3Module io_module,
uint32_t * o_location,
const uint8_t * const i_bytes,
uint32_t i_size);
M3Result m3_PopStack (IM3Module io_module,
uint32_t i_size);
#endif
#if defined(__cplusplus)
}
#endif

@ -1,54 +1,2 @@
//
// m3_api_defs.h
//
// Created by Volodymyr Shymanskyy on 12/20/19.
// Copyright © 2019 Volodymyr Shymanskyy. All rights reserved.
//
#warning "Using m3_api_defs.h is deprecated. Just include wasm3.h"
#ifndef m3_api_defs_h
#define m3_api_defs_h
#include "m3_core.h"
// TODO: perform bounds checks
#define m3ApiOffsetToPtr(offset) (void*)((u8*)_mem + (u32)(offset))
#define m3ApiPtrToOffset(ptr) (u32)((u8*)ptr - (u8*)_mem)
#define m3ApiReturnType(TYPE) TYPE* raw_return = ((TYPE*) (_sp++));
#define m3ApiGetArg(TYPE, NAME) TYPE NAME = * ((TYPE *) (_sp++));
#define m3ApiGetArgMem(TYPE, NAME) TYPE NAME = (TYPE)m3ApiOffsetToPtr(* ((u32 *) (_sp++)));
# define m3ApiIsNullPtr(addr) ((void*)(addr) <= _mem)
#if d_m3SkipMemoryBoundsCheck
# define m3ApiCheckMem(off, len)
#else
# define m3ApiCheckMem(addr, len) { if (UNLIKELY(m3ApiIsNullPtr(addr) || ((u64)(addr) + (len)) > ((u64)(_mem)+runtime->memory.mallocated->length))) m3ApiTrap(m3Err_trapOutOfBoundsMemoryAccess); }
#endif
#define m3ApiRawFunction(NAME) const void * NAME (IM3Runtime runtime, IM3ImportContext _ctx, uint64_t * _sp, void * _mem)
#define m3ApiReturn(VALUE) { *raw_return = (VALUE); return m3Err_none; }
#define m3ApiTrap(VALUE) { return VALUE; }
#define m3ApiSuccess() { return m3Err_none; }
# if defined(M3_BIG_ENDIAN)
# define m3ApiReadMem8(ptr) (* (u8 *)(ptr))
# define m3ApiReadMem16(ptr) __builtin_bswap16((* (u16 *)(ptr)))
# define m3ApiReadMem32(ptr) __builtin_bswap32((* (u32 *)(ptr)))
# define m3ApiReadMem64(ptr) __builtin_bswap64((* (u64 *)(ptr)))
# define m3ApiWriteMem8(ptr, val) { * (u8 *)(ptr) = (val); }
# define m3ApiWriteMem16(ptr, val) { * (u16 *)(ptr) = __builtin_bswap16((val)); }
# define m3ApiWriteMem32(ptr, val) { * (u32 *)(ptr) = __builtin_bswap32((val)); }
# define m3ApiWriteMem64(ptr, val) { * (u64 *)(ptr) = __builtin_bswap64((val)); }
# else
# define m3ApiReadMem8(ptr) (* (u8 *)(ptr))
# define m3ApiReadMem16(ptr) (* (u16 *)(ptr))
# define m3ApiReadMem32(ptr) (* (u32 *)(ptr))
# define m3ApiReadMem64(ptr) (* (u64 *)(ptr))
# define m3ApiWriteMem8(ptr, val) { * (u8 *)(ptr) = (val); }
# define m3ApiWriteMem16(ptr, val) { * (u16 *)(ptr) = (val); }
# define m3ApiWriteMem32(ptr, val) { * (u32 *)(ptr) = (val); }
# define m3ApiWriteMem64(ptr, val) { * (u64 *)(ptr) = (val); }
# endif
#endif // m3_api_defs_h

@ -9,7 +9,6 @@
#include "m3_api_libc.h"
#include "m3_api_defs.h"
#include "m3_env.h"
#include "m3_exception.h"
@ -180,8 +179,11 @@ m3ApiRawFunction(m3_libc_printf)
m3ApiRawFunction(m3_libc_clock_ms)
{
m3ApiReturnType (uint32_t)
#ifdef CLOCKS_PER_SEC
m3ApiReturn(clock() / (CLOCKS_PER_SEC/1000));
#else
m3ApiReturn(clock());
#endif
}
static

@ -7,7 +7,6 @@
#include "m3_api_wasi.h"
#include "m3_api_defs.h"
#include "m3_env.h"
#include "m3_exception.h"
@ -212,7 +211,7 @@ m3ApiRawFunction(m3_wasi_unstable_fd_filestat_get)
m3ApiWriteMem64(buf+0, stat.st_dev);
m3ApiWriteMem64(buf+8, stat.st_ino);
m3ApiWriteMem8 (buf+16, stat.st_filetype);
m3ApiWriteMem64(buf+20, stat.st_nlink);
m3ApiWriteMem32(buf+20, stat.st_nlink);
m3ApiWriteMem64(buf+24, stat.st_size);
m3ApiWriteMem64(buf+32, stat.st_atim);
m3ApiWriteMem64(buf+40, stat.st_mtim);
@ -431,7 +430,7 @@ m3ApiRawFunction(m3_wasi_unstable_path_filestat_get)
m3ApiWriteMem64(buf+0, stat.st_dev);
m3ApiWriteMem64(buf+8, stat.st_ino);
m3ApiWriteMem8 (buf+16, stat.st_filetype);
m3ApiWriteMem64(buf+20, stat.st_nlink);
m3ApiWriteMem32(buf+20, stat.st_nlink);
m3ApiWriteMem64(buf+24, stat.st_size);
m3ApiWriteMem64(buf+32, stat.st_atim);
m3ApiWriteMem64(buf+40, stat.st_mtim);

@ -7,7 +7,6 @@
#include "m3_api_tracer.h"
#include "m3_api_defs.h"
#include "m3_env.h"
#include "m3_exception.h"

@ -9,7 +9,6 @@
#include "m3_api_wasi.h"
#include "m3_api_defs.h"
#include "m3_env.h"
#include "m3_exception.h"
@ -20,6 +19,10 @@
#include "uvwasi.h"
#ifndef d_m3EnableWasiTracing
# define d_m3EnableWasiTracing 0
#endif
#ifdef __APPLE__
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
@ -344,7 +347,7 @@ m3ApiRawFunction(m3_wasi_unstable_fd_filestat_get)
m3ApiWriteMem64(buf+0, stat.st_dev);
m3ApiWriteMem64(buf+8, stat.st_ino);
m3ApiWriteMem8 (buf+16, stat.st_filetype);
m3ApiWriteMem64(buf+20, stat.st_nlink);
m3ApiWriteMem32(buf+20, stat.st_nlink);
m3ApiWriteMem64(buf+24, stat.st_size);
m3ApiWriteMem64(buf+32, stat.st_atim);
m3ApiWriteMem64(buf+40, stat.st_mtim);
@ -518,6 +521,26 @@ m3ApiRawFunction(m3_wasi_generic_path_rename)
m3ApiReturn(ret);
}
m3ApiRawFunction(m3_wasi_generic_path_symlink)
{
m3ApiReturnType (uint32_t)
m3ApiGetArgMem (const char * , old_path)
m3ApiGetArg (uvwasi_size_t , old_path_len)
m3ApiGetArg (uvwasi_fd_t , fd)
m3ApiGetArgMem (const char * , new_path)
m3ApiGetArg (uvwasi_size_t , new_path_len)
m3ApiCheckMem(old_path, old_path_len);
m3ApiCheckMem(new_path, new_path_len);
uvwasi_errno_t ret = uvwasi_path_symlink(&uvwasi, old_path, old_path_len,
fd, new_path, new_path_len);
WASI_TRACE("old_fd:%d, old_path:%s, fd:%d, new_path:%s", old_fd, old_path, fd, new_path);
m3ApiReturn(ret);
}
m3ApiRawFunction(m3_wasi_generic_path_unlink_file)
{
m3ApiReturnType (uint32_t)
@ -596,7 +619,7 @@ m3ApiRawFunction(m3_wasi_unstable_path_filestat_get)
m3ApiWriteMem64(buf+0, stat.st_dev);
m3ApiWriteMem64(buf+8, stat.st_ino);
m3ApiWriteMem8 (buf+16, stat.st_filetype);
m3ApiWriteMem64(buf+20, stat.st_nlink);
m3ApiWriteMem32(buf+20, stat.st_nlink);
m3ApiWriteMem64(buf+24, stat.st_size);
m3ApiWriteMem64(buf+32, stat.st_atim);
m3ApiWriteMem64(buf+40, stat.st_mtim);
@ -990,7 +1013,7 @@ _ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_open",
_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_readlink", "i(i*i*i*)", &m3_wasi_generic_path_readlink)));
_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_remove_directory", "i(i*i)", &m3_wasi_generic_path_remove_directory)));
_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_rename", "i(i*ii*i)", &m3_wasi_generic_path_rename)));
//_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_symlink", "i(*ii*i)", )));
_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_symlink", "i(*ii*i)", &m3_wasi_generic_path_symlink)));
_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "path_unlink_file", "i(i*i)", &m3_wasi_generic_path_unlink_file)));
_ (SuppressLookupFailure (m3_LinkRawFunction (module, wasi, "poll_oneoff", "i(**i*)", &m3_wasi_generic_poll_oneoff)));

@ -9,7 +9,6 @@
#include "m3_api_wasi.h"
#include "m3_api_defs.h"
#include "m3_env.h"
#include "m3_exception.h"
@ -360,6 +359,12 @@ m3ApiRawFunction(m3_wasi_generic_fd_fdstat_get)
#endif // APE
fdstat->fs_rights_base = (uint64_t)-1; // all rights
// Make descriptors 0,1,2 look like a TTY
if (fd <= 2) {
fdstat->fs_rights_base &= ~(__WASI_RIGHTS_FD_SEEK | __WASI_RIGHTS_FD_TELL);
}
fdstat->fs_rights_inheriting = (uint64_t)-1; // all rights
m3ApiReturn(__WASI_ERRNO_SUCCESS);
#endif
@ -855,4 +860,20 @@ _catch:
return result;
}
M3Result m3_CloseWASI (IM3Module io_module)
{
M3Result result = m3Err_none;
#ifdef _WIN32
#else
for (int i = 3; i < PREOPEN_CNT; i++) {
close (preopen[i].fd);
preopen[i].fd = 0;
}
#endif
return result;
}
#endif // d_m3HasWASI

@ -20,6 +20,7 @@ typedef struct m3_wasi_context_t
} m3_wasi_context_t;
M3Result m3_LinkWASI (IM3Module io_module);
M3Result m3_CloseWASI (IM3Module i_module);
m3_wasi_context_t* m3_GetWasiContext();

@ -128,8 +128,9 @@ M3Result LinkRawFunction (IM3Module io_module, IM3Function io_function, ccstr
M3Result result = m3Err_none; d_m3Assert (io_module->runtime);
_try {
_ (ValidateSignature (io_function, signature));
if (signature) {
_ (ValidateSignature (io_function, signature));
}
IM3CodePage page = AcquireCodePageWithCapacity (io_module->runtime, 4);
if (page)

@ -114,6 +114,16 @@ void AlignSlotToType (u16 * io_slot, u8 i_type)
}
M3Result GetStackTopIndexChecked (IM3Compilation o, u16 * o_stackIndex)
{
M3Result result = m3Err_none;
_throwif (m3Err_functionStackUnderrun, o->stackIndex <= o->stackFirstDynamicIndex and not IsStackPolymorphic (o));
* o_stackIndex = o->stackIndex - 1;
_catch: return result;
}
i16 GetStackTopIndex (IM3Compilation o)
{ d_m3Assert (o->stackIndex > o->stackFirstDynamicIndex or IsStackPolymorphic (o));
return o->stackIndex - 1;
@ -292,7 +302,8 @@ M3Result AllocateSlots (IM3Compilation o, u16 * o_slot, u8 i_type)
M3Result AllocateConstantSlots (IM3Compilation o, u16 * o_slot, u8 i_type)
{
return AllocateSlotsWithinRange (o, o_slot, i_type, o->slotFirstConstIndex, o->slotFirstDynamicIndex);
u16 maxTableIndex = o->slotFirstConstIndex + d_m3MaxConstantTableSize;
return AllocateSlotsWithinRange (o, o_slot, i_type, o->slotFirstConstIndex, M3_MIN(o->slotFirstDynamicIndex, maxTableIndex));
}
@ -641,6 +652,8 @@ _ (PushAllocatedSlotAndEmit (o, i_type));
{
u16 constTableIndex = slot - o->slotFirstConstIndex;
d_m3Assert(constTableIndex < d_m3MaxConstantTableSize);
if (is64BitType)
{
u64 * constant = (u64 *) & o->constants [constTableIndex];
@ -767,8 +780,9 @@ M3Result CopyStackTopToSlot (IM3Compilation o, u16 i_destSlot) // NoPushPop
{
M3Result result;
i16 stackTop = GetStackTopIndex (o);
_ (CopyStackIndexToSlot (o, i_destSlot, (u16) stackTop));
u16 stackTop = 0;
_ (GetStackTopIndexChecked (o, & stackTop));
_ (CopyStackIndexToSlot (o, i_destSlot, stackTop));
_catch: return result;
}
@ -942,9 +956,9 @@ _ (CopyStackIndexToSlot (o, targetSlot, i_stackIndex));
o->wasmStack [i_stackIndex] = targetSlot;
}
_ (CopyStackSlotsR (o, i_targetSlotStackIndex + 1, i_stackIndex + 1, i_endStackIndex, i_tempSlot));
// restore the stack state
o->wasmStack [i_stackIndex] = srcSlot;
o->wasmStack [preserveIndex] = collisionSlot;
@ -992,9 +1006,9 @@ _ (CopyStackTopToRegister (o, false));
// TODO: tempslot affects maxStackSlots, so can grow unnecess each time.
u16 tempSlot = o->maxStackSlots;// GetMaxUsedSlotPlusOne (o); doesn't work cause can collide with slotRecords
AlignSlotToType (& tempSlot, c_m3Type_i64);
_ (CopyStackSlotsR (o, slotRecords, endIndex - numValues, endIndex, tempSlot));
if (d_m3LogWasmStack) dump_type_stack (o);
}
@ -1114,17 +1128,17 @@ _ (Read_u8 (& opcode, & o->wasm, o->wasmEnd)); m3log (compile, d_i
//printf("Extended opcode: 0x%x\n", i_opcode);
const M3OpInfo* opinfo = GetOpInfo (i_opcode);
_throwif (m3Err_unknownOpcode, not opinfo);
IM3OpInfo opInfo = GetOpInfo (i_opcode);
_throwif (m3Err_unknownOpcode, not opInfo);
M3Compiler compiler = opinfo->compiler;
M3Compiler compiler = opInfo->compiler;
_throwif (m3Err_noCompiler, not compiler);
_ ((* compiler) (o, i_opcode));
o->previousOpcode = i_opcode;
} _catch: return result;
} _catch: return result;
}
#endif
@ -1468,7 +1482,7 @@ _ (GetBlockScope (o, & scope, target));
// TODO: don't need codepage rigmarole for
// no-param forward-branch targets
_ (AcquireCompilationCodePage (o, & continueOpPage));
pc_t startPC = GetPagePC (continueOpPage);
@ -1681,10 +1695,10 @@ _ (PushRegister (o, c_m3Type_i32));
M3Result Compile_Memory_CopyFill (IM3Compilation o, m3opcode_t i_opcode)
{
M3Result result = m3Err_none;
i8 reserved;
_ (ReadLEB_i7 (& reserved, & o->wasm, o->wasmEnd));
IM3Operation op;
if (i_opcode == c_waOp_memoryCopy)
{
@ -1694,12 +1708,12 @@ _ (ReadLEB_i7 (& reserved, & o->wasm, o->wasmEnd));
else op = op_MemFill;
_ (CopyStackTopToRegister (o, false));
_ (EmitOp (o, op));
_ (PopType (o, c_m3Type_i32));
_ (EmitSlotNumOfStackTopAndPop (o));
_ (EmitSlotNumOfStackTopAndPop (o));
_catch: return result;
}
@ -2009,9 +2023,10 @@ M3Result Compile_Operator (IM3Compilation o, m3opcode_t i_opcode)
{
M3Result result;
const M3OpInfo * op = GetOpInfo(i_opcode);
IM3OpInfo opInfo = GetOpInfo (i_opcode);
_throwif (m3Err_unknownOpcode, not opInfo);
IM3Operation operation;
IM3Operation op;
// This preserve is for for FP compare operations.
// either need additional slot destination operations or the
@ -2019,64 +2034,64 @@ M3Result Compile_Operator (IM3Compilation o, m3opcode_t i_opcode)
// moving out the way might be the optimal solution most often?
// otherwise, the _r0 reg can get buried down in the stack
// and be idle & wasted for a moment.
if (IsFpType (GetStackTopType (o)) and IsIntType (op->type))
if (IsFpType (GetStackTopType (o)) and IsIntType (opInfo->type))
{
_ (PreserveRegisterIfOccupied (o, op->type));
_ (PreserveRegisterIfOccupied (o, opInfo->type));
}
if (op->stackOffset == 0)
if (opInfo->stackOffset == 0)
{
if (IsStackTopInRegister (o))
{
operation = op->operations [0]; // _s
op = opInfo->operations [0]; // _s
}
else
{
_ (PreserveRegisterIfOccupied (o, op->type));
operation = op->operations [1]; // _r
_ (PreserveRegisterIfOccupied (o, opInfo->type));
op = opInfo->operations [1]; // _r
}
}
else
{
if (IsStackTopInRegister (o))
{
operation = op->operations [0]; // _rs
op = opInfo->operations [0]; // _rs
if (IsStackTopMinus1InRegister (o))
{ d_m3Assert (i_opcode == 0x38 or i_opcode == 0x39);
operation = op->operations [3]; // _rr for fp.store
op = opInfo->operations [3]; // _rr for fp.store
}
}
else if (IsStackTopMinus1InRegister (o))
{
operation = op->operations [1]; // _sr
op = opInfo->operations [1]; // _sr
if (not operation) // must be commutative, then
operation = op->operations [0];
if (not op) // must be commutative, then
op = opInfo->operations [0];
}
else
{
_ (PreserveRegisterIfOccupied (o, op->type)); // _ss
operation = op->operations [2];
_ (PreserveRegisterIfOccupied (o, opInfo->type)); // _ss
op = opInfo->operations [2];
}
}
if (operation)
if (op)
{
_ (EmitOp (o, operation));
_ (EmitOp (o, op));
_ (EmitSlotNumOfStackTopAndPop (o));
if (op->stackOffset < 0)
if (opInfo->stackOffset < 0)
_ (EmitSlotNumOfStackTopAndPop (o));
if (op->type != c_m3Type_none)
_ (PushRegister (o, op->type));
if (opInfo->type != c_m3Type_none)
_ (PushRegister (o, opInfo->type));
}
else
{
# ifdef DEBUG
result = ErrorCompile ("no operation found for opcode", o, "'%s'", op->name);
result = ErrorCompile ("no operation found for opcode", o, "'%s'", opInfo->name);
# else
result = ErrorCompile ("no operation found for opcode", o, "%x", i_opcode);
# endif
@ -2091,7 +2106,8 @@ M3Result Compile_Convert (IM3Compilation o, m3opcode_t i_opcode)
{
M3Result result = m3Err_none;
const M3OpInfo * opInfo = GetOpInfo(i_opcode);
IM3OpInfo opInfo = GetOpInfo (i_opcode);
_throwif (m3Err_unknownOpcode, not opInfo);
bool destInSlot = IsRegisterTypeAllocated (o, opInfo->type);
bool sourceInSlot = IsStackTopInSlot (o);
@ -2120,9 +2136,10 @@ _try {
_ (ReadLEB_u32 (& alignHint, & o->wasm, o->wasmEnd));
_ (ReadLEB_u32 (& memoryOffset, & o->wasm, o->wasmEnd));
m3log (compile, d_indent " (offset = %d)", get_indention_string (o), memoryOffset);
const M3OpInfo * op = GetOpInfo(i_opcode);
IM3OpInfo opInfo = GetOpInfo (i_opcode);
_throwif (m3Err_unknownOpcode, not opInfo);
if (IsFpType (op->type))
if (IsFpType (opInfo->type))
_ (PreserveRegisterIfOccupied (o, c_m3Type_f64));
_ (Compile_Operator (o, i_opcode));
@ -2406,7 +2423,7 @@ const M3OpInfo c_operations [] =
d_m3DebugOp (MemFill),
d_m3DebugOp (MemCopy),
#endif
[0xFC] = M3OP( "0xFC", 0, c_m3Type_unknown, d_emptyOpList, Compile_ExtendedOpcode ),
# endif
@ -2427,7 +2444,7 @@ const M3OpInfo c_operationsFC [] =
M3OP_F( "i64.trunc_u:sat/f64",0, i_64, d_convertOpList (u64_TruncSat_f64), Compile_Convert ), // 0x07
M3OP_RESERVED, M3OP_RESERVED,
M3OP( "memory.copy", 0, none, d_emptyOpList, Compile_Memory_CopyFill ), // 0x0a
M3OP( "memory.fill", 0, none, d_emptyOpList, Compile_Memory_CopyFill ), // 0x0b
@ -2437,7 +2454,8 @@ const M3OpInfo c_operationsFC [] =
# endif
};
const M3OpInfo* GetOpInfo (m3opcode_t opcode)
IM3OpInfo GetOpInfo (m3opcode_t opcode)
{
switch (opcode >> 8) {
case 0x00:
@ -2478,8 +2496,8 @@ _ (Read_opcode (& opcode, & o->wasm, o->wasmEnd)); log_opco
}
}
IM3OpInfo opinfo = GetOpInfo(opcode);
IM3OpInfo opinfo = GetOpInfo (opcode);
if (opinfo == NULL)
_throw (ErrorCompile (m3Err_unknownOpcode, o, "opcode '%x' not available", opcode));
@ -2649,6 +2667,8 @@ M3Result CompileLocals (IM3Compilation o)
u32 numLocalBlocks;
_ (ReadLEB_u32 (& numLocalBlocks, & o->wasm, o->wasmEnd));
u32 numLocals = 0;
for (u32 l = 0; l < numLocalBlocks; ++l)
{
u32 varCount;
@ -2658,11 +2678,14 @@ _ (ReadLEB_u32 (& numLocalBlocks, & o->wasm, o->wasmEnd));
_ (ReadLEB_u32 (& varCount, & o->wasm, o->wasmEnd));
_ (ReadLEB_i7 (& waType, & o->wasm, o->wasmEnd));
_ (NormalizeType (& localType, waType));
m3log (compile, "pushing locals. count: %d; type: %s", varCount, c_waTypes [localType]);
numLocals += varCount; m3log (compile, "pushing locals. count: %d; type: %s", varCount, c_waTypes [localType]);
while (varCount--)
_ (PushAllocatedSlot (o, localType));
}
if (o->function)
o->function->numLocals = numLocals;
_catch: return result;
}

@ -35,7 +35,7 @@ enum
c_waOp_i64_const = 0x42,
c_waOp_f32_const = 0x43,
c_waOp_f64_const = 0x44,
c_waOp_memoryCopy = 0xfc0a,
c_waOp_memoryFill = 0xfc0b
};
@ -140,7 +140,7 @@ M3OpInfo;
typedef const M3OpInfo * IM3OpInfo;
extern const M3OpInfo* GetOpInfo(m3opcode_t opcode);
IM3OpInfo GetOpInfo (m3opcode_t opcode);
// TODO: This helper should be removed, when MultiValue is implemented
static inline

@ -73,6 +73,9 @@
# define d_m3EnableExceptionBreakpoint 0 // see m3_exception.h
# endif
# ifndef d_m3EnableExtensions
# define d_m3EnableExtensions 1 // enables the specialized APIs in wasm3_ext.h
# endif
// profiling and tracing ------------------------------------------------------

@ -8,201 +8,22 @@
#ifndef m3_config_platforms_h
#define m3_config_platforms_h
#include "wasm3_defs.h"
/*
* Helpers
* Internal helpers
*/
#define M3_STR__(x) #x
#define M3_STR(x) M3_STR__(x)
#define M3_CONCAT__(a,b) a##b
#define M3_CONCAT(a,b) M3_CONCAT__(a,b)
# if !defined(__cplusplus) || defined(_MSC_VER)
# define not !
# define and &&
# define or ||
# endif
/*
* Detect platform
*/
# if defined(__clang__)
# define M3_COMPILER_CLANG 1
# elif defined(__INTEL_COMPILER)
# define M3_COMPILER_ICC 1
# elif defined(__GNUC__) || defined(__GNUG__)
# define M3_COMPILER_GCC 1
# elif defined(_MSC_VER)
# define M3_COMPILER_MSVC 1
# else
# warning "Compiler not detected"
# endif
# if defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_GCC)
# if defined(__wasm__)
# define M3_ARCH "wasm"
# elif defined(__x86_64__)
# define M3_ARCH "x86_64"
# elif defined(__i386__)
# define M3_ARCH "i386"
# elif defined(__aarch64__)
# define M3_ARCH "arm64-v8a"
# elif defined(__arm__)
# if defined(__ARM_ARCH_7A__)
# if defined(__ARM_NEON__)
# if defined(__ARM_PCS_VFP)
# define M3_ARCH "arm-v7a/NEON hard-float"
# else
# define M3_ARCH "arm-v7a/NEON"
# endif
# else
# if defined(__ARM_PCS_VFP)
# define M3_ARCH "arm-v7a hard-float"
# else
# define M3_ARCH "arm-v7a"
# endif
# endif
# else
# define M3_ARCH "arm"
# endif
# elif defined(__riscv)
# if defined(__riscv_32e)
# define _M3_ARCH_RV "rv32e"
# elif __riscv_xlen == 128
# define _M3_ARCH_RV "rv128i"
# elif __riscv_xlen == 64
# define _M3_ARCH_RV "rv64i"
# elif __riscv_xlen == 32
# define _M3_ARCH_RV "rv32i"
# endif
# if defined(__riscv_muldiv)
# define _M3_ARCH_RV_M _M3_ARCH_RV "m"
# else
# define _M3_ARCH_RV_M _M3_ARCH_RV
# endif
# if defined(__riscv_atomic)
# define _M3_ARCH_RV_A _M3_ARCH_RV_M "a"
# else
# define _M3_ARCH_RV_A _M3_ARCH_RV_M
# endif
# if defined(__riscv_flen)
# define _M3_ARCH_RV_F _M3_ARCH_RV_A "f"
# else
# define _M3_ARCH_RV_F _M3_ARCH_RV_A
# endif
# if defined(__riscv_flen) && __riscv_flen >= 64
# define _M3_ARCH_RV_D _M3_ARCH_RV_F "d"
# else
# define _M3_ARCH_RV_D _M3_ARCH_RV_F
# endif
# if defined(__riscv_compressed)
# define _M3_ARCH_RV_C _M3_ARCH_RV_D "c"
# else
# define _M3_ARCH_RV_C _M3_ARCH_RV_D
# endif
# define M3_ARCH _M3_ARCH_RV_C
# elif defined(__mips__)
# if defined(__MIPSEB__) && defined(__mips64)
# define M3_ARCH "mips64 " _MIPS_ARCH
# elif defined(__MIPSEL__) && defined(__mips64)
# define M3_ARCH "mips64el " _MIPS_ARCH
# elif defined(__MIPSEB__)
# define M3_ARCH "mips " _MIPS_ARCH
# elif defined(__MIPSEL__)
# define M3_ARCH "mipsel " _MIPS_ARCH
# endif
# elif defined(__PPC__)
# if defined(__PPC64__) && defined(__LITTLE_ENDIAN__)
# define M3_ARCH "ppc64le"
# elif defined(__PPC64__)
# define M3_ARCH "ppc64"
# else
# define M3_ARCH "ppc"
# endif
# elif defined(__sparc__)
# if defined(__arch64__)
# define M3_ARCH "sparc64"
# else
# define M3_ARCH "sparc"
# endif
# elif defined(__s390x__)
# define M3_ARCH "s390x"
# elif defined(__alpha__)
# define M3_ARCH "alpha"
# elif defined(__m68k__)
# define M3_ARCH "m68k"
# elif defined(__xtensa__)
# define M3_ARCH "xtensa"
# elif defined(__arc__)
# define M3_ARCH "arc32"
# elif defined(__AVR__)
# define M3_ARCH "avr"
# endif
# endif
# if defined(M3_COMPILER_MSVC)
# if defined(_M_X64)
# define M3_ARCH "x86_64"
# elif defined(_M_IX86)
# define M3_ARCH "i386"
# elif defined(_M_ARM64)
# define M3_ARCH "arm64"
# elif defined(_M_ARM)
# define M3_ARCH "arm"
# endif
# endif
# if !defined(M3_ARCH)
# warning "Architecture not detected"
# define M3_ARCH "unknown"
# endif
# if defined(M3_COMPILER_CLANG)
# if defined(WIN32)
# define M3_COMPILER_VER __VERSION__ " for Windows"
# else
# define M3_COMPILER_VER __VERSION__
# endif
# elif defined(M3_COMPILER_GCC)
# define M3_COMPILER_VER "GCC " __VERSION__
# elif defined(M3_COMPILER_MSVC)
# define M3_COMPILER_VER "MSVC " M3_STR(_MSC_VER)
# else
# define M3_COMPILER_VER "unknown"
# endif
/*
* Detect/define features
*/
# ifdef __has_feature
# define M3_COMPILER_HAS_FEATURE(x) __has_feature(x)
# else
# define M3_COMPILER_HAS_FEATURE(x) 0
# endif
# ifdef __has_builtin
# define M3_COMPILER_HAS_BUILTIN(x) __has_builtin(x)
# else
# define M3_COMPILER_HAS_BUILTIN(x) 0
# endif
# if defined(M3_COMPILER_MSVC)
# include <stdint.h>
# if UINTPTR_MAX == 0xFFFFFFFF
@ -218,64 +39,6 @@
# error "Pointer size not detected"
# endif
# if defined(M3_COMPILER_MSVC)
# define M3_LITTLE_ENDIAN //_byteswap_ushort, _byteswap_ulong, _byteswap_uint64
# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define M3_LITTLE_ENDIAN
# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define M3_BIG_ENDIAN
# else
# error "Byte order not detected"
# endif
// Byte swapping (for Big-Endian systems only)
# if defined(M3_COMPILER_MSVC)
# define m3_bswap16(x) _byteswap_ushort((x))
# define m3_bswap32(x) _byteswap_ulong((x))
# define m3_bswap64(x) _byteswap_uint64((x))
# elif defined(M3_COMPILER_GCC) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
// __builtin_bswap32/64 added in gcc 4.3, __builtin_bswap16 added in gcc 4.8
# define m3_bswap16(x) __builtin_bswap16((x))
# define m3_bswap32(x) __builtin_bswap32((x))
# define m3_bswap64(x) __builtin_bswap64((x))
# elif defined(M3_COMPILER_CLANG) && M3_COMPILER_HAS_BUILTIN(__builtin_bswap16)
# define m3_bswap16(x) __builtin_bswap16((x))
# define m3_bswap32(x) __builtin_bswap32((x))
# define m3_bswap64(x) __builtin_bswap64((x))
# else
# include <endian.h>
# if defined(__bswap_16)
# define m3_bswap16(x) __bswap_16((x))
# define m3_bswap32(x) __bswap_32((x))
# define m3_bswap64(x) __bswap_64((x))
# else
# warning "Using naive (probably slow) bswap operations"
static inline
uint16_t m3_bswap16(uint16_t x) {
return ((( x >> 8 ) & 0xffu ) | (( x & 0xffu ) << 8 ));
}
static inline
uint32_t m3_bswap32(uint32_t x) {
return ((( x & 0xff000000u ) >> 24 ) |
(( x & 0x00ff0000u ) >> 8 ) |
(( x & 0x0000ff00u ) << 8 ) |
(( x & 0x000000ffu ) << 24 ));
}
static inline
uint64_t m3_bswap64(uint64_t x) {
return ((( x & 0xff00000000000000ull ) >> 56 ) |
(( x & 0x00ff000000000000ull ) >> 40 ) |
(( x & 0x0000ff0000000000ull ) >> 24 ) |
(( x & 0x000000ff00000000ull ) >> 8 ) |
(( x & 0x00000000ff000000ull ) << 8 ) |
(( x & 0x0000000000ff0000ull ) << 24 ) |
(( x & 0x000000000000ff00ull ) << 40 ) |
(( x & 0x00000000000000ffull ) << 56 ));
}
# endif
# endif
# if defined(M3_BIG_ENDIAN)
# define M3_BSWAP_u8(X) {}
# define M3_BSWAP_u16(X) { (X)=m3_bswap16((X)); }
@ -300,21 +63,15 @@
# define M3_BSWAP_f64(X) {}
# endif
# if defined(M3_COMPILER_GCC) || defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_ICC)
# 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 defined(M3_COMPILER_MSVC)
# define M3_WEAK //__declspec(selectany)
# define M3_NO_UBSAN
# elif defined(__MINGW32__)
# define M3_WEAK //__attribute__((selectany))
# define M3_NO_UBSAN
# else
# define M3_WEAK __attribute__((weak))
# define M3_WEAK __attribute__((weak))
# define M3_NO_UBSAN //__attribute__((no_sanitize("undefined")))
# endif
# ifndef M3_MIN
@ -409,6 +166,9 @@ typedef int8_t i8;
# ifndef d_m3VerboseErrorMessages
# define d_m3VerboseErrorMessages 0
# endif
# ifndef d_m3MaxConstantTableSize
# define d_m3MaxConstantTableSize 64
# endif
# ifndef d_m3MaxFunctionStackHeight
# define d_m3MaxFunctionStackHeight 64
# endif
@ -417,4 +177,13 @@ typedef int8_t i8;
# endif
# endif
/*
* Arch-specific defaults
*/
#if defined(__riscv) && __riscv_xlen == 64
# ifndef d_m3Use32BitSlots
# define d_m3Use32BitSlots 0
# endif
#endif
#endif // m3_config_platforms_h

@ -245,7 +245,7 @@ M3Result ReadLEB_i64 (i64 * o_value, bytes_t * io_bytes, cbytes_t
M3Result Read_utf8 (cstr_t * o_utf8, bytes_t * io_bytes, cbytes_t i_end);
cstr_t SPrintValue (void * i_value, u8 i_type);
size_t SPrintArg (char * o_string, size_t i_stringBufferSize, m3stack_t i_sp, u8 i_type);
size_t SPrintArg (char * o_string, size_t i_stringBufferSize, voidptr_t i_sp, u8 i_type);
void ReportError (IM3Runtime io_runtime, IM3Module i_module, IM3Function i_function, ccstr_t i_errorMessage, ccstr_t i_file, u32 i_lineNum);

@ -107,6 +107,7 @@ void Environment_AddFuncType (IM3Environment i_environment, IM3FuncType * io_f
* io_funcType = newType;
}
IM3CodePage RemoveCodePageOfCapacity (M3CodePage ** io_list, u32 i_minimumLineCount)
{
IM3CodePage prev = NULL;
@ -189,11 +190,28 @@ IM3Runtime m3_NewRuntime (IM3Environment i_environment, u32 i_stackSizeInBytes
return runtime;
}
u64 * m3_GetStack (IM3Runtime i_runtime)
{
return (i_runtime) ? (u64 *) i_runtime->stack : NULL;
}
void m3_RebaseStack (IM3Runtime i_runtime, u64 * i_newStackBase)
{
if (i_runtime and i_newStackBase)
{
i_runtime->stack = i_newStackBase;
}
}
void * m3_GetUserData (IM3Runtime i_runtime)
{
return i_runtime ? i_runtime->userdata : NULL;
}
void * ForEachModule (IM3Runtime i_runtime, ModuleVisitor i_visitor, void * i_info)
{
void * r = NULL;
@ -286,6 +304,7 @@ M3Result EvaluateExpression (IM3Module i_module, void * o_expressed, u8 i_type
pc_t m3code = GetPagePC (o->page);
result = CompileBlock (o, ftype, c_waOp_block);
// FIX: this compare doesn't make sense
if (not result && o->maxStackSlots >= runtime.numStackSlots) {
result = m3Err_trapStackOverflow;
}
@ -444,6 +463,8 @@ M3Result InitDataSegments (M3Memory * io_memory, IM3Module io_module)
{
M3Result result = m3Err_none;
_throwif ("unallocated linear memory", !(io_memory->mallocated));
for (u32 i = 0; i < io_module->numDataSegments; ++i)
{
M3DataSegment * segment = & io_module->dataSegments [i];
@ -454,12 +475,11 @@ _ (EvaluateExpression (io_module, & segmentOffset, c_m3Type_i32, & start,
m3log (runtime, "loading data segment: %d; size: %d; offset: %d", i, segment->size, segmentOffset);
_throwif ("unallocated linear memory", !(io_memory->mallocated));
if (segmentOffset >= 0 && (size_t)(segmentOffset) + segment->size <= io_memory->mallocated->length)
{
u8 * dest = m3MemData (io_memory->mallocated) + segmentOffset;
memcpy (dest, segment->data, segment->size);
segment->offset = -segmentOffset; // save for m3_GetDataSegmentOffset, negated for validation
} else {
_throw ("data segment out of bounds");
}
@ -490,14 +510,18 @@ _ (EvaluateExpression (io_module, & offset, c_m3Type_i32, & bytes, end
u32 numElements;
_ (ReadLEB_u32 (& numElements, & bytes, end));
size_t endElement = (size_t)(numElements) + offset;
size_t endElement = (size_t) numElements + offset;
_throwif ("table overflow", endElement > d_m3MaxSaneTableSize);
io_module->table0 = m3_ReallocArray (IM3Function, io_module->table0, endElement, io_module->table0Size);
// is there any requirement that elements must be in increasing sequence?
// make sure the table isn't shrunk.
if (endElement > io_module->table0Size)
{
io_module->table0 = m3_ReallocArray (IM3Function, io_module->table0, endElement, io_module->table0Size);
io_module->table0Size = (u32) endElement;
}
_throwifnull(io_module->table0);
io_module->table0Size = (u32) endElement;
for (u32 e = 0; e < numElements; ++e)
{
u32 functionIndex;
@ -513,6 +537,22 @@ _ (ReadLEB_u32 (& functionIndex, & bytes, end));
_catch: return result;
}
M3Result m3_CompileModule (IM3Module io_module)
{
M3Result result = m3Err_none;
for (u32 i = 0; i < io_module->numFunctions; ++i)
{
IM3Function f = & io_module->functions [i];
if (f->wasm and not f->compiled)
{
_ (CompileFunction (f));
}
}
_catch: return result;
}
M3Result m3_RunStart (IM3Module io_module)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
@ -779,6 +819,16 @@ M3Result m3_CallV (IM3Function i_function, ...)
return r;
}
static
void ReportNativeStackUsage ()
{
# if d_m3LogNativeStack
int stackUsed = m3StackGetMax();
fprintf (stderr, "Native stack used: %d\n", stackUsed);
# endif
}
M3Result m3_CallVL (IM3Function i_function, va_list i_args)
{
IM3Runtime runtime = i_function->module->runtime;
@ -808,14 +858,10 @@ M3Result m3_CallVL (IM3Function i_function, va_list i_args)
}
m3StackCheckInit();
M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs);
ReportNativeStackUsage ();
runtime->lastCalled = r ? NULL : i_function;
#if d_m3LogNativeStack
int stackUsed = m3StackGetMax();
fprintf (stderr, "Native stack used: %d\n", stackUsed);
#endif
return r;
}
@ -852,13 +898,10 @@ M3Result m3_Call (IM3Function i_function, uint32_t i_argc, const void * i_argp
m3StackCheckInit();
M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs);
ReportNativeStackUsage ();
runtime->lastCalled = r ? NULL : i_function;
#if d_m3LogNativeStack
int stackUsed = m3StackGetMax();
fprintf (stderr, "Native stack used: %d\n", stackUsed);
#endif
return r;
}
@ -887,7 +930,7 @@ M3Result m3_CallArgv (IM3Function i_function, uint32_t i_argc, const char * i_
case c_m3Type_i32: *(i32*)(s) = strtoul(i_argv[i], NULL, 10); s += 8; break;
case c_m3Type_i64: *(i64*)(s) = strtoull(i_argv[i], NULL, 10); s += 8; break;
# if d_m3HasFloat
case c_m3Type_f32: *(f32*)(s) = strtod(i_argv[i], NULL); s += 8; break; // strtof would be less portable
case c_m3Type_f32: *(f32*)(s) = strtod(i_argv[i], NULL); s += 8; break; // strtof would be less portable
case c_m3Type_f64: *(f64*)(s) = strtod(i_argv[i], NULL); s += 8; break;
# endif
default: return "unknown argument type";
@ -896,18 +939,28 @@ M3Result m3_CallArgv (IM3Function i_function, uint32_t i_argc, const char * i_
m3StackCheckInit();
M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs);
ReportNativeStackUsage ();
runtime->lastCalled = r ? NULL : i_function;
#if d_m3LogNativeStack
int stackUsed = m3StackGetMax();
fprintf (stderr, "Native stack used: %d\n", stackUsed);
#endif
return r;
}
M3Result m3_CallDirect (IM3Function i_function)
{
IM3Runtime runtime = i_function->module->runtime;
m3StackCheckInit();
M3Result result = (M3Result) Call (i_function->compiled, (m3stack_t) (runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs);
ReportNativeStackUsage ();
runtime->lastCalled = result ? NULL : i_function;
return result;
}
//u8 * AlignStackPointerTo64Bits (const u8 * i_stack)
//{
// uintptr_t ptr = (uintptr_t) i_stack;
@ -937,7 +990,7 @@ M3Result m3_GetResults (IM3Function i_function, uint32_t i_retc, const void *
# if d_m3HasFloat
case c_m3Type_f32: *(f32*)o_retptrs[i] = *(f32*)(s); s += 8; break;
case c_m3Type_f64: *(f64*)o_retptrs[i] = *(f64*)(s); s += 8; break;
# endif
# endif
default: return "unknown return type";
}
}
@ -1090,8 +1143,7 @@ void m3_ResetErrorInfo (IM3Runtime i_runtime)
uint8_t * m3_GetMemory (IM3Runtime i_runtime, uint32_t * o_memorySizeInBytes, uint32_t i_memoryIndex)
{
uint8_t * memory = NULL;
d_m3Assert (i_memoryIndex == 0);
uint8_t * memory = NULL; d_m3Assert (i_memoryIndex == 0);
if (i_runtime)
{
@ -1107,6 +1159,29 @@ uint8_t * m3_GetMemory (IM3Runtime i_runtime, uint32_t * o_memorySizeInBytes,
return memory;
}
uint32_t m3_GetMemorySize (IM3Runtime i_runtime)
{
return i_runtime->memory.mallocated->length;
}
uint8_t * m3_GetMemoryAtOffset (IM3Runtime i_runtime, uint64_t i_offset, uint32_t i_size, uint32_t i_memoryIndex)
{
uint8_t * memory = NULL; d_m3Assert (i_memoryIndex == 0);
if (i_runtime)
{
if (i_offset + i_size <= i_runtime->memory.mallocated->length)
{
memory = m3MemData (i_runtime->memory.mallocated) + i_offset;
}
}
return memory;
}
M3BacktraceInfo * m3_GetBacktrace (IM3Runtime i_runtime)
{
# if d_m3RecordBacktraces

@ -41,10 +41,14 @@ typedef M3Memory * IM3Memory;
typedef struct M3DataSegment
{
const u8 * initExpr; // wasm code
const u8 * initExpr; // wasm code
const u8 * data;
u32 initExprSize;
union
{
u32 initExprSize; // after the segment is processed,
i32 offset; // it's offset is written here
};
u32 memoryRegion;
u32 size;
}
@ -93,6 +97,10 @@ typedef struct M3Module
u32 numFunctions;
M3Function * functions;
# if d_m3EnableExtensions
u32 numReservedFunctions;
# endif
i32 startFunction;
u32 numDataSegments;
@ -112,12 +120,14 @@ typedef struct M3Module
M3MemoryInfo memoryInfo;
bool memoryImported;
//bool hasWasmCodeCopy;
bool hasWasmCodeCopy;
struct M3Module * next;
}
M3Module;
IM3Module m3_NewModule (IM3Environment i_environment);
M3Result Module_AddGlobal (IM3Module io_module, IM3Global * o_global, u8 i_type, bool i_mutable, bool i_isImported);
M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportInfo i_importInfo /* can be null */);
@ -163,7 +173,7 @@ typedef struct M3Runtime
IM3Module modules; // linked list of imported modules
void * stack;
u32 stackSize;
// u32 stackSize;
u32 numStackSlots;
IM3Function lastCalled; // last function that successfully executed

@ -83,8 +83,8 @@ d_m3BeginExternC
#endif
#if d_m3EnableStrace >= 3
#define d_m3TraceLoad(TYPE,offset,val) d_m3TracePrint("load." #TYPE " 0x%x = %" PRI##TYPE, offset, val)
#define d_m3TraceStore(TYPE,offset,val) d_m3TracePrint("store." #TYPE " 0x%x , %" PRI##TYPE, offset, val)
#define d_m3TraceLoad(TYPE,offset,val) d_m3TracePrint("load." #TYPE " %d 0x%x = %" PRI##TYPE, offset, offset, val)
#define d_m3TraceStore(TYPE,offset,val) d_m3TracePrint("store." #TYPE " %d 0x%x , %" PRI##TYPE, offset, offset, val)
#else
#define d_m3TraceLoad(TYPE,offset,val)
#define d_m3TraceStore(TYPE,offset,val)
@ -707,7 +707,7 @@ d_m3Op (MemCopy)
u32 size = (u32) _r0;
u64 source = slot (u32);
u64 destination = slot (u32);
if (destination + size <= _mem->length)
{
if (source + size <= _mem->length)
@ -715,7 +715,7 @@ d_m3Op (MemCopy)
u8 * dst = m3MemData (_mem) + destination;
u8 * src = m3MemData (_mem) + source;
memmove (dst, src, size);
nextOp ();
}
else d_outOfBoundsMemOp (source, size);
@ -729,7 +729,7 @@ d_m3Op (MemFill)
u32 size = (u32) _r0;
u32 byte = slot (u32);
u64 destination = slot (u32);
if (destination + size <= _mem->length)
{
u8 * mem8 = m3MemData (_mem) + destination;
@ -781,7 +781,7 @@ d_m3Op (Entry)
#if d_m3SkipStackCheck
if (true)
#else
if (LIKELY((void *)((m3slot_t *) _sp + function->maxStackSlots) < _mem->maxStack))
if (LIKELY ((void *) (_sp + function->maxStackSlots) < _mem->maxStack))
#endif
{
#if defined(DEBUG)
@ -798,7 +798,7 @@ d_m3Op (Entry)
}
#if d_m3EnableStrace >= 2
d_m3TracePrint("%s %s {", m3_GetFunctionName(function), SPrintFunctionArgList (function, _sp));
d_m3TracePrint("%s %s {", m3_GetFunctionName(function), SPrintFunctionArgList (function, _sp + function->numRetSlots));
trace_rt->callDepth++;
#endif

@ -12,30 +12,30 @@
d_m3BeginExternC
# define m3MemData(mem) (u8*)(((M3MemoryHeader*)(mem))+1)
# define m3MemRuntime(mem) (((M3MemoryHeader*)(mem))->runtime)
# define m3MemInfo(mem) (&(((M3MemoryHeader*)(mem))->runtime->memory))
# define d_m3BaseOpSig pc_t _pc, m3stack_t _sp, M3MemoryHeader * _mem, m3reg_t _r0
# define d_m3BaseOpArgs _sp, _mem, _r0
# define d_m3BaseOpAllArgs _pc, _sp, _mem, _r0
# define d_m3BaseOpDefaultArgs 0
# define d_m3BaseClearRegisters _r0 = 0;
# define d_m3ExpOpSig(...) d_m3BaseOpSig, __VA_ARGS__
# define d_m3ExpOpArgs(...) d_m3BaseOpArgs, __VA_ARGS__
# define d_m3ExpOpAllArgs(...) d_m3BaseOpAllArgs, __VA_ARGS__
# define d_m3ExpOpDefaultArgs(...) d_m3BaseOpDefaultArgs, __VA_ARGS__
# define d_m3ExpClearRegisters(...) d_m3BaseClearRegisters; __VA_ARGS__
# define m3MemData(mem) (u8*)(((M3MemoryHeader*)(mem))+1)
# define m3MemRuntime(mem) (((M3MemoryHeader*)(mem))->runtime)
# define m3MemInfo(mem) (&(((M3MemoryHeader*)(mem))->runtime->memory))
# define d_m3BaseOpSig pc_t _pc, m3stack_t _sp, M3MemoryHeader * _mem, m3reg_t _r0
# define d_m3BaseOpArgs _sp, _mem, _r0
# define d_m3BaseOpAllArgs _pc, _sp, _mem, _r0
# define d_m3BaseOpDefaultArgs 0
# define d_m3BaseClearRegisters _r0 = 0;
# define d_m3ExpOpSig(...) d_m3BaseOpSig, __VA_ARGS__
# define d_m3ExpOpArgs(...) d_m3BaseOpArgs, __VA_ARGS__
# define d_m3ExpOpAllArgs(...) d_m3BaseOpAllArgs, __VA_ARGS__
# define d_m3ExpOpDefaultArgs(...) d_m3BaseOpDefaultArgs, __VA_ARGS__
# define d_m3ExpClearRegisters(...) d_m3BaseClearRegisters; __VA_ARGS__
# if d_m3HasFloat
# define d_m3OpSig d_m3ExpOpSig (f64 _fp0)
# define d_m3OpArgs d_m3ExpOpArgs (_fp0)
# define d_m3OpAllArgs d_m3ExpOpAllArgs (_fp0)
# define d_m3OpDefaultArgs d_m3ExpOpDefaultArgs (0.)
# define d_m3ClearRegisters d_m3ExpClearRegisters (_fp0 = 0.;)
# define d_m3OpSig d_m3ExpOpSig (f64 _fp0)
# define d_m3OpArgs d_m3ExpOpArgs (_fp0)
# define d_m3OpAllArgs d_m3ExpOpAllArgs (_fp0)
# define d_m3OpDefaultArgs d_m3ExpOpDefaultArgs (0.)
# define d_m3ClearRegisters d_m3ExpClearRegisters (_fp0 = 0.;)
# else
# define d_m3OpSig d_m3BaseOpSig
# define d_m3OpSig d_m3BaseOpSig
# define d_m3OpArgs d_m3BaseOpArgs
# define d_m3OpAllArgs d_m3BaseOpAllArgs
# define d_m3OpDefaultArgs d_m3BaseOpDefaultArgs
@ -45,7 +45,7 @@ d_m3BeginExternC
typedef m3ret_t (vectorcall * IM3Operation) (d_m3OpSig);
#define d_m3RetSig static inline m3ret_t vectorcall
#define d_m3Op(NAME) op_section d_m3RetSig op_##NAME (d_m3OpSig)
#define d_m3Op(NAME) M3_NO_UBSAN op_section d_m3RetSig op_##NAME (d_m3OpSig)
#define nextOpImpl() ((IM3Operation)(* _pc))(_pc + 1, d_m3OpArgs)
#define jumpOpImpl(PC) ((IM3Operation)(* PC))( PC + 1, d_m3OpArgs)

@ -47,22 +47,25 @@ typedef struct M3Function
bytes_t wasm;
bytes_t wasmEnd;
u16 numNames; // maximum of d_m3MaxDuplicateFunctionImpl
cstr_t names[d_m3MaxDuplicateFunctionImpl];
u16 numNames; // maximum of d_m3MaxDuplicateFunctionImpl
IM3FuncType funcType;
pc_t compiled;
#if (d_m3EnableCodePageRefCounting)
# if (d_m3EnableCodePageRefCounting)
IM3CodePage * codePageRefs; // array of all pages used
u32 numCodePageRefs;
#endif
# endif
#if defined (DEBUG)
# if defined (DEBUG)
u32 hits;
# endif
# if defined (DEBUG) || d_m3EnableExtensions
u32 index;
#endif
# endif
u16 maxStackSlots;

@ -100,7 +100,7 @@ cstr_t SPrintFuncTypeSignature (IM3FuncType i_funcType)
}
size_t SPrintArg (char * o_string, size_t i_stringBufferSize, m3stack_t i_sp, u8 i_type)
size_t SPrintArg (char * o_string, size_t i_stringBufferSize, voidptr_t i_sp, u8 i_type)
{
int len = 0;
@ -142,7 +142,7 @@ cstr_t SPrintFunctionArgList (IM3Function i_function, m3stack_t i_sp)
ret = snprintf (s, e-s, "(");
s += M3_MAX (0, ret);
m3stack_t argSp = i_sp;
u64 * argSp = (u64 *) i_sp;
IM3FuncType funcType = i_function->funcType;
if (funcType)

@ -9,6 +9,29 @@
#include "m3_exception.h"
IM3Module m3_NewModule (IM3Environment i_environment)
{
IM3Module module = m3_AllocStruct (M3Module);
if (module)
{
module->name = ".unnamed";
module->startFunction = -1;
module->environment = i_environment;
module->hasWasmCodeCopy = false;
module->wasmStart = NULL;
module->wasmEnd = NULL;
# if d_m3EnableExtensions
module->numReservedFunctions = 0;
# endif
}
return module;
}
void Module_FreeFunctions (IM3Module i_module)
{
for (u32 i = 0; i < i_module->numFunctions; ++i)
@ -41,6 +64,11 @@ void m3_FreeModule (IM3Module i_module)
}
m3_Free (i_module->globals);
if (i_module->hasWasmCodeCopy)
{
m3_Free (i_module->wasmStart);
}
m3_Free (i_module);
}
}
@ -72,18 +100,33 @@ M3Result Module_AddFunction (IM3Module io_module, u32 i_typeIndex, IM3ImportIn
M3Result result = m3Err_none;
_try {
u32 index = io_module->numFunctions++;
# if d_m3EnableExtensions
if (io_module->runtime) // module loaded, so this must be an InjectFunction call
{
if (io_module->numReservedFunctions)
{
io_module->numReservedFunctions--;
}
else _throw ("reserved function capacity exceeded");
}
else
# endif
io_module->functions = m3_ReallocArray (M3Function, io_module->functions, io_module->numFunctions, index);
_throwifnull(io_module->functions);
_throwif("type sig index out of bounds", i_typeIndex >= io_module->numFuncTypes);
_throwifnull (io_module->functions);
_throwif ("type sig index out of bounds", i_typeIndex >= io_module->numFuncTypes);
IM3FuncType ft = io_module->funcTypes [i_typeIndex];
IM3Function func = Module_GetFunction (io_module, index);
func->funcType = ft;
# ifdef DEBUG
# if defined (DEBUG) || d_m3EnableExtensions
func->index = index;
# endif
# endif
if (i_importInfo and func->numNames == 0)
{
@ -98,6 +141,7 @@ _try {
return result;
}
#ifdef DEBUG
void Module_GenerateNames (IM3Module i_module)
{
for (u32 i = 0; i < i_module->numFunctions; ++i)
@ -124,6 +168,7 @@ void Module_GenerateNames (IM3Module i_module)
}
}
}
#endif
IM3Function Module_GetFunction (IM3Module i_module, u32 i_functionIndex)
{

@ -52,7 +52,7 @@ _ (ReadLEB_u32 (& numTypes, & i_bytes, i_end));
{
// table of IM3FuncType (that point to the actual M3FuncType struct in the Environment)
io_module->funcTypes = m3_AllocArray (IM3FuncType, numTypes);
_throwifnull(io_module->funcTypes);
_throwifnull (io_module->funcTypes);
io_module->numFuncTypes = numTypes;
for (u32 i = 0; i < numTypes; ++i)
@ -110,6 +110,7 @@ _ (NormalizeType (& retType, wasmType));
if (result)
{
m3_Free (ftype);
// FIX: M3FuncTypes in the table are leaked
m3_Free (io_module->funcTypes);
io_module->numFuncTypes = 0;
}
@ -346,6 +347,7 @@ _ (ReadLEB_u32 (& size, & i_bytes, i_end));
if (i_bytes <= i_end)
{
/*
u32 numLocalBlocks;
_ (ReadLEB_u32 (& numLocalBlocks, & ptr, i_end)); m3log (parse, " code size: %-4d", size);
@ -363,6 +365,7 @@ _ (NormalizeType (& normalType, wasmType));
numLocals += varCount; m3log (parse, " %2d locals; type: '%s'", varCount, c_waTypes [normalType]);
}
*/
IM3Function func = Module_GetFunction (io_module, f + io_module->numFuncImports);
@ -370,7 +373,7 @@ _ (NormalizeType (& normalType, wasmType));
func->wasm = start;
func->wasmEnd = i_bytes;
//func->ownsWasmCode = io_module->hasWasmCodeCopy;
func->numLocals = numLocals;
// func->numLocals = numLocals;
}
else _throw (m3Err_wasmSectionOverrun);
}
@ -572,20 +575,23 @@ M3Result ParseModuleSection (M3Module * o_module, u8 i_sectionType, bytes_t i_
}
M3Result m3_ParseModule (IM3Environment i_environment, IM3Module * o_module, cbytes_t i_bytes, u32 i_numBytes)
M3Result m3_ParseModule (IM3Environment i_environment, IM3Module * o_module, cbytes_t i_bytes, u32 i_numBytes, bool i_copyBytes)
{
M3Result result;
M3Result result; m3log (parse, "load module: %d bytes", i_numBytes);
IM3Module module = m3_NewModule (i_environment);
IM3Module module;
_try {
module = m3_AllocStruct (M3Module);
_throwifnull(module);
module->name = ".unnamed"; m3log (parse, "load module: %d bytes", i_numBytes);
module->startFunction = -1;
//module->hasWasmCodeCopy = false;
module->environment = i_environment;
_throwifnull (module);
const u8 * pos = i_bytes;
if (i_copyBytes)
{
pos = m3_CopyMem (i_bytes, i_numBytes);
_throwifnull (pos);
}
const u8 * end = pos + i_numBytes;
module->wasmStart = pos;

@ -9,15 +9,18 @@
#define wasm3_h
#define M3_VERSION_MAJOR 0
#define M3_VERSION_MINOR 4
#define M3_VERSION_REV 9
#define M3_VERSION "0.4.9"
#define M3_VERSION_MINOR 5
#define M3_VERSION_REV 0
#define M3_VERSION "0.5.0"
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdarg.h>
#include "wasm3_defs.h"
#if defined(__cplusplus)
extern "C" {
#endif
@ -118,6 +121,7 @@ d_m3ErrorConst (none, NULL)
// general errors
d_m3ErrorConst (mallocFailed, "memory allocation failed")
d_m3ErrorConst (nullArgument, "null pointer argument provided")
// parse errors
d_m3ErrorConst (incompatibleWasmVersion, "incompatible Wasm binary version")
@ -203,6 +207,14 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow")
uint32_t * o_memorySizeInBytes,
uint32_t i_memoryIndex);
uint8_t * m3_GetMemoryAtOffset (IM3Runtime i_runtime,
uint64_t i_offset,
uint32_t i_size,
uint32_t i_memoryIndex);
// This is used internally by Raw Function helpers
uint32_t m3_GetMemorySize (IM3Runtime i_runtime);
void * m3_GetUserData (IM3Runtime i_runtime);
@ -210,11 +222,12 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow")
// modules
//-------------------------------------------------------------------------------------------------------------------------------
// i_wasmBytes data must be persistent during the lifetime of the module
// i_wasmBytes data must be persistent during the lifetime of the module unless i_copyWasmBytes is true
M3Result m3_ParseModule (IM3Environment i_environment,
IM3Module * o_module,
const uint8_t * const i_wasmBytes,
uint32_t i_numWasmBytes);
uint32_t i_numWasmBytes,
bool i_copyWasmBytes);
// Only modules not loaded into a M3Runtime need to be freed. A module is considered unloaded if
// a. m3_LoadModule has not yet been called on that module. Or,
@ -224,6 +237,9 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow")
// LoadModule transfers ownership of a module to the runtime. Do not free modules once successfully loaded into the runtime
M3Result m3_LoadModule (IM3Runtime io_runtime, IM3Module io_module);
// Optional, compiles all functions in the module
M3Result m3_CompileModule (IM3Module io_module);
// Calling m3_RunStart is optional
M3Result m3_RunStart (IM3Module i_module);
@ -287,6 +303,15 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow")
M3Result m3_GetResultsVL (IM3Function i_function, va_list o_rets);
M3Result m3_GetResults (IM3Function i_function, uint32_t i_retc, const void * o_retptrs[]);
// These two function can be used when you wish to manually push and retrieve from the Wasm3 call stack.
// Arguments and return values are 64-bit aligned, so simply treat the result of m3_GetStack (...) as a u64 array.
// Arguments should be written starting at 'stack_pointer [m3_GetRetCount (...)]'.
// Return values start at 'stack_pointer [0]'
uint64_t * m3_GetStack (IM3Runtime i_runtime);
M3Result m3_CallDirect (IM3Function i_function);
void m3_RebaseStack (IM3Runtime i_runtime,
uint64_t * i_newStackBase);
void m3_GetErrorInfo (IM3Runtime i_runtime, M3ErrorInfo* o_info);
void m3_ResetErrorInfo (IM3Runtime i_runtime);
@ -305,6 +330,45 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow")
// The runtime owns the backtrace, do not free the backtrace you obtain. Returns NULL if there's no backtrace.
IM3BacktraceInfo m3_GetBacktrace (IM3Runtime i_runtime);
//-------------------------------------------------------------------------------------------------------------------------------
// raw function definition helpers
//-------------------------------------------------------------------------------------------------------------------------------
# define m3ApiOffsetToPtr(offset) (void*)((uint8_t*)_mem + (uint32_t)(offset))
# define m3ApiPtrToOffset(ptr) (uint32_t)((uint8_t*)ptr - (uint8_t*)_mem)
# define m3ApiReturnType(TYPE) TYPE* raw_return = ((TYPE*) (_sp++));
# define m3ApiGetArg(TYPE, NAME) TYPE NAME = * ((TYPE *) (_sp++));
# define m3ApiGetArgMem(TYPE, NAME) TYPE NAME = (TYPE)m3ApiOffsetToPtr(* ((uint32_t *) (_sp++)));
# define m3ApiIsNullPtr(addr) ((void*)(addr) <= _mem)
# define m3ApiCheckMem(addr, len) { if (M3_UNLIKELY(m3ApiIsNullPtr(addr) || ((uint64_t)(uintptr_t)(addr) + (len)) > ((uint64_t)(uintptr_t)(_mem)+m3_GetMemorySize(runtime)))) m3ApiTrap(m3Err_trapOutOfBoundsMemoryAccess); }
# define m3ApiRawFunction(NAME) const void * NAME (IM3Runtime runtime, IM3ImportContext _ctx, uint64_t * _sp, void * _mem)
# define m3ApiReturn(VALUE) { *raw_return = (VALUE); return m3Err_none; }
# define m3ApiTrap(VALUE) { return VALUE; }
# define m3ApiSuccess() { return m3Err_none; }
# if defined(M3_BIG_ENDIAN)
# define m3ApiReadMem8(ptr) (* (uint8_t *)(ptr))
# define m3ApiReadMem16(ptr) m3_bswap16((* (uint16_t *)(ptr)))
# define m3ApiReadMem32(ptr) m3_bswap32((* (uint32_t *)(ptr)))
# define m3ApiReadMem64(ptr) m3_bswap64((* (uint64_t *)(ptr)))
# define m3ApiWriteMem8(ptr, val) { * (uint8_t *)(ptr) = (val); }
# define m3ApiWriteMem16(ptr, val) { * (uint16_t *)(ptr) = m3_bswap16((val)); }
# define m3ApiWriteMem32(ptr, val) { * (uint32_t *)(ptr) = m3_bswap32((val)); }
# define m3ApiWriteMem64(ptr, val) { * (uint64_t *)(ptr) = m3_bswap64((val)); }
# else
# define m3ApiReadMem8(ptr) (* (uint8_t *)(ptr))
# define m3ApiReadMem16(ptr) (* (uint16_t *)(ptr))
# define m3ApiReadMem32(ptr) (* (uint32_t *)(ptr))
# define m3ApiReadMem64(ptr) (* (uint64_t *)(ptr))
# define m3ApiWriteMem8(ptr, val) { * (uint8_t *)(ptr) = (val); }
# define m3ApiWriteMem16(ptr, val) { * (uint16_t *)(ptr) = (val); }
# define m3ApiWriteMem32(ptr, val) { * (uint32_t *)(ptr) = (val); }
# define m3ApiWriteMem64(ptr, val) { * (uint64_t *)(ptr) = (val); }
# endif
#if defined(__cplusplus)
}
#endif

@ -0,0 +1,282 @@
//
// wasm3_defs.h
//
// Created by Volodymyr Shymanskyy on 11/20/19.
// Copyright © 2019 Volodymyr Shymanskyy. All rights reserved.
//
#ifndef wasm3_defs_h
#define wasm3_defs_h
#define M3_STR__(x) #x
#define M3_STR(x) M3_STR__(x)
#define M3_CONCAT__(a,b) a##b
#define M3_CONCAT(a,b) M3_CONCAT__(a,b)
/*
* Detect compiler
*/
# if defined(__clang__)
# define M3_COMPILER_CLANG 1
# elif defined(__INTEL_COMPILER)
# define M3_COMPILER_ICC 1
# elif defined(__GNUC__) || defined(__GNUG__)
# define M3_COMPILER_GCC 1
# elif defined(_MSC_VER)
# define M3_COMPILER_MSVC 1
# else
# warning "Compiler not detected"
# endif
# if defined(M3_COMPILER_CLANG)
# if defined(WIN32)
# define M3_COMPILER_VER __VERSION__ " for Windows"
# else
# define M3_COMPILER_VER __VERSION__
# endif
# elif defined(M3_COMPILER_GCC)
# define M3_COMPILER_VER "GCC " __VERSION__
# elif defined(M3_COMPILER_MSVC)
# define M3_COMPILER_VER "MSVC " M3_STR(_MSC_VER)
# else
# define M3_COMPILER_VER "unknown"
# endif
# ifdef __has_feature
# define M3_COMPILER_HAS_FEATURE(x) __has_feature(x)
# else
# define M3_COMPILER_HAS_FEATURE(x) 0
# endif
# ifdef __has_builtin
# define M3_COMPILER_HAS_BUILTIN(x) __has_builtin(x)
# else
# define M3_COMPILER_HAS_BUILTIN(x) 0
# endif
/*
* Detect endianness
*/
# if defined(M3_COMPILER_MSVC)
# define M3_LITTLE_ENDIAN //_byteswap_ushort, _byteswap_ulong, _byteswap_uint64
# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define M3_LITTLE_ENDIAN
# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define M3_BIG_ENDIAN
# else
# error "Byte order not detected"
# endif
/*
* Detect platform
*/
# if defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_GCC)
# if defined(__wasm__)
# define M3_ARCH "wasm"
# elif defined(__x86_64__)
# define M3_ARCH "x86_64"
# elif defined(__i386__)
# define M3_ARCH "i386"
# elif defined(__aarch64__)
# define M3_ARCH "arm64-v8a"
# elif defined(__arm__)
# if defined(__ARM_ARCH_7A__)
# if defined(__ARM_NEON__)
# if defined(__ARM_PCS_VFP)
# define M3_ARCH "arm-v7a/NEON hard-float"
# else
# define M3_ARCH "arm-v7a/NEON"
# endif
# else
# if defined(__ARM_PCS_VFP)
# define M3_ARCH "arm-v7a hard-float"
# else
# define M3_ARCH "arm-v7a"
# endif
# endif
# else
# define M3_ARCH "arm"
# endif
# elif defined(__riscv)
# if defined(__riscv_32e)
# define _M3_ARCH_RV "rv32e"
# elif __riscv_xlen == 128
# define _M3_ARCH_RV "rv128i"
# elif __riscv_xlen == 64
# define _M3_ARCH_RV "rv64i"
# elif __riscv_xlen == 32
# define _M3_ARCH_RV "rv32i"
# endif
# if defined(__riscv_muldiv)
# define _M3_ARCH_RV_M _M3_ARCH_RV "m"
# else
# define _M3_ARCH_RV_M _M3_ARCH_RV
# endif
# if defined(__riscv_atomic)
# define _M3_ARCH_RV_A _M3_ARCH_RV_M "a"
# else
# define _M3_ARCH_RV_A _M3_ARCH_RV_M
# endif
# if defined(__riscv_flen)
# define _M3_ARCH_RV_F _M3_ARCH_RV_A "f"
# else
# define _M3_ARCH_RV_F _M3_ARCH_RV_A
# endif
# if defined(__riscv_flen) && __riscv_flen >= 64
# define _M3_ARCH_RV_D _M3_ARCH_RV_F "d"
# else
# define _M3_ARCH_RV_D _M3_ARCH_RV_F
# endif
# if defined(__riscv_compressed)
# define _M3_ARCH_RV_C _M3_ARCH_RV_D "c"
# else
# define _M3_ARCH_RV_C _M3_ARCH_RV_D
# endif
# define M3_ARCH _M3_ARCH_RV_C
# elif defined(__mips__)
# if defined(__MIPSEB__) && defined(__mips64)
# define M3_ARCH "mips64 " _MIPS_ARCH
# elif defined(__MIPSEL__) && defined(__mips64)
# define M3_ARCH "mips64el " _MIPS_ARCH
# elif defined(__MIPSEB__)
# define M3_ARCH "mips " _MIPS_ARCH
# elif defined(__MIPSEL__)
# define M3_ARCH "mipsel " _MIPS_ARCH
# endif
# elif defined(__PPC__)
# if defined(__PPC64__) && defined(__LITTLE_ENDIAN__)
# define M3_ARCH "ppc64le"
# elif defined(__PPC64__)
# define M3_ARCH "ppc64"
# else
# define M3_ARCH "ppc"
# endif
# elif defined(__sparc__)
# if defined(__arch64__)
# define M3_ARCH "sparc64"
# else
# define M3_ARCH "sparc"
# endif
# elif defined(__s390x__)
# define M3_ARCH "s390x"
# elif defined(__alpha__)
# define M3_ARCH "alpha"
# elif defined(__m68k__)
# define M3_ARCH "m68k"
# elif defined(__xtensa__)
# define M3_ARCH "xtensa"
# elif defined(__arc__)
# define M3_ARCH "arc32"
# elif defined(__AVR__)
# define M3_ARCH "avr"
# endif
# endif
# if defined(M3_COMPILER_MSVC)
# if defined(_M_X64)
# define M3_ARCH "x86_64"
# elif defined(_M_IX86)
# define M3_ARCH "i386"
# elif defined(_M_ARM64)
# define M3_ARCH "arm64"
# elif defined(_M_ARM)
# define M3_ARCH "arm"
# endif
# endif
# if !defined(M3_ARCH)
# warning "Architecture not detected"
# define M3_ARCH "unknown"
# endif
/*
* Byte swapping (for Big-Endian systems only)
*/
# if defined(M3_COMPILER_MSVC)
# define m3_bswap16(x) _byteswap_ushort((x))
# define m3_bswap32(x) _byteswap_ulong((x))
# define m3_bswap64(x) _byteswap_uint64((x))
# elif defined(M3_COMPILER_GCC) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
// __builtin_bswap32/64 added in gcc 4.3, __builtin_bswap16 added in gcc 4.8
# define m3_bswap16(x) __builtin_bswap16((x))
# define m3_bswap32(x) __builtin_bswap32((x))
# define m3_bswap64(x) __builtin_bswap64((x))
# elif defined(M3_COMPILER_CLANG) && M3_COMPILER_HAS_BUILTIN(__builtin_bswap16)
# define m3_bswap16(x) __builtin_bswap16((x))
# define m3_bswap32(x) __builtin_bswap32((x))
# define m3_bswap64(x) __builtin_bswap64((x))
# else
# include <endian.h>
# if defined(__bswap_16)
# define m3_bswap16(x) __bswap_16((x))
# define m3_bswap32(x) __bswap_32((x))
# define m3_bswap64(x) __bswap_64((x))
# else
# warning "Using naive (probably slow) bswap operations"
static inline
uint16_t m3_bswap16(uint16_t x) {
return ((( x >> 8 ) & 0xffu ) | (( x & 0xffu ) << 8 ));
}
static inline
uint32_t m3_bswap32(uint32_t x) {
return ((( x & 0xff000000u ) >> 24 ) |
(( x & 0x00ff0000u ) >> 8 ) |
(( x & 0x0000ff00u ) << 8 ) |
(( x & 0x000000ffu ) << 24 ));
}
static inline
uint64_t m3_bswap64(uint64_t x) {
return ((( x & 0xff00000000000000ull ) >> 56 ) |
(( x & 0x00ff000000000000ull ) >> 40 ) |
(( x & 0x0000ff0000000000ull ) >> 24 ) |
(( x & 0x000000ff00000000ull ) >> 8 ) |
(( x & 0x00000000ff000000ull ) << 8 ) |
(( x & 0x0000000000ff0000ull ) << 24 ) |
(( x & 0x000000000000ff00ull ) << 40 ) |
(( x & 0x00000000000000ffull ) << 56 ));
}
# endif
# endif
/*
* Other
*/
# if defined(M3_COMPILER_GCC) || defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_ICC)
# define M3_UNLIKELY(x) __builtin_expect(!!(x), 0)
# define M3_LIKELY(x) __builtin_expect(!!(x), 1)
# else
# define M3_UNLIKELY(x) (x)
# define M3_LIKELY(x) (x)
# endif
// TODO: remove
# if defined(M3_COMPILER_GCC) || defined(M3_COMPILER_CLANG) || defined(M3_COMPILER_ICC)
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
# define LIKELY(x) __builtin_expect(!!(x), 1)
# else
# define UNLIKELY(x) (x)
# define LIKELY(x) (x)
# endif
#endif // wasm3_defs_h

@ -30,6 +30,8 @@ bool RunTest (int i_argc, const char * i_argv [], cstr_t i_name)
int main (int argc, const char * argv [])
{
// m3_PrintM3Info ();
Test (signatures)
{
M3Result result;
@ -158,13 +160,13 @@ int main (int argc, const char * argv [])
};
// will partially fail (compilation) because module isn't attached to a runtime yet.
result = m3_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result != m3Err_none)
result = m3Ext_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result != m3Err_none)
expect (functionIndex >= 0)
result = m3_LoadModule (runtime, module); expect (result == m3Err_none)
// try again
result = m3_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result == m3Err_none)
result = m3Ext_InjectFunction (module, & functionIndex, "i()", wasm, true); expect (result == m3Err_none)
IM3Function function = m3_GetFunctionByIndex (module, functionIndex); expect (function)
@ -205,7 +207,7 @@ int main (int argc, const char * argv [])
};
IM3Module module;
result = m3_ParseModule (env, & module, wasm, 44); expect (result == m3Err_none)
result = m3_ParseModule (env, & module, wasm, 44, false); expect (result == m3Err_none)
result = m3_LoadModule (runtime, module); expect (result == m3Err_none)

Loading…
Cancel
Save