[interp] Inline newobj. (#32480)
authormonojenkins <jo.shields+jenkins@xamarin.com>
Wed, 19 Feb 2020 22:32:46 +0000 (17:32 -0500)
committerGitHub <noreply@github.com>
Wed, 19 Feb 2020 22:32:46 +0000 (23:32 +0100)
The real goal is to make it not recursive.
This is just a step along the way.
Note that the actual not-recursive change has *not* yet been developed,
so this *might* amount to nothing useful.

Co-authored-by: Jay Krell <jay.krell@cornell.edu>
src/mono/mono/mini/interp/interp.c

index d48451f..30a2c20 100644 (file)
@@ -1160,15 +1160,6 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con
                }                                                                       \
        } while (0)
 
-#define EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION        \
-       do {                                                                            \
-               if (mono_thread_interruption_request_flag && !mono_threads_is_critical_method (frame->imethod->method)) { \
-                       MonoException *exc = mono_thread_interruption_checkpoint ();    \
-                       if (exc)                                                        \
-                               return exc;                                             \
-               }                                                                       \
-       } while (0)
-
 static MonoObject*
 ves_array_create (MonoDomain *domain, MonoClass *klass, int param_count, stackval *values, MonoError *error)
 {
@@ -3215,88 +3206,6 @@ mono_interp_leave (InterpFrame* child_frame)
        return (MonoException*)tmp_sp.data.p;
 }
 
-static MONO_NEVER_INLINE MonoException*
-mono_interp_newobj (
-       // Parameters are sorted by name and parameter list is minimized
-       // to reduce stack use in caller, on e.g. NT/AMD64 (up to 4 parameters
-       // use no stack in caller).
-       InterpFrame* child_frame,
-       ThreadContext* context,
-       MonoError* error,
-       guchar* vt_sp)
-{
-       InterpFrame* const frame = child_frame->parent;
-       InterpMethod* const imethod = frame->imethod;
-       stackval* const sp = child_frame->stack_args;
-
-       MonoObject* o = NULL; // See the comment about GC safety.
-       stackval valuetype_this;
-       stackval retval;
-
-       MonoClass * const newobj_class = child_frame->imethod->method->klass;
-       /*if (profiling_classes) {
-               guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
-               count++;
-               g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
-       }*/
-
-       /*
-        * First arg is the object.
-        */
-       if (m_class_is_valuetype (newobj_class)) {
-               MonoType *t = m_class_get_byval_arg (newobj_class);
-               memset (&valuetype_this, 0, sizeof (stackval));
-               if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
-                       sp->data.p = vt_sp;
-                       valuetype_this.data.p = vt_sp;
-               } else {
-                       sp->data.p = &valuetype_this;
-               }
-       } else {
-               if (newobj_class != mono_defaults.string_class) {
-                       MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
-                       if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
-                               MonoException* const exc = mono_error_convert_to_exception (error);
-                               g_assert (exc);
-                               return exc;
-                       }
-                       ERROR_DECL (error);
-                       OBJREF (o) = mono_object_new_checked (imethod->domain, newobj_class, error);
-                       mono_error_cleanup (error); // FIXME: do not swallow the error
-                       EXCEPTION_CHECKPOINT_IN_HELPER_FUNCTION;
-                       sp->data.o = o;
-#ifndef DISABLE_REMOTING
-                       if (mono_object_is_transparent_proxy (o)) {
-                               MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
-                               mono_error_assert_ok (error);
-                               child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
-                               mono_error_assert_ok (error);
-                       }
-#endif
-               } else {
-                       sp->data.p = NULL;
-                       child_frame->retval = &retval;
-               }
-       }
-
-       interp_exec_method (child_frame, context, error);
-
-       CHECK_RESUME_STATE (context);
-
-       /*
-        * a constructor returns void, but we need to return the object we created
-        */
-       if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
-               *sp = valuetype_this;
-       } else if (newobj_class == mono_defaults.string_class) {
-               *sp = retval;
-       } else {
-               sp->data.o = o;
-       }
-resume:
-       return NULL;
-}
-
 static MONO_NEVER_INLINE void
 mono_interp_enum_hasflag (stackval* sp, MonoClass* klass)
 {
@@ -5087,9 +4996,8 @@ call_newobj:
 
                MINT_IN_CASE(MINT_NEWOBJ) {
                        int dummy;
-                       // This is split up to:
-                       //  - conserve stack
-                       //  - keep exception handling and resume mostly in the main function
+
+                       // FIXME: Clean this up and make it not recursive.
 
                        frame->ip = ip;
 
@@ -5107,11 +5015,75 @@ call_newobj:
 
                        child_frame->stack_args = sp;
 
-                       // FIXME remove recursion
-                       MonoException* const exc = mono_interp_newobj (child_frame, context, error, vt_sp);
-                       if (exc)
-                               THROW_EX (exc, ip);
+                       MonoException *exc = NULL;
+
+                       InterpMethod* const imethod = frame->imethod;
+
+                       MonoObject* o = NULL; // See the comment about GC safety.
+                       stackval valuetype_this;
+                       stackval retval;
+
+                       MonoClass * const newobj_class = child_frame->imethod->method->klass;
+                       /*if (profiling_classes) {
+                               guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
+                               count++;
+                               g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
+                       }*/
+
+                       /*
+                        * First arg is the object.
+                        */
+                       if (m_class_is_valuetype (newobj_class)) {
+                               MonoType *t = m_class_get_byval_arg (newobj_class);
+                               memset (&valuetype_this, 0, sizeof (stackval));
+                               if (!m_class_is_enumtype (newobj_class) && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
+                                       sp->data.p = vt_sp;
+                                       valuetype_this.data.p = vt_sp;
+                               } else {
+                                       sp->data.p = &valuetype_this;
+                               }
+                       } else {
+                               if (newobj_class != mono_defaults.string_class) {
+                                       MonoVTable *vtable = mono_class_vtable_checked (imethod->domain, newobj_class, error);
+                                       if (!is_ok (error) || !mono_runtime_class_init_full (vtable, error)) {
+                                               exc = mono_error_convert_to_exception (error);
+                                               g_assert (exc);
+                                               THROW_EX (exc, ip);
+                                       }
+                                       ERROR_DECL (error);
+                                       OBJREF (o) = mono_object_new_checked (imethod->domain, newobj_class, error);
+                                       mono_error_cleanup (error); // FIXME: do not swallow the error
+                                       EXCEPTION_CHECKPOINT;
+                                       sp->data.o = o;
+#ifndef DISABLE_REMOTING
+                                       if (mono_object_is_transparent_proxy (o)) {
+                                               MonoMethod *remoting_invoke_method = mono_marshal_get_remoting_invoke_with_check (child_frame->imethod->method, error);
+                                               mono_error_assert_ok (error);
+                                               child_frame->imethod = mono_interp_get_imethod (imethod->domain, remoting_invoke_method, error);
+                                               mono_error_assert_ok (error);
+                                       }
+#endif
+                               } else {
+                                       sp->data.p = NULL;
+                                       child_frame->retval = &retval;
+                               }
+                       }
+
+                       interp_exec_method (child_frame, context, error);
+
                        CHECK_RESUME_STATE (context);
+
+                       /*
+                        * a constructor returns void, but we need to return the object we created
+                        */
+                       if (m_class_is_valuetype (newobj_class) && !m_class_is_enumtype (newobj_class)) {
+                               *sp = valuetype_this;
+                       } else if (newobj_class == mono_defaults.string_class) {
+                               *sp = retval;
+                       } else {
+                               sp->data.o = o;
+                       }
+
                        ++sp;
                        MINT_IN_BREAK;
                }