Merge pull request #1659 from alexanderkyte/stringbuilder-referencesource
[mono.git] / mono / mini / jit-icalls.c
index 60ab0af5794c041c61a881d69d7d8dc06ff6a688..3328d51bf2d66324c74263aa00dc9607101d910f 100644 (file)
@@ -23,8 +23,6 @@ mono_ldftn (MonoMethod *method)
 {
        gpointer addr;
 
-       MONO_ARCH_SAVE_REGS;
-
        addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
 
        return mono_create_ftnptr (mono_domain_get (), addr);
@@ -36,10 +34,10 @@ ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
        MonoError error;
        MonoMethod *res;
 
-       MONO_ARCH_SAVE_REGS;
-
-       if (obj == NULL)
-               mono_raise_exception (mono_get_exception_null_reference ());
+       if (obj == NULL) {
+               mono_set_pending_exception (mono_get_exception_null_reference ());
+               return NULL;
+       }
 
        res = mono_object_get_virtual_method (obj, method);
 
@@ -76,12 +74,14 @@ mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method)
 void
 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
 {
-       MONO_ARCH_SAVE_REGS;
-
-       if (!array)
-               mono_raise_exception (mono_get_exception_null_reference ());
-       if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
-               mono_raise_exception (mono_get_exception_array_type_mismatch ());
+       if (!array) {
+               mono_set_pending_exception (mono_get_exception_null_reference ());
+               return;
+       }
+       if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
+               mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
+               return;
+       }
 }
 
 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
@@ -89,7 +89,6 @@ mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
 gint64 
 mono_llmult (gint64 a, gint64 b)
 {
-       /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
        return a * b;
 }
 
@@ -102,8 +101,6 @@ mono_llmult_ovf_un (guint64 a, guint64 b)
        guint32 bh = b >> 32; 
        guint64 res, t1;
 
-       MONO_ARCH_SAVE_REGS;
-
        // fixme: this is incredible slow
 
        if (ah && bh)
@@ -121,7 +118,7 @@ mono_llmult_ovf_un (guint64 a, guint64 b)
        return res;
 
  raise_exception:
-       mono_raise_exception (mono_get_exception_overflow ());
+       mono_set_pending_exception (mono_get_exception_overflow ());
        return 0;
 }
 
@@ -151,8 +148,6 @@ mono_llmult_ovf (gint64 a, gint64 b)
        gint64 res, t1;
        gint32 sign;
 
