@@ -11873,35 +11873,151 @@ void Compiler::impImportBlockCode(BasicBlock* block)
11873
11873
11874
11874
// OSR is not yet supported for methods with explicit tail calls.
11875
11875
//
11876
- // But we also do not have to switch these methods to be optimized as we should be
11876
+ // But we also do not have to switch these methods to be optimized, as we should be
11877
11877
// able to avoid getting trapped in Tier0 code by normal call counting.
11878
11878
// So instead, just suppress adding patchpoints.
11879
11879
//
11880
11880
if (!compTailPrefixSeen)
11881
11881
{
11882
- // The normaly policy is only to add patchpoints to the targets of lexically
11883
- // backwards branches.
11882
+ // We only need to add patchpoints if the method can loop.
11884
11883
//
11885
11884
if (compHasBackwardJump)
11886
11885
{
11887
11886
assert(compCanHavePatchpoints());
11888
11887
11889
- // Is the start of this block a suitable patchpoint?
11888
+ // By default we use the "adaptive" strategy.
11890
11889
//
11891
- if (((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) != 0) && (verCurrentState.esStackDepth == 0))
11890
+ // This can create both source and target patchpoints within a given
11891
+ // loop structure, which isn't ideal, but is not incorrect. We will
11892
+ // just have some extra Tier0 overhead.
11893
+ //
11894
+ // Todo: implement support for mid-block patchpoints. If `block`
11895
+ // is truly a backedge source (and not in a handler) then we should be
11896
+ // able to find a stack empty point somewhere in the block.
11897
+ //
11898
+ const int patchpointStrategy = JitConfig.TC_PatchpointStrategy();
11899
+ bool addPatchpoint = false;
11900
+ bool mustUseTargetPatchpoint = false;
11901
+
11902
+ switch (patchpointStrategy)
11892
11903
{
11893
- // We should have noted this earlier and bailed out of OSR.
11894
- //
11895
- assert(!block->hasHndIndex());
11904
+ default:
11905
+ {
11906
+ // Patchpoints at backedge sources, if possible, otherwise targets.
11907
+ //
11908
+ addPatchpoint = ((block->bbFlags & BBF_BACKWARD_JUMP_SOURCE) == BBF_BACKWARD_JUMP_SOURCE);
11909
+ mustUseTargetPatchpoint = (verCurrentState.esStackDepth != 0) || block->hasHndIndex();
11910
+ break;
11911
+ }
11912
+
11913
+ case 1:
11914
+ {
11915
+ // Patchpoints at stackempty backedge targets.
11916
+ // Note if we have loops where the IL stack is not empty on the backedge we can't patchpoint
11917
+ // them.
11918
+ //
11919
+ // We should not have allowed OSR if there were backedges in handlers.
11920
+ //
11921
+ assert(!block->hasHndIndex());
11922
+ addPatchpoint = ((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) == BBF_BACKWARD_JUMP_TARGET) &&
11923
+ (verCurrentState.esStackDepth == 0);
11924
+ break;
11925
+ }
11926
+
11927
+ case 2:
11928
+ {
11929
+ // Adaptive strategy.
11930
+ //
11931
+ // Patchpoints at backedge targets if there are multiple backedges,
11932
+ // otherwise at backedge sources, if possible. Note a block can be both; if so we
11933
+ // just need one patchpoint.
11934
+ //
11935
+ if ((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) == BBF_BACKWARD_JUMP_TARGET)
11936
+ {
11937
+ // We don't know backedge count, so just use ref count.
11938
+ //
11939
+ addPatchpoint = (block->bbRefs > 1) && (verCurrentState.esStackDepth == 0);
11940
+ }
11941
+
11942
+ if (!addPatchpoint && ((block->bbFlags & BBF_BACKWARD_JUMP_SOURCE) == BBF_BACKWARD_JUMP_SOURCE))
11943
+ {
11944
+ addPatchpoint = true;
11945
+ mustUseTargetPatchpoint = (verCurrentState.esStackDepth != 0) || block->hasHndIndex();
11946
+
11947
+ // Also force target patchpoint if target block has multiple (backedge) preds.
11948
+ //
11949
+ if (!mustUseTargetPatchpoint)
11950
+ {
11951
+ for (BasicBlock* const succBlock : block->Succs(this))
11952
+ {
11953
+ if ((succBlock->bbNum <= block->bbNum) && (succBlock->bbRefs > 1))
11954
+ {
11955
+ mustUseTargetPatchpoint = true;
11956
+ break;
11957
+ }
11958
+ }
11959
+ }
11960
+ }
11961
+ break;
11962
+ }
11963
+ }
11964
+
11965
+ if (addPatchpoint)
11966
+ {
11967
+ if (mustUseTargetPatchpoint)
11968
+ {
11969
+ // We wanted a source patchpoint, but could not have one.
11970
+ // So, add patchpoints to the backedge targets.
11971
+ //
11972
+ for (BasicBlock* const succBlock : block->Succs(this))
11973
+ {
11974
+ if (succBlock->bbNum <= block->bbNum)
11975
+ {
11976
+ // The succBlock had better agree it's a target.
11977
+ //
11978
+ assert((succBlock->bbFlags & BBF_BACKWARD_JUMP_TARGET) == BBF_BACKWARD_JUMP_TARGET);
11979
+
11980
+ // We may already have decided to put a patchpoint in succBlock. If not, add one.
11981
+ //
11982
+ if ((succBlock->bbFlags & BBF_PATCHPOINT) != 0)
11983
+ {
11984
+ // In some cases the target may not be stack-empty at entry.
11985
+ // If so, we will bypass patchpoints for this backedge.
11986
+ //
11987
+ if (succBlock->bbStackDepthOnEntry() > 0)
11988
+ {
11989
+ JITDUMP("\nCan't set source patchpoint at " FMT_BB ", can't use target " FMT_BB
11990
+ " as it has non-empty stack on entry.\n",
11991
+ block->bbNum, succBlock->bbNum);
11992
+ }
11993
+ else
11994
+ {
11995
+ JITDUMP("\nCan't set source patchpoint at " FMT_BB ", using target " FMT_BB
11996
+ " instead\n",
11997
+ block->bbNum, succBlock->bbNum);
11998
+
11999
+ assert(!succBlock->hasHndIndex());
12000
+ succBlock->bbFlags |= BBF_PATCHPOINT;
12001
+ }
12002
+ }
12003
+ }
12004
+ }
12005
+ }
12006
+ else
12007
+ {
12008
+ assert(!block->hasHndIndex());
12009
+ block->bbFlags |= BBF_PATCHPOINT;
12010
+ }
11896
12011
11897
- block->bbFlags |= BBF_PATCHPOINT;
11898
12012
setMethodHasPatchpoint();
11899
12013
}
11900
12014
}
11901
12015
else
11902
12016
{
11903
- // Should not see backward branch targets w/o backwards branches
11904
- assert((block->bbFlags & BBF_BACKWARD_JUMP_TARGET) == 0);
12017
+ // Should not see backward branch targets w/o backwards branches.
12018
+ // So if !compHasBackwardsBranch, these flags should never be set.
12019
+ //
12020
+ assert((block->bbFlags & (BBF_BACKWARD_JUMP_TARGET | BBF_BACKWARD_JUMP_SOURCE)) == 0);
11905
12021
}
11906
12022
}
11907
12023
0 commit comments