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_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
43 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
46 mini_save_cast_details (cfg, klass, args [0]->dreg, TRUE);
47 res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
48 mini_reset_cast_details (cfg);
54 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
57 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
59 MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
60 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
62 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
67 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
69 int idepth_reg = alloc_preg (cfg);
70 int stypes_reg = alloc_preg (cfg);
71 int stype = alloc_preg (cfg);
73 mono_class_setup_supertypes (klass);
75 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
76 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
77 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
78 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
80 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
81 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
83 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
84 } else if (cfg->compile_aot) {
85 int const_reg = alloc_preg (cfg);
86 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
87 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
89 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
91 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
96 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
98 int ibitmap_reg = alloc_preg (cfg);
99 #ifdef COMPRESSED_INTERFACE_BITMAP
102 NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
103 MONO_ADD_INS (cfg->cbb, ins);
105 args [1] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
106 res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
107 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
109 int ibitmap_byte_reg = alloc_preg (cfg);
111 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
113 if (cfg->compile_aot) {
114 int iid_reg = alloc_preg (cfg);
115 int shifted_iid_reg = alloc_preg (cfg);
116 int ibitmap_byte_address_reg = alloc_preg (cfg);
117 int masked_iid_reg = alloc_preg (cfg);
118 int iid_one_bit_reg = alloc_preg (cfg);
119 int iid_bit_reg = alloc_preg (cfg);
120 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
121 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
122 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
123 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
124 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
125 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
126 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
127 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
129 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
130 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
136 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
137 * stored in "klass_reg" implements the interface "klass".
140 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
142 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
146 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
147 * stored in "vtable_reg" implements the interface "klass".
150 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
152 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
156 * Emit code which checks whenever the interface id of @klass is smaller than
157 * than the value given by max_iid_reg.
160 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
161 MonoBasicBlock *false_target)
163 if (cfg->compile_aot) {
164 int iid_reg = alloc_preg (cfg);
165 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
166 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
169 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
171 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
173 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
176 /* Same as above, but obtains max_iid from a vtable */
178 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
179 MonoBasicBlock *false_target)
181 int max_iid_reg = alloc_preg (cfg);
183 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
184 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
187 /* Same as above, but obtains max_iid from a klass */
189 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
190 MonoBasicBlock *false_target)
192 int max_iid_reg = alloc_preg (cfg);
194 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
195 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
199 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
201 if (cfg->compile_aot) {
202 int const_reg = alloc_preg (cfg);
203 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
204 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
206 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
208 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
213 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
215 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
219 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
221 int intf_reg = alloc_preg (cfg);
223 mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
224 mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
225 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
227 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
229 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
233 * Variant of the above that takes a register to the class, not the vtable.
236 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
238 int intf_bit_reg = alloc_preg (cfg);
240 mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
241 mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
242 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
244 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
246 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
251 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
254 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
257 int rank_reg = alloc_preg (cfg);
258 int eclass_reg = alloc_preg (cfg);
260 g_assert (!klass_inst);
261 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
262 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
263 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
264 // MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
265 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
266 if (klass->cast_class == mono_defaults.object_class) {
267 int parent_reg = alloc_preg (cfg);
268 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
269 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
270 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
271 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
272 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
273 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
274 } else if (klass->cast_class == mono_defaults.enum_class) {
275 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
276 } else if (mono_class_is_interface (klass->cast_class)) {
277 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
279 // Pass -1 as obj_reg to skip the check below for arrays of arrays
280 mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
283 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
284 /* Check that the object is a vector too */
285 int bounds_reg = alloc_preg (cfg);
286 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
287 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
288 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
291 int idepth_reg = alloc_preg (cfg);
292 int stypes_reg = alloc_preg (cfg);
293 int stype = alloc_preg (cfg);
295 mono_class_setup_supertypes (klass);
297 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
298 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
299 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
300 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
302 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
303 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
304 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
309 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
311 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
316 * Returns NULL and set the cfg exception on error.
319 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
321 MonoBasicBlock *is_null_bb;
322 int obj_reg = src->dreg;
323 int vtable_reg = alloc_preg (cfg);
324 MonoInst *klass_inst = NULL;
326 if (MONO_INS_IS_PCONST_NULL (src))
332 if (is_complex_isinst (klass)) {
335 cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
340 /* klass - it's the second element of the cache entry*/
341 EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
344 args [2] = cache_ins;
346 return emit_castclass_with_cache (cfg, klass, args);
349 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
352 NEW_BBLOCK (cfg, is_null_bb);
354 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
355 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
357 mini_save_cast_details (cfg, klass, obj_reg, FALSE);
359 if (mono_class_is_interface (klass)) {
360 int tmp_reg = alloc_preg (cfg);
361 #ifndef DISABLE_REMOTING
362 MonoBasicBlock *interface_fail_bb;
363 int klass_reg = alloc_preg (cfg);
365 NEW_BBLOCK (cfg, interface_fail_bb);
367 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
368 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, is_null_bb);
370 // iface bitmap check failed
371 MONO_START_BB (cfg, interface_fail_bb);
372 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
374 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
376 tmp_reg = alloc_preg (cfg);
377 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
378 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
379 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
381 MonoInst *args [1] = { src };
382 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
383 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
384 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
386 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
388 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
389 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
390 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
392 } else if (mono_class_is_marshalbyref (klass)) {
393 #ifndef DISABLE_REMOTING
394 MonoBasicBlock *no_proxy_bb, *fail_1_bb;
395 int tmp_reg = alloc_preg (cfg);
396 int klass_reg = alloc_preg (cfg);
398 NEW_BBLOCK (cfg, no_proxy_bb);
400 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
401 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
402 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);
404 tmp_reg = alloc_preg (cfg);
405 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
406 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
408 tmp_reg = alloc_preg (cfg);
409 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
410 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
411 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
413 NEW_BBLOCK (cfg, fail_1_bb);
415 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, is_null_bb);
417 MONO_START_BB (cfg, fail_1_bb);
419 MonoInst *args [1] = { src };
420 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
421 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
422 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
424 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
426 MONO_START_BB (cfg, no_proxy_bb);
428 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
430 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
433 int klass_reg = alloc_preg (cfg);
435 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
437 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
438 /* the remoting code is broken, access the class for now */
439 if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
440 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
442 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
443 cfg->exception_ptr = klass;
446 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
448 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
449 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
451 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
453 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
454 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
458 MONO_START_BB (cfg, is_null_bb);
460 mini_reset_cast_details (cfg);
466 * Returns NULL and set the cfg exception on error.
469 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
472 MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
473 int obj_reg = src->dreg;
474 int vtable_reg = alloc_preg (cfg);
475 int res_reg = alloc_ireg_ref (cfg);
476 MonoInst *klass_inst = NULL;
481 if(is_complex_isinst (klass)) {
482 MonoInst *cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
484 args [0] = src; /* obj */
486 /* klass - it's the second element of the cache entry*/
487 EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
489 args [2] = cache_ins; /* cache */
490 return emit_isinst_with_cache (cfg, klass, args);
493 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
496 NEW_BBLOCK (cfg, is_null_bb);
497 NEW_BBLOCK (cfg, false_bb);
498 NEW_BBLOCK (cfg, end_bb);
500 /* Do the assignment at the beginning, so the other assignment can be if converted */
501 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
502 ins->type = STACK_OBJ;
505 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
506 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
508 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
510 if (mono_class_is_interface (klass)) {
511 int tmp_reg, klass_reg;
513 #ifndef DISABLE_REMOTING
514 MonoBasicBlock *interface_fail_bb, *call_proxy_isinst;
516 NEW_BBLOCK (cfg, interface_fail_bb);
517 NEW_BBLOCK (cfg, call_proxy_isinst);
520 #ifndef DISABLE_REMOTING
521 klass_reg = alloc_preg (cfg);
522 mini_emit_iface_cast (cfg, vtable_reg, klass, interface_fail_bb, is_null_bb);
523 MONO_START_BB (cfg, interface_fail_bb);
524 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
526 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
528 tmp_reg = alloc_preg (cfg);
529 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
530 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
531 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
533 MONO_START_BB (cfg, call_proxy_isinst);
535 MonoInst *args [1] = { src };
536 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
537 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
538 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_null_bb);
540 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
543 int klass_reg = alloc_preg (cfg);
546 int rank_reg = alloc_preg (cfg);
547 int eclass_reg = alloc_preg (cfg);
549 g_assert (!context_used);
550 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
551 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
552 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
553 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
554 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
555 if (klass->cast_class == mono_defaults.object_class) {
556 int parent_reg = alloc_preg (cfg);
557 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
558 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
559 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
560 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
561 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
562 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
563 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
564 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
565 } else if (klass->cast_class == mono_defaults.enum_class) {
566 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
567 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
568 } else if (mono_class_is_interface (klass->cast_class)) {
569 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
571 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
572 /* Check that the object is a vector too */
573 int bounds_reg = alloc_preg (cfg);
574 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
575 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
576 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
579 /* the is_null_bb target simply copies the input register to the output */
580 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
582 } else if (mono_class_is_nullable (klass)) {
583 g_assert (!context_used);
584 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
585 /* the is_null_bb target simply copies the input register to the output */
586 mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
588 if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
589 g_assert (!context_used);
590 /* the remoting code is broken, access the class for now */
591 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
592 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
594 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
595 cfg->exception_ptr = klass;
598 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
600 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
601 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
603 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
604 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
606 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
607 /* the is_null_bb target simply copies the input register to the output */
608 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
613 MONO_START_BB (cfg, false_bb);
615 MONO_EMIT_NEW_PCONST (cfg, res_reg, NULL);
616 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
618 MONO_START_BB (cfg, is_null_bb);
620 MONO_START_BB (cfg, end_bb);
626 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
628 MonoInst *ret, *move, *source;
629 MonoClass *klass = ins->klass;
630 int context_used = mini_class_check_context_used (cfg, klass);
631 int is_isinst = ins->opcode == OP_ISINST;
632 g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
633 source = get_vreg_to_inst (cfg, ins->sreg1);
634 if (!source || source == (MonoInst *) -1)
635 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
636 g_assert (source && source != (MonoInst *) -1);
638 MonoBasicBlock *first_bb;
639 NEW_BBLOCK (cfg, first_bb);
642 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || klass->is_array_special_interface) {
644 args [0] = source; /* obj */
649 cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
651 /* klass - it's the second element of the cache entry*/
652 EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
654 args [2] = cache_ins; /* cache */
658 EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
660 idx = get_castclass_cache_idx (cfg); /* inline cache*/
661 args [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
664 ret = emit_isinst_with_cache (cfg, klass, args);
666 ret = emit_castclass_with_cache (cfg, klass, args);
668 } else if (!context_used && is_isinst && mono_class_is_marshalbyref (klass)) {
673 MonoMethod *wrapper = mono_marshal_get_isinst (klass);
674 costs = mini_inline_method (cfg, wrapper, mono_method_signature (wrapper), iargs, 0, 0, TRUE);
675 g_assert (costs > 0);
679 ret = handle_isinst (cfg, klass, source, context_used);
681 ret = handle_castclass (cfg, klass, source, context_used);
683 EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
685 g_assert (cfg->cbb->code || first_bb->code);
686 MonoInst *prev = ins->prev;
687 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
691 mono_decompose_typechecks (MonoCompile *cfg)
693 gboolean found_typetest = FALSE;
694 for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
696 MONO_BB_FOR_EACH_INS (bb, ins) {
697 switch (ins->opcode) {
700 found_typetest = TRUE;
701 mono_decompose_typecheck (cfg, bb, ins);
706 if ((cfg->verbose_level > 2) && found_typetest)
707 mono_print_code (cfg, "AFTER DECOMPOSE TYPE_CHECKS");
711 //Those two functions will go away as we get rid of CEE_MONO_CISINST and CEE_MONO_CCASTCLASS.
713 mini_emit_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
715 /* This opcode takes as input an object reference and a class, and returns:
716 0) if the object is an instance of the class,
717 1) if the object is not instance of the class,
718 2) if the object is a proxy whose type cannot be determined */
721 #ifndef DISABLE_REMOTING
722 MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
724 MonoBasicBlock *true_bb, *false_bb, *end_bb;
726 int obj_reg = src->dreg;
727 int dreg = alloc_ireg (cfg);
729 #ifndef DISABLE_REMOTING
730 int klass_reg = alloc_preg (cfg);
733 NEW_BBLOCK (cfg, true_bb);
734 NEW_BBLOCK (cfg, false_bb);
735 NEW_BBLOCK (cfg, end_bb);
736 #ifndef DISABLE_REMOTING
737 NEW_BBLOCK (cfg, false2_bb);
738 NEW_BBLOCK (cfg, no_proxy_bb);
741 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
742 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
744 if (mono_class_is_interface (klass)) {
745 g_error ("not supported");
747 #ifndef DISABLE_REMOTING
748 tmp_reg = alloc_preg (cfg);
749 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
750 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
752 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);
753 tmp_reg = alloc_preg (cfg);
754 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
755 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
757 tmp_reg = alloc_preg (cfg);
758 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
759 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
760 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
762 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
763 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
765 MONO_START_BB (cfg, no_proxy_bb);
767 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
769 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
773 MONO_START_BB (cfg, false_bb);
775 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
776 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
778 #ifndef DISABLE_REMOTING
779 MONO_START_BB (cfg, false2_bb);
781 MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
782 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
785 MONO_START_BB (cfg, true_bb);
787 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
789 MONO_START_BB (cfg, end_bb);
792 MONO_INST_NEW (cfg, ins, OP_ICONST);
794 ins->type = STACK_I4;
799 //API used by method-to-ir.c
801 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
803 mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);