More WASM fixes, with this I can get half of the mini test suite to run without crashing.
static MonoObject*
mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
{
+#ifdef HOST_WASM
+ return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
+#else
MONO_REQ_GC_UNSAFE_MODE;
RuntimeInvokeFunction runtime_invoke;
runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
+#endif
}
/**
* mono_async_result_new:
{
scan_area_arg_start = start_nursery;
scan_area_arg_end = end_nursery;
+#ifdef HOST_WASM
+ //Under WASM we don't scan thread stacks and we can't trust the values we find there either.
+ return;
+#endif
FOREACH_THREAD (info) {
int skip_reason = 0;
#if !defined(MONO_CROSS_COMPILE) && MONO_ARCH_HAS_MONO_CONTEXT
MONO_CONTEXT_GET_CURRENT (info->client_info.ctx);
+#elif defined (HOST_WASM)
+ //nothing
#else
g_error ("Sgen STW requires a working mono-context");
#endif
} pair;
} interp_pair;
+static void
+wasm_invoke_l (void *target_func, InterpMethodArguments *margs)
+{
+ gint64 (*func)(void) = target_func;
+
+ gint64 res = func ();
+ *(gint64*)margs->retval = res;
+}
+
static void
wasm_invoke_ll (void *target_func, InterpMethodArguments *margs)
{
*(float*)&margs->iargs [1]);
}
+static void
+wasm_invoke_ff (void *target_func, InterpMethodArguments *margs)
+{
+ float (*func)(float a) = target_func;
+
+ float res = func (*(float*)&margs->fargs [FIDX (0)]);
+ *(float*)margs->retval = res;
+}
+
static void
wasm_enter_icall_trampoline (void *target_func, InterpMethodArguments *margs)
{
wasm_invoke_iiiii (target_func, margs);
else if (!strcmp ("IIIIII", cookie))
wasm_invoke_iiiiii (target_func, margs);
+ else if (!strcmp ("L", cookie))
+ wasm_invoke_l (target_func, margs);
else if (!strcmp ("LL", cookie))
wasm_invoke_ll (target_func, margs);
else if (!strcmp ("LI", cookie))
wasm_invoke_viffff (target_func, margs);
else if (!strcmp ("VIFFFFFI", cookie))
wasm_invoke_vifffffi (target_func, margs);
+ else if (!strcmp ("FF", cookie))
+ wasm_invoke_ff (target_func, margs);
else {
printf ("CANNOT HANDLE COOKIE %s\n", cookie);
g_assert (0);
public delegate void ArrayDelegate (int[,] arr);
+ [Category ("!WASM")] //Requires a working threadpool
static int test_0_array_delegate_full_aot () {
ArrayDelegate d = delegate (int[,] arr) {
};
[Category ("DYNCALL")]
[Category ("!FULLAOT-AMD64")]
+ [Category ("!INTERPRETER")] //known bug in the interpreter
public static int test_0_dyncall_nullable () {
int? v;
[Category ("DYNCALL")]
[Category ("!FULLAOT-AMD64")]
+ [Category ("!INTERPRETER")] //known bug in the interpreter
public static int test_0_large_nullable_invoke () {
var s = new LargeStruct () { a = 1, b = 2, c = 3, d = 4 };
return 0;
}
+#if !__MOBILE__
public static int Main (String[] args) {
return TestDriver.RunTests (typeof (BuiltinTests), args);
}
+#endif
}
}
-class Tests {
+class DevirtualizationTests {
+#if !__MOBILE__
static int Main (string[] args) {
- return TestDriver.RunTests (typeof (Tests), args);
+ return TestDriver.RunTests (typeof (DevirtualizationTests), args);
}
+#endif
static public int test_0_sealed_class_devirt_right_method () {
SealedFinal x = new SealedFinal ();
return 0;
}
+ [Category ("!WASM")] // reported as https://github.com/kripken/emscripten/issues/5603
public static int test_0_simple_double_casts () {
double d = 0xffffffff;
/*
* Regression tests for the GC support in the JIT
*/
-
-class Tests {
-
- static int Main () {
- return TestDriver.RunTests (typeof (Tests));
- }
+#if __MOBILE__
+class GcTests
+#else
+class Tests
+#endif
+{
+#if !__MOBILE__
+ public static int Main (string[] args) {
+ return TestDriver.RunTests (typeof (Tests), args);
+ }
+#endif
public static int test_36_simple () {
// Overflow the registers
return 0;
}
+ class ObjWithShiftOp {
+ public static ObjWithShiftOp operator >> (ObjWithShiftOp bi1, int shiftVal) {
+ clobber_regs_and_gc ();
+ return bi1;
+ }
+ }
+
// Liveness for spill slots holding managed pointers
public static int test_0_liveness_11 () {
- Tests[] arr = new Tests [10];
+ ObjWithShiftOp[] arr = new ObjWithShiftOp [10];
// This uses an ldelema internally
// FIXME: This doesn't crash if mp-s are not correctly tracked, just writes to
// an old object.
return 0;
}
- public static Tests operator >> (Tests bi1, int shiftVal) {
- clobber_regs_and_gc ();
- return bi1;
- }
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void liveness_12_inner (int a, int b, int c, int d, int e, int f, object o, ref string s) {
/* needed on arm64 */
if (isinf (sp [-1].data.f))
sp [-1].data.i = 0;
+ /* needed by wasm */
+ else if (isnan (sp [-1].data.f))
+ sp [-1].data.i = 0;
else
sp [-1].data.i = (guint32)sp [-1].data.f;
++ip;
return;
} else {
/* mheader might not exist if this is a delegate invoc, etc */
- if (mheader && *mheader->code == CEE_RET && called_inited) {
+ gboolean has_vt_arg = FALSE;
+ for (i = 0; i < csignature->param_count; i++)
+ has_vt_arg |= !mini_type_is_reference (csignature->params [i]);
+
+ if (mheader && *mheader->code == CEE_RET && called_inited && !has_vt_arg) {
if (td->verbose_level)
g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name);
for (i = 0; i < csignature->param_count; i++) {
MonoException *
mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context)
{
+ MonoError error;
int i, align, size, offset;
MonoMethod *method = imethod->method;
MonoImage *image = method->klass->image;
MonoDomain *domain = imethod->domain;
// g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name);
- method_class_vt = mono_class_vtable (domain, imethod->method->klass);
+ method_class_vt = mono_class_vtable_full (domain, imethod->method->klass, &error);
+ if (!is_ok (&error))
+ return mono_error_convert_to_exception (&error);
+
if (!method_class_vt->initialized) {
- MonoError error;
jmp_buf env;
InterpFrame *last_env_frame = context->env_frame;
jmp_buf *old_env = context->current_env;
break;
case MonoInlineMethod:
if (method->wrapper_type == MONO_WRAPPER_NONE && *ip != CEE_CALLI) {
- m = mono_get_method_full (image, read32 (ip + 1), NULL, generic_context);
- if (m == NULL) {
+ m = mono_get_method_checked (image, read32 (ip + 1), NULL, generic_context, &error);
+ if (!is_ok (&error)) {
g_free (is_bb_start);
- g_error ("FIXME: where to get method and class string?");
- return NULL;
- // return mono_get_exception_missing_method ();
+ return mono_error_convert_to_exception (&error);
}
mono_class_init (m->klass);
if (!mono_class_is_interface (m->klass))
if (mono_ex->trace_ips) {
GList *trace_ips = NULL;
- gpointer ip = RETURN_ADDRESS ();
+ gpointer ip = MONO_RETURN_ADDRESS ();
size_t upper = mono_array_length (mono_ex->trace_ips);
/* regression test suite */
if (!strcmp ("builtin-types", klass->image->assembly_name))
return TRUE;
+ if (!strcmp ("mini_tests", klass->image->assembly_name))
+ return TRUE;
return FALSE;
}
void
mini_init_delegate (MonoDelegate *del)
{
- if (mono_llvm_only)
- del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
#ifdef ENABLE_INTERPRETER
if (mono_use_interpreter)
mono_interp_init_delegate (del);
+ else
#endif
+ if (mono_llvm_only)
+ del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
}
char*
#if defined (HOST_WASM)
-#define RETURN_ADDRESS_N(N) NULL
-#define RETURN_ADDRESS() RETURN_ADDRESS_N(0)
+#define MONO_RETURN_ADDRESS_N(N) NULL
+#define MONO_RETURN_ADDRESS() MONO_RETURN_ADDRESS_N(0)
#elif defined (__GNUC__)
-#define RETURN_ADDRESS_N(N) (__builtin_extract_return_addr (__builtin_return_address (N)))
-#define RETURN_ADDRESS() RETURN_ADDRESS_N(0)
+#define MONO_RETURN_ADDRESS_N(N) (__builtin_extract_return_addr (__builtin_return_address (N)))
+#define MONO_RETURN_ADDRESS() MONO_RETURN_ADDRESS_N(0)
#elif defined(_MSC_VER)
#include <intrin.h>
#pragma intrinsic(_ReturnAddress)
-#define RETURN_ADDRESS() _ReturnAddress()
-#define RETURN_ADDRESS_N(N) NULL
+#define MONO_RETURN_ADDRESS() _ReturnAddress()
+#define MONO_RETURN_ADDRESS_N(N) NULL
#else
return a;
}
+#if __MOBILE__
+ public static test_2_old_test_suite () {
+ return test1 (1);
+ }
+#else
static int Main() {
if (test1 (1) != 2)
return 1;
return 0;
}
+#endif
}
}
g_free (fname);
if (!ebp) {
- printf (") ip: %p\n", RETURN_ADDRESS_N (1));
+ printf (") ip: %p\n", MONO_RETURN_ADDRESS_N (1));
goto unlock;
}
if (method->is_inflated) {
/* FIXME: Might be better to pass the ji itself */
- MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)RETURN_ADDRESS (), NULL);
+ MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)MONO_RETURN_ADDRESS (), NULL);
if (ji) {
gsctx = mono_jit_info_get_generic_sharing_context (ji);
if (gsctx && gsctx->is_gsharedvt) {
if (method->is_inflated) {
/* FIXME: Might be better to pass the ji itself */
- MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)RETURN_ADDRESS (), NULL);
+ MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (char *)MONO_RETURN_ADDRESS (), NULL);
if (ji) {
gsctx = mono_jit_info_get_generic_sharing_context (ji);
if (gsctx && gsctx->is_gsharedvt) {
printf ("(unknown return type %x)", mono_method_signature (method)->ret->type);
}
- //printf (" ip: %p\n", RETURN_ADDRESS_N (1));
+ //printf (" ip: %p\n", MONO_RETURN_ADDRESS_N (1));
printf ("\n");
fflush (stdout);
#endif
#endif
-#if defined (TARGET_WASM)
+#if defined (HOST_WASM)
#define DEFAULT_MAJOR SGEN_MAJOR_SERIAL
#define DEFAULT_SWEEP_MODE SGEN_SWEEP_SERIAL
#elif defined(HAVE_CONC_GC_AS_DEFAULT)
* LOCKING: Assumes the GC lock is held.
*/
void
-sgen_perform_collection (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish, gboolean stw)
+sgen_perform_collection_inner (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish, gboolean stw)
{
TV_DECLARE (gc_total_start);
TV_DECLARE (gc_total_end);
sgen_restart_world (oldest_generation_collected);
}
+#ifdef HOST_WASM
+
+typedef struct {
+ size_t requested_size;
+ int generation_to_collect;
+ const char *reason;
+} SgenGcRequest;
+
+static SgenGcRequest gc_request;
+static gboolean pending_request;
+
+extern void request_gc_cycle (void);
+
+#include <emscripten.h>
+
+EMSCRIPTEN_KEEPALIVE void
+mono_gc_pump_callback (void)
+{
+ if (!pending_request)
+ return;
+ pending_request = FALSE;
+ sgen_perform_collection_inner (gc_request.requested_size, gc_request.generation_to_collect, gc_request.reason, TRUE, TRUE);
+}
+#endif
+
+void
+sgen_perform_collection (size_t requested_size, int generation_to_collect, const char *reason, gboolean wait_to_finish, gboolean stw)
+{
+#ifdef HOST_WASM
+ g_assert (stw); //can't handle non-stw mode (IE, domain unload)
+ //we ignore wait_to_finish
+ if (!pending_request || gc_request.generation_to_collect <= generation_to_collect) { //no active request or request was for a smaller part of the heap
+ gc_request.requested_size = requested_size;
+ gc_request.generation_to_collect = generation_to_collect;
+ gc_request.reason = reason;
+ if (!pending_request) {
+ request_gc_cycle ();
+ pending_request = TRUE;
+ }
+ }
+
+ degraded_mode = 1; //enable degraded mode so allocation can continue
+#else
+ sgen_perform_collection_inner (requested_size, generation_to_collect, reason, wait_to_finish, stw);
+#endif
+}
/*
* ######################################################################
* ######## Memory allocation from the OS