# HG changeset patch # User Thomas Wuerthinger # Date 1427731051 -7200 # Node ID 0b2bd777d9337e818ea09ab9216c9d67dc2020d4 # Parent 00decb5cd984706d39585cc3d3a25bd1dad8bc28# Parent 8529bfcef6f5c8c72dd04650b4307d0196d8a8b4 Merge. diff -r 00decb5cd984 -r 0b2bd777d933 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 Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Mar 30 17:57:31 2015 +0200 @@ -122,6 +122,11 @@ SaveRbp saveRbp; + /** + * Helper instruction to reserve a stack slot for the whole method. Note that the actual users + * of the stack slot might be inserted after stack slot allocation. This dummy instruction + * ensures that the stack slot is alive and gets a real stack slot assigned. + */ private static final class RescueSlotDummyOp extends LIRInstruction { public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RescueSlotDummyOp.class); @@ -144,17 +149,16 @@ private RescueSlotDummyOp rescueSlotOp; private StackSlotValue getOrInitRescueSlot() { + RescueSlotDummyOp op = getOrInitRescueSlotOp(); + return op.getSlot(); + } + + private RescueSlotDummyOp getOrInitRescueSlotOp() { if (rescueSlotOp == null) { // create dummy instruction to keep the rescue slot alive rescueSlotOp = new RescueSlotDummyOp(getResult().getFrameMapBuilder(), getLIRKindTool().getWordKind()); - // insert dummy instruction into the start block - LIR lir = getResult().getLIR(); - List instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock()); - // Note: we do not insert at position 1 to avoid interference with the save rpb op - instructions.add(instructions.size() - 1, rescueSlotOp); - Debug.dump(lir, "created rescue dummy op"); } - return rescueSlotOp.getSlot(); + return rescueSlotOp; } /** @@ -481,7 +485,12 @@ } if (BenchmarkCounters.enabled) { // ensure that the rescue slot is available - getOrInitRescueSlot(); + LIRInstruction op = getOrInitRescueSlotOp(); + // insert dummy instruction into the start block + LIR lir = getResult().getLIR(); + List instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock()); + instructions.add(1, op); + Debug.dump(lir, "created rescue dummy op"); } } diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java Mon Mar 30 17:57:31 2015 +0200 @@ -205,10 +205,9 @@ } private StructuredGraph compile(String test, boolean compileAOT) { - StructuredGraph graph = parseEager(test, AllowAssumptions.YES); - ResolvedJavaMethod method = graph.method(); - try (OverrideScope s = OptionValue.override(ImmutableCode, compileAOT)) { + StructuredGraph graph = parseEager(test, AllowAssumptions.YES); + ResolvedJavaMethod method = graph.method(); CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false); // create suites everytime, as we modify options for the compiler SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites(); @@ -217,8 +216,7 @@ final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, lirSuitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default); addMethod(method, compResult); + return graph; } - - return graph; } } diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoadFieldPlugin.java Mon Mar 30 17:57:31 2015 +0200 @@ -23,7 +23,6 @@ package com.oracle.graal.hotspot.meta; import static com.oracle.graal.compiler.common.GraalOptions.*; -import static com.oracle.graal.java.AbstractBytecodeParser.Options.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; @@ -42,7 +41,7 @@ static final ThreadLocal FieldReadEnabledInImmutableCode = new ThreadLocal<>(); public boolean apply(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) { - if ((InlineDuringParsing.getValue() && !ImmutableCode.getValue()) || b.parsingReplacement()) { + if (!ImmutableCode.getValue() || b.parsingReplacement()) { if (receiver.isConstant()) { JavaConstant asJavaConstant = receiver.asJavaConstant(); return tryReadField(b, field, asJavaConstant); @@ -65,7 +64,7 @@ } public boolean apply(GraphBuilderContext b, ResolvedJavaField staticField) { - if ((InlineDuringParsing.getValue() && !ImmutableCode.getValue()) || b.parsingReplacement()) { + if (!ImmutableCode.getValue() || b.parsingReplacement()) { // Javac does not allow use of "$assertionsDisabled" for a field name but // Eclipse does in which case a suffix is added to the generated field. if (b.parsingReplacement() && staticField.isSynthetic() && staticField.getName().startsWith("$assertionsDisabled")) { diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Mon Mar 30 17:57:31 2015 +0200 @@ -206,7 +206,9 @@ } public void replace(LIR lir, LIRInstruction replacement) { - lir.getLIRforBlock(block).set(index, replacement); + List instructions = lir.getLIRforBlock(block); + assert instructions.get(index).equals(this) : String.format("Replacing the wrong instruction: %s instead of %s", instructions.get(index), this); + instructions.set(index, replacement); } @Override diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Interval.java Mon Mar 30 17:57:31 2015 +0200 @@ -414,7 +414,7 @@ } public void setRegisterPriority(int index, RegisterPriority registerPriority) { - list.set(index * 2, registerPriority.ordinal()); + list.set((index << 1) + 1, registerPriority.ordinal()); } @Override diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java Mon Mar 30 17:57:31 2015 +0200 @@ -29,6 +29,7 @@ import com.oracle.graal.nodeinfo.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; @NodeInfo public final class UnboxNode extends FixedWithNextNode implements Virtualizable, Lowerable, Canonicalizable.Unary { @@ -78,6 +79,9 @@ @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { + if (hasNoUsages() && StampTool.isPointerNonNull(forValue)) { + return null; + } ValueNode synonym = findSynonym(tool.getMetaAccess(), tool.getConstantReflection(), forValue, boxingKind); if (synonym != null) { return synonym; diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java Mon Mar 30 17:57:31 2015 +0200 @@ -122,7 +122,7 @@ /** * Checks whether this {@link Stamp} represents a {@linkplain Stamp#isLegal() legal} pointer - * stamp whose values known to be always null. + * stamp whose values are known to never be null. * * @param stamp the stamp to check * @return true if this stamp represents a legal object stamp whose values are known to be diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java Mon Mar 30 17:57:31 2015 +0200 @@ -208,7 +208,7 @@ } @Override - public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) { + public void replace(ValueNode oldNode, ValueNode newNode) { assert newNode instanceof PhiNode; assert oldNode == instanceOf; newNode.inferStamp(); @@ -239,7 +239,7 @@ } @Override - public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) { + public void replace(ValueNode oldNode, ValueNode newNode) { assert newNode instanceof PhiNode; assert oldNode == instanceOf; newNode.inferStamp(); diff -r 00decb5cd984 -r 0b2bd777d933 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 Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Mon Mar 30 17:57:31 2015 +0200 @@ -722,18 +722,20 @@ new FloatingReadPhase(false, true).apply(snippetCopy); - MemoryAnchorNode memoryAnchor = snippetCopy.add(new MemoryAnchorNode()); - snippetCopy.start().replaceAtUsages(InputType.Memory, memoryAnchor); + MemoryAnchorNode anchor = snippetCopy.add(new MemoryAnchorNode()); + snippetCopy.start().replaceAtUsages(InputType.Memory, anchor); this.snippet = snippetCopy; Debug.dump(snippet, "SnippetTemplate after fixing memory anchoring"); StartNode entryPointNode = snippet.start(); - if (memoryAnchor.hasNoUsages()) { - memoryAnchor.safeDelete(); + if (anchor.hasNoUsages()) { + anchor.safeDelete(); + this.memoryAnchor = null; } else { - snippetCopy.addAfterFixed(snippetCopy.start(), memoryAnchor); + snippetCopy.addAfterFixed(snippetCopy.start(), anchor); + this.memoryAnchor = anchor; } List returnNodes = snippet.getNodes(ReturnNode.TYPE).snapshot(); if (returnNodes.isEmpty()) { @@ -832,6 +834,11 @@ private final ReturnNode returnNode; /** + * The memory anchor (if any) of the snippet. + */ + private final MemoryAnchorNode memoryAnchor; + + /** * Nodes that inherit the {@link StateSplit#stateAfter()} from the replacee during * instantiation. */ @@ -948,7 +955,7 @@ /** * Replaces all usages of {@code oldNode} with direct or indirect usages of {@code newNode}. */ - void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap); + void replace(ValueNode oldNode, ValueNode newNode); } /** @@ -957,48 +964,8 @@ */ public static final UsageReplacer DEFAULT_REPLACER = new UsageReplacer() { - private LocationIdentity getLocationIdentity(Node node) { - if (node instanceof MemoryAccess) { - return ((MemoryAccess) node).getLocationIdentity(); - } else if (node instanceof MemoryProxy) { - return ((MemoryProxy) node).getLocationIdentity(); - } else if (node instanceof MemoryPhiNode) { - return ((MemoryPhiNode) node).getLocationIdentity(); - } else { - return null; - } - } - @Override - public void replace(ValueNode oldNode, ValueNode newNode, MemoryMap mmap) { - if (mmap != null) { - for (Node usage : oldNode.usages().snapshot()) { - LocationIdentity identity = getLocationIdentity(usage); - boolean usageReplaced = false; - if (identity != null && !identity.isImmutable()) { - // lastLocationAccess points into the snippet graph. find a proper - // MemoryCheckPoint inside the snippet graph - MemoryNode lastAccess = mmap.getLastLocationAccess(identity); - - assert lastAccess != null : "no mapping found for lowerable node " + oldNode + ". (No node in the snippet kills the same location as the lowerable node?)"; - if (usage instanceof MemoryAccess) { - MemoryAccess access = (MemoryAccess) usage; - if (access.getLastLocationAccess() == oldNode) { - assert oldNode.graph().isAfterFloatingReadPhase(); - access.setLastLocationAccess(lastAccess); - usageReplaced = true; - } - } else { - assert usage instanceof MemoryProxy || usage instanceof MemoryPhiNode; - usage.replaceFirstInput(oldNode, lastAccess.asNode()); - usageReplaced = true; - } - } - if (!usageReplaced) { - assert newNode != null : "this branch is only valid if we have a newNode for replacement"; - } - } - } + public void replace(ValueNode oldNode, ValueNode newNode) { if (newNode == null) { assert oldNode.hasNoUsages(); } else { @@ -1066,14 +1033,48 @@ return true; } - private class DuplicateMapper implements MemoryMap { + private static class MemoryInputMap implements MemoryMap { + + private final LocationIdentity locationIdentity; + private final MemoryNode lastLocationAccess; + + public MemoryInputMap(ValueNode replacee) { + if (replacee instanceof MemoryAccess) { + MemoryAccess access = (MemoryAccess) replacee; + locationIdentity = access.getLocationIdentity(); + lastLocationAccess = access.getLastLocationAccess(); + } else { + locationIdentity = null; + lastLocationAccess = null; + } + } + + @Override + public MemoryNode getLastLocationAccess(LocationIdentity location) { + if (locationIdentity != null && locationIdentity.equals(location)) { + return lastLocationAccess; + } else { + return null; + } + } + + @Override + public Collection getLocations() { + if (locationIdentity == null) { + return Collections.emptySet(); + } else { + return Collections.singleton(locationIdentity); + } + } + } + + private class MemoryOutputMap extends MemoryInputMap { private final Map duplicates; - private StartNode replaceeStart; - public DuplicateMapper(Map duplicates, StartNode replaceeStart) { + public MemoryOutputMap(ValueNode replacee, Map duplicates) { + super(replacee); this.duplicates = duplicates; - this.replaceeStart = replaceeStart; } @Override @@ -1081,9 +1082,9 @@ MemoryMapNode memoryMap = returnNode.getMemoryMap(); assert memoryMap != null : "no memory map stored for this snippet graph (snippet doesn't have a ReturnNode?)"; MemoryNode lastLocationAccess = memoryMap.getLastLocationAccess(locationIdentity); - assert lastLocationAccess != null; - if (lastLocationAccess instanceof StartNode) { - return replaceeStart; + assert lastLocationAccess != null : locationIdentity; + if (lastLocationAccess == memoryAnchor) { + return super.getLastLocationAccess(locationIdentity); } else { return (MemoryNode) duplicates.get(ValueNodeUtil.asNode(lastLocationAccess)); } @@ -1095,6 +1096,60 @@ } } + private void rewireMemoryGraph(ValueNode replacee, Map duplicates) { + // rewire outgoing memory edges + replaceMemoryUsages(replacee, new MemoryOutputMap(replacee, duplicates)); + + ReturnNode ret = (ReturnNode) duplicates.get(returnNode); + MemoryMapNode memoryMap = ret.getMemoryMap(); + ret.setMemoryMap(null); + memoryMap.safeDelete(); + + if (memoryAnchor != null) { + // rewire incoming memory edges + MemoryAnchorNode memoryDuplicate = (MemoryAnchorNode) duplicates.get(memoryAnchor); + replaceMemoryUsages(memoryDuplicate, new MemoryInputMap(replacee)); + + if (memoryDuplicate.hasNoUsages()) { + memoryDuplicate.graph().removeFixed(memoryDuplicate); + } + } + } + + private static LocationIdentity getLocationIdentity(Node node) { + if (node instanceof MemoryAccess) { + return ((MemoryAccess) node).getLocationIdentity(); + } else if (node instanceof MemoryProxy) { + return ((MemoryProxy) node).getLocationIdentity(); + } else if (node instanceof MemoryPhiNode) { + return ((MemoryPhiNode) node).getLocationIdentity(); + } else { + return null; + } + } + + private static void replaceMemoryUsages(ValueNode node, MemoryMap map) { + for (Node usage : node.usages().snapshot()) { + if (usage instanceof MemoryMapNode) { + continue; + } + + LocationIdentity location = getLocationIdentity(usage); + if (location != null) { + NodePosIterator iter = usage.inputs().iterator(); + while (iter.hasNext()) { + Position pos = iter.nextPosition(); + if (pos.getInputType() == InputType.Memory && pos.get(usage) == node) { + MemoryNode replacement = map.getLastLocationAccess(location); + if (replacement != null) { + pos.set(usage, replacement.asNode()); + } + } + } + } + } + } + /** * Replaces a given fixed node with this specialized snippet. * @@ -1181,17 +1236,18 @@ updateStamps(replacee, duplicates); + rewireMemoryGraph(replacee, duplicates); + // Replace all usages of the replacee with the value returned by the snippet ValueNode returnValue = null; if (returnNode != null && !(replacee instanceof ControlSinkNode)) { ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode); returnValue = returnDuplicate.result(); - MemoryMap mmap = new DuplicateMapper(duplicates, replaceeGraph.start()); if (returnValue == null && replacee.usages().isNotEmpty() && replacee instanceof MemoryCheckpoint) { - replacer.replace(replacee, null, mmap); + replacer.replace(replacee, null); } else { assert returnValue != null || replacee.hasNoUsages(); - replacer.replace(replacee, returnValue, mmap); + replacer.replace(replacee, returnValue); } if (returnDuplicate.isAlive()) { FixedNode next = null; @@ -1284,11 +1340,13 @@ } updateStamps(replacee, duplicates); + rewireMemoryGraph(replacee, duplicates); + // Replace all usages of the replacee with the value returned by the snippet ReturnNode returnDuplicate = (ReturnNode) duplicates.get(returnNode); ValueNode returnValue = returnDuplicate.result(); assert returnValue != null || replacee.hasNoUsages(); - replacer.replace(replacee, returnValue, new DuplicateMapper(duplicates, replaceeGraph.start())); + replacer.replace(replacee, returnValue); if (returnDuplicate.isAlive()) { returnDuplicate.replaceAndDelete(next); diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleReplacements.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleReplacements.java Mon Mar 30 17:56:43 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * 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.truffle.hotspot; - -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.api.runtime.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.runtime.*; -import com.oracle.graal.truffle.*; - -public final class HotSpotTruffleReplacements extends TruffleReplacements { - - private HotSpotTruffleReplacements(Providers providers, SnippetReflectionProvider snippetReflection) { - super(providers, snippetReflection); - } - - public static Replacements makeInstance() { - Providers providers = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders(); - SnippetReflectionProvider snippetReflection = Graal.getRequiredCapability(SnippetReflectionProvider.class); - return new HotSpotTruffleReplacements(providers, snippetReflection); - } -} diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java --- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Mon Mar 30 17:57:31 2015 +0200 @@ -50,7 +50,6 @@ import com.oracle.graal.lir.phases.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.tiers.*; @@ -74,7 +73,6 @@ } private TruffleCompilerImpl truffleCompiler; - private Replacements truffleReplacements; private Map> compilations = newIdentityMap(); private final ThreadPoolExecutor compileQueue; @@ -143,14 +141,6 @@ return createCallTargetImpl(source, root); } - @Override - public Replacements getReplacements() { - if (truffleReplacements == null) { - truffleReplacements = HotSpotTruffleReplacements.makeInstance(); - } - return truffleReplacements; - } - public static void installOptimizedCallTargetCallMethod() { Providers providers = getGraalProviders(); MetaAccessProvider metaAccess = providers.getMetaAccess(); diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Mar 30 17:57:31 2015 +0200 @@ -32,7 +32,6 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; import com.oracle.graal.truffle.debug.*; import com.oracle.graal.truffle.unsafe.*; import com.oracle.truffle.api.*; @@ -270,8 +269,6 @@ public abstract Collection getQueuedCallTargets(); - public abstract Replacements getReplacements(); - public abstract void compile(OptimizedCallTarget optimizedCallTarget, boolean mayBeAsynchronous); public abstract boolean cancelInstalledTask(OptimizedCallTarget optimizedCallTarget, Object source, CharSequence reason); diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Mon Mar 30 17:57:31 2015 +0200 @@ -26,9 +26,7 @@ import java.util.*; -import com.oracle.graal.api.meta.Assumptions.AssumptionResult; import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod; import com.oracle.graal.api.replacements.*; import com.oracle.graal.compiler.common.*; import com.oracle.graal.compiler.common.type.*; @@ -42,7 +40,6 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.*; import com.oracle.graal.phases.common.*; @@ -71,7 +68,7 @@ private final ResolvedJavaMethod callDirectMethod; private final ResolvedJavaMethod callInlinedMethod; private final ResolvedJavaMethod callSiteProxyMethod; - protected final ResolvedJavaMethod callRootMethod; + private final ResolvedJavaMethod callRootMethod; private final GraphBuilderConfiguration configForRoot; public PartialEvaluator(Providers providers, GraphBuilderConfiguration configForRoot, SnippetReflectionProvider snippetReflection) { @@ -173,13 +170,6 @@ if (original.getAnnotation(TruffleBoundary.class) != null) { return null; } - IntrinsicMethod intrinsicMethod = builder.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(original); - if (intrinsicMethod != null) { - InlineInfo inlineInfo = getMethodHandleIntrinsicInlineInfo(builder, arguments, intrinsicMethod); - if (inlineInfo != null) { - return inlineInfo; - } - } if (replacements != null && replacements.getMethodSubstitutionMethod(original) != null) { return null; } @@ -214,59 +204,6 @@ inlining.pop(); } } - - private InlineInfo getMethodHandleIntrinsicInlineInfo(GraphBuilderContext builder, ValueNode[] arguments, IntrinsicMethod intrinsicMethod) { - ResolvedJavaMethod targetMethod = null; - switch (intrinsicMethod) { - case INVOKE_BASIC: - ValueNode methodHandleNode = arguments[0]; - if (methodHandleNode.isConstant()) { - targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true); - } - break; - case LINK_TO_STATIC: - case LINK_TO_SPECIAL: - case LINK_TO_VIRTUAL: - case LINK_TO_INTERFACE: - ValueNode memberNameNode = arguments[arguments.length - 1]; - if (memberNameNode.isConstant()) { - targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant()); - } - break; - default: - throw GraalInternalError.shouldNotReachHere(); - } - if (targetMethod != null) { - // TODO maybe cast arguments - - if (!targetMethod.canBeInlined()) { - return null; - } - if (targetMethod.canBeStaticallyBound()) { - return new InlineInfo(targetMethod, false, false); - } - - // Try to get the most accurate receiver type - if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) { - ResolvedJavaType receiverType = StampTool.typeOrNull(arguments[0].stamp()); - if (receiverType != null) { - AssumptionResult concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod); - if (concreteMethod != null) { - builder.getAssumptions().record(concreteMethod); - return new InlineInfo(concreteMethod.getResult(), false, false); - } - } - } else { - AssumptionResult concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod); - if (concreteMethod != null) { - builder.getAssumptions().record(concreteMethod); - return new InlineInfo(concreteMethod.getResult(), false, false); - } - } - } - - return null; - } } private class PELoopExplosionPlugin implements LoopExplosionPlugin { diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java Mon Mar 30 17:56:43 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * 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.truffle; - -import java.util.*; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.api.replacements.*; -import com.oracle.graal.compiler.common.*; -import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.phases.util.*; -import com.oracle.graal.replacements.*; - -/** - * Custom {@link Replacements} for Truffle compilation. - */ -public abstract class TruffleReplacements extends ReplacementsImpl { - - private final Replacements graalReplacements; - - protected TruffleReplacements(Providers providers, SnippetReflectionProvider snippetReflection) { - super(providers, snippetReflection, providers.getCodeCache().getTarget()); - this.graalReplacements = providers.getReplacements(); - } - - @Override - public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args) { - return graalReplacements.getSnippet(method, null, args); - } - - @Override - public StructuredGraph getMethodSubstitution(ResolvedJavaMethod method) { - StructuredGraph graph = graalReplacements.getMethodSubstitution(method); - if (graph == null) { - return super.getMethodSubstitution(method); - } - return graph; - } - - @Override - public Collection getAllReplacements() { - throw GraalInternalError.shouldNotReachHere(); - } - - @Override - public boolean isForcedSubstitution(ResolvedJavaMethod method) { - return graalReplacements.isForcedSubstitution(method) || super.isForcedSubstitution(method); - } - - @Override - public void registerSnippetTemplateCache(SnippetTemplateCache templates) { - throw GraalInternalError.shouldNotReachHere(); - } - - @Override - public T getSnippetTemplateCache(Class templatesClass) { - return graalReplacements.getSnippetTemplateCache(templatesClass); - } -} diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java Mon Mar 30 17:57:31 2015 +0200 @@ -33,20 +33,23 @@ final HashMap readCache; - static class ReadCacheEntry { + static final class ReadCacheEntry { public final LocationIdentity identity; public final ValueNode object; + public final int index; - public ReadCacheEntry(LocationIdentity identity, ValueNode object) { + public ReadCacheEntry(LocationIdentity identity, ValueNode object, int index) { this.identity = identity; this.object = object; + this.index = index; } @Override public int hashCode() { int result = 31 + ((identity == null) ? 0 : identity.hashCode()); - return 31 * result + ((object == null) ? 0 : object.hashCode()); + result = 31 * result + ((object == null) ? 0 : object.hashCode()); + return result * 31 + index; } @Override @@ -60,7 +63,7 @@ @Override public String toString() { - return object + ":" + identity; + return index == -1 ? (object + ":" + identity) : (object + "[" + index + "]:" + identity); } } @@ -83,7 +86,7 @@ if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode instance = (VirtualInstanceNode) virtual; for (int i = 0; i < instance.entryCount(); i++) { - readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation), values.get(i)); + readCache.put(new ReadCacheEntry(instance.field(i).getLocationIdentity(), representation, -1), values.get(i)); } } } @@ -96,7 +99,7 @@ return super.equivalentTo(other); } - public void addReadCache(ValueNode object, LocationIdentity identity, ValueNode value, PartialEscapeClosure closure) { + public void addReadCache(ValueNode object, LocationIdentity identity, int index, ValueNode value, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -105,10 +108,10 @@ } else { cacheObject = object; } - readCache.put(new ReadCacheEntry(identity, cacheObject), value); + readCache.put(new ReadCacheEntry(identity, cacheObject, index), value); } - public ValueNode getReadCache(ValueNode object, LocationIdentity identity, PartialEscapeClosure closure) { + public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, PartialEscapeClosure closure) { ValueNode cacheObject; ObjectState obj = closure.getObjectState(this, object); if (obj != null) { @@ -117,7 +120,7 @@ } else { cacheObject = object; } - ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject)); + ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index)); obj = closure.getObjectState(this, cacheValue); if (obj != null) { assert !obj.isVirtual(); @@ -133,11 +136,11 @@ readCache.clear(); } - public void killReadCache(LocationIdentity identity) { + public void killReadCache(LocationIdentity identity, int index) { Iterator> iter = readCache.entrySet().iterator(); while (iter.hasNext()) { - Map.Entry entry = iter.next(); - if (entry.getKey().identity.equals(identity)) { + ReadCacheEntry entry = iter.next().getKey(); + if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) { iter.remove(); } } diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Mon Mar 30 17:57:31 2015 +0200 @@ -38,6 +38,14 @@ public class PEReadEliminationClosure extends PartialEscapeClosure { + private static final EnumMap UNBOX_LOCATIONS; + static { + UNBOX_LOCATIONS = new EnumMap<>(Kind.class); + for (Kind kind : Kind.values()) { + UNBOX_LOCATIONS.put(kind, NamedLocationIdentity.immutable("PEA unbox " + kind.getJavaName())); + } + } + public PEReadEliminationClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { super(schedule, metaAccess, constantReflection); } @@ -57,8 +65,14 @@ return processLoadField((LoadFieldNode) node, state, effects); } else if (node instanceof StoreFieldNode) { return processStoreField((StoreFieldNode) node, state, effects); + } else if (node instanceof LoadIndexedNode) { + return processLoadIndexed((LoadIndexedNode) node, state, effects); + } else if (node instanceof StoreIndexedNode) { + return processStoreIndexed((StoreIndexedNode) node, state, effects); } else if (node instanceof ArrayLengthNode) { return processArrayLength((ArrayLengthNode) node, state, effects); + } else if (node instanceof UnboxNode) { + return processUnbox((UnboxNode) node, state, effects); } else if (node instanceof MemoryCheckpoint.Single) { METRIC_MEMORYCHECKPOINT.increment(); LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); @@ -75,13 +89,13 @@ private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) { ValueNode array = GraphUtil.unproxify(length.array()); - ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, this); + ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, -1, this); if (cachedValue != null) { effects.replaceAtUsages(length, cachedValue); addScalarAlias(length, cachedValue); return true; } else { - state.addReadCache(array, ARRAY_LENGTH_LOCATION, length, this); + state.addReadCache(array, ARRAY_LENGTH_LOCATION, -1, length, this); } return false; } @@ -89,7 +103,7 @@ private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) { if (!store.isVolatile()) { ValueNode object = GraphUtil.unproxify(store.object()); - ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), this); + ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), -1, this); ValueNode value = getScalarAlias(store.value()); boolean result = false; @@ -97,8 +111,8 @@ effects.deleteNode(store); result = true; } - state.killReadCache(store.field().getLocationIdentity()); - state.addReadCache(object, store.field().getLocationIdentity(), value, this); + state.killReadCache(store.field().getLocationIdentity(), -1); + state.addReadCache(object, store.field().getLocationIdentity(), -1, value, this); return result; } else { processIdentity(state, any()); @@ -111,14 +125,67 @@ processIdentity(state, any()); } else { ValueNode object = GraphUtil.unproxify(load.object()); - ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), this); + ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), -1, this); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); addScalarAlias(load, cachedValue); return true; } else { - state.addReadCache(object, load.field().getLocationIdentity(), load, this); + state.addReadCache(object, load.field().getLocationIdentity(), -1, load, this); + } + } + return false; + } + + private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) { + LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind()); + if (store.index().isConstant()) { + int index = ((JavaConstant) store.index().asConstant()).asInt(); + ValueNode object = GraphUtil.unproxify(store.array()); + ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this); + + ValueNode value = getScalarAlias(store.value()); + boolean result = false; + if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { + effects.deleteNode(store); + result = true; } + state.killReadCache(arrayLocation, index); + state.addReadCache(object, arrayLocation, index, value, this); + return result; + } else { + state.killReadCache(arrayLocation, -1); + } + return false; + } + + private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) { + if (load.index().isConstant()) { + int index = ((JavaConstant) load.index().asConstant()).asInt(); + LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind()); + ValueNode object = GraphUtil.unproxify(load.array()); + ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this); + if (cachedValue != null) { + effects.replaceAtUsages(load, cachedValue); + addScalarAlias(load, cachedValue); + return true; + } else { + state.addReadCache(object, arrayLocation, index, load, this); + } + } + return false; + } + + private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) { + ValueNode object = GraphUtil.unproxify(unbox.getValue()); + LocationIdentity identity = UNBOX_LOCATIONS.get(unbox.getBoxingKind()); + ValueNode cachedValue = state.getReadCache(object, identity, -1, this); + if (cachedValue != null) { + effects.replaceAtUsages(unbox, cachedValue); + addScalarAlias(unbox, cachedValue); + return true; + } else { + state.addReadCache(object, identity, -1, unbox, this); } return false; } @@ -127,7 +194,7 @@ if (identity.isAny()) { state.killReadCache(); } else { - state.killReadCache(identity); + state.killReadCache(identity, -1); } } @@ -138,7 +205,7 @@ if (exitNode.graph().hasValueProxies()) { for (Map.Entry entry : exitState.getReadCache().entrySet()) { if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { - ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, this); + ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, this); if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) { ProxyNode proxy = new ValueProxyNode(value, exitNode); effects.addFloatingNode(proxy, "readCacheProxy"); @@ -192,7 +259,7 @@ PhiNode phiNode = getPhi(entry, value.stamp().unrestricted()); mergeEffects.addFloatingNode(phiNode, "mergeReadCache"); for (int i = 0; i < states.size(); i++) { - afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, PEReadEliminationClosure.this)); + afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, key.index, PEReadEliminationClosure.this)); } newState.readCache.put(key, phiNode); } else if (value != null) { @@ -203,7 +270,7 @@ if (phi.getKind() == Kind.Object) { for (Map.Entry entry : states.get(0).readCache.entrySet()) { if (entry.getKey().object == phi.valueAt(0)) { - mergeReadCachePhi(phi, entry.getKey().identity, states); + mergeReadCachePhi(phi, entry.getKey().identity, entry.getKey().index, states); } } @@ -211,22 +278,22 @@ } } - private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, List states) { + private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, List states) { ValueNode[] values = new ValueNode[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, PEReadEliminationClosure.this); + ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, index, PEReadEliminationClosure.this); if (value == null) { return; } values[i] = value; } - PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi), values[0].stamp().unrestricted()); + PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index), values[0].stamp().unrestricted()); mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi"); for (int i = 0; i < values.length; i++) { afterMergeEffects.addPhiInput(phiNode, values[i]); } - newState.readCache.put(new ReadCacheEntry(identity, phi), phiNode); + newState.readCache.put(new ReadCacheEntry(identity, phi, index), phiNode); } } } diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ExactClassValueProfile.java Mon Mar 30 17:57:31 2015 +0200 @@ -40,14 +40,16 @@ @SuppressWarnings("unchecked") @Override public T profile(T value) { - if (cachedClass != null && cachedClass.isInstance(value)) { - return (T) cachedClass.cast(value); - } else { - CompilerDirectives.transferToInterpreterAndInvalidate(); - if (cachedClass == null && value != null) { - cachedClass = value.getClass(); + if (cachedClass != Object.class) { + if (cachedClass != null && cachedClass.isInstance(value)) { + return (T) cachedClass.cast(value); } else { - cachedClass = Object.class; + CompilerDirectives.transferToInterpreterAndInvalidate(); + if (cachedClass == null && value != null) { + cachedClass = value.getClass(); + } else { + cachedClass = Object.class; + } } } return value; diff -r 00decb5cd984 -r 0b2bd777d933 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java Mon Mar 30 17:56:43 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java Mon Mar 30 17:57:31 2015 +0200 @@ -53,27 +53,42 @@ public Object profile(Object value) { Object snapshot = this.cachedValue; if (snapshot != GENERIC) { - if (snapshot instanceof Byte && value instanceof Byte && (byte) snapshot == (byte) value) { - return snapshot; - } else if (snapshot instanceof Short && value instanceof Short && (short) snapshot == (short) value) { - return snapshot; - } else if (snapshot instanceof Integer && value instanceof Integer && (int) snapshot == (int) value) { - return snapshot; - } else if (snapshot instanceof Long && value instanceof Long && (long) snapshot == (long) value) { - return snapshot; - } else if (snapshot instanceof Float && value instanceof Float && exactCompare((float) snapshot, (float) value)) { - return snapshot; - } else if (snapshot instanceof Double && value instanceof Double && exactCompare((double) snapshot, (double) value)) { - return snapshot; - } else if (snapshot instanceof Boolean && value instanceof Boolean && (boolean) snapshot == (boolean) value) { - return snapshot; - } else if (snapshot instanceof Character && value instanceof Character && (char) snapshot == (char) value) { - return snapshot; + if (snapshot instanceof Byte) { + if (value instanceof Byte && (byte) snapshot == (byte) value) { + return snapshot; + } + } else if (snapshot instanceof Short) { + if (value instanceof Short && (short) snapshot == (short) value) { + return snapshot; + } + } else if (snapshot instanceof Integer) { + if (value instanceof Integer && (int) snapshot == (int) value) { + return snapshot; + } + } else if (snapshot instanceof Long) { + if (value instanceof Long && (long) snapshot == (long) value) { + return snapshot; + } + } else if (snapshot instanceof Float) { + if (value instanceof Float && exactCompare((float) snapshot, (float) value)) { + return snapshot; + } + } else if (snapshot instanceof Double) { + if (value instanceof Double && exactCompare((double) snapshot, (double) value)) { + return snapshot; + } + } else if (snapshot instanceof Boolean) { + if (value instanceof Boolean && (boolean) snapshot == (boolean) value) { + return snapshot; + } + } else if (snapshot instanceof Character) { + if (value instanceof Character && (char) snapshot == (char) value) { + return snapshot; + } } else if (snapshot == value) { return snapshot; - } else { - cacheMiss(value); } + cacheMiss(value); } return value; }