# HG changeset patch # User Doug Simon # Date 1386795430 -3600 # Node ID d64c0112fb947d950f72552de10bb61039b607ad # Parent 5a3491b0c2f001493d332ac3a592955ed69c3b36# Parent d2165b699e0f9c6eceb9345a8b88a4ef04a4bb3c Merge. diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -55,8 +55,7 @@ import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatCondMoveOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.ReturnOp; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.SequentialSwitchOp; -import com.oracle.graal.lir.amd64.AMD64ControlFlow.SwitchRangesOp; +import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp; import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; @@ -220,6 +219,7 @@ @Override public void emitJump(LabelRef label) { + assert label != null; append(new JumpOp(label)); } @@ -980,20 +980,9 @@ } @Override - protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { - // Making a copy of the switch value is necessary because jump table destroys the input - // value - if (key.getKind() == Kind.Int || key.getKind() == Kind.Long) { - append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL)); - } else { - assert key.getKind() == Kind.Object : key.getKind(); - append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object))); - } - } - - @Override - protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) { - append(new SwitchRangesOp(lowKeys, highKeys, targets, defaultTarget, key)); + protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { + boolean needsTemp = key.getKind() == Kind.Object; + append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL)); } @Override diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java --- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -46,14 +46,13 @@ import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp; import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCondMoveOp; import com.oracle.graal.lir.hsail.HSAILControlFlow.ReturnOp; -import com.oracle.graal.lir.hsail.HSAILControlFlow.SwitchOp; +import com.oracle.graal.lir.hsail.HSAILControlFlow.StrategySwitchOp; import com.oracle.graal.lir.hsail.HSAILMove.LeaOp; import com.oracle.graal.lir.hsail.HSAILMove.MembarOp; import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp; import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.phases.util.*; /** @@ -702,17 +701,10 @@ * * Note: Only IntegerSwitchNodes are currently supported. The IntegerSwitchNode is the node that * Graal generates for any switch construct appearing in Java bytecode. - * - * @param x the SwitchNode */ @Override - public void emitSwitch(SwitchNode x) { - // get the key of the switch. - Variable key = load(operand(x.value())); - // set the default target. - LabelRef defaultTarget = x.defaultSuccessor() == null ? null : getLIRBlock(x.defaultSuccessor()); - // emit a sequential switch for the specified key and default target. - emitSequentialSwitch(x, key, defaultTarget); + protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) { + emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget); } /** @@ -727,19 +719,19 @@ * handling operations related to method dispatch. We haven't yet added support for the * TypeSwitchNode, so for the time being we have added a check to ensure that the keys are of * type int. This also allows us to flag any test cases/execution paths that may trigger the - * creation fo a TypeSwitchNode which we don't support yet. + * creation of a TypeSwitchNode which we don't support yet. * * - * @param keyConstants array of key constants used for the case statements. + * @param strategy the strategy used for this switch. * @param keyTargets array of branch targets for each of the cases. * @param defaultTarget the branch target for the default case. * @param key the key that is compared against the key constants in the case statements. */ @Override - protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { + protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { if (key.getKind() == Kind.Int) { // Append the LIR instruction for generating compare and branch instructions. - append(new SwitchOp(keyConstants, keyTargets, defaultTarget, key)); + append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key)); } else { // Throw an exception if the keys aren't ints. throw GraalInternalError.unimplemented("Switch statements are only supported for keys of type int"); @@ -747,11 +739,6 @@ } @Override - protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) { - throw GraalInternalError.unimplemented(); - } - - @Override protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { throw GraalInternalError.unimplemented(); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -51,7 +51,7 @@ import com.oracle.graal.lir.ptx.PTXControlFlow.FloatCondMoveOp; import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnNoValOp; import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp; -import com.oracle.graal.lir.ptx.PTXControlFlow.SequentialSwitchOp; +import com.oracle.graal.lir.ptx.PTXControlFlow.StrategySwitchOp; import com.oracle.graal.lir.ptx.PTXControlFlow.TableSwitchOp; import com.oracle.graal.lir.ptx.PTXMemOp.LoadOp; import com.oracle.graal.lir.ptx.PTXMemOp.LoadParamOp; @@ -62,6 +62,7 @@ import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.util.*; @@ -269,18 +270,26 @@ } @Override - public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) { + public Variable emitLoad(Kind kind, Value address, Access access) { PTXAddressValue loadAddress = asAddress(address); Variable result = newVariable(kind); - append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null)); + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } + append(new LoadOp(kind, result, loadAddress, state)); return result; } @Override - public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) { + public void emitStore(Kind kind, Value address, Value inputVal, Access access) { PTXAddressValue storeAddress = asAddress(address); Variable input = load(inputVal); - append(new StoreOp(kind, storeAddress, input, deopting != null ? state(deopting) : null)); + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } + append(new StoreOp(kind, storeAddress, input, state)); } @Override @@ -779,20 +788,9 @@ } @Override - protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { - // Making a copy of the switch value is necessary because jump table destroys the input - // value - if (key.getKind() == Kind.Int || key.getKind() == Kind.Long) { - append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL, nextPredRegNum++)); - } else { - assert key.getKind() == Kind.Object : key.getKind(); - append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object), nextPredRegNum++)); - } - } - - @Override - protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) { - throw new InternalError("NYI"); + protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { + boolean needsTemp = key.getKind() == Kind.Object; + append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL, nextPredRegNum++)); } @Override diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java --- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -50,8 +50,7 @@ import com.oracle.graal.lir.sparc.SPARCControlFlow.CondMoveOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.FloatCondMoveOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.ReturnOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.SequentialSwitchOp; -import com.oracle.graal.lir.sparc.SPARCControlFlow.SwitchRangesOp; +import com.oracle.graal.lir.sparc.SPARCControlFlow.StrategySwitchOp; import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp; import com.oracle.graal.lir.sparc.SPARCMove.LoadAddressOp; import com.oracle.graal.lir.sparc.SPARCMove.MembarOp; @@ -359,16 +358,9 @@ } @Override - protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { - // Making a copy of the switch value is necessary because jump table destroys the input - // value - assert key.getKind() == Kind.Int || key.getKind() == Kind.Long || key.getKind() == Kind.Object : key.getKind(); - append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(key.getKind()))); - } - - @Override - protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) { - append(new SwitchRangesOp(lowKeys, highKeys, targets, defaultTarget, key)); + protected void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { + boolean needsTemp = key.getKind() == Kind.Long || key.getKind() == Kind.Object; + append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getKind()) : Value.ILLEGAL)); } @Override diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -28,7 +28,6 @@ import static com.oracle.graal.lir.LIR.*; import static com.oracle.graal.lir.LIRValueUtil.*; import static com.oracle.graal.nodes.ConstantNode.*; -import static com.oracle.graal.phases.GraalOptions.*; import java.util.*; import java.util.Map.Entry; @@ -730,118 +729,66 @@ */ @Override public void emitSwitch(SwitchNode x) { + assert x.defaultSuccessor() != null; + LabelRef defaultTarget = getLIRBlock(x.defaultSuccessor()); int keyCount = x.keyCount(); if (keyCount == 0) { - emitJump(getLIRBlock(x.defaultSuccessor())); + emitJump(defaultTarget); } else { Variable value = load(operand(x.value())); - LabelRef defaultTarget = x.defaultSuccessor() == null ? null : getLIRBlock(x.defaultSuccessor()); - if (value.getKind() != Kind.Int) { - // hopefully only a few entries - emitSequentialSwitch(x, value, defaultTarget); + if (keyCount == 1) { + assert defaultTarget != null; + emitCompareBranch(load(operand(x.value())), x.keyAt(0), Condition.EQ, false, getLIRBlock(x.keySuccessor(0)), defaultTarget); } else { - assert value.getKind() == Kind.Int; - long valueRange = x.keyAt(keyCount - 1).asLong() - x.keyAt(0).asLong() + 1; - int switchRangeCount = switchRangeCount(x); - if (switchRangeCount == 0) { - emitJump(getLIRBlock(x.defaultSuccessor())); - } else if (switchRangeCount >= MinimumJumpTableSize.getValue() && keyCount / (double) valueRange >= MinTableSwitchDensity.getValue()) { - int minValue = x.keyAt(0).asInt(); - assert valueRange < Integer.MAX_VALUE; - LabelRef[] targets = new LabelRef[(int) valueRange]; - for (int i = 0; i < valueRange; i++) { - targets[i] = defaultTarget; - } - for (int i = 0; i < keyCount; i++) { - targets[x.keyAt(i).asInt() - minValue] = getLIRBlock(x.keySuccessor(i)); - } - emitTableSwitch(minValue, defaultTarget, targets, value); - } else if (keyCount / switchRangeCount >= RangeTestsSwitchDensity.getValue()) { - emitSwitchRanges(x, switchRangeCount, value, defaultTarget); + LabelRef[] keyTargets = new LabelRef[keyCount]; + Constant[] keyConstants = new Constant[keyCount]; + double[] keyProbabilities = new double[keyCount]; + for (int i = 0; i < keyCount; i++) { + keyTargets[i] = getLIRBlock(x.keySuccessor(i)); + keyConstants[i] = x.keyAt(i); + keyProbabilities[i] = x.keyProbability(i); + } + if (value.getKind() != Kind.Int || !x.isSorted()) { + // hopefully only a few entries + emitStrategySwitch(new SwitchStrategy.SequentialStrategy(keyProbabilities, keyConstants), value, keyTargets, defaultTarget); } else { - emitSequentialSwitch(x, value, defaultTarget); + emitStrategySwitch(keyConstants, keyProbabilities, keyTargets, defaultTarget, value); } } } } - protected void emitSequentialSwitch(final SwitchNode x, Variable key, LabelRef defaultTarget) { - int keyCount = x.keyCount(); - Integer[] indexes = Util.createSortedPermutation(keyCount, new Comparator() { - - @Override - public int compare(Integer o1, Integer o2) { - return x.keyProbability(o1) < x.keyProbability(o2) ? 1 : x.keyProbability(o1) > x.keyProbability(o2) ? -1 : 0; + protected void emitStrategySwitch(Constant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) { + int keyCount = keyConstants.length; + SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets); + long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1; + double tableSwitchDensity = keyCount / (double) valueRange; + /* + * This heuristic tries to find a compromise between the effort for the best switch strategy + * and the density of a tableswitch. If the effort for the strategy is at least 4, then a + * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers + * gradually with additional effort. + */ + if (strategy.getAverageEffort() < 4 || tableSwitchDensity < (1 / Math.sqrt(strategy.getAverageEffort()))) { + emitStrategySwitch(strategy, value, keyTargets, defaultTarget); + } else { + int minValue = keyConstants[0].asInt(); + assert valueRange < Integer.MAX_VALUE; + LabelRef[] targets = new LabelRef[(int) valueRange]; + for (int i = 0; i < valueRange; i++) { + targets[i] = defaultTarget; } - }); - LabelRef[] keyTargets = new LabelRef[keyCount]; - Constant[] keyConstants = new Constant[keyCount]; - for (int i = 0; i < keyCount; i++) { - keyTargets[i] = getLIRBlock(x.keySuccessor(indexes[i])); - keyConstants[i] = x.keyAt(indexes[i]); + for (int i = 0; i < keyCount; i++) { + targets[keyConstants[i].asInt() - minValue] = keyTargets[i]; + } + emitTableSwitch(minValue, defaultTarget, targets, value); } - emitSequentialSwitch(keyConstants, keyTargets, defaultTarget, key); } - protected abstract void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key); - - protected abstract void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key); + protected abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget); protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key); - private static int switchRangeCount(SwitchNode x) { - int keyCount = x.keyCount(); - int switchRangeCount = 0; - int defaultSux = x.defaultSuccessorIndex(); - - int key = x.keyAt(0).asInt(); - int sux = x.keySuccessorIndex(0); - for (int i = 0; i < keyCount; i++) { - int newKey = x.keyAt(i).asInt(); - int newSux = x.keySuccessorIndex(i); - if (newSux != defaultSux && (newKey != key + 1 || sux != newSux)) { - switchRangeCount++; - } - key = newKey; - sux = newSux; - } - return switchRangeCount; - } - - private void emitSwitchRanges(SwitchNode x, int switchRangeCount, Variable keyValue, LabelRef defaultTarget) { - assert switchRangeCount >= 1 : "switch ranges should not be used for emitting only the default case"; - - int[] lowKeys = new int[switchRangeCount]; - int[] highKeys = new int[switchRangeCount]; - LabelRef[] targets = new LabelRef[switchRangeCount]; - - int keyCount = x.keyCount(); - int defaultSuccessor = x.defaultSuccessorIndex(); - - int current = -1; - int key = -1; - int successor = -1; - for (int i = 0; i < keyCount; i++) { - int newSuccessor = x.keySuccessorIndex(i); - int newKey = x.keyAt(i).asInt(); - if (newSuccessor != defaultSuccessor) { - if (key + 1 == newKey && successor == newSuccessor) { - // still in same range - highKeys[current] = newKey; - } else { - current++; - lowKeys[current] = newKey; - highKeys[current] = newKey; - targets[current] = getLIRBlock(x.blockSuccessor(newSuccessor)); - } - } - key = newKey; - successor = newSuccessor; - } - assert current == switchRangeCount - 1; - emitSwitchRanges(lowKeys, highKeys, targets, defaultTarget, keyValue); - } - public FrameMap frameMap() { return frameMap; } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -59,6 +59,7 @@ import com.oracle.graal.lir.amd64.AMD64Move.StoreOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; @@ -446,15 +447,18 @@ /** * Returns whether or not the input access is a (de)compression candidate. */ - private static boolean isCompressCandidate(DeoptimizingNode access) { - return access != null && ((HeapAccess) access).isCompressible(); + private static boolean isCompressCandidate(Access access) { + return access != null && access.isCompressible(); } @Override - public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) { + public Variable emitLoad(Kind kind, Value address, Access access) { AMD64AddressValue loadAddress = asAddressValue(address); Variable result = newVariable(kind); - assert access == null || access instanceof HeapAccess; + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } /** * Currently, the (de)compression of pointers applies conditionally to some objects (oops, * kind==Object) and some addresses (klass pointers, kind==Long). Initially, the input @@ -467,24 +471,27 @@ */ if (isCompressCandidate(access)) { if (config.useCompressedOops && kind == Kind.Object) { - append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, access != null ? state(access) : null, getNarrowKlassBase(), - getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment())); + append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, state, getNarrowKlassBase(), getNarrowOopBase(), + getNarrowOopShift(), getLogMinObjectAlignment())); } else if (config.useCompressedClassPointers && kind == Kind.Long) { - append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, access != null ? state(access) : null, getNarrowKlassBase(), - getNarrowOopBase(), getNarrowKlassShift(), getLogKlassAlignment())); + append(new LoadCompressedPointer(kind, result, getProviders().getRegisters().getHeapBaseRegister().asValue(), loadAddress, state, getNarrowKlassBase(), getNarrowOopBase(), + getNarrowKlassShift(), getLogKlassAlignment())); } else { - append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null)); + append(new LoadOp(kind, result, loadAddress, state)); } } else { - append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null)); + append(new LoadOp(kind, result, loadAddress, state)); } return result; } @Override - public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) { + public void emitStore(Kind kind, Value address, Value inputVal, Access access) { AMD64AddressValue storeAddress = asAddressValue(address); - LIRFrameState state = access != null ? state(access) : null; + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } if (isConstant(inputVal)) { Constant c = asConstant(inputVal); if (canStoreConstant(c)) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotLIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -35,6 +35,7 @@ import com.oracle.graal.lir.hsail.HSAILMove.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.util.*; @@ -74,8 +75,8 @@ return config.narrowKlassBase; } - private static boolean isCompressCandidate(DeoptimizingNode access) { - return access != null && ((HeapAccess) access).isCompressible(); + private static boolean isCompressCandidate(Access access) { + return access != null && access.isCompressible(); } /** @@ -114,11 +115,13 @@ } @Override - public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) { + public Variable emitLoad(Kind kind, Value address, Access access) { HSAILAddressValue loadAddress = asAddressValue(address); Variable result = newVariable(kind); - LIRFrameState state = access != null ? state(access) : null; - assert access == null || access instanceof HeapAccess; + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) { Variable scratch = newVariable(Kind.Long); append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, getNarrowOopBase(), getNarrowOopShift(), getLogMinObjectAlignment())); @@ -132,9 +135,12 @@ } @Override - public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) { + public void emitStore(Kind kind, Value address, Value inputVal, Access access) { HSAILAddressValue storeAddress = asAddressValue(address); - LIRFrameState state = access != null ? state(access) : null; + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } Variable input = load(inputVal); if (isCompressCandidate(access) && config.useCompressedOops && kind == Kind.Object) { Variable scratch = newVariable(Kind.Long); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -45,6 +45,7 @@ import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp; import com.oracle.graal.lir.sparc.SPARCMove.StoreOp; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator { @@ -231,15 +232,18 @@ append(op); } - private static boolean isCompressCandidate(DeoptimizingNode access) { - return access != null && ((HeapAccess) access).isCompressible(); + private static boolean isCompressCandidate(Access access) { + return access != null && access.isCompressible(); } @Override - public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) { + public Variable emitLoad(Kind kind, Value address, Access access) { SPARCAddressValue loadAddress = asAddressValue(address); Variable result = newVariable(kind); - assert access == null || access instanceof HeapAccess; + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } if (isCompressCandidate(access)) { if (config.useCompressedOops && kind == Kind.Object) { // append(new LoadCompressedPointer(kind, result, loadAddress, access != null ? @@ -254,18 +258,21 @@ // config.logKlassAlignment)); throw GraalInternalError.unimplemented(); } else { - append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null)); + append(new LoadOp(kind, result, loadAddress, state)); } } else { - append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null)); + append(new LoadOp(kind, result, loadAddress, state)); } return result; } @Override - public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) { + public void emitStore(Kind kind, Value address, Value inputVal, Access access) { SPARCAddressValue storeAddress = asAddressValue(address); - LIRFrameState state = access != null ? state(access) : null; + LIRFrameState state = null; + if (access instanceof DeoptimizingNode) { + state = state((DeoptimizingNode) access); + } if (isConstant(inputVal)) { Constant c = asConstant(inputVal); if (canStoreConstant(c)) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Wed Dec 11 21:57:10 2013 +0100 @@ -197,7 +197,7 @@ HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedObjectType klass); - HotSpotResolvedJavaMethod[] getMethods(HotSpotResolvedObjectType klass); + long getClassInitializer(HotSpotResolvedObjectType klass); boolean hasFinalizableSubclass(HotSpotResolvedObjectType klass); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Wed Dec 11 21:57:10 2013 +0100 @@ -98,7 +98,7 @@ public native HotSpotResolvedJavaField[] getInstanceFields(HotSpotResolvedObjectType klass); @Override - public native HotSpotResolvedJavaMethod[] getMethods(HotSpotResolvedObjectType klass); + public native long getClassInitializer(HotSpotResolvedObjectType klass); @Override public native int getCompiledCodeSize(long metaspaceMethod); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Wed Dec 11 21:57:10 2013 +0100 @@ -65,6 +65,9 @@ @Option(help = "Print compilation queue activity periodically") private static final OptionValue PrintQueue = new OptionValue<>(false); + @Option(help = "Print bootstrap progress and summary") + private static final OptionValue PrintBootstrap = new OptionValue<>(true); + @Option(help = "Time limit in milliseconds for bootstrap (-1 for no limit)") private static final OptionValue TimedBootstrap = new OptionValue<>(-1); @@ -226,8 +229,11 @@ } public void bootstrap() throws Throwable { - TTY.print("Bootstrapping Graal"); - TTY.flush(); + if (PrintBootstrap.getValue()) { + TTY.print("Bootstrapping Graal"); + TTY.flush(); + } + long startTime = System.currentTimeMillis(); boolean firstRun = true; @@ -261,8 +267,10 @@ Thread.sleep(100); while (z < compileQueue.getCompletedTaskCount() / 100) { ++z; - TTY.print("."); - TTY.flush(); + if (PrintBootstrap.getValue()) { + TTY.print("."); + TTY.flush(); + } } // Are we out of time? @@ -283,7 +291,10 @@ bootstrapRunning = false; - TTY.println(" in %d ms (compiled %d methods)", System.currentTimeMillis() - startTime, compileQueue.getCompletedTaskCount()); + if (PrintBootstrap.getValue()) { + TTY.println(" in %d ms (compiled %d methods)", System.currentTimeMillis() - startTime, compileQueue.getCompletedTaskCount()); + } + if (runtime.getGraphCache() != null) { runtime.getGraphCache().clear(); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Wed Dec 11 21:57:10 2013 +0100 @@ -106,7 +106,7 @@ ValueNode array = arrayLengthNode.array(); ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(), BarrierType.NONE, false)); - tool.createNullCheckGuard(arrayLengthRead, array); + tool.createNullCheckGuard(arrayLengthNode, arrayLengthRead, array); graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead); } else if (n instanceof Invoke) { Invoke invoke = (Invoke) n; @@ -117,7 +117,7 @@ ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); GuardingNode receiverNullCheck = null; if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !ObjectStamp.isObjectNonNull(receiver)) { - receiverNullCheck = tool.createNullCheckGuard(invoke, receiver); + receiverNullCheck = tool.createNullCheckGuard(invoke.asNode(), invoke, receiver); } JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); @@ -161,7 +161,7 @@ BarrierType barrierType = getFieldLoadBarrierType(field); ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object))); graph.replaceFixedWithFixed(loadField, memoryRead); - tool.createNullCheckGuard(memoryRead, object); + tool.createNullCheckGuard(memoryRead, memoryRead, object); if (loadField.isVolatile()) { MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ)); @@ -175,9 +175,9 @@ ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), metaAccess, graph) : storeField.object(); BarrierType barrierType = getFieldStoreBarrierType(storeField); WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object)); - tool.createNullCheckGuard(memoryWrite, object); memoryWrite.setStateAfter(storeField.stateAfter()); graph.replaceFixedWithFixed(storeField, memoryWrite); + tool.createNullCheckGuard(memoryWrite, memoryWrite, object); FixedWithNextNode last = memoryWrite; FixedWithNextNode first = memoryWrite; @@ -197,11 +197,10 @@ graph.replaceFixedWithFixed(cas, atomicNode); } else if (n instanceof LoadIndexedNode) { LoadIndexedNode loadIndexed = (LoadIndexedNode) n; - GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool); Kind elementKind = loadIndexed.elementKind(); LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false); ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object)); - memoryRead.setGuard(boundsCheck); + memoryRead.setGuard(createBoundsCheck(loadIndexed, tool)); graph.replaceFixedWithFixed(loadIndexed, memoryRead); } else if (n instanceof StoreIndexedNode) { StoreIndexedNode storeIndexed = (StoreIndexedNode) n; @@ -719,11 +718,11 @@ Stamp stamp = StampFactory.positiveInt(); ReadNode readArrayLength = g.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, runtime.getConfig().arrayLengthOffset, g), stamp, BarrierType.NONE, false)); g.addBeforeFixed(n, readArrayLength); - tool.createNullCheckGuard(readArrayLength, array); + tool.createNullCheckGuard(readArrayLength, readArrayLength, array); arrayLength = readArrayLength; } - return tool.createGuard(g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); + return tool.createGuard(n, g.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile); } } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java Wed Dec 11 21:57:10 2013 +0100 @@ -596,11 +596,9 @@ } public ResolvedJavaMethod getClassInitializer() { - ResolvedJavaMethod[] methods = runtime().getCompilerToVM().getMethods(this); - for (ResolvedJavaMethod m : methods) { - if (m.isClassInitializer()) { - return m; - } + long metaspaceMethod = runtime().getCompilerToVM().getClassInitializer(this); + if (metaspaceMethod != 0L) { + return createMethod(metaspaceMethod); } return null; } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -66,7 +66,7 @@ } } - protected static void addG1PreWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean doLoad, boolean nullCheck, StructuredGraph graph) { + protected static void addG1PreWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean doLoad, boolean nullCheck, StructuredGraph graph) { G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(object, value, location, doLoad, nullCheck)); preBarrier.setDeoptimizationState(node.getDeoptimizationState()); node.setNullCheck(false); @@ -74,12 +74,12 @@ graph.addBeforeFixed(node, preBarrier); } - protected void addG1PostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) { + protected void addG1PostWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) { final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value); graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(object, value, location, precise, alwaysNull))); } - protected void addSerialPostWriteBarrier(AccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) { + protected void addSerialPostWriteBarrier(FixedAccessNode node, ValueNode object, ValueNode value, LocationNode location, boolean precise, StructuredGraph graph) { final boolean alwaysNull = ObjectStamp.isObjectAlwaysNull(value); final LocationNode loc = (precise ? location : null); graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(object, loc, precise, alwaysNull))); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -73,12 +73,12 @@ Node currentNode = iterator.next(); assert !isSafepoint(currentNode) : "Write barrier must be present " + write; if (useG1GC()) { - if (!(currentNode instanceof G1PostWriteBarrier) || ((currentNode instanceof G1PostWriteBarrier) && !validateBarrier((AccessNode) write, (WriteBarrier) currentNode))) { + if (!(currentNode instanceof G1PostWriteBarrier) || ((currentNode instanceof G1PostWriteBarrier) && !validateBarrier((FixedAccessNode) write, (WriteBarrier) currentNode))) { expandFrontier(frontier, currentNode); } } else { - if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((AccessNode) write, (WriteBarrier) currentNode)) || - ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((AccessNode) write, (WriteBarrier) currentNode))) { + if (!(currentNode instanceof SerialWriteBarrier) || ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (WriteBarrier) currentNode)) || + ((currentNode instanceof SerialWriteBarrier) && !validateBarrier((FixedAccessNode) write, (WriteBarrier) currentNode))) { expandFrontier(frontier, currentNode); } } @@ -90,8 +90,8 @@ final Node previous = node.predecessor(); final boolean validatePreBarrier = HotSpotReplacementsUtil.useG1GC() && (isObjectWrite(node) || !((ArrayRangeWriteNode) node).isInitialization()); if (isObjectWrite(node)) { - return next instanceof WriteBarrier && validateBarrier((AccessNode) node, (WriteBarrier) next) && - (!validatePreBarrier || (previous instanceof WriteBarrier && validateBarrier((AccessNode) node, (WriteBarrier) previous))); + return next instanceof WriteBarrier && validateBarrier((FixedAccessNode) node, (WriteBarrier) next) && + (!validatePreBarrier || (previous instanceof WriteBarrier && validateBarrier((FixedAccessNode) node, (WriteBarrier) previous))); } else if (isObjectArrayRangeWrite(node)) { return ((next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWriteNode) node).getArray() == ((ArrayRangeWriteBarrier) next).getObject()) && @@ -103,7 +103,7 @@ private static boolean isObjectWrite(Node node) { // Read nodes with barrier attached (G1 Ref field) are not validated yet. - return node instanceof AccessNode && ((HeapAccess) node).getBarrierType() != BarrierType.NONE && !(node instanceof ReadNode); + return node instanceof FixedAccessNode && ((HeapAccess) node).getBarrierType() != BarrierType.NONE && !(node instanceof ReadNode); } private static boolean isObjectArrayRangeWrite(Node node) { @@ -127,7 +127,7 @@ return ((node instanceof DeoptimizingNode) && ((DeoptimizingNode) node).canDeoptimize()) || (node instanceof LoopBeginNode); } - private static boolean validateBarrier(AccessNode write, WriteBarrier barrier) { + private static boolean validateBarrier(FixedAccessNode write, WriteBarrier barrier) { assert write instanceof WriteNode || write instanceof LoweredCompareAndSwapNode : "Node must be of type requiring a write barrier"; if ((barrier.getObject() == write.object()) && (!barrier.usePrecise() || (barrier.usePrecise() && barrier.getLocation() == write.location()))) { return true; diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/VerifyOptionsPhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -64,12 +64,11 @@ if (superType != null && !MetaUtil.isJavaLangObject(superType)) { checkType(superType, option, metaAccess, foreignCalls, checked); } - for (ResolvedJavaMethod method : type.getDeclaredMethods()) { - if (method.isClassInitializer()) { - StructuredGraph graph = new StructuredGraph(method); - new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); - new VerifyOptionsPhase(type, metaAccess, option).apply(graph); - } + ResolvedJavaMethod clinit = type.getClassInitializer(); + if (clinit != null) { + StructuredGraph graph = new StructuredGraph(clinit); + new GraphBuilderPhase(metaAccess, foreignCalls, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph); + new VerifyOptionsPhase(type, metaAccess, option).apply(graph); } } } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Wed Dec 11 21:57:10 2013 +0100 @@ -36,6 +36,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.SwitchStrategy.*; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.calc.*; @@ -102,6 +103,61 @@ } } + public static class StrategySwitchOp extends AMD64LIRInstruction implements BlockEndOp { + @Use({CONST}) protected Constant[] keyConstants; + private final LabelRef[] keyTargets; + private LabelRef defaultTarget; + @Alive({REG}) protected Value key; + @Temp({REG, ILLEGAL}) protected Value scratch; + private final SwitchStrategy strategy; + + public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { + this.strategy = strategy; + this.keyConstants = strategy.keyConstants; + this.keyTargets = keyTargets; + this.defaultTarget = defaultTarget; + this.key = key; + this.scratch = scratch; + assert keyConstants.length == keyTargets.length; + assert keyConstants.length == strategy.keyProbabilities.length; + assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int || key.getKind() == Kind.Long); + } + + @Override + public void emitCode(final CompilationResultBuilder crb, final AMD64MacroAssembler masm) { + final Register keyRegister = asRegister(key); + + BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) { + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + switch (key.getKind()) { + case Int: + if (crb.codeCache.needsDataPatch(keyConstants[index])) { + crb.recordDataReferenceInCode(keyConstants[index], 0, true); + } + long lc = keyConstants[index].asLong(); + assert NumUtil.isInt(lc); + masm.cmpl(keyRegister, (int) lc); + break; + case Long: + masm.cmpq(keyRegister, (AMD64Address) crb.asLongConstRef(keyConstants[index])); + break; + case Object: + assert condition == Condition.EQ || condition == Condition.NE; + Register temp = asObjectReg(scratch); + AMD64Move.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]); + masm.cmpptr(keyRegister, temp); + break; + default: + throw new GraalInternalError("switch only supported for int, long and object"); + } + masm.jcc(intCond(condition), target); + } + }; + strategy.run(closure); + } + } + public static class TableSwitchOp extends AMD64LIRInstruction implements BlockEndOp { private final int lowKey; private final LabelRef defaultTarget; @@ -119,128 +175,64 @@ @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - tableswitch(crb, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch)); - } - } - - public static class SequentialSwitchOp extends AMD64LIRInstruction implements BlockEndOp { - @Use({CONST}) protected Constant[] keyConstants; - private final LabelRef[] keyTargets; - private LabelRef defaultTarget; - @Alive({REG}) protected Value key; - @Temp({REG, ILLEGAL}) protected Value scratch; - - public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { - assert keyConstants.length == keyTargets.length; - this.keyConstants = keyConstants; - this.keyTargets = keyTargets; - this.defaultTarget = defaultTarget; - this.key = key; - this.scratch = scratch; - } + Register value = asIntReg(index); + Register scratchReg = asLongReg(scratch); - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - if (key.getKind() == Kind.Int) { - Register intKey = asIntReg(key); - for (int i = 0; i < keyConstants.length; i++) { - if (crb.codeCache.needsDataPatch(keyConstants[i])) { - crb.recordDataReferenceInCode(keyConstants[i], 0, true); - } - long lc = keyConstants[i].asLong(); - assert NumUtil.isInt(lc); - masm.cmpl(intKey, (int) lc); - masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); - } - } else if (key.getKind() == Kind.Long) { - Register longKey = asLongReg(key); - for (int i = 0; i < keyConstants.length; i++) { - masm.cmpq(longKey, (AMD64Address) crb.asLongConstRef(keyConstants[i])); - masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); - } - } else if (key.getKind() == Kind.Object) { - Register objectKey = asObjectReg(key); - Register temp = asObjectReg(scratch); - for (int i = 0; i < keyConstants.length; i++) { - AMD64Move.move(crb, masm, temp.asValue(Kind.Object), keyConstants[i]); - masm.cmpptr(objectKey, temp); - masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); - } + Buffer buf = masm.codeBuffer; + // Compare index against jump table bounds + int highKey = lowKey + targets.length - 1; + if (lowKey != 0) { + // subtract the low value from the switch value + masm.subl(value, lowKey); + masm.cmpl(value, highKey - lowKey); } else { - throw new GraalInternalError("sequential switch only supported for int, long and object"); - } - if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { - masm.jmp(defaultTarget.label()); + masm.cmpl(value, highKey); } - } - } - - public static class SwitchRangesOp extends AMD64LIRInstruction implements BlockEndOp { - private final LabelRef[] keyTargets; - private LabelRef defaultTarget; - private final int[] lowKeys; - private final int[] highKeys; - @Alive protected Value key; - - public SwitchRangesOp(int[] lowKeys, int[] highKeys, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { - this.lowKeys = lowKeys; - this.highKeys = highKeys; - this.keyTargets = keyTargets; - this.defaultTarget = defaultTarget; - this.key = key; - } - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - assert isSorted(lowKeys) && isSorted(highKeys); - - Label actualDefaultTarget = defaultTarget == null ? new Label() : defaultTarget.label(); - int prevHighKey = 0; - boolean skipLowCheck = false; - for (int i = 0; i < lowKeys.length; i++) { - int lowKey = lowKeys[i]; - int highKey = highKeys[i]; - if (lowKey == highKey) { - masm.cmpl(asIntReg(key), lowKey); - masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); - skipLowCheck = false; - } else { - if (!skipLowCheck || (prevHighKey + 1) != lowKey) { - masm.cmpl(asIntReg(key), lowKey); - masm.jcc(ConditionFlag.Less, actualDefaultTarget); - } - masm.cmpl(asIntReg(key), highKey); - masm.jcc(ConditionFlag.LessEqual, keyTargets[i].label()); - skipLowCheck = true; - } - prevHighKey = highKey; + // Jump to default target if index is not within the jump table + if (defaultTarget != null) { + masm.jcc(ConditionFlag.Above, defaultTarget.label()); } - if (defaultTarget != null) { - if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { - masm.jmp(defaultTarget.label()); - } - } else { - masm.bind(actualDefaultTarget); - masm.hlt(); + // Set scratch to address of jump table + int leaPos = buf.position(); + masm.leaq(scratchReg, new AMD64Address(AMD64.rip, 0)); + int afterLea = buf.position(); + + // Load jump table entry into scratch and jump to it + masm.movslq(value, new AMD64Address(scratchReg, value, Scale.Times4, 0)); + masm.addq(scratchReg, value); + masm.jmp(scratchReg); + + // Inserting padding so that jump table address is 4-byte aligned + if ((buf.position() & 0x3) != 0) { + masm.nop(4 - (buf.position() & 0x3)); } - } - @Override - protected void verify() { - super.verify(); - assert lowKeys.length == keyTargets.length; - assert highKeys.length == keyTargets.length; - assert key.getKind() == Kind.Int; - } + // Patch LEA instruction above now that we know the position of the jump table + int jumpTablePos = buf.position(); + buf.setPosition(leaPos); + masm.leaq(scratchReg, new AMD64Address(AMD64.rip, jumpTablePos - afterLea)); + buf.setPosition(jumpTablePos); - private static boolean isSorted(int[] values) { - for (int i = 1; i < values.length; i++) { - if (values[i - 1] >= values[i]) { - return false; + // Emit jump table entries + for (LabelRef target : targets) { + Label label = target.label(); + int offsetToJumpTableBase = buf.position() - jumpTablePos; + if (label.isBound()) { + int imm32 = label.position() - jumpTablePos; + buf.emitInt(imm32); + } else { + label.addPatchAt(buf.position()); + + buf.emitByte(0); // pseudo-opcode for jump table entry + buf.emitShort(offsetToJumpTableBase); + buf.emitByte(0); // padding to make jump table entry 4 bytes wide } } - return true; + + JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4); + crb.compilationResult.addAnnotation(jt); } } @@ -286,64 +278,6 @@ } } - private static void tableswitch(CompilationResultBuilder crb, AMD64MacroAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Register value, Register scratch) { - Buffer buf = masm.codeBuffer; - // Compare index against jump table bounds - int highKey = lowKey + targets.length - 1; - if (lowKey != 0) { - // subtract the low value from the switch value - masm.subl(value, lowKey); - masm.cmpl(value, highKey - lowKey); - } else { - masm.cmpl(value, highKey); - } - - // Jump to default target if index is not within the jump table - if (defaultTarget != null) { - masm.jcc(ConditionFlag.Above, defaultTarget.label()); - } - - // Set scratch to address of jump table - int leaPos = buf.position(); - masm.leaq(scratch, new AMD64Address(AMD64.rip, 0)); - int afterLea = buf.position(); - - // Load jump table entry into scratch and jump to it - masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0)); - masm.addq(scratch, value); - masm.jmp(scratch); - - // Inserting padding so that jump table address is 4-byte aligned - if ((buf.position() & 0x3) != 0) { - masm.nop(4 - (buf.position() & 0x3)); - } - - // Patch LEA instruction above now that we know the position of the jump table - int jumpTablePos = buf.position(); - buf.setPosition(leaPos); - masm.leaq(scratch, new AMD64Address(AMD64.rip, jumpTablePos - afterLea)); - buf.setPosition(jumpTablePos); - - // Emit jump table entries - for (LabelRef target : targets) { - Label label = target.label(); - int offsetToJumpTableBase = buf.position() - jumpTablePos; - if (label.isBound()) { - int imm32 = label.position() - jumpTablePos; - buf.emitInt(imm32); - } else { - label.addPatchAt(buf.position()); - - buf.emitByte(0); // pseudo-opcode for jump table entry - buf.emitShort(offsetToJumpTableBase); - buf.emitByte(0); // padding to make jump table entry 4 bytes wide - } - } - - JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4); - crb.compilationResult.addAnnotation(jt); - } - private static void floatJcc(AMD64MacroAssembler masm, ConditionFlag condition, boolean unorderedIsTrue, Label label) { Label endLabel = new Label(); if (unorderedIsTrue && !trueOnUnordered(condition)) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java Wed Dec 11 21:57:10 2013 +0100 @@ -71,7 +71,7 @@ emitCompare(masm, condition, x, y, unorderedIsTrue); } - private static String conditionToString(Condition condition) { + public static String conditionToString(Condition condition) { switch (condition) { case EQ: return "eq"; diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Wed Dec 11 21:57:10 2013 +0100 @@ -25,10 +25,12 @@ import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; import com.oracle.graal.asm.hsail.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.calc.*; @@ -46,7 +48,7 @@ * performing HSAIL code. Thus the execution path for both the TABLESWITCH and LOOKUPSWITCH * bytecodes go through this op. */ - public static class SwitchOp extends HSAILLIRInstruction implements BlockEndOp { + public static class StrategySwitchOp extends HSAILLIRInstruction implements BlockEndOp { /** * The array of key constants used for the cases of this switch statement. */ @@ -61,20 +63,19 @@ */ @Alive({REG}) protected Value key; + private final SwitchStrategy strategy; + /** - * Constructor. Called from the HSAILLIRGenerator.emitSequentialSwitch routine. - * - * @param keyConstants - * @param keyTargets - * @param defaultTarget - * @param key + * Constructor. Called from the HSAILLIRGenerator.emitStrategySwitch routine. */ - public SwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { - assert keyConstants.length == keyTargets.length; - this.keyConstants = keyConstants; + public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { + this.strategy = strategy; + this.keyConstants = strategy.keyConstants; this.keyTargets = keyTargets; this.defaultTarget = defaultTarget; this.key = key; + assert keyConstants.length == keyTargets.length; + assert keyConstants.length == strategy.keyProbabilities.length; } /** @@ -89,22 +90,24 @@ * @param masm the HSAIL assembler */ @Override - public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { - if (key.getKind() == Kind.Int) { - for (int i = 0; i < keyConstants.length; i++) { - // Generate cascading compare and branches for each case. - masm.emitCompare(key, keyConstants[i], "eq", false, false); - masm.cbr(masm.nameOf(keyTargets[i].label())); + public void emitCode(CompilationResultBuilder crb, final HSAILAssembler masm) { + BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) { + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + switch (key.getKind()) { + case Int: + // Generate cascading compare and branches for each case. + masm.emitCompare(key, keyConstants[index], HSAILCompare.conditionToString(condition), false, false); + masm.cbr(masm.nameOf(target)); + break; + case Long: + case Object: + default: + throw new GraalInternalError("switch only supported for int"); + } } - // Generate a jump for the default target if there is one. - if (defaultTarget != null && !defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { - masm.jmp(defaultTarget.label()); - } - - } else { - // Throw an exception if the key isn't of type int. - throw new GraalInternalError("Switch statments are only supported for int keys"); - } + }; + strategy.run(closure); } } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Wed Dec 11 21:57:10 2013 +0100 @@ -29,13 +29,14 @@ import com.oracle.graal.api.code.CompilationResult.JumpTable; import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; -import com.oracle.graal.asm.ptx.*; import com.oracle.graal.asm.ptx.PTXAssembler.Global; import com.oracle.graal.asm.ptx.PTXAssembler.Setp; +import com.oracle.graal.asm.ptx.*; import com.oracle.graal.asm.ptx.PTXMacroAssembler.Mov; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.calc.*; @@ -193,54 +194,55 @@ } } - public static class SequentialSwitchOp extends PTXLIRInstruction implements BlockEndOp { + public static class StrategySwitchOp extends PTXLIRInstruction implements BlockEndOp { @Use({CONST}) protected Constant[] keyConstants; private final LabelRef[] keyTargets; private LabelRef defaultTarget; @Alive({REG}) protected Value key; @Temp({REG, ILLEGAL}) protected Value scratch; + private final SwitchStrategy strategy; // Number of predicate register that would be set by this instruction. protected int predRegNum; - public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, int predReg) { - assert keyConstants.length == keyTargets.length; - this.keyConstants = keyConstants; + public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, int predReg) { + this.strategy = strategy; + this.keyConstants = strategy.keyConstants; this.keyTargets = keyTargets; this.defaultTarget = defaultTarget; this.key = key; this.scratch = scratch; + assert keyConstants.length == keyTargets.length; + assert keyConstants.length == strategy.keyProbabilities.length; + assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int || key.getKind() == Kind.Long); predRegNum = predReg; } @Override - public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { - Kind keyKind = key.getKind(); - - if (keyKind == Kind.Int || keyKind == Kind.Long) { - for (int i = 0; i < keyConstants.length; i++) { - if (crb.codeCache.needsDataPatch(keyConstants[i])) { - crb.recordDataReferenceInCode(keyConstants[i], 0, true); + public void emitCode(final CompilationResultBuilder crb, final PTXMacroAssembler masm) { + BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) { + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + switch (key.getKind()) { + case Int: + case Long: + if (crb.codeCache.needsDataPatch(keyConstants[index])) { + crb.recordDataReferenceInCode(keyConstants[index], 0, true); + } + new Setp(EQ, keyConstants[index], key, predRegNum).emit(masm); + break; + case Object: + assert condition == Condition.EQ || condition == Condition.NE; + PTXMove.move(crb, masm, scratch, keyConstants[index]); + new Setp(condition, scratch, key, predRegNum).emit(masm); + break; + default: + throw new GraalInternalError("switch only supported for int, long and object"); } - new Setp(EQ, keyConstants[i], key, predRegNum).emit(masm); - masm.bra(masm.nameOf(keyTargets[i].label()), predRegNum); + masm.bra(masm.nameOf(target), predRegNum); } - } else if (keyKind == Kind.Object) { - for (int i = 0; i < keyConstants.length; i++) { - PTXMove.move(crb, masm, scratch, keyConstants[i]); - new Setp(EQ, keyConstants[i], scratch, predRegNum).emit(masm); - masm.bra(keyTargets[i].label().toString(), predRegNum); - } - } else { - throw new GraalInternalError("sequential switch only supported for int, long and object"); - } - if (defaultTarget != null) { - if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { - masm.jmp(defaultTarget.label()); - } - } else { - // masm.hlt(); - } + }; + strategy.run(closure); } } @@ -265,41 +267,35 @@ @Override public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { - tableswitch(crb, masm, lowKey, defaultTarget, targets, index, scratch, predRegNum); + Buffer buf = masm.codeBuffer; + + // Compare index against jump table bounds + + int highKey = lowKey + targets.length - 1; + if (lowKey != 0) { + // subtract the low value from the switch value + // new Sub(value, value, lowKey).emit(masm); + new Setp(GT, index, Constant.forInt(highKey - lowKey), predRegNum).emit(masm); + } else { + new Setp(GT, index, Constant.forInt(highKey), predRegNum).emit(masm); + } + + // Jump to default target if index is not within the jump table + if (defaultTarget != null) { + masm.bra(masm.nameOf(defaultTarget.label()), predRegNum); + } + + // address of jump table + int tablePos = buf.position(); + + JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); + String name = "jumptable" + jt.position; + + new Global(index, name, targets).emit(masm); + + // bra(Value, name); + + crb.compilationResult.addAnnotation(jt); } } - - @SuppressWarnings("unused") - private static void tableswitch(CompilationResultBuilder crb, PTXAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value value, Value scratch, int predNum) { - Buffer buf = masm.codeBuffer; - - // Compare index against jump table bounds - - int highKey = lowKey + targets.length - 1; - if (lowKey != 0) { - // subtract the low value from the switch value - // new Sub(value, value, lowKey).emit(masm); - new Setp(GT, value, Constant.forInt(highKey - lowKey), predNum).emit(masm); - } else { - new Setp(GT, value, Constant.forInt(highKey), predNum).emit(masm); - } - - // Jump to default target if index is not within the jump table - if (defaultTarget != null) { - masm.bra(masm.nameOf(defaultTarget.label()), predNum); - } - - // address of jump table - int tablePos = buf.position(); - - JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); - String name = "jumptable" + jt.position; - - new Global(value, name, targets).emit(masm); - - // bra(Value, name); - - crb.compilationResult.addAnnotation(jt); - - } } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Wed Dec 11 21:57:10 2013 +0100 @@ -30,15 +30,31 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.asm.*; import com.oracle.graal.asm.sparc.*; -import com.oracle.graal.asm.sparc.SPARCAssembler.*; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpe; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpg; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpge; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpgu; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpl; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bple; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpleu; +import com.oracle.graal.asm.sparc.SPARCAssembler.Bpne; +import com.oracle.graal.asm.sparc.SPARCAssembler.CC; +import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag; +import com.oracle.graal.asm.sparc.SPARCAssembler.Movcc; +import com.oracle.graal.asm.sparc.SPARCAssembler.Sub; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Bpgeu; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Bplu; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Cmp; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Jmp; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Nop; +import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Ret; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.*; +import com.oracle.graal.lir.StandardOp.BlockEndOp; +import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure; import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.calc.*; -import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*; - public class SPARCControlFlow { public static class BranchOp extends SPARCLIRInstruction implements StandardOp.BranchOp { @@ -72,40 +88,7 @@ } assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; CC cc = kind == Kind.Int ? CC.Icc : CC.Xcc; - switch (actualCondition) { - case EQ: - new Bpe(cc, actualTarget).emit(masm); - break; - case NE: - new Bpne(cc, actualTarget).emit(masm); - break; - case BT: - new Bplu(cc, actualTarget).emit(masm); - break; - case LT: - new Bpl(cc, actualTarget).emit(masm); - break; - case BE: - new Bpleu(cc, actualTarget).emit(masm); - break; - case LE: - new Bple(cc, actualTarget).emit(masm); - break; - case GE: - new Bpge(cc, actualTarget).emit(masm); - break; - case AE: - new Bpgeu(cc, actualTarget).emit(masm); - break; - case GT: - new Bpg(cc, actualTarget).emit(masm); - break; - case AT: - new Bpgu(cc, actualTarget).emit(masm); - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } + emitCompare(masm, actualTarget, actualCondition, cc); new Nop().emit(masm); // delay slot if (needJump) { masm.jmp(falseDestination.label()); @@ -113,6 +96,43 @@ } } + private static void emitCompare(SPARCMacroAssembler masm, Label target, Condition actualCondition, CC cc) { + switch (actualCondition) { + case EQ: + new Bpe(cc, target).emit(masm); + break; + case NE: + new Bpne(cc, target).emit(masm); + break; + case BT: + new Bplu(cc, target).emit(masm); + break; + case LT: + new Bpl(cc, target).emit(masm); + break; + case BE: + new Bpleu(cc, target).emit(masm); + break; + case LE: + new Bple(cc, target).emit(masm); + break; + case GE: + new Bpge(cc, target).emit(masm); + break; + case AE: + new Bpgeu(cc, target).emit(masm); + break; + case GT: + new Bpg(cc, target).emit(masm); + break; + case AT: + new Bpgu(cc, target).emit(masm); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + @Opcode("CMOVE") public static class CondMoveOp extends SPARCLIRInstruction { @@ -264,136 +284,64 @@ } } - public static class SequentialSwitchOp extends SPARCLIRInstruction implements BlockEndOp { - + public static class StrategySwitchOp extends SPARCLIRInstruction implements BlockEndOp { @Use({CONST}) protected Constant[] keyConstants; private final LabelRef[] keyTargets; private LabelRef defaultTarget; @Alive({REG}) protected Value key; @Temp({REG, ILLEGAL}) protected Value scratch; + private final SwitchStrategy strategy; - public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { - assert keyConstants.length == keyTargets.length; - this.keyConstants = keyConstants; + public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { + this.strategy = strategy; + this.keyConstants = strategy.keyConstants; this.keyTargets = keyTargets; this.defaultTarget = defaultTarget; this.key = key; this.scratch = scratch; + assert keyConstants.length == keyTargets.length; + assert keyConstants.length == strategy.keyProbabilities.length; + assert (scratch.getKind() == Kind.Illegal) == (key.getKind() == Kind.Int); } @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - if (key.getKind() == Kind.Int) { - Register intKey = asIntReg(key); - for (int i = 0; i < keyConstants.length; i++) { - if (crb.codeCache.needsDataPatch(keyConstants[i])) { - crb.recordDataReferenceInCode(keyConstants[i], 0, true); + public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) { + final Register keyRegister = asRegister(key); + + BaseSwitchClosure closure = new BaseSwitchClosure(crb, masm, keyTargets, defaultTarget) { + @Override + protected void conditionalJump(int index, Condition condition, Label target) { + switch (key.getKind()) { + case Int: + if (crb.codeCache.needsDataPatch(keyConstants[index])) { + crb.recordDataReferenceInCode(keyConstants[index], 0, true); + } + long lc = keyConstants[index].asLong(); + assert NumUtil.isInt(lc); + new Cmp(keyRegister, (int) lc).emit(masm); + emitCompare(masm, target, condition, CC.Icc); + break; + case Long: { + Register temp = asLongReg(scratch); + SPARCMove.move(crb, masm, temp.asValue(Kind.Long), keyConstants[index]); + new Cmp(keyRegister, temp).emit(masm); + emitCompare(masm, target, condition, CC.Xcc); + break; + } + case Object: { + Register temp = asObjectReg(scratch); + SPARCMove.move(crb, masm, temp.asValue(Kind.Object), keyConstants[index]); + new Cmp(keyRegister, temp).emit(masm); + emitCompare(masm, target, condition, CC.Ptrcc); + break; + } + default: + throw new GraalInternalError("switch only supported for int, long and object"); } - long lc = keyConstants[i].asLong(); - assert NumUtil.isInt(lc); - new Cmp(intKey, (int) lc).emit(masm); - new Bpe(CC.Icc, keyTargets[i].label()).emit(masm); - new Nop().emit(masm); // delay slot - } - } else if (key.getKind() == Kind.Long) { - Register longKey = asLongReg(key); - Register temp = asLongReg(scratch); - for (int i = 0; i < keyConstants.length; i++) { - SPARCMove.move(crb, masm, temp.asValue(Kind.Long), keyConstants[i]); - new Cmp(longKey, temp).emit(masm); - new Bpe(CC.Xcc, keyTargets[i].label()).emit(masm); - new Nop().emit(masm); // delay slot - } - } else if (key.getKind() == Kind.Object) { - Register objectKey = asObjectReg(key); - Register temp = asObjectReg(scratch); - for (int i = 0; i < keyConstants.length; i++) { - SPARCMove.move(crb, masm, temp.asValue(Kind.Object), keyConstants[i]); - new Cmp(objectKey, temp).emit(masm); - new Bpe(CC.Ptrcc, keyTargets[i].label()).emit(masm); new Nop().emit(masm); // delay slot } - } else { - throw new GraalInternalError("sequential switch only supported for int, long and object"); - } - if (defaultTarget != null) { - if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { - masm.jmp(defaultTarget.label()); - } - } else { - new Illtrap(0).emit(masm); - } - } - } - - public static class SwitchRangesOp extends SPARCLIRInstruction implements BlockEndOp { - - private final LabelRef[] keyTargets; - private LabelRef defaultTarget; - private final int[] lowKeys; - private final int[] highKeys; - @Alive protected Value key; - - public SwitchRangesOp(int[] lowKeys, int[] highKeys, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) { - this.lowKeys = lowKeys; - this.highKeys = highKeys; - this.keyTargets = keyTargets; - this.defaultTarget = defaultTarget; - this.key = key; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - assert isSorted(lowKeys) && isSorted(highKeys); - - Label actualDefaultTarget = defaultTarget == null ? new Label() : defaultTarget.label(); - int prevHighKey = 0; - boolean skipLowCheck = false; - for (int i = 0; i < lowKeys.length; i++) { - int lowKey = lowKeys[i]; - int highKey = highKeys[i]; - if (lowKey == highKey) { - // masm.cmpl(asIntReg(key), lowKey); - // masm.jcc(ConditionFlag.Equal, keyTargets[i].label()); - skipLowCheck = false; - } else { - if (!skipLowCheck || (prevHighKey + 1) != lowKey) { - // masm.cmpl(asIntReg(key), lowKey); - // masm.jcc(ConditionFlag.Less, actualDefaultTarget); - } - // masm.cmpl(asIntReg(key), highKey); - // masm.jcc(ConditionFlag.LessEqual, keyTargets[i].label()); - skipLowCheck = true; - } - prevHighKey = highKey; - } - - if (defaultTarget != null) { - if (!defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { - new Bpa(defaultTarget.label()).emit(masm); - } - } else { - masm.bind(actualDefaultTarget); - new Illtrap(0).emit(masm); - } - throw GraalInternalError.unimplemented(); - } - - @Override - protected void verify() { - super.verify(); - assert lowKeys.length == keyTargets.length; - assert highKeys.length == keyTargets.length; - assert key.getKind() == Kind.Int; - } - - private static boolean isSorted(int[] values) { - for (int i = 1; i < values.length; i++) { - if (values[i - 1] >= values[i]) { - return false; - } - } - return true; + }; + strategy.run(closure); } } @@ -415,41 +363,40 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - tableswitch(crb, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch)); + Register value = asIntReg(index); + Register scratchReg = asLongReg(scratch); + + Buffer buf = masm.codeBuffer; + // Compare index against jump table bounds + int highKey = lowKey + targets.length - 1; + if (lowKey != 0) { + // subtract the low value from the switch value + new Sub(value, lowKey, value).emit(masm); + // masm.setp_gt_s32(value, highKey - lowKey); + } else { + // masm.setp_gt_s32(value, highKey); + } + + // Jump to default target if index is not within the jump table + if (defaultTarget != null) { + new Bpgu(CC.Icc, defaultTarget.label()).emit(masm); + new Nop().emit(masm); // delay slot + } + + // Load jump table entry into scratch and jump to it + // masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0)); + // masm.addq(scratch, value); + new Jmp(new SPARCAddress(scratchReg, 0)).emit(masm); + new Nop().emit(masm); // delay slot + + // address of jump table + int tablePos = buf.position(); + + JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); + crb.compilationResult.addAnnotation(jt); + + // SPARC: unimp: tableswitch extract + throw GraalInternalError.unimplemented(); } } - - private static void tableswitch(CompilationResultBuilder crb, SPARCAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, Register value, Register scratch) { - Buffer buf = masm.codeBuffer; - // Compare index against jump table bounds - int highKey = lowKey + targets.length - 1; - if (lowKey != 0) { - // subtract the low value from the switch value - new Sub(value, lowKey, value).emit(masm); - // masm.setp_gt_s32(value, highKey - lowKey); - } else { - // masm.setp_gt_s32(value, highKey); - } - - // Jump to default target if index is not within the jump table - if (defaultTarget != null) { - new Bpgu(CC.Icc, defaultTarget.label()).emit(masm); - new Nop().emit(masm); // delay slot - } - - // Load jump table entry into scratch and jump to it - // masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0)); - // masm.addq(scratch, value); - new Jmp(new SPARCAddress(scratch, 0)).emit(masm); - new Nop().emit(masm); // delay slot - - // address of jump table - int tablePos = buf.position(); - - JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); - crb.compilationResult.addAnnotation(jt); - - // SPARC: unimp: tableswitch extract - throw GraalInternalError.unimplemented(); - } } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java Wed Dec 11 21:57:10 2013 +0100 @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.lir; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.asm.*; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.calc.*; + +public abstract class SwitchStrategy { + + private interface SwitchClosure { + /** + * Generates a conditional or unconditional jump. The jump will be unconditional if + * condition is null. If defaultTarget is true, then the jump will go the the default. + * + * @param index Index of the value and the jump target (only used if defaultTarget == false) + * @param condition The condition on which to jump (can be null) + * @param defaultTarget true if the jump should go to the default target, false if index + * should be used. + */ + void conditionalJump(int index, Condition condition, boolean defaultTarget); + + /** + * Generates a conditional jump to the target with the specified index. The fall through + * should go to the default target. + * + * @param index Index of the value and the jump target + * @param condition The condition on which to jump + * @param canFallThrough true if this is the last instruction in the switch statement, to + * allow for fall-through optimizations. + */ + void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough); + + /** + * Create a new label and generate a conditional jump to it. + * + * @param index Index of the value and the jump target + * @param condition The condition on which to jump + * @return a new Label + */ + Label conditionalJump(int index, Condition condition); + + /** + * Binds a label returned by {@link #conditionalJump(int, Condition)}. + */ + void bind(Label label); + + /** + * Return true iff the target of both indexes is the same. + */ + boolean isSameTarget(int index1, int index2); + } + + /** + * Backends can subclass this abstract class to generate code for switch strategies. + */ + public abstract static class BaseSwitchClosure implements SwitchClosure { + + private final CompilationResultBuilder crb; + private final AbstractAssembler masm; + private final LabelRef[] keyTargets; + private final LabelRef defaultTarget; + + public BaseSwitchClosure(CompilationResultBuilder crb, AbstractAssembler masm, LabelRef[] keyTargets, LabelRef defaultTarget) { + this.crb = crb; + this.masm = masm; + this.keyTargets = keyTargets; + this.defaultTarget = defaultTarget; + } + + /** + * This method generates code for a comparison between the actual value and the constant at + * the given index and a condition jump to target. + */ + protected abstract void conditionalJump(int index, Condition condition, Label target); + + public void conditionalJump(int index, Condition condition, boolean targetDefault) { + Label target = targetDefault ? defaultTarget.label() : keyTargets[index].label(); + if (condition == null) { + masm.jmp(target); + } else { + conditionalJump(index, condition, target); + } + } + + public void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough) { + if (canFallThrough && defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { + conditionalJump(index, condition, keyTargets[index].label()); + } else if (canFallThrough && keyTargets[index].isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { + conditionalJump(index, condition.negate(), defaultTarget.label()); + } else { + conditionalJump(index, condition, keyTargets[index].label()); + masm.jmp(defaultTarget.label()); + } + } + + public Label conditionalJump(int index, Condition condition) { + Label label = new Label(); + conditionalJump(index, condition, label); + return label; + } + + public void bind(Label label) { + masm.bind(label); + } + + public boolean isSameTarget(int index1, int index2) { + return keyTargets[index1] == keyTargets[index2]; + } + + } + + private class EffortClosure implements SwitchClosure { + + private int defaultEffort; + private int defaultCount; + private final int[] keyEfforts = new int[keyConstants.length]; + private final int[] keyCounts = new int[keyConstants.length]; + private final LabelRef[] keyTargets; + + public EffortClosure(LabelRef[] keyTargets) { + this.keyTargets = keyTargets; + } + + public void conditionalJump(int index, Condition condition, boolean defaultTarget) { + // nothing to do + } + + public void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough) { + // nothing to do + } + + public Label conditionalJump(int index, Condition condition) { + // nothing to do + return null; + } + + public void bind(Label label) { + // nothing to do + } + + public boolean isSameTarget(int index1, int index2) { + return keyTargets[index1] == keyTargets[index2]; + } + + public double getAverageEffort() { + double defaultProbability = 1; + double effort = 0; + for (int i = 0; i < keyConstants.length; i++) { + effort += keyEfforts[i] * keyProbabilities[i] / keyCounts[i]; + defaultProbability -= keyProbabilities[i]; + } + return effort + defaultEffort * defaultProbability / defaultCount; + } + } + + public final double[] keyProbabilities; + public final Constant[] keyConstants; + private double averageEffort = -1; + private EffortClosure effortClosure; + + public SwitchStrategy(double[] keyProbabilities, Constant[] keyConstants) { + assert keyConstants.length == keyProbabilities.length && keyConstants.length >= 2; + this.keyProbabilities = keyProbabilities; + this.keyConstants = keyConstants; + } + + public double getAverageEffort() { + assert averageEffort >= 0; + return averageEffort; + } + + /* + * Looks for the end of a stretch of key constants that are successive numbers and have the same + * target. + */ + protected int getSliceEnd(SwitchClosure closure, int pos) { + int slice = pos; + while (slice < (keyConstants.length - 1) && keyConstants[slice + 1].asLong() == keyConstants[slice].asLong() + 1 && closure.isSameTarget(slice, slice + 1)) { + slice++; + } + return slice; + } + + protected void registerEffort(int rangeStart, int rangeEnd, int depth) { + if (effortClosure != null) { + for (int i = rangeStart; i <= rangeEnd; i++) { + effortClosure.keyEfforts[i] += depth; + effortClosure.keyCounts[i]++; + } + } + } + + protected void registerDefaultEffort(int depth) { + if (effortClosure != null) { + effortClosure.defaultEffort += depth; + effortClosure.defaultCount++; + } + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[avgEffort=" + averageEffort + "]"; + } + + public static class SequentialStrategy extends SwitchStrategy { + private final Integer[] indexes; + + public SequentialStrategy(final double[] keyProbabilities, Constant[] keyConstants) { + super(keyProbabilities, keyConstants); + + int keyCount = keyConstants.length; + indexes = new Integer[keyCount]; + for (int i = 0; i < keyCount; i++) { + indexes[i] = i; + } + Arrays.sort(indexes, new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return keyProbabilities[o1] < keyProbabilities[o2] ? 1 : keyProbabilities[o1] > keyProbabilities[o2] ? -1 : 0; + } + }); + } + + @Override + public void run(SwitchClosure closure) { + for (int i = 0; i < keyConstants.length - 1; i++) { + closure.conditionalJump(indexes[i], Condition.EQ, false); + registerEffort(indexes[i], indexes[i], i + 1); + } + closure.conditionalJumpOrDefault(indexes[keyConstants.length - 1], Condition.EQ, true); + registerEffort(indexes[keyConstants.length - 1], indexes[keyConstants.length - 1], keyConstants.length); + registerDefaultEffort(keyConstants.length); + } + } + + public static class RangesStrategy extends SwitchStrategy { + private final Integer[] indexes; + + public RangesStrategy(final double[] keyProbabilities, Constant[] keyConstants) { + super(keyProbabilities, keyConstants); + + int keyCount = keyConstants.length; + indexes = new Integer[keyCount]; + for (int i = 0; i < keyCount; i++) { + indexes[i] = i; + } + Arrays.sort(indexes, new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return keyProbabilities[o1] < keyProbabilities[o2] ? 1 : keyProbabilities[o1] > keyProbabilities[o2] ? -1 : 0; + } + }); + } + + @Override + public void run(SwitchClosure closure) { + int depth = 0; + closure.conditionalJump(0, Condition.LT, true); + registerDefaultEffort(++depth); + int rangeStart = 0; + int rangeEnd = getSliceEnd(closure, rangeStart); + while (rangeEnd != keyConstants.length - 1) { + if (rangeStart == rangeEnd) { + closure.conditionalJump(rangeStart, Condition.EQ, false); + registerEffort(rangeStart, rangeEnd, ++depth); + } else { + if (rangeStart == 0 || keyConstants[rangeStart - 1].asLong() + 1 != keyConstants[rangeStart].asLong()) { + closure.conditionalJump(rangeStart, Condition.LT, true); + registerDefaultEffort(++depth); + } + closure.conditionalJump(rangeEnd, Condition.LE, false); + registerEffort(rangeStart, rangeEnd, ++depth); + } + rangeStart = rangeEnd + 1; + rangeEnd = getSliceEnd(closure, rangeStart); + } + if (rangeStart == rangeEnd) { + closure.conditionalJumpOrDefault(rangeStart, Condition.EQ, true); + registerEffort(rangeStart, rangeEnd, ++depth); + registerDefaultEffort(depth); + } else { + if (rangeStart == 0 || keyConstants[rangeStart - 1].asLong() + 1 != keyConstants[rangeStart].asLong()) { + closure.conditionalJump(rangeStart, Condition.LT, true); + registerDefaultEffort(++depth); + } + closure.conditionalJumpOrDefault(rangeEnd, Condition.LE, true); + registerEffort(rangeStart, rangeEnd, ++depth); + registerDefaultEffort(depth); + } + } + } + + public static class BooleanStrategy extends SwitchStrategy { + + private static final double MIN_PROBABILITY = 0.00001; + + private final double[] probabilitySums; + + public BooleanStrategy(double[] keyProbabilities, Constant[] keyConstants) { + super(keyProbabilities, keyConstants); + probabilitySums = new double[keyProbabilities.length + 1]; + double sum = 0; + for (int i = 0; i < keyConstants.length; i++) { + sum += Math.max(keyProbabilities[i], MIN_PROBABILITY); + probabilitySums[i + 1] = sum; + } + } + + @Override + public void run(SwitchClosure closure) { + recurseBooleanSwitch(closure, 0, keyConstants.length - 1, 0); + } + + /** + * Recursively generate a list of comparisons that always subdivides the key list in the + * middle (in terms of probability, not index). + */ + private void recurseBooleanSwitch(SwitchClosure closure, int left, int right, int startDepth) { + assert startDepth < keyConstants.length * 3 : "runaway recursion in boolean switch"; + int depth = startDepth; + boolean leftBorder = left == 0; + boolean rightBorder = right == keyConstants.length - 1; + + if (left + 1 == right) { + // only two possible values + if (leftBorder || rightBorder || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong() || keyConstants[left].asLong() + 1 != keyConstants[right].asLong()) { + closure.conditionalJump(left, Condition.EQ, false); + registerEffort(left, left, ++depth); + closure.conditionalJumpOrDefault(right, Condition.EQ, rightBorder); + registerEffort(right, right, ++depth); + registerDefaultEffort(depth); + } else { + closure.conditionalJump(left, Condition.EQ, false); + registerEffort(left, left, ++depth); + closure.conditionalJump(right, null, false); + registerEffort(right, right, depth); + } + return; + } + double probabilityStart = probabilitySums[left]; + double probabilityMiddle = (probabilityStart + probabilitySums[right + 1]) / 2; + assert probabilityStart >= probabilityStart; + int middle = left; + while (getSliceEnd(closure, middle + 1) < right && probabilitySums[getSliceEnd(closure, middle + 1)] < probabilityMiddle) { + middle = getSliceEnd(closure, middle + 1); + } + middle = getSliceEnd(closure, middle); + assert middle < keyConstants.length - 1; + + if (getSliceEnd(closure, left) == middle) { + if (left == 0) { + closure.conditionalJump(0, Condition.LT, true); + registerDefaultEffort(++depth); + } + closure.conditionalJump(middle, Condition.LE, false); + registerEffort(left, middle, ++depth); + + if (middle + 1 == right) { + closure.conditionalJumpOrDefault(right, Condition.EQ, rightBorder); + registerEffort(right, right, ++depth); + registerDefaultEffort(depth); + } else { + if (keyConstants[middle].asLong() + 1 != keyConstants[middle + 1].asLong()) { + closure.conditionalJump(middle + 1, Condition.LT, true); + registerDefaultEffort(++depth); + } + if (getSliceEnd(closure, middle + 1) == right) { + if (right == keyConstants.length - 1 || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong()) { + closure.conditionalJumpOrDefault(right, Condition.LE, rightBorder); + registerEffort(middle + 1, right, ++depth); + registerDefaultEffort(depth); + } else { + closure.conditionalJump(middle + 1, null, false); + registerEffort(middle + 1, right, depth); + } + } else { + recurseBooleanSwitch(closure, middle + 1, right, depth); + } + } + } else if (getSliceEnd(closure, middle + 1) == right) { + if (rightBorder || keyConstants[right].asLong() + 1 != keyConstants[right + 1].asLong()) { + closure.conditionalJump(right, Condition.GT, true); + registerDefaultEffort(++depth); + } + closure.conditionalJump(middle + 1, Condition.GE, false); + registerEffort(middle + 1, right, ++depth); + recurseBooleanSwitch(closure, left, middle, depth); + } else { + Label label = closure.conditionalJump(middle + 1, Condition.GE); + depth++; + recurseBooleanSwitch(closure, left, middle, depth); + closure.bind(label); + recurseBooleanSwitch(closure, middle + 1, right, depth); + } + } + } + + public abstract void run(SwitchClosure closure); + + private static SwitchStrategy[] getStrategies(double[] keyProbabilities, Constant[] keyConstants, LabelRef[] keyTargets) { + SwitchStrategy[] strategies = new SwitchStrategy[]{new SequentialStrategy(keyProbabilities, keyConstants), new RangesStrategy(keyProbabilities, keyConstants), + new BooleanStrategy(keyProbabilities, keyConstants)}; + for (SwitchStrategy strategy : strategies) { + strategy.effortClosure = strategy.new EffortClosure(keyTargets); + strategy.run(strategy.effortClosure); + strategy.averageEffort = strategy.effortClosure.getAverageEffort(); + strategy.effortClosure = null; + } + return strategies; + } + + public static SwitchStrategy getBestStrategy(double[] keyProbabilities, Constant[] keyConstants, LabelRef[] keyTargets) { + SwitchStrategy[] strategies = getStrategies(keyProbabilities, keyConstants, keyTargets); + double bestEffort = Integer.MAX_VALUE; + SwitchStrategy bestStrategy = null; + for (SwitchStrategy strategy : strategies) { + if (strategy.getAverageEffort() < bestEffort) { + bestEffort = strategy.getAverageEffort(); + bestStrategy = strategy; + } + } + return bestStrategy; + } +} diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -26,7 +26,7 @@ public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode { - @Input private FrameState deoptState; + @Input(notDataflow = true) private FrameState deoptState; public DeoptimizingFixedWithNextNode(Stamp stamp) { super(stamp); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -25,7 +25,7 @@ import com.oracle.graal.nodes.spi.*; /** - * Interface implemented by nodes which need deoptimization information. + * Interface implemented by nodes which may need {@linkplain FrameState deoptimization information}. */ public interface DeoptimizingNode extends NodeWithState { @@ -42,7 +42,7 @@ /** * Sets the deoptimization information associated with this node. * - * @param state the FrameState which represents the deoptimization information + * @param state the {@link FrameState} which represents the deoptimization information */ void setDeoptimizationState(FrameState state); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -63,7 +63,7 @@ @Override public void lower(LoweringTool tool) { if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) { - ValueNode guard = tool.createGuard(condition(), getReason(), getAction(), isNegated()).asNode(); + ValueNode guard = tool.createGuard(this, condition(), getReason(), getAction(), isNegated()).asNode(); this.replaceAtUsages(guard); ValueAnchorNode newAnchor = graph().add(new ValueAnchorNode(guard.asNode())); graph().replaceFixedWithFixed(this, newAnchor); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Dec 11 21:57:10 2013 +0100 @@ -33,6 +33,8 @@ /** * The {@code FrameState} class encapsulates the frame state (i.e. local variables and operand * stack) at a particular point in the abstract interpretation. + * + * This can be used as debug or deoptimization information. */ @NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}") public final class FrameState extends VirtualState implements IterableNodeType { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -77,7 +77,7 @@ @Override public void lower(LoweringTool tool) { - GuardingNode guard = tool.createGuard(condition, reason, action, negated); + GuardingNode guard = tool.createGuard(next(), condition, reason, action, negated); ValueAnchorNode anchor = graph().add(new ValueAnchorNode((ValueNode) guard)); PiNode pi = graph().unique(new PiNode(object, stamp(), (ValueNode) guard)); replaceAtUsages(pi); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java Wed Dec 11 21:57:10 2013 +0100 @@ -30,19 +30,21 @@ public interface StateSplit extends NodeWithState { /** - * Gets the state of the JVM frame after execution of this node. + * Gets the {@link FrameState} corresponding to the state of the JVM after execution of this + * node. */ FrameState stateAfter(); /** - * Sets the state of the JVM frame after execution of this node. + * Sets the {@link FrameState} corresponding to the state of the JVM after execution of this + * node. */ void setStateAfter(FrameState x); /** - * Determines if this node has a side-effect. Execution of such a node changes state visible to - * other threads. These nodes denote boundaries across which deoptimization points cannot be - * moved. + * Determines if this node has a side-effect. Such nodes can not be safely re-executed because + * they modified state which is visible to other thread or modified state beyond what is + * captured in {@link FrameState} nodes. */ boolean hasSideEffect(); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/Access.java Wed Dec 11 21:57:10 2013 +0100 @@ -24,12 +24,10 @@ import com.oracle.graal.nodes.*; -public interface Access extends DeoptimizingNode, GuardedNode, HeapAccess { +public interface Access extends GuardedNode, HeapAccess { ValueNode object(); LocationNode nullCheckLocation(); - void setNullCheck(boolean check); - } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java Mon Dec 09 21:40:45 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.nodes.extended; - -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.type.*; - -/** - * Accesses a value at an memory address specified by an {@linkplain #object object} and a - * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the - * object. - */ -public abstract class AccessNode extends DeoptimizingFixedWithNextNode implements Access, GuardingNode { - - @Input private GuardingNode guard; - @Input private ValueNode object; - @Input private ValueNode location; - private boolean nullCheck; - private BarrierType barrierType; - private boolean compressible; - - public ValueNode object() { - return object; - } - - public LocationNode location() { - return (LocationNode) location; - } - - public LocationNode nullCheckLocation() { - return (LocationNode) location; - } - - public boolean getNullCheck() { - return nullCheck; - } - - public void setNullCheck(boolean check) { - this.nullCheck = check; - } - - public AccessNode(ValueNode object, ValueNode location, Stamp stamp) { - this(object, location, stamp, null, BarrierType.NONE, false); - } - - public AccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) { - this(object, location, stamp, null, barrierType, compressible); - } - - public AccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) { - super(stamp); - this.object = object; - this.location = location; - this.guard = guard; - this.barrierType = barrierType; - this.compressible = compressible; - } - - @Override - public boolean canDeoptimize() { - return nullCheck; - } - - @Override - public GuardingNode getGuard() { - return guard; - } - - @Override - public void setGuard(GuardingNode guard) { - updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); - this.guard = guard; - } - - @Override - public BarrierType getBarrierType() { - return barrierType; - } - - @Override - public boolean isCompressible() { - return compressible; - } -} diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.extended; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * Accesses a value at an memory address specified by an {@linkplain #object object} and a + * {@linkplain #nullCheckLocation() location}. The access does not include a null check on the + * object. + */ +public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access, GuardingNode { + + @Input private GuardingNode guard; + @Input private ValueNode object; + @Input private ValueNode location; + private boolean nullCheck; + private BarrierType barrierType; + private boolean compressible; + + public ValueNode object() { + return object; + } + + public LocationNode location() { + return (LocationNode) location; + } + + public LocationNode nullCheckLocation() { + return (LocationNode) location; + } + + public boolean getNullCheck() { + return nullCheck; + } + + public void setNullCheck(boolean check) { + this.nullCheck = check; + } + + public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp) { + this(object, location, stamp, null, BarrierType.NONE, false); + } + + public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType, boolean compressible) { + this(object, location, stamp, null, barrierType, compressible); + } + + public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean compressible) { + super(stamp); + this.object = object; + this.location = location; + this.guard = guard; + this.barrierType = barrierType; + this.compressible = compressible; + } + + @Override + public boolean canDeoptimize() { + return nullCheck; + } + + @Override + public GuardingNode getGuard() { + return guard; + } + + @Override + public void setGuard(GuardingNode guard) { + updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); + this.guard = guard; + } + + @Override + public BarrierType getBarrierType() { + return barrierType; + } + + @Override + public boolean isCompressible() { + return compressible; + } +} diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -27,9 +27,9 @@ import com.oracle.graal.nodes.type.*; /** - * An {@link AccessNode} that can be converted to a {@link FloatingAccessNode}. + * An {@link FixedAccessNode} that can be converted to a {@link FloatingAccessNode}. */ -public abstract class FloatableAccessNode extends AccessNode { +public abstract class FloatableAccessNode extends FixedAccessNode { public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp) { super(object, location, stamp); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -30,8 +30,6 @@ @Input private ValueNode object; @Input private LocationNode location; - @Input private FrameState deoptState; - private boolean nullCheck; private BarrierType barrierType; private boolean compressible; @@ -51,14 +49,6 @@ return location.getLocationIdentity(); } - public boolean getNullCheck() { - return nullCheck; - } - - public void setNullCheck(boolean check) { - this.nullCheck = check; - } - public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp) { super(stamp); this.object = object; @@ -74,34 +64,14 @@ } @Override - public boolean canDeoptimize() { - return nullCheck; - } - - @Override - public FrameState getDeoptimizationState() { - return deoptState; - } - - @Override - public void setDeoptimizationState(FrameState f) { - updateUsages(deoptState, f); - deoptState = f; - } - - @Override public BarrierType getBarrierType() { return barrierType; } - public FrameState getState() { - return deoptState; - } - @Override public boolean isCompressible() { return compressible; } - public abstract Access asFixedNode(); + public abstract FixedAccessNode asFixedNode(); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -71,7 +71,7 @@ } @Override - public Access asFixedNode() { + public FixedAccessNode asFixedNode() { return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard(), getBarrierType(), isCompressible())); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -54,6 +54,15 @@ assert keySuccessors.length == keys.length + 1; assert keySuccessors.length == keyProbabilities.length; this.keys = keys; + assert assertValues(); + assert assertSorted(); + } + + private boolean assertSorted() { + for (int i = 1; i < keys.length; i++) { + assert keys[i - 1] < keys[i]; + } + return true; } /** @@ -70,6 +79,11 @@ this(value, new AbstractBeginNode[successorCount], keys, keyProbabilities, keySuccessors); } + @Override + public boolean isSorted() { + return true; + } + /** * Gets the key at the specified index. * diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -31,7 +31,7 @@ import com.oracle.graal.nodes.virtual.*; /** - * Reads an {@linkplain AccessNode accessed} value. + * Reads an {@linkplain FixedAccessNode accessed} value. */ public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -47,6 +47,7 @@ */ public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) { super(StampFactory.forVoid()); + assert value.kind() == Kind.Int || value.kind() == Kind.Long || value.kind() == Kind.Object; assert keySuccessors.length == keyProbabilities.length; this.successors = new NodeSuccessorList<>(this, successors); this.value = value; @@ -65,6 +66,15 @@ return true; } + protected boolean assertValues() { + Kind kind = value.kind(); + for (int i = 0; i < keyCount(); i++) { + Constant key = keyAt(i); + assert key.getKind() == kind; + } + return true; + } + @Override public double probability(AbstractBeginNode successor) { double sum = 0; @@ -107,6 +117,8 @@ return value; } + public abstract boolean isSorted(); + /** * The number of distinct keys in this switch. */ diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -31,9 +31,9 @@ import com.oracle.graal.nodes.virtual.*; /** - * Writes a given {@linkplain #value() value} a {@linkplain AccessNode memory location}. + * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}. */ -public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Virtualizable { +public final class WriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, MemoryAccess, Virtualizable { @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -31,7 +31,7 @@ /** * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}. */ -public class LoweredCompareAndSwapNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single { +public class LoweredCompareAndSwapNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single { @Input private ValueNode expectedValue; @Input private ValueNode newValue; diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -56,6 +56,25 @@ assert successors.length <= keys.length + 1; assert keySuccessors.length == keyProbabilities.length; this.keys = keys; + assert assertValues(); + } + + @Override + public boolean isSorted() { + Kind kind = value().kind(); + if (kind.isNumericInteger()) { + Constant lastKey = null; + for (int i = 0; i < keyCount(); i++) { + Constant key = keyAt(i); + if (lastKey != null && key.asLong() <= lastKey.asLong()) { + return false; + } + lastKey = key; + } + return true; + } else { + return false; + } } @Override diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Wed Dec 11 21:57:10 2013 +0100 @@ -61,9 +61,9 @@ Value emitAddress(StackSlot slot); - Value emitLoad(Kind kind, Value address, DeoptimizingNode deopting); + Value emitLoad(Kind kind, Value address, Access access); - void emitStore(Kind kind, Value address, Value input, DeoptimizingNode deopting); + void emitStore(Kind kind, Value address, Value input, Access access); void emitMembar(int barriers); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java Wed Dec 11 21:57:10 2013 +0100 @@ -39,11 +39,11 @@ Replacements getReplacements(); - GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object); + GuardingNode createNullCheckGuard(FixedNode before, GuardedNode guardedNode, ValueNode object); - GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action); + GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action); - GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated); + GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated); Assumptions assumptions(); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java Wed Dec 11 21:57:10 2013 +0100 @@ -22,8 +22,29 @@ */ package com.oracle.graal.nodes.spi; +import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import static com.oracle.graal.nodes.StructuredGraph.GuardsStage.*; +/** + * Interface for nodes which have {@link FrameState} nodes as input. + *

