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_exec.c

497 lines
11 KiB
C

5 years ago
//
// m3_exec.c
//
// Created by Steven Massey on 4/17/19.
// Copyright © 2019 Steven Massey. All rights reserved.
//
#include "m3_env.h"
5 years ago
#include "m3_exec.h"
#include "m3_compile.h"
static inline
IM3Memory GetMemoryInfo (M3MemoryHeader * header)
{
IM3Memory memory = & header->runtime->memory;
5 years ago
return memory;
}
static inline
IM3Runtime GetRuntime (M3MemoryHeader * header)
{
return header->runtime;
}
void ReportError2 (IM3Function i_function, m3ret_t i_result)
5 years ago
{
i_function->module->runtime->runtimeError = (M3Result)i_result;
5 years ago
}
d_m3OpDef (GetGlobal_s32)
{
u32 * global = immediate (u32 *);
slot (u32) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global);
nextOp ();
}
d_m3OpDef (GetGlobal_s64)
{
u64 * global = immediate (u64 *);
slot (u64) = * global; // printf ("get global: %p %" PRIi64 "\n", global, *global);
nextOp ();
}
d_m3OpDef (SetGlobal_i32)
{
u32 * global = immediate (u32 *);
* global = (u32) _r0; // printf ("set global: %p %" PRIi64 "\n", global, _r0);
nextOp ();
}
d_m3OpDef (SetGlobal_i64)
{
u64 * global = immediate (u64 *);
* global = (u64) _r0; // printf ("set global: %p %" PRIi64 "\n", global, _r0);
nextOp ();
}
5 years ago
d_m3OpDef (Call)
{
pc_t callPC = immediate (pc_t);
i32 stackOffset = immediate (i32);
IM3Memory memory = GetMemoryInfo (_mem);
m3stack_t sp = _sp + stackOffset;
m3ret_t r = Call (callPC, sp, _mem, d_m3OpDefaultArgs);
5 years ago
if (r == 0)
{
_mem = memory->mallocated;
nextOp ();
}
else return r;
5 years ago
}
d_m3OpDef (CallIndirect)
{
4 years ago
u32 tableIndex = slot (u32);
IM3Module module = immediate (IM3Module);
IM3FuncType type = immediate (IM3FuncType);
i32 stackOffset = immediate (i32);
IM3Memory memory = GetMemoryInfo (_mem);
m3stack_t sp = _sp + stackOffset;
m3ret_t r = m3Err_none;
4 years ago
if (tableIndex < module->table0Size)
{
IM3Function function = module->table0 [tableIndex];
if (function)
{
if (type == function->funcType)
{
if (not function->compiled)
r = Compile_Function (function);
if (not r)
{
r = Call (function->compiled, sp, _mem, d_m3OpDefaultArgs);
if (not r)
{
_mem = memory->mallocated;
r = nextOpDirect ();
}
}
}
else r = m3Err_trapIndirectCallTypeMismatch;
}
else r = m3Err_trapTableElementIsNull;
}
else r = m3Err_trapTableIndexOutOfRange;
return r;
5 years ago
}
5 years ago
d_m3OpDef (CallRawFunction)
{
M3RawCall call = (M3RawCall) (* _pc++);
IM3Runtime runtime = GetRuntime (_mem);
5 years ago
m3ret_t possible_trap = call (runtime, (u64 *) _sp, m3MemData(_mem));
5 years ago
return possible_trap;
}
d_m3OpDef (CallRawFunctionEx)
{
M3RawCallEx call = (M3RawCallEx) (* _pc++);
void * cookie = immediate (void *);
IM3Runtime runtime = GetRuntime (_mem);
m3ret_t possible_trap = call (runtime, (u64 *)_sp, m3MemData(_mem), cookie);
return possible_trap;
}
5 years ago
d_m3OpDef (MemCurrent)
{
IM3Memory memory = GetMemoryInfo (_mem);
_r0 = memory->numPages;
nextOp ();
}
d_m3OpDef (MemGrow)
{
IM3Runtime runtime = GetRuntime (_mem);
IM3Memory memory = & runtime->memory;
u32 numPagesToGrow = (u32) _r0;
_r0 = memory->numPages;
5 years ago
if (numPagesToGrow)
{
u32 requiredPages = memory->numPages + numPagesToGrow;
5 years ago
5 years ago
M3Result r = ResizeMemory (runtime, requiredPages);
if (r)
_r0 = -1;
5 years ago
_mem = memory->mallocated;
5 years ago
}
5 years ago
nextOp ();
}
5 years ago
// it's a debate: should the compilation be trigger be the caller or callee page.
// it's a much easier to put it in the caller pager. if it's in the callee, either the entire page
// has be left dangling or it's just a stub that jumps to a newly acquire page. In Gestalt, I opted
// for the stub approach. Stubbing makes it easier to dynamically free the compilation. You can also
// do both.
d_m3OpDef (Compile)
{
rewrite_op (op_Call);
IM3Function function = immediate (IM3Function);
m3ret_t result = m3Err_none;
if (not function->compiled) // check to see if function was compiled since this operation was emitted.
result = Compile_Function (function);
if (not result)
{
// patch up compiled pc and call rewriten op_Call
*((size_t *) --_pc) = (size_t) (function->compiled);
--_pc;
result = nextOpDirect ();
}
else ReportError2 (function, result);
return result;
5 years ago
}
d_m3OpDef (Entry)
{
d_m3ClearRegisters
IM3Function function = immediate (IM3Function);
4 years ago
#if defined (d_m3SkipStackCheck)
if (true)
#else
4 years ago
if ((void *) ((m3slot_t *) _sp + function->maxStackSlots) < _mem->maxStack)
#endif
{
function->hits++; m3log (exec, " enter %p > %s %s", _pc - 2, function->name ? function->name : ".unnamed", SPrintFunctionArgList (function, _sp));
4 years ago
u8 * stack = (u8 *) ((m3slot_t *) _sp + function->numArgSlots);
4 years ago
memset (stack, 0x0, function->numLocalBytes);
stack += function->numLocalBytes;
4 years ago
if (function->constants)
{
4 years ago
memcpy (stack, function->constants, function->numConstantBytes);
}
4 years ago
m3ret_t r = nextOpDirect ();
# if d_m3LogExec
u8 returnType = function->funcType->returnType;
char str [100] = { '!', 0 };
if (not r)
SPrintArg (str, 99, _sp, function->funcType->returnType);
5 years ago
m3log (exec, " exit < %s %s %s %s", function->name, returnType ? "->" : "", str, r ? r : "");
# elif d_m3LogStackTrace
if (r)
printf (" ** %s %p\n", function->name, _sp);
# endif
5 years ago
return r;
}
else return m3Err_trapStackOverflow;
5 years ago
}
d_m3OpDef (Loop)
{
// regs are unused coming into a loop anyway
// this reduces code size & stack usage
d_m3ClearRegisters
m3ret_t r;
IM3Memory memory = GetMemoryInfo (_mem);
5 years ago
do
{
r = nextOpDirect (); // printf ("loop: %p\n", r);
5 years ago
// linear memory pointer needs refreshed here because the block it's looping over
// can potentially invoke the grow operation.
_mem = memory->mallocated;
}
while (r == _pc);
return r;
5 years ago
}
d_m3OpDef (Branch)
{
return jumpOp (* _pc);
}
5 years ago
d_m3OpDef (If_r)
{
i32 condition = (i32) _r0;
pc_t elsePC = immediate (pc_t);
if (condition)
nextOp ();
else
return jumpOp (elsePC);
5 years ago
}
d_m3OpDef (If_s)
{
i32 condition = slot (i32);
pc_t elsePC = immediate (pc_t);
if (condition)
nextOp ();
else
return jumpOp (elsePC);
5 years ago
}
5 years ago
d_m3OpDef (BranchTable)
{
i32 branchIndex = slot (i32); // branch index is always in a slot
i32 numTargets = immediate (i32);
5 years ago
5 years ago
pc_t * branches = (pc_t *) _pc;
5 years ago
5 years ago
if (branchIndex < 0 or branchIndex > numTargets)
branchIndex = numTargets; // the default index
5 years ago
5 years ago
return jumpOp (branches [branchIndex]);
}
5 years ago
#define d_m3SetRegisterSetSlot(TYPE, REG) \
d_m3OpDef (SetRegister_##TYPE) \
{ \
REG = slot (TYPE); \
nextOp (); \
} \
\
d_m3OpDef (SetSlot_##TYPE) \
{ \
slot (TYPE) = (TYPE) REG; \
nextOp (); \
} \
\
d_m3OpDef (PreserveSetSlot_##TYPE) \
{ \
TYPE * stack = slot_ptr (TYPE); \
TYPE * preserve = slot_ptr (TYPE); \
\
* preserve = * stack; \
* stack = (TYPE) REG; \
\
nextOp (); \
}
d_m3SetRegisterSetSlot (i32, _r0)
d_m3SetRegisterSetSlot (i64, _r0)
d_m3SetRegisterSetSlot (f32, _fp0)
d_m3SetRegisterSetSlot (f64, _fp0)
5 years ago
d_m3OpDef (CopySlot_32)
{
u32 * dst = slot_ptr (u32);
u32 * src = slot_ptr (u32);
5 years ago
* dst = * src;
5 years ago
nextOp ();
}
5 years ago
d_m3OpDef (PreserveCopySlot_32)
{
u32 * dest = slot_ptr (u32);
u32 * src = slot_ptr (u32);
u32 * preserve = slot_ptr (u32);
* preserve = * dest;
* dest = * src;
nextOp ();
5 years ago
}
5 years ago
d_m3OpDef (CopySlot_64)
{
u64 * dst = slot_ptr (u64);
u64 * src = slot_ptr (u64);
5 years ago
5 years ago
* dst = * src; // printf ("copy: %p <- %" PRIi64 " <- %p\n", dst, * dst, src);
5 years ago
nextOp ();
5 years ago
}
5 years ago
d_m3OpDef (PreserveCopySlot_64)
{
u64 * dest = slot_ptr (u64);
u64 * src = slot_ptr (u64);
u64 * preserve = slot_ptr (u64);
* preserve = * dest;
* dest = * src;
nextOp ();
5 years ago
}
5 years ago
#if d_m3RuntimeStackDumps
//--------------------------------------------------------------------------------------------------------
d_m3OpDef (DumpStack)
{
u32 opcodeIndex = immediate (u32);
u64 stackHeight = immediate (u64);
IM3Function function = immediate (IM3Function);
cstr_t funcName = (function) ? function->name : "";
printf (" %4d ", opcodeIndex);
printf (" %-25s r0: 0x%016" PRIx64 " i:%" PRIi64 " u:%" PRIu64 "\n", funcName, _r0, _r0, _r0);
printf (" fp0: %lf \n", _fp0);
u64 * sp = _sp;
for (u32 i = 0; i < stackHeight; ++i)
{
printf ("%016llx ", (u64) sp);
cstr_t kind = "";
printf ("%5s %2d: 0x%" PRIx64 " %" PRIi64 "\n", kind, i, (u64) *(sp), (i64) *sp);
++sp;
}
printf ("---------------------------------------------------------------------------------------------------------\n");
return nextOpDirect();
}
#endif
# if d_m3EnableOpProfiling
//--------------------------------------------------------------------------------------------------------
M3ProfilerSlot s_opProfilerCounts [c_m3ProfilerSlotMask + 1] = {};
5 years ago
void ProfileHit (cstr_t i_operationName)
{
u64 ptr = (u64) i_operationName;
M3ProfilerSlot * slot = & s_opProfilerCounts [ptr & c_m3ProfilerSlotMask];
if (slot->opName)
{
if (slot->opName != i_operationName)
{
5 years ago
m3Abort ("profiler slot collision; increase c_m3ProfilerSlotMask");
5 years ago
}
}
slot->opName = i_operationName;
slot->hitCount++;
}
5 years ago
void m3_PrintProfilerInfo ()
{
M3ProfilerSlot dummy;
M3ProfilerSlot * maxSlot = & dummy;
do
5 years ago
{
maxSlot->hitCount = 0;
for (u32 i = 0; i <= c_m3ProfilerSlotMask; ++i)
{
M3ProfilerSlot * slot = & s_opProfilerCounts [i];
if (slot->opName)
{
if (slot->hitCount > maxSlot->hitCount)
maxSlot = slot;
}
}
5 years ago
if (maxSlot->opName)
{
fprintf (stderr, "%13llu %s\n", maxSlot->hitCount, maxSlot->opName);
maxSlot->opName = NULL;
}
5 years ago
}
while (maxSlot->hitCount);
5 years ago
}
# else
void m3_PrintProfilerInfo () {}
# endif