[interp] lock when acquiring memory from a mempool.
[mono.git] / mono / mini / interp / interp.c
index 280ffc938ca64b9b70ea86c0a2aa1c9be5f8819c..0f0223b421c1aa79f876df137cde9ca6adf4ed6f 100644 (file)
@@ -253,26 +253,23 @@ ves_real_abort (int line, MonoMethod *mh,
                THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
        } while (0);
 
-static mono_mutex_t runtime_method_lookup_section;
-
 RuntimeMethod*
 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
 {
        RuntimeMethod *rtm;
        error_init (error);
 
-       mono_os_mutex_lock (&runtime_method_lookup_section);
+       mono_domain_jit_code_hash_lock (domain);
        if ((rtm = mono_internal_hash_table_lookup (&domain->jit_code_hash, method))) {
-               mono_os_mutex_unlock (&runtime_method_lookup_section);
+               mono_domain_jit_code_hash_unlock (domain);
                return rtm;
        }
-       rtm = mono_mempool_alloc (domain->mp, sizeof (RuntimeMethod));
-       memset (rtm, 0, sizeof (*rtm));
+       rtm = mono_domain_alloc0 (domain, sizeof (RuntimeMethod));
        rtm->method = method;
        rtm->param_count = mono_method_signature (method)->param_count;
        rtm->hasthis = mono_method_signature (method)->hasthis;
        mono_internal_hash_table_insert (&domain->jit_code_hash, method, rtm);
-       mono_os_mutex_unlock (&runtime_method_lookup_section);
+       mono_domain_jit_code_hash_unlock (domain);
 
        return rtm;
 }
@@ -525,7 +522,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,45 +544,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;
@@ -598,96 +608,53 @@ 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 void
-ves_array_element_address (MonoInvocation *frame)
+static gpointer
+ves_array_element_address (MonoInvocation *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
 {
-       stackval *sp = frame->stack_args + 1;
-       MonoObject *o;
-       MonoArray *ao;
-       MonoClass *ac;
-       gint32 i, t, pos, esize;
-       gpointer ea;
-
-       o = frame->stack_args->data.p;
-       ao = (MonoArray *)o;
-       ac = o->vtable->klass;
+       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 ((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);
-               return;
-       }
-
-       esize = mono_array_element_size (ac);
-       ea = mono_array_addr_with_size (ao, esize, pos);
+       gint32 pos = ves_array_calculate_index (ao, sp, frame);
+       if (frame->ex)
+               return NULL;
 
-       frame->retval->data.p = ea;
+       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;
+       }
+       gint32 esize = mono_array_element_size (ac);
+       return mono_array_addr_with_size (ao, esize, pos);
 }
 
 void
@@ -826,13 +793,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:
@@ -919,10 +892,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;
@@ -968,10 +946,6 @@ ves_runtime_method (MonoInvocation *frame, ThreadContext *context)
                        ves_array_get (frame);
                        return;
                }
-               if (*name == 'A' && (strcmp (name, "Address") == 0)) {
-                       ves_array_element_address (frame);
-                       return;
-               }
        }
        
        g_error ("Don't know how to exec runtime method %s.%s::%s", 
@@ -1959,7 +1933,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 ... */
@@ -1977,8 +1951,12 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        child_frame.retval = sp;
                        /* decrement by the actual number of args */
                        sp -= child_frame.runtime_method->param_count;
-                       if (child_frame.runtime_method->hasthis)
+                       if (child_frame.runtime_method->hasthis) {
                                --sp;
+                               MonoObject *this_arg = sp->data.p;
+                               if (!this_arg)
+                                       THROW_EX (mono_get_exception_null_reference(), ip - 2);
+                       }
                        child_frame.stack_args = sp;
 
                        if (child_frame.runtime_method->hasthis && !child_frame.runtime_method->method->klass->valuetype && mono_object_is_transparent_proxy (sp->data.p)) {
@@ -2560,11 +2538,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)
@@ -2758,17 +2740,14 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context)
                        sp [-1].data.l = (guint64)sp [-1].data.f;
                        ++ip;
                        MINT_IN_BREAK;
