Merge pull request #5560 from kumpera/wasm-work-p3
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Thu, 28 Sep 2017 22:06:02 +0000 (18:06 -0400)
committerGitHub <noreply@github.com>
Thu, 28 Sep 2017 22:06:02 +0000 (18:06 -0400)
More WASM fixes, with this I can get half of the mini test suite to run without crashing.

19 files changed:
mono/metadata/object.c
mono/metadata/sgen-mono.c
mono/metadata/sgen-stw.c
mono/mini/aot-runtime-wasm.c
mono/mini/aot-tests.cs
mono/mini/builtin-types.cs
mono/mini/devirtualization.cs
mono/mini/exceptions.cs
mono/mini/gc-test.cs
mono/mini/interp/interp.c
mono/mini/interp/transform.c
mono/mini/mini-exceptions.c
mono/mini/mini-native-types.c
mono/mini/mini-runtime.c
mono/mini/mini.h
mono/mini/test.cs
mono/mini/trace.c
mono/sgen/sgen-conf.h
mono/sgen/sgen-gc.c

index 9ace3f66652855063c4af180e32252fb48708dc2..457c50e02cc115b4deeeaa547ff0453ef9df24c5 100644 (file)
@@ -7410,6 +7410,9 @@ mono_wait_handle_get_handle (MonoWaitHandle *handle)
 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;
@@ -7431,6 +7434,7 @@ mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
        runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
 
        return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
