6 #include <mono/utils/mono-compiler.h>
12 #include <mono/metadata/abi-details.h>
15 //XXX maybe move to mini.h / mini.c?
18 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
21 return mono_class_check_context_used (klass);
27 #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)
30 get_castclass_cache_idx (MonoCompile *cfg)
32 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
33 cfg->castclass_cache_index ++;
34 return (cfg->method_index << 16) | cfg->castclass_cache_index;
38 emit_cached_check_args (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used, MonoInst *args[3])
45 cache_ins = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
47 /* klass - it's the second element of the cache entry*/
48 EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
50 args [2] = cache_ins; /* cache */
54 EMIT_NEW_CLASSCONST (cfg, args [1], klass); /* klass */
56 idx = get_castclass_cache_idx (cfg); /* inline cache*/
57 args [2] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
62 emit_isinst_with_cache (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used)
65 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
67 emit_cached_check_args (cfg, obj, klass, context_used, args);
68 return mono_emit_method_call (cfg, mono_isinst, args, NULL);
72 emit_castclass_with_cache_no_details (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used)
75 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
78 emit_cached_check_args (cfg, obj, klass, context_used, args);
80 res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
86 emit_castclass_with_cache (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, int context_used)
89 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
92 emit_cached_check_args (cfg, obj, klass, context_used, args);
94 mini_save_cast_details (cfg, klass, args [0]->dreg, TRUE);
95 res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
96 mini_reset_cast_details (cfg);
102 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
105 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
107 MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
108 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
110 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
115 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
117 int idepth_reg = alloc_preg (cfg);
118 int stypes_reg = alloc_preg (cfg);
119 int stype = alloc_preg (cfg);
121 mono_class_setup_supertypes (klass);
123 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
124 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
125 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
126 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
128 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
129 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
131 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
132 } else if (cfg->compile_aot) {
133 int const_reg = alloc_preg (cfg);
134 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
135 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
137 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
139 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
144 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
146 int ibitmap_reg = alloc_preg (cfg);
147 #ifdef COMPRESSED_INTERFACE_BITMAP
150 NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
151 MONO_ADD_INS (cfg->cbb, ins);
153 args [1] = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
154 res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
155 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
157 int ibitmap_byte_reg = alloc_preg (cfg);
159 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
161 if (cfg->compile_aot) {
162 int iid_reg = alloc_preg (cfg);
163 int shifted_iid_reg = alloc_preg (cfg);
164 int ibitmap_byte_address_reg = alloc_preg (cfg);
165 int masked_iid_reg = alloc_preg (cfg);
166 int iid_one_bit_reg = alloc_preg (cfg);
167 int iid_bit_reg = alloc_preg (cfg);
168 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
169 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
170 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
171 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
172 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
173 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
174 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
175 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
177 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
178 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
184 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
185 * stored in "klass_reg" implements the interface "klass".
188 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
190 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
194 * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
195 * stored in "vtable_reg" implements the interface "klass".
198 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
200 mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
204 * Emit code which checks whenever the interface id of @klass is smaller than
205 * than the value given by max_iid_reg.
208 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
209 MonoBasicBlock *false_target)
211 if (cfg->compile_aot) {
212 int iid_reg = alloc_preg (cfg);
213 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
214 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
217 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
219 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
221 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
224 /* Same as above, but obtains max_iid from a vtable */
226 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_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, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
232 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
235 /* Same as above, but obtains max_iid from a klass */
237 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
238 MonoBasicBlock *false_target)
240 int max_iid_reg = alloc_preg (cfg);
242 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU4_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
243 mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
247 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
249 if (cfg->compile_aot) {
250 int const_reg = alloc_preg (cfg);
251 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
252 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
254 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
256 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
261 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
263 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
267 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
269 int intf_reg = alloc_preg (cfg);
271 mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
272 mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
273 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
275 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
277 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
281 * Variant of the above that takes a register to the class, not the vtable.
284 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
286 int intf_bit_reg = alloc_preg (cfg);
288 mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
289 mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
290 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
292 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
294 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
299 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
302 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
305 int rank_reg = alloc_preg (cfg);
306 int eclass_reg = alloc_preg (cfg);
308 g_assert (!klass_inst);
309 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
310 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
311 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
312 // MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
313 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
314 if (klass->cast_class == mono_defaults.object_class) {
315 int parent_reg = alloc_preg (cfg);
316 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
317 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
318 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
319 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
320 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
321 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
322 } else if (klass->cast_class == mono_defaults.enum_class) {
323 mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
324 } else if (mono_class_is_interface (klass->cast_class)) {
325 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
327 // Pass -1 as obj_reg to skip the check below for arrays of arrays
328 mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
331 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
332 /* Check that the object is a vector too */
333 int bounds_reg = alloc_preg (cfg);
334 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
335 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
336 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
339 int idepth_reg = alloc_preg (cfg);
340 int stypes_reg = alloc_preg (cfg);
341 int stype = alloc_preg (cfg);
343 mono_class_setup_supertypes (klass);
345 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
346 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
347 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
348 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
350 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
351 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
352 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
357 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
359 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
363 emit_special_array_iface_check (MonoCompile *cfg, MonoInst *src, MonoClass* klass, int vtable_reg, MonoBasicBlock *true_bb, int context_used)
365 MonoBasicBlock *not_an_array;
368 if (!klass->is_array_special_interface)
371 rank_reg = alloc_ireg (cfg);
373 NEW_BBLOCK (cfg, not_an_array);
374 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
375 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 1);
376 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, not_an_array);
378 emit_castclass_with_cache_no_details (cfg, src, klass, context_used);
379 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, true_bb);
381 MONO_START_BB (cfg, not_an_array);
386 * Returns NULL and set the cfg exception on error.
389 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
391 MonoBasicBlock *is_null_bb;
392 int obj_reg = src->dreg;
393 MonoInst *klass_inst = NULL;
395 if (MONO_INS_IS_PCONST_NULL (src))
400 if (is_complex_isinst (klass))
401 return emit_castclass_with_cache (cfg, src, klass, context_used);
403 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
406 NEW_BBLOCK (cfg, is_null_bb);
408 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
409 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
411 mini_save_cast_details (cfg, klass, obj_reg, FALSE);
413 if (mono_class_is_interface (klass)) {
414 int tmp_reg = alloc_preg (cfg);
415 #ifndef DISABLE_REMOTING
416 MonoBasicBlock *interface_fail_bb;
417 int klass_reg = alloc_preg (cfg);
419 NEW_BBLOCK (cfg, interface_fail_bb);
421 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
422 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, is_null_bb);
424 // iface bitmap check failed
425 MONO_START_BB (cfg, interface_fail_bb);
427 //Check if it's a rank zero array and emit fallback casting
428 emit_special_array_iface_check (cfg, src, klass, tmp_reg, is_null_bb, context_used);
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 (klass->is_array_special_interface) {
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, 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 (!klass->rank && !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 (cfg->domain, klass);
514 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
515 cfg->exception_ptr = klass;
518 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
520 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
521 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
523 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
525 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
526 mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
530 MONO_START_BB (cfg, is_null_bb);
532 mini_reset_cast_details (cfg);
538 * Returns NULL and set the cfg exception on error.
541 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
544 MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
545 int obj_reg = src->dreg;
546 int vtable_reg = alloc_preg (cfg);
547 int res_reg = alloc_ireg_ref (cfg);
548 MonoInst *klass_inst = NULL;
551 if(is_complex_isinst (klass))
552 return emit_isinst_with_cache (cfg, src, klass, context_used);
554 klass_inst = mini_emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
557 NEW_BBLOCK (cfg, is_null_bb);
558 NEW_BBLOCK (cfg, false_bb);
559 NEW_BBLOCK (cfg, end_bb);
561 /* Do the assignment at the beginning, so the other assignment can be if converted */
562 EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
563 ins->type = STACK_OBJ;
566 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
567 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
569 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
571 if (mono_class_is_interface (klass)) {
572 MonoBasicBlock *interface_fail_bb;
574 NEW_BBLOCK (cfg, interface_fail_bb);
576 mini_emit_iface_cast (cfg, vtable_reg, klass, interface_fail_bb, is_null_bb);
577 MONO_START_BB (cfg, interface_fail_bb);
579 if (klass->is_array_special_interface) {
580 MonoBasicBlock *not_an_array;
582 int rank_reg = alloc_ireg (cfg);
584 NEW_BBLOCK (cfg, not_an_array);
585 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
586 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 1);
587 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, not_an_array);
589 MonoInst *res_inst = emit_isinst_with_cache (cfg, src, klass, context_used);
590 EMIT_NEW_UNALU (cfg, move, OP_MOVE, res_reg, res_inst->dreg);
591 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
593 MONO_START_BB (cfg, not_an_array);
596 #ifndef DISABLE_REMOTING
597 int tmp_reg, klass_reg;
598 MonoBasicBlock *call_proxy_isinst;
600 NEW_BBLOCK (cfg, call_proxy_isinst);
602 klass_reg = alloc_preg (cfg);
603 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
605 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
607 tmp_reg = alloc_preg (cfg);
608 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
609 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
610 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
612 MONO_START_BB (cfg, call_proxy_isinst);
614 MonoInst *args [1] = { src };
615 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
616 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
617 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_null_bb);
619 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
622 } else if (mono_class_is_marshalbyref (klass)) {
624 #ifndef DISABLE_REMOTING
625 int tmp_reg, klass_reg;
626 MonoBasicBlock *no_proxy_bb, *call_proxy_isinst;
628 NEW_BBLOCK (cfg, no_proxy_bb);
629 NEW_BBLOCK (cfg, call_proxy_isinst);
631 klass_reg = alloc_preg (cfg);
632 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
634 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);
636 tmp_reg = alloc_preg (cfg);
637 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
638 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
640 tmp_reg = alloc_preg (cfg);
641 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
642 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
643 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
645 mini_emit_isninst_cast (cfg, klass_reg, klass, call_proxy_isinst, is_null_bb);
647 MONO_START_BB (cfg, call_proxy_isinst);
649 MonoInst *args [1] = { src };
650 MonoInst *proxy_test_inst = mono_emit_method_call (cfg, mono_marshal_get_proxy_cancast (klass), args, NULL);
651 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, proxy_test_inst->dreg, 0);
652 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, is_null_bb);
653 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
655 MONO_START_BB (cfg, no_proxy_bb);
657 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, is_null_bb);
659 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
662 int klass_reg = alloc_preg (cfg);
665 int rank_reg = alloc_preg (cfg);
666 int eclass_reg = alloc_preg (cfg);
668 g_assert (!context_used);
669 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
670 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
671 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
672 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
673 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
674 if (klass->cast_class == mono_defaults.object_class) {
675 int parent_reg = alloc_preg (cfg);
676 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
677 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, 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->parent) {
681 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
682 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
683 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
684 } else if (klass->cast_class == mono_defaults.enum_class) {
685 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
686 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
687 } else if (mono_class_is_interface (klass->cast_class)) {
688 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
690 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
691 /* Check that the object is a vector too */
692 int bounds_reg = alloc_preg (cfg);
693 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
694 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
695 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
698 /* the is_null_bb target simply copies the input register to the output */
699 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
701 } else if (mono_class_is_nullable (klass)) {
702 g_assert (!context_used);
703 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
704 /* the is_null_bb target simply copies the input register to the output */
705 mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
707 if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && mono_class_is_sealed (klass)) {
708 g_assert (!context_used);
709 /* the remoting code is broken, access the class for now */
710 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
711 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
713 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
714 cfg->exception_ptr = klass;
717 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
719 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
720 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
722 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
723 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
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_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
732 MONO_START_BB (cfg, false_bb);
734 MONO_EMIT_NEW_PCONST (cfg, res_reg, NULL);
735 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
737 MONO_START_BB (cfg, is_null_bb);
739 MONO_START_BB (cfg, end_bb);
745 mono_decompose_typecheck (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins)
747 MonoInst *ret, *move, *source;
748 MonoClass *klass = ins->klass;
749 int context_used = mini_class_check_context_used (cfg, klass);
750 int is_isinst = ins->opcode == OP_ISINST;
751 g_assert (is_isinst || ins->opcode == OP_CASTCLASS);
752 source = get_vreg_to_inst (cfg, ins->sreg1);
753 if (!source || source == (MonoInst *) -1)
754 source = mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, ins->sreg1);
755 g_assert (source && source != (MonoInst *) -1);
757 MonoBasicBlock *first_bb;
758 NEW_BBLOCK (cfg, first_bb);
761 if (mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
763 ret = emit_isinst_with_cache (cfg, source, klass, context_used);
765 ret = emit_castclass_with_cache (cfg, source, klass, context_used);
769 ret = handle_isinst (cfg, klass, source, context_used);
771 ret = handle_castclass (cfg, klass, source, context_used);
773 EMIT_NEW_UNALU (cfg, move, OP_MOVE, ins->dreg, ret->dreg);
775 g_assert (cfg->cbb->code || first_bb->code);
776 MonoInst *prev = ins->prev;
777 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
781 mono_decompose_typechecks (MonoCompile *cfg)
783 gboolean found_typetest = FALSE;
784 for (MonoBasicBlock *bb = cfg->bb_entry; bb; bb = bb->next_bb) {
786 MONO_BB_FOR_EACH_INS (bb, ins) {
787 switch (ins->opcode) {
790 found_typetest = TRUE;
791 mono_decompose_typecheck (cfg, bb, ins);
796 if ((cfg->verbose_level > 2) && found_typetest)
797 mono_print_code (cfg, "AFTER DECOMPOSE TYPE_CHECKS");
802 //API used by method-to-ir.c
804 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
806 mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
811 MONO_EMPTY_SOURCE_FILE (type_checking);