Basic stack access API. Closes #41

extensions
Volodymyr Shymanskyy 3 years ago
parent 23ccccb9f8
commit d71a204e55

@ -10,7 +10,6 @@
#include <time.h> #include <time.h>
#include "m3/wasm3.h" #include "m3/wasm3.h"
#include "m3/m3_env.h"
#include "m3/m3_config.h" #include "m3/m3_config.h"
#include "m3/extra/fib32.wasm.h" #include "m3/extra/fib32.wasm.h"
@ -45,10 +44,9 @@ void run_wasm()
printf("Running...\n"); printf("Running...\n");
const char* i_argv[2] = { "40", NULL }; result = m3_CallV (f, 40);
result = m3_CallWithArgs (f, 1, i_argv);
if (result) FATAL("m3_CallWithArgs: %s", result); if (result) FATAL("m3_Call: %s", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);
printf("Result: %ld\n", value); printf("Result: %ld\n", value);

@ -14,7 +14,6 @@
#include "m3_api_wasi.h" #include "m3_api_wasi.h"
#include "m3_api_libc.h" #include "m3_api_libc.h"
#include "m3_api_tracer.h" #include "m3_api_tracer.h"
#include "m3_env.h"
#define FATAL(msg, ...) { printf("Error: [Fatal] " msg "\n", ##__VA_ARGS__); goto _onfatal; } #define FATAL(msg, ...) { printf("Error: [Fatal] " msg "\n", ##__VA_ARGS__); goto _onfatal; }
@ -157,7 +156,7 @@ M3Result repl_call (const char* name, int argc, const char* argv[])
M3Result result = m3_FindFunction (&func, runtime, "_start"); M3Result result = m3_FindFunction (&func, runtime, "_start");
if (result) return result; if (result) return result;
result = m3_CallWithArgs(func, 0, NULL); result = m3_CallArgV(func, 0, NULL);
if (result == m3Err_trapExit) { if (result == m3Err_trapExit) {
exit(wasi_ctx->exit_code); exit(wasi_ctx->exit_code);
@ -170,31 +169,36 @@ M3Result repl_call (const char* name, int argc, const char* argv[])
} }
int arg_count = m3_GetArgCount(func); int arg_count = m3_GetArgCount(func);
int ret_count = m3_GetRetCount(func);
if (argc < arg_count) { if (argc < arg_count) {
return "not enough arguments"; return "not enough arguments";
} else if (argc > arg_count) { } else if (argc > arg_count) {
return "too many arguments"; return "too many arguments";
} }
result = m3_CallWithArgs (func, argc, argv); result = m3_CallArgV (func, argc, argv);
if (result) return result; if (result) return result;
// TODO: Stack access API static uint64_t valbuff[128];
uint64_t* stack = (uint64_t*)runtime->stack; static const void* valptrs[128];
memset(valbuff, 0, sizeof(valbuff));
for (int i = 0; i < ret_count; i++) {
valptrs[i] = &valbuff[i];
}
result = m3_GetResults (func, ret_count, valptrs);
if (result) return result;
int ret_count = m3_GetRetCount(func);
if (ret_count <= 0) { if (ret_count <= 0) {
fprintf (stderr, "Result: <Empty Stack>\n"); fprintf (stderr, "Result: <Empty Stack>\n");
} }
for (int i = 0; i < ret_count; i++) { for (int i = 0; i < ret_count; i++) {
switch (m3_GetRetType(func, i)) { switch (m3_GetRetType(func, i)) {
case c_m3Type_i32: fprintf (stderr, "Result: %" PRIi32 "\n", *(i32*)(stack)); break; case c_m3Type_i32: fprintf (stderr, "Result: %" PRIi32 "\n", *(i32*)valptrs[i]); break;
case c_m3Type_i64: fprintf (stderr, "Result: %" PRIi64 "\n", *(i64*)(stack)); break; case c_m3Type_i64: fprintf (stderr, "Result: %" PRIi64 "\n", *(i64*)valptrs[i]); break;
case c_m3Type_f32: fprintf (stderr, "Result: %f\n", *(f32*)(stack)); break; case c_m3Type_f32: fprintf (stderr, "Result: %" PRIf32 "\n", *(f32*)valptrs[i]); break;
case c_m3Type_f64: fprintf (stderr, "Result: %lf\n", *(f64*)(stack)); break; case c_m3Type_f64: fprintf (stderr, "Result: %" PRIf64 "\n", *(f64*)valptrs[i]); break;
default: return "unknown return type"; default: return "unknown return type";
} }
stack++;
} }
return result; return result;
@ -208,6 +212,8 @@ M3Result repl_invoke (const char* name, int argc, const char* argv[])
if (result) return result; if (result) return result;
int arg_count = m3_GetArgCount(func); int arg_count = m3_GetArgCount(func);
int ret_count = m3_GetRetCount(func);
if (argc > 128) { if (argc > 128) {
return "arguments limit reached"; return "arguments limit reached";
} else if (argc < arg_count) { } else if (argc < arg_count) {
@ -216,14 +222,14 @@ M3Result repl_invoke (const char* name, int argc, const char* argv[])
return "too many arguments"; return "too many arguments";
} }
static uint64_t argbuff[128]; static uint64_t valbuff[128];
static const void* argptrs[128]; static const void* valptrs[128];
memset(argbuff, 0, sizeof(argbuff)); memset(valbuff, 0, sizeof(valbuff));
memset(argptrs, 0, sizeof(argptrs)); memset(valptrs, 0, sizeof(valptrs));
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
u64* s = &argbuff[i]; u64* s = &valbuff[i];
argptrs[i] = s; valptrs[i] = s;
switch (m3_GetArgType(func, i)) { switch (m3_GetArgType(func, i)) {
case c_m3Type_i32: case c_m3Type_i32:
case c_m3Type_f32: *(u32*)(s) = strtoul(argv[i], NULL, 10); break; case c_m3Type_f32: *(u32*)(s) = strtoul(argv[i], NULL, 10); break;
@ -233,27 +239,30 @@ M3Result repl_invoke (const char* name, int argc, const char* argv[])
} }
} }
result = m3_Call (func, argc, argptrs); result = m3_Call (func, argc, valptrs);
if (result) return result; if (result) return result;
// TODO: Stack access API // reuse valbuff for return values
uint64_t* stack = (uint64_t*)runtime->stack; memset(valbuff, 0, sizeof(valbuff));
for (int i = 0; i < ret_count; i++) {
valptrs[i] = &valbuff[i];
}
result = m3_GetResults (func, ret_count, valptrs);
if (result) return result;
unsigned ret_count = m3_GetRetCount(func);
if (ret_count <= 0) { if (ret_count <= 0) {
fprintf (stderr, "Result: <Empty Stack>\n"); fprintf (stderr, "Result: <Empty Stack>\n");
} }
for (unsigned i = 0; i < ret_count; i++) { for (int i = 0; i < ret_count; i++) {
switch (m3_GetRetType(func, i)) { switch (m3_GetRetType(func, i)) {
case c_m3Type_i32: case c_m3Type_i32:
case c_m3Type_f32: case c_m3Type_f32:
fprintf (stderr, "Result: %" PRIu32 "\n", *(u32*)(stack)); break; fprintf (stderr, "Result: %" PRIu32 "\n", *(u32*)valptrs[i]); break;
case c_m3Type_i64: case c_m3Type_i64:
case c_m3Type_f64: case c_m3Type_f64:
fprintf (stderr, "Result: %" PRIu64 "\n", *(u64*)(stack)); break; fprintf (stderr, "Result: %" PRIu64 "\n", *(u64*)valptrs[i]); break;
default: return "unknown return type"; default: return "unknown return type";
} }
stack++;
} }
return result; return result;