-#if 0
                MINT_IN_CASE(MINT_CPOBJ) {
-                       MonoClass *vtklass;
-                       ++ip;
-                       vtklass = rtm->data_items[READ32 (ip)];
+                       c = rtm->data_items[* (guint16 *)(ip + 1)];
+                       g_assert (c->byval_arg.type == MONO_TYPE_VALUETYPE);
+                       stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
                        ip += 2;
                        sp -= 2;
-                       memcpy (sp [0].data.p, sp [1].data.p, mono_class_value_size (vtklass, NULL));
                        MINT_IN_BREAK;
                }
-#endif
                MINT_IN_CASE(MINT_LDOBJ) {
                        void *p;
                        c = rtm->data_items[* (guint16 *)(ip + 1)];
@@ -2799,6 +2778,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;
@@ -2807,10 +2789,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;
                        }
 
@@ -2850,9 +2835,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;
@@ -2928,6 +2910,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)
@@ -3168,9 +3155,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;
@@ -3207,6 +3204,9 @@ array_constructed:
                }
                MINT_IN_CASE(MINT_NEWARR)
                        sp [-1].data.p = (MonoObject*) mono_array_new_checked (context->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
+                       if (!mono_error_ok (&error)) {
+                               THROW_EX (mono_error_convert_to_exception (&error), ip);
+                       }
                        mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                        ip += 2;
                        /*if (profiling_classes) {
@@ -3250,26 +3250,18 @@ array_constructed:
                MINT_IN_CASE(MINT_LDELEMA)
                MINT_IN_CASE(MINT_LDELEMA_TC) {
                        gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
-                       guint32 esize;
-                       mono_u aindex;
                        
                        MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
-                       ip += 2;
-                       sp -= 2;
+                       guint16 numargs = *(guint16 *) (ip + 2);
+                       ip += 3;
+                       sp -= numargs;
 
                        o = sp [0].data.p;
-
-                       aindex = sp [1].data.i;
-                       if (aindex >= mono_array_length ((MonoArray *) o))
-                               THROW_EX (mono_get_exception_index_out_of_range (), ip - 2);
-
-                       if (needs_typecheck && o->vtable->klass->element_class != klass)
-                               THROW_EX (mono_get_exception_array_type_mismatch (), ip);
-
-                       esize = mono_array_element_size (((MonoArray *) o)->obj.vtable->klass);
-                       sp->data.p = mono_array_addr_with_size ((MonoArray *) o, esize, aindex);
-
+                       sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
+                       if (frame->ex)
+                               THROW_EX (frame->ex, ip);
                        ++sp;
+
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
@@ -3354,6 +3346,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 */
@@ -3380,6 +3373,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;
@@ -3426,7 +3422,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;
@@ -4372,7 +4374,6 @@ mono_interp_init ()
 {
        mono_native_tls_alloc (&thread_context_id, NULL);
     mono_native_tls_set_value (thread_context_id, NULL);
-       mono_os_mutex_init_recursive (&runtime_method_lookup_section);
        mono_os_mutex_init_recursive (&create_method_pointer_mutex);
 
        mono_interp_transform_init ();
@@ -4394,16 +4395,6 @@ interp_regression_step (MonoImage *image, int verbose, int *total_run, int *tota
        cfailed = failed = run = 0;
        transform_time = elapsed = 0.0;
 
-#if 0
-       /* fixme: ugly hack - delete all previously compiled methods */
-       if (domain_jit_info (domain)) {
-               g_hash_table_destroy (domain_jit_info (domain)->jit_trampoline_hash);
-               domain_jit_info (domain)->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
-               mono_internal_hash_table_destroy (&(domain->jit_code_hash));
-               mono_jit_code_hash_init (&(domain->jit_code_hash));
-       }
-#endif
-
        g_timer_start (timer);
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
                MonoObject *exc = NULL;