@@ -386,6 +386,27 @@ var_types Compiler::impImportCall(OPCODE opcode,
386386 {
387387 assert (!(mflags & CORINFO_FLG_STATIC)); // can't call a static method
388388 assert (!(clsFlags & CORINFO_FLG_VALUECLASS));
389+ assert (stackState.esStackDepth >= sig->numArgs + 1 );
390+
391+ const bool needsFatPointerHandling =
392+ (sig->sigInst .methInstCount != 0 ) && IsTargetAbi (CORINFO_NATIVEAOT_ABI);
393+ if (needsFatPointerHandling)
394+ {
395+ // NativeAOT generic virtual method: need to handle potential fat function pointers
396+ // Spill any side-effecting arguments before we do the LDVIRTFTN
397+ for (unsigned argIndex = 0 ; argIndex < sig->numArgs ; argIndex++)
398+ {
399+ const unsigned level = stackState.esStackDepth - 1 - argIndex;
400+ GenTree* argTree = stackState.esStack [level].val ;
401+ if ((argTree->gtFlags & GTF_SIDE_EFFECT) == 0 )
402+ {
403+ continue ;
404+ }
405+
406+ impSpillStackEntry (level, BAD_VAR_NUM DEBUGARG (false ) DEBUGARG (" fat pointer arg spill" ));
407+ }
408+ }
409+
389410 // OK, We've been told to call via LDVIRTFTN, so just
390411 // take the call now....
391412 call = gtNewIndCallNode (nullptr , callRetTyp, di);
@@ -421,9 +442,11 @@ var_types Compiler::impImportCall(OPCODE opcode,
421442 call->AsCall ()->gtCallAddr = fptr;
422443 call->gtFlags |= GTF_EXCEPT | (fptr->gtFlags & GTF_GLOB_EFFECT);
423444
424- if ((sig-> sigInst . methInstCount != 0 ) && IsTargetAbi (CORINFO_NATIVEAOT_ABI) )
445+ if (needsFatPointerHandling )
425446 {
426- // NativeAOT generic virtual method: need to handle potential fat function pointers
447+ const unsigned fptrLclNum = lvaGrabTemp (true DEBUGARG (" fat pointer temp" ));
448+ impStoreToTemp (fptrLclNum, fptr, CHECK_SPILL_ALL);
449+ call->AsCall ()->gtCallAddr = gtNewLclvNode (fptrLclNum, genActualType (fptr->TypeGet ()));
427450 addFatPointerCandidate (call->AsCall ());
428451 }
429452#ifdef FEATURE_READYTORUN
@@ -6943,17 +6966,6 @@ void Compiler::addFatPointerCandidate(GenTreeCall* call)
69436966{
69446967 JITDUMP (" Marking call [%06u] as fat pointer candidate\n " , dspTreeID (call));
69456968
6946- GenTree* fptr = call->gtCallAddr ;
6947- assert (fptr != nullptr );
6948- if (!fptr->OperIsLocalRead ())
6949- {
6950- // Spill the call address to a local for fat pointer handling
6951- const unsigned fptrLclNum = lvaGrabTemp (true DEBUGARG (" fat pointer temp" ));
6952- impStoreToTemp (fptrLclNum, fptr, CHECK_SPILL_ALL);
6953- fptr = gtNewLclvNode (fptrLclNum, genActualType (fptr->TypeGet ()));
6954- call->gtCallAddr = fptr;
6955- }
6956-
69576969 setMethodHasFatPointer ();
69586970 call->SetFatPointerCandidate ();
69596971 SpillRetExprHelper helper (this );
0 commit comments