@ -41,8 +41,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
IM3Function f = NULL; IM3Function f = NULL;
result = m3_FindFunction (&f, runtime, "fib"); result = m3_FindFunction (&f, runtime, "fib");
if (f) { if (f) {
const char* i_argv[1] = { "10", NULL }; m3_CallV (f, 10);
m3_CallWithArgs (f, 1, i_argv);
} }
} }

@ -44,7 +44,7 @@ void run_wasm()
Serial.println("Running..."); Serial.println("Running...");
result = m3_CallVariadic(f, 1, 24); result = m3_CallV(f, 24);
if (result) FATAL("m3_Call", result); if (result) FATAL("m3_Call", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);

@ -44,7 +44,7 @@ void run_wasm()
puts("Running..."); puts("Running...");
result = m3_CallVariadic(f, 1, 24); result = m3_CallV (f, 24);
if (result) FATAL("m3_Call", result); if (result) FATAL("m3_Call", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);

@ -309,7 +309,7 @@ namespace wasm3 {
call_argv(Args... args) { call_argv(Args... args) {
/* std::enable_if above checks that all argument types are convertible const char* */ /* std::enable_if above checks that all argument types are convertible const char* */
const char* argv[] = {args...}; const char* argv[] = {args...};
M3Result res = m3_CallWithArgs(m_func, sizeof...(args), argv); M3Result res = m3_CallArgV(m_func, sizeof...(args), argv);
detail::check_error(res); detail::check_error(res);
Ret ret; Ret ret;
/* FIXME: there should be a public API to get the return value */ /* FIXME: there should be a public API to get the return value */

@ -50,8 +50,7 @@ void run_wasm()
result = m3_FindFunction (&f, runtime, "fib"); result = m3_FindFunction (&f, runtime, "fib");
if (result) FATAL("m3_FindFunction: %s", result); if (result) FATAL("m3_FindFunction: %s", result);
const char* i_argv[2] = { "40", NULL }; result = m3_CallV (f, 40);
result = m3_CallWithArgs (f, 1, i_argv);
if (result) FATAL("Call: %s", result); if (result) FATAL("Call: %s", result);

@ -50,7 +50,7 @@ uint32_t call(IM3Runtime runtime, int argc, const char* argv[]) {
result = m3_FindFunction (&f, runtime, argv[0]); result = m3_FindFunction (&f, runtime, argv[0]);
if (result) return -1; if (result) return -1;
result = m3_CallWithArgs (f, argc-1, argv+1); result = m3_CallArgV (f, argc-1, argv+1);
if (result) return -2; if (result) return -2;
return *(uint64_t*)(runtime->stack); return *(uint64_t*)(runtime->stack);

@ -50,7 +50,7 @@ static void run_wasm(void)
printf("Running...\n"); printf("Running...\n");
const char* i_argv[2] = { "test.wasm", NULL }; const char* i_argv[2] = { "test.wasm", NULL };
result = m3_CallWithArgs (f, 1, i_argv); result = m3_CallArgV (f, 1, i_argv);
if (result) FATAL("m3_CallWithArgs: %s", result); if (result) FATAL("m3_CallWithArgs: %s", result);

@ -45,7 +45,7 @@ static void run_wasm(void)
printf("Running...\n"); printf("Running...\n");
result = m3_CallVariadic(f, 1, 24); result = m3_CallV(f, 24);
if (result) FATAL("m3_Call: %s", result); if (result) FATAL("m3_Call: %s", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);

@ -45,7 +45,7 @@ static void run_wasm(void)
printf("Running...\n"); printf("Running...\n");
result = m3_CallVariadic(f, 1, 24); result = m3_CallV(f, 24);
if (result) FATAL("m3_Call: %s", result); if (result) FATAL("m3_Call: %s", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);

@ -42,7 +42,7 @@ void run_wasm()
printf("Running...\n"); printf("Running...\n");
result = m3_CallVariadic(f, 1, 24); result = m3_CallV(f, 24);
if (result) FATAL("m3_Call: %s", result); if (result) FATAL("m3_Call: %s", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);

@ -72,7 +72,7 @@ bool run_wasm()
uart_print("Running...\n"); uart_print("Running...\n");
result = m3_CallVariadic(f, 1, 24); result = m3_CallV (f, 24);
if (result) FATAL("m3_Call: %s", result); if (result) FATAL("m3_Call: %s", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);

@ -41,7 +41,7 @@ void run_wasm()
printf("Running...\n"); printf("Running...\n");
result = m3_CallVariadic(f, 1, 24); result = m3_CallV (f, 24);
if (result) FATAL("m3_Call: %s", result); if (result) FATAL("m3_Call: %s", result);
long value = *(uint64_t*)(runtime->stack); long value = *(uint64_t*)(runtime->stack);

@ -81,10 +81,10 @@ void run_wasm()
const char* i_argv[2] = { FIB_ARG_VALUE, NULL }; const char* i_argv[2] = { FIB_ARG_VALUE, NULL };
clock_t start = clock(); clock_t start = clock();
result = m3_CallWithArgs (f, 1, i_argv); result = m3_CallArgV (f, 1, i_argv);
clock_t end = clock(); clock_t end = clock();
if (result) FATAL("m3_CallWithArgs: %s", result); if (result) FATAL("m3_Call: %s", result);
printf("Elapsed: %ld ms\n\n", (end - start) * 1000 / CLOCKS_PER_SEC); printf("Elapsed: %ld ms\n\n", (end - start) * 1000 / CLOCKS_PER_SEC);
// uint64_t value = *(uint64_t*)(runtime->stack); // uint64_t value = *(uint64_t*)(runtime->stack);

@ -1,8 +1,8 @@
#include "Python.h" #include "Python.h"
#include "m3_api_defs.h"
#include "wasm3.h" #include "wasm3.h"
/* FIXME: remove when there is a public API to get function return value */ #include "m3_api_defs.h"
/* FIXME: remove when there is a public API to get module/function names */
#include "m3_env.h" #include "m3_env.h"
#define MAX_ARGS 32 #define MAX_ARGS 32
@ -153,7 +153,7 @@ static PyType_Slot M3_Runtime_Type_slots[] = {
static PyObject* static PyObject*
Module_name(m3_module *self, void * closure) Module_name(m3_module *self, void * closure)
{ {
return PyUnicode_FromString(self->m->name); return PyUnicode_FromString(self->m->name); // TODO
} }
static PyGetSetDef M3_Module_properties[] = { static PyGetSetDef M3_Module_properties[] = {
@ -182,18 +182,44 @@ put_arg_on_stack(u64 *s, M3ValueType type, PyObject *arg)
} }
static PyObject * static PyObject *
get_result_from_stack(IM3FuncType ftype, m3stack_t stack) get_result_from_stack(IM3Function f)
{ {
u8 type = GetSingleRetType(ftype); int nRets = m3_GetRetCount(f);
if (nRets <= 0) {
Py_RETURN_NONE;
}
if (nRets > 1) {
return PyErr_Format(PyExc_TypeError, "multi-value not supported yet");
}
if (nRets > MAX_ARGS) {
return PyErr_Format(PyExc_TypeError, "too many rets");
}
static uint64_t valbuff[MAX_ARGS];
static const void* valptrs[MAX_ARGS];
memset(valbuff, 0, sizeof(valbuff));
memset(valptrs, 0, sizeof(valptrs));
for (int i = 0; i < nRets; i++) {
valptrs[i] = &valbuff[i];
}
M3Result res = m3_GetResults (f, nRets, valptrs);
if (res) {
return PyErr_Format(PyExc_TypeError, "Error: %s", res);
}
int i = 0;
u8 type = m3_GetRetType(f, i);
switch (type) { switch (type) {
case c_m3Type_none: Py_RETURN_NONE; case c_m3Type_i32: return PyLong_FromLong( *(i32*)valptrs[i]); break;
case c_m3Type_i32: return PyLong_FromLong(*(i32*)(stack)); case c_m3Type_i64: return PyLong_FromLong( *(i64*)valptrs[i]); break;
case c_m3Type_i64: return PyLong_FromLong(*(i64*)(stack)); case c_m3Type_f32: return PyFloat_FromDouble(*(f32*)valptrs[i]); break;
case c_m3Type_f32: return PyFloat_FromDouble(*(f32*)(stack)); case c_m3Type_f64: return PyFloat_FromDouble(*(f64*)valptrs[i]); break;
case c_m3Type_f64: return PyFloat_FromDouble(*(f64*)(stack));
default: default:
return PyErr_Format(PyExc_TypeError, "unknown return type %d", (int)type); return PyErr_Format(PyExc_TypeError, "unknown return type %d", (int)type);
} }
} }
static PyObject * static PyObject *
@ -204,13 +230,13 @@ M3_Function_call_argv(m3_function *func, PyObject *args)
for(i = 0; i< size;++i) { for(i = 0; i< size;++i) {
argv[i] = PyUnicode_AsUTF8(PyTuple_GET_ITEM(args, i)); argv[i] = PyUnicode_AsUTF8(PyTuple_GET_ITEM(args, i));
} }
M3Result res = m3_CallWithArgs(func->f, size, argv); M3Result res = m3_CallArgV(func->f, size, argv);
if (res) { if (res) {
return PyErr_Format(PyExc_TypeError, "Error: %s", res); return PyErr_Format(PyExc_TypeError, "Error: %s", res);
} }
return get_result_from_stack(func->f->funcType, func->r->stack); return get_result_from_stack(func->f);
} }
static PyObject* static PyObject*
@ -219,36 +245,36 @@ M3_Function_call(m3_function *self, PyObject *args, PyObject *kwargs)
u32 i; u32 i;
IM3Function f = self->f; IM3Function f = self->f;
unsigned nArgs = m3_GetArgCount(f); int nArgs = m3_GetArgCount(f);
if (nArgs > MAX_ARGS) { if (nArgs > MAX_ARGS) {
return PyErr_Format(PyExc_TypeError, "too many args"); return PyErr_Format(PyExc_TypeError, "too many args");
} }
static uint64_t argsbuf[MAX_ARGS]; static uint64_t valbuff[MAX_ARGS];
static const void* argptrs[MAX_ARGS]; static const void* valptrs[MAX_ARGS];
memset(argsbuf, 0, sizeof(args)); memset(valbuff, 0, sizeof(args));
memset(argptrs, 0, sizeof(argptrs)); memset(valptrs, 0, sizeof(valptrs));
for (unsigned i = 0; i < nArgs; i++) { for (int i = 0; i < nArgs; i++) {
u64* s = &argsbuf[i]; u64* s = &valbuff[i];
argptrs[i] = s; valptrs[i] = s;
put_arg_on_stack(s, m3_GetArgType(f, i), PyTuple_GET_ITEM(args, i)); put_arg_on_stack(s, m3_GetArgType(f, i), PyTuple_GET_ITEM(args, i));
} }
M3Result res = m3_Call (f, nArgs, argptrs); M3Result res = m3_Call (f, nArgs, valptrs);
if (res) { if (res) {
return PyErr_Format(PyExc_TypeError, "Error: %s", res); return PyErr_Format(PyExc_TypeError, "Error: %s", res);
} }
return get_result_from_stack(f->funcType, self->r->stack); return get_result_from_stack(f);
} }
static PyObject* static PyObject*
Function_name(m3_function *self, void * closure) Function_name(m3_function *self, void * closure)
{ {
return PyUnicode_FromString(self->f->name); return PyUnicode_FromString(self->f->name); // TODO
} }
static PyObject* static PyObject*
@ -258,9 +284,9 @@ Function_num_args(m3_function *self, void * closure)
} }
static PyObject* static PyObject*
Function_return_type(m3_function *self, void * closure) Function_num_rets(m3_function *self, void * closure)
{ {
return PyLong_FromLong(GetSingleRetType(self->f->funcType)); return PyLong_FromLong(m3_GetRetCount(self->f));
} }
static PyObject* static PyObject*
@ -277,11 +303,26 @@ Function_arg_types(m3_function *self, void * closure)
return ret; return ret;
} }
static PyObject*
Function_ret_types(m3_function *self, void * closure)
{
Py_ssize_t nRets = m3_GetRetCount(self->f);
PyObject *ret = PyTuple_New(nRets);
if (ret) {
Py_ssize_t i;
for (i = 0; i < nRets; ++i) {
PyTuple_SET_ITEM(ret, i, PyLong_FromLong(m3_GetRetType(self->f, i)));
}
}
return ret;
}
static PyGetSetDef M3_Function_properties[] = { static PyGetSetDef M3_Function_properties[] = {
{"name", (getter) Function_name, NULL, "function name", NULL }, {"name", (getter) Function_name, NULL, "function name", NULL },
{"num_args", (getter) Function_num_args, NULL, "number of args", NULL }, {"num_args", (getter) Function_num_args, NULL, "number of args", NULL },
{"return_type", (getter) Function_return_type, NULL, "return type", NULL }, {"num_rets", (getter) Function_num_rets, NULL, "number of rets", NULL },
{"arg_types", (getter) Function_arg_types, NULL, "types of args", NULL }, {"arg_types", (getter) Function_arg_types, NULL, "types of args", NULL },
{"ret_types", (getter) Function_ret_types, NULL, "types of rets", NULL },
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };

@ -54,8 +54,9 @@ def test_m3(capfd):
assert func.call_argv('10') == 55 assert func.call_argv('10') == 55
assert func.name == 'fib' assert func.name == 'fib'
assert func.num_args == 1 assert func.num_args == 1
assert func.return_type == 1 assert func.num_rets == 1
assert func.arg_types == (1,) assert func.arg_types == (1,)
assert func.ret_types == (1,)
assert func(0) == 0 assert func(0) == 0
assert func(1) == 1 assert func(1) == 1
rt.load(env.parse_module(ADD_WASM)) rt.load(env.parse_module(ADD_WASM))

@ -46,10 +46,9 @@ void run_wasm()
printf("Running...\n"); printf("Running...\n");
const char* i_argv[2] = { "24", NULL }; result = m3_CallV (f, 24);
result = m3_CallWithArgs (f, 1, i_argv);
if (result) FATAL("m3_CallWithArgs: %s", result); if (result) FATAL("m3_Call: %s", result);
//long value = *(uint64_t*)(runtime->stack); //long value = *(uint64_t*)(runtime->stack);
//printf("Result: %ld\n", value); //printf("Result: %ld\n", value);

@ -83,10 +83,10 @@ d_m3TraceMemory( load_val_i32, "load i32", int32_t, "%" PRIi32)
d_m3TraceMemory(store_val_i32, "store i32", int32_t, "%" PRIi32) d_m3TraceMemory(store_val_i32, "store i32", int32_t, "%" PRIi32)
d_m3TraceMemory( load_val_i64, "load i64", int64_t, "%" PRIi64) d_m3TraceMemory( load_val_i64, "load i64", int64_t, "%" PRIi64)
d_m3TraceMemory(store_val_i64, "store i64", int64_t, "%" PRIi64) d_m3TraceMemory(store_val_i64, "store i64", int64_t, "%" PRIi64)
d_m3TraceMemory( load_val_f32, "load f32", float, "%f") d_m3TraceMemory( load_val_f32, "load f32", float, "%" PRIf32)
d_m3TraceMemory(store_val_f32, "store f32", float, "%f") d_m3TraceMemory(store_val_f32, "store f32", float, "%" PRIf32)
d_m3TraceMemory( load_val_f64, "load f64", double, "%lf") d_m3TraceMemory( load_val_f64, "load f64", double, "%" PRIf64)
d_m3TraceMemory(store_val_f64, "store f64", double, "%lf") d_m3TraceMemory(store_val_f64, "store f64", double, "%" PRIf64)
#define d_m3TraceLocal(FUNC, NAME, TYPE, FMT) \ #define d_m3TraceLocal(FUNC, NAME, TYPE, FMT) \
@ -105,10 +105,10 @@ d_m3TraceLocal(get_i32, "get i32", int32_t, "%" PRIi32)
d_m3TraceLocal(set_i32, "set i32", int32_t, "%" PRIi32) d_m3TraceLocal(set_i32, "set i32", int32_t, "%" PRIi32)
d_m3TraceLocal(get_i64, "get i64", int64_t, "%" PRIi64) d_m3TraceLocal(get_i64, "get i64", int64_t, "%" PRIi64)
d_m3TraceLocal(set_i64, "set i64", int64_t, "%" PRIi64) d_m3TraceLocal(set_i64, "set i64", int64_t, "%" PRIi64)
d_m3TraceLocal(get_f32, "get f32", float, "%f") d_m3TraceLocal(get_f32, "get f32", float, "%" PRIf32)
d_m3TraceLocal(set_f32, "set f32", float, "%f") d_m3TraceLocal(set_f32, "set f32", float, "%" PRIf32)
d_m3TraceLocal(get_f64, "get f64", double, "%lf") d_m3TraceLocal(get_f64, "get f64", double, "%" PRIf64)
d_m3TraceLocal(set_f64, "set f64", double, "%lf") d_m3TraceLocal(set_f64, "set f64", double, "%" PRIf64)
static static

@ -938,7 +938,7 @@ M3Result Compile_Const_f32 (IM3Compilation o, m3opcode_t i_opcode)
union { u32 u; f32 f; } value = { 0 }; union { u32 u; f32 f; } value = { 0 };
_ (Read_f32 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (const f32 = %f)", get_indention_string (o), value.f); _ (Read_f32 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (const f32 = %" PRIf32 ")", get_indention_string (o), value.f);
_ (PushConst (o, value.u, c_m3Type_f32)); _ (PushConst (o, value.u, c_m3Type_f32));
_catch: return result; _catch: return result;
@ -951,7 +951,7 @@ M3Result Compile_Const_f64 (IM3Compilation o, m3opcode_t i_opcode)
union { u64 u; f64 f; } value = { 0 }; union { u64 u; f64 f; } value = { 0 };
_ (Read_f64 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (const f64 = %lf)", get_indention_string (o), value.f); _ (Read_f64 (& value.f, & o->wasm, o->wasmEnd)); m3log (compile, d_indent " (const f64 = %" PRIf64 ")", get_indention_string (o), value.f);
_ (PushConst (o, value.u, c_m3Type_f64)); _ (PushConst (o, value.u, c_m3Type_f64));
_catch: return result; _catch: return result;

@ -43,6 +43,9 @@ typedef uint8_t u8;
typedef int8_t i8; typedef int8_t i8;
#endif // d_m3ShortTypesDefined #endif // d_m3ShortTypesDefined
#define PRIf32 "f"
#define PRIf64 "lf"
typedef const void * m3ret_t; typedef const void * m3ret_t;
typedef const void * voidptr_t; typedef const void * voidptr_t;
typedef const char * cstr_t; typedef const char * cstr_t;

@ -781,113 +781,180 @@ M3ValueType m3_GetRetType (IM3Function i_function, uint32_t index)
return c_m3Type_none; return c_m3Type_none;
} }
M3Result m3_CallVariadic (IM3Function i_function, uint32_t i_argc, ...) M3Result m3_CallV (IM3Function i_function, ...)
{ {
va_list ap; va_list ap;
va_start(ap, i_argc); va_start(ap, i_function);
M3Result r = m3_CallWithVaList(i_function, i_argc, ap); M3Result r = m3_CallVL(i_function, ap);
va_end(ap); va_end(ap);
return r; return r;
} }
M3Result m3_CallWithVaList (IM3Function i_function, uint32_t i_argc, va_list i_args) M3Result m3_CallVL (IM3Function i_function, va_list i_args)
{ {
IM3Runtime runtime = i_function->module->runtime;
IM3FuncType ftype = i_function->funcType; IM3FuncType ftype = i_function->funcType;
if (i_argc != ftype->numArgs) {
return m3Err_argumentCountMismatch;
}
if (!i_function->compiled) { if (!i_function->compiled) {
return m3Err_missingCompiledCode; return m3Err_missingCompiledCode;
} }
IM3Runtime runtime = i_function->module->runtime;
// args are always 64-bit aligned
u64* stack = (u64*) runtime->stack;
u8* s = (u8*) runtime->stack;
for (u32 i = 0; i < ftype->numArgs; ++i) for (u32 i = 0; i < ftype->numArgs; ++i)
{ {
u64* s = & stack[i];
switch (d_FuncArgType(ftype, i)) { switch (d_FuncArgType(ftype, i)) {
case c_m3Type_i32: *(i32*)(s) = va_arg(i_args, i32); break; case c_m3Type_i32: *(i32*)(s) = va_arg(i_args, i32); s += 8; break;
case c_m3Type_i64: *(i64*)(s) = va_arg(i_args, i64); break; case c_m3Type_i64: *(i64*)(s) = va_arg(i_args, i64); s += 8; break;
case c_m3Type_f32: *(f32*)(s) = va_arg(i_args, f64); break; // f32 is passed as f64 case c_m3Type_f32: *(f32*)(s) = va_arg(i_args, f64); s += 8; break; // f32 is passed as f64
case c_m3Type_f64: *(f64*)(s) = va_arg(i_args, f64); break; case c_m3Type_f64: *(f64*)(s) = va_arg(i_args, f64); s += 8; break;
default: return "unknown argument type"; default: return "unknown argument type";
} }
} }
m3StackCheckInit(); m3StackCheckInit();
return (M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memory.mallocated, d_m3OpDefaultArgs); M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs);
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_Call (IM3Function i_function, uint32_t i_argc, const void * i_argptrs[]) M3Result m3_Call (IM3Function i_function, uint32_t i_argc, const void * i_argptrs[])
{ {
IM3Runtime runtime = i_function->module->runtime;
IM3FuncType ftype = i_function->funcType; IM3FuncType ftype = i_function->funcType;
if (i_argc != ftype->numArgs) { if (i_argc != ftype->numArgs) {
return m3Err_argumentCountMismatch; return m3Err_argumentCountMismatch;
} }
if (!i_function->compiled) { if (!i_function->compiled) {
return m3Err_missingCompiledCode; return m3Err_missingCompiledCode;
} }
IM3Runtime runtime = i_function->module->runtime;
// args are always 64-bit aligned
u64* stack = (u64*) runtime->stack;
u8* s = (u8*) runtime->stack;
for (u32 i = 0; i < ftype->numArgs; ++i) for (u32 i = 0; i < ftype->numArgs; ++i)
{ {
u64* s = & stack[i];
switch (d_FuncArgType(ftype, i)) { switch (d_FuncArgType(ftype, i)) {
case c_m3Type_i32: *(i32*)(s) = *(i32*)i_argptrs[i]; break; case c_m3Type_i32: *(i32*)(s) = *(i32*)i_argptrs[i]; s += 8; break;
case c_m3Type_i64: *(i64*)(s) = *(i64*)i_argptrs[i]; break; case c_m3Type_i64: *(i64*)(s) = *(i64*)i_argptrs[i]; s += 8; break;
case c_m3Type_f32: *(f32*)(s) = *(f32*)i_argptrs[i]; break; case c_m3Type_f32: *(f32*)(s) = *(f32*)i_argptrs[i]; s += 8; break;
case c_m3Type_f64: *(f64*)(s) = *(f64*)i_argptrs[i]; break; case c_m3Type_f64: *(f64*)(s) = *(f64*)i_argptrs[i]; s += 8; break;
default: return "unknown argument type"; default: return "unknown argument type";
} }
} }
m3StackCheckInit(); m3StackCheckInit();
return (M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memory.mallocated, d_m3OpDefaultArgs); M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs);
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_CallWithArgs (IM3Function i_function, uint32_t i_argc, const char * i_argv[]) M3Result m3_CallArgV (IM3Function i_function, uint32_t i_argc, const char * i_argv[])
{ {
IM3FuncType ftype = i_function->funcType; IM3FuncType ftype = i_function->funcType;
IM3Runtime runtime = i_function->module->runtime;
if (i_argc != ftype->numArgs) { if (i_argc != ftype->numArgs) {
return m3Err_argumentCountMismatch; return m3Err_argumentCountMismatch;
} }
if (!i_function->compiled) { if (!i_function->compiled) {
return m3Err_missingCompiledCode; return m3Err_missingCompiledCode;
} }
IM3Runtime runtime = i_function->module->runtime;
// args are always 64-bit aligned
u64* stack = (u64*) runtime->stack;
u8* s = (u8*) runtime->stack;
for (u32 i = 0; i < ftype->numArgs; ++i) for (u32 i = 0; i < ftype->numArgs; ++i)
{ {
u64* s = & stack[i];
switch (d_FuncArgType(ftype, i)) { switch (d_FuncArgType(ftype, i)) {
case c_m3Type_i32: *(i32*)(s) = strtoul(i_argv[i], NULL, 10); break; 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); break; case c_m3Type_i64: *(i64*)(s) = strtoull(i_argv[i], NULL, 10); s += 8; break;
case c_m3Type_f32: *(f32*)(s) = strtod(i_argv[i], NULL); break; 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); break; case c_m3Type_f64: *(f64*)(s) = strtod(i_argv[i], NULL); s += 8; break;
default: return "unknown argument type"; default: return "unknown argument type";
} }
} }
m3StackCheckInit(); m3StackCheckInit();
M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t) stack, runtime->memory.mallocated, d_m3OpDefaultArgs); M3Result r = (M3Result) Call (i_function->compiled, (m3stack_t)(runtime->stack), runtime->memory.mallocated, d_m3OpDefaultArgs);
runtime->lastCalled = r ? NULL : i_function;
#if d_m3LogNativeStack #if d_m3LogNativeStack
int stackUsed = m3StackGetMax(); int stackUsed = m3StackGetMax();
fprintf (stderr, "Native stack used: %d\n", stackUsed); fprintf (stderr, "Native stack used: %d\n", stackUsed);
#endif // d_m3LogNativeStack #endif
return r; return r;
} }
M3Result m3_GetResults (IM3Function i_function, uint32_t i_retc, const void * o_retptrs[])
{
IM3FuncType ftype = i_function->funcType;
IM3Runtime runtime = i_function->module->runtime;
if (i_retc != ftype->numRets) {
return m3Err_argumentCountMismatch;
}
if (i_function != runtime->lastCalled) {
return "function not called";
}
u8* s = (u8*) runtime->stack;
for (u32 i = 0; i < ftype->numRets; ++i)
{
switch (d_FuncRetType(ftype, i)) {
case c_m3Type_i32: *(i32*)o_retptrs[i] = *(i32*)(s); s += 8; break;
case c_m3Type_i64: *(i64*)o_retptrs[i] = *(i64*)(s); s += 8; break;
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;
default: return "unknown return type";
}
}
return m3Err_none;
}
M3Result m3_GetResultsV (IM3Function i_function, ...)
{
va_list ap;
va_start(ap, i_function);
M3Result r = m3_GetResultsVL(i_function, ap);
va_end(ap);
return r;
}
M3Result m3_GetResultsVL (IM3Function i_function, va_list o_rets)
{
IM3Runtime runtime = i_function->module->runtime;
IM3FuncType ftype = i_function->funcType;
if (i_function != runtime->lastCalled) {
return "function not called";
}
u8* s = (u8*) runtime->stack;
for (u32 i = 0; i < ftype->numRets; ++i)
{
switch (d_FuncRetType(ftype, i)) {
case c_m3Type_i32: *va_arg(o_rets, i32*) = *(i32*)(s); s += 8; break;
case c_m3Type_i64: *va_arg(o_rets, i64*) = *(i64*)(s); s += 8; break;
case c_m3Type_f32: *va_arg(o_rets, f32*) = *(f32*)(s); s += 8; break;
case c_m3Type_f64: *va_arg(o_rets, f64*) = *(f64*)(s); s += 8; break;
default: return "unknown argument type";
}
}
return m3Err_none;
}
void ReleaseCodePageNoTrack (IM3Runtime i_runtime, IM3CodePage i_codePage) void ReleaseCodePageNoTrack (IM3Runtime i_runtime, IM3CodePage i_codePage)
{ {
if (i_codePage) if (i_codePage)
@ -978,9 +1045,9 @@ M3Result m3Error (M3Result i_result, IM3Runtime i_runtime, IM3Module i_module,
#endif #endif
void m3_GetErrorInfo (IM3Runtime i_runtime, M3ErrorInfo* info) void m3_GetErrorInfo (IM3Runtime i_runtime, M3ErrorInfo* o_info)
{ {
*info = i_runtime->error; *o_info = i_runtime->error;
m3_ResetErrorInfo (i_runtime); m3_ResetErrorInfo (i_runtime);
} }

@ -218,6 +218,7 @@ typedef struct M3Runtime
void * stack; void * stack;
u32 stackSize; u32 stackSize;
u32 numStackSlots; u32 numStackSlots;
IM3Function lastCalled; // last function that successfully executed
void * userdata; void * userdata;

@ -558,10 +558,10 @@ d_m3Op (CallRawFunction)
for (int i=0; i<nArgs; i++) { for (int i=0; i<nArgs; i++) {
const int type = ftype->types[nRets + i]; const int type = ftype->types[nRets + i];
switch (type) { switch (type) {
case c_m3Type_i32: outp += snprintf(outp, oute-outp, "%i", *(i32*)(sp+i)); break; case c_m3Type_i32: outp += snprintf(outp, oute-outp, "%" PRIi32, *(i32*)(sp+i)); break;
case c_m3Type_i64: outp += snprintf(outp, oute-outp, "%lli", *(i64*)(sp+i)); break; case c_m3Type_i64: outp += snprintf(outp, oute-outp, "%" PRIi64, *(i64*)(sp+i)); break;
case c_m3Type_f32: outp += snprintf(outp, oute-outp, "%f", *(f32*)(sp+i)); break; case c_m3Type_f32: outp += snprintf(outp, oute-outp, "%" PRIf32, *(f32*)(sp+i)); break;
case c_m3Type_f64: outp += snprintf(outp, oute-outp, "%lf", *(f64*)(sp+i)); break; case c_m3Type_f64: outp += snprintf(outp, oute-outp, "%" PRIf64, *(f64*)(sp+i)); break;
default: outp += snprintf(outp, oute-outp, "<unknown type %d>", type); break; default: outp += snprintf(outp, oute-outp, "<unknown type %d>", type); break;
} }
outp += snprintf(outp, oute-outp, (i < nArgs-1) ? ", " : ")"); outp += snprintf(outp, oute-outp, (i < nArgs-1) ? ", " : ")");
@ -576,10 +576,10 @@ d_m3Op (CallRawFunction)
} else { } else {
switch (GetSingleRetType(ftype)) { switch (GetSingleRetType(ftype)) {
case c_m3Type_none: fprintf(out, "%s\n", outbuff); break; case c_m3Type_none: fprintf(out, "%s\n", outbuff); break;
case c_m3Type_i32: fprintf(out, "%s = %i\n", outbuff, *(i32*)sp); break; case c_m3Type_i32: fprintf(out, "%s = %" PRIi32 "\n", outbuff, *(i32*)sp); break;
case c_m3Type_i64: fprintf(out, "%s = %lli\n", outbuff, *(i64*)sp); break; case c_m3Type_i64: fprintf(out, "%s = %" PRIi64 "\n", outbuff, *(i64*)sp); break;
case c_m3Type_f32: fprintf(out, "%s = %f\n", outbuff, *(f32*)sp); break; case c_m3Type_f32: fprintf(out, "%s = %" PRIf32 "\n", outbuff, *(f32*)sp); break;
case c_m3Type_f64: fprintf(out, "%s = %lf\n", outbuff, *(f64*)sp); break; case c_m3Type_f64: fprintf(out, "%s = %" PRIf64 "\n", outbuff, *(f64*)sp); break;
} }
} }
#endif #endif
@ -861,8 +861,9 @@ d_m3Op (DumpStack)
printf (" %4d ", opcodeIndex); printf (" %4d ", opcodeIndex);
printf (" %-25s r0: 0x%016" PRIx64 " i:%" PRIi64 " u:%" PRIu64 "\n", funcName, _r0, _r0, _r0); printf (" %-25s r0: 0x%016" PRIx64 " i:%" PRIi64 " u:%" PRIu64 "\n", funcName, _r0, _r0, _r0);
printf (" fp0: %lf\n", _fp0); #if d_m3HasFloat
printf (" fp0: %" PRIf64 "\n", _fp0);
#endif
m3stack_t sp = _sp; m3stack_t sp = _sp;
for (u32 i = 0; i < stackHeight; ++i) for (u32 i = 0; i < stackHeight; ++i)

@ -100,9 +100,9 @@ size_t SPrintArg (char * o_string, size_t i_n, m3stack_t i_sp, u8 i_type)
len = snprintf (o_string, i_n, "%" PRIi64, * (i64 *) i_sp); len = snprintf (o_string, i_n, "%" PRIi64, * (i64 *) i_sp);
#if d_m3HasFloat #if d_m3HasFloat
else if (i_type == c_m3Type_f32) else if (i_type == c_m3Type_f32)
len = snprintf (o_string, i_n, "%f", * (f32 *) i_sp); len = snprintf (o_string, i_n, "%" PRIf32, * (f32 *) i_sp);
else if (i_type == c_m3Type_f64) else if (i_type == c_m3Type_f64)
len = snprintf (o_string, i_n, "%lf", * (f64 *) i_sp); len = snprintf (o_string, i_n, "%" PRIf64, * (f64 *) i_sp);
#endif #endif
len = M3_MAX (0, len); len = M3_MAX (0, len);

@ -208,17 +208,21 @@ d_m3ErrorConst (trapStackOverflow, "[trap] stack overflow")
uint32_t m3_GetArgCount (IM3Function i_function); uint32_t m3_GetArgCount (IM3Function i_function);
uint32_t m3_GetRetCount (IM3Function i_function); uint32_t m3_GetRetCount (IM3Function i_function);
M3ValueType m3_GetArgType (IM3Function i_function, uint32_t index); M3ValueType m3_GetArgType (IM3Function i_function, uint32_t i_index);
M3ValueType m3_GetRetType (IM3Function i_function, uint32_t index); M3ValueType m3_GetRetType (IM3Function i_function, uint32_t i_index);
M3Result m3_CallVariadic (IM3Function i_function, uint32_t i_argc, ...); M3Result m3_CallV (IM3Function i_function, ...);
M3Result m3_CallWithVaList (IM3Function i_function, uint32_t i_argc, va_list i_args); M3Result m3_CallVL (IM3Function i_function, va_list i_args);
M3Result m3_Call (IM3Function i_function, uint32_t i_argc, const void * i_argptrs[]); M3Result m3_Call (IM3Function i_function, uint32_t i_argc, const void * i_argptrs[]);
M3Result m3_CallWithArgs (IM3Function i_function, uint32_t i_argc, const char * i_argv[]); M3Result m3_CallArgV (IM3Function i_function, uint32_t i_argc, const char * i_argv[]);
M3Result m3_GetResultsV (IM3Function i_function, ...);
M3Result m3_GetResultsVL (IM3Function i_function, va_list o_rets);
M3Result m3_GetResults (IM3Function i_function, uint32_t i_retc, const void * o_retptrs[]);
// IM3Functions are valid during the lifetime of the originating runtime // IM3Functions are valid during the lifetime of the originating runtime
void m3_GetErrorInfo (IM3Runtime i_runtime, M3ErrorInfo* info); void m3_GetErrorInfo (IM3Runtime i_runtime, M3ErrorInfo* o_info);
void m3_ResetErrorInfo (IM3Runtime i_runtime); void m3_ResetErrorInfo (IM3Runtime i_runtime);
//------------------------------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------------------------------

Loading…
Cancel
Save