2 #include <mono/utils/mono-compiler.h>
8 #include <mono/metadata/abi-details.h>
11 //XXX maybe move to mini.h / mini.c?
14 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
17 return mono_class_check_context_used (klass);
23 #define is_complex_isinst(klass) (mono_class_is_interface (klass) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || mono_class_is_sealed (klass) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
26 emit_isinst_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
28 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
29 return mono_emit_method_call (cfg, mono_isinst, args, NULL);
33 get_castclass_cache_idx (MonoCompile *cfg)
35 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
36 cfg->castclass_cache_index ++;
37 return (cfg->method_index << 16) | cfg->castclass_cache_index;
41 emit_isinst_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
46 args [0] = obj; /* obj */
47 EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
49 idx = get_castclass_cache_idx (cfg); /* inline cache*/
50 args [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
52 return emit_isinst_with_cache (cfg, klass, args);
56 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
58 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
61 mini_save_cast_details (cfg, klass, args [0]->dreg, TRUE);
62 res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
63 mini_reset_cast_details (cfg);
69 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
72 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
74 MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
75 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
77 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
82 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
84 int idepth_reg = alloc_preg (cfg);
85 int stypes_reg = alloc_preg (cfg);
86 int stype = alloc_preg (cfg);
88 mono_class_setup_supertypes (klass);
90 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
91 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
92 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
93 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
95 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
96 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
98 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
99 } else if (cfg->compile_aot) {
100 int const_reg = alloc_preg (cfg);
101 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
102 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
104 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
106 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
111 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
113 int ibitmap_reg = alloc_preg (cfg);
114 #ifdef COMPRESSED_INTERFACE_BITMAP
117 NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
118 MONO_ADD_INS (cfg->cbb, ins);
120 args [1] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
121 res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
122 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
124 int ibitmap_byte_reg = alloc_preg (cfg);
126 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
128 if (cfg->compile_aot) {
129 int iid_reg = alloc_preg (cfg);
130 int shifted_iid_reg = alloc_preg (cfg);
131 int ibitmap_byte_address_reg = alloc_preg (cfg);
132 int masked_iid_reg = alloc_preg (cfg);
133 int iid_one_bit_reg = alloc_preg (cfg);
134 int iid_bit_reg = alloc_preg (cfg);
135 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
136 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
137 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
138 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
139 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
140 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
141 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
142 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
144 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
145 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
151 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
152 * stored in "klass_reg" implements the interface "klass".
155 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
157 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
161 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
162 * stored in "vtable_reg" implements the interface "klass".
165 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
167 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
171 * Emit code which checks whenever the interface id of @klass is smaller than
172 * than the value given by max_iid_reg.
175 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
176 MonoBasicBlock *false_target)
178 if (cfg->compile_aot) {
179 int iid_reg = alloc_preg (cfg);
180 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
181 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
186 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
188 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
191 /* Same as above, but obtains max_iid from a vtable */
193 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
194 MonoBasicBlock *false_target)
196 int max_iid_reg = alloc_preg (cfg);
198 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
199 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
202 /* Same as above, but obtains max_iid from a klass */
204 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
205 MonoBasicBlock *false_target)
207 int max_iid_reg = alloc_preg (cfg);
209 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
210 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
214 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
216 if (cfg->compile_aot) {
217 int const_reg = alloc_preg (cfg);
218 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
219 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
221 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
223 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
228 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
230 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
234 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
236 int intf_reg = alloc_preg (cfg);
238 mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
239 mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
240 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
242 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
244 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
248 * Variant of the above that takes a register to the class, not the vtable.
251 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
253 int intf_bit_reg = alloc_preg (cfg);
255 mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
256 mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
257 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
259 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
261 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
266 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
269 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
272 int rank_reg = alloc_preg (cfg);
273 int eclass_reg = alloc_preg (cfg);
275 g_assert (!klass_inst);
276 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
277 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
278 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
279 // MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
280 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
281 if (klass->cast_class == mono_defaults.object_class) {
282 int parent_reg = alloc_preg (cfg);
283 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
284 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
285 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
286 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
287 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
288 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
289 } else if (klass->cast_class == mono_defaults.enum_class) {
290 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
291 } else if (mono_class_is_interface (klass->cast_class)) {
292 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
294 // Pass -1 as obj_reg to skip the check below for arrays of arrays
295 mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
298 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
299 /* Check that the object is a vector too */
300 int bounds_reg = alloc_preg (cfg);
301 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
302 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
303 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
306 int idepth_reg = alloc_preg (cfg);
307 int stypes_reg = alloc_preg (cfg);
308 int stype = alloc_preg (cfg);
310 mono_class_setup_supertypes (klass);
312 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
313 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
314 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
315 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
317 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
318 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
319 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
324 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
326 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
331 * Returns NULL and set the cfg exception on error.
334 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
336 MonoBasicBlock *is_null_bb;
337 int obj_reg = src->dreg;
338 int vtable_reg = alloc_preg (cfg);
339 MonoInst *klass_inst = NULL;
341 if (MONO_INS_IS_PCONST_NULL (src))
347 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
350 cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
355 /* klass - it's the second element of the cache entry*/
356 EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
359 args [2] = cache_ins;
361 return emit_castclass_with_cache (cfg, klass, args);
364 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
367 NEW_BBLOCK (cfg, is_null_bb);
369 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
370 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
372 mini_save_cast_details (cfg, klass, obj_reg, FALSE);
374 if (mono_class_is_interface (klass)) {
375 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
376 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
378 int klass_reg = alloc_preg (cfg);
380 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
382 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
383 /* the remoting code is broken, access the class for now */
384 if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
385 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
387 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
388 cfg->exception_ptr = klass;
391 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
393 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
394 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
396 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
398 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
399 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
403 MONO_START_BB (cfg, is_null_bb);
405 mini_reset_cast_details (cfg);
411 * Returns NULL and set the cfg exception on error.
414 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
417 MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
418 int obj_reg = src->dreg;
419 int vtable_reg = alloc_preg (cfg);
420 int res_reg = alloc_ireg_ref (cfg);
421 MonoInst *klass_inst = NULL;
426 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
427 MonoInst *cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
429 args [0] = src; /* obj */
431 /* klass - it's the second element of the cache entry*/
432 EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
434 args [2] = cache_ins; /* cache */
435 return emit_isinst_with_cache (cfg, klass, args);
438 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
441 NEW_BBLOCK (cfg, is_null_bb);
442 NEW_BBLOCK (cfg, false_bb);
443 NEW_BBLOCK (cfg, end_bb);
445 /* Do the assignment at the beginning, so the other assignment can be if converted */
446 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
447 ins->type = STACK_OBJ;
450 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
451 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
453 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
455 if (mono_class_is_interface (klass)) {
456 g_assert (!context_used);
457 /* the is_null_bb target simply copies the input register to the output */
458 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
460 int klass_reg = alloc_preg (cfg);
463 int rank_reg = alloc_preg (cfg);
464 int eclass_reg = alloc_preg (cfg);
466 g_assert (!context_used);
467 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
468 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
469 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
470 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
471 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
472 if (klass->cast_class == mono_defaults.object_class) {
473 int parent_reg = alloc_preg (cfg);
474 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
475 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
476 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
477 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
478 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
479 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
480 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
481 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
482 } else if (klass->cast_class == mono_defaults.enum_class) {
483 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
484 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
485 } else if (mono_class_is_interface (klass->cast_class)) {
486 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
488 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
489 /* Check that the object is a vector too */
490 int bounds_reg = alloc_preg (cfg);
491 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
492 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
493 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
496 /* the is_null_bb target simply copies the input register to the output */
497 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
499 } else if (mono_class_is_nullable (klass)) {
500 g_assert (!context_used);
501 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
502 /* the is_null_bb target simply copies the input register to the output */
503 mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
505 if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
506 g_assert (!context_used);
507 /* the remoting code is broken, access the class for now */
508 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
509 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
511 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
512 cfg->exception_ptr = klass;
515 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
517 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
518 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
520 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
521 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
523 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
524 /* the is_null_bb target simply copies the input register to the output */
525 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
530 MONO_START_BB (cfg, false_bb);
532 MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
533 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
535 MONO_START_BB (cfg, is_null_bb);
537 MONO_START_BB (cfg, end_bb);
543 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
552 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
555 idx = get_castclass_cache_idx (cfg);
556 args [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
558 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
559 return emit_castclass_with_cache (cfg, klass, args);
564 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
566 MonoInst *ret, *move, *source;
567 MonoClass *klass = ins->klass;
568 int context_used = mini_class_check_context_used (cfg, klass);
569 int is_isinst = ins->opcode == OP_ISINST;
570 g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
571 source = get_vreg_to_inst (cfg, ins->sreg1);
572 if (!source || source == (MonoInst *) -1)
573 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
574 g_assert (source && source != (MonoInst *) -1);
576 MonoBasicBlock *first_bb;
577 NEW_BBLOCK (cfg, first_bb);
580 if (!context_used && (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface)) {
582 ret = emit_isinst_with_cache_nonshared (cfg, source, klass);
584 ret = emit_castclass_with_cache_nonshared (cfg, source, klass);
585 } else if (!context_used && (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass))) {
591 MonoMethod *wrapper = mono_marshal_get_isinst (klass);
592 costs = mini_inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
594 MonoMethod *wrapper = mono_marshal_get_castclass (klass);
595 mini_save_cast_details (cfg, klass, source->dreg, TRUE);
596 costs = mini_inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
597 mini_reset_cast_details (cfg);
599 g_assert (costs > 0);
603 ret = handle_isinst (cfg, klass, source, context_used);
605 ret = handle_castclass (cfg, klass, source, context_used);
607 EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
609 g_assert (cfg->cbb->code || first_bb->code);
610 MonoInst *prev = ins->prev;
611 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
615 mono_decompose_typechecks (MonoCompile *cfg)
617 for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
619 MONO_BB_FOR_EACH_INS (bb, ins) {
620 switch (ins->opcode) {
623 mono_decompose_typecheck (cfg, bb, ins);
630 //Those two functions will go away as we get rid of CEE_MONO_CISINST and CEE_MONO_CCASTCLASS.
632 mini_emit_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
634 /* This opcode takes as input an object reference and a class, and returns:
635 0) if the object is an instance of the class,
636 1) if the object is not instance of the class,
637 2) if the object is a proxy whose type cannot be determined */
640 #ifndef DISABLE_REMOTING
641 MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
643 MonoBasicBlock *true_bb, *false_bb, *end_bb;
645 int obj_reg = src->dreg;
646 int dreg = alloc_ireg (cfg);
648 #ifndef DISABLE_REMOTING
649 int klass_reg = alloc_preg (cfg);
652 NEW_BBLOCK (cfg, true_bb);
653 NEW_BBLOCK (cfg, false_bb);
654 NEW_BBLOCK (cfg, end_bb);
655 #ifndef DISABLE_REMOTING
656 NEW_BBLOCK (cfg, false2_bb);
657 NEW_BBLOCK (cfg, no_proxy_bb);
660 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
661 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
663 if (mono_class_is_interface (klass)) {
664 #ifndef DISABLE_REMOTING
665 NEW_BBLOCK (cfg, interface_fail_bb);
668 tmp_reg = alloc_preg (cfg);
669 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
670 #ifndef DISABLE_REMOTING
671 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
672 MONO_START_BB (cfg, interface_fail_bb);
673 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
675 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
677 tmp_reg = alloc_preg (cfg);
678 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
679 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
680 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);
682 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
685 #ifndef DISABLE_REMOTING
686 tmp_reg = alloc_preg (cfg);
687 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
688 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
690 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);
691 tmp_reg = alloc_preg (cfg);
692 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
693 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
695 tmp_reg = alloc_preg (cfg);
696 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
697 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
698 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
700 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
701 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
703 MONO_START_BB (cfg, no_proxy_bb);
705 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
707 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
711 MONO_START_BB (cfg, false_bb);
713 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
714 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
716 #ifndef DISABLE_REMOTING
717 MONO_START_BB (cfg, false2_bb);
719 MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
720 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
723 MONO_START_BB (cfg, true_bb);
725 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
727 MONO_START_BB (cfg, end_bb);
730 MONO_INST_NEW (cfg, ins, OP_ICONST);
732 ins->type = STACK_I4;
738 mini_emit_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
740 /* This opcode takes as input an object reference and a class, and returns:
741 0) if the object is an instance of the class,
742 1) if the object is a proxy whose type cannot be determined
743 an InvalidCastException exception is thrown otherwhise*/
746 #ifndef DISABLE_REMOTING
747 MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
749 MonoBasicBlock *ok_result_bb;
751 int obj_reg = src->dreg;
752 int dreg = alloc_ireg (cfg);
753 int tmp_reg = alloc_preg (cfg);
755 #ifndef DISABLE_REMOTING
756 int klass_reg = alloc_preg (cfg);
757 NEW_BBLOCK (cfg, end_bb);
760 NEW_BBLOCK (cfg, ok_result_bb);
762 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
763 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
765 mini_save_cast_details (cfg, klass, obj_reg, FALSE);
767 if (mono_class_is_interface (klass)) {
768 #ifndef DISABLE_REMOTING
769 NEW_BBLOCK (cfg, interface_fail_bb);
771 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
772 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
773 MONO_START_BB (cfg, interface_fail_bb);
774 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
776 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
778 tmp_reg = alloc_preg (cfg);
779 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
780 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
781 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
783 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
784 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
786 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
787 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
788 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
791 #ifndef DISABLE_REMOTING
792 NEW_BBLOCK (cfg, no_proxy_bb);
794 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
795 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
796 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);
798 tmp_reg = alloc_preg (cfg);
799 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
800 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
802 tmp_reg = alloc_preg (cfg);
803 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
804 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
805 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
807 NEW_BBLOCK (cfg, fail_1_bb);
809 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
811 MONO_START_BB (cfg, fail_1_bb);
813 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
814 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
816 MONO_START_BB (cfg, no_proxy_bb);
818 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
820 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
824 MONO_START_BB (cfg, ok_result_bb);
826 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
828 #ifndef DISABLE_REMOTING
829 MONO_START_BB (cfg, end_bb);
833 MONO_INST_NEW (cfg, ins, OP_ICONST);
835 ins->type = STACK_I4;
840 //API used by method-to-ir.c
842 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
844 mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);