[interp] support stelem for g{,u}int64
[mono.git] / mono / mini / interp / interp.c
index 736deb7a78994c37ef2852a084db4aedf63944ad..395850a0709a0d44dcd8d4454ee45aa92cea99e1 100644 (file)
@@ -525,7 +525,7 @@ fill_in_trace (MonoException *exception, MonoInvocation *frame)
        } while (0)
 
 static MonoObject*
-ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
+ves_array_create (MonoInvocation *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
 {
        uintptr_t *lengths;
        intptr_t *lower_bounds;
@@ -547,46 +547,58 @@ ves_array_create (MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig
                lengths += klass->rank;
        }
        obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
+       if (!mono_error_ok (&error)) {
+               frame->ex = mono_error_convert_to_exception (&error);
+               FILL_IN_TRACE (frame->ex, frame);
+       }
        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
        return obj;
 }
 
-static void 
+static gint32
+ves_array_calculate_index (MonoArray *ao, stackval *sp, MonoInvocation *frame)
+{
+       g_assert (!frame->ex);
+       MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
+
+       guint32 pos = 0;
+       if (ao->bounds) {
+               for (gint32 i = 0; i < ac->rank; i++) {
+                       guint32 idx = sp [i].data.i;
+                       guint32 lower = ao->bounds [i].lower_bound;
+                       guint32 len = ao->bounds [i].length;
+                       if (idx < lower || (idx - lower) >= len) {
+                               frame->ex = mono_get_exception_index_out_of_range ();
+                               FILL_IN_TRACE (frame->ex, frame);
+                               return -1;
+                       }
+                       pos = (pos * len) + idx - lower;
+               }
+       } else {
+               pos = sp [0].data.i;
+               if (pos >= ao->max_length) {
+                       frame->ex = mono_get_exception_index_out_of_range ();
+                       FILL_IN_TRACE (frame->ex, frame);
+                       return -1;
+               }
+       }
+       return pos;
+}
+
+static void
 ves_array_set (MonoInvocation *frame)
 {
        stackval *sp = frame->stack_args + 1;
-       MonoObject *o;
-       MonoArray *ao;
-       MonoClass *ac;
-       gint32 i, t, pos, esize;
-       gpointer ea;
-       MonoType *mt;
 
-       o = frame->stack_args->data.p;
-       ao = (MonoArray *)o;
-       ac = o->vtable->klass;
+       MonoObject *o = frame->stack_args->data.p;
+       MonoArray *ao = (MonoArray *) o;
+       MonoClass *ac = o->vtable->klass;
 
        g_assert (ac->rank >= 1);
 
-       pos = sp [0].data.i;
-       if (ao->bounds != NULL) {
-               pos -= ao->bounds [0].lower_bound;
-               for (i = 1; i < ac->rank; i++) {
-                       if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= 
-                           ao->bounds [i].length) {
-                               frame->ex = mono_get_exception_index_out_of_range ();
-                               FILL_IN_TRACE(frame->ex, frame);
-                               return;
-                       }
-                       pos = pos*ao->bounds [i].length + sp [i].data.i - 
-                               ao->bounds [i].lower_bound;
-               }
-       } else if (pos >= ao->max_length) {
-               frame->ex = mono_get_exception_index_out_of_range ();
-               FILL_IN_TRACE(frame->ex, frame);
+       gint32 pos = ves_array_calculate_index (ao, sp, frame);
+       if (frame->ex)
                return;
-       }
-
 
        if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
                MonoError error;
@@ -599,88 +611,52 @@ ves_array_set (MonoInvocation *frame)
                }
        }
 
-       esize = mono_array_element_size (ac);
-       ea = mono_array_addr_with_size (ao, esize, pos);
+       gint32 esize = mono_array_element_size (ac);
+       gpointer ea = mono_array_addr_with_size (ao, esize, pos);
 
-       mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
+       MonoType *mt = mono_method_signature (frame->runtime_method->method)->params [ac->rank];
        stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
 }
 
