@@ -167,7 +167,7 @@ mono_tailcall_print (const char *format, ...)
167167
168168#define TYPE_LOAD_ERROR (klass ) do { \
169169 cfg->exception_ptr = klass; \
170- LOAD_ERROR; \
170+ LOAD_ERROR; \
171171 } while (0)
172172
173173#define CHECK_CFG_ERROR do {\
@@ -2303,6 +2303,18 @@ emit_not_supported_failure (MonoCompile *cfg)
23032303 mono_emit_jit_icall (cfg , mono_throw_not_supported , NULL );
23042304}
23052305
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+
23062318static void
23072319emit_invalid_program_with_msg (MonoCompile * cfg , MonoError * error_msg , MonoMethod * caller , MonoMethod * callee )
23082320{
@@ -4982,6 +4994,15 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
49824994#define CHECK_UNVERIFIABLE (cfg ) if (cfg->unverifiable) UNVERIFIED
49834995#define CHECK_TYPELOAD (klass ) if (!(klass) || mono_class_has_failure (klass)) TYPE_LOAD_ERROR ((klass))
49844996
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+
49855006/* offset from br.s -> br like opcodes */
49865007#define BIG_BRANCH_OFFSET 13
49875008
@@ -5457,7 +5478,9 @@ emit_optimized_ldloca_ir (MonoCompile *cfg, guchar *ip, guchar *end, int local)
54575478 if ((ip = il_read_initobj (ip , end , & token )) && ip_in_bb (cfg , cfg -> cbb , start + 1 )) {
54585479 /* From the INITOBJ case */
54595480 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+ }
54615484 type = mini_get_underlying_type (m_class_get_byval_arg (klass ));
54625485 emit_init_local (cfg , local , type , TRUE);
54635486 return ip ;
@@ -6189,6 +6212,49 @@ emit_llvmonly_interp_entry (MonoCompile *cfg, MonoMethodHeader *header)
61896212 link_bblock (cfg , cfg -> cbb , cfg -> bb_exit );
61906213}
61916214
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+
61926258typedef union _MonoOpcodeParameter {
61936259 gint32 i32 ;
61946260 gint64 i64 ;
@@ -9900,6 +9966,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
99009966 MonoType * ftype ;
99019967 MonoInst * store_val = NULL ;
99029968 MonoInst * thread_ins ;
9969+ ins = NULL ;
99039970
99049971 is_instance = (il_op == MONO_CEE_LDFLD || il_op == MONO_CEE_LDFLDA || il_op == MONO_CEE_STFLD );
99059972 if (is_instance ) {
@@ -9927,8 +9994,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
99279994 else {
99289995 klass = NULL ;
99299996 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+ }
993210019 CHECK_CFG_ERROR ;
993310020 }
993410021 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
1039410481 }
1039510482
1039610483 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 );
1039810487
10488+ MonoInst * load ;
1039910489 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg , load , field -> type , ins -> dreg , 0 );
1040010490 load -> flags |= ins_flag ;
1040110491 * sp ++ = load ;
@@ -11882,13 +11972,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
1188211972 inline_costs += 100000 ;
1188311973 break ;
1188411974 case MONO_CEE_INITOBJ :
11885- -- sp ;
1188611975 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+
1188811984 if (mini_class_is_reference (klass ))
1188911985 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg , OP_STORE_MEMBASE_IMM , sp [0 ]-> dreg , 0 , 0 );
1189011986 else
1189111987 mini_emit_initobj (cfg , * sp , NULL , klass );
11988+
1189211989 inline_costs += 1 ;
1189311990 break ;
1189411991 case MONO_CEE_CONSTRAINED_ :
@@ -11978,7 +12075,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
1197812075 EMIT_NEW_ICONST (cfg , ins , val );
1197912076 } else {
1198012077 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+ }
1198212084
1198312085 if (mini_is_gsharedvt_klass (klass )) {
1198412086 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
1203112133 }
1203212134 if (start_new_bblock != 1 )
1203312135 UNVERIFIED ;
12136+ all_bbs_done :
1203412137
1203512138 cfg -> cbb -> cil_length = GPTRDIFF_TO_INT32 (ip - cfg -> cbb -> cil_code );
1203612139 if (cfg -> cbb -> next_bb ) {
0 commit comments