# HG changeset patch # User Andreas Woess # Date 1373890184 -7200 # Node ID 64740220db8534bc0d45f9df818b54156a8f2852 # Parent 3811d04d933eb7e84663c57e2a8fedd644a1fb06# Parent e2f5ae9afdc5da7af598bd3bc01e72c50b547267 Merge diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerStampTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerStampTest.java Mon Jul 15 14:09:44 2013 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012, 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.compiler.test; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +/** + * This class tests that integer stamps are created correctly for constants. + */ +public class IntegerStampTest extends GraalCompilerTest { + + private StructuredGraph graph; + + @Before + public void before() { + graph = new StructuredGraph(); + } + + @Test + public void testBooleanConstant() { + assertEquals(new IntegerStamp(Kind.Int, 1, 1, 0x1), ConstantNode.forBoolean(true, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0), ConstantNode.forBoolean(false, graph).integerStamp()); + } + + @Test + public void testByteConstant() { + assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0), ConstantNode.forByte((byte) 0, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 16, 16, 0x10), ConstantNode.forByte((byte) 16, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, -16, -16, 0xf0), ConstantNode.forByte((byte) -16, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 127, 127, 0x7f), ConstantNode.forByte((byte) 127, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, -128, -128, 0x80), ConstantNode.forByte((byte) -128, graph).integerStamp()); + } + + @Test + public void testShortConstant() { + assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0), ConstantNode.forShort((short) 0, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 128, 128, 0x80), ConstantNode.forShort((short) 128, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, -128, -128, 0xff80), ConstantNode.forShort((short) -128, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 32767, 32767, 0x7fff), ConstantNode.forShort((short) 32767, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, -32768, -32768, 0x8000), ConstantNode.forShort((short) -32768, graph).integerStamp()); + } + + @Test + public void testCharConstant() { + assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0), ConstantNode.forChar((char) 0, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 'A', 'A', 'A'), ConstantNode.forChar('A', graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 128, 128, 0x80), ConstantNode.forChar((char) 128, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 65535, 65535, 0xffff), ConstantNode.forChar((char) 65535, graph).integerStamp()); + } + + @Test + public void testIntConstant() { + assertEquals(new IntegerStamp(Kind.Int, 0, 0, 0x0), ConstantNode.forInt(0, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, 128, 128, 0x80), ConstantNode.forInt(128, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, -128, -128, 0xffffff80L), ConstantNode.forInt(-128, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, Integer.MAX_VALUE, Integer.MAX_VALUE, 0x7fffffff), ConstantNode.forInt(Integer.MAX_VALUE, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Int, Integer.MIN_VALUE, Integer.MIN_VALUE, 0x80000000L), ConstantNode.forInt(Integer.MIN_VALUE, graph).integerStamp()); + } + + @Test + public void testLongConstant() { + assertEquals(new IntegerStamp(Kind.Long, 0, 0, 0x0), ConstantNode.forLong(0, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Long, 128, 128, 0x80), ConstantNode.forLong(128, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Long, -128, -128, 0xffffffffffffff80L), ConstantNode.forLong(-128, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Long, Long.MAX_VALUE, Long.MAX_VALUE, 0x7fffffffffffffffL), ConstantNode.forLong(Long.MAX_VALUE, graph).integerStamp()); + assertEquals(new IntegerStamp(Kind.Long, Long.MIN_VALUE, Long.MIN_VALUE, 0x8000000000000000L), ConstantNode.forLong(Long.MIN_VALUE, graph).integerStamp()); + } +} diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Mon Jul 15 14:09:44 2013 +0200 @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2011, 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.compiler.test.ea; + +import static org.junit.Assert.*; + +import java.util.concurrent.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.virtual.phases.ea.*; + +public class PEAReadEliminationTest extends GraalCompilerTest { + + private StructuredGraph graph; + + public static Object staticField; + + public static class TestObject implements Callable { + + public int x; + public int y; + + public TestObject(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public Integer call() throws Exception { + return x; + } + } + + public static class TestObject2 { + + public Object x; + public Object y; + + public TestObject2(Object x, Object y) { + this.x = x; + this.y = y; + } + } + + @SuppressWarnings("all") + public static int testSimpleSnippet(TestObject a) { + a.x = 2; + staticField = a; + return a.x; + } + + @Test + public void testSimple() { + ValueNode result = getReturn("testSimpleSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertTrue(result.isConstant()); + assertEquals(2, result.asConstant().asInt()); + } + + @SuppressWarnings("all") + public static int testSimpleConflictSnippet(TestObject a, TestObject b) { + a.x = 2; + b.x = 3; + staticField = a; + return a.x; + } + + @Test + public void testSimpleConflict() { + ValueNode result = getReturn("testSimpleConflictSnippet").result(); + assertFalse(result.isConstant()); + assertTrue(result instanceof LoadFieldNode); + } + + @SuppressWarnings("all") + public static int testParamSnippet(TestObject a, int b) { + a.x = b; + return a.x; + } + + @Test + public void testParam() { + ValueNode result = getReturn("testParamSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(1), result); + } + + @SuppressWarnings("all") + public static int testMaterializedSnippet(int a) { + TestObject obj = new TestObject(a, 0); + staticField = obj; + return obj.x; + } + + @Test + public void testMaterialized() { + ValueNode result = getReturn("testMaterializedSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(0), result); + } + + @SuppressWarnings("all") + public static int testSimpleLoopSnippet(TestObject obj, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + } + return obj.x; + } + + @Test + public void testSimpleLoop() { + ValueNode result = getReturn("testSimpleLoopSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertEquals(graph.getLocal(1), result); + } + + @SuppressWarnings("all") + public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + obj2.x = 10; + obj.x = 0; + } + return obj.x; + } + + @Test + public void testBadLoop() { + ValueNode result = getReturn("testBadLoopSnippet").result(); + assertEquals(0, graph.getNodes(LoadFieldNode.class).count()); + assertTrue(result instanceof ProxyNode); + assertTrue(((ProxyNode) result).value() instanceof PhiNode); + } + + @SuppressWarnings("all") + public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + obj.x = 0; + obj2.x = 10; + } + return obj.x; + } + + @Test + public void testBadLoop2() { + ValueNode result = getReturn("testBadLoop2Snippet").result(); + assertEquals(1, graph.getNodes(LoadFieldNode.class).count()); + assertTrue(result instanceof LoadFieldNode); + } + + @SuppressWarnings("all") + public static int testPhiSnippet(TestObject a, int b) { + if (b < 0) { + a.x = 1; + } else { + a.x = 2; + } + return a.x; + } + + @Test + public void testPhi() { + ValueNode result = getReturn("testPhiSnippet").result(); + assertTrue(graph.getNodes(LoadFieldNode.class).isEmpty()); + assertTrue(result instanceof PhiNode); + PhiNode phi = (PhiNode) result; + assertTrue(phi.valueAt(0).isConstant()); + assertTrue(phi.valueAt(1).isConstant()); + assertEquals(1, phi.valueAt(0).asConstant().asInt()); + assertEquals(2, phi.valueAt(1).asConstant().asInt()); + } + + @SuppressWarnings("all") + public static void testSimpleStoreSnippet(TestObject a, int b) { + a.x = b; + a.x = b; + } + + @Test + public void testSimpleStore() { + processMethod("testSimpleStoreSnippet"); + assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count()); + } + + final ReturnNode getReturn(String snippet) { + processMethod(snippet); + assertEquals(1, graph.getNodes(ReturnNode.class).count()); + return graph.getNodes(ReturnNode.class).first(); + } + + private void processMethod(final String snippet) { + graph = parse(snippet); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(runtime(), assumptions, replacements); + new InliningPhase(runtime(), null, replacements, assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL).apply(graph); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true); + new PartialEscapePhase(false, true, canonicalizer).apply(graph, context); + } +} diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon Jul 15 14:09:44 2013 +0200 @@ -236,7 +236,15 @@ Register receiver = asRegister(cc.getArgument(0)); AMD64Address src = new AMD64Address(receiver, config.hubOffset); - asm.cmpq(inlineCacheKlass, src); + AMD64HotSpotLIRGenerator gen = (AMD64HotSpotLIRGenerator) lirGen; + HotSpotRuntime hr = ((HotSpotRuntime) gen.getRuntime()); + if (hr.config.useCompressedKlassPointers) { + Register register = r10; + AMD64Move.decodeKlassPointer(asm, register, src, hr.config.narrowKlassBase, hr.config.narrowKlassShift, hr.config.logKlassAlignment); + asm.cmpq(inlineCacheKlass, register); + } else { + asm.cmpq(inlineCacheKlass, src); + } asm.jcc(ConditionFlag.NotEqual, unverifiedStub); } diff -r e2f5ae9afdc5 -r 64740220db85 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 Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Jul 15 14:09:44 2013 +0200 @@ -413,10 +413,16 @@ AMD64AddressValue loadAddress = asAddressValue(address); Variable result = newVariable(kind); assert access == null || access instanceof HeapAccess; - if (runtime().config.useCompressedOops && isCompressCandidate(access)) { - Variable scratch = newVariable(Kind.Long); - append(new LoadCompressedPointer(kind, result, scratch, loadAddress, access != null ? state(access) : null, runtime().config.narrowOopBase, runtime().config.narrowOopShift, - runtime().config.logMinObjAlignment)); + if (isCompressCandidate(access)) { + if (runtime().config.useCompressedOops && kind == Kind.Object) { + append(new LoadCompressedPointer(kind, result, loadAddress, access != null ? state(access) : null, runtime().config.narrowOopBase, runtime().config.narrowOopShift, + runtime().config.logMinObjAlignment)); + } else if (runtime().config.useCompressedKlassPointers && kind == Kind.Long) { + append(new LoadCompressedPointer(kind, result, loadAddress, access != null ? state(access) : null, runtime().config.narrowKlassBase, runtime().config.narrowKlassShift, + runtime().config.logKlassAlignment)); + } else { + append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null)); + } } else { append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null)); } @@ -430,17 +436,31 @@ if (isConstant(inputVal)) { Constant c = asConstant(inputVal); if (canStoreConstant(c)) { - append(new StoreConstantOp(kind, storeAddress, c, state, runtime().config.useCompressedOops && isCompressCandidate(access))); + if (inputVal.getKind() == Kind.Object) { + append(new StoreConstantOp(kind, storeAddress, c, state, runtime().config.useCompressedOops && isCompressCandidate(access))); + } else if (inputVal.getKind() == Kind.Long) { + append(new StoreConstantOp(kind, storeAddress, c, state, runtime().config.useCompressedKlassPointers && isCompressCandidate(access))); + } else { + append(new StoreConstantOp(kind, storeAddress, c, state, false)); + } return; } } Variable input = load(inputVal); - if (runtime().config.useCompressedOops && isCompressCandidate(access)) { - if (input.getKind() == Kind.Object) { + if (isCompressCandidate(access)) { + if (runtime().config.useCompressedOops && kind == Kind.Object) { + if (input.getKind() == Kind.Object) { + Variable scratch = newVariable(Kind.Long); + append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + } else { + // the input oop is already compressed + append(new StoreOp(input.getKind(), storeAddress, input, state)); + } + } else if (runtime().config.useCompressedKlassPointers && kind == Kind.Long) { Variable scratch = newVariable(Kind.Long); - append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, runtime().config.narrowKlassBase, runtime().config.narrowKlassShift, runtime().config.logKlassAlignment)); } else { - append(new StoreOp(input.getKind(), storeAddress, input, state)); + append(new StoreOp(kind, storeAddress, input, state)); } } else { append(new StoreOp(kind, storeAddress, input, state)); diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java --- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java Mon Jul 15 14:09:44 2013 +0200 @@ -287,6 +287,103 @@ return "Test".equals(c1); } + @SuppressWarnings("unchecked") + public static Object[] unmodListTestByte(Object c1, @SuppressWarnings("unused") Object c2, @SuppressWarnings("unused") Object c3) { + List queue = (ArrayList) c1; + Byte[] result = Collections.unmodifiableCollection(queue).toArray(new Byte[queue.size()]); + return result; + } + + @Test + public void test13() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("unmodListTestByte"); + List list = new ArrayList<>(); + Byte[] array = (Byte[]) installedBenchmarkCode.execute(list, null, null); + Assert.assertTrue(list.size() == array.length); + } + + @Test + public void test14() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBufferTest"); + StringBuffer buffer = new StringBuffer("TestTestTestTestTestTestTest"); + Assert.assertTrue(buffer.length() == 28); + String a = new String("TestTestTestTestTestTestTest"); + installedBenchmarkCode.execute(buffer, a.toCharArray(), null); + Assert.assertTrue(buffer.length() == 56); + Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest")); + } + + public static void stringBufferTest(Object c1, Object c2, @SuppressWarnings("unused") Object c3) { + StringBuffer source = (StringBuffer) c1; + char[] add = (char[]) c2; + for (int i = 0; i < add.length; i++) { + source.append(add[i]); + } + } + + @Test + public void test15() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBufferTestIn"); + installedBenchmarkCode.execute(null, null, null); + } + + @SuppressWarnings("unused") + public static void stringBufferTestIn(Object c1, Object c2, Object c3) { + StringBuffer buffer = new StringBuffer("TestTestTestTestTestTestTest"); + Assert.assertTrue(buffer.length() == 28); + String a = new String("TestTestTestTestTestTestTest"); + char[] add = a.toCharArray(); + for (int i = 0; i < add.length; i++) { + buffer.append(add[i]); + } + Assert.assertTrue(buffer.length() == 56); + Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest")); + } + + @Test + public void test16() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBufferArrayCopy"); + installedBenchmarkCode.execute(null, null, null); + } + + @SuppressWarnings("unused") + public static void stringBufferArrayCopy(Object c1, Object c2, Object c3) { + StringBuffer buffer = new StringBuffer("TestTestTestTestTestTestTest"); + Assert.assertTrue(buffer.length() == 28); + String a = new String("TestTestTestTestTestTestTest"); + char[] dst = new char[buffer.length() * 2]; + System.arraycopy(buffer.toString().toCharArray(), 0, dst, 0, buffer.length()); + System.arraycopy(a.toCharArray(), 0, dst, buffer.length(), buffer.length()); + Assert.assertTrue(dst.length == 56); + Assert.assertTrue(new String(dst).equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest")); + } + + @Test + public void test17() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringFormat"); + installedBenchmarkCode.execute(null, null, null); + } + + @SuppressWarnings("unused") + public static void stringFormat(Object c1, Object c2, Object c3) { + String.format("Hello %d", 0); + String.format("Hello %d", -11); + String.format("Hello %d", -2147483648); + } + + @Test + public void test18() throws Exception { + HotSpotInstalledCode installedBenchmarkCode = getInstalledCode("stringBuilder"); + StringBuilder b = (StringBuilder) installedBenchmarkCode.execute(null, null, null); + Assert.assertTrue(b.capacity() == 16); + Assert.assertTrue(b.length() == 0); + } + + @SuppressWarnings("unused") + public static Object stringBuilder(Object c1, Object c2, Object c3) { + return new StringBuilder(); + } + static class Container { public Object a = new Object(); @@ -352,5 +449,4 @@ } } - } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Mon Jul 15 14:09:44 2013 +0200 @@ -153,6 +153,13 @@ } /** + * Reads a klass pointer from a constant object. + */ + public static long unsafeReadKlassPointer(Object object) { + return instance.getCompilerToVM().readUnsafeKlassPointer(object); + } + + /** * Reads a word value from a given object. */ public static long unsafeReadWord(Object object, long offset) { diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Mon Jul 15 14:09:44 2013 +0200 @@ -58,6 +58,9 @@ public long narrowOopBase; public int narrowOopShift; public int logMinObjAlignment; + public long narrowKlassBase; + public int narrowKlassShift; + public int logKlassAlignment; // CPU capabilities public int useSSE; diff -r e2f5ae9afdc5 -r 64740220db85 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 Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Mon Jul 15 14:09:44 2013 +0200 @@ -216,6 +216,8 @@ Object readUnsafeUncompressedPointer(Object o, long displacement); + long readUnsafeKlassPointer(Object o); + /** * Invalidates the profiling information and restarts profiling upon the next invocation. * diff -r e2f5ae9afdc5 -r 64740220db85 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 Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Mon Jul 15 14:09:44 2013 +0200 @@ -173,6 +173,9 @@ public native Object readUnsafeUncompressedPointer(Object o, long displacement); @Override + public native long readUnsafeKlassPointer(Object o); + + @Override public Object executeCompiledMethod(Object arg1, Object arg2, Object arg3, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException { return executeCompiledMethodIntrinsic(arg1, arg2, arg3, hotspotInstalledCode); } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Jul 15 14:09:44 2013 +0200 @@ -649,6 +649,10 @@ ResolvedJavaMethod method = loadMethodNode.getMethod(); ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method); graph.replaceFixed(loadMethodNode, metaspaceMethod); + } else if (n instanceof StoreHubNode) { + StoreHubNode storeHub = (StoreHubNode) n; + WriteNode hub = createWriteHub(graph, wordKind, storeHub.getObject(), storeHub.getValue()); + graph.replaceFixed(storeHub, hub); } else if (n instanceof FixedGuardNode) { FixedGuardNode node = (FixedGuardNode) n; GuardingNode guard = tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated()); @@ -836,7 +840,13 @@ private ReadNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object) { LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph); assert !object.isConstant() || object.asConstant().isNull(); - return graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()), WriteBarrierType.NONE, false)); + return graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()), WriteBarrierType.NONE, config.useCompressedKlassPointers)); + } + + private WriteNode createWriteHub(StructuredGraph graph, Kind wordKind, ValueNode object, ValueNode value) { + LocationNode location = ConstantLocationNode.create(ANY_LOCATION, wordKind, config.hubOffset, graph); + assert !object.isConstant() || object.asConstant().isNull(); + return graph.add(new WriteNode(object, value, location, WriteBarrierType.NONE, config.useCompressedKlassPointers)); } public static long referentOffset() { @@ -1157,7 +1167,15 @@ case Int: return Constant.forInt(base == null ? unsafe.getInt(displacement) : unsafe.getInt(base, displacement)); case Long: - return Constant.forLong(base == null ? unsafe.getLong(displacement) : unsafe.getLong(base, displacement)); + if (displacement == config().hubOffset && this.getGraalRuntime().getRuntime().config.useCompressedKlassPointers) { + if (base == null) { + throw new GraalInternalError("Base of object must not be null"); + } else { + return Constant.forLong(this.getGraalRuntime().getCompilerToVM().readUnsafeKlassPointer(base)); + } + } else { + return Constant.forLong(base == null ? unsafe.getLong(displacement) : unsafe.getLong(base, displacement)); + } case Float: return Constant.forFloat(base == null ? unsafe.getFloat(displacement) : unsafe.getFloat(base, displacement)); case Double: diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Mon Jul 15 14:09:44 2013 +0200 @@ -277,7 +277,7 @@ public static void initializeObjectHeader(Word memory, Word markWord, Word hub) { memory.writeWord(markOffset(), markWord, MARK_WORD_LOCATION); - memory.writeWord(hubOffset(), hub, HUB_LOCATION); + StoreHubNode.write(memory.toObject(), hub); } @Fold @@ -351,6 +351,11 @@ } @Fold + public static int instanceHeaderSize() { + return config().useCompressedKlassPointers ? (2 * wordSize()) - 4 : 2 * wordSize(); + } + + @Fold public static int cardTableShift() { return config().cardtableShift; } @@ -468,6 +473,7 @@ } public static Word loadWordFromObject(Object object, int offset) { + assert offset != hubOffset() : "Use loadHubIntrinsic instead"; return loadWordFromObjectIntrinsic(object, 0, offset, getWordKind()); } @@ -483,7 +489,10 @@ @SuppressWarnings("unused") @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) static Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word) { - return Word.box(unsafeReadWord(object, hubOffset())); + if (wordKind() == Kind.Int) { + return Word.box((int) unsafeReadKlassPointer(object)); + } + return Word.box(unsafeReadKlassPointer(object)); } @Fold diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon Jul 15 14:09:44 2013 +0200 @@ -203,12 +203,12 @@ if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { new_seqInit.inc(); explodeLoop(); - for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { + for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) { memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } else { new_loopInit.inc(); - for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) { + for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) { memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon Jul 15 14:09:44 2013 +0200 @@ -57,7 +57,7 @@ Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, useG1GC()); Pointer memory = Word.fromObject(result); - for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) { + for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) { memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION); } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon Jul 15 14:09:44 2013 +0200 @@ -94,7 +94,7 @@ if (memory.notEqual(0)) { Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); initializeObjectHeader(memory, prototypeMarkWord, hub); - for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) { + for (int offset = instanceHeaderSize(); offset < sizeInBytes; offset += wordSize()) { memory.writeWord(offset, Word.zero(), ANY_LOCATION); } return verifyObject(memory.toObject()); diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Mon Jul 15 14:09:44 2013 +0200 @@ -213,7 +213,7 @@ fatal("oop not in heap: %p", oop.rawValue()); } - Word klass = oop.readWord(hubOffset()); + Word klass = loadHub(object); if (klass.equal(Word.zero())) { fatal("klass for oop %p is null", oop.rawValue()); } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Mon Jul 15 14:09:44 2013 +0200 @@ -120,26 +120,27 @@ public static class LoadCompressedPointer extends LoadOp { - private long narrowOopBase; - private int narrowOopShift; - private int logMinObjAlignment; - @Temp({REG}) private AllocatableValue scratch; + private long base; + private int shift; + private int alignment; - public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, AMD64AddressValue address, LIRFrameState state, long narrowOopBase, int narrowOopShift, - int logMinObjAlignment) { + public LoadCompressedPointer(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state, long base, int shift, int alignment) { super(kind, result, address, state); - this.narrowOopBase = narrowOopBase; - this.narrowOopShift = narrowOopShift; - this.logMinObjAlignment = logMinObjAlignment; - this.scratch = scratch; - assert kind == Kind.Object; + this.base = base; + this.shift = shift; + this.alignment = alignment; + assert kind == Kind.Object || kind == Kind.Long; } @Override public void emitMemAccess(AMD64MacroAssembler masm) { Register resRegister = asRegister(result); masm.movl(resRegister, address.toAddress()); - decodePointer(masm, resRegister, narrowOopBase, narrowOopShift, logMinObjAlignment); + if (kind == Kind.Object) { + decodePointer(masm, resRegister, base, shift, alignment); + } else { + decodeKlassPointer(masm, resRegister, base, shift, alignment); + } } } @@ -189,31 +190,34 @@ public static class StoreCompressedPointer extends AMD64LIRInstruction { protected final Kind kind; - private long narrowOopBase; - private int narrowOopShift; - private int logMinObjAlignment; + private long base; + private int shift; + private int alignment; @Temp({REG}) private AllocatableValue scratch; @Alive({REG}) protected AllocatableValue input; @Alive({COMPOSITE}) protected AMD64AddressValue address; @State protected LIRFrameState state; - public StoreCompressedPointer(Kind kind, AMD64AddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long narrowOopBase, int narrowOopShift, - int logMinObjAlignment) { - this.narrowOopBase = narrowOopBase; - this.narrowOopShift = narrowOopShift; - this.logMinObjAlignment = logMinObjAlignment; + public StoreCompressedPointer(Kind kind, AMD64AddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long base, int shift, int alignment) { + this.base = base; + this.shift = shift; + this.alignment = alignment; this.scratch = scratch; this.kind = kind; this.address = address; this.state = state; this.input = input; - assert kind == Kind.Object; + assert kind == Kind.Object || kind == Kind.Long; } @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { masm.movq(asRegister(scratch), asRegister(input)); - encodePointer(masm, asRegister(scratch), narrowOopBase, narrowOopShift, logMinObjAlignment); + if (kind == Kind.Object) { + encodePointer(masm, asRegister(scratch), base, shift, alignment); + } else { + encodeKlassPointer(masm, asRegister(scratch), base, shift, alignment); + } if (state != null) { tasm.recordImplicitException(masm.codeBuffer.position(), state); } @@ -290,7 +294,11 @@ break; case Long: if (NumUtil.isInt(input.asLong())) { - masm.movslq(address.toAddress(), (int) input.asLong()); + if (compress) { + masm.movl(address.toAddress(), (int) input.asLong()); + } else { + masm.movslq(address.toAddress(), (int) input.asLong()); + } } else { throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); } @@ -410,15 +418,15 @@ @Alive protected AllocatableValue newValue; @Temp({REG}) protected AllocatableValue scratch; - private long narrowOopBase; - private int narrowOopShift; - private int logMinObjAlignment; + private long base; + private int shift; + private int alignment; - public CompareAndSwapCompressedOp(AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue, AllocatableValue scratch, long narrowOopBase, - int narrowOopShift, int logMinObjAlignment) { - this.narrowOopBase = narrowOopBase; - this.narrowOopShift = narrowOopShift; - this.logMinObjAlignment = logMinObjAlignment; + public CompareAndSwapCompressedOp(AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue, AllocatableValue scratch, long base, int shift, + int alignment) { + this.base = base; + this.shift = shift; + this.alignment = alignment; this.scratch = scratch; this.result = result; this.address = address; @@ -429,7 +437,7 @@ @Override public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - compareAndSwapCompressed(tasm, masm, result, address, cmpValue, newValue, scratch, narrowOopBase, narrowOopShift, logMinObjAlignment); + compareAndSwapCompressed(tasm, masm, result, address, cmpValue, newValue, scratch, base, shift, alignment); } } @@ -643,56 +651,82 @@ } protected static void compareAndSwapCompressed(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, - AllocatableValue newValue, AllocatableValue scratch, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { + AllocatableValue newValue, AllocatableValue scratch, long base, int shift, int alignment) { assert AMD64.rax.equals(asRegister(cmpValue)) && AMD64.rax.equals(asRegister(result)); final Register scratchRegister = asRegister(scratch); final Register cmpRegister = asRegister(cmpValue); final Register newRegister = asRegister(newValue); - encodePointer(masm, cmpRegister, narrowOopBase, narrowOopShift, logMinObjAlignment); + encodePointer(masm, cmpRegister, base, shift, alignment); masm.movq(scratchRegister, newRegister); - encodePointer(masm, scratchRegister, narrowOopBase, narrowOopShift, logMinObjAlignment); + encodePointer(masm, scratchRegister, base, shift, alignment); if (tasm.target.isMP) { masm.lock(); } masm.cmpxchgl(scratchRegister, address.toAddress()); } - private static void encodePointer(AMD64MacroAssembler masm, Register scratchRegister, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { - // If the narrowOopBase is zero, the uncompressed address has to be shifted right + private static void encodePointer(AMD64MacroAssembler masm, Register scratchRegister, long base, int shift, int alignment) { + // If the base is zero, the uncompressed address has to be shifted right // in order to be compressed. - if (narrowOopBase == 0) { - if (narrowOopShift != 0) { - assert logMinObjAlignment == narrowOopShift : "Encode algorithm is wrong"; - masm.shrq(scratchRegister, logMinObjAlignment); + if (base == 0) { + if (shift != 0) { + assert alignment == shift : "Encode algorithm is wrong"; + masm.shrq(scratchRegister, alignment); } } else { - // Otherwise the narrow heap base, which resides always in register 12, is subtracted + // Otherwise the heap base, which resides always in register 12, is subtracted // followed by right shift. masm.testq(scratchRegister, scratchRegister); // If the stored reference is null, move the heap to scratch // register and then calculate the compressed oop value. masm.cmovq(ConditionFlag.Equal, scratchRegister, AMD64.r12); masm.subq(scratchRegister, AMD64.r12); - masm.shrq(scratchRegister, logMinObjAlignment); + masm.shrq(scratchRegister, alignment); } } - private static void decodePointer(AMD64MacroAssembler masm, Register resRegister, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { - // If the narrowOopBase is zero, the compressed address has to be shifted left + private static void decodePointer(AMD64MacroAssembler masm, Register resRegister, long base, int shift, int alignment) { + // If the base is zero, the compressed address has to be shifted left // in order to be uncompressed. - if (narrowOopBase == 0) { - if (narrowOopShift != 0) { - assert logMinObjAlignment == narrowOopShift : "Decode algorithm is wrong"; - masm.shlq(resRegister, logMinObjAlignment); + if (base == 0) { + if (shift != 0) { + assert alignment == shift : "Decode algorithm is wrong"; + masm.shlq(resRegister, alignment); } } else { Label done = new Label(); - masm.shlq(resRegister, logMinObjAlignment); + masm.shlq(resRegister, alignment); masm.jccb(ConditionFlag.Equal, done); - // Otherwise the narrow heap base is added to the shifted address. + // Otherwise the heap base is added to the shifted address. masm.addq(resRegister, AMD64.r12); masm.bind(done); } } + private static void encodeKlassPointer(AMD64MacroAssembler masm, Register scratchRegister, long base, int shift, int alignment) { + if (base != 0) { + masm.subq(scratchRegister, AMD64.r12); + } + if (shift != 0) { + assert alignment == shift : "Encode algorithm is wrong"; + masm.shrq(scratchRegister, alignment); + } + } + + private static void decodeKlassPointer(AMD64MacroAssembler masm, Register resRegister, long base, int shift, int alignment) { + if (shift != 0) { + assert alignment == shift : "Decode algorighm is wrong"; + masm.shlq(resRegister, alignment); + if (base != 0) { + masm.addq(resRegister, AMD64.r12); + } + } else { + assert base == 0 : "Sanity"; + } + } + + public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, AMD64Address address, long narrowKlassBase, int narrowKlassShift, int logKlassAlignment) { + masm.movl(register, address); + decodeKlassPointer(masm, register, narrowKlassBase, narrowKlassShift, logKlassAlignment); + } } diff -r e2f5ae9afdc5 -r 64740220db85 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 Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java Mon Jul 15 14:09:44 2013 +0200 @@ -88,12 +88,11 @@ this.replaceAtUsages(BeginNode.prevBegin(this)); graph().removeFixed(this); } else { - FixedNode next = this.next(); - if (next != null) { - tool.deleteBranch(next); - } - setNext(graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, reason))); - return; + FixedWithNextNode predecessor = (FixedWithNextNode) predecessor(); + DeoptimizeNode deopt = graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, reason)); + deopt.setDeoptimizationState(getDeoptimizationState()); + tool.deleteBranch(this); + predecessor.setNext(deopt); } } } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java Mon Jul 15 14:09:44 2013 +0200 @@ -0,0 +1,55 @@ +/* + * 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.nodes.extended; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +public final class StoreHubNode extends FixedWithNextNode implements Lowerable { + + @Input private ValueNode value; + @Input private ValueNode object; + + public ValueNode getValue() { + return value; + } + + public ValueNode getObject() { + return object; + } + + private StoreHubNode(ValueNode object, ValueNode value) { + super(StampFactory.forVoid()); + this.value = value; + this.object = object; + } + + @Override + public void lower(LoweringTool tool, LoweringType loweringType) { + tool.getRuntime().lower(this, tool); + } + + @NodeIntrinsic + public static native void write(Object object, Object value); +} diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Mon Jul 15 14:09:44 2013 +0200 @@ -25,7 +25,9 @@ import static com.oracle.graal.api.code.DeoptimizationAction.*; import static com.oracle.graal.api.meta.DeoptimizationReason.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.meta.ProfilingInfo.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -66,6 +68,10 @@ return forStoreCheck; } + // TODO (ds) remove once performance regression in compiler.sunflow (and other benchmarks) + // caused by new lowering is fixed + private static final boolean useNewLowering = true; // Boolean.getBoolean("graal.checkcast.useNewLowering"); + /** * Lowers a {@link CheckCastNode} to a {@link GuardingPiNode}. That is: * @@ -94,20 +100,31 @@ */ @Override public void lower(LoweringTool tool, LoweringType loweringType) { - InstanceOfNode typeTest = graph().add(new InstanceOfNode(type, object, profile)); - Stamp stamp = StampFactory.declared(type).join(object.stamp()); - ValueNode condition; - if (stamp == null) { - // This is a check cast that will always fail - condition = LogicConstantNode.contradiction(graph()); - stamp = StampFactory.declared(type); - } else if (object.stamp().nonNull()) { - condition = typeTest; + if (useNewLowering) { + InstanceOfNode typeTest = graph().add(new InstanceOfNode(type, object, profile)); + Stamp stamp = StampFactory.declared(type).join(object.stamp()); + ValueNode condition; + if (stamp == null) { + // This is a check cast that will always fail + condition = LogicConstantNode.contradiction(graph()); + stamp = StampFactory.declared(type); + } else if (object.stamp().nonNull()) { + condition = typeTest; + } else { + if (profile != null && profile.getNullSeen() == TriState.FALSE) { + FixedGuardNode nullGuard = graph().add(new FixedGuardNode(graph().unique(new IsNullNode(object)), UnreachedCode, DeoptimizationAction.InvalidateReprofile, true)); + graph().addBeforeFixed(this, nullGuard); + condition = typeTest; + stamp = stamp.join(StampFactory.objectNonNull()); + } else { + condition = graph().unique(new LogicDisjunctionNode(graph().unique(new IsNullNode(object)), typeTest)); + } + } + GuardingPiNode checkedObject = graph().add(new GuardingPiNode(object, condition, false, forStoreCheck ? ArrayStoreException : ClassCastException, InvalidateReprofile, stamp)); + graph().replaceFixedWithFixed(this, checkedObject); } else { - condition = graph().unique(new LogicDisjunctionNode(graph().unique(new IsNullNode(object)), typeTest)); + tool.getRuntime().lower(this, tool); } - GuardingPiNode checkedObject = graph().add(new GuardingPiNode(object, condition, false, forStoreCheck ? ArrayStoreException : ClassCastException, InvalidateReprofile, stamp)); - graph().replaceFixedWithFixed(this, checkedObject); } @Override diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Mon Jul 15 14:09:44 2013 +0200 @@ -132,18 +132,21 @@ } public static Stamp forConstant(Constant value) { - assert value.getKind() != Kind.Object; - if (value.getKind() == Kind.Object) { - throw new GraalInternalError("unexpected kind: %s", value.getKind()); - } else { - if (value.getKind() == Kind.Int || value.getKind() == Kind.Long) { - return forInteger(value.getKind(), value.asLong(), value.asLong(), value.asLong() & IntegerStamp.defaultMask(value.getKind())); - } else if (value.getKind() == Kind.Float) { - return forFloat(value.getKind(), value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); - } else if (value.getKind() == Kind.Double) { - return forFloat(value.getKind(), value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble())); - } - return forKind(value.getKind().getStackKind()); + Kind kind = value.getKind(); + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), value.asLong() & IntegerStamp.defaultMask(kind)); + case Float: + return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); + case Double: + return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble())); + default: + throw new GraalInternalError("unexpected kind: %s", kind); } } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon Jul 15 14:09:44 2013 +0200 @@ -397,15 +397,24 @@ GraphUtil.killWithUnusedFloatingInputs(guard); metricGuardsRemoved.increment(); } else { - LogicNode replacement = evaluateCondition(condition, trueConstant, falseConstant); - if (replacement != null) { - guard.setCondition(replacement); - if (condition.usages().isEmpty()) { - GraphUtil.killWithUnusedFloatingInputs(condition); + ValueNode anchor = state.trueConditions.get(condition); + if (anchor != null) { + if (!guard.negated()) { + guard.replaceAtUsages(anchor); + metricGuardsRemoved.increment(); + GraphUtil.killWithUnusedFloatingInputs(guard); } - metricGuardsRemoved.increment(); } else { - registerCondition(!guard.negated(), condition, guard); + anchor = state.falseConditions.get(condition); + if (anchor != null) { + if (guard.negated()) { + guard.replaceAtUsages(anchor); + metricGuardsRemoved.increment(); + GraphUtil.killWithUnusedFloatingInputs(guard); + } + } else { + registerCondition(!guard.negated(), condition, guard); + } } } } diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java Mon Jul 15 14:09:44 2013 +0200 @@ -22,6 +22,7 @@ */ package com.oracle.graal.printer; +import static com.oracle.graal.compiler.GraalDebugConfig.*; import static com.oracle.graal.phases.GraalOptions.*; import java.io.*; @@ -32,7 +33,6 @@ import java.util.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.compiler.*; import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.phases.schedule.*; @@ -151,8 +151,8 @@ // Check for method scopes that must be closed since the previous dump. for (int i = 0; i < previousInlineContext.size(); ++i) { if (i >= inlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) { - for (int j = previousInlineContext.size() - 1; j >= i; --j) { - closeScope(); + for (int inlineDepth = previousInlineContext.size() - 1; inlineDepth >= i; --inlineDepth) { + closeScope(inlineDepth); } break; } @@ -161,8 +161,8 @@ // Check for method scopes that must be opened since the previous dump. for (int i = 0; i < inlineContext.size(); ++i) { if (i >= previousInlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) { - for (int j = i; j < inlineContext.size(); ++j) { - openScope(inlineContext.get(j), j == 0); + for (int inlineDepth = i; inlineDepth < inlineContext.size(); ++inlineDepth) { + openScope(inlineContext.get(inlineDepth), inlineDepth); } break; } @@ -191,11 +191,11 @@ private static List getInlineContext() { List result = new ArrayList<>(); - Object last = null; + Object lastMethodOrGraph = null; for (Object o : Debug.context()) { - JavaMethod method = GraalDebugConfig.asJavaMethod(o); + JavaMethod method = asJavaMethod(o); if (method != null) { - if (last != method) { + if (lastMethodOrGraph == null || asJavaMethod(lastMethodOrGraph) != method) { result.add(MetaUtil.format("%H::%n(%p)", method)); } else { // This prevents multiple adjacent method context objects for the same method @@ -211,7 +211,9 @@ result.add(debugDumpScope.name); } } - last = o; + if (o instanceof JavaMethod || o instanceof Graph) { + lastMethodOrGraph = o; + } } if (result.isEmpty()) { result.add("Top Scope"); @@ -229,8 +231,8 @@ return result; } - private void openScope(String name, boolean showThread) { - String prefix = showThread ? Thread.currentThread().getName() + ":" : ""; + private void openScope(String name, int inlineDepth) { + String prefix = inlineDepth == 0 ? Thread.currentThread().getName() + ":" : ""; try { printer.beginGroup(prefix + name, name, Debug.contextLookup(ResolvedJavaMethod.class), -1); } catch (IOException e) { @@ -239,7 +241,8 @@ } } - private void closeScope() { + private void closeScope(int inlineDepth) { + dumpIds[inlineDepth] = 0; try { printer.endGroup(); } catch (IOException e) { @@ -250,8 +253,8 @@ @Override public void close() { - for (int i = 0; i < previousInlineContext.size(); i++) { - closeScope(); + for (int inlineDepth = 0; inlineDepth < previousInlineContext.size(); inlineDepth++) { + closeScope(inlineDepth); } if (printer != null) { printer.close(); diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java Mon Jul 15 14:09:44 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Mon Jul 15 14:09:44 2013 +0200 @@ -32,6 +32,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.nodes.virtual.*; +import com.oracle.graal.options.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.graph.*; import com.oracle.graal.phases.schedule.*; @@ -39,21 +40,26 @@ public class PartialEscapePhase extends EffectsPhase { + //@formatter:off + @Option(help = "") + public static final OptionValue OptEarlyReadElimination = new OptionValue<>(true); + //@formatter:on + + private final boolean readElimination; + public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer) { + this(iterative, OptEarlyReadElimination.getValue(), canonicalizer); + } + + public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer) { super(iterative ? EscapeAnalysisIterations.getValue() : 1, canonicalizer); + this.readElimination = readElimination; } @Override protected void run(StructuredGraph graph, PhaseContext context) { if (VirtualUtil.matches(graph, EscapeAnalyzeOnly.getValue())) { - boolean analyzableNodes = false; - for (Node node : graph.getNodes()) { - if (node instanceof VirtualizableAllocation) { - analyzableNodes = true; - break; - } - } - if (analyzableNodes) { + if (readElimination || graph.getNodes().filterInterface(VirtualizableAllocation.class).isNotEmpty()) { runAnalysis(graph, context); } } @@ -61,7 +67,11 @@ @Override protected Closure createEffectsClosure(PhaseContext context, SchedulePhase schedule) { - return new PartialEscapeClosure.Final(schedule, context.getRuntime(), context.getAssumptions()); + if (readElimination) { + return new ReadEliminationPEClosure(schedule, context.getRuntime(), context.getAssumptions()); + } else { + return new PartialEscapeClosure.Final(schedule, context.getRuntime(), context.getAssumptions()); + } } public static Map getHints(StructuredGraph graph) { diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEBlockState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEBlockState.java Mon Jul 15 14:09:44 2013 +0200 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2011, 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.virtual.phases.ea; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.virtual.*; + +public class ReadEliminationPEBlockState extends PartialEscapeBlockState { + + final HashMap readCache; + + static class ReadCacheEntry { + + public final ResolvedJavaField identity; + public final ValueNode object; + + public ReadCacheEntry(ResolvedJavaField identity, ValueNode object) { + this.identity = identity; + this.object = object; + } + + @Override + public int hashCode() { + int result = 31 + ((identity == null) ? 0 : identity.hashCode()); + return 31 * result + ((object == null) ? 0 : object.hashCode()); + } + + @Override + public boolean equals(Object obj) { + ReadCacheEntry other = (ReadCacheEntry) obj; + return identity == other.identity && object == other.object; + } + + @Override + public String toString() { + return object + ":" + identity; + } + } + + public ReadEliminationPEBlockState() { + readCache = new HashMap<>(); + } + + public ReadEliminationPEBlockState(ReadEliminationPEBlockState other) { + super(other); + readCache = new HashMap<>(other.readCache); + } + + @Override + public String toString() { + return super.toString() + " " + readCache; + } + + @Override + protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List values) { + if (virtual instanceof VirtualInstanceNode) { + VirtualInstanceNode instance = (VirtualInstanceNode) virtual; + for (int i = 0; i < instance.entryCount(); i++) { + readCache.put(new ReadCacheEntry(instance.field(i), representation), values.get(i)); + } + } + } + + @Override + public boolean equivalentTo(ReadEliminationPEBlockState other) { + if (!compareMapsNoSize(readCache, other.readCache)) { + return false; + } + return super.equivalentTo(other); + } + + public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) { + ValueNode cacheObject; + ObjectState obj = getObjectState(object); + if (obj != null) { + assert !obj.isVirtual(); + cacheObject = obj.getMaterializedValue(); + } else { + cacheObject = object; + } + readCache.put(new ReadCacheEntry(identity, cacheObject), value); + } + + public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) { + ValueNode cacheObject; + ObjectState obj = getObjectState(object); + if (obj != null) { + assert !obj.isVirtual(); + cacheObject = obj.getMaterializedValue(); + } else { + cacheObject = object; + } + ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject)); + obj = getObjectState(cacheValue); + if (obj != null) { + assert !obj.isVirtual(); + cacheValue = obj.getMaterializedValue(); + } else { + // assert !scalarAliases.containsKey(cacheValue); + cacheValue = getScalarAlias(cacheValue); + } + return cacheValue; + } + + public void killReadCache() { + readCache.clear(); + } + + public void killReadCache(ResolvedJavaField identity) { + Iterator> iter = readCache.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + if (entry.getKey().identity == identity) { + iter.remove(); + } + } + } + + public Map getReadCache() { + return readCache; + } +} diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java Mon Jul 15 14:09:44 2013 +0200 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2011, 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.virtual.phases.ea; + +import static com.oracle.graal.api.meta.LocationIdentity.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.PhiNode.PhiType; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.virtual.phases.ea.ReadEliminationPEBlockState.ReadCacheEntry; + +public class ReadEliminationPEClosure extends PartialEscapeClosure { + + public ReadEliminationPEClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) { + super(schedule, metaAccess, assumptions); + } + + @Override + protected ReadEliminationPEBlockState getInitialState() { + return new ReadEliminationPEBlockState(); + } + + @Override + protected boolean processNode(Node node, ReadEliminationPEBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) { + boolean deleted = super.processNode(node, state, effects, lastFixedNode); + if (!deleted) { + if (node instanceof LoadFieldNode) { + LoadFieldNode load = (LoadFieldNode) node; + ValueNode cachedValue = state.getReadCache(load.object(), load.field()); + if (cachedValue != null) { + effects.replaceAtUsages(load, cachedValue); + state.addScalarAlias(load, cachedValue); + } else { + state.addReadCache(load.object(), load.field(), load); + } + deleted = true; + } else if (node instanceof StoreFieldNode) { + StoreFieldNode store = (StoreFieldNode) node; + ValueNode cachedValue = state.getReadCache(store.object(), store.field()); + + if (state.getScalarAlias(store.value()) == cachedValue) { + effects.deleteFixedNode(store); + deleted = true; + } + state.killReadCache(store.field()); + state.addReadCache(store.object(), store.field(), store.value()); + } else if (node instanceof MemoryCheckpoint.Single) { + METRIC_MEMORYCHECKOINT.increment(); + LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); + processIdentity(state, identity); + } else if (node instanceof MemoryCheckpoint.Multi) { + METRIC_MEMORYCHECKOINT.increment(); + for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) { + processIdentity(state, identity); + } + } + } + return deleted; + } + + private static void processIdentity(ReadEliminationPEBlockState state, LocationIdentity identity) { + if (identity instanceof ResolvedJavaField) { + state.killReadCache((ResolvedJavaField) identity); + } else if (identity == ANY_LOCATION) { + state.killReadCache(); + } + } + + @Override + protected void processLoopExit(LoopExitNode exitNode, ReadEliminationPEBlockState initialState, ReadEliminationPEBlockState exitState, GraphEffectList effects) { + super.processLoopExit(exitNode, initialState, exitState, effects); + + for (Map.Entry entry : exitState.getReadCache().entrySet()) { + if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) { + ProxyNode proxy = new ProxyNode(exitState.getReadCache(entry.getKey().object, entry.getKey().identity), exitNode, PhiType.Value, null); + effects.addFloatingNode(proxy, "readCacheProxy"); + entry.setValue(proxy); + } + } + } + + @Override + protected ReadEliminationPEBlockState cloneState(ReadEliminationPEBlockState other) { + return new ReadEliminationPEBlockState(other); + } + + @Override + protected MergeProcessor createMergeProcessor(Block merge) { + return new ReadEliminationMergeProcessor(merge); + } + + private class ReadEliminationMergeProcessor extends MergeProcessor { + + public ReadEliminationMergeProcessor(Block mergeBlock) { + super(mergeBlock); + } + + @Override + protected void merge(List states) { + super.merge(states); + + mergeReadCache(states); + } + + private void mergeReadCache(List states) { + for (Map.Entry entry : states.get(0).readCache.entrySet()) { + ReadCacheEntry key = entry.getKey(); + ValueNode value = entry.getValue(); + boolean phi = false; + for (int i = 1; i < states.size(); i++) { + ValueNode otherValue = states.get(i).readCache.get(key); + if (otherValue == null) { + value = null; + phi = false; + break; + } + if (!phi && otherValue != value) { + phi = true; + } + } + if (phi) { + PhiNode phiNode = getCachedPhi(entry, value.kind()); + mergeEffects.addFloatingNode(phiNode, "mergeReadCache"); + for (int i = 0; i < states.size(); i++) { + afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity)); + } + newState.readCache.put(key, phiNode); + } else if (value != null) { + newState.readCache.put(key, value); + } + } + for (PhiNode phi : merge.phis()) { + if (phi.kind() == Kind.Object) { + for (Map.Entry entry : states.get(0).readCache.entrySet()) { + if (entry.getKey().object == phi.valueAt(0)) { + mergeReadCachePhi(phi, entry.getKey().identity, states); + } + } + + } + } + } + + private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, 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); + if (value == null) { + return; + } + values[i] = value; + } + + PhiNode phiNode = getCachedPhi(new ReadCacheEntry(identity, phi), values[0].kind()); + 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); + } + } +} diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java Mon Jul 15 14:09:44 2013 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, 2012, 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.truffle.api.dsl.test; + +import static com.oracle.truffle.api.dsl.test.TestHelper.*; +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.BinaryNodeTest.BinaryNode; +import com.oracle.truffle.api.dsl.test.PolymorphicTest2Factory.Node1Factory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.NodeInfo.Kind; + +public class PolymorphicTest2 { + + @Test + public void testMultipleTypes() { + /* Tests the unexpected polymorphic case. */ + TestRootNode node = TestHelper.createRoot(Node1Factory.getInstance()); + assertEquals(21, executeWith(node, false, false)); + assertEquals(42, executeWith(node, 21, 21)); + assertEquals("(boolean,int)", executeWith(node, false, 42)); + assertEquals(Kind.POLYMORPHIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind()); + } + + @SuppressWarnings("unused") + @PolymorphicLimit(3) + abstract static class Node1 extends BinaryNode { + + @Specialization(order = 1) + int add(int left, int right) { + return 42; + } + + @Specialization(order = 2) + int add(boolean left, boolean right) { + return 21; + } + + @Specialization(order = 4) + String add(boolean left, int right) { + return "(boolean,int)"; + } + + } + +} diff -r e2f5ae9afdc5 -r 64740220db85 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 15 14:09:44 2013 +0200 @@ -352,17 +352,26 @@ public static void replaceChild(Node parent, Node oldChild, Node newChild) { NodeClass nodeClass = NodeClass.get(parent.getClass()); - for (long fieldOffset : nodeClass.childOffsets) { + long[] fieldOffsets = nodeClass.childOffsets; + for (int i = 0; i < fieldOffsets.length; i++) { + long fieldOffset = fieldOffsets[i]; if (unsafe.getObject(parent, fieldOffset) == oldChild) { + assert assertAssignable(nodeClass, parent, oldChild, newChild); unsafe.putObject(parent, fieldOffset, newChild); } } - for (long fieldOffset : nodeClass.childrenOffsets) { - Node[] array = (Node[]) unsafe.getObject(parent, fieldOffset); - if (array != null) { - for (int i = 0; i < array.length; i++) { - if (array[i] == oldChild) { - array[i] = newChild; + + long[] childrenOffsets = nodeClass.childrenOffsets; + for (int i = 0; i < childrenOffsets.length; i++) { + long fieldOffset = childrenOffsets[i]; + Object arrayObject = unsafe.getObject(parent, fieldOffset); + if (arrayObject != null) { + assert arrayObject instanceof Node[] : "Children 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; } } @@ -370,6 +379,26 @@ } } + private static boolean assertAssignable(NodeClass clazz, Node parent, Object oldValue, 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; + } + } + } + return true; + } + /** Returns all declared fields in the class hierarchy. */ private static Field[] getAllFields(Class clazz) { Field[] declaredFields = clazz.getDeclaredFields(); @@ -660,4 +689,5 @@ p.print(" "); } } + } diff -r e2f5ae9afdc5 -r 64740220db85 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 Thu Jul 11 22:14:27 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Jul 15 14:09:44 2013 +0200 @@ -32,6 +32,7 @@ import javax.lang.model.util.*; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.NodeInfo.Kind; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.ast.*; @@ -1226,6 +1227,12 @@ private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph, CodeExecutableElement genericPolymorphMethod) { String name = executeCachedName(polymorph); CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED), polymorph.getReturnType().getType(), name); + + ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0); + boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); + if (sourceThrowsUnexpected) { + cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class)); + } addInternalValueParameters(cachedExecute, polymorph, true, true); if (polymorph == node.getGenericPolymorphicSpecialization()) { @@ -2441,11 +2448,18 @@ } if (!returnBuilder.isEmpty()) { - builder.startReturn(); + + ExecutableTypeData sourceExecutableType = node.findExecutableType(specialization.getReturnType().getTypeSystemType(), 0); + boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); + boolean targetSupportsUnexpected = executable.hasUnexpectedValue(getContext()); TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType()); TypeData sourceType = specialization.getReturnType().getTypeSystemType(); + if (specialization.isPolymorphic() && sourceThrowsUnexpected && !targetSupportsUnexpected) { + builder.startTryBlock(); + } + builder.startReturn(); if (targetType == null || sourceType == null) { builder.tree(returnBuilder.getRoot()); } else if (sourceType.needsCastTo(getContext(), targetType)) { @@ -2454,6 +2468,19 @@ builder.tree(returnBuilder.getRoot()); } builder.end(); + if (specialization.isPolymorphic() && sourceThrowsUnexpected && !targetSupportsUnexpected) { + builder.end(); + builder.startCatchBlock(getUnexpectedValueException(), "ex"); + builder.startReturn(); + CodeTree returns = CodeTreeBuilder.singleString("ex.getResult()"); + if (sourceType.needsCastTo(getContext(), targetType)) { + builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), returns)); + } else { + builder.tree(returns); + } + builder.end(); + builder.end(); + } } if (!specialization.getExceptions().isEmpty()) { diff -r e2f5ae9afdc5 -r 64740220db85 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java Mon Jul 15 14:09:44 2013 +0200 @@ -118,8 +118,8 @@ } }; - server = new Server(callback, false); - binaryServer = new Server(callback, true); + server = new Server(getDocument(), callback, false); + binaryServer = new Server(getDocument(), callback, true); } public void clear() { diff -r e2f5ae9afdc5 -r 64740220db85 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/ImportAction.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/ImportAction.java Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/ImportAction.java Mon Jul 15 14:09:44 2013 +0200 @@ -110,14 +110,14 @@ } }; final GraphParser parser; + final OutlineTopComponent component = OutlineTopComponent.findInstance(); if (file.getName().endsWith(".xml")) { parser = new Parser(channel, monitor, null); } else if (file.getName().endsWith(".bgv")) { - parser = new BinaryParser(channel, monitor, null); + parser = new BinaryParser(channel, monitor, component.getDocument(), null); } else { parser = null; } - final OutlineTopComponent component = OutlineTopComponent.findInstance(); RequestProcessor.getDefault().post(new Runnable() { @Override public void run() { diff -r e2f5ae9afdc5 -r 64740220db85 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Mon Jul 15 14:09:44 2013 +0200 @@ -69,6 +69,7 @@ private final List constantPool; private final ByteBuffer buffer; private final ReadableByteChannel channel; + private final GraphDocument rootDocument; private final Deque folderStack; private final ParseMonitor monitor; @@ -240,12 +241,13 @@ } } - public BinaryParser(ReadableByteChannel channel, ParseMonitor monitor, GroupCallback callback) { + public BinaryParser(ReadableByteChannel channel, ParseMonitor monitor, GraphDocument rootDocument, GroupCallback callback) { this.callback = callback; constantPool = new ArrayList<>(); buffer = ByteBuffer.allocateDirect(256 * 1024); buffer.flip(); this.channel = channel; + this.rootDocument = rootDocument; folderStack = new LinkedList<>(); this.monitor = monitor; } @@ -527,8 +529,7 @@ @Override public GraphDocument parse() throws IOException { - GraphDocument doc = new GraphDocument(); - folderStack.push(doc); + folderStack.push(rootDocument); if (monitor != null) { monitor.setState("Starting parsing"); } @@ -542,7 +543,7 @@ if (monitor != null) { monitor.setState("Finished parsing"); } - return doc; + return rootDocument; } private void parseRoot() throws IOException { diff -r e2f5ae9afdc5 -r 64740220db85 src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Client.java --- a/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Client.java Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Client.java Mon Jul 15 14:09:44 2013 +0200 @@ -24,6 +24,7 @@ */ package com.sun.hotspot.igv.connection; +import com.sun.hotspot.igv.data.GraphDocument; import com.sun.hotspot.igv.data.serialization.BinaryParser; import com.sun.hotspot.igv.data.serialization.Parser; import com.sun.hotspot.igv.data.services.GroupCallback; @@ -34,12 +35,14 @@ public class Client implements Runnable { private final boolean binary; private final SocketChannel socket; + private final GraphDocument rootDocument; private final GroupCallback callback; - public Client(SocketChannel socket, GroupCallback callback, boolean binary) { + public Client(SocketChannel socket, GraphDocument rootDocument, GroupCallback callback, boolean binary) { this.callback = callback; this.socket = socket; this.binary = binary; + this.rootDocument = rootDocument; } @Override @@ -49,7 +52,7 @@ final SocketChannel channel = socket; channel.configureBlocking(true); if (binary) { - new BinaryParser(channel, null, callback).parse(); + new BinaryParser(channel, null, rootDocument, callback).parse(); } else { new Parser(channel, null, callback).parse(); } diff -r e2f5ae9afdc5 -r 64740220db85 src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Server.java --- a/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Server.java Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Server.java Mon Jul 15 14:09:44 2013 +0200 @@ -24,6 +24,7 @@ */ package com.sun.hotspot.igv.connection; +import com.sun.hotspot.igv.data.GraphDocument; import com.sun.hotspot.igv.data.services.GroupCallback; import com.sun.hotspot.igv.settings.Settings; import java.io.IOException; @@ -43,12 +44,14 @@ public class Server implements PreferenceChangeListener { private final boolean binary; private ServerSocketChannel serverSocket; + private final GraphDocument rootDocument; private final GroupCallback callback; private int port; private Runnable serverRunnable; - public Server(GroupCallback callback, boolean binary) { + public Server(GraphDocument rootDocument, GroupCallback callback, boolean binary) { this.binary = binary; + this.rootDocument = rootDocument; this.callback = callback; initializeNetwork(); Settings.get().addPreferenceChangeListener(this); @@ -87,7 +90,7 @@ clientSocket.close(); return; } - RequestProcessor.getDefault().post(new Client(clientSocket, callback, binary), 0, Thread.MAX_PRIORITY); + RequestProcessor.getDefault().post(new Client(clientSocket, rootDocument, callback, binary), 0, Thread.MAX_PRIORITY); } catch (IOException ex) { serverSocket = null; NotifyDescriptor message = new NotifyDescriptor.Message("Error during listening for incoming connections. Listening for incoming binary data is disabled.", NotifyDescriptor.ERROR_MESSAGE); diff -r e2f5ae9afdc5 -r 64740220db85 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Mon Jul 15 14:09:44 2013 +0200 @@ -867,6 +867,10 @@ set_address("narrowOopBase", Universe::narrow_oop_base()); set_int("narrowOopShift", Universe::narrow_oop_shift()); set_int("logMinObjAlignment", LogMinObjAlignmentInBytes); + set_address("narrowKlassBase", Universe::narrow_klass_base()); + set_int("narrowKlassShift", Universe::narrow_klass_shift()); + set_int("logKlassAlignment", LogKlassAlignmentInBytes); + set_int("g1CardQueueIndexOffset", in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_index())); set_int("g1CardQueueBufferOffset", in_bytes(JavaThread::dirty_card_queue_offset() + PtrQueue::byte_offset_of_buf())); @@ -1186,6 +1190,11 @@ return JNIHandles::make_local(*((oop*)address)); C2V_END +C2V_VMENTRY(jlong, readUnsafeKlassPointer, (JNIEnv *env, jobject, jobject o)) + oop resolved_o = JNIHandles::resolve(o); + jlong klass = (jlong)(address)resolved_o->klass(); + return klass; +C2V_END #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) @@ -1265,6 +1274,7 @@ {CC"reprofile", CC"("METASPACE_METHOD")V", FN_PTR(reprofile)}, {CC"invalidateInstalledCode", CC"("HS_INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)}, {CC"readUnsafeUncompressedPointer", CC"("OBJECT"J)"OBJECT, FN_PTR(readUnsafeUncompressedPointer)}, + {CC"readUnsafeKlassPointer", CC"("OBJECT")J", FN_PTR(readUnsafeKlassPointer)}, }; int CompilerToVM_methods_count() { diff -r e2f5ae9afdc5 -r 64740220db85 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/vm/runtime/arguments.cpp Mon Jul 15 14:09:44 2013 +0200 @@ -2208,12 +2208,9 @@ #ifdef GRAAL if (UseCompressedKlassPointers) { if (IgnoreUnrecognizedVMOptions) { - warning("UseCompressedKlassPointers is disabled, because it is not supported by Graal"); - FLAG_SET_CMDLINE(bool, UseCompressedKlassPointers, false); + FLAG_SET_CMDLINE(bool, UseCompressedKlassPointers, true); } else { - jio_fprintf(defaultStream::error_stream(), - "UseCompressedKlassPointers are not supported in Graal at the moment\n"); - status = false; + status = true; } } else { // This prevents the flag being set to true by set_ergonomics_flags() diff -r e2f5ae9afdc5 -r 64740220db85 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Thu Jul 11 22:14:27 2013 +0200 +++ b/src/share/vm/runtime/deoptimization.cpp Mon Jul 15 14:09:44 2013 +0200 @@ -1300,8 +1300,8 @@ nmethodLocker nl(fr.pc()); // Log a message - Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT, - trap_request, fr.pc()); + Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT " relative=" INTPTR_FORMAT, + trap_request, fr.pc(), fr.pc() - fr.cb()->code_begin()); { ResourceMark rm;