+ * Some node can declare more than one interface which requires a {@link FrameState} input (e.g. + * {@link DeoptimizingNode} and {@link StateSplit}). Since this interface can only report one + * {@link FrameState}, such nodes must ensure they only maintain a link to at most one + * {@link FrameState} at all times. Usually this is not a problem because {@link FrameState} are + * associated only with {@link StateSplit} nodes before the {@link #AFTER_FSA} stage and only with + * {@link DeoptimizingNode} after. + * + * + */ public interface NodeWithState { + /** + * Gets the {@link FrameState} associated with this node. + * + * @return the {@link FrameState} associated with this node + */ FrameState getState(); + + Node asNode(); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -226,7 +226,6 @@ if (accessNode.canFloat()) { MemoryNode lastLocationAccess = state.getLastLocationAccess(locationIdentity); FloatingAccessNode floatingNode = accessNode.asFloatingNode(lastLocationAccess); - floatingNode.setNullCheck(accessNode.getNullCheck()); ValueAnchorNode anchor = null; GuardingNode guard = accessNode.getGuard(); if (guard != null) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -86,10 +86,11 @@ @Override protected void run(StructuredGraph graph) { - assert checkFixedDeopts(graph); - ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null); - - graph.setGuardsStage(GuardsStage.AFTER_FSA); + assert graph.getGuardsStage().ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal() && checkFixedDeopts(graph); + if (graph.getGuardsStage().ordinal() < GuardsStage.AFTER_FSA.ordinal()) { + ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null); + graph.setGuardsStage(GuardsStage.AFTER_FSA); + } } private static boolean checkFixedDeopts(StructuredGraph graph) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -95,12 +95,13 @@ GuardNode guard = nullGuarded.get(access.object()); if (guard != null && isImplicitNullCheck(access.nullCheckLocation())) { access.setGuard(guard.getGuard()); - Access fixedAccess = access; + FixedAccessNode fixedAccess; if (access instanceof FloatingAccessNode) { fixedAccess = ((FloatingAccessNode) access).asFixedNode(); - replaceCurrent((FixedWithNextNode) fixedAccess.asNode()); + replaceCurrent(fixedAccess.asNode()); + } else { + fixedAccess = (FixedAccessNode) access; } - assert fixedAccess instanceof FixedNode; fixedAccess.setNullCheck(true); LogicNode condition = guard.condition(); guard.replaceAndDelete(fixedAccess.asNode()); @@ -185,14 +186,17 @@ @Override protected void run(StructuredGraph graph, MidTierContext context) { - SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); - schedule.apply(graph); + if (graph.getGuardsStage().ordinal() < GuardsStage.FIXED_DEOPTS.ordinal()) { + SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); + schedule.apply(graph); - for (Block block : schedule.getCFG().getBlocks()) { - processBlock(block, schedule, context.getTarget().implicitNullCheckLimit); + for (Block block : schedule.getCFG().getBlocks()) { + processBlock(block, schedule, context != null ? context.getTarget().implicitNullCheckLimit : 0); + } + graph.setGuardsStage(GuardsStage.FIXED_DEOPTS); } - graph.setGuardsStage(GuardsStage.FIXED_DEOPTS); + assert graph.getNodes(GuardNode.class).isEmpty(); } private static void processBlock(Block block, SchedulePhase schedule, int implicitNullCheckLimit) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Dec 11 21:57:10 2013 +0100 @@ -1297,6 +1297,7 @@ public static Map inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) { final NodeInputList parameters = invoke.callTarget().arguments(); StructuredGraph graph = invoke.asNode().graph(); + assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal(); FrameState stateAfter = invoke.stateAfter(); assert stateAfter == null || stateAfter.isAlive(); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -89,7 +89,7 @@ } @Override - public GuardingNode createNullCheckGuard(GuardedNode guardedNode, ValueNode object) { + public GuardingNode createNullCheckGuard(FixedNode before, GuardedNode guardedNode, ValueNode object) { if (ObjectStamp.isObjectNonNull(object)) { // Short cut creation of null check guard if the object is known to be non-null. return null; @@ -97,10 +97,10 @@ StructuredGraph graph = guardedNode.asNode().graph(); if (graph.getGuardsStage().ordinal() > GuardsStage.FLOATING_GUARDS.ordinal()) { NullCheckNode nullCheck = graph.add(new NullCheckNode(object)); - graph.addBeforeFixed((FixedNode) guardedNode, nullCheck); + graph.addBeforeFixed(before, nullCheck); return nullCheck; } else { - GuardingNode guard = createGuard(graph.unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true); + GuardingNode guard = createGuard(before, graph.unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true); assert guardedNode.getGuard() == null; guardedNode.setGuard(guard); return guard; @@ -108,8 +108,8 @@ } @Override - public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) { - return createGuard(condition, deoptReason, action, false); + public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) { + return createGuard(before, condition, deoptReason, action, false); } @Override @@ -117,11 +117,32 @@ return context.getAssumptions(); } + private class DummyGuardHandle extends ValueNode implements GuardedNode { + @Input private GuardingNode guard; + + public DummyGuardHandle(GuardingNode guard) { + super(StampFactory.forVoid()); + this.guard = guard; + } + + public GuardingNode getGuard() { + return guard; + } + + public void setGuard(GuardingNode guard) { + updateUsages(this.guard == null ? null : this.guard.asNode(), guard == null ? null : guard.asNode()); + this.guard = guard; + } + + @Override + public ValueNode asNode() { + return this; + } + + } + @Override - public GuardingNode createGuard(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) { - if (condition.graph().getGuardsStage().ordinal() > StructuredGraph.GuardsStage.FLOATING_GUARDS.ordinal()) { - throw new GraalInternalError("Cannot create guards after guard lowering"); - } + public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) { if (OptEliminateGuards.getValue()) { for (Node usage : condition.usages()) { if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).negated() == negated) { @@ -129,12 +150,21 @@ } } } - GuardNode newGuard = guardAnchor.asNode().graph().unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated)); - if (OptEliminateGuards.getValue()) { - activeGuards.grow(); - activeGuards.mark(newGuard); + StructuredGraph graph = before.graph(); + if (condition.graph().getGuardsStage().ordinal() >= StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal()) { + FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, deoptReason, action, negated)); + graph.addBeforeFixed(before, fixedGuard); + DummyGuardHandle handle = graph.add(new DummyGuardHandle(fixedGuard)); + fixedGuard.lower(this); + return handle.getGuard(); + } else { + GuardNode newGuard = graph.unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated)); + if (OptEliminateGuards.getValue()) { + activeGuards.grow(); + activeGuards.mark(newGuard); + } + return newGuard; } - return newGuard; } @Override diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Wed Dec 11 21:57:10 2013 +0100 @@ -891,7 +891,7 @@ closure.apply(cfg.getNodeToBlock().get(pred)); } } else { - // For the time being, only FrameStates can be connected to StateSplits. + // For the time being, FrameStates can only be connected to NodeWithState. if (!(usage instanceof FrameState)) { throw new SchedulingError(usage.toString()); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Wed Dec 11 21:57:10 2013 +0100 @@ -325,7 +325,7 @@ this.method = info.method; this.guardsStage = guardsStage; this.values = new Object[info.getParameterCount()]; - this.hash = info.method.hashCode(); + this.hash = info.method.hashCode() + 31 * guardsStage.hashCode(); } protected void setParam(int paramIdx, Object value) { @@ -475,8 +475,7 @@ ResolvedJavaMethod method = snippetGraph.method(); Signature signature = method.getSignature(); - Assumptions assumptions = providers.getReplacements().getAssumptions(); - PhaseContext phaseContext = new PhaseContext(providers, assumptions); + PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false)); // Copy snippet graph, replacing constant parameters with given arguments final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method()); @@ -578,11 +577,14 @@ } } while (exploded); + GuardsStage guardsStage = args.cacheKey.guardsStage; // Perform lowering on the snippet - snippetCopy.setGuardsStage(args.cacheKey.guardsStage); + if (guardsStage.ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal()) { + new GuardLoweringPhase().apply(snippetCopy, null); + } + snippetCopy.setGuardsStage(guardsStage); try (Scope s = Debug.scope("LoweringSnippetTemplate", snippetCopy)) { - PhaseContext c = new PhaseContext(providers, new Assumptions(false)); - new LoweringPhase(new CanonicalizerPhase(true)).apply(snippetCopy, c); + new LoweringPhase(new CanonicalizerPhase(true)).apply(snippetCopy, phaseContext); } catch (Throwable e) { throw Debug.handle(e); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -31,6 +31,7 @@ import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.GuardsStage; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; @@ -96,9 +97,15 @@ * @param replacementGraph a replacement (i.e., snippet or method substitution) graph */ protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) { - replacementGraph.setGuardsStage(graph().getGuardsStage()); final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.assumptions()); - try (Scope s = Debug.scope("LoweringReplacement", replacementGraph)) { + GuardsStage guardsStage = graph().getGuardsStage(); + if (guardsStage.ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal()) { + new GuardLoweringPhase().apply(replacementGraph, null); + if (guardsStage.ordinal() >= GuardsStage.AFTER_FSA.ordinal()) { + new FrameStateAssignmentPhase().apply(replacementGraph); + } + } + try (Scope s = Debug.scope("LoweringSnippetTemplate", replacementGraph)) { new LoweringPhase(new CanonicalizerPhase(true)).apply(replacementGraph, c); } catch (Throwable e) { throw Debug.handle(e); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Wed Dec 11 21:57:10 2013 +0100 @@ -130,19 +130,14 @@ } private void processNodeWithState(NodeWithState nodeWithState, final BlockT state, final GraphEffectList effects) { - FrameState stateAfter = nodeWithState.getState(); - if (stateAfter != null) { - if (stateAfter.usages().count() > 1) { - if (nodeWithState instanceof StateSplit) { - StateSplit split = (StateSplit) nodeWithState; - stateAfter = (FrameState) stateAfter.copyWithInputs(); - split.setStateAfter(stateAfter); - } else { - throw GraalInternalError.shouldNotReachHere(); - } + FrameState frameState = nodeWithState.getState(); + if (frameState != null) { + if (frameState.usages().count() > 1) { + nodeWithState.asNode().replaceFirstInput(frameState, frameState.copyWithInputs()); + frameState = nodeWithState.getState(); } final HashSet virtual = new HashSet<>(); - stateAfter.applyToNonVirtual(new NodeClosure() { + frameState.applyToNonVirtual(new NodeClosure() { @Override public void apply(Node usage, ValueNode value) { @@ -203,7 +198,7 @@ } else { v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue()); } - effects.addVirtualMapping(stateAfter, v); + effects.addVirtualMapping(frameState, v); } } } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java Wed Dec 11 21:57:10 2013 +0100 @@ -91,18 +91,24 @@ boolean success = true; for (Node node : obsoleteNodes) { if (flood.isMarked(node)) { - TTY.print("offending node path:"); + TTY.println("offending node path:"); Node current = node; - while (current != null) { - TTY.println(current.toString()); + TTY.print(current.toString()); + while (true) { current = path.get(current); - if (current != null && current instanceof FixedNode && !obsoleteNodes.contains(current)) { - break; + if (current != null) { + TTY.print(" -> " + current.toString()); + if (current instanceof FixedNode && !obsoleteNodes.contains(current)) { + break; + } } } success = false; } } + if (!success) { + TTY.println(); + } return success; } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java Wed Dec 11 21:57:10 2013 +0100 @@ -26,8 +26,22 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.*; -import com.oracle.truffle.api.dsl.test.TypeSystemTest.*; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.DoubleEvaluatedNodeFactory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.EvaluatedNodeFactory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedGenerationFactory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs0Factory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs1Factory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs2Factory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs3Factory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs4Factory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs5Factory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory; +import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ArgumentNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestArguments; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -126,4 +140,120 @@ } } + @Test + public void test0VarArgs1() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs0Factory.getInstance()); + Assert.assertEquals(42, root.getNode().execute1(null)); + } + + abstract static class TestEvaluatedVarArgs0 extends ChildrenNode { + + public abstract Object execute1(VirtualFrame frame, Object... value); + + @Specialization + int call() { + return 42; + } + } + + @Test + public void test1VarArgs1() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs1Factory.getInstance()); + Assert.assertEquals(42, root.getNode().execute1(null, 42)); + } + + @Test(expected = AssertionError.class) + public void test1VarArgs2() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance()); + Assert.assertEquals(-1, root.getNode().execute1(null)); + } + + abstract static class TestEvaluatedVarArgs1 extends ChildrenNode { + + public abstract Object execute1(VirtualFrame frame, Object... value); + + @Specialization + int call(int exp0) { + return exp0; + } + } + + @Test + public void test2VarArgs1() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance()); + Assert.assertEquals(42, root.getNode().execute1(null, 21, 21)); + } + + @Test(expected = AssertionError.class) + public void test2VarArgs2() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance()); + Assert.assertEquals(-1, root.getNode().execute1(null, 42)); + } + + @Test(expected = AssertionError.class) + public void test2VarArgs3() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance()); + Assert.assertEquals(-1, root.getNode().execute1(null)); + } + + abstract static class TestEvaluatedVarArgs2 extends ChildrenNode { + + public abstract Object execute1(VirtualFrame frame, Object... value); + + @Specialization + int call(int exp0, int exp1) { + return exp0 + exp1; + } + } + + @Test + public void test3VarArgs1() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs3Factory.getInstance()); + Assert.assertEquals(42, root.getNode().execute1(null, 42)); + } + + @NodeChild + abstract static class TestEvaluatedVarArgs3 extends ValueNode { + + public abstract Object execute1(VirtualFrame frame, Object... value); + + @Specialization + int call(int exp0) { + return exp0; + } + } + + @Test + public void test4VarArgs1() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs4Factory.getInstance()); + Assert.assertEquals(42, root.getNode().execute1(null, 21, 21)); + } + + @NodeChildren({@NodeChild, @NodeChild}) + abstract static class TestEvaluatedVarArgs4 extends ValueNode { + + public abstract Object execute1(VirtualFrame frame, Object... value); + + @Specialization + int call(int exp0, int exp1) { + return exp0 + exp1; + } + } + + @Test + public void test5VarArgs1() { + TestRootNode root = TestHelper.createRoot(TestEvaluatedVarArgs5Factory.getInstance()); + Assert.assertEquals(42, root.getNode().execute1(null)); + } + + abstract static class TestEvaluatedVarArgs5 extends ValueNode { + + public abstract Object execute1(VirtualFrame frame, Object... value); + + @Specialization + int call() { + return 42; + } + } + } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java Wed Dec 11 21:57:10 2013 +0100 @@ -113,6 +113,11 @@ return name; } + public CodeTreeBuilder getBuilder() { + CodeTree tree = this.bodyTree; + return createBuilder().tree(tree); + } + public CodeTreeBuilder createBuilder() { CodeTreeBuilder builder = new CodeTreeBuilder(null); this.bodyTree = builder.getTree(); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java Wed Dec 11 21:57:10 2013 +0100 @@ -274,16 +274,28 @@ } } } else { + Element enclosing = f.getEnclosingElement(); writeModifiers(f.getModifiers()); - write(useImport(f, f.asType())); - if (f.getEnclosingElement().getKind() == ElementKind.METHOD) { - ExecutableElement method = (ExecutableElement) f.getEnclosingElement(); + boolean varArgs = false; + if (enclosing.getKind() == ElementKind.METHOD) { + ExecutableElement method = (ExecutableElement) enclosing; if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) { - write("..."); + varArgs = true; } } + TypeMirror varType = f.asType(); + if (varArgs) { + if (varType.getKind() == TypeKind.ARRAY) { + varType = ((ArrayType) varType).getComponentType(); + } + write(useImport(f, varType)); + write("..."); + } else { + write(useImport(f, varType)); + } + write(" "); write(f.getSimpleName()); if (init != null) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java Wed Dec 11 21:57:10 2013 +0100 @@ -39,6 +39,7 @@ super(context, node); setEmitErrors(false); setParseNullOnError(false); + setUseVarArgs(true); } @Override diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -478,6 +478,14 @@ return createCastType(typeSystem, sourceType, targetType, true, expression); } + public CodeTree createDeoptimize(CodeTreeBuilder parent) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startStatement(); + builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end(); + builder.end(); + return builder.getRoot(); + } + private class NodeFactoryFactory extends ClassElementFactory { private final Map> childTypes; @@ -1015,7 +1023,7 @@ CodeTreeBuilder access = builder.create(); access.string("this.").string(child.getName()); if (child.getCardinality().isMany()) { - access.string("[").string(String.valueOf(param.getIndex())).string("]"); + access.string("[").string(String.valueOf(param.getSpecificationIndex())).string("]"); } String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName()); @@ -2102,7 +2110,7 @@ return null; } String prefix = expect ? "expect" : "execute"; - return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + param.getIndex(); + return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + param.getSpecificationIndex(); } private List createExecuteChilds(ActualParameter param, Set expectTypes) { @@ -2418,7 +2426,7 @@ throw new AssertionError(); } if (targetParameter.getSpecification().isIndexed()) { - builder.string("[" + targetParameter.getIndex() + "]"); + builder.string("[" + targetParameter.getSpecificationIndex() + "]"); } return builder.getRoot(); } @@ -2470,14 +2478,6 @@ return builder.getRoot(); } - protected CodeTree createDeoptimize(CodeTreeBuilder parent) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - builder.startStatement(); - builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end(); - builder.end(); - return builder.getRoot(); - } - protected CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData current, ActualParameter exceptionParam, String reason) { NodeData node = current.getNode(); SpecializationData generic = node.getGenericSpecialization(); @@ -2729,7 +2729,7 @@ } CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true); clazz.add(executeMethod); - CodeTreeBuilder builder = executeMethod.createBuilder(); + CodeTreeBuilder builder = executeMethod.getBuilder(); CodeTree result = createExecuteBody(builder, specialization, execType); if (result != null) { builder.tree(result); @@ -2757,7 +2757,7 @@ ExecutableTypeData execType = parser.parse(Arrays.asList(executeCached)).get(0); CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false); - CodeTreeBuilder builder = executeMethod.createBuilder(); + CodeTreeBuilder builder = executeMethod.getBuilder(); if (specialization.isGeneric() || specialization.isPolymorphic()) { builder.startThrow().startNew(getContext().getType(AssertionError.class)); @@ -2786,7 +2786,7 @@ NodeData node = specialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); - builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); + builder.tree(createDeoptimize(builder)); builder.declaration(getContext().getTruffleTypes().getNode(), "root", "this"); builder.declaration(getContext().getType(int.class), "depth", "0"); @@ -2851,15 +2851,46 @@ private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) { CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); + CodeTreeBuilder builder = method.createBuilder(); int i = 0; + int signatureIndex = -1; for (VariableElement param : method.getParameters()) { CodeVariableElement var = CodeVariableElement.clone(param); ActualParameter actualParameter = execType.getParameters().get(i); + if (actualParameter.getSpecification().isSignature()) { + signatureIndex++; + } + + String name; if (evaluated && actualParameter.getSpecification().isSignature()) { - var.setName(valueNameEvaluated(actualParameter)); + name = valueNameEvaluated(actualParameter); } else { - var.setName(valueName(actualParameter)); + name = valueName(actualParameter); } + + int varArgCount = getModel().getSignatureSize() - signatureIndex; + if (evaluated && actualParameter.isVarArgs()) { + ActualParameter baseVarArgs = actualParameter; + name = valueName(baseVarArgs) + "Args"; + + builder.startAssert().string(name).string(" != null").end(); + builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end(); + if (varArgCount > 0) { + List varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size()); + for (ActualParameter varArg : varArgsParameter) { + if (varArgCount <= 0) { + break; + } + TypeMirror type = baseVarArgs.getType(); + if (type.getKind() == TypeKind.ARRAY) { + type = ((ArrayType) type).getComponentType(); + } + builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getVarArgsIndex() + "]"); + varArgCount--; + } + } + } + var.setName(name); method.getParameters().set(i, var); i++; } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java Wed Dec 11 21:57:10 2013 +0100 @@ -78,6 +78,13 @@ this.assumptions = splitSource.assumptions; } + public int getSignatureSize() { + if (getSpecializations() != null && !getSpecializations().isEmpty()) { + return getSpecializations().get(0).getSignatureSize(); + } + return 0; + } + public boolean needsFrame(ProcessorContext context) { for (SpecializationData specialization : specializations) { if (!specialization.isReachable()) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Wed Dec 11 21:57:10 2013 +0100 @@ -205,6 +205,7 @@ finalizeSpecializations(elements, splittedNode); verifyNode(splittedNode, elements); + expandExecutableTypeVarArgs(splittedNode); createPolymorphicSpecializations(splittedNode); assignShortCircuitsToSpecializations(splittedNode); } @@ -217,6 +218,26 @@ return node; } + private static void expandExecutableTypeVarArgs(NodeData node) { + for (ExecutableTypeData executableMethod : node.getExecutableTypes()) { + if (!(executableMethod.getMethod().isVarArgs() && executableMethod.getSpecification().isVariableRequiredArguments())) { + continue; + } + int expandArguments = node.getSignatureSize() - executableMethod.getSignatureSize(); + if (expandArguments > 0) { + int signatureSize = executableMethod.getSignatureSize(); + ActualParameter parameter = executableMethod.getSignatureParameter(signatureSize - 1); + for (int i = 0; i < expandArguments; i++) { + int newVarArgsIndex = parameter.getVarArgsIndex() + i + 1; + int newSpecificationIndex = parameter.getSpecificationIndex() + i + 1; + executableMethod.getParameters().add( + new ActualParameter(parameter.getSpecification(), parameter.getTypeSystemType(), newSpecificationIndex, newVarArgsIndex, parameter.isImplicit())); + } + + } + } + } + private void createPolymorphicSpecializations(NodeData node) { if (!node.needsRewrites(context) || !node.isPolymorphic()) { node.setPolymorphicSpecializations(Collections. emptyList()); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java Wed Dec 11 21:57:10 2013 +0100 @@ -261,7 +261,7 @@ if (getParameters().isEmpty() || !Utils.typeEquals(getParameters().get(0).getType(), frameType)) { ParameterSpec frameSpec = getSpecification().findParameterSpec("frame"); if (frameSpec != null) { - getParameters().add(0, new ActualParameter(frameSpec, frameType, -1, false)); + getParameters().add(0, new ActualParameter(frameSpec, frameType, -1, -1, false)); } } } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java Wed Dec 11 21:57:10 2013 +0100 @@ -33,49 +33,56 @@ private TypeData typeSystemType; private TemplateMethod method; private final String localName; - private final int index; + private final int specificationIndex; + private final int varArgsIndex; private final boolean implicit; private final TypeMirror type; - public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) { + public ActualParameter(ParameterSpec specification, TypeMirror actualType, int specificationIndex, int varArgsIndex, boolean implicit) { this.specification = specification; this.type = actualType; this.typeSystemType = null; - this.index = index; + this.specificationIndex = specificationIndex; this.implicit = implicit; String valueName = specification.getName() + "Value"; if (specification.isIndexed()) { - valueName += index; + valueName += specificationIndex; } + this.varArgsIndex = varArgsIndex; this.localName = valueName; } - public ActualParameter(ParameterSpec specification, TypeData actualType, int index, boolean implicit) { - this(specification, actualType.getPrimitiveType(), index, implicit); + public ActualParameter(ParameterSpec specification, TypeData actualType, int specificationIndex, int varArgsIndex, boolean implicit) { + this(specification, actualType.getPrimitiveType(), specificationIndex, varArgsIndex, implicit); this.typeSystemType = actualType; } public ActualParameter(ActualParameter parameter, TypeData otherType) { - this(parameter.specification, otherType, parameter.index, parameter.implicit); + this(parameter.specification, otherType, parameter.specificationIndex, parameter.varArgsIndex, parameter.implicit); } public ActualParameter(ActualParameter parameter) { this.specification = parameter.specification; this.type = parameter.type; this.typeSystemType = parameter.typeSystemType; - this.index = parameter.index; + this.specificationIndex = parameter.specificationIndex; this.implicit = parameter.implicit; this.localName = parameter.localName; + this.varArgsIndex = parameter.varArgsIndex; + } + + public int getVarArgsIndex() { + return varArgsIndex; } public boolean isImplicit() { return implicit; } - public int getIndex() { - return index; + public int getSpecificationIndex() { + return specificationIndex; } public String getLocalName() { @@ -102,6 +109,10 @@ return typeSystemType; } + public boolean isVarArgs() { + return varArgsIndex >= 0; + } + public ActualParameter getPreviousParameter() { return method.getPreviousParam(this); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java Wed Dec 11 21:57:10 2013 +0100 @@ -37,6 +37,7 @@ private final List optional = new ArrayList<>(); private final List required = new ArrayList<>(); + private int minimumRequiredArguments; private boolean variableRequiredArguments; private List typeDefinitions; @@ -44,6 +45,14 @@ this.returnType = returnType; } + public void setMinimumRequiredArguments(int minimumRequiredArguments) { + this.minimumRequiredArguments = minimumRequiredArguments; + } + + public int getMinimumRequiredArguments() { + return minimumRequiredArguments; + } + public void setVariableRequiredArguments(boolean variableArguments) { this.variableRequiredArguments = variableArguments; } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java Wed Dec 11 21:57:10 2013 +0100 @@ -202,6 +202,17 @@ return prev; } + public int getSignatureSize() { + int signatureSize = 0; + for (ActualParameter parameter : getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + signatureSize++; + } + return signatureSize; + } + public Signature getSignature() { Signature signature = new Signature(); for (ActualParameter parameter : getReturnTypeAndParameters()) { diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java Wed Dec 11 21:57:10 2013 +0100 @@ -44,12 +44,21 @@ private boolean emitErrors = true; private boolean parseNullOnError = false; + private boolean useVarArgs = false; public TemplateMethodParser(ProcessorContext context, T template) { this.template = template; this.context = context; } + protected void setUseVarArgs(boolean useVarArgs) { + this.useVarArgs = useVarArgs; + } + + public boolean isUseVarArgs() { + return useVarArgs; + } + public boolean isEmitErrors() { return emitErrors; } @@ -140,7 +149,7 @@ ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); - ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false); + ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, -1, false); if (returnTypeMirror == null) { if (emitErrors) { E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); @@ -161,7 +170,7 @@ parameterTypes.add(var.asType()); } - List parameters = parseParameters(methodSpecification, parameterTypes); + List parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method.isVarArgs()); if (parameters == null) { if (isEmitErrors()) { E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); @@ -201,7 +210,7 @@ * ones are cut and used to parse the optional parameters. All those remaining parameters must * be consumed otherwise its an error. */ - private List parseParameters(MethodSpec spec, List parameterTypes) { + private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { List implicitTypes = spec.getImplicitRequiredTypes(); int offset = -1; @@ -211,7 +220,7 @@ offset++; types = new ConsumableListIterator<>(new ArrayList<>(implicitTypes)); types.data.addAll(parameterTypes.subList(offset, parameterTypes.size())); - parsedRequired = parseParametersRequired(spec, types); + parsedRequired = parseParametersRequired(spec, types, varArgs); } if (parsedRequired == null && offset >= 0) { @@ -244,7 +253,7 @@ int oldIndex = types.getIndex(); int optionalCount = 1; for (ParameterSpec paramspec : optionals) { - ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, false); + ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, -1, false); if (optionalParam != null) { optionals.consume(optionalCount); types.consume(); @@ -264,9 +273,10 @@ return parsedParams; } - private List parseParametersRequired(MethodSpec spec, ConsumableListIterator types) { + private List parseParametersRequired(MethodSpec spec, ConsumableListIterator types, boolean varArgs) { List parsedParams = new ArrayList<>(); + int varArgsParameterIndex = -1; int specificationParameterIndex = 0; ConsumableListIterator required = new ConsumableListIterator<>(spec.getRequired()); while (required.get() != null || types.get() != null) { @@ -278,8 +288,15 @@ } break; } + TypeMirror actualType = types.get(); + if (varArgs && types.isLast()) { + if (actualType.getKind() == TypeKind.ARRAY) { + actualType = ((ArrayType) actualType).getComponentType(); + } + varArgsParameterIndex++; + } boolean implicit = types.getIndex() < spec.getImplicitRequiredTypes().size(); - ActualParameter resolvedParameter = matchParameter(required.get(), types.get(), template, specificationParameterIndex, implicit); + ActualParameter resolvedParameter = matchParameter(required.get(), actualType, template, specificationParameterIndex, varArgsParameterIndex, implicit); if (resolvedParameter == null) { if (required.get().getCardinality() == Cardinality.MANY) { required.consume(); @@ -289,7 +306,16 @@ return null; } else { parsedParams.add(resolvedParameter); - types.consume(); + + if (varArgs && types.isLast()) { + /* Both varargs spec and varargs definition. Need to consume to terminate. */ + if (required.get().getCardinality() == Cardinality.MANY) { + types.consume(); + } + } else { + types.consume(); + } + if (required.get().getCardinality() == Cardinality.ONE) { required.consume(); specificationParameterIndex = 0; @@ -299,7 +325,7 @@ } } - if (!types.toList().isEmpty()) { + if (!types.toList().isEmpty() && !(varArgs && types.isLast())) { // additional types -> error return null; } @@ -311,7 +337,7 @@ return parsedParams; } - private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int index, boolean implicit) { + private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int specificationIndex, int varArgsIndex, boolean implicit) { TypeMirror resolvedType = mirror; if (hasError(resolvedType)) { resolvedType = context.resolveNotYetCompiledType(mirror, originalTemplate); @@ -323,9 +349,9 @@ TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); if (resolvedTypeData != null) { - return new ActualParameter(specification, resolvedTypeData, index, implicit); + return new ActualParameter(specification, resolvedTypeData, specificationIndex, varArgsIndex, implicit); } else { - return new ActualParameter(specification, resolvedType, index, implicit); + return new ActualParameter(specification, resolvedType, specificationIndex, varArgsIndex, implicit); } } @@ -346,6 +372,10 @@ return data.get(index); } + public boolean isLast() { + return index == data.size() - 1; + } + public E consume() { return consume(1); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java Wed Dec 11 21:57:10 2013 +0100 @@ -93,9 +93,11 @@ } else { ActualParameter p; if (parameter.getTypeSystemType() != null) { - p = new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getIndex(), parameter.isImplicit()); + p = new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getSpecificationIndex(), + specializationParameter.getVarArgsIndex(), parameter.isImplicit()); } else { - p = new ActualParameter(specializationParameter.getSpecification(), parameter.getType(), specializationParameter.getIndex(), parameter.isImplicit()); + p = new ActualParameter(specializationParameter.getSpecification(), parameter.getType(), specializationParameter.getSpecificationIndex(), + specializationParameter.getVarArgsIndex(), parameter.isImplicit()); } newParameters.add(p); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java Wed Dec 11 21:57:10 2013 +0100 @@ -221,7 +221,7 @@ } builder.startElseBlock(); - builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); + builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); builder.end(); return method; @@ -248,7 +248,7 @@ } builder.startElseBlock(); - builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); + builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); builder.end(); diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java Wed Dec 11 21:57:10 2013 +0100 @@ -59,10 +59,6 @@ this.parser = parser; } - public CallTarget findFunction(String name) { - return context.getFunctionRegistry().lookup(name); - } - public void startFunction() { frameDescriptor = new FrameDescriptor(); } diff -r 5a3491b0c2f0 -r d64c0112fb94 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java Mon Dec 09 21:40:45 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java Wed Dec 11 21:57:10 2013 +0100 @@ -140,22 +140,21 @@ } return new InlinableCallNode((DefaultCallTarget) function, clonedArgs); } + // got a call target that is not inlinable (should not occur for SL) + return new DispatchedCallNode(defaultFunction, clonedArgs); + } else { + throw new AssertionError(); } - // got a call target that is not inlinable (should not occur for SL) - return new DispatchedCallNode(function, clonedArgs); } } private static final class InlinableCallNode extends DispatchedCallNode implements InlinableCallSite { - private final DefaultCallTarget inlinableTarget; - @CompilationFinal private int callCount; InlinableCallNode(DefaultCallTarget function, ArgumentsNode arguments) { super(function, arguments); - this.inlinableTarget = function; } @Override @@ -170,7 +169,7 @@ @Override public Node getInlineTree() { - RootNode root = inlinableTarget.getRootNode(); + RootNode root = function.getRootNode(); if (root instanceof FunctionRootNode) { return ((FunctionRootNode) root).getUninitializedBody(); } @@ -182,7 +181,7 @@ CompilerAsserts.neverPartOfCompilation(); TypedNode functionCall = null; - RootNode root = inlinableTarget.getRootNode(); + RootNode root = function.getRootNode(); if (root instanceof FunctionRootNode) { functionCall = ((FunctionRootNode) root).inline(NodeUtil.cloneNode(args)); } @@ -204,7 +203,7 @@ @Override public CallTarget getCallTarget() { - return inlinableTarget; + return function; } } @@ -212,9 +211,9 @@ private static class DispatchedCallNode extends TypedNode { @Child protected ArgumentsNode args; - protected final CallTarget function; + protected final DefaultCallTarget function; - DispatchedCallNode(CallTarget function, ArgumentsNode arguments) { + DispatchedCallNode(DefaultCallTarget function, ArgumentsNode arguments) { this.args = adoptChild(arguments); this.function = function; } diff -r 5a3491b0c2f0 -r d64c0112fb94 mxtool/mx.py --- a/mxtool/mx.py Mon Dec 09 21:40:45 2013 +0100 +++ b/mxtool/mx.py Wed Dec 11 21:57:10 2013 +0100 @@ -2155,13 +2155,17 @@ log('{0} files were modified'.format(len(modified))) if len(modified) != 0: + arcbase = _primary_suite.dir if args.backup: backup = os.path.abspath('eclipseformat.backup.zip') - arcbase = _primary_suite.dir zf = zipfile.ZipFile(backup, 'w', zipfile.ZIP_DEFLATED) - for fi in modified: - arcname = os.path.relpath(fi.path, arcbase).replace(os.sep, '/') + for fi in modified: + name = os.path.relpath(fi.path, arcbase) + log(' - {0}'.format(name)) + if args.backup: + arcname = name.replace(os.sep, '/') zf.writestr(arcname, fi.content) + if args.backup: zf.close() log('Wrote backup of {0} modified files to {1}'.format(len(modified), backup)) return 1 diff -r 5a3491b0c2f0 -r d64c0112fb94 src/cpu/x86/vm/globals_x86.hpp --- a/src/cpu/x86/vm/globals_x86.hpp Mon Dec 09 21:40:45 2013 +0100 +++ b/src/cpu/x86/vm/globals_x86.hpp Wed Dec 11 21:57:10 2013 +0100 @@ -79,7 +79,8 @@ // GC Ergo Flags define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread -define_pd_global(uintx, TypeProfileLevel, 111); +// Disabled in GRAAL until HotSpotMethodData is updated to be aware of the new profiling tags +define_pd_global(uintx, TypeProfileLevel, GRAAL_ONLY(0) NOT_GRAAL(111)); #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \ \ diff -r 5a3491b0c2f0 -r d64c0112fb94 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Mon Dec 09 21:40:45 2013 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Wed Dec 11 21:57:10 2013 +0100 @@ -469,25 +469,10 @@ return JNIHandles::make_local(THREAD, field_array()); C2V_END -C2V_VMENTRY(jobject, getMethods, (JNIEnv *, jobject, jobject klass)) - ResourceMark rm; - +C2V_VMENTRY(jlong, getClassInitializer, (JNIEnv *, jobject, jobject klass)) instanceKlassHandle k(THREAD, java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaClass(klass))); - Array* methods = k->methods(); - int methods_length = methods->length(); - - // Allocate result - objArrayOop r = oopFactory::new_objArray(SystemDictionary::HotSpotResolvedJavaMethod_klass(), methods_length, CHECK_NULL); - objArrayHandle result (THREAD, r); - - for (int i = 0; i < methods_length; i++) { - methodHandle method(THREAD, methods->at(i)); - Handle holder = JNIHandles::resolve(klass); - oop m = VMToCompiler::createResolvedJavaMethod(holder, method(), THREAD); - result->obj_at_put(i, m); - } - - return JNIHandles::make_local(THREAD, result()); + Method* clinit = k->class_initializer(); + return (jlong) (address) clinit; C2V_END C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv *env, jobject, jlong addr)) @@ -966,7 +951,7 @@ {CC"lookupFieldInPool", CC"("METASPACE_CONSTANT_POOL"IB)"FIELD, FN_PTR(lookupFieldInPool)}, {CC"resolveMethod", CC"("HS_RESOLVED_TYPE STRING STRING")"METHOD, FN_PTR(resolveMethod)}, {CC"getInstanceFields", CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_FIELD, FN_PTR(getInstanceFields)}, - {CC"getMethods", CC"("HS_RESOLVED_TYPE")["HS_RESOLVED_METHOD, FN_PTR(getMethods)}, + {CC"getClassInitializer", CC"("HS_RESOLVED_TYPE")"METASPACE_METHOD, FN_PTR(getClassInitializer)}, {CC"hasFinalizableSubclass", CC"("HS_RESOLVED_TYPE")Z", FN_PTR(hasFinalizableSubclass)}, {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, {CC"getMetaspaceMethod", CC"("CLASS"I)"METASPACE_METHOD, FN_PTR(getMetaspaceMethod)}, diff -r 5a3491b0c2f0 -r d64c0112fb94 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Mon Dec 09 21:40:45 2013 +0100 +++ b/src/share/vm/oops/methodData.hpp Wed Dec 11 21:57:10 2013 +0100 @@ -2193,7 +2193,7 @@ // Return (uint)-1 for overflow. uint trap_count(int reason) const { - assert((uint)reason < _trap_hist_limit, "oob"); + assert((uint)reason < GRAAL_ONLY(2*) _trap_hist_limit, "oob"); return (int)((_trap_hist._array[reason]+1) & _trap_hist_mask) - 1; } // For loops: @@ -2202,7 +2202,7 @@ uint inc_trap_count(int reason) { // Count another trap, anywhere in this method. assert(reason >= 0, "must be single trap"); - assert((uint)reason < _trap_hist_limit, "oob"); + assert((uint)reason < GRAAL_ONLY(2*) _trap_hist_limit, "oob"); uint cnt1 = 1 + _trap_hist._array[reason]; if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... _trap_hist._array[reason] = cnt1; diff -r 5a3491b0c2f0 -r d64c0112fb94 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon Dec 09 21:40:45 2013 +0100 +++ b/src/share/vm/runtime/arguments.cpp Wed Dec 11 21:57:10 2013 +0100 @@ -2336,6 +2336,10 @@ warning("forcing ScavengeRootsInCode non-zero because Graal is enabled"); ScavengeRootsInCode = 1; } + if (TypeProfileLevel != 0) { + warning("forcing TypeProfileLevel to 0 as HotSpotMethodData can not yet handle the new type profile info"); + TypeProfileLevel = 0; + } #endif // Need to limit the extent of the padding to reasonable size.