use of org.graalvm.compiler.nodes.ProfileData.ProfileSource in project graal by oracle.
the class BytecodeParser method genSwitch.
private void genSwitch(BytecodeSwitch bs) {
int bci = bci();
ValueNode value = frameState.pop(JavaKind.Int);
int nofCases = bs.numberOfCases();
int nofCasesPlusDefault = nofCases + 1;
double[] keyProbabilities = switchProbability(nofCasesPlusDefault, bci);
EconomicMap<Integer, SuccessorInfo> bciToBlockSuccessorIndex = EconomicMap.create(Equivalence.DEFAULT);
for (int i = 0; i < currentBlock.getSuccessorCount(); i++) {
assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci);
bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i));
}
ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
int[] keys = new int[nofCases];
int[] keySuccessors = new int[nofCasesPlusDefault];
int deoptSuccessorIndex = SWITCH_DEOPT_UNSEEN;
int nextSuccessorIndex = 0;
boolean constantValue = value.isConstant();
for (int i = 0; i < nofCasesPlusDefault; i++) {
if (i < nofCases) {
keys[i] = bs.keyAt(i);
}
if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
deoptSuccessorIndex = SWITCH_DEOPT_SEEN;
keySuccessors[i] = SWITCH_DEOPT_SEEN;
} else {
int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget();
SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
if (info.actualIndex < 0) {
info.actualIndex = nextSuccessorIndex++;
actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
}
keySuccessors[i] = info.actualIndex;
}
}
/*
* When the profile indicates a case is never taken, the above code will cause the case to
* deopt should it be subsequently encountered. However, the case may share code with
* another case that is taken according to the profile.
*
* For example:
* // @formatter:off
* switch (opcode) {
* case GOTO:
* case GOTO_W: {
* // emit goto code
* break;
* }
* }
* // @formatter:on
*
* The profile may indicate the GOTO_W case is never taken, and thus a deoptimization stub
* will be emitted. There might be optimization opportunity if additional branching based
* on opcode is within the case block. Specially, if there is only single case that
* reaches a target, we have better chance cutting out unused branches. Otherwise,
* it might be beneficial routing to the same code instead of deopting.
*
* The following code rewires deoptimization stub to existing resolved branch target if
* the target is connected by more than 1 cases.
*
* If this operation rewires every deoptimization seen to an existing branch, care is
* taken that we do not spawn a branch that will never be taken.
*/
if (deoptSuccessorIndex == SWITCH_DEOPT_SEEN) {
int[] connectedCases = new int[nextSuccessorIndex + 1];
for (int i = 0; i < nofCasesPlusDefault; i++) {
connectedCases[keySuccessors[i] + 1]++;
}
for (int i = 0; i < nofCasesPlusDefault; i++) {
if (keySuccessors[i] == SWITCH_DEOPT_SEEN) {
int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget();
SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
int rewiredIndex = info.actualIndex;
if (rewiredIndex >= 0 && connectedCases[rewiredIndex + 1] > 1) {
// Rewire
keySuccessors[i] = info.actualIndex;
} else {
if (deoptSuccessorIndex == SWITCH_DEOPT_SEEN) {
// Spawn deopt successor if needed.
deoptSuccessorIndex = nextSuccessorIndex++;
actualSuccessors.add(null);
}
keySuccessors[i] = deoptSuccessorIndex;
}
}
}
}
ProfileSource profileSource = getSwitchProfileSource(bci);
genIntegerSwitch(value, actualSuccessors, keys, keyProbabilities, keySuccessors, profileSource);
}
Aggregations