-static void 
+static void
 ves_array_get (MonoInvocation *frame)
 {
        stackval *sp = frame->stack_args + 1;
-       MonoObject *o;
-       MonoArray *ao;
-       MonoClass *ac;
-       gint32 i, t, pos, esize;
-       gpointer ea;
-       MonoType *mt;
 
-       o = frame->stack_args->data.p;
-       ao = (MonoArray *)o;
-       ac = o->vtable->klass;
+       MonoObject *o = frame->stack_args->data.p;
+       MonoArray *ao = (MonoArray *) o;
+       MonoClass *ac = o->vtable->klass;
 
        g_assert (ac->rank >= 1);
 
-       pos = sp [0].data.i;
-       if (ao->bounds != NULL) {
-               pos -= ao->bounds [0].lower_bound;
-               for (i = 1; i < ac->rank; i++) {
-                       if ((t = sp [i].data.i - ao->bounds [i].lower_bound) >= 
-                           ao->bounds [i].length) {
-                               frame->ex = mono_get_exception_index_out_of_range ();
-                               FILL_IN_TRACE(frame->ex, frame);
-                               return;
-                       }
-
-                       pos = pos*ao->bounds [i].length + sp [i].data.i - 
-                               ao->bounds [i].lower_bound;
-               }
-       } else if (pos >= ao->max_length) {
-               frame->ex = mono_get_exception_index_out_of_range ();
-               FILL_IN_TRACE(frame->ex, frame);
+       gint32 pos = ves_array_calculate_index (ao, sp, frame);
+       if (frame->ex)
                return;
-       }
 
-       esize = mono_array_element_size (ac);
-       ea = mono_array_addr_with_size (ao, esize, pos);
+       gint32 esize = mono_array_element_size (ac);
+       gpointer ea = mono_array_addr_with_size (ao, esize, pos);
 
-       mt = mono_method_signature (frame->runtime_method->method)->ret;
+       MonoType *mt = mono_method_signature (frame->runtime_method->method)->ret;
        stackval_from_data (mt, frame->retval, ea, FALSE);
 }
 
 static gpointer
 ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
 {
-       gint32 i, pos, esize;
        MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
 
        g_assert (ac->rank >= 1);
 
-       pos = sp [0].data.i;
-       if (ao->bounds != NULL) {
-               pos -= ao->bounds [0].lower_bound;
-               for (i = 1; i < ac->rank; i++) {
-                       if ((sp [i].data.i - ao->bounds [i].lower_bound) >= ao->bounds [i].length) {
-                               frame->ex = mono_get_exception_index_out_of_range ();
-                               FILL_IN_TRACE(frame->ex, frame);
-                               return NULL;
-                       }
-                       pos = pos * ao->bounds [i].length + sp [i].data.i - ao->bounds [i].lower_bound;
-               }
-       } else if (pos >= ao->max_length) {
-               frame->ex = mono_get_exception_index_out_of_range ();
-               FILL_IN_TRACE(frame->ex, frame);
+       gint32 pos = ves_array_calculate_index (ao, sp, frame);
+       if (frame->ex)
                return NULL;
-       }
 
        if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
                frame->ex = mono_get_exception_array_type_mismatch ();
                FILL_IN_TRACE (frame->ex, frame);
                return NULL;
        }
-       esize = mono_array_element_size (ac);
+       gint32 esize = mono_array_element_size (ac);
        return mono_array_addr_with_size (ao, esize, pos);
 }
 
@@ -820,13 +796,19 @@ static MethodArguments* build_args_from_sig (MonoMethodSignature *sig, MonoInvoc
                case MONO_TYPE_GENERICINST:
                        margs->iargs [int_i] = frame->stack_args [i].data.p;
 #if DEBUG_INTERP
-                       g_print ("build_args_from_sig: margs->iargs[%d]: %p (frame @ %d)\n", int_i, margs->iargs[int_i], i);
+                       g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
 #endif
                        int_i++;
                        break;
                case MONO_TYPE_R4:
                case MONO_TYPE_R8:
-                       margs->fargs [int_f] = frame->stack_args [i].data.f;
+                       if (ptype == MONO_TYPE_R4)
+                               * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
+                       else
+                               margs->fargs [int_f] = frame->stack_args [i].data.f;
+#if DEBUG_INTERP
+                       g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i);
+#endif
                        int_f++;
                        break;
                default:
@@ -913,10 +895,15 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a
        /* domain can only be changed by native code */
        context->domain = mono_domain_get ();
 
-       if (*mono_thread_interruption_request_flag ())
-               mono_thread_interruption_checkpoint ();
+       if (*mono_thread_interruption_request_flag ()) {
+               MonoException *exc = mono_thread_interruption_checkpoint ();
+               if (exc) {
+                       frame->ex = exc;
+                       context->search_for_handler = 1;
+               }
+       }
        
