Merge pull request #1708 from alexanderkyte/always_use_imt
authorZoltan Varga <vargaz@gmail.com>
Mon, 13 Apr 2015 18:48:35 +0000 (14:48 -0400)
committerZoltan Varga <vargaz@gmail.com>
Mon, 13 Apr 2015 18:48:35 +0000 (14:48 -0400)
[runtime] Remove checks for mono_use_imt because always true.

1  2 
mono/mini/method-to-ir.c
mono/mini/mini-runtime.c
mono/mini/mini.h

diff --combined mono/mini/method-to-ir.c
index 0f5e45ad93fa98b40fea13a538e791e65f619430,e5310e2544ae037b9dc398c7b7ed8dd5e0bf7bfa..6bce61df376328e46939bc6bc8bbfbb46f274848
@@@ -407,7 -407,7 +407,7 @@@ static MONO_NEVER_INLINE voi
  gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
  {
        if (cfg->verbose_level > 2)                                                                                     \
 -              printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), __LINE__);
 +              printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), line);
        mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
  }
  
@@@ -2898,18 -2898,10 +2898,10 @@@ mono_emit_method_call_full (MonoCompil
                        vtable_reg = alloc_preg (cfg);
                        MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
                        if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
-                               slot_reg = -1;
-                               if (mono_use_imt) {
-                                       guint32 imt_slot = mono_method_get_imt_slot (method);
-                                       emit_imt_argument (cfg, call, call->method, imt_arg);
-                                       slot_reg = vtable_reg;
-                                       offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
-                               }
-                               if (slot_reg == -1) {
-                                       slot_reg = alloc_preg (cfg);
-                                       mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
-                                       offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
-                               }
+                               guint32 imt_slot = mono_method_get_imt_slot (method);
+                               emit_imt_argument (cfg, call, call->method, imt_arg);
+                               slot_reg = vtable_reg;
+                               offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
                        } else {
                                slot_reg = vtable_reg;
                                offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
@@@ -2998,7 -2990,7 +2990,7 @@@ direct_icalls_enabled (MonoCompile *cfg
        if (cfg->compile_llvm)
                return FALSE;
  #endif
 -      if (cfg->gen_seq_points_debug_data || cfg->disable_direct_icalls)
 +      if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
                return FALSE;
        return TRUE;
  }
@@@ -3514,28 -3506,6 +3506,28 @@@ emit_get_rgctx_gsharedvt_call (MonoComp
        return emit_rgctx_fetch (cfg, rgctx, entry);
  }
  
 +/*
 + * emit_get_rgctx_virt_method:
 + *
 + *   Return data for method VIRT_METHOD for a receiver of type KLASS.
 + */
 +static MonoInst*
 +emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
 +                                                      MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
 +{
 +      MonoJumpInfoVirtMethod *info;
 +      MonoJumpInfoRgctxEntry *entry;
 +      MonoInst *rgctx;
 +
 +      info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
 +      info->klass = klass;
 +      info->method = virt_method;
 +
 +      entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
 +      rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
 +
 +      return emit_rgctx_fetch (cfg, rgctx, entry);
 +}
  
  static MonoInst*
  emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
@@@ -7820,13 -7790,16 +7812,13 @@@ mono_method_to_ir (MonoCompile *cfg, Mo
        cfg->stat_cil_code_size += header->code_size;
  
        seq_points = cfg->gen_seq_points && cfg->method == method;
 -#ifdef PLATFORM_ANDROID
 -      seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
 -#endif
  
        if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
                /* We could hit a seq point before attaching to the JIT (#8338) */
                seq_points = FALSE;
        }
  
 -      if (cfg->gen_seq_points_debug_data && cfg->method == method) {
 +      if (cfg->gen_sdb_seq_points && cfg->method == method) {
                minfo = mono_debug_lookup_method (method);
                if (minfo) {
                        int i, n_il_offsets;
                        gboolean skip_ret = FALSE;
                        gboolean delegate_invoke = FALSE;
                        gboolean direct_icall = FALSE;
 +                      gboolean constrained_partial_call = FALSE;
                        MonoMethod *cil_method;
  
                        CHECK_OPSIZE (5);
                                if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
                                        if (!mini_is_gsharedvt_klass (cfg, constrained_class)) {
                                                g_assert (!cmethod->klass->valuetype);
 -                                              if (!mini_type_is_reference (cfg, &constrained_class->byval_arg)) {
 -                                                      /* FIXME: gshared type constrained to a primitive type */
 -                                                      GENERIC_SHARING_FAILURE (CEE_CALL);
 -                                              }
 +                                              if (!mini_type_is_reference (cfg, &constrained_class->byval_arg))
 +                                                      constrained_partial_call = TRUE;
                                        }
                                }
  
                                /*
                                 * We have the `constrained.' prefix opcode.
                                 */
 -                              if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
 +                              if (constrained_partial_call) {
 +                                      gboolean need_box = TRUE;
 +
 +                                      /*
 +                                       * The receiver is a valuetype, but the exact type is not known at compile time. This means the
 +                                       * called method is not known at compile time either. The called method could end up being
 +                                       * one of the methods on the parent classes (object/valuetype/enum), in which case we need
 +                                       * to box the receiver.
 +                                       * A simple solution would be to box always and make a normal virtual call, but that would
 +                                       * be bad performance wise.
 +                                       */
 +                                      if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
 +                                              /*
 +                                               * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
 +                                               */
 +                                              need_box = FALSE;
 +                                      }
 +
 +                                      if (need_box) {
 +                                              MonoInst *box_type;
 +                                              MonoBasicBlock *is_ref_bb, *end_bb;
 +                                              MonoInst *nonbox_call;
 +
 +                                              /*
 +                                               * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
 +                                               * if needed.
 +                                               * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
 +                                               * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
 +                                               */
 +                                              addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
 +
 +                                              NEW_BBLOCK (cfg, is_ref_bb);
 +                                              NEW_BBLOCK (cfg, end_bb);
 +
 +                                              box_type = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE);
 +                                              MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, 1);
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
 +
 +                                              /* Non-ref case */
 +                                              nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
 +
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 +
 +                                              /* Ref case */
 +                                              MONO_START_BB (cfg, is_ref_bb);
 +                                              EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
 +                                              ins->klass = constrained_class;
 +                                              sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
 +                                              ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
 +
 +                                              MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
 +
 +                                              MONO_START_BB (cfg, end_bb);
 +                                              bblock = end_bb;
 +
 +                                              nonbox_call->dreg = ins->dreg;
 +                                      } else {
 +                                              g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
 +                                              addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
 +                                              ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
 +                                      }
 +                                      goto call_end;
 +                              } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
                                        /*
                                         * The type parameter is instantiated as a valuetype,
                                         * but that type doesn't override the method we're
                                        GSHAREDVT_FAILURE (*ip);
  
  #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
-                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
+                               if (cmethod->wrapper_type == MONO_WRAPPER_NONE)
                                        use_imt = TRUE;
  #endif
  
                                                GSHAREDVT_FAILURE (*ip);
                                        if (fsig->generic_param_count) {
                                                /* virtual generic call */
