@@ -167,7 +167,7 @@ mono_tailcall_print (const char *format, ...)
167
167
168
168
#define TYPE_LOAD_ERROR (klass ) do { \
169
169
cfg->exception_ptr = klass; \
170
- LOAD_ERROR; \
170
+ LOAD_ERROR; \
171
171
} while (0)
172
172
173
173
#define CHECK_CFG_ERROR do {\
@@ -2303,6 +2303,18 @@ emit_not_supported_failure (MonoCompile *cfg)
2303
2303
mono_emit_jit_icall (cfg , mono_throw_not_supported , NULL );
2304
2304
}
2305
2305
2306
+ static void
2307
+ emit_type_load_failure (MonoCompile * cfg , MonoClass * klass )
2308
+ {
2309
+ MonoInst * iargs [1 ];
2310
+ if (G_LIKELY (klass )) {
2311
+ EMIT_NEW_CLASSCONST (cfg , iargs [0 ], klass );
2312
+ } else {
2313
+ EMIT_NEW_PCONST (cfg , iargs [0 ], NULL );
2314
+ }
2315
+ mono_emit_jit_icall (cfg , mono_throw_type_load , iargs );
2316
+ }
2317
+
2306
2318
static void
2307
2319
emit_invalid_program_with_msg (MonoCompile * cfg , MonoError * error_msg , MonoMethod * caller , MonoMethod * callee )
2308
2320
{
@@ -4982,6 +4994,15 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
4982
4994
#define CHECK_UNVERIFIABLE (cfg ) if (cfg->unverifiable) UNVERIFIED
4983
4995
#define CHECK_TYPELOAD (klass ) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
4984
4996
4997
+ #define CLEAR_TYPELOAD_EXCEPTION (cfg ) if (cfg->exception_type == MONO_EXCEPTION_TYPE_LOAD) { clear_cfg_error (cfg); cfg->exception_type = MONO_EXCEPTION_NONE; }
4998
+ #define CLASS_HAS_FAILURE (klass ) (!(klass) || mono_class_has_failure (klass))
4999
+ #define HANDLE_TYPELOAD_ERROR (cfg ,klass ) do { \
5000
+ if (!cfg->compile_aot) \
5001
+ TYPE_LOAD_ERROR ((klass)); \
5002
+ emit_type_load_failure (cfg, klass); \
5003
+ CLEAR_TYPELOAD_EXCEPTION (cfg); \
5004
+ } while (0)
5005
+
4985
5006
/* offset from br.s -> br like opcodes */
4986
5007
#define BIG_BRANCH_OFFSET 13
4987
5008
@@ -5457,7 +5478,9 @@ emit_optimized_ldloca_ir (MonoCompile *cfg, guchar *ip, guchar *end, int local)
5457
5478
if ((ip = il_read_initobj (ip , end , & token )) && ip_in_bb (cfg , cfg -> cbb , start + 1 )) {
5458
5479
/* From the INITOBJ case */
5459
5480
klass = mini_get_class (cfg -> current_method , token , cfg -> generic_context );
5460
- CHECK_TYPELOAD (klass );
5481
+ if (CLASS_HAS_FAILURE (klass )) {
5482
+ HANDLE_TYPELOAD_ERROR (cfg , klass );
5483
+ }
5461
5484
type = mini_get_underlying_type (m_class_get_byval_arg (klass ));
5462
5485
emit_init_local (cfg , local , type , TRUE);
5463
5486
return ip ;
@@ -6189,6 +6212,49 @@ emit_llvmonly_interp_entry (MonoCompile *cfg, MonoMethodHeader *header)
6189
6212
link_bblock (cfg , cfg -> cbb , cfg -> bb_exit );
6190
6213
}
6191
6214
6215
+ static void
6216
+ method_make_alwaysthrow_typeloadfailure (MonoCompile * cfg , MonoClass * klass )
6217
+ {
6218
+ // Get rid of all out-BBs from the entry BB. (all but init BB)
6219
+ for (gint16 i = cfg -> bb_entry -> out_count - 1 ; i >= 0 ; i -- ) {
6220
+ if (cfg -> bb_entry -> out_bb [i ] != cfg -> bb_init ) {
6221
+ mono_unlink_bblock (cfg , cfg -> bb_entry , cfg -> bb_entry -> out_bb [i ]);
6222
+ mono_remove_bblock (cfg , cfg -> bb_entry -> out_bb [i ]);
6223
+ }
6224
+ }
6225
+
6226
+ // Discard all out-BBs from the init BB.
6227
+ for (gint16 i = cfg -> bb_init -> out_count - 1 ; i >= 0 ; i -- ) {
6228
+ if (cfg -> bb_init -> out_bb [i ] != cfg -> bb_exit ) {
6229
+ mono_unlink_bblock (cfg , cfg -> bb_init , cfg -> bb_init -> out_bb [i ]);
6230
+ mono_remove_bblock (cfg , cfg -> bb_init -> out_bb [i ]);
6231
+ }
6232
+ }
6233
+
6234
+ // Maintain linked list consistency. This BB should have been added as the last,
6235
+ // ignoring the ones that held actual method code.
6236
+ cfg -> cbb = cfg -> bb_init ;
6237
+
6238
+ // Create a new BB that only throws, link it after the entry.
6239
+ MonoBasicBlock * bb ;
6240
+ NEW_BBLOCK (cfg , bb );
6241
+ bb -> cil_code = NULL ;
6242
+ bb -> cil_length = 0 ;
6243
+ cfg -> cbb -> next_bb = bb ;
6244
+ cfg -> cbb = bb ;
6245
+
6246
+ emit_type_load_failure (cfg , klass );
6247
+ MonoInst * ins ;
6248
+ MONO_INST_NEW (cfg , ins , OP_NOT_REACHED );
6249
+ MONO_ADD_INS (cfg -> cbb , ins );
6250
+
6251
+ ADD_BBLOCK (cfg , bb );
6252
+ mono_link_bblock (cfg , cfg -> bb_init , bb );
6253
+ mono_link_bblock (cfg , bb , cfg -> bb_exit );
6254
+
6255
+ cfg -> disable_inline = TRUE;
6256
+ }
6257
+
6192
6258
typedef union _MonoOpcodeParameter {
6193
6259
gint32 i32 ;
6194
6260
gint64 i64 ;
@@ -9900,6 +9966,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
9900
9966
MonoType * ftype ;
9901
9967
MonoInst * store_val = NULL ;
9902
9968
MonoInst * thread_ins ;
9969
+ ins = NULL ;
9903
9970
9904
9971
is_instance = (il_op == MONO_CEE_LDFLD || il_op == MONO_CEE_LDFLDA || il_op == MONO_CEE_STFLD );
9905
9972
if (is_instance ) {
@@ -9927,8 +9994,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
9927
9994
else {
9928
9995
klass = NULL ;
9929
9996
field = mono_field_from_token_checked (image , token , & klass , generic_context , cfg -> error );
9930
- if (!field )
9931
- CHECK_TYPELOAD (klass );
9997
+ if (!field || CLASS_HAS_FAILURE (klass )) {
9998
+ HANDLE_TYPELOAD_ERROR (cfg , klass );
9999
+
10000
+ // Reached only in AOT. Cannot turn a token into a class. We silence the compilation error
10001
+ // and generate a runtime exception.
10002
+ if (cfg -> error -> error_code == MONO_ERROR_BAD_IMAGE )
10003
+ clear_cfg_error (cfg );
10004
+
10005
+ // We need to push a dummy value onto the stack, respecting the intended type.
10006
+ if (il_op == MONO_CEE_LDFLDA || il_op == MONO_CEE_LDSFLDA ) {
10007
+ // Address is expected, push a null pointer.
10008
+ EMIT_NEW_PCONST (cfg , * sp , NULL );
10009
+ sp ++ ;
10010
+ } else if (il_op == MONO_CEE_LDFLD || il_op == MONO_CEE_LDSFLD ) {
10011
+ // An object is expected here. It may be impossible to correctly infer its type,
10012
+ // we turn this entire method into a throw.
10013
+ method_make_alwaysthrow_typeloadfailure (cfg , klass );
10014
+ goto all_bbs_done ;
10015
+ }
10016
+
10017
+ break ;
10018
+ }
9932
10019
CHECK_CFG_ERROR ;
9933
10020
}
9934
10021
if (!dont_verify && !cfg -> skip_visibility && !mono_method_can_access_field (method , field ))
@@ -10394,8 +10481,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
10394
10481
}
10395
10482
10396
10483
if (!is_const ) {
10397
- MonoInst * load ;
10484
+ // This can happen in case of type load error.
10485
+ if (!ins )
10486
+ EMIT_NEW_PCONST (cfg , ins , 0 );
10398
10487
10488
+ MonoInst * load ;
10399
10489
EMIT_NEW_LOAD_MEMBASE_TYPE (cfg , load , field -> type , ins -> dreg , 0 );
10400
10490
load -> flags |= ins_flag ;
10401
10491
* sp ++ = load ;
@@ -11882,13 +11972,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
11882
11972
inline_costs += 100000 ;
11883
11973
break ;
11884
11974
case MONO_CEE_INITOBJ :
11885
- -- sp ;
11886
11975
klass = mini_get_class (method , token , generic_context );
11887
- CHECK_TYPELOAD (klass );
11976
+ if (CLASS_HAS_FAILURE (klass )) {
11977
+ HANDLE_TYPELOAD_ERROR (cfg , klass );
11978
+ inline_costs += 10 ;
11979
+ break ; // reached only in AOT
11980
+ }
11981
+
11982
+ -- sp ;
11983
+
11888
11984
if (mini_class_is_reference (klass ))
11889
11985
MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg , OP_STORE_MEMBASE_IMM , sp [0 ]-> dreg , 0 , 0 );
11890
11986
else
11891
11987
mini_emit_initobj (cfg , * sp , NULL , klass );
11988
+
11892
11989
inline_costs += 1 ;
11893
11990
break ;
11894
11991
case MONO_CEE_CONSTRAINED_ :
@@ -11978,7 +12075,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
11978
12075
EMIT_NEW_ICONST (cfg , ins , val );
11979
12076
} else {
11980
12077
klass = mini_get_class (method , token , generic_context );
11981
- CHECK_TYPELOAD (klass );
12078
+ if (CLASS_HAS_FAILURE (klass )) {
12079
+ HANDLE_TYPELOAD_ERROR (cfg , klass );
12080
+ EMIT_NEW_ICONST (cfg , ins , 0 );
12081
+ * sp ++ = ins ;
12082
+ break ;
12083
+ }
11982
12084
11983
12085
if (mini_is_gsharedvt_klass (klass )) {
11984
12086
ins = mini_emit_get_gsharedvt_info_klass (cfg , klass , MONO_RGCTX_INFO_CLASS_SIZEOF );
@@ -12031,6 +12133,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
12031
12133
}
12032
12134
if (start_new_bblock != 1 )
12033
12135
UNVERIFIED ;
12136
+ all_bbs_done :
12034
12137
12035
12138
cfg -> cbb -> cil_length = GPTRDIFF_TO_INT32 (ip - cfg -> cbb -> cil_code );
12036
12139
if (cfg -> cbb -> next_bb ) {
0 commit comments