+#endif
 }
 /**
  * mono_async_result_new:
index 33d1e52dd8d54de2bb03247eb072253093d70f88..4f8a285f4993c05e2bf1a4a90c99967917841032 100644 (file)
@@ -2361,6 +2361,10 @@ sgen_client_scan_thread_data (void *start_nursery, void *end_nursery, gboolean p
 {
        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;
index 48ce7f963ed23cfab6cc0eb68b6b42aa4f37eebf..a8a1b9bf32c9f8437d6772e3031ddf03ea1e3625 100644 (file)
@@ -70,6 +70,8 @@ update_current_thread_stack (void *start)
 
 #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
index 4fb8906941cb2debcb65916bc9beb051db1101a0..d3b286cd0457418313aaee3dfb651e008074de6c 100644 (file)
@@ -204,6 +204,15 @@ typedef union {
        } 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)
 {
@@ -303,6 +312,15 @@ wasm_invoke_vifffffi (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)
 {
@@ -345,6 +363,8 @@ 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))
@@ -363,6 +383,8 @@ wasm_enter_icall_trampoline (void *target_func, InterpMethodArguments *margs)
                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);
index 7f3dafea5c602ab31d1db9590fca9253b7f2a265..82fb3ae674dfe4030e7ff8b9fe35be8cb2c56d12 100644 (file)
@@ -26,6 +26,7 @@ class Tests
 
        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) {
                };
@@ -260,6 +261,7 @@ class Tests
 
        [Category ("DYNCALL")]
        [Category ("!FULLAOT-AMD64")]
+       [Category ("!INTERPRETER")] //known bug in the interpreter
        public static int test_0_dyncall_nullable () {
                int? v;
 
@@ -410,6 +412,7 @@ class Tests
 
        [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 };
 
index ff4f689290d9c57474d3848c39959e94096333d3..de06a0dc579cdc79bdf2ff481ec06379cb09834d 100644 (file)
@@ -792,9 +792,11 @@ public class BuiltinTests {
                return 0;
        }
 
+#if !__MOBILE__
        public static int Main (String[] args) {
                return TestDriver.RunTests (typeof (BuiltinTests), args);
        }
+#endif
 }
 
 
index bf1134be6bb765cbed3bab6e178cd595a00106d3..20ca3bdb70adf1891e8f2d96ca483deafda141c1 100644 (file)
@@ -86,11 +86,13 @@ sealed public class SealedFinal : Middle {
 }
 
 
-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 ();
index aa5ca277ac544e5e57bdeffbbfd454a0c95de9ab..1e3ded9587a7d63ff7bdf25ad5024fc446fe7cb4 100644 (file)
@@ -1427,6 +1427,7 @@ class Tests
                return 0;
        }
 
+       [Category ("!WASM")] // reported as https://github.com/kripken/emscripten/issues/5603
        public static int test_0_simple_double_casts () {
 
                double d = 0xffffffff;
index 023a56d716507bda15dc1dc604531d94b82090eb..91234b6eec8da38a58334dc3a7f04e00c5ea9864 100644 (file)
@@ -7,12 +7,17 @@ using System.Threading;
 /*
  * 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
@@ -525,9 +530,16 @@ class Tests {
                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.
@@ -536,10 +548,6 @@ class Tests {
                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) {
index 42b91954fcf2c223e6c66a23fd404544ff3cb88b..412145683039727b6c053676cf346110372960a3 100644 (file)
@@ -3442,6 +3442,9 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign
                        /* 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;
index 6faca6d5b93e0fe7e50928fd7553011c74347d55..1868eb62c1024e74b43f95dd60d3930562ba25b5 100644 (file)
@@ -1155,7 +1155,11 @@ no_intrinsic:
                        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++) {
@@ -4258,6 +4262,7 @@ mono_interp_transform_init (void)
 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;
@@ -4275,9 +4280,11 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context)
        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;
@@ -4415,12 +4422,10 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context)
                        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))
index e3461a80aec1631eb756b7d15f18d5133125ede3..707951af02e15c807e7eccced069307a22af527b 100644 (file)
@@ -3268,7 +3268,7 @@ mono_llvm_load_exception (void)
 
        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);
 
index 88efb61d67b9a587edd702b6c4f0741a10bc048c..3f0540ff5fe527eeb7de9fe776ef5554110f5ae1 100644 (file)
@@ -352,6 +352,8 @@ mono_class_is_magic_assembly (MonoClass *klass)
        /* 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;
 }
 
index b433a360d97e7a1cd83f9a9d7989b97105d05fb7..2eeb5f34d6e3de1fb09db5496e922816efd868ad 100644 (file)
@@ -3311,12 +3311,13 @@ mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
 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*
index 539125b2f387005ca812adf5d3d01d7c70e42f37..f8d052627cd72c45b10e5563471039bbb43eb0b9 100644 (file)
@@ -3274,22 +3274,22 @@ void mono_interruption_checkpoint_from_trampoline (void);
 
 #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
 
index 49e17ad14dd3ff89e2be6ecec526b15e041dcd6a..956a6310169bbee2492c869577ad25c580ba7a99 100644 (file)
@@ -338,11 +338,17 @@ namespace SSA {
                        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
        }
 }
 
index b81fe604ed3aef345b7eef2ca52c01e4630172d7..3c916a941b3ddf62af09f0ed8db444584e76c84e 100644 (file)
@@ -416,7 +416,7 @@ mono_trace_enter_method (MonoMethod *method, char *ebp)
        g_free (fname);
 
        if (!ebp) {
-               printf (") ip: %p\n", RETURN_ADDRESS_N (1));
+               printf (") ip: %p\n", MONO_RETURN_ADDRESS_N (1));
                goto unlock;
        }
 
@@ -426,7 +426,7 @@ mono_trace_enter_method (MonoMethod *method, char *ebp)
 
        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) {
@@ -590,7 +590,7 @@ mono_trace_leave_method (MonoMethod *method, ...)
 
        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) {
@@ -698,7 +698,7 @@ mono_trace_leave_method (MonoMethod *method, ...)
                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);
 
index 5e8866ffff869d2123ece47d39040009b0a95118..47173bc29c959a8bd3ed8f1fc52c2d256959092f 100644 (file)
@@ -104,7 +104,7 @@ typedef mword SgenDescriptor;
 #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)
index d5416f0df3630ee6a6bc5b4781bc0e9c5442873c..4c3454823fdd42c2f5e0073a87f650601d6b84bf 100644 (file)
@@ -2503,7 +2503,7 @@ sgen_ensure_free_space (size_t size, int generation)
  * 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);
@@ -2582,6 +2582,52 @@ sgen_perform_collection (size_t requested_size, int generation_to_collect, const
                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