@@ -3739,12 +3739,15 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
37393739 * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
37403740 */
37413741
3742- args [0 ] = sp [0 ];
3742+ if (fsig -> hasthis )
3743+ args [0 ] = sp [0 ];
3744+ else
3745+ EMIT_NEW_PCONST (cfg , args [0 ], NULL );
37433746 args [1 ] = emit_get_rgctx_method (cfg , mono_method_check_context_used (cmethod ), cmethod , MONO_RGCTX_INFO_METHOD );
37443747 args [2 ] = mini_emit_get_rgctx_klass (cfg , mono_class_check_context_used (constrained_class ), constrained_class , MONO_RGCTX_INFO_KLASS );
37453748
3746- /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
3747- if (fsig -> hasthis && fsig -> param_count ) {
3749+ /* !fsig->hasthis is for the wrapper for the Object.GetType () icall or static virtual methods */
3750+ if (( fsig -> hasthis || m_method_is_static ( cmethod )) && fsig -> param_count ) {
37483751 /* Call mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean *deref_args, gpointer *args) */
37493752 gboolean has_gsharedvt = FALSE;
37503753 for (int i = 0 ; i < fsig -> param_count ; ++ i ) {
@@ -3783,12 +3786,14 @@ handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMe
37833786 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg , OP_STOREI1_MEMBASE_IMM , args [3 ]-> dreg , i , 0 );
37843787 }
37853788
3789+ MonoInst * arg = sp [i + fsig -> hasthis ];
3790+
37863791 if (mini_is_gsharedvt_type (fsig -> params [i ]) || MONO_TYPE_IS_PRIMITIVE (fsig -> params [i ]) || MONO_TYPE_ISSTRUCT (fsig -> params [i ])) {
3787- EMIT_NEW_VARLOADA_VREG (cfg , ins , sp [ i + 1 ] -> dreg , fsig -> params [i ]);
3792+ EMIT_NEW_VARLOADA_VREG (cfg , ins , arg -> dreg , fsig -> params [i ]);
37883793 addr_reg = ins -> dreg ;
37893794 EMIT_NEW_STORE_MEMBASE (cfg , ins , OP_STORE_MEMBASE_REG , args [4 ]-> dreg , i * sizeof (target_mgreg_t ), addr_reg );
37903795 } else {
3791- EMIT_NEW_STORE_MEMBASE (cfg , ins , OP_STORE_MEMBASE_REG , args [4 ]-> dreg , i * sizeof (target_mgreg_t ), sp [ i + 1 ] -> dreg );
3796+ EMIT_NEW_STORE_MEMBASE (cfg , ins , OP_STORE_MEMBASE_REG , args [4 ]-> dreg , i * sizeof (target_mgreg_t ), arg -> dreg );
37923797 }
37933798 }
37943799 } else {
@@ -5726,9 +5731,9 @@ handle_constrained_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat
57265731 }
57275732
57285733 if (m_method_is_static (cmethod )) {
5729- /* Call to an abstract static method */
5734+ /* Call to an abstract static method, handled normally */
57305735 return NULL ;
5731- } if (constrained_partial_call ) {
5736+ } else if (constrained_partial_call ) {
57325737 gboolean need_box = TRUE;
57335738
57345739 /*
@@ -7325,6 +7330,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
73257330 gboolean direct_icall ; direct_icall = FALSE;
73267331 gboolean tailcall_calli ; tailcall_calli = FALSE;
73277332 gboolean noreturn ; noreturn = FALSE;
7333+ gboolean gshared_static_virtual ; gshared_static_virtual = FALSE;
73287334#ifdef TARGET_WASM
73297335 gboolean needs_stack_walk ; needs_stack_walk = FALSE;
73307336#endif
@@ -7357,20 +7363,24 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
73577363
73587364 MonoMethod * cil_method ; cil_method = cmethod ;
73597365 if (constrained_class ) {
7360- if (m_method_is_static (cil_method ) && mini_class_check_context_used (cfg , constrained_class ))
7361- // FIXME:
7362- GENERIC_SHARING_FAILURE (CEE_CALL );
7363-
7364- cmethod = get_constrained_method (cfg , image , token , cil_method , constrained_class , generic_context );
7365- CHECK_CFG_ERROR ;
7366+ if (m_method_is_static (cil_method ) && mini_class_check_context_used (cfg , constrained_class )) {
7367+ /* get_constrained_method () doesn't work on the gparams used by generic sharing */
7368+ // FIXME: Other configurations
7369+ //if (!cfg->gsharedvt)
7370+ // GENERIC_SHARING_FAILURE (CEE_CALL);
7371+ gshared_static_virtual = TRUE;
7372+ } else {
7373+ cmethod = get_constrained_method (cfg , image , token , cil_method , constrained_class , generic_context );
7374+ CHECK_CFG_ERROR ;
73667375
7367- if (m_class_is_enumtype (constrained_class ) && !strcmp (cmethod -> name , "GetHashCode" )) {
7368- /* Use the corresponding method from the base type to avoid boxing */
7369- MonoType * base_type = mono_class_enum_basetype_internal (constrained_class );
7370- g_assert (base_type );
7371- constrained_class = mono_class_from_mono_type_internal (base_type );
7372- cmethod = get_method_nofail (constrained_class , cmethod -> name , 0 , 0 );
7373- g_assert (cmethod );
7376+ if (m_class_is_enumtype (constrained_class ) && !strcmp (cmethod -> name , "GetHashCode" )) {
7377+ /* Use the corresponding method from the base type to avoid boxing */
7378+ MonoType * base_type = mono_class_enum_basetype_internal (constrained_class );
7379+ g_assert (base_type );
7380+ constrained_class = mono_class_from_mono_type_internal (base_type );
7381+ cmethod = get_method_nofail (constrained_class , cmethod -> name , 0 , 0 );
7382+ g_assert (cmethod );
7383+ }
73747384 }
73757385 }
73767386
@@ -7400,7 +7410,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
74007410#endif
74017411 }
74027412
7403- if (!virtual_ && (cmethod -> flags & METHOD_ATTRIBUTE_ABSTRACT )) {
7413+ if (!virtual_ && (cmethod -> flags & METHOD_ATTRIBUTE_ABSTRACT ) && ! gshared_static_virtual ) {
74047414 if (!mono_class_is_interface (method -> klass ))
74057415 emit_bad_image_failure (cfg , method , cil_method );
74067416 else
@@ -7510,7 +7520,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
75107520 if (constrained_class ) {
75117521 ins = handle_constrained_call (cfg , cmethod , fsig , constrained_class , sp , & cdata , & cmethod , & virtual_ , & emit_widen );
75127522 CHECK_CFG_EXCEPTION ;
7513- constrained_class = NULL ;
7523+ if (!gshared_static_virtual )
7524+ constrained_class = NULL ;
75147525 if (ins )
75157526 goto call_end ;
75167527 }
@@ -7935,41 +7946,56 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
79357946 /* Generic sharing */
79367947
79377948 /*
7949+ * Calls to generic methods from shared code cannot go through the trampoline infrastructure
7950+ * in some cases, because the called method might end up being different on every call.
7951+ * Load the called method address from the rgctx and do an indirect call in these cases.
79387952 * Use this if the callee is gsharedvt sharable too, since
79397953 * at runtime we might find an instantiation so the call cannot
79407954 * be patched (the 'no_patch' code path in mini-trampolines.c).
79417955 */
7942- if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
7943- (!mono_method_is_generic_sharable_full (cmethod , TRUE, FALSE, FALSE) ||
7944- !mono_class_generic_sharing_enabled (cmethod -> klass )) &&
7945- (!virtual_ || MONO_METHOD_IS_FINAL (cmethod ) ||
7946- !(cmethod -> flags & METHOD_ATTRIBUTE_VIRTUAL ))) {
7956+ gboolean gshared_indirect ;
7957+ gshared_indirect = context_used && !imt_arg && !array_rank && !delegate_invoke ;
7958+ if (gshared_indirect )
7959+ gshared_indirect = (!mono_method_is_generic_sharable_full (cmethod , TRUE, FALSE, FALSE) ||
7960+ !mono_class_generic_sharing_enabled (cmethod -> klass ) ||
7961+ gshared_static_virtual );
7962+ if (gshared_indirect )
7963+ gshared_indirect = (!virtual_ || MONO_METHOD_IS_FINAL (cmethod ) ||
7964+ !(cmethod -> flags & METHOD_ATTRIBUTE_VIRTUAL ));
7965+ if (gshared_indirect ) {
79477966 INLINE_FAILURE ("gshared" );
79487967
79497968 g_assert (cfg -> gshared && cmethod );
79507969 g_assert (!addr );
79517970
7952- /*
7953- * We are compiling a call to a
7954- * generic method from shared code,
7955- * which means that we have to look up
7956- * the method in the rgctx and do an
7957- * indirect call.
7958- */
79597971 if (fsig -> hasthis )
79607972 MONO_EMIT_NEW_CHECK_THIS (cfg , sp [0 ]-> dreg );
79617973
79627974 if (cfg -> llvm_only ) {
7963- if (cfg -> gsharedvt && mini_is_gsharedvt_variable_signature (fsig ))
7975+ if (cfg -> gsharedvt && mini_is_gsharedvt_variable_signature (fsig )) {
7976+ /* Handled in handle_constrained_gsharedvt_call () */
7977+ g_assert (!gshared_static_virtual );
79647978 addr = emit_get_rgctx_method (cfg , context_used , cmethod , MONO_RGCTX_INFO_GSHAREDVT_OUT_WRAPPER );
7965- else
7966- addr = emit_get_rgctx_method (cfg , context_used , cmethod , MONO_RGCTX_INFO_METHOD_FTNDESC );
7979+ } else {
7980+ if (gshared_static_virtual )
7981+ addr = emit_get_rgctx_virt_method (cfg , mono_class_check_context_used (constrained_class ), constrained_class , cmethod , MONO_RGCTX_INFO_VIRT_METHOD_CODE );
7982+ else
7983+ addr = emit_get_rgctx_method (cfg , context_used , cmethod , MONO_RGCTX_INFO_METHOD_FTNDESC );
7984+ }
79677985 // FIXME: Avoid initializing imt_arg/vtable_arg
79687986 ins = mini_emit_llvmonly_calli (cfg , fsig , sp , addr );
79697987 if (inst_tailcall ) // FIXME
79707988 mono_tailcall_print ("missed tailcall context_used_llvmonly %s -> %s\n" , method -> name , cmethod -> name );
79717989 } else {
7972- addr = emit_get_rgctx_method (cfg , context_used , cmethod , MONO_RGCTX_INFO_GENERIC_METHOD_CODE );
7990+ if (gshared_static_virtual ) {
7991+ /*
7992+ * cmethod is a static interface method, the actual called method at runtime
7993+ * needs to be computed using constrained_class and cmethod.
7994+ */
7995+ addr = emit_get_rgctx_virt_method (cfg , mono_class_check_context_used (constrained_class ), constrained_class , cmethod , MONO_RGCTX_INFO_VIRT_METHOD_CODE );
7996+ } else {
7997+ addr = emit_get_rgctx_method (cfg , context_used , cmethod , MONO_RGCTX_INFO_GENERIC_METHOD_CODE );
7998+ }
79737999 if (inst_tailcall )
79748000 mono_tailcall_print ("%s tailcall_calli#2 %s -> %s\n" , tailcall_calli ? "making" : "missed" , method -> name , cmethod -> name );
79758001 tailcall = tailcall_calli ;
0 commit comments