-       MONO_ARCH_SAVE_REGS;
-
        /* need to work with absoulte values, so find out what the
           resulting sign will be and convert any negative numbers
           from two's complement
@@ -232,20 +227,22 @@ mono_llmult_ovf (gint64 a, gint64 b)
                return res;
 
  raise_exception:
-       mono_raise_exception (mono_get_exception_overflow ());
+       mono_set_pending_exception (mono_get_exception_overflow ());
        return 0;
 }
 
 gint64 
 mono_lldiv (gint64 a, gint64 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
-       else if (b == -1 && a == (-9223372036854775807LL - 1LL))
-               mono_raise_exception (mono_get_exception_arithmetic ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
+       else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
+               mono_set_pending_exception (mono_get_exception_arithmetic ());
+               return 0;
+       }
 #endif
        return a / b;
 }
@@ -253,13 +250,15 @@ mono_lldiv (gint64 a, gint64 b)
 gint64 
 mono_llrem (gint64 a, gint64 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
-       else if (b == -1 && a == (-9223372036854775807LL - 1LL))
-               mono_raise_exception (mono_get_exception_arithmetic ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
+       else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
+               mono_set_pending_exception (mono_get_exception_arithmetic ());
+               return 0;
+       }
 #endif
        return a % b;
 }
@@ -267,11 +266,11 @@ mono_llrem (gint64 a, gint64 b)
 guint64 
 mono_lldiv_un (guint64 a, guint64 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
 #endif
        return a / b;
 }
@@ -279,11 +278,11 @@ mono_lldiv_un (guint64 a, guint64 b)
 guint64 
 mono_llrem_un (guint64 a, guint64 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
 #endif
        return a % b;
 }
@@ -297,8 +296,7 @@ mono_lshl (guint64 a, gint32 shamt)
 {
        guint64 res;
 
-       /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
-       res = a << shamt;
+       res = a << (shamt & 0x7f);
 
        /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
 
@@ -310,8 +308,7 @@ mono_lshr_un (guint64 a, gint32 shamt)
 {
        guint64 res;
 
-       /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
-       res = a >> shamt;
+       res = a >> (shamt & 0x7f);
 
        /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
 
@@ -323,8 +320,7 @@ mono_lshr (gint64 a, gint32 shamt)
 {
        gint64 res;
 
-       /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
-       res = a >> shamt;
+       res = a >> (shamt & 0x7f);
 
        /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
 
@@ -338,13 +334,15 @@ mono_lshr (gint64 a, gint32 shamt)
 gint32
 mono_idiv (gint32 a, gint32 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
-       else if (b == -1 && a == (0x80000000))
-               mono_raise_exception (mono_get_exception_overflow ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
+       else if (b == -1 && a == (0x80000000)) {
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
+       }
 #endif
        return a / b;
 }
@@ -352,11 +350,11 @@ mono_idiv (gint32 a, gint32 b)
 guint32
 mono_idiv_un (guint32 a, guint32 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
 #endif
        return a / b;
 }
@@ -364,26 +362,27 @@ mono_idiv_un (guint32 a, guint32 b)
 gint32
 mono_irem (gint32 a, gint32 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
-       else if (b == -1 && a == (0x80000000))
-               mono_raise_exception (mono_get_exception_overflow ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
+       else if (b == -1 && a == (0x80000000)) {
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
+       }
 #endif
-
        return a % b;
 }
 
 guint32
 mono_irem_un (guint32 a, guint32 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
 #ifdef MONO_ARCH_NEED_DIV_CHECK
-       if (!b)
-               mono_raise_exception (mono_get_exception_divide_by_zero ());
+       if (!b) {
+               mono_set_pending_exception (mono_get_exception_divide_by_zero ());
+               return 0;
+       }
 #endif
        return a % b;
 }
@@ -395,8 +394,6 @@ mono_irem_un (guint32 a, guint32 b)
 gint32
 mono_imul (gint32 a, gint32 b)
 {
-       MONO_ARCH_SAVE_REGS;
-
        return a * b;
 }
 
@@ -405,12 +402,12 @@ mono_imul_ovf (gint32 a, gint32 b)
 {
        gint64 res;
 
-       MONO_ARCH_SAVE_REGS;
-
        res = (gint64)a * (gint64)b;
 
-       if ((res > 0x7fffffffL) || (res < -2147483648LL))
-               mono_raise_exception (mono_get_exception_overflow ());
+       if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
+       }
 
        return res;
 }
@@ -420,12 +417,12 @@ mono_imul_ovf_un (guint32 a, guint32 b)
 {
        guint64 res;
 
-       MONO_ARCH_SAVE_REGS;
-
        res = (guint64)a * (guint64)b;
 
-       if ((res >> 32))
-               mono_raise_exception (mono_get_exception_overflow ());
+       if (res >> 32) {
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
+       }
 
        return res;
 }
@@ -435,8 +432,6 @@ mono_imul_ovf_un (guint32 a, guint32 b)
 double
 mono_fdiv (double a, double b)
 {
-       MONO_ARCH_SAVE_REGS;
-
        return a / b;
 }
 #endif
@@ -649,8 +644,6 @@ mono_array_new_va (MonoMethod *cm, ...)
        int rank;
        int i, d;
 
-       MONO_ARCH_SAVE_REGS;
-
        pcount = mono_method_signature (cm)->param_count;
        rank = cm->klass->rank;
 
@@ -689,8 +682,6 @@ mono_array_new_1 (MonoMethod *cm, guint32 length)
        int pcount;
        int rank;
 
-       MONO_ARCH_SAVE_REGS;
-
        pcount = mono_method_signature (cm)->param_count;
        rank = cm->klass->rank;
 
@@ -717,8 +708,6 @@ mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
        int pcount;
        int rank;
 
-       MONO_ARCH_SAVE_REGS;
-
        pcount = mono_method_signature (cm)->param_count;
        rank = cm->klass->rank;
 
@@ -746,8 +735,6 @@ mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 leng
        int pcount;
        int rank;
 
-       MONO_ARCH_SAVE_REGS;
-
        pcount = mono_method_signature (cm)->param_count;
        rank = cm->klass->rank;
 
@@ -776,8 +763,6 @@ mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 leng
        int pcount;
        int rank;
 
-       MONO_ARCH_SAVE_REGS;
-
        pcount = mono_method_signature (cm)->param_count;
        rank = cm->klass->rank;
 
@@ -804,8 +789,6 @@ mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
        MonoVTable *vtable;
        gpointer addr;
        
-       MONO_ARCH_SAVE_REGS;
-
        //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
 
        mono_class_init (field->parent);
@@ -831,7 +814,6 @@ mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
        MonoClass *handle_class;
        gpointer res;
 
-       MONO_ARCH_SAVE_REGS;
        res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
        mono_error_raise_exception (&error);
        mono_class_init (handle_class);
@@ -866,7 +848,6 @@ mono_fconv_u8 (double v)
 gint64
 mono_fconv_i8 (double v)
 {
-       /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
        return (gint64)v;
 }
 #endif
@@ -874,8 +855,6 @@ mono_fconv_i8 (double v)
 guint32
 mono_fconv_u4 (double v)
 {
-       /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
-
        /* MS.NET behaves like this for some reason */
 #ifdef HAVE_ISINF
        if (isinf (v) || isnan (v))
