X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini.c;h=28b66be959ff9fe33df01979916b3dd65ec2cc44;hb=4df4b7a47a07d924d7bfcfc53f43bd2319b54266;hp=5f035d7e4ef6b39d36069617e995d97219ad9a62;hpb=850f2f412499e8f47db7e72bfa80135f9661efff;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 5f035d7e4ef..28b66be959f 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -367,6 +367,8 @@ mono_print_method_from_ip (void *ip) MonoDomain *domain = mono_domain_get (); MonoDomain *target_domain = mono_domain_get (); FindTrampUserData user_data; + MonoGenericSharingContext*gsctx; + const char *shared_type; ji = mini_jit_info_table_find (domain, ip, &target_domain); if (!ji) { @@ -388,7 +390,16 @@ mono_print_method_from_ip (void *ip) method = mono_method_full_name (ji->method, TRUE); source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain); - g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name); + gsctx = mono_jit_info_get_generic_sharing_context (ji); + shared_type = ""; + if (gsctx) { + if (gsctx->var_is_vt || gsctx->mvar_is_vt) + shared_type = "gsharedvt "; + else + shared_type = "gshared "; + } + + g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name); if (source) g_print ("%s:%d\n", source->source_file, source->row); @@ -862,12 +873,10 @@ handle_enum: goto handle_enum; case MONO_TYPE_VAR: case MONO_TYPE_MVAR: - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ - g_assert (cfg->generic_sharing_context); - return OP_STORE_MEMBASE_REG; + if (mini_type_var_is_vt (cfg, type)) + return OP_STOREV_MEMBASE; + else + return OP_STORE_MEMBASE_REG; default: g_error ("unknown type 0x%02x in type_to_store_membase", type->type); } @@ -928,12 +937,11 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type) break; case MONO_TYPE_VAR: case MONO_TYPE_MVAR: - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ g_assert (cfg->generic_sharing_context); - return OP_LOAD_MEMBASE; + if (mini_type_var_is_vt (cfg, type)) + return OP_LOADV_MEMBASE; + else + return OP_LOAD_MEMBASE; default: g_error ("unknown type 0x%02x in type_to_load_membase", type->type); } @@ -944,26 +952,28 @@ static guint mini_type_to_ldind (MonoCompile* cfg, MonoType *type) { if (cfg->generic_sharing_context && !type->byref) { - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ - if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) - return CEE_LDIND_REF; + if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) { + if (mini_type_var_is_vt (cfg, type)) + return CEE_LDOBJ; + else + return CEE_LDIND_REF; + } } return mono_type_to_ldind (type); } +#ifndef DISABLE_JIT + guint mini_type_to_stind (MonoCompile* cfg, MonoType *type) { if (cfg->generic_sharing_context && !type->byref) { - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ - if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) - return CEE_STIND_REF; + if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) { + if (mini_type_var_is_vt (cfg, type)) + return CEE_STOBJ; + else + return CEE_STIND_REF; + } } return mono_type_to_stind (type); } @@ -1098,6 +1108,8 @@ mono_decompose_op_imm (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins) bb->max_vreg = MAX (bb->max_vreg, cfg->next_vreg); } +#endif + static void set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst) { @@ -1153,6 +1165,9 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, inst->backend.is_pinvoke = 0; inst->dreg = vreg; + if (inst->klass->exception_type) + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); + if (cfg->compute_gc_maps) { if (type->byref) { mono_mark_vreg_as_mp (cfg, vreg); @@ -1746,18 +1761,22 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_ vmv = current; inst = cfg->varinfo [vmv->idx]; + t = mono_type_get_underlying_type (inst->inst_vtype); + if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t)) + t = mini_get_gsharedvt_alloc_type_for_type (cfg, t); + /* inst->backend.is_pinvoke indicates native sized value types, this is used by the * pinvoke wrappers when they call functions returning structures */ - if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) { - size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align); + if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) { + size = mono_class_native_size (mono_class_from_mono_type (t), &align); } else { int ialign; - size = mono_type_size (inst->inst_vtype, &ialign); + size = mono_type_size (t, &ialign); align = ialign; - if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype))) + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t))) align = 16; } @@ -1765,7 +1784,6 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_ if (cfg->disable_reuse_stack_slots) reuse_slot = FALSE; - t = mono_type_get_underlying_type (inst->inst_vtype); switch (t->type) { case MONO_TYPE_GENERICINST: if (!mono_type_generic_inst_is_valuetype (t)) { @@ -2039,17 +2057,24 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s vmv = l->data; inst = cfg->varinfo [vmv->idx]; + t = mono_type_get_underlying_type (inst->inst_vtype); + if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t)) + t = mini_get_gsharedvt_alloc_type_for_type (cfg, t); + /* inst->backend.is_pinvoke indicates native sized value types, this is used by the * pinvoke wrappers when they call functions returning structures */ - if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) { - size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align); + if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) { + size = mono_class_native_size (mono_class_from_mono_type (t), &align); } else { int ialign; - size = mono_type_size (inst->inst_vtype, &ialign); + size = mono_type_size (t, &ialign); align = ialign; - if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype))) + if (mono_class_from_mono_type (t)->exception_type) + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); + + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t))) align = 16; } @@ -2057,7 +2082,6 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s if (cfg->disable_reuse_stack_slots) reuse_slot = FALSE; - t = mono_type_get_underlying_type (inst->inst_vtype); if (t->byref) { slot_info = &scalar_stack_slots [MONO_TYPE_I]; } else { @@ -2110,9 +2134,13 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s if (cfg->disable_reuse_ref_stack_slots) reuse_slot = FALSE; break; - + case MONO_TYPE_VAR: + case MONO_TYPE_MVAR: + slot_info = &scalar_stack_slots [t->type]; + break; default: slot_info = &scalar_stack_slots [t->type]; + break; } } @@ -2264,8 +2292,8 @@ mono_find_jit_opcode_emulation (int opcode) return NULL; } -void -mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw) +static void +register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, const char *symbol, gboolean no_throw) { MonoJitICallInfo *info; MonoMethodSignature *sig = mono_create_icall_signature (sigstr); @@ -2273,7 +2301,7 @@ mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr g_assert (!sig->hasthis); g_assert (sig->param_count < 3); - info = mono_register_jit_icall (func, name, sig, no_throw); + info = mono_register_jit_icall_full (func, name, sig, no_throw, symbol); if (emul_opcode_num >= emul_opcode_alloced) { int incr = emul_opcode_alloced? emul_opcode_alloced/2: 16; @@ -2287,11 +2315,28 @@ mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] |= (1 << (opcode & EMUL_HIT_MASK)); } +/* + * For JIT icalls implemented in C. + * NAME should be the same as the name of the C function whose address is FUNC. + */ static void register_icall (gpointer func, const char *name, const char *sigstr, gboolean save) { MonoMethodSignature *sig; + if (sigstr) + sig = mono_create_icall_signature (sigstr); + else + sig = NULL; + + mono_register_jit_icall_full (func, name, sig, save, save ? name : NULL); +} + +static void +register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolean save) +{ + MonoMethodSignature *sig; + if (sigstr) sig = mono_create_icall_signature (sigstr); else @@ -2554,7 +2599,8 @@ mono_get_lmf_addr (void) #else MonoJitTlsData *jit_tls; - if ((jit_tls = mono_native_tls_get_value (mono_jit_tls_id))) + jit_tls = mono_native_tls_get_value (mono_jit_tls_id); + if (G_LIKELY (jit_tls)) return &jit_tls->lmf; /* @@ -2898,6 +2944,10 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info) memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry)); res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data); break; + case MONO_PATCH_INFO_GSHAREDVT_CALL: + res->data.gsharedvt = mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall)); + memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall)); + break; default: break; } @@ -2934,6 +2984,8 @@ mono_patch_info_hash (gconstpointer data) case MONO_PATCH_INFO_SFLDA: case MONO_PATCH_INFO_SEQ_POINT_INFO: return (ji->type << 8) | (gssize)ji->data.target; + case MONO_PATCH_INFO_GSHAREDVT_CALL: + return (ji->type << 8) | (gssize)ji->data.gsharedvt->method; default: return (ji->type << 8); } @@ -2970,13 +3022,18 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) break; case MONO_PATCH_INFO_INTERNAL_METHOD: return g_str_equal (ji1->data.name, ji2->data.name); - case MONO_PATCH_INFO_RGCTX_FETCH: { MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry; MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry; return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data); } + case MONO_PATCH_INFO_GSHAREDVT_CALL: { + MonoJumpInfoGSharedVtCall *c1 = ji1->data.gsharedvt; + MonoJumpInfoGSharedVtCall *c2 = ji2->data.gsharedvt; + + return c1->sig == c2->sig && c1->method == c2->method; + } default: if (ji1->data.target != ji2->data.target) return 0; @@ -3028,6 +3085,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, target = mono_icall_get_wrapper (mi); break; } + case MONO_PATCH_INFO_JIT_ICALL_ADDR: { + MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name); + if (!mi) { + g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name); + g_assert_not_reached (); + } + target = mi->func; + break; + } case MONO_PATCH_INFO_METHOD_JUMP: target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE); #if defined(__native_client__) && defined(__native_client_codegen__) @@ -3211,15 +3277,6 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, g_error ("Unregistered icall '%s'\n", mono_method_full_name (patch_info->data.method, TRUE)); } break; - case MONO_PATCH_INFO_JIT_ICALL_ADDR: { - MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name); - if (!mi) { - g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name); - g_assert_not_reached (); - } - target = mi->func; - break; - } case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG: target = mono_thread_interruption_request_flag (); break; @@ -3250,6 +3307,16 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, case MONO_PATCH_INFO_FIELD: slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method)); break; + case MONO_PATCH_INFO_SIGNATURE: + slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method)); + break; + case MONO_PATCH_INFO_GSHAREDVT_CALL: { + MonoJumpInfoGSharedVtCall *call_info = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall)); + + memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall)); + slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method)); + break; + } default: g_assert_not_reached (); break; @@ -3295,6 +3362,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, target = mono_domain_alloc0 (domain, sizeof (gpointer)); break; } + case MONO_PATCH_INFO_JIT_TLS_ID: { + target = (gpointer)mono_jit_tls_id; + break; + } default: g_assert_not_reached (); } @@ -3393,8 +3464,6 @@ mono_compile_create_vars (MonoCompile *cfg) mono_arch_create_vars (cfg); } -#endif /* #ifndef DISABLE_JIT */ - void mono_print_code (MonoCompile *cfg, const char* msg) { @@ -3404,8 +3473,6 @@ mono_print_code (MonoCompile *cfg, const char* msg) mono_print_bb (bb, msg); } -#ifndef DISABLE_JIT - static void mono_postprocess_patches (MonoCompile *cfg) { @@ -3423,27 +3490,14 @@ mono_postprocess_patches (MonoCompile *cfg) */ if (info) { //printf ("TEST %s %p\n", info->name, patch_info->data.target); - // FIXME: CLEAN UP THIS MESS. - if ((cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && - strstr (cfg->method->name, info->name)) { - /* - * This is an icall wrapper, and this is a call to the - * wrapped function. - */ - if (cfg->compile_aot) { - patch_info->type = MONO_PATCH_INFO_JIT_ICALL_ADDR; - patch_info->data.name = info->name; - } - } else { - /* for these array methods we currently register the same function pointer - * since it's a vararg function. But this means that mono_find_jit_icall_by_addr () - * will return the incorrect one depending on the order they are registered. - * See tests/test-arr.cs - */ - if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) { - patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD; - patch_info->data.name = info->name; - } + /* for these array methods we currently register the same function pointer + * since it's a vararg function. But this means that mono_find_jit_icall_by_addr () + * will return the incorrect one depending on the order they are registered. + * See tests/test-arr.cs + */ + if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) { + patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD; + patch_info->data.name = info->name; } } @@ -3895,6 +3949,34 @@ mono_handle_out_of_line_bblock (MonoCompile *cfg) } } +#endif /* #ifndef DISABLE_JIT */ + +static MonoJitInfo* +create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info) +{ + MonoDomain *domain = mono_get_root_domain (); + MonoJitInfo *jinfo; + guint8 *uw_info; + guint32 info_len; + + if (info->uw_info) { + uw_info = info->uw_info; + info_len = info->uw_info_len; + } else { + uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len); + } + + jinfo = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO); + jinfo->method = wrapper; + jinfo->code_start = info->code; + jinfo->code_size = info->code_size; + jinfo->used_regs = mono_cache_unwind_info (uw_info, info_len); + + return jinfo; +} + +#ifndef DISABLE_JIT + static MonoJitInfo* create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) { @@ -3985,7 +4067,11 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) gi = mono_jit_info_get_generic_jit_info (jinfo); g_assert (gi); - gi->generic_sharing_context = cfg->generic_sharing_context; + if (cfg->method->dynamic) + gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1); + else + gi->generic_sharing_context = mono_domain_alloc0 (cfg->domain, sizeof (MonoGenericSharingContext)); + memcpy (gi->generic_sharing_context, cfg->generic_sharing_context, sizeof (MonoGenericSharingContext)); if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) || mini_method_get_context (method_to_compile)->method_inst || @@ -4206,67 +4292,165 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) } #endif +static MonoType* +get_gsharedvt_type (MonoType *t) +{ + MonoGenericParam *par = t->data.generic_param; + MonoType *res; + + /* + * Create an anonymous gparam with a different serial so normal gshared and gsharedvt methods have + * a different instantiation. + */ + g_assert (mono_generic_param_info (par)); + par = g_memdup (par, sizeof (MonoGenericParamFull)); + par->owner = NULL; + // FIXME: + par->image = mono_defaults.corlib; + par->serial = 1; + res = mono_metadata_type_dup (NULL, t); + res->data.generic_param = par; + + return res; +} + +static gboolean +is_gsharedvt_type (MonoType *t) +{ + return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->serial == 1; +} + +/* Return whenever METHOD is a gsharedvt method */ +static gboolean +is_gsharedvt_method (MonoMethod *method) +{ + MonoGenericContext *context; + MonoGenericInst *inst; + int i; + + if (!method->is_inflated) + return FALSE; + context = mono_method_get_context (method); + inst = context->class_inst; + if (inst) { + for (i = 0; i < inst->type_argc; ++i) + if (is_gsharedvt_type (inst->type_argv [i])) + return TRUE; + } + inst = context->method_inst; + if (inst) { + for (i = 0; i < inst->type_argc; ++i) + if (is_gsharedvt_type (inst->type_argv [i])) + return TRUE; + } + return FALSE; +} + +static gboolean +has_ref_constraint (MonoGenericParamInfo *info) +{ + MonoClass **constraints; + + //return FALSE; + + if (info && info->constraints) { + constraints = info->constraints; + + while (*constraints) { + MonoClass *cklass = *constraints; + if (!(cklass == mono_defaults.object_class || (cklass->image == mono_defaults.corlib && !strcmp (cklass->name, "ValueType")) || MONO_CLASS_IS_INTERFACE (cklass))) + return TRUE; + constraints ++; + } + } + return FALSE; +} + +static MonoGenericInst* +get_shared_inst (MonoGenericInst *inst, MonoGenericInst *shared_inst, MonoGenericContainer *container, gboolean all_vt, gboolean gsharedvt) +{ + MonoGenericInst *res; + MonoType **type_argv; + int i; + + type_argv = g_new0 (MonoType*, inst->type_argc); + for (i = 0; i < inst->type_argc; ++i) { + if (!all_vt && (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)) { + type_argv [i] = shared_inst->type_argv [i]; + } else if (all_vt) { + if (container && has_ref_constraint (&container->type_params [i].info)) + type_argv [i] = shared_inst->type_argv [i]; + else + type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]); + } else if (gsharedvt) { + type_argv [i] = get_gsharedvt_type (shared_inst->type_argv [i]); + } else { + type_argv [i] = inst->type_argv [i]; + } + } + + res = mono_metadata_get_generic_inst (inst->type_argc, type_argv); + g_free (type_argv); + return res; +} + /* - * mini_get_shared_method: + * mini_get_shared_method_full: * * Return the method which is actually compiled/registered when doing generic sharing. + * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation. + * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints. + * METHOD can be a non-inflated generic method. */ MonoMethod* -mini_get_shared_method (MonoMethod *method) +mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt) { MonoGenericContext shared_context; MonoMethod *declaring_method, *res; - int i; gboolean partial = FALSE; + gboolean gsharedvt = FALSE; + MonoGenericContainer *class_container, *method_container = NULL; - if (method->is_generic || method->klass->generic_container) + if (method->is_generic || method->klass->generic_container) { declaring_method = method; - else + } else { declaring_method = mono_method_get_declaring_generic_method (method); + } if (declaring_method->is_generic) shared_context = mono_method_get_generic_container (declaring_method)->context; else shared_context = declaring_method->klass->generic_container->context; - /* Handle partial sharing */ - if (method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE)) { + /* Handle gsharedvt/partial sharing */ + if ((method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) || + is_gsharedvt || mini_is_gsharedvt_sharable_method (method)) { MonoGenericContext *context = mono_method_get_context (method); MonoGenericInst *inst; - MonoType **type_argv; + + gsharedvt = is_gsharedvt || mini_is_gsharedvt_sharable_method (method); + + class_container = declaring_method->klass->generic_container; + method_container = mono_method_get_generic_container (declaring_method); /* * Create the shared context by replacing the ref type arguments with * type parameters, and keeping the rest. */ partial = TRUE; - inst = context->class_inst; - if (inst) { - type_argv = g_new0 (MonoType*, inst->type_argc); - for (i = 0; i < inst->type_argc; ++i) { - if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR) - type_argv [i] = shared_context.class_inst->type_argv [i]; - else - type_argv [i] = inst->type_argv [i]; - } - - shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv); - g_free (type_argv); - } - - inst = context->method_inst; - if (inst) { - type_argv = g_new0 (MonoType*, inst->type_argc); - for (i = 0; i < inst->type_argc; ++i) { - if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR) - type_argv [i] = shared_context.method_inst->type_argv [i]; - else - type_argv [i] = inst->type_argv [i]; - } + if (context) + inst = context->class_inst; + else + inst = shared_context.class_inst; + if (inst) + shared_context.class_inst = get_shared_inst (inst, shared_context.class_inst, class_container, all_vt, gsharedvt); - shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv); - g_free (type_argv); - } + if (context) + inst = context->method_inst; + else + inst = shared_context.method_inst; + if (inst) + shared_context.method_inst = get_shared_inst (inst, shared_context.method_inst, method_container, all_vt, gsharedvt); } res = mono_class_inflate_generic_method (declaring_method, &shared_context); @@ -4277,6 +4461,44 @@ mini_get_shared_method (MonoMethod *method) return res; } +MonoMethod* +mini_get_shared_method (MonoMethod *method) +{ + return mini_get_shared_method_full (method, FALSE, FALSE); +} + +void +mini_init_gsctx (MonoGenericContext *context, MonoGenericSharingContext *gsctx) +{ + MonoGenericInst *inst; + int i; + + memset (gsctx, 0, sizeof (MonoGenericSharingContext)); + + if (context->class_inst) { + inst = context->class_inst; + gsctx->var_is_vt = g_new0 (gboolean, inst->type_argc); + + for (i = 0; i < inst->type_argc; ++i) { + MonoType *type = inst->type_argv [i]; + + if ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && type->data.generic_param->serial == 1) + gsctx->var_is_vt [i] = TRUE; + } + } + if (context->method_inst) { + inst = context->method_inst; + gsctx->mvar_is_vt = g_new0 (gboolean, inst->type_argc); + + for (i = 0; i < inst->type_argc; ++i) { + MonoType *type = inst->type_argv [i]; + + if ((type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) && type->data.generic_param->serial == 1) + gsctx->mvar_is_vt [i] = TRUE; + } + } +} + #ifndef DISABLE_JIT /* * mini_method_compile: @@ -4302,6 +4524,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool gboolean deadce_has_run = FALSE; gboolean try_generic_shared, try_llvm = FALSE; MonoMethod *method_to_compile, *method_to_register; + gboolean method_is_gshared = FALSE; InterlockedIncrement (&mono_jit_stats.methods_compiled); if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) @@ -4316,10 +4539,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool * FIXME: Remove the method->klass->generic_class limitation. */ try_generic_shared = mono_class_generic_sharing_enabled (method->klass) && - (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl (method, TRUE))); + (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl_full (method, TRUE, FALSE, FALSE))); else try_generic_shared = mono_class_generic_sharing_enabled (method->klass) && - (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE); + (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE); if (opts & MONO_OPT_GSHARED) { if (try_generic_shared) @@ -4328,16 +4551,34 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool mono_stats.generics_unsharable_methods++; } + if (mini_is_gsharedvt_sharable_method (method)) { + if (!mono_debug_count ()) + try_generic_shared = FALSE; + if (compile_aot) + try_generic_shared = FALSE; + } + + if (is_gsharedvt_method (method)) { + /* We are AOTing a gshared method directly */ + method_is_gshared = TRUE; + g_assert (compile_aot); + try_generic_shared = TRUE; + } + #ifdef ENABLE_LLVM try_llvm = mono_use_llvm; #endif restart_compile: - if (try_generic_shared) { - method_to_compile = mini_get_shared_method (method); - g_assert (method_to_compile); - } else { + if (method_is_gshared) { method_to_compile = method; + } else { + if (try_generic_shared) { + method_to_compile = mini_get_shared_method (method); + g_assert (method_to_compile); + } else { + method_to_compile = method; + } } cfg = g_new0 (MonoCompile, 1); @@ -4356,18 +4597,43 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->explicit_null_checks = debug_options.explicit_null_checks; cfg->soft_breakpoints = debug_options.soft_breakpoints; if (try_generic_shared) - cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context; + cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->gsctx; cfg->compile_llvm = try_llvm; cfg->token_info_hash = g_hash_table_new (NULL, NULL); if (cfg->gen_seq_points) cfg->seq_points = g_ptr_array_new (); - if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) { + if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container || method_is_gshared)) { cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; return cfg; } + if (cfg->generic_sharing_context && (mini_is_gsharedvt_sharable_method (method) || method_is_gshared)) { + MonoMethodInflated *inflated; + MonoGenericContext *context; + + // FIXME: Free the contents of gsctx if compilation fails + if (method_is_gshared) { + g_assert (method->is_inflated); + inflated = (MonoMethodInflated*)method; + context = &inflated->context; + + /* We are compiling a gsharedvt method directly */ + g_assert (compile_aot); + } else { + g_assert (method_to_compile->is_inflated); + inflated = (MonoMethodInflated*)method_to_compile; + context = &inflated->context; + } + + mini_init_gsctx (context, &cfg->gsctx); + + cfg->gsharedvt = TRUE; + // FIXME: + cfg->disable_llvm = TRUE; + } + if (cfg->generic_sharing_context) { method_to_register = method_to_compile; } else { @@ -4507,12 +4773,19 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if (cfg->verbose_level > 0) { char *method_name; + + method_name = mono_method_full_name (method, TRUE); + g_print ("converting %s%s%smethod %s\n", COMPILE_LLVM (cfg) ? "llvm " : "", cfg->gsharedvt ? "gsharedvt " : "", (cfg->generic_sharing_context && !cfg->gsharedvt) ? "gshared " : "", method_name); + /* if (COMPILE_LLVM (cfg)) g_print ("converting llvm method %s\n", method_name = mono_method_full_name (method, TRUE)); + else if (cfg->gsharedvt) + g_print ("converting gsharedvt method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE)); else if (cfg->generic_sharing_context) g_print ("converting shared method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE)); else g_print ("converting method %s\n", method_name = mono_method_full_name (method, TRUE)); + */ g_free (method_name); } @@ -5059,9 +5332,16 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool mono_domain_unlock (cfg->domain); } +#if 0 + if (cfg->gsharedvt) + printf ("GSHAREDVT: %s\n", mono_method_full_name (cfg->method, TRUE)); +#endif + /* collect statistics */ +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->jit_methods++; mono_perfcounters->jit_bytes += header->code_size; +#endif mono_jit_stats.allocated_code_size += cfg->code_len; code_size_ratio = cfg->code_len; if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) { @@ -5130,7 +5410,7 @@ lookup_method_inner (MonoDomain *domain, MonoMethod *method) if (ji) return ji; - if (!mono_method_is_generic_sharable_impl (method, FALSE)) + if (!mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) return NULL; return mono_domain_lookup_shared_generic (domain, method); } @@ -5288,9 +5568,42 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in return NULL; } + if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) { + WrapperInfo *info = mono_marshal_get_wrapper_info (method); + + if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) { + static MonoTrampInfo *in_tinfo, *out_tinfo; + MonoTrampInfo *tinfo; + MonoJitInfo *jinfo; + gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN; + + if (is_in && in_tinfo) + return in_tinfo->code; + else if (!is_in && out_tinfo) + return out_tinfo->code; + + /* + * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH + * works. + * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms + */ + if (mono_aot_only) + mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo); + else + mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE); + jinfo = create_jit_info_for_trampoline (method, tinfo); + mono_jit_info_table_add (mono_get_root_domain (), jinfo); + if (is_in) + in_tinfo = tinfo; + else + out_tinfo = tinfo; + return tinfo->code; + } + } + if (mono_aot_only) { char *fullname = mono_method_full_name (method, TRUE); - char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only.\n", fullname); + char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname); *jit_ex = mono_get_exception_execution_engine (msg); g_free (fullname); @@ -5412,8 +5725,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in mono_domain_jit_code_hash_unlock (target_domain); code = cfg->native_code; - if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE)) + if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) mono_stats.generics_shared_methods++; + if (cfg->gsharedvt) + mono_stats.gsharedvt_methods++; } else { mono_domain_jit_code_hash_unlock (target_domain); } @@ -5499,17 +5814,16 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException MonoJitInfo *info; gpointer code, p; MonoJitICallInfo *callinfo = NULL; + WrapperInfo *winfo = NULL; /* * ICALL wrappers are handled specially, since there is only one copy of them * shared by all appdomains. */ - if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) { - const char *icall_name; - - icall_name = method->name + strlen ("__icall_wrapper_"); - g_assert (icall_name); - callinfo = mono_find_jit_icall_by_name (icall_name); + if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) + winfo = mono_marshal_get_wrapper_info (method); + if (winfo && winfo->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER) { + callinfo = mono_find_jit_icall_by_addr (winfo->d.icall.func); g_assert (callinfo); /* Must be domain neutral since there is only one copy */ @@ -5597,7 +5911,7 @@ static void invalidated_delegate_trampoline (char *desc) { g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n" - "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.", + "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.", desc); } #endif @@ -5792,8 +6106,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec } } - if (mono_method_needs_static_rgctx_invoke (method, FALSE)) - info->compiled_method = mono_create_static_rgctx_trampoline (method, info->compiled_method); + info->compiled_method = mini_add_method_trampoline (NULL, method, info->compiled_method, mono_method_needs_static_rgctx_invoke (method, FALSE)); } /* @@ -5817,7 +6130,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec supported = FALSE; } - if (method->klass->contextbound || !info->compiled_method) + if (mono_class_is_contextbound (method->klass) || !info->compiled_method) supported = FALSE; if (supported) @@ -6089,6 +6402,7 @@ SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler) mono_arch_handle_exception (ctx, exc); } +#ifndef DISABLE_REMOTING /* mono_jit_create_remoting_trampoline: * @method: pointer to the method info * @@ -6109,14 +6423,16 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon } if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || - (mono_method_signature (method)->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) { + (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) { nm = mono_marshal_get_remoting_invoke_for_target (method, target); addr = mono_compile_method (nm); - } else { + } else + { addr = mono_compile_method (method); } return mono_get_addr_from_ftnptr (addr); } +#endif static gpointer *vtable_trampolines; static int vtable_trampolines_size; @@ -6357,9 +6673,10 @@ mini_free_jit_domain_info (MonoDomain *domain) g_hash_table_destroy (info->runtime_invoke_hash); g_hash_table_destroy (info->seq_points); g_hash_table_destroy (info->arch_seq_points); - if (info->agent_info) mono_debugger_agent_free_domain_info (domain); + if (info->gsharedvt_arg_tramp_hash) + g_hash_table_destroy (info->gsharedvt_arg_tramp_hash); g_free (domain->runtime_info); domain->runtime_info = NULL; @@ -6385,6 +6702,11 @@ mini_init (const char *filename, const char *runtime_version) if (!default_opt_set) default_opt = mono_parse_default_optimizations (NULL); +#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED + if (mono_aot_only) + mono_set_generic_sharing_vt_supported (TRUE); +#endif + InitializeCriticalSection (&jit_mutex); #ifdef MONO_DEBUGGER_SUPPORTED @@ -6473,7 +6795,6 @@ mini_init (const char *filename, const char *runtime_version) g_thread_init (NULL); mono_native_tls_alloc (&mono_jit_tls_id, NULL); - setup_jit_tls_data ((gpointer)-1, mono_thread_abort); if (default_opt & MONO_OPT_AOT) mono_aot_init (); @@ -6505,7 +6826,9 @@ mini_init (const char *filename, const char *runtime_version) mono_install_free_method (mono_jit_free_method); mono_install_trampoline (mono_create_jit_trampoline); mono_install_jump_trampoline (mono_create_jump_trampoline); +#ifndef DISABLE_REMOTING mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline); +#endif mono_install_delegate_trampoline (mono_create_delegate_trampoline); mono_install_create_domain_hook (mini_create_jit_domain_info); mono_install_free_domain_hook (mini_free_jit_domain_info); @@ -6566,7 +6889,14 @@ mini_init (const char *filename, const char *runtime_version) mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers); +#ifdef PLATFORM_ANDROID + mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal", + mono_debugger_agent_unhandled_exception); +#endif + +#ifndef DISABLE_JIT mono_create_helper_signatures (); +#endif register_jit_stats (); @@ -6585,15 +6915,16 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE); register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE); - register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE); - register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE); - register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", - "void ptr", TRUE); + register_dyn_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE); + register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE); + register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE); register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE); register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE); register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE); +#ifndef DISABLE_REMOTING register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE); register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE); +#endif #if defined(__native_client__) || defined(__native_client_codegen__) register_icall (mono_nacl_gc, "mono_nacl_gc", "void", TRUE); @@ -6604,102 +6935,102 @@ mini_init (const char *filename, const char *runtime_version) * rule to the burg files, because we need the arity information to be correct. */ #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS - mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, TRUE); - mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, FALSE); - mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, FALSE); - mono_register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, FALSE); - mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, FALSE); - mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, FALSE); - mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, FALSE); + register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", TRUE); + register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE); + register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE); + register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE); + register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", "long long long", mono_llrem_un, "mono_llrem_un", FALSE); + register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", "long long long", mono_llmult_ovf_un, "mono_llmult_ovf_un", FALSE); + register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", "long long long", mono_llmult_ovf, "mono_llmult_ovf", FALSE); #endif #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS - mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, TRUE); - mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, TRUE); - mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, TRUE); + register_opcode_emulation (OP_LSHL, "__emul_lshl", "long long int32", mono_lshl, "mono_lshl", TRUE); + register_opcode_emulation (OP_LSHR, "__emul_lshr", "long long int32", mono_lshr, "mono_lshr", TRUE); + register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", "long long int32", mono_lshr_un, "mono_lshr_un", TRUE); #endif #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV) - mono_register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, FALSE); - mono_register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE); - mono_register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, FALSE); - mono_register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, FALSE); + register_opcode_emulation (OP_IDIV, "__emul_op_idiv", "int32 int32 int32", mono_idiv, "mono_idiv", FALSE); + register_opcode_emulation (OP_IDIV_UN, "__emul_op_idiv_un", "int32 int32 int32", mono_idiv_un, "mono_idiv_un", FALSE); + register_opcode_emulation (OP_IREM, "__emul_op_irem", "int32 int32 int32", mono_irem, "mono_irem", FALSE); + register_opcode_emulation (OP_IREM_UN, "__emul_op_irem_un", "int32 int32 int32", mono_irem_un, "mono_irem_un", FALSE); #endif #ifdef MONO_ARCH_EMULATE_MUL_DIV - mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE); + register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, "mono_imul", TRUE); #endif #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF) - mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE); - mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE); + register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, "mono_imul_ovf", FALSE); + register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE); #endif #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT) - mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE); + register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE); #endif - mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, FALSE); + register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE); + register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE); + register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE); + register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE); #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8 - mono_register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, FALSE); + register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE); #endif #ifdef MONO_ARCH_EMULATE_CONV_R8_UN - mono_register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, FALSE); + register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE); #endif #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8 - mono_register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, FALSE); + register_opcode_emulation (OP_LCONV_TO_R8, "__emul_lconv_to_r8", "double long", mono_lconv_to_r8, "mono_lconv_to_r8", FALSE); #endif #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4 - mono_register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, FALSE); + register_opcode_emulation (OP_LCONV_TO_R4, "__emul_lconv_to_r4", "float long", mono_lconv_to_r4, "mono_lconv_to_r4", FALSE); #endif #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN - mono_register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, FALSE); + register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE); #endif #ifdef MONO_ARCH_EMULATE_FREM #if defined(__default_codegen__) - mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE); + register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE); #elif defined(__native_client_codegen__) - mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, FALSE); + register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE); #endif #endif #ifdef MONO_ARCH_SOFT_FLOAT - mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE); - mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE); - mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE); - mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE); - mono_register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, FALSE); - mono_register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE); - mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE); + register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE); + register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE); + register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE); + register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE); + register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE); + register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE); + register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE); + register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE); + register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE); + register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE); + register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE); + register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE); #if SIZEOF_VOID_P == 4 - mono_register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, FALSE); -#endif - - mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE); - mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE); - mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE); - mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE); - mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE); - mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE); - mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE); - mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE); - mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE); - mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE); - - mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE); - mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE); - mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE); - mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE); - mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE); + register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE); +#endif + + register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE); + register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE); + register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE); + register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE); + register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE); + register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE); + register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE); + register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE); + register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE); + register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE); + + register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE); + register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE); + register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE); + register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE); + register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE); register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE); register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE); @@ -6712,7 +7043,7 @@ mini_init (const char *filename, const char *runtime_version) #endif #if SIZEOF_REGISTER == 4 - mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE); + register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE); #endif /* other jit icalls */ @@ -6724,7 +7055,7 @@ mini_init (const char *filename, const char *runtime_version) "ptr ptr ptr ptr", FALSE); register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE); register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE); - register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE); + register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE); register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE); register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE); register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE); @@ -6733,10 +7064,10 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE); register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE); register_icall (mono_ldvirtfn_gshared, "mono_ldvirtfn_gshared", "ptr object ptr", FALSE); - register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE); - register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE); - register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE); - register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE); + register_icall (mono_helper_compile_generic_method, "mono_helper_compile_generic_method", "ptr object ptr ptr", FALSE); + register_icall (mono_helper_ldstr, "mono_helper_ldstr", "object ptr int", FALSE); + register_icall (mono_helper_ldstr_mscorlib, "mono_helper_ldstr_mscorlib", "object int", FALSE); + register_icall (mono_helper_newobj_mscorlib, "mono_helper_newobj_mscorlib", "object int", FALSE); register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE); register_icall (mono_object_castclass, "mono_object_castclass", "object object ptr", FALSE); register_icall (mono_break, "mono_break", NULL, TRUE); @@ -6746,8 +7077,11 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE); register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE); register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE); + register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int int int int", FALSE); register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE); register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE); + register_icall (mono_object_tostring_gsharedvt, "mono_object_tostring_gsharedvt", "object ptr ptr ptr", TRUE); + register_icall (mono_object_gethashcode_gsharedvt, "mono_object_gethashcode_gsharedvt", "int ptr ptr ptr", TRUE); register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE); @@ -6755,7 +7089,10 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE); register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE); +#endif +#ifdef TARGET_IOS + register_icall (pthread_getspecific, "pthread_getspecific", NULL, TRUE); #endif mono_generic_sharing_init (); @@ -6818,6 +7155,7 @@ print_jit_stats (void) g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods); g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods); g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods); + g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods); g_print ("Dynamic code allocs: %ld\n", mono_stats.dynamic_code_alloc_count); g_print ("Dynamic code bytes: %ld\n", mono_stats.dynamic_code_bytes_count); @@ -6925,14 +7263,17 @@ mini_cleanup (MonoDomain *domain) DeleteCriticalSection (&jit_mutex); DeleteCriticalSection (&mono_delegate_section); + +#ifdef USE_JUMP_TABLES + mono_jumptable_cleanup (); +#endif } void mono_set_defaults (int verbose_level, guint32 opts) { mini_verbose = verbose_level; - default_opt = opts; - default_opt_set = TRUE; + mono_set_optimizations (opts); } void @@ -6946,6 +7287,9 @@ mono_set_optimizations (guint32 opts) { default_opt = opts; default_opt_set = TRUE; +#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED + mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0)); +#endif } void @@ -7002,10 +7346,12 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data) invoke = mono_marshal_get_runtime_invoke (method, FALSE); mono_compile_method (invoke); } - if (method->klass->marshalbyref && mono_method_signature (method)->hasthis) { +#ifndef DISABLE_REMOTING + if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) { invoke = mono_marshal_get_remoting_invoke_with_check (method); mono_compile_method (invoke); } +#endif } /* Load and precompile referenced assemblies as well */ @@ -7050,3 +7396,148 @@ mono_cfg_set_exception (MonoCompile *cfg, int type) } #endif + +/* Dummy versions of some arch specific functions to avoid ifdefs at call sites */ + +#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED + +gboolean +mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig) +{ + return FALSE; +} + +gpointer +mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +#endif + +#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(MONOTOUCH) && !defined(MONO_EXTENSIONS) + +gboolean +mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig) +{ + return FALSE; +} + +gpointer +mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) +{ + NOT_IMPLEMENTED; + return NULL; +} + +#endif + +#ifdef USE_JUMP_TABLES +#define DEFAULT_JUMPTABLE_CHUNK_ELEMENTS 128 + +typedef struct MonoJumpTableChunk { + guint32 total; + guint32 active; + struct MonoJumpTableChunk *previous; + /* gpointer entries[total]; */ +} MonoJumpTableChunk; + +static MonoJumpTableChunk* g_jumptable = NULL; +#define mono_jumptable_lock() EnterCriticalSection (&jumptable_mutex) +#define mono_jumptable_unlock() LeaveCriticalSection (&jumptable_mutex) +static CRITICAL_SECTION jumptable_mutex; + +static MonoJumpTableChunk* +mono_create_jumptable_chunk (guint32 max_entries) +{ + guint32 size = sizeof (MonoJumpTableChunk) + max_entries * sizeof(gpointer); + MonoJumpTableChunk *chunk = (MonoJumpTableChunk*) g_new0 (guchar, size); + chunk->total = max_entries; + return chunk; +} + +void +mono_jumptable_init (void) +{ + if (g_jumptable == NULL) { + InitializeCriticalSection (&jumptable_mutex); + g_jumptable = mono_create_jumptable_chunk (DEFAULT_JUMPTABLE_CHUNK_ELEMENTS); + } +} + +gpointer* +mono_jumptable_add_entry (void) +{ + return mono_jumptable_add_entries (1); +} + +gpointer* +mono_jumptable_add_entries (guint32 entries) +{ + guint32 index; + gpointer *result; + + mono_jumptable_init (); + mono_jumptable_lock (); + index = g_jumptable->active; + if (index + entries >= g_jumptable->total) { + /* + * Grow jumptable, by adding one more chunk. + * We cannot realloc jumptable, as there could be pointers + * to existing jump table entries in the code, so instead + * we just add one more chunk. + */ + guint32 max_entries = entries; + MonoJumpTableChunk *new_chunk; + + if (max_entries < DEFAULT_JUMPTABLE_CHUNK_ELEMENTS) + max_entries = DEFAULT_JUMPTABLE_CHUNK_ELEMENTS; + new_chunk = mono_create_jumptable_chunk (max_entries); + /* Link old jumptable, so that we could free it up later. */ + new_chunk->previous = g_jumptable; + g_jumptable = new_chunk; + index = 0; + } + g_jumptable->active = index + entries; + result = (gpointer*)((guchar*)g_jumptable + sizeof(MonoJumpTableChunk)) + index; + mono_jumptable_unlock(); + + return result; +} + +void +mono_jumptable_cleanup (void) +{ + if (g_jumptable) { + MonoJumpTableChunk *current = g_jumptable, *prev; + while (current != NULL) { + prev = current->previous; + g_free (current); + current = prev; + } + g_jumptable = NULL; + DeleteCriticalSection (&jumptable_mutex); + } +} + +gpointer* +mono_jumptable_get_entry (guint8 *code_ptr) +{ + return mono_arch_jumptable_entry_from_code (code_ptr); +} +#endif