-       if (!MONO_TYPE_ISSTRUCT (sig->ret))
+       if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
                stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
 
        context->current_frame = old_frame;
@@ -1949,7 +1936,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                                 * An exception occurred, need to run finally, fault and catch handlers..
                                 */
                                frame->ex = child_frame.ex;
-                               goto handle_finally;
+                               goto handle_exception;;
                        }
 
                        /* need to handle typedbyref ... */
@@ -2554,11 +2541,15 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                MINT_IN_CASE(MINT_REM_I4)
                        if (sp [-1].data.i == 0)
                                THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       if (sp [-1].data.i == (-1))
+                               THROW_EX (mono_get_exception_overflow (), ip);
                        BINOP(i, %);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_REM_I8)
                        if (sp [-1].data.l == 0)
                                THROW_EX (mono_get_exception_divide_by_zero (), ip);
+                       if (sp [-1].data.l == (-1))
+                               THROW_EX (mono_get_exception_overflow (), ip);
                        BINOP(l, %);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_REM_R8)
@@ -2790,6 +2781,9 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        token = * (guint16 *)(ip + 1);
                        ip += 2;
 
+                       child_frame.ip = NULL;
+                       child_frame.ex = NULL;
+
                        child_frame.runtime_method = rtm->data_items [token];
                        csig = mono_method_signature (child_frame.runtime_method->method);
                        newobj_class = child_frame.runtime_method->method->klass;
@@ -2798,10 +2792,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                                count++;
                                g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
                        }*/
-                               
+
                        if (newobj_class->parent == mono_defaults.array_class) {
                                sp -= csig->param_count;
-                               o = ves_array_create (context->domain, newobj_class, csig, sp);
+                               child_frame.stack_args = sp;
+                               o = ves_array_create (&child_frame, context->domain, newobj_class, csig, sp);
+                               if (child_frame.ex)
+                                       THROW_EX (child_frame.ex, ip);
                                goto array_constructed;
                        }
 
@@ -2841,9 +2838,6 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
 
                        g_assert (csig->call_convention == MONO_CALL_DEFAULT);
 
-                       child_frame.ip = NULL;
-                       child_frame.ex = NULL;
-
                        ves_exec_method_with_context (&child_frame, context);
 
                        context->current_frame = frame;
@@ -2919,6 +2913,11 @@ array_constructed:
                                sp->data.p = mono_get_exception_null_reference ();
                        THROW_EX ((MonoException *)sp->data.p, ip);
                        MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
+                       o = sp [-1].data.p;
+                       sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
+                       ip += 2;
+                       MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDFLDA)
                        o = sp [-1].data.p;
                        if (!o)
@@ -3159,9 +3158,19 @@ array_constructed:
                        sp [-1].data.l = sp [-1].data.i;
                        ++ip;
                        MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
+                       if (sp [-1].data.l < 0)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
+                       if ((guint64) sp [-1].data.l > MYGINT64_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       ++ip;
+                       MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
                MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
-                       if (sp [-1].data.f < 0 || sp [-1].data.f > 9223372036854775807LL)
+                       if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
                                THROW_EX (mono_get_exception_overflow (), ip);
                        sp [-1].data.l = (guint64)sp [-1].data.f;
                        ++ip;
@@ -3340,6 +3349,7 @@ array_constructed:
                }
                MINT_IN_CASE(MINT_STELEM_I)  /* fall through */
                MINT_IN_CASE(MINT_STELEM_I1) /* fall through */ 
+               MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
                MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
                MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
                MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
@@ -3366,6 +3376,9 @@ array_constructed:
                        case MINT_STELEM_I1:
                                mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
                                break;
+                       case MINT_STELEM_U1:
+                               mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
+                               break;
                        case MINT_STELEM_I2:
                                mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
                                break;
@@ -3412,7 +3425,13 @@ array_constructed:
                        ++ip;
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
-                       if (sp [-1].data.l <= MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
+                       if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
+                               THROW_EX (mono_get_exception_overflow (), ip);
+                       sp [-1].data.i = (gint32) sp [-1].data.l;
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
+                       if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
                                THROW_EX (mono_get_exception_overflow (), ip);
                        sp [-1].data.i = (gint32) sp [-1].data.l;
                        ++ip;