-                                               g_assert (mono_use_imt);
                                                g_assert (!imt_arg);
                                                /* Same as the virtual generic case above */
                                                imt_arg = emit_get_rgctx_method (cfg, context_used,
        }
  
        /* Add a sequence point for method entry/exit events */
 -      if (seq_points && cfg->gen_seq_points_debug_data) {
 +      if (seq_points && cfg->gen_sdb_seq_points) {
                NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
                MONO_ADD_INS (init_localsbb, ins);
                NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
diff --combined mono/mini/mini-runtime.c
index 9b48dcde6bb6c50e23730cab721724624dcc5feb,bd8605a5fa84dbee796dbe776f7fcf1a9a53c8dd..c0943117994ef469b57b90cd38a9dc3ce5f561a9
@@@ -86,8 -86,7 +86,7 @@@ MONO_FAST_TLS_DECLARE(mono_jit_tls)
  gboolean mono_compile_aot = FALSE;
  /* If this is set, no code is generated dynamically, everything is taken from AOT files */
  gboolean mono_aot_only = FALSE;
- /* Whenever to use IMT */
- gboolean mono_use_imt = TRUE;
  const char *mono_build_date;
  gboolean mono_do_signal_chaining;
  gboolean mono_do_crash_chaining;
@@@ -1108,16 -1107,6 +1107,16 @@@ mono_patch_info_dup_mp (MonoMemPool *mp
                //memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
                break;
        }
 +      case MONO_PATCH_INFO_VIRT_METHOD: {
 +              MonoJumpInfoVirtMethod *info;
 +              MonoJumpInfoVirtMethod *oinfo;
 +
 +              oinfo = patch_info->data.virt_method;
 +              info = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoVirtMethod));
 +              res->data.virt_method = info;
 +              memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
 +              break;
 +      }
        default:
                break;
        }