@@ -901,12 +880,11 @@ mono_fconv_ovf_i8 (double v)
 {
        gint64 res;
 
-       MONO_ARCH_SAVE_REGS;
-
        res = (gint64)v;
 
        if (isnan(v) || trunc (v) != res) {
-               mono_raise_exception (mono_get_exception_overflow ());
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
        }
        return res;
 }
@@ -916,7 +894,6 @@ mono_fconv_ovf_u8 (double v)
 {
        guint64 res;
 
-       MONO_ARCH_SAVE_REGS;
 /*
  * The soft-float implementation of some ARM devices have a buggy guin64 to double
  * conversion that it looses precision even when the integer if fully representable
@@ -928,18 +905,55 @@ mono_fconv_ovf_u8 (double v)
  */
 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
        if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
-               mono_raise_exception (mono_get_exception_overflow ());
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
        }
        res = (guint64)v;
 #else
        res = (guint64)v;
        if (isnan(v) || trunc (v) != res) {
-               mono_raise_exception (mono_get_exception_overflow ());
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
        }
 #endif
        return res;
 }
 
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
+gint64
+mono_rconv_i8 (float v)
+{
+       return (gint64)v;
+}
+#endif
+
+gint64
+mono_rconv_ovf_i8 (float v)
+{
+       gint64 res;
+
+       res = (gint64)v;
+
+       if (isnan(v) || trunc (v) != res) {
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
+       }
+       return res;
+}
+
+guint64
+mono_rconv_ovf_u8 (float v)
+{
+       guint64 res;
+
+       res = (guint64)v;
+       if (isnan(v) || trunc (v) != res) {
+               mono_set_pending_exception (mono_get_exception_overflow ());
+               return 0;
+       }
+       return res;
+}
+
 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
 double
 mono_lconv_to_r8 (gint64 a)
@@ -991,8 +1005,10 @@ mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointe
 
        mono_jit_stats.generic_virtual_invocations++;
 
-       if (obj == NULL)
-               mono_raise_exception (mono_get_exception_null_reference ());
+       if (obj == NULL) {
+               mono_set_pending_exception (mono_get_exception_null_reference ());
+               return NULL;
+       }
        vmethod = mono_object_get_virtual_method (obj, method);
        g_assert (!vmethod->klass->generic_container);
        g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
@@ -1086,7 +1102,7 @@ mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
                jit_tls->class_cast_to = klass;
        }
 
-       mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
+       mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
                                        "System", "InvalidCastException"));
 
        return NULL;
@@ -1122,7 +1138,7 @@ mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *c
                jit_tls->class_cast_to = klass;
        }
 
-       mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
+       mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
                                        "System", "InvalidCastException"));
 
        return NULL;
@@ -1174,8 +1190,10 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
        MonoMethod *m;
        int vt_slot;
 
-       if (klass->flags & TYPE_ATTRIBUTE_INTERFACE)
-               mono_raise_exception (mono_get_exception_execution_engine ("Not yet supported."));
+       if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
+               mono_set_pending_exception (mono_get_exception_execution_engine ("Not yet supported."));
+               return NULL;
+       }
 
        if (mono_method_signature (cmethod)->pinvoke) {
                /* Object.GetType () */
@@ -1193,6 +1211,8 @@ constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *k
                        vt_slot += iface_offset;
                }
                m = klass->vtable [vt_slot];
+               if (cmethod->is_inflated)
+                       m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
        }
        if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
                /*