6 #include <mono/utils/mono-compiler.h>
12 #include <mono/metadata/abi-details.h>
13 #include <mono/metadata/class-abi-details.h>
16 #define is_complex_isinst(klass) (mono_class_is_interface (klass) || m_class_get_rank (klass) || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || m_class_get_byval_arg (klass)->type == MONO_TYPE_VAR || m_class_get_byval_arg (klass)->type == MONO_TYPE_MVAR)
19 get_castclass_cache_idx (MonoCompile
*cfg
)
21 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
22 cfg
->castclass_cache_index
++;
23 return (cfg
->method_index
<< 16) | cfg
->castclass_cache_index
;
27 emit_cached_check_args (MonoCompile
*cfg
, MonoInst
*obj
, MonoClass
*klass
, int context_used
, MonoInst
*args
[3])
34 cache_ins
= mini_emit_get_rgctx_klass (cfg
, context_used
, klass
, MONO_RGCTX_INFO_CAST_CACHE
);
36 /* klass - it's the second element of the cache entry*/
37 EMIT_NEW_LOAD_MEMBASE (cfg
, args
[1], OP_LOAD_MEMBASE
, alloc_preg (cfg
), cache_ins
->dreg
, TARGET_SIZEOF_VOID_P
);
39 args
[2] = cache_ins
; /* cache */
43 EMIT_NEW_CLASSCONST (cfg
, args
[1], klass
); /* klass */
45 idx
= get_castclass_cache_idx (cfg
); /* inline cache*/
46 args
[2] = mini_emit_runtime_constant (cfg
, MONO_PATCH_INFO_CASTCLASS_CACHE
, GINT_TO_POINTER (idx
));
51 emit_isinst_with_cache (MonoCompile
*cfg
, MonoInst
*obj
, MonoClass
*klass
, int context_used
)
54 MonoMethod
*mono_isinst
= mono_marshal_get_isinst_with_cache ();
56 emit_cached_check_args (cfg
, obj
, klass
, context_used
, args
);
57 return mono_emit_method_call (cfg
, mono_isinst
, args
, NULL
);
61 emit_castclass_with_cache_no_details (MonoCompile
*cfg
, MonoInst
*obj
, MonoClass
*klass
, int context_used
)
64 MonoMethod
*mono_castclass
= mono_marshal_get_castclass_with_cache ();
67 emit_cached_check_args (cfg
, obj
, klass
, context_used
, args
);
69 res
= mono_emit_method_call (cfg
, mono_castclass
, args
, NULL
);
75 emit_castclass_with_cache (MonoCompile
*cfg
, MonoInst
*obj
, MonoClass
*klass
, int context_used
)
78 MonoMethod
*mono_castclass
= mono_marshal_get_castclass_with_cache ();
81 emit_cached_check_args (cfg
, obj
, klass
, context_used
, args
);
83 mini_save_cast_details (cfg
, klass
, args
[0]->dreg
, TRUE
);
84 res
= mono_emit_method_call (cfg
, mono_castclass
, args
, NULL
);
85 mini_reset_cast_details (cfg
);
91 mini_emit_class_check_inst (MonoCompile
*cfg
, int klass_reg
, MonoClass
*klass
, MonoInst
*klass_inst
)
94 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, klass_reg
, klass_inst
->dreg
);
96 MonoInst
*ins
= mini_emit_runtime_constant (cfg
, MONO_PATCH_INFO_CLASS
, klass
);
97 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, klass_reg
, ins
->dreg
);
99 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "InvalidCastException");
104 mini_emit_isninst_cast_inst (MonoCompile
*cfg
, int klass_reg
, MonoClass
*klass
, MonoInst
*klass_ins
, MonoBasicBlock
*false_target
, MonoBasicBlock
*true_target
)
106 int idepth_reg
= alloc_preg (cfg
);
107 int stypes_reg
= alloc_preg (cfg
);
108 int stype
= alloc_preg (cfg
);
110 mono_class_setup_supertypes (klass
);
112 if (m_class_get_idepth (klass
) > MONO_DEFAULT_SUPERTABLE_SIZE
) {
113 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU2_MEMBASE
, idepth_reg
, klass_reg
, m_class_offsetof_idepth ());
114 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, idepth_reg
, m_class_get_idepth (klass
));
115 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBLT_UN
, false_target
);
117 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, stypes_reg
, klass_reg
, m_class_offsetof_supertypes ());
118 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, stype
, stypes_reg
, ((m_class_get_idepth (klass
) - 1) * TARGET_SIZEOF_VOID_P
));
120 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, stype
, klass_ins
->dreg
);
121 } else if (cfg
->compile_aot
) {
122 int const_reg
= alloc_preg (cfg
);
123 MONO_EMIT_NEW_CLASSCONST (cfg
, const_reg
, klass
);
124 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, stype
, const_reg
);
126 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, stype
, (gsize
)klass
);
128 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBEQ
, true_target
);
133 mini_emit_interface_bitmap_check (MonoCompile
*cfg
, int intf_bit_reg
, int base_reg
, int offset
, MonoClass
*klass
)
135 int ibitmap_reg
= alloc_preg (cfg
);
136 #ifdef COMPRESSED_INTERFACE_BITMAP
139 NEW_LOAD_MEMBASE (cfg
, ins
, OP_LOAD_MEMBASE
, ibitmap_reg
, base_reg
, offset
);
140 MONO_ADD_INS (cfg
->cbb
, ins
);
142 args
[1] = mini_emit_runtime_constant (cfg
, MONO_PATCH_INFO_IID
, klass
);
143 res
= mono_emit_jit_icall (cfg
, mono_class_interface_match
, args
);
144 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, intf_bit_reg
, res
->dreg
);
146 int ibitmap_byte_reg
= alloc_preg (cfg
);
148 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, ibitmap_reg
, base_reg
, offset
);
150 if (cfg
->compile_aot
) {
151 int iid_reg
= alloc_preg (cfg
);
152 int shifted_iid_reg
= alloc_preg (cfg
);
153 int ibitmap_byte_address_reg
= alloc_preg (cfg
);
154 int masked_iid_reg
= alloc_preg (cfg
);
155 int iid_one_bit_reg
= alloc_preg (cfg
);
156 int iid_bit_reg
= alloc_preg (cfg
);
157 MONO_EMIT_NEW_AOTCONST (cfg
, iid_reg
, klass
, MONO_PATCH_INFO_IID
);
158 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, shifted_iid_reg
, iid_reg
, 3);
159 MONO_EMIT_NEW_BIALU (cfg
, OP_PADD
, ibitmap_byte_address_reg
, ibitmap_reg
, shifted_iid_reg
);
160 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU1_MEMBASE
, ibitmap_byte_reg
, ibitmap_byte_address_reg
, 0);
161 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, masked_iid_reg
, iid_reg
, 7);
162 MONO_EMIT_NEW_ICONST (cfg
, iid_one_bit_reg
, 1);
163 MONO_EMIT_NEW_BIALU (cfg
, OP_ISHL
, iid_bit_reg
, iid_one_bit_reg
, masked_iid_reg
);
164 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, intf_bit_reg
, ibitmap_byte_reg
, iid_bit_reg
);
166 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI1_MEMBASE
, ibitmap_byte_reg
, ibitmap_reg
, m_class_get_interface_id (klass
) >> 3);
167 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, intf_bit_reg
, ibitmap_byte_reg
, 1 << (m_class_get_interface_id (klass
) & 7));
173 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
174 * stored in "klass_reg" implements the interface "klass".
177 mini_emit_load_intf_bit_reg_class (MonoCompile
*cfg
, int intf_bit_reg
, int klass_reg
, MonoClass
*klass
)
179 mini_emit_interface_bitmap_check (cfg
, intf_bit_reg
, klass_reg
, m_class_offsetof_interface_bitmap (), klass
);
183 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
184 * stored in "vtable_reg" implements the interface "klass".
187 mini_emit_load_intf_bit_reg_vtable (MonoCompile
*cfg
, int intf_bit_reg
, int vtable_reg
, MonoClass
*klass
)
189 mini_emit_interface_bitmap_check (cfg
, intf_bit_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, interface_bitmap
), klass
);
193 * Emit code which checks whenever the interface id of @klass is smaller than
194 * than the value given by max_iid_reg.
197 mini_emit_max_iid_check (MonoCompile
*cfg
, int max_iid_reg
, MonoClass
*klass
,
198 MonoBasicBlock
*false_target
)
200 if (cfg
->compile_aot
) {
201 int iid_reg
= alloc_preg (cfg
);
202 MONO_EMIT_NEW_AOTCONST (cfg
, iid_reg
, klass
, MONO_PATCH_INFO_IID
);
203 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, max_iid_reg
, iid_reg
);
206 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, max_iid_reg
, m_class_get_interface_id (klass
));
208 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBLT_UN
, false_target
);
210 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "InvalidCastException");
213 /* Same as above, but obtains max_iid from a vtable */
215 mini_emit_max_iid_check_vtable (MonoCompile
*cfg
, int vtable_reg
, MonoClass
*klass
,
216 MonoBasicBlock
*false_target
)
218 int max_iid_reg
= alloc_preg (cfg
);
220 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU4_MEMBASE
, max_iid_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, max_interface_id
));
221 mini_emit_max_iid_check (cfg
, max_iid_reg
, klass
, false_target
);
224 /* Same as above, but obtains max_iid from a klass */
226 mini_emit_max_iid_check_class (MonoCompile
*cfg
, int klass_reg
, MonoClass
*klass
,
227 MonoBasicBlock
*false_target
)
229 int max_iid_reg
= alloc_preg (cfg
);
231 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU4_MEMBASE
, max_iid_reg
, klass_reg
, m_class_offsetof_max_interface_id ());
232 mini_emit_max_iid_check (cfg
, max_iid_reg
, klass
, false_target
);
236 mini_emit_class_check_branch (MonoCompile
*cfg
, int klass_reg
, MonoClass
*klass
, int branch_op
, MonoBasicBlock
*target
)
238 if (cfg
->compile_aot
) {
239 int const_reg
= alloc_preg (cfg
);
240 MONO_EMIT_NEW_CLASSCONST (cfg
, const_reg
, klass
);
241 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, klass_reg
, const_reg
);
243 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, klass_reg
, (gsize
)klass
);
245 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, branch_op
, target
);
250 mini_emit_isninst_cast (MonoCompile
*cfg
, int klass_reg
, MonoClass
*klass
, MonoBasicBlock
*false_target
, MonoBasicBlock
*true_target
)
252 mini_emit_isninst_cast_inst (cfg
, klass_reg
, klass
, NULL
, false_target
, true_target
);
256 mini_emit_iface_cast (MonoCompile
*cfg
, int vtable_reg
, MonoClass
*klass
, MonoBasicBlock
*false_target
, MonoBasicBlock
*true_target
)
258 int intf_reg
= alloc_preg (cfg
);
260 mini_emit_max_iid_check_vtable (cfg
, vtable_reg
, klass
, false_target
);
261 mini_emit_load_intf_bit_reg_vtable (cfg
, intf_reg
, vtable_reg
, klass
);
262 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, intf_reg
, 0);
264 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, true_target
);
266 MONO_EMIT_NEW_COND_EXC (cfg
, EQ
, "InvalidCastException");
270 * Variant of the above that takes a register to the class, not the vtable.
273 mini_emit_iface_class_cast (MonoCompile
*cfg
, int klass_reg
, MonoClass
*klass
, MonoBasicBlock
*false_target
, MonoBasicBlock
*true_target
)
275 int intf_bit_reg
= alloc_preg (cfg
);
277 mini_emit_max_iid_check_class (cfg
, klass_reg
, klass
, false_target
);
278 mini_emit_load_intf_bit_reg_class (cfg
, intf_bit_reg
, klass_reg
, klass
);
279 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, intf_bit_reg
, 0);
281 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, true_target
);
283 MONO_EMIT_NEW_COND_EXC (cfg
, EQ
, "InvalidCastException");
288 mini_emit_castclass (MonoCompile
*cfg
, int obj_reg
, int klass_reg
, MonoClass
*klass
, MonoBasicBlock
*object_is_null
);
291 mini_emit_castclass_inst (MonoCompile
*cfg
, int obj_reg
, int klass_reg
, MonoClass
*klass
, MonoInst
*klass_inst
, MonoBasicBlock
*object_is_null
)
293 if (m_class_get_rank (klass
)) {
294 int rank_reg
= alloc_preg (cfg
);
295 int eclass_reg
= alloc_preg (cfg
);
297 g_assert (!klass_inst
);
299 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU1_MEMBASE
, rank_reg
, klass_reg
, m_class_offsetof_rank ());
300 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, rank_reg
, m_class_get_rank (klass
));
301 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "InvalidCastException");
303 // MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
304 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, eclass_reg
, klass_reg
, m_class_offsetof_cast_class ());
305 if (m_class_is_array_special_interface (m_class_get_cast_class (klass
))) {
308 MONO_INST_NEW (cfg
, src
, OP_LOCAL
);
310 emit_castclass_with_cache_no_details (cfg
, src
, klass
, 0);
311 } else if (m_class_get_cast_class (klass
) == mono_defaults
.object_class
) {
312 int parent_reg
= alloc_preg (cfg
);
313 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, parent_reg
, eclass_reg
, m_class_offsetof_parent ());
314 mini_emit_class_check_branch (cfg
, parent_reg
, m_class_get_parent (mono_defaults
.enum_class
), OP_PBNE_UN
, object_is_null
);
315 mini_emit_class_check (cfg
, eclass_reg
, mono_defaults
.enum_class
);
316 } else if (m_class_get_cast_class (klass
) == m_class_get_parent (mono_defaults
.enum_class
)) {
317 mini_emit_class_check_branch (cfg
, eclass_reg
, m_class_get_parent (mono_defaults
.enum_class
), OP_PBEQ
, object_is_null
);
318 mini_emit_class_check (cfg
, eclass_reg
, mono_defaults
.enum_class
);
319 } else if (m_class_get_cast_class (klass
) == mono_defaults
.enum_class
) {
320 mini_emit_class_check (cfg
, eclass_reg
, mono_defaults
.enum_class
);
321 } else if (mono_class_is_interface (m_class_get_cast_class (klass
))) {
322 mini_emit_iface_class_cast (cfg
, eclass_reg
, m_class_get_cast_class (klass
), NULL
, NULL
);
324 // Pass -1 as obj_reg to skip the check below for arrays of arrays
325 mini_emit_castclass (cfg
, -1, eclass_reg
, m_class_get_cast_class (klass
), object_is_null
);
328 if ((m_class_get_rank (klass
) == 1) && (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
) && (obj_reg
!= -1)) {
329 /* Check that the object is a vector too */
330 int bounds_reg
= alloc_preg (cfg
);
331 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, bounds_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoArray
, bounds
));
332 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, bounds_reg
, 0);
333 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "InvalidCastException");
336 int idepth_reg
= alloc_preg (cfg
);
337 int stypes_reg
= alloc_preg (cfg
);
338 int stype
= alloc_preg (cfg
);
340 mono_class_setup_supertypes (klass
);
342 if (m_class_get_idepth (klass
) > MONO_DEFAULT_SUPERTABLE_SIZE
) {
343 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU2_MEMBASE
, idepth_reg
, klass_reg
, m_class_offsetof_idepth ());
344 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, idepth_reg
, m_class_get_idepth (klass
));
345 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "InvalidCastException");
347 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, stypes_reg
, klass_reg
, m_class_offsetof_supertypes ());
348 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, stype
, stypes_reg
, ((m_class_get_idepth (klass
) - 1) * TARGET_SIZEOF_VOID_P
));
349 mini_emit_class_check_inst (cfg
, stype
, klass
, klass_inst
);
354 mini_emit_castclass (MonoCompile
*cfg
, int obj_reg
, int klass_reg
, MonoClass
*klass
, MonoBasicBlock
*object_is_null
)
356 mini_emit_castclass_inst (cfg
, obj_reg
, klass_reg
, klass
, NULL
, object_is_null
);
360 emit_special_array_iface_check (MonoCompile
*cfg
, MonoInst
*src
, MonoClass
* klass
, int vtable_reg
, MonoBasicBlock
*not_an_array
, MonoBasicBlock
*true_bb
, int context_used
)
364 if (!m_class_is_array_special_interface (klass
))
367 rank_reg
= alloc_ireg (cfg
);
369 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU1_MEMBASE
, rank_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, rank
));
370 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, rank_reg
, 1);
372 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, not_an_array
);
374 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "InvalidCastException");
376 emit_castclass_with_cache_no_details (cfg
, src
, klass
, context_used
);
377 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, true_bb
);
381 * Returns NULL and set the cfg exception on error.
384 handle_castclass (MonoCompile
*cfg
, MonoClass
*klass
, MonoInst
*src
, int context_used
)
386 MonoBasicBlock
*is_null_bb
;
387 int obj_reg
= src
->dreg
;
388 MonoInst
*klass_inst
= NULL
;
390 if (MONO_INS_IS_PCONST_NULL (src
))
395 if (is_complex_isinst (klass
))
396 return emit_castclass_with_cache (cfg
, src
, klass
, context_used
);
398 klass_inst
= mini_emit_get_rgctx_klass (cfg
, context_used
, klass
, MONO_RGCTX_INFO_KLASS
);
401 NEW_BBLOCK (cfg
, is_null_bb
);
403 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, obj_reg
, 0);
404 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBEQ
, is_null_bb
);
406 mini_save_cast_details (cfg
, klass
, obj_reg
, FALSE
);
408 if (mono_class_is_interface (klass
)) {
409 int tmp_reg
= alloc_preg (cfg
);
410 #ifndef DISABLE_REMOTING
411 MonoBasicBlock
*interface_fail_bb
;
412 MonoBasicBlock
*array_fail_bb
;
413 int klass_reg
= alloc_preg (cfg
);
415 NEW_BBLOCK (cfg
, interface_fail_bb
);
416 NEW_BBLOCK (cfg
, array_fail_bb
);
418 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
419 mini_emit_iface_cast (cfg
, tmp_reg
, klass
, interface_fail_bb
, is_null_bb
);
421 // iface bitmap check failed
422 MONO_START_BB (cfg
, interface_fail_bb
);
424 //Check if it's a rank zero array and emit fallback casting
425 emit_special_array_iface_check (cfg
, src
, klass
, tmp_reg
, array_fail_bb
, is_null_bb
, context_used
);
427 // array check failed
428 MONO_START_BB (cfg
, array_fail_bb
);
430 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, tmp_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
432 mini_emit_class_check (cfg
, klass_reg
, mono_defaults
.transparent_proxy_class
);
434 tmp_reg
= alloc_preg (cfg
);
435 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, custom_type_info
));
436 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tmp_reg
, 0);
437 MONO_EMIT_NEW_COND_EXC (cfg
, EQ
, "InvalidCastException");
439 MonoInst
*args
[1] = { src
};
440 MonoInst
*proxy_test_inst
= mono_emit_method_call (cfg
, mono_marshal_get_proxy_cancast (klass
), args
, NULL
);
441 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, proxy_test_inst
->dreg
, 0);
442 MONO_EMIT_NEW_COND_EXC (cfg
, EQ
, "InvalidCastException");
444 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, is_null_bb
);
446 MonoBasicBlock
*interface_fail_bb
= NULL
;
448 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
450 if (m_class_is_array_special_interface (klass
)) {
451 NEW_BBLOCK (cfg
, interface_fail_bb
);
452 mini_emit_iface_cast (cfg
, tmp_reg
, klass
, interface_fail_bb
, is_null_bb
);
453 // iface bitmap check failed
454 MONO_START_BB (cfg
, interface_fail_bb
);
456 //Check if it's a rank zero array and emit fallback casting
457 emit_special_array_iface_check (cfg
, src
, klass
, tmp_reg
, NULL
, is_null_bb
, context_used
);
459 mini_emit_iface_cast (cfg
, tmp_reg
, klass
, NULL
, NULL
);
460 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, is_null_bb
);
463 } else if (mono_class_is_marshalbyref (klass
)) {
464 #ifndef DISABLE_REMOTING
465 MonoBasicBlock
*no_proxy_bb
, *fail_1_bb
;
466 int tmp_reg
= alloc_preg (cfg
);
467 int klass_reg
= alloc_preg (cfg
);
469 NEW_BBLOCK (cfg
, no_proxy_bb
);
471 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
472 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, tmp_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
473 mini_emit_class_check_branch (cfg
, klass_reg
, mono_defaults
.transparent_proxy_class
, OP_PBNE_UN
, no_proxy_bb
);
475 tmp_reg
= alloc_preg (cfg
);
476 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, remote_class
));
477 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, tmp_reg
, MONO_STRUCT_OFFSET (MonoRemoteClass
, proxy_class
));
479 tmp_reg
= alloc_preg (cfg
);
480 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, custom_type_info
));
481 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tmp_reg
, 0);
482 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBEQ
, no_proxy_bb
);
484 NEW_BBLOCK (cfg
, fail_1_bb
);
486 mini_emit_isninst_cast (cfg
, klass_reg
, klass
, fail_1_bb
, is_null_bb
);
488 MONO_START_BB (cfg
, fail_1_bb
);
490 MonoInst
*args
[1] = { src
};
491 MonoInst
*proxy_test_inst
= mono_emit_method_call (cfg
, mono_marshal_get_proxy_cancast (klass
), args
, NULL
);
492 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, proxy_test_inst
->dreg
, 0);
493 MONO_EMIT_NEW_COND_EXC (cfg
, EQ
, "InvalidCastException");
495 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, is_null_bb
);
497 MONO_START_BB (cfg
, no_proxy_bb
);
499 mini_emit_castclass_inst (cfg
, obj_reg
, klass_reg
, klass
, klass_inst
, is_null_bb
);
501 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
504 int vtable_reg
= alloc_preg (cfg
);
505 int klass_reg
= alloc_preg (cfg
);
507 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, vtable_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
509 if (!m_class_get_rank (klass
) && !cfg
->compile_aot
&& !(cfg
->opt
& MONO_OPT_SHARED
) && mono_class_is_sealed (klass
)) {
510 /* the remoting code is broken, access the class for now */
511 if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
512 MonoVTable
*vt
= mono_class_vtable_checked (cfg
->domain
, klass
, &cfg
->error
);
513 if (!is_ok (&cfg
->error
)) {
514 mono_cfg_set_exception (cfg
, MONO_EXCEPTION_MONO_ERROR
);
517 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, vtable_reg
, (gsize
)vt
);
519 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
520 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, klass_reg
, (gsize
)klass
);
522 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "InvalidCastException");
524 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
525 mini_emit_castclass_inst (cfg
, obj_reg
, klass_reg
, klass
, klass_inst
, is_null_bb
);
529 MONO_START_BB (cfg
, is_null_bb
);
531 mini_reset_cast_details (cfg
);
537 * Returns NULL and set the cfg exception on error.
540 handle_isinst (MonoCompile
*cfg
, MonoClass
*klass
, MonoInst
*src
, int context_used
)
543 MonoBasicBlock
*is_null_bb
, *false_bb
, *end_bb
;
544 int obj_reg
= src
->dreg
;
545 int vtable_reg
= alloc_preg (cfg
);
546 int res_reg
= alloc_ireg_ref (cfg
);
547 MonoInst
*klass_inst
= NULL
;
550 if(is_complex_isinst (klass
))
551 return emit_isinst_with_cache (cfg
, src
, klass
, context_used
);
553 klass_inst
= mini_emit_get_rgctx_klass (cfg
, context_used
, klass
, MONO_RGCTX_INFO_KLASS
);
556 NEW_BBLOCK (cfg
, is_null_bb
);
557 NEW_BBLOCK (cfg
, false_bb
);
558 NEW_BBLOCK (cfg
, end_bb
);
560 /* Do the assignment at the beginning, so the other assignment can be if converted */
561 EMIT_NEW_UNALU (cfg
, ins
, OP_MOVE
, res_reg
, obj_reg
);
562 ins
->type
= STACK_OBJ
;
565 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, obj_reg
, 0);
566 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBEQ
, is_null_bb
);
568 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, vtable_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoObject
, vtable
));
570 if (mono_class_is_interface (klass
)) {
571 MonoBasicBlock
*interface_fail_bb
;
573 NEW_BBLOCK (cfg
, interface_fail_bb
);
575 mini_emit_iface_cast (cfg
, vtable_reg
, klass
, interface_fail_bb
, is_null_bb
);
576 MONO_START_BB (cfg
, interface_fail_bb
);
578 if (m_class_is_array_special_interface (klass
)) {
579 MonoBasicBlock
*not_an_array
;
581 int rank_reg
= alloc_ireg (cfg
);
583 NEW_BBLOCK (cfg
, not_an_array
);
584 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU1_MEMBASE
, rank_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, rank
));
585 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, rank_reg
, 1);
586 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, not_an_array
);
588 MonoInst
*res_inst
= emit_isinst_with_cache (cfg
, src
, klass
, context_used
);
589 EMIT_NEW_UNALU (cfg
, move
, OP_MOVE
, res_reg
, res_inst
->dreg
);
590 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_bb
);
592 MONO_START_BB (cfg
, not_an_array
);
595 #ifndef DISABLE_REMOTING
596 int tmp_reg
, klass_reg
;
597 MonoBasicBlock
*call_proxy_isinst
;
599 NEW_BBLOCK (cfg
, call_proxy_isinst
);
601 klass_reg
= alloc_preg (cfg
);
602 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
604 mini_emit_class_check_branch (cfg
, klass_reg
, mono_defaults
.transparent_proxy_class
, OP_PBNE_UN
, false_bb
);
606 tmp_reg
= alloc_preg (cfg
);
607 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, custom_type_info
));
608 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tmp_reg
, 0);
609 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBEQ
, false_bb
);
611 MONO_START_BB (cfg
, call_proxy_isinst
);
613 MonoInst
*args
[1] = { src
};
614 MonoInst
*proxy_test_inst
= mono_emit_method_call (cfg
, mono_marshal_get_proxy_cancast (klass
), args
, NULL
);
615 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, proxy_test_inst
->dreg
, 0);
616 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, is_null_bb
);
618 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, false_bb
);
621 } else if (mono_class_is_marshalbyref (klass
)) {
623 #ifndef DISABLE_REMOTING
624 int tmp_reg
, klass_reg
;
625 MonoBasicBlock
*no_proxy_bb
, *call_proxy_isinst
;
627 NEW_BBLOCK (cfg
, no_proxy_bb
);
628 NEW_BBLOCK (cfg
, call_proxy_isinst
);
630 klass_reg
= alloc_preg (cfg
);
631 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
633 mini_emit_class_check_branch (cfg
, klass_reg
, mono_defaults
.transparent_proxy_class
, OP_PBNE_UN
, no_proxy_bb
);
635 tmp_reg
= alloc_preg (cfg
);
636 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, remote_class
));
637 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, tmp_reg
, MONO_STRUCT_OFFSET (MonoRemoteClass
, proxy_class
));
639 tmp_reg
= alloc_preg (cfg
);
640 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, tmp_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoTransparentProxy
, custom_type_info
));
641 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tmp_reg
, 0);
642 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBEQ
, false_bb
);
644 mini_emit_isninst_cast (cfg
, klass_reg
, klass
, call_proxy_isinst
, is_null_bb
);
646 MONO_START_BB (cfg
, call_proxy_isinst
);
648 MonoInst
*args
[1] = { src
};
649 MonoInst
*proxy_test_inst
= mono_emit_method_call (cfg
, mono_marshal_get_proxy_cancast (klass
), args
, NULL
);
650 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, proxy_test_inst
->dreg
, 0);
651 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, is_null_bb
);
652 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, false_bb
);
654 MONO_START_BB (cfg
, no_proxy_bb
);
656 mini_emit_isninst_cast (cfg
, klass_reg
, klass
, false_bb
, is_null_bb
);
658 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
661 int klass_reg
= alloc_preg (cfg
);
663 if (m_class_get_rank (klass
)) {
664 int rank_reg
= alloc_preg (cfg
);
665 int eclass_reg
= alloc_preg (cfg
);
667 if ((m_class_get_rank (klass
) == 1) && (m_class_get_byval_arg (klass
)->type
== MONO_TYPE_SZARRAY
)) {
668 /* Check that the object is a vector too */
669 int bounds_reg
= alloc_preg (cfg
);
670 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, bounds_reg
, obj_reg
, MONO_STRUCT_OFFSET (MonoArray
, bounds
));
671 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, bounds_reg
, 0);
672 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, false_bb
);
675 g_assert (!context_used
);
676 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU1_MEMBASE
, rank_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, rank
));
677 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, rank_reg
, m_class_get_rank (klass
));
678 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, false_bb
);
679 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
680 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, eclass_reg
, klass_reg
, m_class_offsetof_cast_class ());
681 if (m_class_is_array_special_interface (m_class_get_cast_class (klass
))) {
682 MonoInst
*move
, *res_inst
;
684 res_inst
= emit_isinst_with_cache (cfg
, src
, klass
, context_used
);
685 EMIT_NEW_UNALU (cfg
, move
, OP_MOVE
, res_reg
, res_inst
->dreg
);
686 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_bb
);
687 } else if (m_class_get_cast_class (klass
) == mono_defaults
.object_class
) {
688 int parent_reg
, class_kind_reg
;
689 MonoBasicBlock
*pointer_check_bb
;
691 NEW_BBLOCK (cfg
, pointer_check_bb
);
693 parent_reg
= alloc_preg (cfg
);
694 class_kind_reg
= alloc_preg (cfg
);
695 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, parent_reg
, eclass_reg
, m_class_offsetof_parent ());
696 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADU1_MEMBASE
, class_kind_reg
, eclass_reg
, m_class_offsetof_class_kind ());
698 // Check if the parent class of the element is not System.ValueType
699 mini_emit_class_check_branch (cfg
, parent_reg
, m_class_get_parent (mono_defaults
.enum_class
), OP_PBNE_UN
, pointer_check_bb
);
700 mini_emit_class_check_branch (cfg
, eclass_reg
, mono_defaults
.enum_class
, OP_PBEQ
, is_null_bb
);
701 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, false_bb
);
703 MONO_START_BB (cfg
, pointer_check_bb
);
704 // Check if the parent class of the element is non-null, else manually check the type
705 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, parent_reg
, NULL
);
706 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, is_null_bb
);
707 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, class_kind_reg
, MONO_CLASS_POINTER
);
708 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBEQ
, false_bb
);
709 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, is_null_bb
);
710 } else if (m_class_get_cast_class (klass
) == m_class_get_parent (mono_defaults
.enum_class
)) {
711 mini_emit_class_check_branch (cfg
, eclass_reg
, m_class_get_parent (mono_defaults
.enum_class
), OP_PBEQ
, is_null_bb
);
712 mini_emit_class_check_branch (cfg
, eclass_reg
, mono_defaults
.enum_class
, OP_PBEQ
, is_null_bb
);
713 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, false_bb
);
714 } else if (m_class_get_cast_class (klass
) == mono_defaults
.enum_class
) {
715 mini_emit_class_check_branch (cfg
, eclass_reg
, mono_defaults
.enum_class
, OP_PBEQ
, is_null_bb
);
716 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, false_bb
);
717 } else if (mono_class_is_interface (m_class_get_cast_class (klass
))) {
718 mini_emit_iface_class_cast (cfg
, eclass_reg
, m_class_get_cast_class (klass
), false_bb
, is_null_bb
);
720 /* the is_null_bb target simply copies the input register to the output */
721 mini_emit_isninst_cast (cfg
, eclass_reg
, m_class_get_cast_class (klass
), false_bb
, is_null_bb
);
723 } else if (mono_class_is_nullable (klass
)) {
724 g_assert (!context_used
);
725 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
726 /* the is_null_bb target simply copies the input register to the output */
727 mini_emit_isninst_cast (cfg
, klass_reg
, m_class_get_cast_class (klass
), false_bb
, is_null_bb
);
729 if (!cfg
->compile_aot
&& !(cfg
->opt
& MONO_OPT_SHARED
) && mono_class_is_sealed (klass
)) {
730 g_assert (!context_used
);
731 /* the remoting code is broken, access the class for now */
732 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
733 MonoVTable
*vt
= mono_class_vtable_checked (cfg
->domain
, klass
, &cfg
->error
);
734 if (!is_ok (&cfg
->error
)) {
735 mono_cfg_set_exception (cfg
, MONO_EXCEPTION_MONO_ERROR
);
738 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, vtable_reg
, (gsize
)vt
);
740 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
741 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, klass_reg
, (gsize
)klass
);
743 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_PBNE_UN
, false_bb
);
744 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, is_null_bb
);
746 MONO_EMIT_NEW_LOAD_MEMBASE (cfg
, klass_reg
, vtable_reg
, MONO_STRUCT_OFFSET (MonoVTable
, klass
));
747 /* the is_null_bb target simply copies the input register to the output */
748 mini_emit_isninst_cast_inst (cfg
, klass_reg
, klass
, klass_inst
, false_bb
, is_null_bb
);
753 MONO_START_BB (cfg
, false_bb
);
755 MONO_EMIT_NEW_PCONST (cfg
, res_reg
, NULL
);
756 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_bb
);
758 MONO_START_BB (cfg
, is_null_bb
);
760 MONO_START_BB (cfg
, end_bb
);
766 mono_decompose_typecheck (MonoCompile
*cfg
, MonoBasicBlock
*bb
, MonoInst
*ins
)
768 MonoInst
*ret
, *move
, *source
;
769 MonoClass
*klass
= ins
->klass
;
770 int context_used
= mini_class_check_context_used (cfg
, klass
);
771 int is_isinst
= ins
->opcode
== OP_ISINST
;
772 g_assert (is_isinst
|| ins
->opcode
== OP_CASTCLASS
);
773 source
= get_vreg_to_inst (cfg
, ins
->sreg1
);
774 if (!source
|| source
== (MonoInst
*) -1)
775 source
= mono_compile_create_var_for_vreg (cfg
, mono_get_object_type (), OP_LOCAL
, ins
->sreg1
);
776 g_assert (source
&& source
!= (MonoInst
*) -1);
778 MonoBasicBlock
*first_bb
;
779 NEW_BBLOCK (cfg
, first_bb
);
782 if (mini_class_has_reference_variant_generic_argument (cfg
, klass
, context_used
)) {
784 ret
= emit_isinst_with_cache (cfg
, source
, klass
, context_used
);
786 ret
= emit_castclass_with_cache (cfg
, source
, klass
, context_used
);
790 ret
= handle_isinst (cfg
, klass
, source
, context_used
);
792 ret
= handle_castclass (cfg
, klass
, source
, context_used
);
794 EMIT_NEW_UNALU (cfg
, move
, OP_MOVE
, ins
->dreg
, ret
->dreg
);
796 g_assert (cfg
->cbb
->code
|| first_bb
->code
);
797 MonoInst
*prev
= ins
->prev
;
798 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
802 mono_decompose_typechecks (MonoCompile
*cfg
)
804 gboolean found_typetest
= FALSE
;
805 for (MonoBasicBlock
*bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
807 MONO_BB_FOR_EACH_INS (bb
, ins
) {
808 switch (ins
->opcode
) {
811 found_typetest
= TRUE
;
812 mono_decompose_typecheck (cfg
, bb
, ins
);
817 if ((cfg
->verbose_level
> 2) && found_typetest
)
818 mono_print_code (cfg
, "AFTER DECOMPOSE TYPE_CHECKS");
823 //API used by method-to-ir.c
825 mini_emit_class_check (MonoCompile
*cfg
, int klass_reg
, MonoClass
*klass
)
827 mini_emit_class_check_inst (cfg
, klass_reg
, klass
, NULL
);
832 MONO_EMPTY_SOURCE_FILE (type_checking
);