提交 5518da4d 编写于 作者: R Rodrigo Kumpera

Add single entry cache to casts of types with variant generic arguments.

        * jit-icall.c (mono_object_castclass_with_cache): Check
        single entry cache before calling mono_object_isinst.

        * jit-icall.c (mono_object_isinst_with_cache): Check
        single entry cache before calling mono_object_isinst.
        This uses a positive and negative cache as it is used
        for type queries quite often.

        * jit-icalls.h: Export new icalls.

        * mini.c (mini_init): Register new icalls.

        * method-to-ir.c: Call into cache aware version of type
        test ops for types with variant generic arguments.

        This patch replaces direct calls to mono_object_castclass
        mono_object_isisnt to functions that check a cache first.
        The cache is per managed code callsite so the hit ratio
        is very high.
上级 21835deb
......@@ -1033,6 +1033,67 @@ mono_object_castclass (MonoObject *obj, MonoClass *klass)
return NULL;
}
MonoObject*
mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
{
MonoJitTlsData *jit_tls = NULL;
gpointer cached_vtable, obj_vtable;
if (mini_get_debug_options ()->better_cast_details) {
jit_tls = TlsGetValue (mono_jit_tls_id);
jit_tls->class_cast_from = NULL;
}
if (!obj)
return NULL;
cached_vtable = *cache;
obj_vtable = obj->vtable;
if (cached_vtable == obj_vtable)
return obj;
if (mono_object_isinst (obj, klass)) {
*cache = obj_vtable;
return obj;
}
if (mini_get_debug_options ()->better_cast_details) {
jit_tls->class_cast_from = obj->vtable->klass;
jit_tls->class_cast_to = klass;
}
mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
"System", "InvalidCastException"));
return NULL;
}
MonoObject*
mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
{
size_t cached_vtable, obj_vtable;
if (!obj)
return NULL;
cached_vtable = (size_t)*cache;
obj_vtable = (size_t)obj->vtable;
if ((cached_vtable & ~0x1) == obj_vtable) {
return (cached_vtable & 0x1) ? NULL : obj;
}
if (mono_object_isinst (obj, klass)) {
*cache = (gpointer)obj_vtable;
return obj;
} else {
/*negative cache*/
*cache = (gpointer)(obj_vtable | 0x1);
return NULL;
}
}
gpointer
mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
{
......
......@@ -163,5 +163,11 @@ MonoObject* mono_object_castclass (MonoObject *obj, MonoClass *klass) MONO_INTER
gpointer mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func) MONO_INTERNAL;
MonoObject*
mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache);
MonoObject*
mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache);
#endif /* __MONO_JIT_ICALLS_H__ */
......@@ -3290,17 +3290,21 @@ handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
static gboolean
mini_class_has_reference_variant_generic_argument (MonoClass *klass)
mini_class_has_reference_variant_generic_argument (MonoClass *klass, int context_used)
{
int i;
MonoGenericContainer *container;
MonoGenericInst *ginst;
if (!klass->generic_class)
if (klass->generic_class) {
container = klass->generic_class->container_class->generic_container;
ginst = klass->generic_class->context.class_inst;
} else if (klass->generic_container && context_used) {
container = klass->generic_container;
ginst = container->context.class_inst;
} else {
return FALSE;
container = klass->generic_class->container_class->generic_container;
ginst = klass->generic_class->context.class_inst;
}
for (i = 0; i < container->type_argc; ++i) {
MonoType *type;
......@@ -3309,12 +3313,15 @@ mini_class_has_reference_variant_generic_argument (MonoClass *klass)
type = ginst->type_argv [i];
if (MONO_TYPE_IS_REFERENCE (type))
return TRUE;
if (context_used && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
return TRUE;
}
return FALSE;
}
// FIXME: This doesn't work yet (class libs tests fail?)
#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || mini_class_has_reference_variant_generic_argument (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
#define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
/*
* Returns NULL and set the cfg exception on error.
......@@ -7872,8 +7879,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (klass);
if (!context_used && mini_class_has_reference_variant_generic_argument (klass)) {
MonoInst *args [2];
if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
MonoInst *args [3];
/* obj */
args [0] = *sp;
......@@ -7881,7 +7888,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
/* klass */
EMIT_NEW_CLASSCONST (cfg, args [1], klass);
ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
/* inline cache*/
/*FIXME AOT support*/
EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
ins = mono_emit_jit_icall (cfg, mono_object_castclass_with_cache, args);
*sp ++ = ins;
ip += 5;
inline_costs += 2;
......@@ -7926,8 +7938,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
if (cfg->generic_sharing_context)
context_used = mono_class_check_context_used (klass);
if (!context_used && mini_class_has_reference_variant_generic_argument (klass)) {
MonoInst *args [2];
if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
MonoInst *args [3];
/* obj */
args [0] = *sp;
......@@ -7935,7 +7947,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
/* klass */
EMIT_NEW_CLASSCONST (cfg, args [1], klass);
*sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
/* inline cache*/
/*FIXME AOT support*/
EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
*sp = mono_emit_jit_icall (cfg, mono_object_isinst_with_cache, args);
sp++;
ip += 5;
inline_costs += 2;
......@@ -7983,7 +7999,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
if (generic_class_is_reference_type (cfg, klass)) {
/* CASTCLASS FIXME kill this huge slice of duplicated code*/
if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
MonoInst *args [3];
/* obj */
args [0] = *sp;
/* klass */
EMIT_NEW_CLASSCONST (cfg, args [1], klass);
/* inline cache*/
/*FIXME AOT support*/
EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
ins = mono_emit_jit_icall (cfg, mono_object_castclass_with_cache, args);
*sp ++ = ins;
ip += 5;
inline_costs += 2;
} else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
MonoMethod *mono_castclass;
MonoInst *iargs [1];
int costs;
......
......@@ -6164,6 +6164,9 @@ mini_init (const char *filename, const char *runtime_version)
register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
#endif
mono_generic_sharing_init ();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册