6 #include <mono/utils/mono-compiler.h>
12 #include <mono/metadata/abi-details.h>
15 #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)
18 get_castclass_cache_idx (MonoCompile *cfg)
20 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
21 cfg->castclass_cache_index ++;
22 return (cfg->method_index << 16) | cfg->castclass_cache_index;
26 emit_cached_check_args (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used, MonoInst *args[3])
33 cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
35 /* klass - it's the second element of the cache entry*/
36 EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
38 args [2] = cache_ins; /* cache */
42 EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
44 idx = get_castclass_cache_idx (cfg); /* inline cache*/
45 args [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
50 emit_isinst_with_cache (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used)
53 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
55 emit_cached_check_args (cfg, obj, klass, context_used, args);
56 return mono_emit_method_call (cfg, mono_isinst, args, NULL);
60 emit_castclass_with_cache_no_details (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used)
63 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
66 emit_cached_check_args (cfg, obj, klass, context_used, args);
68 res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
74 emit_castclass_with_cache (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used)
77 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
80 emit_cached_check_args (cfg, obj, klass, context_used, args);
82 mini_save_cast_details (cfg, klass, args [0]->dreg, TRUE);
83 res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
84 mini_reset_cast_details (cfg);
90 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
93 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
95 MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
96 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
98 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
103 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
105 int idepth_reg = alloc_preg (cfg);
106 int stypes_reg = alloc_preg (cfg);
107 int stype = alloc_preg (cfg);
109 mono_class_setup_supertypes (klass);
111 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
112 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
113 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
114 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
116 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
117 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
119 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
120 } else if (cfg->compile_aot) {
121 int const_reg = alloc_preg (cfg);
122 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
123 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
125 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
127 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
132 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
134 int ibitmap_reg = alloc_preg (cfg);
135 #ifdef COMPRESSED_INTERFACE_BITMAP
138 NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
139 MONO_ADD_INS (cfg->cbb, ins);
141 args [1] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
142 res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
143 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
145 int ibitmap_byte_reg = alloc_preg (cfg);
147 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
149 if (cfg->compile_aot) {
150 int iid_reg = alloc_preg (cfg);
151 int shifted_iid_reg = alloc_preg (cfg);
152 int ibitmap_byte_address_reg = alloc_preg (cfg);
153 int masked_iid_reg = alloc_preg (cfg);
154 int iid_one_bit_reg = alloc_preg (cfg);
155 int iid_bit_reg = alloc_preg (cfg);
156 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
157 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
158 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
159 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
160 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
161 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
162 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
163 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
165 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
166 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
172 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
173 * stored in "klass_reg" implements the interface "klass".
176 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
178 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
182 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
183 * stored in "vtable_reg" implements the interface "klass".
186 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
188 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
192 * Emit code which checks whenever the interface id of @klass is smaller than
193 * than the value given by max_iid_reg.
196 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
197 MonoBasicBlock *false_target)
199 if (cfg->compile_aot) {
200 int iid_reg = alloc_preg (cfg);
201 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
202 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
205 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
207 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
209 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
212 /* Same as above, but obtains max_iid from a vtable */
214 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
215 MonoBasicBlock *false_target)
217 int max_iid_reg = alloc_preg (cfg);
219 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
220 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
223 /* Same as above, but obtains max_iid from a klass */
225 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
226 MonoBasicBlock *false_target)
228 int max_iid_reg = alloc_preg (cfg);
230 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
231 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
235 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
237 if (cfg->compile_aot) {
238 int const_reg = alloc_preg (cfg);
239 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
240 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
242 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
244 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
249 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
251 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
255 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
257 int intf_reg = alloc_preg (cfg);
259 mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
260 mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
261 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
263 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
265 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
269 * Variant of the above that takes a register to the class, not the vtable.
272 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
274 int intf_bit_reg = alloc_preg (cfg);
276 mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
277 mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
278 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
280 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
282 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
287 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
290 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
293 int rank_reg = alloc_preg (cfg);
294 int eclass_reg = alloc_preg (cfg);
296 g_assert (!klass_inst);
297 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
298 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
299 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
300 // MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
301 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
302 if (klass->cast_class == mono_defaults.object_class) {
303 int parent_reg = alloc_preg (cfg);
304 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
305 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
306 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
307 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
308 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
309 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
310 } else if (klass->cast_class == mono_defaults.enum_class) {
311 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
312 } else if (mono_class_is_interface (klass->cast_class)) {
313 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
315 // Pass -1 as obj_reg to skip the check below for arrays of arrays
316 mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
319 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
320 /* Check that the object is a vector too */
321 int bounds_reg = alloc_preg (cfg);
322 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
323 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
324 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
327 int idepth_reg = alloc_preg (cfg);
328 int stypes_reg = alloc_preg (cfg);
329 int stype = alloc_preg (cfg);
331 mono_class_setup_supertypes (klass);
333 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
334 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
335 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
336 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
338 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
339 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
340 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
345 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
347 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
351 emit_special_array_iface_check (MonoCompile *cfg, MonoInst *src, MonoClass* klass, int vtable_reg, MonoBasicBlock *true_bb, int context_used)
353 MonoBasicBlock *not_an_array;
356 if (!klass->is_array_special_interface)
359 rank_reg = alloc_ireg (cfg);
361 NEW_BBLOCK (cfg, not_an_array);
362 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
363 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 1);
364 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, not_an_array);
366 emit_castclass_with_cache_no_details (cfg, src, klass, context_used);
367 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, true_bb);
369 MONO_START_BB (cfg, not_an_array);
374 * Returns NULL and set the cfg exception on error.
377 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
379 MonoBasicBlock *is_null_bb;
380 int obj_reg = src->dreg;
381 MonoInst *klass_inst = NULL;
383 if (MONO_INS_IS_PCONST_NULL (src))
388 if (is_complex_isinst (klass))
389 return emit_castclass_with_cache (cfg, src, klass, context_used);
391 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
394 NEW_BBLOCK (cfg, is_null_bb);
396 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
397 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
399 mini_save_cast_details (cfg, klass, obj_reg, FALSE);
401 if (mono_class_is_interface (klass)) {
402 int tmp_reg = alloc_preg (cfg);
403 #ifndef DISABLE_REMOTING
404 MonoBasicBlock *interface_fail_bb;
405 int klass_reg = alloc_preg (cfg);
407 NEW_BBLOCK (cfg, interface_fail_bb);
409 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
410 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, is_null_bb);
412 // iface bitmap check failed
413 MONO_START_BB (cfg, interface_fail_bb);
415 //Check if it's a rank zero array and emit fallback casting
416 emit_special_array_iface_check (cfg, src, klass, tmp_reg, is_null_bb, context_used);
418 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
420 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
422 tmp_reg = alloc_preg (cfg);
423 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
424 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
425 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
427 MonoInst *args [1] = { src };
428 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
429 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
430 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
432 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
434 MonoBasicBlock *interface_fail_bb = NULL;
436 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
438 if (klass->is_array_special_interface) {
439 NEW_BBLOCK (cfg, interface_fail_bb);
440 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, is_null_bb);
441 // iface bitmap check failed
442 MONO_START_BB (cfg, interface_fail_bb);
444 //Check if it's a rank zero array and emit fallback casting
445 emit_special_array_iface_check (cfg, src, klass, tmp_reg, is_null_bb, context_used);
447 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
448 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
451 } else if (mono_class_is_marshalbyref (klass)) {
452 #ifndef DISABLE_REMOTING
453 MonoBasicBlock *no_proxy_bb, *fail_1_bb;
454 int tmp_reg = alloc_preg (cfg);
455 int klass_reg = alloc_preg (cfg);
457 NEW_BBLOCK (cfg, no_proxy_bb);
459 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
460 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
461 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);
463 tmp_reg = alloc_preg (cfg);
464 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
465 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
467 tmp_reg = alloc_preg (cfg);
468 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
469 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
470 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
472 NEW_BBLOCK (cfg, fail_1_bb);
474 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, is_null_bb);
476 MONO_START_BB (cfg, fail_1_bb);
478 MonoInst *args [1] = { src };
479 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
480 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
481 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
483 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
485 MONO_START_BB (cfg, no_proxy_bb);
487 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
489 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
492 int vtable_reg = alloc_preg (cfg);
493 int klass_reg = alloc_preg (cfg);
495 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
497 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
498 /* the remoting code is broken, access the class for now */
499 if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
500 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
502 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
503 cfg->exception_ptr = klass;
506 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
508 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
509 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
511 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
513 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
514 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
518 MONO_START_BB (cfg, is_null_bb);
520 mini_reset_cast_details (cfg);
526 * Returns NULL and set the cfg exception on error.
529 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
532 MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
533 int obj_reg = src->dreg;
534 int vtable_reg = alloc_preg (cfg);
535 int res_reg = alloc_ireg_ref (cfg);
536 MonoInst *klass_inst = NULL;
539 if(is_complex_isinst (klass))
540 return emit_isinst_with_cache (cfg, src, klass, context_used);
542 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
545 NEW_BBLOCK (cfg, is_null_bb);
546 NEW_BBLOCK (cfg, false_bb);
547 NEW_BBLOCK (cfg, end_bb);
549 /* Do the assignment at the beginning, so the other assignment can be if converted */
550 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
551 ins->type = STACK_OBJ;
554 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
555 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
557 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
559 if (mono_class_is_interface (klass)) {
560 MonoBasicBlock *interface_fail_bb;
562 NEW_BBLOCK (cfg, interface_fail_bb);
564 mini_emit_iface_cast (cfg, vtable_reg, klass, interface_fail_bb, is_null_bb);
565 MONO_START_BB (cfg, interface_fail_bb);
567 if (klass->is_array_special_interface) {
568 MonoBasicBlock *not_an_array;
570 int rank_reg = alloc_ireg (cfg);
572 NEW_BBLOCK (cfg, not_an_array);
573 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
574 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 1);
575 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, not_an_array);
577 MonoInst *res_inst = emit_isinst_with_cache (cfg, src, klass, context_used);
578 EMIT_NEW_UNALU (cfg, move, OP_MOVE, res_reg, res_inst->dreg);
579 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
581 MONO_START_BB (cfg, not_an_array);
584 #ifndef DISABLE_REMOTING
585 int tmp_reg, klass_reg;
586 MonoBasicBlock *call_proxy_isinst;
588 NEW_BBLOCK (cfg, call_proxy_isinst);
590 klass_reg = alloc_preg (cfg);
591 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
593 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
595 tmp_reg = alloc_preg (cfg);
596 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
597 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
598 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
600 MONO_START_BB (cfg, call_proxy_isinst);
602 MonoInst *args [1] = { src };
603 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
604 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
605 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_null_bb);
607 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
610 } else if (mono_class_is_marshalbyref (klass)) {
612 #ifndef DISABLE_REMOTING
613 int tmp_reg, klass_reg;
614 MonoBasicBlock *no_proxy_bb, *call_proxy_isinst;
616 NEW_BBLOCK (cfg, no_proxy_bb);
617 NEW_BBLOCK (cfg, call_proxy_isinst);
619 klass_reg = alloc_preg (cfg);
620 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
622 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);
624 tmp_reg = alloc_preg (cfg);
625 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
626 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
628 tmp_reg = alloc_preg (cfg);
629 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
630 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
631 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
633 mini_emit_isninst_cast (cfg, klass_reg, klass, call_proxy_isinst, is_null_bb);
635 MONO_START_BB (cfg, call_proxy_isinst);
637 MonoInst *args [1] = { src };
638 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
639 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
640 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_null_bb);
641 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
643 MONO_START_BB (cfg, no_proxy_bb);
645 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, is_null_bb);
647 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
650 int klass_reg = alloc_preg (cfg);
653 int rank_reg = alloc_preg (cfg);
654 int eclass_reg = alloc_preg (cfg);
656 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
657 /* Check that the object is a vector too */
658 int bounds_reg = alloc_preg (cfg);
659 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
660 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
661 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
664 g_assert (!context_used);
665 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
666 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
667 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
668 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
669 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
670 if (klass->cast_class == mono_defaults.object_class) {
671 int parent_reg = alloc_preg (cfg);
672 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
673 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
674 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
675 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
676 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
677 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
678 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
679 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
680 } else if (klass->cast_class == mono_defaults.enum_class) {
681 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
682 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
683 } else if (mono_class_is_interface (klass->cast_class)) {
684 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
686 /* the is_null_bb target simply copies the input register to the output */
687 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
689 } else if (mono_class_is_nullable (klass)) {
690 g_assert (!context_used);
691 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
692 /* the is_null_bb target simply copies the input register to the output */
693 mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
695 if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
696 g_assert (!context_used);
697 /* the remoting code is broken, access the class for now */
698 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
699 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
701 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
702 cfg->exception_ptr = klass;
705 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
707 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
708 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
710 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
711 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
713 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
714 /* the is_null_bb target simply copies the input register to the output */
715 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
720 MONO_START_BB (cfg, false_bb);
722 MONO_EMIT_NEW_PCONST (cfg, res_reg, NULL);
723 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
725 MONO_START_BB (cfg, is_null_bb);
727 MONO_START_BB (cfg, end_bb);
733 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
735 MonoInst *ret, *move, *source;
736 MonoClass *klass = ins->klass;
737 int context_used = mini_class_check_context_used (cfg, klass);
738 int is_isinst = ins->opcode == OP_ISINST;
739 g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
740 source = get_vreg_to_inst (cfg, ins->sreg1);
741 if (!source || source == (MonoInst *) -1)
742 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
743 g_assert (source && source != (MonoInst *) -1);
745 MonoBasicBlock *first_bb;
746 NEW_BBLOCK (cfg, first_bb);
749 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
751 ret = emit_isinst_with_cache (cfg, source, klass, context_used);
753 ret = emit_castclass_with_cache (cfg, source, klass, context_used);
757 ret = handle_isinst (cfg, klass, source, context_used);
759 ret = handle_castclass (cfg, klass, source, context_used);
761 EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
763 g_assert (cfg->cbb->code || first_bb->code);
764 MonoInst *prev = ins->prev;
765 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
769 mono_decompose_typechecks (MonoCompile *cfg)
771 gboolean found_typetest = FALSE;
772 for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
774 MONO_BB_FOR_EACH_INS (bb, ins) {
775 switch (ins->opcode) {
778 found_typetest = TRUE;
779 mono_decompose_typecheck (cfg, bb, ins);
784 if ((cfg->verbose_level > 2) && found_typetest)
785 mono_print_code (cfg, "AFTER DECOMPOSE TYPE_CHECKS");
790 //API used by method-to-ir.c
792 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
794 mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
799 MONO_EMPTY_SOURCE_FILE (type_checking);