You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wasm3/source/m3_core.c

483 lines
9.5 KiB
C

//
// m3_core.c
//
// Created by Steven Massey on 4/15/19.
// Copyright © 2019 Steven Massey. All rights reserved.
//
#define M3_IMPLEMENT_ERROR_STRINGS
#include "m3.h"
#include "m3_core.h"
void m3Abort(const char* message) {
#if d_m3LogOutput
fprintf(stderr, "Error: %s\n", message);
#endif
abort();
}
void m3NotImplemented() {
m3Abort("Not implemented");
}
M3_WEAK
void m3Yield ()
{
}
#if d_m3FixedHeap
static u8 fixedHeap[d_m3FixedHeap];
static u8* fixedHeapPtr = fixedHeap;
static u8* const fixedHeapEnd = fixedHeap + d_m3FixedHeap;
static u8* fixedHeapLast = NULL;
#if d_m3FixedHeapAlign > 1
# define HEAP_ALIGN_PTR(P) P = (u8*)(((size_t)(P)+(d_m3FixedHeapAlign-1)) & ~ (d_m3FixedHeapAlign-1));
#else
# define HEAP_ALIGN_PTR(P)
#endif
M3Result m3Malloc (void ** o_ptr, size_t i_size)
{
u8 * ptr = fixedHeapPtr;
fixedHeapPtr += i_size;
HEAP_ALIGN_PTR(fixedHeapPtr);
if (fixedHeapPtr >= fixedHeapEnd)
{
* o_ptr = NULL;
return m3Err_mallocFailed;
}
memset (ptr, 0x0, i_size);
* o_ptr = ptr;
fixedHeapLast = ptr;
//printf("== alloc %d => %p\n", i_size, ptr);
return m3Err_none;
}
void m3Free_impl (void * o_ptr)
{
if (!o_ptr) return;
// Handle the last chunk
if (o_ptr == fixedHeapLast) {
fixedHeapPtr = fixedHeapLast;
fixedHeapLast = NULL;
//printf("== free %p\n", o_ptr);
} else {
//printf("== free %p [failed]\n", o_ptr);
}
}
void * m3Realloc (void * i_ptr, size_t i_newSize, size_t i_oldSize)
{
//printf("== realloc %p => %d\n", i_ptr, i_newSize);
void * ptr = i_ptr;
if (i_newSize == i_oldSize) return ptr;
// Handle the last chunk
if (i_ptr && i_ptr == fixedHeapLast) {
fixedHeapPtr = fixedHeapLast + i_newSize;
HEAP_ALIGN_PTR(fixedHeapPtr);
return ptr;
}
m3Malloc(&ptr, i_newSize);
if (!ptr) return NULL;
if (i_ptr) {
memcpy(ptr, i_ptr, i_oldSize);
}
return ptr;
}
#else
M3Result m3Malloc (void ** o_ptr, size_t i_size)
{
M3Result result = m3Err_none;
void * ptr = malloc (i_size);
if (ptr)
{
memset (ptr, 0x0, i_size);
}
else result = m3Err_mallocFailed;
* o_ptr = ptr;
//printf("== alloc %d => %p\n", i_size, ptr);
return result;
}
void m3Free_impl (void * o_ptr)
{
if (!o_ptr) return;
//printf("== free %p\n", o_ptr);
free(o_ptr);
}
void * m3Realloc (void * i_ptr, size_t i_newSize, size_t i_oldSize)
{
//printf("== realloc %p => %d\n", i_ptr, i_newSize);
void * ptr = i_ptr;
if (i_newSize != i_oldSize)
{
ptr = realloc (i_ptr, i_newSize);
if (ptr)
{
if (i_ptr)
{
if (i_newSize > i_oldSize)
memset ((u8*) ptr + i_oldSize, 0x0, i_newSize - i_oldSize);
}
else memset (ptr, 0x0, i_newSize);
}
}
return ptr;
}
#endif
//--------------------------------------------------------------------------------------------
#if d_m3LogNativeStack
static size_t stack_start;
static size_t stack_end;
void m3StackCheckInit ()
{
char stack;
stack_end = stack_start = (size_t)&stack;
}
void m3StackCheck ()
{
char stack;
size_t addr = (size_t)&stack;
size_t stackEnd = stack_end;
stack_end = min(stack_end, addr);
// if (stackEnd != stack_end)
// printf ("maxStack: %ld\n", m3StackGetMax ());
}
size_t m3StackGetMax ()
{
return stack_start - stack_end;
}
#endif
//--------------------------------------------------------------------------------------------
M3Result NormalizeType (u8 * o_type, i8 i_convolutedWasmType)
{
M3Result result = m3Err_none;
u8 type = -i_convolutedWasmType;
if (type == 0x40)
type = c_m3Type_none;
else if (type < c_m3Type_i32 or type > c_m3Type_f64)
result = m3Err_invalidTypeId;
* o_type = type;
return result;
}
bool IsFpType (u8 i_m3Type)
{
return (i_m3Type == c_m3Type_f32 or i_m3Type == c_m3Type_f64);
}
bool IsIntType (u8 i_m3Type)
{
return (i_m3Type == c_m3Type_i32 or i_m3Type == c_m3Type_i64);
}
bool Is64BitType (u8 i_m3Type)
{
if (i_m3Type == c_m3Type_i64 or i_m3Type == c_m3Type_f64)
return true;
else if (i_m3Type == c_m3Type_i32 or i_m3Type == c_m3Type_f32 or i_m3Type == c_m3Type_none)
return false;
else
return (sizeof (voidptr_t) == 8); // all other cases are pointers
}
u32 SizeOfType (u8 i_m3Type)
{
u32 size = sizeof (i64);
if (i_m3Type == c_m3Type_i32 or i_m3Type == c_m3Type_f32)
size = sizeof (i32);
return size;
}
//-- Binary Wasm parsing utils ------------------------------------------------------------------------------------------
M3Result Read_u64 (u64 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
const u8 * ptr = * io_bytes;
ptr += sizeof (u64);
if (ptr <= i_end)
{
memcpy(o_value, * io_bytes, sizeof(u64));
* io_bytes = ptr;
return m3Err_none;
}
else return m3Err_wasmUnderrun;
}
M3Result Read_u32 (u32 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
const u8 * ptr = * io_bytes;
ptr += sizeof (u32);
if (ptr <= i_end)
{
memcpy(o_value, * io_bytes, sizeof(u32));
* io_bytes = ptr;
return m3Err_none;
}
else return m3Err_wasmUnderrun;
}
M3Result Read_f64 (f64 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
const u8 * ptr = * io_bytes;
ptr += sizeof (f64);
if (ptr <= i_end)
{
memcpy(o_value, * io_bytes, sizeof(f64));
* io_bytes = ptr;
return m3Err_none;
}
else return m3Err_wasmUnderrun;
}
M3Result Read_f32 (f32 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
const u8 * ptr = * io_bytes;
ptr += sizeof (f32);
if (ptr <= i_end)
{
memcpy(o_value, * io_bytes, sizeof(f32));
* io_bytes = ptr;
return m3Err_none;
}
else return m3Err_wasmUnderrun;
}
M3Result Read_u8 (u8 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
const u8 * ptr = * io_bytes;
if (ptr < i_end)
{
* o_value = * ptr;
ptr += sizeof (u8);
* io_bytes = ptr;
return m3Err_none;
}
else return m3Err_wasmUnderrun;
}
M3Result ReadLebUnsigned (u64 * o_value, u32 i_maxNumBits, bytes_t * io_bytes, cbytes_t i_end)
{
M3Result result = m3Err_wasmUnderrun;
u64 value = 0;
u32 shift = 0;
const u8 * ptr = * io_bytes;
while (ptr < i_end)
{
u64 byte = * (ptr++);
value |= ((byte & 0x7f) << shift);
shift += 7;
if ((byte & 0x80) == 0)
{
result = m3Err_none;
break;
}
if (shift > i_maxNumBits)
{
result = m3Err_lebOverflow;
break;
}
}
* o_value = value;
* io_bytes = ptr;
return result;
}
M3Result ReadLebSigned (i64 * o_value, u32 i_maxNumBits, bytes_t * io_bytes, cbytes_t i_end)
{
M3Result result = m3Err_wasmUnderrun;
i64 value = 0;
u32 shift = 0;
const u8 * ptr = * io_bytes;
while (ptr < i_end)
{
u64 byte = * (ptr++);
value |= ((byte & 0x7f) << shift);
shift += 7;
if ((byte & 0x80) == 0)
{
result = m3Err_none;
if ((byte & 0x40) and (shift < 64)) // do sign extension
{
u64 extend = 1;
extend <<= shift;
value |= -extend;
}
break;
}
if (shift > i_maxNumBits)
{
result = m3Err_lebOverflow;
break;
}
}
* o_value = value;
* io_bytes = ptr;
return result;
}
M3Result ReadLEB_u32 (u32 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
u64 value;
M3Result result = ReadLebUnsigned (& value, 32, io_bytes, i_end);
* o_value = (u32) value;
return result;
}
M3Result ReadLEB_u7 (u8 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
u64 value;
M3Result result = ReadLebUnsigned (& value, 7, io_bytes, i_end);
* o_value = (u8) value;
return result;
}
M3Result ReadLEB_i7 (i8 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
i64 value;
M3Result result = ReadLebSigned (& value, 7, io_bytes, i_end);
* o_value = (i8) value;
return result;
}
M3Result ReadLEB_i32 (i32 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
i64 value;
M3Result result = ReadLebSigned (& value, 32, io_bytes, i_end);
* o_value = (i32) value;
return result;
}
M3Result ReadLEB_i64 (i64 * o_value, bytes_t * io_bytes, cbytes_t i_end)
{
i64 value;
M3Result result = ReadLebSigned (& value, 64, io_bytes, i_end);
* o_value = value;
return result;
}
M3Result Read_utf8 (cstr_t * o_utf8, bytes_t * io_bytes, cbytes_t i_end)
{
*o_utf8 = NULL;
u32 utf8Length;
M3Result result = ReadLEB_u32 (& utf8Length, io_bytes, i_end);
if (not result)
{
if (utf8Length <= d_m3MaxSaneUtf8Length)
{
const u8 * ptr = * io_bytes;
const u8 * end = ptr + utf8Length;
if (end <= i_end)
{
char * utf8;
result = m3Malloc ((void **) & utf8, utf8Length + 1);
if (not result)
{
memcpy (utf8, ptr, utf8Length);
utf8 [utf8Length] = 0;
* o_utf8 = utf8;
}
* io_bytes = end;
}
else result = m3Err_wasmUnderrun;
}
else result = m3Err_missingUTF8;
}
return result;
}