Mercurial > hg > truffle
changeset 10768:058abc2b59a5
Merge
author | Lukas Stadler <lukas.stadler@jku.at> |
---|---|
date | Mon, 15 Jul 2013 17:54:00 +0200 |
parents | 88d0dc388450 (current diff) dd7a8807378b (diff) |
children | 395d34c10e26 f0fdbb2b7135 |
files | graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java |
diffstat | 17 files changed, 228 insertions(+), 56 deletions(-) [+] |
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon Jul 15 17:54:00 2013 +0200 @@ -70,6 +70,11 @@ private ValueNode lastInstructionPrinted; // Debugging only /** + * Records whether the code being generated makes at least one foreign call. + */ + private boolean hasForeignCall; + + /** * Checks whether the supplied constant can be used without loading it into a register for store * operations, i.e., on the right hand side of a memory access. * @@ -116,6 +121,13 @@ } /** + * Determines whether the code being generated makes at least one foreign call. + */ + public boolean hasForeignCall() { + return hasForeignCall; + } + + /** * Returns the operand that has been previously initialized by * {@link #setResult(ValueNode, Value)} with the result of an instruction. * @@ -601,6 +613,7 @@ emitMove(loc, arg); argLocations[i] = loc; } + this.hasForeignCall = true; emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state); if (isLegal(linkageCc.getReturn())) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon Jul 15 17:54:00 2013 +0200 @@ -153,11 +153,13 @@ // - has no spill slots or other slots allocated during register allocation // - has no callee-saved registers // - has no incoming arguments passed on the stack - // - has no instructions with debug info + // - has no deoptimization points + // - makes no foreign calls (which require an aligned stack) AMD64HotSpotLIRGenerator gen = (AMD64HotSpotLIRGenerator) lirGen; FrameMap frameMap = gen.frameMap; LIR lir = gen.lir; - boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame(); + assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; + boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall(); Stub stub = gen.getStub(); AbstractAssembler masm = createAssembler(frameMap);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Mon Jul 15 17:54:00 2013 +0200 @@ -69,10 +69,12 @@ WriteBarrierType barrierType = node.getWriteBarrierType(); if (barrierType == WriteBarrierType.PRECISE) { if (useG1GC()) { - G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(node.object(), null, node.location(), true, node.getNullCheck())); - preBarrier.setDeoptimizationState(node.getDeoptimizationState()); - node.setNullCheck(false); - graph.addBeforeFixed(node, preBarrier); + if (node.isInitialized()) { + G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(node.object(), null, node.location(), true, node.getNullCheck())); + preBarrier.setDeoptimizationState(node.getDeoptimizationState()); + node.setNullCheck(false); + graph.addBeforeFixed(node, preBarrier); + } graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.value(), node.location(), true))); } else { graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.location(), true))); @@ -116,9 +118,11 @@ private static void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) { if (useG1GC()) { - G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + if (node.isInitialized()) { + G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier); + } G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); - graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier); graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier); } else { SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon Jul 15 17:54:00 2013 +0200 @@ -259,7 +259,7 @@ args.addConst("size", size); args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); - args.addConst("fillContents", useG1GC() || newInstanceNode.fillContents()); + args.addConst("fillContents", newInstanceNode.fillContents()); SnippetTemplate template = template(args); Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args); @@ -284,7 +284,7 @@ args.add("prototypeMarkWord", arrayType.prototypeMarkWord()); args.addConst("headerSize", headerSize); args.addConst("log2ElementSize", log2ElementSize); - args.addConst("fillContents", useG1GC() || newArrayNode.fillContents()); + args.addConst("fillContents", newArrayNode.fillContents()); SnippetTemplate template = template(args); Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); @@ -295,7 +295,7 @@ Arguments args = new Arguments(allocateArrayDynamic); args.add("elementType", newArrayNode.getElementType()); args.add("length", newArrayNode.length()); - args.addConst("fillContents", useG1GC() || newArrayNode.fillContents()); + args.addConst("fillContents", newArrayNode.fillContents()); SnippetTemplate template = template(args); template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon Jul 15 17:54:00 2013 +0200 @@ -54,7 +54,7 @@ private static Object instanceClone(Object src, Word hub, int layoutHelper) { int instanceSize = layoutHelper; Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, useG1GC()); + Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false); Pointer memory = Word.fromObject(result); for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) { @@ -71,7 +71,7 @@ int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, useG1GC()); + Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false); Pointer memory = Word.fromObject(result); for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java Mon Jul 15 17:54:00 2013 +0200 @@ -82,6 +82,11 @@ return elementKind == Kind.Object; } + @Override + public boolean isInitialized() { + return true; + } + public Kind getElementKind() { return elementKind; }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java Mon Jul 15 17:54:00 2013 +0200 @@ -54,4 +54,10 @@ * Return true if the written array is an object array, false if it is a primitive array. */ public abstract boolean isObjectArray(); + + /** + * If {@link #isInitialized()} is true, the memory location contains a valid value. If + * {@link #isInitialized()} is false, the memory location is uninitialized or zero. + */ + public abstract boolean isInitialized(); }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Mon Jul 15 17:54:00 2013 +0200 @@ -37,6 +37,7 @@ @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; + private final boolean initialized; public FrameState stateAfter() { return stateAfter; @@ -56,9 +57,22 @@ return value; } + /** + * If {@link #isInitialized()} is true, the memory location contains a valid value. If + * {@link #isInitialized()} is false, the memory location is uninitialized or zero. + */ + public boolean isInitialized() { + return initialized; + } + public WriteNode(ValueNode object, ValueNode value, ValueNode location, WriteBarrierType barrierType, boolean compress) { + this(object, value, location, barrierType, compress, true); + } + + public WriteNode(ValueNode object, ValueNode value, ValueNode location, WriteBarrierType barrierType, boolean compress, boolean initialized) { super(object, location, StampFactory.forVoid(), barrierType, compress); this.value = value; + this.initialized = initialized; } @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Jul 15 17:54:00 2013 +0200 @@ -65,8 +65,7 @@ if (truffleCompiler == null) { truffleCompiler = new TruffleCompilerImpl(); } - return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleCompilationThreshold.getValue(), TruffleInliningReprofileCount.getValue(), - TruffleInvalidationReprofileCount.getValue()); + return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleCompilationThreshold.getValue()); } @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 15 17:54:00 2013 +0200 @@ -40,19 +40,19 @@ public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, FrameFactory { private static final PrintStream OUT = TTY.out().out(); + private static final int MIN_INVOKES_AFTER_INLINING = 2; - private final int inliningReprofileCount; - private final int invalidationReprofileCount; - - protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold, int inliningReprofileCount, int invalidationReprofileCount) { + protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold) { super(rootNode, descriptor); this.compiler = compiler; this.invokeCounter = compilationThreshold >> 7; this.loopAndInvokeCounter = compilationThreshold; this.originalInvokeCounter = compilationThreshold; this.rootNode.setCallTarget(this); - this.inliningReprofileCount = inliningReprofileCount; - this.invalidationReprofileCount = invalidationReprofileCount; + + if (TruffleProfiling.getValue()) { + registerCallTarget(this); + } } private InstalledCode compiledMethod; @@ -62,6 +62,11 @@ private int loopAndInvokeCounter; private boolean disableCompilation; + // TruffleProfiling + private int callCount; + private int inlinedCallSiteCount; + + // TraceTruffleCompilation long timeCompilationStarted; long timePartialEvaluationFinished; long timeCompilationFinished; @@ -71,6 +76,9 @@ @Override public Object call(PackedFrame caller, Arguments args) { + if (TruffleProfiling.getValue()) { + callCount++; + } if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, compiledMethod != null)) { try { return compiledMethod.execute(this, caller, args); @@ -82,8 +90,9 @@ } } - protected Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { + private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { compiledMethod = null; + int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue(); invokeCounter = invalidationReprofileCount; if (TruffleFunctionInlining.getValue()) { originalInvokeCounter += invalidationReprofileCount; @@ -101,7 +110,8 @@ return executeHelper(caller, args); } else { if (TruffleFunctionInlining.getValue() && inline()) { - invokeCounter = 2; + invokeCounter = MIN_INVOKES_AFTER_INLINING; + int inliningReprofileCount = TruffleInliningReprofileCount.getValue(); loopAndInvokeCounter = inliningReprofileCount; originalInvokeCounter = inliningReprofileCount; } else { @@ -112,10 +122,12 @@ } public boolean inline() { + CompilerAsserts.neverPartOfCompilation(); return new InliningHelper(this).inline(); } public void compile() { + CompilerAsserts.neverPartOfCompilation(); try { compiledMethod = compiler.compile(this); if (compiledMethod == null) { @@ -127,6 +139,9 @@ (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, codeSize); } + if (TruffleProfiling.getValue()) { + resetProfiling(); + } } } catch (Throwable e) { disableCompilation = true; @@ -202,10 +217,14 @@ boolean inlined = false; for (InlinableCallSiteInfo inlinableCallSite : inlinableCallSites) { - if (policy.isWorthInlining(inlinableCallSite) && inlinableCallSite.getCallSite().inline(target)) { + if (!policy.isWorthInlining(inlinableCallSite)) { + break; + } + if (inlinableCallSite.getCallSite().inline(target)) { if (TraceTruffleInlining.getValue()) { printCallSiteInfo(policy, inlinableCallSite, "inlined"); } + target.inlinedCallSiteCount++; inlined = true; break; } @@ -267,7 +286,11 @@ @Override public int compare(InlinableCallSiteInfo cs1, InlinableCallSiteInfo cs2) { - return Double.compare(metric(cs2), metric(cs1)); + int result = (isWorthInlining(cs2) ? 1 : 0) - (isWorthInlining(cs1) ? 1 : 0); + if (result == 0) { + return Double.compare(metric(cs2), metric(cs1)); + } + return result; } }); } @@ -313,4 +336,65 @@ return inlinableCallSites; } } + + private static void resetProfiling() { + for (OptimizedCallTarget callTarget : OptimizedCallTarget.callTargets.keySet()) { + callTarget.callCount = 0; + } + } + + private static void printProfiling() { + List<OptimizedCallTarget> sortedCallTargets = new ArrayList<>(OptimizedCallTarget.callTargets.keySet()); + Collections.sort(sortedCallTargets, new Comparator<OptimizedCallTarget>() { + + @Override + public int compare(OptimizedCallTarget o1, OptimizedCallTarget o2) { + return o2.callCount - o1.callCount; + } + }); + + int totalCallCount = 0; + int totalInlinedCallSiteCount = 0; + int totalNotInlinedCallSiteCount = 0; + int totalNodeCount = 0; + + PrintStream out = TTY.out().out(); + out.println(); + out.printf("%-50s | %-10s | %s / %s | %s\n", "Call Target", "Call Count", "Calls Sites Inlined", "Not Inlined", "Node Count"); + for (OptimizedCallTarget callTarget : sortedCallTargets) { + if (callTarget.callCount == 0) { + continue; + } + + int notInlinedCallSiteCount = InliningHelper.getInlinableCallSites(callTarget).size(); + int nodeCount = NodeUtil.countNodes(callTarget.rootNode); + String comment = callTarget.compiledMethod == null ? " int" : ""; + out.printf("%-50s | %10s | %15s | %15s | %10s%s\n", callTarget.getRootNode(), callTarget.callCount, callTarget.inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, comment); + + totalCallCount += callTarget.callCount; + totalInlinedCallSiteCount += callTarget.inlinedCallSiteCount; + totalNotInlinedCallSiteCount += notInlinedCallSiteCount; + totalNodeCount += nodeCount; + } + out.printf("%-50s | %10s | %15s | %15s | %10s\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount); + } + + private static void registerCallTarget(OptimizedCallTarget callTarget) { + callTargets.put(callTarget, 0); + } + + private static Map<OptimizedCallTarget, Integer> callTargets; + static { + if (TruffleProfiling.getValue()) { + callTargets = new WeakHashMap<>(); + + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + printProfiling(); + } + }); + } + } }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Jul 15 17:54:00 2013 +0200 @@ -64,7 +64,7 @@ private final HotSpotGraalRuntime graalRuntime; private final TruffleCache truffleCache; - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class}; + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class, InvalidInstalledCodeException.class}; public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 15 17:54:00 2013 +0200 @@ -81,5 +81,7 @@ public static final OptionValue<Boolean> TraceTruffleInlining = new OptionValue<>(true); @Option(help = "") public static final OptionValue<Boolean> TraceTruffleInliningDetails = new OptionValue<>(false); + @Option(help = "") + public static final OptionValue<Boolean> TruffleProfiling = new StableOptionValue<>(false); // @formatter:on }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Mon Jul 15 17:54:00 2013 +0200 @@ -365,6 +365,20 @@ void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity); /** + * Initializes the memory at address {@code (this + offset)}. Both the base address and offset + * are in bytes. The memory must be uninitialized or zero prior to this operation. + * <p> + * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void initializeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity); + + /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. * <p> @@ -459,6 +473,16 @@ void writeWord(int offset, WordBase val, LocationIdentity locationIdentity); /** + * Initializes the memory at address {@code (this + offset)}. Both the base address and offset + * are in bytes. The memory must be uninitialized or zero prior to this operation. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void initializeWord(int offset, WordBase val, LocationIdentity locationIdentity); + + /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. *
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Mon Jul 15 17:54:00 2013 +0200 @@ -61,6 +61,7 @@ READ, READ_COMPRESSED, WRITE, + INITIALIZE, ZERO, FROM_UNSIGNED, FROM_SIGNED, @@ -758,6 +759,12 @@ } @Override + @Operation(opcode = Opcode.INITIALIZE) + public void initializeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity) { + unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox()); + } + + @Override @Operation(opcode = Opcode.WRITE) public native void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity); @@ -810,6 +817,12 @@ } @Override + @Operation(opcode = Opcode.INITIALIZE) + public void initializeWord(int offset, WordBase val, LocationIdentity locationIdentity) { + initializeWord(signed(offset), val, locationIdentity); + } + + @Override @Operation(opcode = Opcode.WRITE) public void writeObject(int offset, Object val, LocationIdentity locationIdentity) { writeObject(signed(offset), val, locationIdentity);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon Jul 15 17:54:00 2013 +0200 @@ -38,6 +38,7 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.word.*; +import com.oracle.graal.word.Word.Opcode; import com.oracle.graal.word.Word.Operation; /** @@ -189,7 +190,8 @@ replace(invoke, readOp(graph, arguments.get(0), invoke, location, true)); break; } - case WRITE: { + case WRITE: + case INITIALIZE: { assert arguments.size() == 3 || arguments.size() == 4; Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass())); LocationNode location; @@ -198,7 +200,7 @@ } else { location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3)); } - replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location)); + replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location, operation.opcode())); break; } case ZERO: @@ -335,8 +337,9 @@ return read; } - private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location) { - WriteNode write = graph.add(new WriteNode(base, value, location, WriteBarrierType.NONE, false)); + private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) { + assert op == Opcode.WRITE || op == Opcode.INITIALIZE; + WriteNode write = graph.add(new WriteNode(base, value, location, WriteBarrierType.NONE, false, op == Opcode.WRITE)); write.setStateAfter(invoke.stateAfter()); graph.addBeforeFixed(invoke.asNode(), write); return write;
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Mon Jul 15 17:54:00 2013 +0200 @@ -81,7 +81,7 @@ class TestRootNode extends RootNode { - @Children private ValueNode[] children; + @Children private final ValueNode[] children; public TestRootNode(ValueNode[] children) { this.children = adoptChildren(children);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 15 17:52:35 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 15 17:54:00 2013 +0200 @@ -163,9 +163,11 @@ } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) { kind = NodeFieldKind.CHILD; childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); + assert !Modifier.isFinal(field.getModifiers()) : "child field must not be final (\"" + field.getName() + "\", " + clazz + ")"; } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { kind = NodeFieldKind.CHILDREN; childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); + assert Modifier.isFinal(field.getModifiers()) : "children array field must be final (\"" + field.getName() + "\", " + clazz + ")"; } else { kind = NodeFieldKind.DATA; } @@ -352,51 +354,52 @@ public static void replaceChild(Node parent, Node oldChild, Node newChild) { NodeClass nodeClass = NodeClass.get(parent.getClass()); - long[] fieldOffsets = nodeClass.childOffsets; - for (int i = 0; i < fieldOffsets.length; i++) { - long fieldOffset = fieldOffsets[i]; + for (long fieldOffset : nodeClass.getChildOffsets()) { if (unsafe.getObject(parent, fieldOffset) == oldChild) { - assert assertAssignable(nodeClass, parent, oldChild, newChild); + assert assertAssignable(nodeClass, fieldOffset, newChild); unsafe.putObject(parent, fieldOffset, newChild); } } - long[] childrenOffsets = nodeClass.childrenOffsets; - for (int i = 0; i < childrenOffsets.length; i++) { - long fieldOffset = childrenOffsets[i]; + for (long fieldOffset : nodeClass.getChildrenOffsets()) { Object arrayObject = unsafe.getObject(parent, fieldOffset); if (arrayObject != null) { - assert arrayObject instanceof Node[] : "Children must be instanceof Node[] "; + assert arrayObject instanceof Node[] : "Children array must be instanceof Node[] "; Node[] array = (Node[]) arrayObject; - for (int j = 0; j < array.length; j++) { - if (array[j] == oldChild) { - assert newChild != null && array.getClass().getComponentType().isAssignableFrom(newChild.getClass()) : "Array type does not match"; - array[j] = newChild; - return; + for (int i = 0; i < array.length; i++) { + if (array[i] == oldChild) { + assert assertAssignable(nodeClass, fieldOffset, newChild); + array[i] = newChild; } } } } } - private static boolean assertAssignable(NodeClass clazz, Node parent, Object oldValue, Object newValue) { + private static boolean assertAssignable(NodeClass clazz, long fieldOffset, Object newValue) { if (newValue == null) { return true; } - for (NodeField field : clazz.fields) { - if (field.kind != NodeFieldKind.CHILD) { - continue; - } - if (unsafe.getObject(parent, field.offset) == oldValue) { - if (!field.type.isAssignableFrom(newValue.getClass())) { - assert false : "Child class " + newValue.getClass() + " is not assignable to field " + field.type.getName() + " at " + field.name + " in "; - return false; - } else { - break; + for (NodeField field : clazz.getFields()) { + if (field.getOffset() == fieldOffset) { + if (field.getKind() == NodeFieldKind.CHILD) { + if (field.getType().isAssignableFrom(newValue.getClass())) { + return true; + } else { + assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); + return false; + } + } else if (field.getKind() == NodeFieldKind.CHILDREN) { + if (field.getType().getComponentType().isAssignableFrom(newValue.getClass())) { + return true; + } else { + assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); + return false; + } } } } - return true; + throw new IllegalArgumentException(); } /** Returns all declared fields in the class hierarchy. */