@@@ -1190,11 -1179,6 +1189,11 @@@ mono_patch_info_hash (gconstpointer dat
                return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method | (gsize)ji->data.del_tramp->virtual;
        case MONO_PATCH_INFO_LDSTR_LIT:
                return g_str_hash (ji->data.target);
 +      case MONO_PATCH_INFO_VIRT_METHOD: {
 +              MonoJumpInfoVirtMethod *info = ji->data.virt_method;
 +
 +              return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
 +      }
        default:
                printf ("info type: %d\n", ji->type);
                mono_print_ji (ji); printf ("\n");
@@@ -1252,8 -1236,6 +1251,8 @@@ mono_patch_info_equal (gconstpointer ka
                return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method && ji1->data.del_tramp->virtual == ji2->data.del_tramp->virtual;
        case MONO_PATCH_INFO_CASTCLASS_CACHE:
                return ji1->data.index == ji2->data.index;
 +      case MONO_PATCH_INFO_VIRT_METHOD:
 +              return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@@ -1591,15 -1573,6 +1590,15 @@@ mono_resolve_patch_target (MonoMethod *
                        slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
                        break;
                }
 +              case MONO_PATCH_INFO_VIRT_METHOD: {
 +                      MonoJumpInfoVirtMethod *info;
 +                      MonoJumpInfoVirtMethod *oinfo = entry->data->data.virt_method;
 +
 +                      info = g_malloc0 (sizeof (MonoJumpInfoVirtMethod));
 +                      memcpy (info, oinfo, sizeof (MonoJumpInfoVirtMethod));
 +                      slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
 +                      break;
 +              }
                default:
                        g_assert_not_reached ();
                        break;
@@@ -2690,7 -2663,7 +2689,7 @@@ mini_parse_debug_options (void
                else if (!strcmp (arg, "explicit-null-checks"))
                        debug_options.explicit_null_checks = TRUE;
                else if (!strcmp (arg, "gen-seq-points"))
 -                      debug_options.gen_seq_points_debug_data = TRUE;
 +                      debug_options.gen_sdb_seq_points = TRUE;
                else if (!strcmp (arg, "gen-compact-seq-points"))
                        debug_options.gen_seq_points_compact_data = TRUE;
                else if (!strcmp (arg, "init-stacks"))
@@@ -2984,10 -2957,8 +2983,8 @@@ mini_init (const char *filename, const 
        callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
        callbacks.tls_key_supported = mini_tls_key_supported;
  
-       if (mono_use_imt) {
-               callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
-               callbacks.get_imt_trampoline = mini_get_imt_trampoline;
-       }
+       callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
+       callbacks.get_imt_trampoline = mini_get_imt_trampoline;
  
        mono_install_callbacks (&callbacks);
  
                mono_marshal_use_aot_wrappers (TRUE);
        }
  
-       if (mono_use_imt) {
-               if (mono_aot_only)
-                       mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
-               else
-                       mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
-       }
+       if (mono_aot_only)
+               mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
+       else
+               mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
  
        /*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
        mono_arch_finish_init ();
diff --combined mono/mini/mini.h
index feb08be3afd203fdb570c613060deb9de04c93c8,eb4a5f102acbb409eea070e1aa57052631c6dfd1..d195176c84c86680e4a84e931f90d07362b83d56
  #endif
  
  /* Version number of the AOT file format */
 -#define MONO_AOT_FILE_VERSION 110
 +#define MONO_AOT_FILE_VERSION 112
  
  //TODO: This is x86/amd64 specific.
  #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
@@@ -482,7 -482,6 +482,6 @@@ extern gboolean mono_break_on_exc
  extern int mono_exc_esp_offset;
  extern gboolean mono_compile_aot;
  extern gboolean mono_aot_only;
- extern gboolean mono_use_imt;
  extern MonoMethodDesc *mono_inject_async_exc_method;
  extern int mono_inject_async_exc_pos;
  extern MonoMethodDesc *mono_break_at_bb_method;
@@@ -1123,14 -1122,6 +1122,14 @@@ typedef enum 
        /* The address of Nullable<T>.Box () */
        MONO_RGCTX_INFO_NULLABLE_CLASS_BOX,
        MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX,
 +      /* MONO_PATCH_INFO_VCALL_METHOD */
 +      MONO_RGCTX_INFO_VIRT_METHOD_CODE,
 +      /*
 +       * MONO_PATCH_INFO_VCALL_METHOD
 +       * Same as MONO_RGCTX_INFO_CLASS_BOX_TYPE, but for the class
 +       * which implements the method.
 +       */
 +      MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE
  } MonoRgctxInfoType;
  
  typedef struct _MonoRuntimeGenericContextInfoTemplate {
@@@ -1224,17 -1215,6 +1223,17 @@@ typedef struct MonoJumpInfoImtTramp 
  
  typedef struct MonoJumpInfoGSharedVtCall MonoJumpInfoGSharedVtCall;
  
 +/*
 + * Represents the method which is called when a virtual call is made to METHOD
 + * on a receiver of type KLASS.
 + */
 +typedef struct {
 +      /* Receiver class */
 +      MonoClass *klass;
 +      /* Virtual method */
 +      MonoMethod *method;
 +} MonoJumpInfoVirtMethod;
 +
  typedef struct MonoJumpInfo MonoJumpInfo;
  struct MonoJumpInfo {
        MonoJumpInfo *next;
                MonoGSharedVtMethodInfo *gsharedvt_method;
                MonoMethodSignature *sig;
                MonoDelegateClassMethodPair *del_tramp;
 +              /* MONO_PATCH_INFO_VIRT_METHOD */
 +              MonoJumpInfoVirtMethod *virt_method;
        } data;
  };
   
 -/* Contains information describing an rgctx entry */
 +/*
 + * Contains information for computing the
 + * property given by INFO_TYPE of the runtime
 + * object described by DATA.
 + */
  struct MonoJumpInfoRgctxEntry {
        MonoMethod *method;
        gboolean in_mrgctx;
@@@ -1543,7 -1517,7 +1542,7 @@@ typedef struct 
        guint            keep_cil_nops : 1;
        guint            gen_seq_points : 1;
        /* Generate seq points for use by the debugger */
 -      guint            gen_seq_points_debug_data : 1;
 +      guint            gen_sdb_seq_points : 1;
        guint            explicit_null_checks : 1;
        guint            compute_gc_maps : 1;
        guint            soft_breakpoints : 1;
        GHashTable       *token_info_hash;
        MonoCompileArch  arch;
        guint32          inline_depth;
 +      /* Size of memory reserved for thunks */
 +      int              thunk_area;
        guint32          exception_type;        /* MONO_EXCEPTION_* */
        guint32          exception_data;
        char*            exception_message;
@@@ -1911,7 -1883,7 +1910,7 @@@ typedef struct 
         * Whenever data such as next sequence points and flags is required.
         * Next sequence points and flags are required by the debugger agent.
         */
 -      gboolean gen_seq_points_debug_data;
 +      gboolean gen_sdb_seq_points;
        gboolean gen_seq_points_compact_data;
        gboolean explicit_null_checks;
        /*