# HG changeset patch # User twisti # Date 1373936297 25200 # Node ID fbeda94727f86d80861facdd7c5e06cd3b93a6f1 # Parent dfc4b73e79e810165b9dff3984dfc683c470d577# Parent 395d34c10e26faff92adcacd13a868b86806c2a7 Merge diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java --- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Mon Jul 15 17:58:17 2013 -0700 @@ -79,13 +79,15 @@ * created by JNI since these JNI global references do not move. */ public final void mov(Register a, Object obj) { + String regName = "$d" + a.encoding(); if (obj instanceof Class) { Class clazz = (Class) obj; long refHandle = OkraUtil.getRefHandle(clazz); String className = clazz.getName(); - String regName = "$d" + a.encoding(); emitString("mov_b64 " + regName + ", 0x" + Long.toHexString(refHandle) + "; // handle for " + className); emitString("ld_global_u64 " + regName + ", [" + regName + "];"); + } else if (obj == null) { + emitString("mov_b64 " + regName + ", 0x0; // null object"); } else { throw GraalInternalError.shouldNotReachHere("mov from object not a class"); } @@ -101,16 +103,32 @@ } } + private void emitAddrOp(String instr, Value reg, HSAILAddress addr) { + emitString(instr + " " + HSAIL.mapRegister(reg) + ", " + mapAddress(addr) + ";"); + } + public final void emitLoad(Value dest, HSAILAddress addr) { - emitString("ld_global_" + getArgType(dest) + " " + HSAIL.mapRegister(dest) + ", " + mapAddress(addr) + ";"); + emitLoad(dest, addr, getArgType(dest)); + } + + public final void emitLoad(Value dest, HSAILAddress addr, String argTypeStr) { + emitAddrOp("ld_global_" + argTypeStr, dest, addr); + } + + public final void emitLda(Value dest, HSAILAddress addr) { + emitAddrOp("lda_global_u64", dest, addr); + } + + public final void emitStore(Value src, HSAILAddress addr) { + emitStore(src, addr, getArgType(src)); + } + + public final void emitStore(Value dest, HSAILAddress addr, String argTypeStr) { + emitAddrOp("st_global_" + argTypeStr, dest, addr); } public final void emitSpillLoad(Value dest, Value src) { - emitString("ld_spill_" + getArgType(dest) + " " + HSAIL.mapRegister(dest) + ", " + HSAIL.mapStackSlot(src) + ";"); - } - - public final void emitStore(Value src, HSAILAddress addr) { - emitString("st_global_" + getArgType(src) + " " + HSAIL.mapRegister(src) + ", " + mapAddress(addr) + ";"); + emitString("ld_spill_" + getArgType(dest) + " " + HSAIL.mapRegister(dest) + ", " + mapStackSlot(src, getArgSize(dest)) + ";"); } public final void emitSpillStore(Value src, Value dest) { @@ -122,7 +140,21 @@ if (maxStackOffset < stackoffset) { maxStackOffset = stackoffset; } - emitString("st_spill_" + getArgType(src) + " " + HSAIL.mapRegister(src) + ", " + HSAIL.mapStackSlot(dest) + ";"); + emitString("st_spill_" + getArgType(src) + " " + HSAIL.mapRegister(src) + ", " + mapStackSlot(dest, getArgSize(src)) + ";"); + } + + /** + * The mapping to stack slots is always relative to the beginning + * of the spillseg. HSAIL.getStackOffset returns the positive + * version of the originally negative offset. Then we back up + * from that by the argSize in bytes. This ensures that slots of + * different size do not overlap, even though we have converted + * from negative to positive offsets. + */ + public static String mapStackSlot(Value reg, int argSize) { + long offset = HSAIL.getStackOffset(reg); + int argSizeBytes = argSize / 8; + return "[%spillseg]" + "[" + (offset - argSizeBytes) + "]"; } public void cbr(String target1) { @@ -181,7 +213,9 @@ public void emitCompare(Value src0, Value src1, String condition, boolean unordered, boolean isUnsignedCompare) { String prefix = "cmp_" + condition + (unordered ? "u" : "") + "_b1_" + (isUnsignedCompare ? getArgTypeForceUnsigned(src1) : getArgType(src1)); - emitString(prefix + " $c0, " + mapRegOrConstToString(src0) + ", " + mapRegOrConstToString(src1) + ";"); + String comment = (isConstant(src1) && (src1.getKind() == Kind.Object) + && (asConstant(src1).asObject() == null) ? " // null test " : ""); + emitString(prefix + " $c0, " + mapRegOrConstToString(src0) + ", " + mapRegOrConstToString(src1) + ";" + comment); } public void emitConvert(Value dest, Value src) { @@ -210,7 +244,14 @@ case Double: return Double.toString(consrc.asDouble()); case Long: - return Long.toString(consrc.asLong()); + return "0x" + Long.toHexString(consrc.asLong()); + case Object: + Object obj = consrc.asObject(); + if (obj == null) { + return "0"; + } else { + throw GraalInternalError.shouldNotReachHere("unknown type: " + src); + } default: throw GraalInternalError.shouldNotReachHere("unknown type: " + src); } @@ -223,14 +264,68 @@ emit(mnemonic + "_" + prefix, dest, "", src0, src1); } + public final void emitForceUnsigned(String mnemonic, Value dest, Value src0, Value src1) { + String prefix = getArgTypeForceUnsigned(dest); + emit(mnemonic + "_" + prefix, dest, "", src0, src1); + } + + private void emit(String instr, Value dest, String controlRegString, Value src0, Value src1) { assert (!isConstant(dest)); emitString(String.format("%s %s, %s%s, %s;", instr, HSAIL.mapRegister(dest), controlRegString, mapRegOrConstToString(src0), mapRegOrConstToString(src1))); } + private void emit(String instr, Value dest, Value src0, Value src1, Value src2) { + assert (!isConstant(dest)); + emitString(String.format("%s %s, %s, %s, %s;", instr, HSAIL.mapRegister(dest), mapRegOrConstToString(src0), + mapRegOrConstToString(src1), mapRegOrConstToString(src2))); + } + + public final void cmovCommon(Value dest, Value trueReg, Value falseReg, int width) { String instr = (width == 32 ? "cmov_b32" : "cmov_b64"); emit(instr, dest, "$c0, ", trueReg, falseReg); } + + /** + * Emit code to build a 64-bit pointer from a compressed-oop and the associated base and shift. + * We only emit this if base and shift are not both zero. + */ + public void emitCompressedOopDecode(Value result, long narrowOopBase, int narrowOopShift) { + if (narrowOopBase == 0) { + emit("shl", result, result, Constant.forInt(narrowOopShift)); + } else if (narrowOopShift == 0) { + // only use add if result is not starting as null (unsigned compare) + emitCompare(result, Constant.forLong(0), "eq", false, true); + emit("add", result, result, Constant.forLong(narrowOopBase)); + cmovCommon(result, Constant.forLong(0), result, 64); + } else { + // only use mad if result is not starting as null (unsigned compare) + emitCompare(result, Constant.forLong(0), "eq", false, true); + emit("mad_u64 ", result, result, Constant.forInt(1 << narrowOopShift), Constant.forLong(narrowOopBase)); + cmovCommon(result, Constant.forLong(0), result, 64); + } + } + + /** + * Emit code to build a 32-bit compressed pointer from a full + * 64-bit pointer using the associated base and shift. We only + * emit this if base and shift are not both zero. + */ + public void emitCompressedOopEncode(Value result, long narrowOopBase, int narrowOopShift) { + if (narrowOopBase != 0) { + // only use sub if result is not starting as null (unsigned compare) + emitCompare(result, Constant.forLong(0), "eq", false, true); + emit("sub", result, result, Constant.forLong(narrowOopBase)); + cmovCommon(result, Constant.forLong(0), result, 64); + } + if (narrowOopShift != 0) { + emit("shr", result, result, Constant.forInt(narrowOopShift)); + } + } + + public void emitComment(String comment) { + emitString(comment); + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Mon Jul 15 17:58:17 2013 -0700 @@ -30,6 +30,7 @@ import com.oracle.graal.compiler.hsail.HSAILCompilationResult; import java.lang.reflect.Method; import java.io.*; +import static com.oracle.graal.phases.GraalOptions.*; public abstract class GraalKernelTester extends KernelTester { @@ -61,4 +62,15 @@ return hsailSource; } + public boolean aggressiveInliningEnabled() { + return (InlineEverything.getValue()); + } + + public boolean canHandleHSAILMethodCalls() { + // needs 2 things, backend needs to be able to generate such calls, and target needs to be + // able to run them + boolean canGenerateCalls = false; // not implemented yet + boolean canExecuteCalls = runningOnSimulator(); + return (canGenerateCalls && canExecuteCalls); + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java --- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/KernelTester.java Mon Jul 15 17:58:17 2013 -0700 @@ -150,6 +150,12 @@ } private boolean compareObjects(Object first, Object second) { + if (first == null) { + return (second == null); + } + if (second == null) { + return (first == null); + } Class clazz = first.getClass(); if (clazz != second.getClass()) { return false; @@ -265,6 +271,11 @@ Object getElement(Object ary, int index) { return Array.get(ary, index); } + + @Override + boolean isEquals(Object firstElement, Object secondElement) { + return compareObjects(firstElement, secondElement); + } } /** @@ -496,7 +507,7 @@ String hsailSource = getHSAILSource(testMethod); if (!okraLibExists) { if (!gaveNoOkraWarning) { - logger.fine("No Okra library detected, skipping all KernelTester tests in " + this.getClass().getPackage().getName()); + logger.severe("No Okra library detected, skipping all KernelTester tests in " + this.getClass().getPackage().getName()); gaveNoOkraWarning = true; } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Float2DMatrixBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Float2DMatrixBase.java Mon Jul 15 17:58:17 2013 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009, 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.hsail.test; + +import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; + +/** + * Base class used by other Float2DMatrix tests. + */ +public abstract class Float2DMatrixBase extends GraalKernelTester { + + float[][] matrixA; + float[][] matrixB; + @Result float[][] outMatrix; + + public void setupArrays(int range) { + matrixA = new float[range][]; + matrixB = new float[range][]; + outMatrix = new float[range][]; + for (int j = 0; j < range; j++) { + matrixA[j] = new float[range]; + matrixB[j] = new float[range]; + outMatrix[j] = new float[range]; + for (int k = 0; k < range; k++) { + matrixA[j][k] = (j + k) % 7; + matrixB[j][k] = (j + k + 1) % 8; + } + } + } +} diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Float2DMatrixMultiplyRangeFinalTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Float2DMatrixMultiplyRangeFinalTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009, 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.hsail.test; + +import org.junit.*; + +/** + * Tests the mixing of 32-bit and 64-bit spills caused by loop unrolling. + */ +public class Float2DMatrixMultiplyRangeFinalTest extends Float2DMatrixBase { + + static final int range = 6; + + public void run(int gid) { + for (int j = 0; j < range; j++) { + float sum = 0; + for (int k = 0; k < range; k++) { + sum += (matrixA[gid][k] * matrixB[k][j]); + } + outMatrix[gid][j] = sum; + } + } + + @Override + public void runTest() { + setupArrays(range); + dispatchMethodKernel(range); + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Float2DMatrixMultiplyTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/Float2DMatrixMultiplyTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009, 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.hsail.test; + +import org.junit.Test; + +/** + * Tests 2D array access for Matrix Multiplication. + */ +public class Float2DMatrixMultiplyTest extends Float2DMatrixBase { + int range = 20; + + public void run(int gid) { + for (int j = 0; j < range; j++) { + float sum = 0; + for (int k = 0; k < range; k++) { + sum += (matrixA[gid][k] * matrixB[k][j]); + } + outMatrix[gid][j] = sum; + } + } + @Override + public void runTest() { + setupArrays(range); + dispatchMethodKernel(range); + } + + @Test + public void test() { + testGeneratedHsail(); + } +} diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjectStoreNullTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjectStoreNullTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2009, 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.hsail.test; + +import org.junit.*; + +/** + * Tests the storing of null in an Object array. + */ +public class ObjectStoreNullTest extends ObjectStoreTest { + + @Override + public void run(int gid) { + outIntegerArray[gid] = (gid % 3 == 1 ? null : inIntegerArray[gid]); + } + + @Test + @Override + public void test() { + testGeneratedHsail(); + } + +} diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjectStoreTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjectStoreTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2009, 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.hsail.test; + +import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; +import org.junit.Test; + +/** + * Tests the storing of objects into an array. + */ +public class ObjectStoreTest extends GraalKernelTester { + + static final int NUM = 20; + + @Result public Integer[] outIntegerArray = new Integer[NUM]; + public Integer[] inIntegerArray = new Integer[NUM]; + + void setupArrays() { + for (int i = 0; i < NUM; i++) { + inIntegerArray[i] = new Integer(i); + outIntegerArray[i] = null; + } + } + + public void run(int gid) { + outIntegerArray[gid] = inIntegerArray[gid]; + } + + @Override + public void runTest() { + setupArrays(); + + dispatchMethodKernel(NUM); + } + + @Test + public void test() { + testGeneratedHsail(); + } + +} diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMandelTest.java --- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMandelTest.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticMandelTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -25,6 +25,7 @@ import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester; import org.junit.Test; +import static org.junit.Assume.*; /** * Unit test that simulates the Mandelbrot application. The run method here is a static method @@ -79,6 +80,7 @@ @Test public void test() { + assumeTrue(runningOnSimulator()); testGeneratedHsail(); } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyCallTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticNBodyCallTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009, 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.hsail.test; + +import static org.junit.Assume.*; + +import org.junit.*; + +/** + * Unit test of NBody demo app. This version uses a call to the main routine which would normally be + * too large to inline. + */ +public class StaticNBodyCallTest extends StaticNBodyTest { + + public static void run(float[] inxyz, float[] outxyz, float[] invxyz, float[] outvxyz, int gid) { + StaticNBodyTest.run(inxyz, outxyz, invxyz, outvxyz, gid); + } + + @Test + @Override + public void test() { + assumeTrue(aggressiveInliningEnabled() || canHandleHSAILMethodCalls()); + testGeneratedHsail(); + } +} diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILCompilationResult.java --- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILCompilationResult.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILCompilationResult.java Mon Jul 15 17:58:17 2013 -0700 @@ -98,7 +98,7 @@ public static HSAILCompilationResult getHSAILCompilationResult(StructuredGraph graph) { Debug.dump(graph, "Graph"); - TargetDescription target = new TargetDescription(new HSAIL(), true, 1, 0, true); + TargetDescription target = new TargetDescription(new HSAIL(), true, 8, 0, true); HSAILBackend hsailBackend = new HSAILBackend(Graal.getRequiredCapability(GraalCodeCacheProvider.class), target); PhasePlan phasePlan = new PhasePlan(); GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.NONE); diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java --- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Mon Jul 15 17:58:17 2013 -0700 @@ -47,20 +47,29 @@ import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCompareBranchOp; import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCondMoveOp; import com.oracle.graal.lir.hsail.HSAILControlFlow.ReturnOp; +import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCallNoArgOp; +import com.oracle.graal.lir.hsail.HSAILControlFlow.ForeignCall1ArgOp; import com.oracle.graal.lir.hsail.HSAILMove.LeaOp; import com.oracle.graal.lir.hsail.HSAILMove.LoadOp; import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp; import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp; import com.oracle.graal.lir.hsail.HSAILMove.StoreOp; +import com.oracle.graal.lir.hsail.HSAILMove.LoadCompressedPointer; +import com.oracle.graal.lir.hsail.HSAILMove.StoreCompressedPointer; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.hotspot.meta.*; /** * This class implements the HSAIL specific portion of the LIR generator. */ public class HSAILLIRGenerator extends LIRGenerator { + private HotSpotRuntime runtime() { + return (HotSpotRuntime) runtime; + } + public static class HSAILSpillMoveFactory implements LIR.SpillMoveFactory { @Override @@ -123,6 +132,14 @@ } } + protected HSAILAddressValue asAddressValue(Value address) { + if (address instanceof HSAILAddressValue) { + return (HSAILAddressValue) address; + } else { + return emitAddress(address, 0, Value.ILLEGAL, 0); + } + } + public HSAILAddressValue emitAddress(Value base, long displacement, Value index, int scale) { AllocatableValue baseRegister; long finalDisp = displacement; @@ -163,27 +180,36 @@ return new HSAILAddressValue(target().wordKind, baseRegister, finalDisp); } - private HSAILAddressValue asAddress(Value address) { - if (address instanceof HSAILAddressValue) { - return (HSAILAddressValue) address; - } else { - return emitAddress(address, 0, Value.ILLEGAL, 0); - } + private static boolean isCompressCandidate(DeoptimizingNode access) { + return access != null && ((HeapAccess) access).compress(); } @Override - public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) { - HSAILAddressValue loadAddress = asAddress(address); + public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) { + HSAILAddressValue loadAddress = asAddressValue(address); Variable result = newVariable(kind); - append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null)); + LIRFrameState state = access != null ? state(access) : null; + assert access == null || access instanceof HeapAccess; + if (runtime().config.useCompressedOops && isCompressCandidate(access)) { + Variable scratch = newVariable(Kind.Long); + append(new LoadCompressedPointer(kind, result, scratch, loadAddress, state, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + } else { + append(new LoadOp(kind, result, loadAddress, state)); + } return result; } @Override - public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) { - HSAILAddressValue storeAddress = asAddress(address); + public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) { + HSAILAddressValue storeAddress = asAddressValue(address); + LIRFrameState state = access != null ? state(access) : null; Variable input = load(inputVal); - append(new StoreOp(kind, storeAddress, input, deopting != null ? state(deopting) : null)); + if (runtime().config.useCompressedOops && isCompressCandidate(access)) { + Variable scratch = newVariable(Kind.Long); + append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment)); + } else { + append(new StoreOp(kind, storeAddress, input, state)); + } } @Override @@ -460,6 +486,9 @@ case Int: append(new Op2Stack(IAND, result, a, loadNonConst(b))); break; + case Long: + append(new Op2Stack(LAND, result, a, loadNonConst(b))); + break; default: throw GraalInternalError.shouldNotReachHere(); } @@ -483,6 +512,9 @@ case Int: append(new ShiftOp(ISHL, result, a, b)); break; + case Long: + append(new ShiftOp(LSHL, result, a, b)); + break; default: GraalInternalError.shouldNotReachHere(); } @@ -501,6 +533,9 @@ case Int: append(new ShiftOp(IUSHR, result, a, b)); break; + case Long: + append(new ShiftOp(LUSHR, result, a, b)); + break; default: GraalInternalError.shouldNotReachHere(); } @@ -561,7 +596,23 @@ @Override protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { - throw new InternalError("NYI emitForeignCall"); + String callName = linkage.getDescriptor().getName(); + if (callName.equals("createOutOfBoundsException") || callName.equals("createNullPointerException")) { + // hack Alert !! + switch (arguments.length) { + case 0: + append(new ForeignCallNoArgOp(callName, result)); + break; + case 1: + append(new ForeignCall1ArgOp(callName, result, arguments[0])); + break; + default: + throw new InternalError("NYI emitForeignCall"); + } + + } else { + throw new InternalError("NYI emitForeignCall"); + } } @Override diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -22,8 +22,14 @@ */ package com.oracle.graal.compiler.test; +import static org.junit.Assert.*; + import org.junit.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.*; import com.oracle.graal.phases.common.*; /** @@ -89,4 +95,102 @@ test("search", e2, "e3", new Entry("e4")); } + + @SuppressWarnings("unused") + public static int testNullnessSnippet(Object a, Object b) { + if (a == null) { + if (a == b) { + if (b == null) { + return 1; + } else { + return -2; + } + } else { + if (b == null) { + return 3; + } else { + return 4; + } + } + } else { + if (a == b) { + if (b == null) { + return -5; + } else { + return 6; + } + } else { + if (b == null) { + return 7; + } else { + return 8; + } + } + } + } + + @Test + public void testNullness() { + test("testNullnessSnippet", null, null); + test("testNullnessSnippet", null, new Object()); + test("testNullnessSnippet", new Object(), null); + test("testNullnessSnippet", new Object(), new Object()); + + StructuredGraph graph = parse("testNullnessSnippet"); + new ConditionalEliminationPhase(runtime()).apply(graph); + new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph); + for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) { + assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0); + } + } + + @SuppressWarnings("unused") + public static int testDisjunctionSnippet(Object a) { + if (a instanceof Integer) { + if (a == null) { + return -1; + } else { + return 2; + } + } else { + return 3; + } + } + + @Test + public void testDisjunction() { + StructuredGraph graph = parse("testDisjunctionSnippet"); + new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph); + IfNode ifNode = (IfNode) graph.start().next(); + InstanceOfNode instanceOf = (InstanceOfNode) ifNode.condition(); + LogicDisjunctionNode disjunction = graph.unique(new LogicDisjunctionNode(graph.unique(new IsNullNode(graph.getLocal(0))), instanceOf)); + ifNode.setCondition(disjunction); + ifNode.negate(disjunction); + new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph); + new ConditionalEliminationPhase(runtime()).apply(graph); + new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph); + for (ConstantNode constant : graph.getNodes().filter(ConstantNode.class)) { + assertTrue("unexpected constant: " + constant, constant.asConstant().isNull() || constant.asConstant().asInt() > 0); + } + } + + public static int testInvokeSnippet(Number n) { + if (n instanceof Integer) { + return n.intValue(); + } else { + return 1; + } + } + + @Test + public void testInvoke() { + test("testInvokeSnippet", new Integer(16)); + StructuredGraph graph = parse("testInvokeSnippet"); + new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph); + new ConditionalEliminationPhase(runtime()).apply(graph); + + InvokeNode invoke = graph.getNodes(InvokeNode.class).first(); + assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind()); + } + } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -507,6 +507,7 @@ } private StructuredGraph parse0(Method m, GraphBuilderConfiguration conf) { + assert m.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + m; ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(m); StructuredGraph graph = new StructuredGraph(javaMethod); new GraphBuilderPhase(runtime, conf, OptimisticOptimizations.ALL).apply(graph); diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -24,8 +24,6 @@ import static org.junit.Assert.*; -import java.util.concurrent.*; - import org.junit.*; import com.oracle.graal.api.code.*; @@ -43,7 +41,7 @@ public static Object staticField; - public static class TestObject implements Callable { + public static class TestObject { public int x; public int y; @@ -52,11 +50,6 @@ this.x = x; this.y = y; } - - @Override - public Integer call() throws Exception { - return x; - } } public static class TestObject2 { @@ -70,6 +63,16 @@ } } + public static class TestObject3 extends TestObject { + + public int z; + + public TestObject3(int x, int y, int z) { + super(x, y); + this.z = z; + } + } + @SuppressWarnings("all") public static int testSimpleSnippet(TestObject a) { a.x = 2; @@ -213,6 +216,24 @@ assertEquals(1, graph.getNodes().filter(StoreFieldNode.class).count()); } + public static int testValueProxySnippet(boolean b, TestObject o) { + int sum = 0; + if (b) { + sum += o.x; + } else { + TestObject3 p = (TestObject3) o; + sum += p.x; + } + sum += o.x; + return sum; + } + + @Test + public void testValueProxy() { + processMethod("testValueProxySnippet"); + assertEquals(2, graph.getNodes().filter(LoadFieldNode.class).count()); + } + final ReturnNode getReturn(String snippet) { processMethod(snippet); assertEquals(1, graph.getNodes(ReturnNode.class).count()); diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Mon Jul 15 17:58:17 2013 -0700 @@ -70,6 +70,11 @@ private ValueNode lastInstructionPrinted; // Debugging only /** + * Records whether the code being generated makes at least one foreign call. + */ + private boolean hasForeignCall; + + /** * Checks whether the supplied constant can be used without loading it into a register for store * operations, i.e., on the right hand side of a memory access. * @@ -116,6 +121,13 @@ } /** + * Determines whether the code being generated makes at least one foreign call. + */ + public boolean hasForeignCall() { + return hasForeignCall; + } + + /** * Returns the operand that has been previously initialized by * {@link #setResult(ValueNode, Value)} with the result of an instruction. * @@ -601,6 +613,7 @@ emitMove(loc, arg); argLocations[i] = loc; } + this.hasForeignCall = true; emitForeignCall(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state); if (isLegal(linkageCc.getReturn())) { diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Mon Jul 15 17:58:17 2013 -0700 @@ -153,11 +153,13 @@ // - has no spill slots or other slots allocated during register allocation // - has no callee-saved registers // - has no incoming arguments passed on the stack - // - has no instructions with debug info + // - has no deoptimization points + // - makes no foreign calls (which require an aligned stack) AMD64HotSpotLIRGenerator gen = (AMD64HotSpotLIRGenerator) lirGen; FrameMap frameMap = gen.frameMap; LIR lir = gen.lir; - boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame(); + assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; + boolean omitFrame = CanOmitFrame.getValue() && !frameMap.frameNeedsAllocating() && !lir.hasArgInCallerFrame() && !gen.hasForeignCall(); Stub stub = gen.getStub(); AbstractAssembler masm = createAssembler(frameMap); @@ -236,7 +238,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 dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Jul 15 17:58:17 2013 -0700 @@ -413,9 +413,16 @@ AMD64AddressValue loadAddress = asAddressValue(address); Variable result = newVariable(kind); assert access == null || access instanceof HeapAccess; - if (runtime().config.useCompressedOops && isCompressCandidate(access)) { - append(new LoadCompressedPointer(kind, result, 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)); } @@ -429,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 dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompressedOopTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -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 dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Mon Jul 15 17:58:17 2013 -0700 @@ -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() { @@ -1158,7 +1168,11 @@ return Constant.forInt(base == null ? unsafe.getInt(displacement) : unsafe.getInt(base, displacement)); case Long: if (displacement == config().hubOffset && this.getGraalRuntime().getRuntime().config.useCompressedKlassPointers) { - return Constant.forLong(this.getGraalRuntime().getCompilerToVM().readUnsafeKlassPointer(base)); + 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)); } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FixedValueAnchorNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FixedValueAnchorNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/FixedValueAnchorNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -26,7 +26,7 @@ import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; -public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable { +public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable, ValueProxy { @Input private ValueNode object; @@ -53,4 +53,9 @@ generator.setResult(this, generator.operand(object)); } + @Override + public ValueNode getOriginalValue() { + return object; + } + } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java Mon Jul 15 17:58:17 2013 -0700 @@ -69,10 +69,12 @@ WriteBarrierType barrierType = node.getWriteBarrierType(); if (barrierType == WriteBarrierType.PRECISE) { if (useG1GC()) { - G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(node.object(), null, node.location(), true, node.getNullCheck())); - preBarrier.setDeoptimizationState(node.getDeoptimizationState()); - node.setNullCheck(false); - graph.addBeforeFixed(node, preBarrier); + if (node.isInitialized()) { + G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(node.object(), null, node.location(), true, node.getNullCheck())); + preBarrier.setDeoptimizationState(node.getDeoptimizationState()); + node.setNullCheck(false); + graph.addBeforeFixed(node, preBarrier); + } graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.value(), node.location(), true))); } else { graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.location(), true))); @@ -116,9 +118,11 @@ private static void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) { if (useG1GC()) { - G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + if (node.isInitialized()) { + G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); + graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier); + } G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); - graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier); graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier); } else { SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java Mon Jul 15 17:58:17 2013 -0700 @@ -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,7 +351,7 @@ } @Fold - public static int headerSize() { + public static int instanceHeaderSize() { return config().useCompressedKlassPointers ? (2 * wordSize()) - 4 : 2 * wordSize(); } @@ -473,6 +473,7 @@ } public static Word loadWordFromObject(Object object, int offset) { + assert offset != hubOffset() : "Use loadHubIntrinsic instead"; return loadWordFromObjectIntrinsic(object, 0, offset, getWordKind()); } @@ -488,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 dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Mon Jul 15 17:58:17 2013 -0700 @@ -203,12 +203,12 @@ if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { new_seqInit.inc(); explodeLoop(); - for (int offset = headerSize(); 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 = headerSize(); offset < size; offset += wordSize()) { + for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) { memory.writeWord(offset, Word.zero(), ANY_LOCATION); } } @@ -259,7 +259,7 @@ args.addConst("size", size); args.add("hub", hub); args.add("prototypeMarkWord", type.prototypeMarkWord()); - args.addConst("fillContents", useG1GC() || newInstanceNode.fillContents()); + args.addConst("fillContents", newInstanceNode.fillContents()); SnippetTemplate template = template(args); Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args); @@ -284,7 +284,7 @@ args.add("prototypeMarkWord", arrayType.prototypeMarkWord()); args.addConst("headerSize", headerSize); args.addConst("log2ElementSize", log2ElementSize); - args.addConst("fillContents", useG1GC() || newArrayNode.fillContents()); + args.addConst("fillContents", newArrayNode.fillContents()); SnippetTemplate template = template(args); Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args); @@ -295,7 +295,7 @@ Arguments args = new Arguments(allocateArrayDynamic); args.add("elementType", newArrayNode.getElementType()); args.add("length", newArrayNode.length()); - args.addConst("fillContents", useG1GC() || newArrayNode.fillContents()); + args.addConst("fillContents", newArrayNode.fillContents()); SnippetTemplate template = template(args); template.instantiate(runtime, newArrayNode, DEFAULT_REPLACER, args); diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java Mon Jul 15 17:58:17 2013 -0700 @@ -54,10 +54,10 @@ private static Object instanceClone(Object src, Word hub, int layoutHelper) { int instanceSize = layoutHelper; Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, useG1GC()); + Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false); Pointer memory = Word.fromObject(result); - for (int offset = headerSize(); offset < instanceSize; offset += wordSize()) { + for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) { memory.writeWord(offset, Word.fromObject(src).readWord(offset, ANY_LOCATION), ANY_LOCATION); } @@ -71,7 +71,7 @@ int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize); Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); - Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, useG1GC()); + Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false); Pointer memory = Word.fromObject(result); for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) { diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/UnsafeArrayCopyNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -82,6 +82,11 @@ return elementKind == Kind.Object; } + @Override + public boolean isInitialized() { + return true; + } + public Kind getElementKind() { return elementKind; } diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Mon Jul 15 17:58:17 2013 -0700 @@ -94,7 +94,7 @@ if (memory.notEqual(0)) { Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); initializeObjectHeader(memory, prototypeMarkWord, hub); - for (int offset = headerSize(); 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 dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/StubUtil.java Mon Jul 15 17:58:17 2013 -0700 @@ -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 dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java Mon Jul 15 17:58:17 2013 -0700 @@ -129,14 +129,18 @@ this.base = base; this.shift = shift; this.alignment = alignment; - assert kind == Kind.Object; + 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, base, shift, alignment); + if (kind == Kind.Object) { + decodePointer(masm, resRegister, base, shift, alignment); + } else { + decodeKlassPointer(masm, resRegister, base, shift, alignment); + } } } @@ -203,13 +207,17 @@ 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), base, shift, alignment); + 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); } @@ -286,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"); } @@ -691,4 +703,30 @@ } } + 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 dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java Mon Jul 15 17:58:17 2013 -0700 @@ -44,10 +44,11 @@ IMIN, LMIN, IUMIN, LUMIN, IREM, LREM, FREM, DREM, IUREM, LUREM, ICARRY, LCARRY, IUCARRY, LUCARRY, - IAND, INEG, IUSHR, I2B, I2S, I2L, + IAND, LAND, INEG, I2B, I2S, I2L, F2D, F2I, F2L, D2F, I2F, I2D, D2I, L2F, D2L, MOV_F2I, MOV_D2L, L2D, MOV_I2F, - MOV_L2D, ISHL, SQRT, UNDEF, CALL, L2I; + MOV_L2D, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, + SQRT, UNDEF, CALL, L2I; public static class Op1Stack extends HSAILLIRInstruction { @Opcode private final HSAILArithmetic opcode; @@ -245,6 +246,22 @@ } public static void emit(TargetMethodAssembler tasm, HSAILAssembler masm, HSAILArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) { + /** + * First check if one of src1 or src2 is an AddressValue. If it is, + * convert the address to a register using an lda instruction. We can + * just reuse the eventual dst register for this. + */ + if (src1 instanceof HSAILAddressValue) { + assert (!(src2 instanceof HSAILAddressValue)); + masm.emitLda(dst, ((HSAILAddressValue) src1).toAddress()); + emit(tasm, masm, opcode, dst, dst, src2, info); + return; + } else if (src2 instanceof HSAILAddressValue) { + assert (!(src1 instanceof HSAILAddressValue)); + masm.emitLda(dst, ((HSAILAddressValue) src2).toAddress()); + emit(tasm, masm, opcode, dst, src1, dst, info); + return; + } int exceptionOffset = -1; switch (opcode) { case IADD: @@ -276,7 +293,14 @@ case LMIN: masm.emit("min", dst, src1, src2); break; case ISHL: + case LSHL: masm.emit("shl", dst, src1, src2); break; + case ISHR: + case LSHR: + masm.emit("shr", dst, src1, src2); break; + case IUSHR: + case LUSHR: + masm.emitForceUnsigned("shr", dst, src1, src2); break; case IREM: masm.emit("rem", dst, src1, src2); break; default: throw GraalInternalError.shouldNotReachHere(); diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Mon Jul 15 17:58:17 2013 -0700 @@ -53,6 +53,34 @@ } } + + public static class ForeignCallNoArgOp extends HSAILLIRInstruction { + + @Def({REG}) protected Value out; + String callName; + + public ForeignCallNoArgOp(String callName, Value out) { + this.out = out; + this.callName = callName; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) { + masm.emitComment("//ForeignCall to " + callName + " would have gone here"); + } + } + + public static class ForeignCall1ArgOp extends ForeignCallNoArgOp { + + @Use({REG, ILLEGAL}) protected Value arg1; + + public ForeignCall1ArgOp(String callName, Value out, Value arg1) { + super(callName, out); + this.arg1 = arg1; + } + } + + public static class CompareBranchOp extends HSAILLIRInstruction implements StandardOp.BranchOp { @Opcode protected final HSAILCompare opcode; diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Mon Jul 15 17:58:17 2013 -0700 @@ -129,49 +129,147 @@ } } - public static class LoadOp extends HSAILLIRInstruction { - @SuppressWarnings("unused") private final Kind kind; - @Def({REG}) protected AllocatableValue result; + public abstract static class MemOp extends HSAILLIRInstruction { + + protected final Kind kind; @Use({COMPOSITE}) protected HSAILAddressValue address; @State protected LIRFrameState state; - public LoadOp(Kind kind, AllocatableValue result, HSAILAddressValue address, LIRFrameState state) { + public MemOp(Kind kind, HSAILAddressValue address, LIRFrameState state) { this.kind = kind; - this.result = result; this.address = address; this.state = state; } + protected abstract void emitMemAccess(HSAILAssembler masm); + @Override public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) { + if (state != null) { + // tasm.recordImplicitException(masm.codeBuffer.position(), state); + throw new InternalError("NYI"); + } + emitMemAccess(masm); + } + } + + public static class LoadOp extends MemOp { + + @Def({REG}) protected AllocatableValue result; + + public LoadOp(Kind kind, AllocatableValue result, HSAILAddressValue address, LIRFrameState state) { + super(kind, address, state); + this.result = result; + } + + @Override + public void emitMemAccess(HSAILAssembler masm) { HSAILAddress addr = address.toAddress(); masm.emitLoad(result, addr); } } - public static class StoreOp extends HSAILLIRInstruction { + public static class StoreOp extends MemOp { - @SuppressWarnings("unused") private final Kind kind; - @Use({COMPOSITE}) protected HSAILAddressValue address; @Use({REG}) protected AllocatableValue input; - @State protected LIRFrameState state; public StoreOp(Kind kind, HSAILAddressValue address, AllocatableValue input, LIRFrameState state) { - this.kind = kind; - this.address = address; + super(kind, address, state); this.input = input; - this.state = state; } @Override - public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) { + public void emitMemAccess(HSAILAssembler masm) { assert isRegister(input); HSAILAddress addr = address.toAddress(); masm.emitStore(input, addr); } } + public static class LoadCompressedPointer extends LoadOp { + + private long narrowOopBase; + private int narrowOopShift; + private int logMinObjAlignment; + @Temp({REG}) private AllocatableValue scratch; + + public LoadCompressedPointer(Kind kind, AllocatableValue result, AllocatableValue scratch, HSAILAddressValue address, LIRFrameState state, long narrowOopBase, int narrowOopShift, + int logMinObjAlignment) { + super(kind, result, address, state); + this.narrowOopBase = narrowOopBase; + this.narrowOopShift = narrowOopShift; + this.logMinObjAlignment = logMinObjAlignment; + this.scratch = scratch; + assert kind == Kind.Object; + } + + @Override + public void emitMemAccess(HSAILAssembler masm) { + // we will do a 32 bit load, zero extending into a 64 bit register + masm.emitLoad(result, address.toAddress(), "u32"); + decodePointer(masm, result, narrowOopBase, narrowOopShift, logMinObjAlignment); + } + } + + public static class StoreCompressedPointer extends HSAILLIRInstruction { + + protected final Kind kind; + private long narrowOopBase; + private int narrowOopShift; + private int logMinObjAlignment; + @Temp({REG}) private AllocatableValue scratch; + @Alive({REG}) protected AllocatableValue input; + @Alive({COMPOSITE}) protected HSAILAddressValue address; + @State protected LIRFrameState state; + + public StoreCompressedPointer(Kind kind, HSAILAddressValue address, AllocatableValue input, AllocatableValue scratch, LIRFrameState state, long narrowOopBase, int narrowOopShift, + int logMinObjAlignment) { + this.narrowOopBase = narrowOopBase; + this.narrowOopShift = narrowOopShift; + this.logMinObjAlignment = logMinObjAlignment; + this.scratch = scratch; + this.kind = kind; + this.address = address; + this.state = state; + this.input = input; + assert kind == Kind.Object; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, HSAILAssembler masm) { + masm.emitMov(scratch, input); + encodePointer(masm, scratch, narrowOopBase, narrowOopShift, logMinObjAlignment); + if (state != null) { + throw new InternalError("NYI"); + // tasm.recordImplicitException(masm.codeBuffer.position(), state); + } + masm.emitStore(scratch, address.toAddress(), "u32"); + } + } + + private static void encodePointer(HSAILAssembler masm, Value scratch, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { + if (narrowOopBase == 0 && narrowOopShift == 0) { + return; + } + if (narrowOopShift != 0) { + assert logMinObjAlignment == narrowOopShift : "Encode algorithm is wrong"; + } + masm.emitCompressedOopEncode(scratch, narrowOopBase, narrowOopShift); + } + + private static void decodePointer(HSAILAssembler masm, Value result, long narrowOopBase, int narrowOopShift, int logMinObjAlignment) { + if (narrowOopBase == 0 && narrowOopShift == 0) { + return; + } + if (narrowOopShift != 0) { + assert logMinObjAlignment == narrowOopShift : "Decode algorithm is wrong"; + } + masm.emitCompressedOopDecode(result, narrowOopBase, narrowOopShift); + } + + + public static class LeaOp extends HSAILLIRInstruction { @Def({REG}) protected AllocatableValue result; diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -34,7 +34,7 @@ * * A GuardedValueNode will only go away if its guard is null or {@link StructuredGraph#start()}. */ -public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable { +public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable, ValueProxy { @Input private ValueNode object; @@ -81,4 +81,9 @@ } return this; } + + @Override + public ValueNode getOriginalValue() { + return object; + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -34,7 +34,7 @@ * A node that changes the stamp of its input based on some condition being true. */ @NodeInfo(nameTemplate = "GuardingPi(!={p#negated}) {p#reason/s}") -public class GuardingPiNode extends FixedWithNextNode implements Lowerable, GuardingNode, Canonicalizable { +public class GuardingPiNode extends FixedWithNextNode implements Lowerable, GuardingNode, Canonicalizable, ValueProxy { @Input private ValueNode object; @Input private LogicNode condition; @@ -109,4 +109,9 @@ public ValueNode asNode() { return this; } + + @Override + public ValueNode getOriginalValue() { + return object; + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -36,7 +36,7 @@ * is as narrow or narrower than the PiNode's type. The PiNode, and therefore also the scheduling * restriction enforced by the anchor, will go away. */ -public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable { +public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, Node.IterableNodeType, GuardingNode, Canonicalizable, ValueProxy { @Input private ValueNode object; @@ -82,4 +82,9 @@ } return this; } + + @Override + public ValueNode getOriginalValue() { + return object; + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -27,7 +27,6 @@ import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; /** * A value proxy that is inserted in the frame state of a loop exit for any value that is created @@ -35,7 +34,7 @@ * loop. */ @NodeInfo(nameTemplate = "{p#type/s}Proxy") -public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable { +public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable, ValueProxy { @Input(notDataflow = true) private AbstractBeginNode proxyPoint; @Input private ValueNode value; @@ -60,11 +59,6 @@ return updateStamp(value.stamp()); } - @Override - public Stamp stamp() { - return value().stamp(); - } - public AbstractBeginNode proxyPoint() { return proxyPoint; } @@ -116,4 +110,8 @@ return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location)); } + @Override + public ValueNode getOriginalValue() { + return value; + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -27,12 +27,11 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.spi.*; -import com.oracle.graal.nodes.type.*; /** * A node that attaches a type profile to a proxied input node. */ -public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType { +public final class TypeProfileProxyNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType, ValueProxy { @Input private ValueNode object; private final JavaTypeProfile profile; @@ -67,12 +66,7 @@ @Override public boolean inferStamp() { - return object.inferStamp(); - } - - @Override - public Stamp stamp() { - return object.stamp(); + return updateStamp(object.stamp()); } @Override @@ -130,4 +124,9 @@ } assert graph.getNodes(TypeProfileProxyNode.class).count() == 0; } + + @Override + public ValueNode getOriginalValue() { + return object; + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -44,7 +44,7 @@ this.stamp = stamp; } - public Stamp stamp() { + public final Stamp stamp() { return stamp; } @@ -80,7 +80,7 @@ return false; } - public Kind kind() { + public final Kind kind() { return stamp().kind(); } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -54,4 +54,10 @@ * Return true if the written array is an object array, false if it is a primitive array. */ public abstract boolean isObjectArray(); + + /** + * If {@link #isInitialized()} is true, the memory location contains a valid value. If + * {@link #isInitialized()} is false, the memory location is uninitialized or zero. + */ + public abstract boolean isInitialized(); } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -37,6 +37,7 @@ @Input private ValueNode value; @Input(notDataflow = true) private FrameState stateAfter; + private final boolean initialized; public FrameState stateAfter() { return stateAfter; @@ -56,9 +57,22 @@ return value; } + /** + * If {@link #isInitialized()} is true, the memory location contains a valid value. If + * {@link #isInitialized()} is false, the memory location is uninitialized or zero. + */ + public boolean isInitialized() { + return initialized; + } + public WriteNode(ValueNode object, ValueNode value, ValueNode location, WriteBarrierType barrierType, boolean compress) { + this(object, value, location, barrierType, compress, true); + } + + public WriteNode(ValueNode object, ValueNode value, ValueNode location, WriteBarrierType barrierType, boolean compress, boolean initialized) { super(object, location, StampFactory.forVoid(), barrierType, compress); this.value = value; + this.initialized = initialized; } @Override diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java Mon Jul 15 17:58:17 2013 -0700 @@ -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.*; @@ -35,7 +37,7 @@ /** * Implements a type check against a compile-time known type. */ -public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Node.IterableNodeType, Virtualizable { +public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Lowerable, Node.IterableNodeType, Virtualizable, ValueProxy { @Input private ValueNode object; private final ResolvedJavaType type; @@ -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 @@ -176,4 +193,9 @@ } } } + + @Override + public ValueNode getOriginalValue() { + return object; + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ValueProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ValueProxy.java Mon Jul 15 17:58:17 2013 -0700 @@ -0,0 +1,31 @@ +/* + * 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.spi; + +import com.oracle.graal.nodes.*; + +public interface ValueProxy { + + ValueNode getOriginalValue(); + +} diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Mon Jul 15 17:58:17 2013 -0700 @@ -30,6 +30,7 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.spi.*; public class GraphUtil { @@ -257,14 +258,6 @@ return null; } - public static ValueNode unProxify(ValueNode proxy) { - ValueNode v = proxy; - while (v instanceof ProxyNode) { - v = ((ProxyNode) v).value(); - } - return v; - } - /** * Returns a string representation of the given collection of objects. * @@ -285,16 +278,31 @@ } /** + * Gets the original value by iterating through all {@link ValueProxy ValueProxies}. + * + * @param value The start value. + * @return The first non-proxy value encountered. + */ + public static ValueNode unproxify(ValueNode value) { + ValueNode result = value; + while (result instanceof ValueProxy) { + result = ((ValueProxy) result).getOriginalValue(); + } + return result; + } + + /** * Tries to find an original value of the given node by traversing through proxies and - * unambiguous phis. + * unambiguous phis. Note that this method will perform an exhaustive search through phis. It is + * intended to be used during graph building, when phi nodes aren't yet canonicalized. * * @param proxy The node whose original value should be determined. */ public static ValueNode originalValue(ValueNode proxy) { ValueNode v = proxy; do { - if (v instanceof ProxyNode) { - v = ((ProxyNode) v).value(); + if (v instanceof ValueProxy) { + v = ((ValueProxy) v).getOriginalValue(); } else if (v instanceof PhiNode) { v = ((PhiNode) v).singleValue(); } else { @@ -308,8 +316,8 @@ NodeWorkList worklist = proxy.graph().createNodeWorkList(); worklist.add(proxy); for (Node node : worklist) { - if (node instanceof ProxyNode) { - worklist.add(((ProxyNode) node).value()); + if (node instanceof ValueProxy) { + worklist.add(((ValueProxy) node).getOriginalValue()); } else if (node instanceof PhiNode) { worklist.addAll(((PhiNode) node).values()); } else { diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Mon Jul 15 17:58:17 2013 -0700 @@ -22,6 +22,7 @@ */ package com.oracle.graal.phases.common; +import java.lang.reflect.*; import java.util.*; import com.oracle.graal.api.meta.*; @@ -33,6 +34,7 @@ import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.java.MethodCallTargetNode.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.*; @@ -193,16 +195,16 @@ } public ResolvedJavaType getNodeType(ValueNode node) { - ResolvedJavaType result = knownTypes.get(node); + ResolvedJavaType result = knownTypes.get(GraphUtil.unproxify(node)); return result == null ? node.objectStamp().type() : result; } public boolean isNull(ValueNode value) { - return value.objectStamp().alwaysNull() || knownNull.contains(value); + return value.objectStamp().alwaysNull() || knownNull.contains(GraphUtil.unproxify(value)); } public boolean isNonNull(ValueNode value) { - return value.objectStamp().nonNull() || knownNonNull.contains(value); + return value.objectStamp().nonNull() || knownNonNull.contains(GraphUtil.unproxify(value)); } @Override @@ -245,25 +247,27 @@ * to be null, otherwise the value is known to be non-null. */ public void addNullness(boolean isNull, ValueNode value) { + ValueNode original = GraphUtil.unproxify(value); if (isNull) { - if (!isNull(value)) { + if (!isNull(original)) { metricNullnessRegistered.increment(); - knownNull.add(value); + knownNull.add(original); } } else { - if (!isNonNull(value)) { + if (!isNonNull(original)) { metricNullnessRegistered.increment(); - knownNonNull.add(value); + knownNonNull.add(original); } } } public void addType(ResolvedJavaType type, ValueNode value) { - ResolvedJavaType knownType = getNodeType(value); + ValueNode original = GraphUtil.unproxify(value); + ResolvedJavaType knownType = getNodeType(original); ResolvedJavaType newType = tighten(type, knownType); if (newType != knownType) { - knownTypes.put(value, newType); + knownTypes.put(original, newType); metricTypeRegistered.increment(); } } @@ -315,42 +319,48 @@ } private void registerCondition(boolean isTrue, LogicNode condition, ValueNode anchor) { - state.addCondition(isTrue, condition, anchor); + if (!isTrue && condition instanceof LogicDisjunctionNode) { + LogicDisjunctionNode disjunction = (LogicDisjunctionNode) condition; + registerCondition(disjunction.isXNegated(), disjunction.getX(), anchor); + registerCondition(disjunction.isYNegated(), disjunction.getY(), anchor); + } else { + state.addCondition(isTrue, condition, anchor); - if (isTrue && condition instanceof InstanceOfNode) { - InstanceOfNode instanceOf = (InstanceOfNode) condition; - ValueNode object = instanceOf.object(); - state.addNullness(false, object); - state.addType(instanceOf.type(), object); - } else if (condition instanceof IsNullNode) { - IsNullNode nullCheck = (IsNullNode) condition; - state.addNullness(isTrue, nullCheck.object()); - } else if (condition instanceof ObjectEqualsNode) { - ObjectEqualsNode equals = (ObjectEqualsNode) condition; - ValueNode x = equals.x(); - ValueNode y = equals.y(); - if (isTrue) { - if (state.isNull(x) && !state.isNull(y)) { - metricObjectEqualsRegistered.increment(); - state.addNullness(true, y); - } else if (!state.isNull(x) && state.isNull(y)) { - metricObjectEqualsRegistered.increment(); - state.addNullness(true, x); - } - if (state.isNonNull(x) && !state.isNonNull(y)) { - metricObjectEqualsRegistered.increment(); - state.addNullness(false, y); - } else if (!state.isNonNull(x) && state.isNonNull(y)) { - metricObjectEqualsRegistered.increment(); - state.addNullness(false, x); - } - } else { - if (state.isNull(x) && !state.isNonNull(y)) { - metricObjectEqualsRegistered.increment(); - state.addNullness(true, y); - } else if (!state.isNonNull(x) && state.isNull(y)) { - metricObjectEqualsRegistered.increment(); - state.addNullness(true, x); + if (isTrue && condition instanceof InstanceOfNode) { + InstanceOfNode instanceOf = (InstanceOfNode) condition; + ValueNode object = instanceOf.object(); + state.addNullness(false, object); + state.addType(instanceOf.type(), object); + } else if (condition instanceof IsNullNode) { + IsNullNode nullCheck = (IsNullNode) condition; + state.addNullness(isTrue, nullCheck.object()); + } else if (condition instanceof ObjectEqualsNode) { + ObjectEqualsNode equals = (ObjectEqualsNode) condition; + ValueNode x = equals.x(); + ValueNode y = equals.y(); + if (isTrue) { + if (state.isNull(x) && !state.isNull(y)) { + metricObjectEqualsRegistered.increment(); + state.addNullness(true, y); + } else if (!state.isNull(x) && state.isNull(y)) { + metricObjectEqualsRegistered.increment(); + state.addNullness(true, x); + } + if (state.isNonNull(x) && !state.isNonNull(y)) { + metricObjectEqualsRegistered.increment(); + state.addNullness(false, y); + } else if (!state.isNonNull(x) && state.isNonNull(y)) { + metricObjectEqualsRegistered.increment(); + state.addNullness(false, x); + } + } else { + if (state.isNull(x) && !state.isNonNull(y)) { + metricObjectEqualsRegistered.increment(); + state.addNullness(false, y); + } else if (!state.isNonNull(x) && state.isNull(y)) { + metricObjectEqualsRegistered.increment(); + state.addNullness(false, x); + } } } } @@ -569,6 +579,25 @@ } } } + } else if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + if (invoke.callTarget() instanceof MethodCallTargetNode) { + MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); + ValueNode receiver = callTarget.receiver(); + if (receiver != null && (callTarget.invokeKind() == InvokeKind.Interface || callTarget.invokeKind() == InvokeKind.Virtual)) { + ResolvedJavaType type = state.getNodeType(receiver); + if (type != receiver.objectStamp().type()) { + ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod()); + if (method != null) { + if ((method.getModifiers() & Modifier.FINAL) != 0 || (type.getModifiers() & Modifier.FINAL) != 0) { + callTarget.setInvokeKind(InvokeKind.Special); + callTarget.setTargetMethod(method); + } + } + } + } + } + } } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Mon Jul 15 17:58:17 2013 -0700 @@ -448,6 +448,10 @@ @Override public boolean isWorthInlining(InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed) { + if (InlineEverything.getValue()) { + return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); + } + if (isIntrinsic(info)) { return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Mon Jul 15 17:58:17 2013 -0700 @@ -63,6 +63,8 @@ public static final OptionValue SmallCompiledLowLevelGraphSize = new OptionValue<>(300); @Option(help = "") public static final OptionValue LimitInlinedInvokes = new OptionValue<>(5.0); + @Option(help = "") + public static final OptionValue InlineEverything = new OptionValue<>(false); // escape analysis settings @Option(help = "") diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java Mon Jul 15 17:58:17 2013 -0700 @@ -65,8 +65,7 @@ if (truffleCompiler == null) { truffleCompiler = new TruffleCompilerImpl(); } - return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleCompilationThreshold.getValue(), TruffleInliningReprofileCount.getValue(), - TruffleInvalidationReprofileCount.getValue()); + return new OptimizedCallTarget(rootNode, frameDescriptor, truffleCompiler, TruffleCompilationThreshold.getValue()); } @Override diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java Mon Jul 15 17:58:17 2013 -0700 @@ -40,19 +40,19 @@ public final class OptimizedCallTarget extends DefaultCallTarget implements LoopCountReceiver, FrameFactory { private static final PrintStream OUT = TTY.out().out(); + private static final int MIN_INVOKES_AFTER_INLINING = 2; - private final int inliningReprofileCount; - private final int invalidationReprofileCount; - - protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold, int inliningReprofileCount, int invalidationReprofileCount) { + protected OptimizedCallTarget(RootNode rootNode, FrameDescriptor descriptor, TruffleCompiler compiler, int compilationThreshold) { super(rootNode, descriptor); this.compiler = compiler; this.invokeCounter = compilationThreshold >> 7; this.loopAndInvokeCounter = compilationThreshold; this.originalInvokeCounter = compilationThreshold; this.rootNode.setCallTarget(this); - this.inliningReprofileCount = inliningReprofileCount; - this.invalidationReprofileCount = invalidationReprofileCount; + + if (TruffleProfiling.getValue()) { + registerCallTarget(this); + } } private InstalledCode compiledMethod; @@ -62,6 +62,11 @@ private int loopAndInvokeCounter; private boolean disableCompilation; + // TruffleProfiling + private int callCount; + private int inlinedCallSiteCount; + + // TraceTruffleCompilation long timeCompilationStarted; long timePartialEvaluationFinished; long timeCompilationFinished; @@ -71,6 +76,9 @@ @Override public Object call(PackedFrame caller, Arguments args) { + if (TruffleProfiling.getValue()) { + callCount++; + } if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, compiledMethod != null)) { try { return compiledMethod.execute(this, caller, args); @@ -82,8 +90,9 @@ } } - protected Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { + private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) { compiledMethod = null; + int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue(); invokeCounter = invalidationReprofileCount; if (TruffleFunctionInlining.getValue()) { originalInvokeCounter += invalidationReprofileCount; @@ -101,7 +110,8 @@ return executeHelper(caller, args); } else { if (TruffleFunctionInlining.getValue() && inline()) { - invokeCounter = 2; + invokeCounter = MIN_INVOKES_AFTER_INLINING; + int inliningReprofileCount = TruffleInliningReprofileCount.getValue(); loopAndInvokeCounter = inliningReprofileCount; originalInvokeCounter = inliningReprofileCount; } else { @@ -112,10 +122,12 @@ } public boolean inline() { + CompilerAsserts.neverPartOfCompilation(); return new InliningHelper(this).inline(); } public void compile() { + CompilerAsserts.neverPartOfCompilation(); try { compiledMethod = compiler.compile(this); if (compiledMethod == null) { @@ -127,6 +139,9 @@ (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6, (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, codeSize); } + if (TruffleProfiling.getValue()) { + resetProfiling(); + } } } catch (Throwable e) { disableCompilation = true; @@ -202,10 +217,14 @@ boolean inlined = false; for (InlinableCallSiteInfo inlinableCallSite : inlinableCallSites) { - if (policy.isWorthInlining(inlinableCallSite) && inlinableCallSite.getCallSite().inline(target)) { + if (!policy.isWorthInlining(inlinableCallSite)) { + break; + } + if (inlinableCallSite.getCallSite().inline(target)) { if (TraceTruffleInlining.getValue()) { printCallSiteInfo(policy, inlinableCallSite, "inlined"); } + target.inlinedCallSiteCount++; inlined = true; break; } @@ -267,7 +286,11 @@ @Override public int compare(InlinableCallSiteInfo cs1, InlinableCallSiteInfo cs2) { - return Double.compare(metric(cs2), metric(cs1)); + int result = (isWorthInlining(cs2) ? 1 : 0) - (isWorthInlining(cs1) ? 1 : 0); + if (result == 0) { + return Double.compare(metric(cs2), metric(cs1)); + } + return result; } }); } @@ -313,4 +336,65 @@ return inlinableCallSites; } } + + private static void resetProfiling() { + for (OptimizedCallTarget callTarget : OptimizedCallTarget.callTargets.keySet()) { + callTarget.callCount = 0; + } + } + + private static void printProfiling() { + List sortedCallTargets = new ArrayList<>(OptimizedCallTarget.callTargets.keySet()); + Collections.sort(sortedCallTargets, new Comparator() { + + @Override + public int compare(OptimizedCallTarget o1, OptimizedCallTarget o2) { + return o2.callCount - o1.callCount; + } + }); + + int totalCallCount = 0; + int totalInlinedCallSiteCount = 0; + int totalNotInlinedCallSiteCount = 0; + int totalNodeCount = 0; + + PrintStream out = TTY.out().out(); + out.println(); + out.printf("%-50s | %-10s | %s / %s | %s\n", "Call Target", "Call Count", "Calls Sites Inlined", "Not Inlined", "Node Count"); + for (OptimizedCallTarget callTarget : sortedCallTargets) { + if (callTarget.callCount == 0) { + continue; + } + + int notInlinedCallSiteCount = InliningHelper.getInlinableCallSites(callTarget).size(); + int nodeCount = NodeUtil.countNodes(callTarget.rootNode); + String comment = callTarget.compiledMethod == null ? " int" : ""; + out.printf("%-50s | %10s | %15s | %15s | %10s%s\n", callTarget.getRootNode(), callTarget.callCount, callTarget.inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, comment); + + totalCallCount += callTarget.callCount; + totalInlinedCallSiteCount += callTarget.inlinedCallSiteCount; + totalNotInlinedCallSiteCount += notInlinedCallSiteCount; + totalNodeCount += nodeCount; + } + out.printf("%-50s | %10s | %15s | %15s | %10s\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount); + } + + private static void registerCallTarget(OptimizedCallTarget callTarget) { + callTargets.put(callTarget, 0); + } + + private static Map callTargets; + static { + if (TruffleProfiling.getValue()) { + callTargets = new WeakHashMap<>(); + + Runtime.getRuntime().addShutdownHook(new Thread() { + + @Override + public void run() { + printProfiling(); + } + }); + } + } } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Mon Jul 15 17:58:17 2013 -0700 @@ -64,7 +64,7 @@ private final HotSpotGraalRuntime graalRuntime; private final TruffleCache truffleCache; - private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class}; + private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class, InvalidInstalledCodeException.class}; public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability, OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints); diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java Mon Jul 15 17:58:17 2013 -0700 @@ -81,5 +81,7 @@ public static final OptionValue TraceTruffleInlining = new OptionValue<>(true); @Option(help = "") public static final OptionValue TraceTruffleInliningDetails = new OptionValue<>(false); + @Option(help = "") + public static final OptionValue TruffleProfiling = new StableOptionValue<>(false); // @formatter:on } diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationPEClosure.java Mon Jul 15 17:58:17 2013 -0700 @@ -34,6 +34,7 @@ import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.virtual.phases.ea.ReadEliminationPEBlockState.ReadCacheEntry; @@ -54,24 +55,26 @@ if (!deleted) { if (node instanceof LoadFieldNode) { LoadFieldNode load = (LoadFieldNode) node; - ValueNode cachedValue = state.getReadCache(load.object(), load.field()); + ValueNode object = GraphUtil.unproxify(load.object()); + ValueNode cachedValue = state.getReadCache(object, load.field()); if (cachedValue != null) { effects.replaceAtUsages(load, cachedValue); state.addScalarAlias(load, cachedValue); + deleted = true; } else { - state.addReadCache(load.object(), load.field(), load); + state.addReadCache(object, load.field(), load); } - deleted = true; } else if (node instanceof StoreFieldNode) { StoreFieldNode store = (StoreFieldNode) node; - ValueNode cachedValue = state.getReadCache(store.object(), store.field()); + ValueNode object = GraphUtil.unproxify(store.object()); + ValueNode cachedValue = state.getReadCache(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()); + state.addReadCache(object, store.field(), store.value()); } else if (node instanceof MemoryCheckpoint.Single) { METRIC_MEMORYCHECKOINT.increment(); LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Pointer.java Mon Jul 15 17:58:17 2013 -0700 @@ -365,6 +365,20 @@ void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity); /** + * Initializes the memory at address {@code (this + offset)}. Both the base address and offset + * are in bytes. The memory must be uninitialized or zero prior to this operation. + *

+ * The offset is always treated as a {@link Signed} value. However, the static type is + * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller + * knows that the highest-order bit of the unsigned value is never used). + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void initializeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity); + + /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. *

@@ -459,6 +473,16 @@ void writeWord(int offset, WordBase val, LocationIdentity locationIdentity); /** + * Initializes the memory at address {@code (this + offset)}. Both the base address and offset + * are in bytes. The memory must be uninitialized or zero prior to this operation. + * + * @param offset the signed offset for the memory access + * @param locationIdentity the identity of the write (see {@link LocationNode}) + * @param val the value to be written to memory + */ + void initializeWord(int offset, WordBase val, LocationIdentity locationIdentity); + + /** * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in * bytes. * diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java Mon Jul 15 17:58:17 2013 -0700 @@ -61,6 +61,7 @@ READ, READ_COMPRESSED, WRITE, + INITIALIZE, ZERO, FROM_UNSIGNED, FROM_SIGNED, @@ -758,6 +759,12 @@ } @Override + @Operation(opcode = Opcode.INITIALIZE) + public void initializeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity) { + unsafe.putAddress(add((Word) offset).unbox(), ((Word) val).unbox()); + } + + @Override @Operation(opcode = Opcode.WRITE) public native void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity); @@ -810,6 +817,12 @@ } @Override + @Operation(opcode = Opcode.INITIALIZE) + public void initializeWord(int offset, WordBase val, LocationIdentity locationIdentity) { + initializeWord(signed(offset), val, locationIdentity); + } + + @Override @Operation(opcode = Opcode.WRITE) public void writeObject(int offset, Object val, LocationIdentity locationIdentity) { writeObject(signed(offset), val, locationIdentity); diff -r dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java Mon Jul 15 17:58:17 2013 -0700 @@ -38,6 +38,7 @@ import com.oracle.graal.phases.*; import com.oracle.graal.phases.util.*; import com.oracle.graal.word.*; +import com.oracle.graal.word.Word.Opcode; import com.oracle.graal.word.Word.Operation; /** @@ -69,15 +70,20 @@ @Override protected void run(StructuredGraph graph) { for (Node n : GraphOrder.forwardGraph(graph)) { - if (n instanceof ValueNode) { + if (n instanceof ValueNode && !(n instanceof PhiNode && ((PhiNode) n).isLoopPhi())) { ValueNode valueNode = (ValueNode) n; if (isWord(valueNode)) { changeToWord(valueNode); } } } + for (PhiNode phi : graph.getNodes(PhiNode.class)) { + if (phi.isLoopPhi() && isWord(phi)) { + changeToWord(phi); + } + } - // Remove casts between different word types (which are by now no longer have kind Object) + // Remove casts between different word types (which by now no longer have kind Object) for (CheckCastNode checkCastNode : graph.getNodes().filter(CheckCastNode.class).snapshot()) { if (!checkCastNode.isDeleted() && checkCastNode.kind() == wordKind) { checkCastNode.replaceAtUsages(checkCastNode.object()); @@ -184,7 +190,8 @@ replace(invoke, readOp(graph, arguments.get(0), invoke, location, true)); break; } - case WRITE: { + case WRITE: + case INITIALIZE: { assert arguments.size() == 3 || arguments.size() == 4; Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass())); LocationNode location; @@ -193,7 +200,7 @@ } else { location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3)); } - replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location)); + replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location, operation.opcode())); break; } case ZERO: @@ -330,8 +337,9 @@ return read; } - private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location) { - WriteNode write = graph.add(new WriteNode(base, value, location, WriteBarrierType.NONE, false)); + private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) { + assert op == Opcode.WRITE || op == Opcode.INITIALIZE; + WriteNode write = graph.add(new WriteNode(base, value, location, WriteBarrierType.NONE, false, op == Opcode.WRITE)); write.setStateAfter(invoke.stateAfter()); graph.addBeforeFixed(invoke.asNode(), write); return write; diff -r dfc4b73e79e8 -r fbeda94727f8 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 17:58:17 2013 -0700 @@ -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 dfc4b73e79e8 -r fbeda94727f8 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Mon Jul 15 17:58:17 2013 -0700 @@ -81,7 +81,7 @@ class TestRootNode extends RootNode { - @Children private ValueNode[] children; + @Children private final ValueNode[] children; public TestRootNode(ValueNode[] children) { this.children = adoptChildren(children); diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Mon Jul 15 17:58:17 2013 -0700 @@ -163,9 +163,11 @@ } else if (Node.class.isAssignableFrom(field.getType()) && field.getAnnotation(Child.class) != null) { kind = NodeFieldKind.CHILD; childOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); + assert !Modifier.isFinal(field.getModifiers()) : "child field must not be final (\"" + field.getName() + "\", " + clazz + ")"; } else if (field.getType().isArray() && Node.class.isAssignableFrom(field.getType().getComponentType()) && field.getAnnotation(Children.class) != null) { kind = NodeFieldKind.CHILDREN; childrenOffsetsList.add(fieldOffsetProvider.objectFieldOffset(field)); + assert Modifier.isFinal(field.getModifiers()) : "children array field must be final (\"" + field.getName() + "\", " + clazz + ")"; } else { kind = NodeFieldKind.DATA; } @@ -352,24 +354,54 @@ public static void replaceChild(Node parent, Node oldChild, Node newChild) { NodeClass nodeClass = NodeClass.get(parent.getClass()); - for (long fieldOffset : nodeClass.childOffsets) { + for (long fieldOffset : nodeClass.getChildOffsets()) { if (unsafe.getObject(parent, fieldOffset) == oldChild) { + assert assertAssignable(nodeClass, fieldOffset, newChild); unsafe.putObject(parent, fieldOffset, newChild); } } - for (long fieldOffset : nodeClass.childrenOffsets) { - Node[] array = (Node[]) unsafe.getObject(parent, fieldOffset); - if (array != null) { + + for (long fieldOffset : nodeClass.getChildrenOffsets()) { + Object arrayObject = unsafe.getObject(parent, fieldOffset); + if (arrayObject != null) { + assert arrayObject instanceof Node[] : "Children array must be instanceof Node[] "; + Node[] array = (Node[]) arrayObject; for (int i = 0; i < array.length; i++) { if (array[i] == oldChild) { + assert assertAssignable(nodeClass, fieldOffset, newChild); array[i] = newChild; - return; } } } } } + private static boolean assertAssignable(NodeClass clazz, long fieldOffset, Object newValue) { + if (newValue == null) { + return true; + } + for (NodeField field : clazz.getFields()) { + if (field.getOffset() == fieldOffset) { + if (field.getKind() == NodeFieldKind.CHILD) { + if (field.getType().isAssignableFrom(newValue.getClass())) { + return true; + } else { + assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); + return false; + } + } else if (field.getKind() == NodeFieldKind.CHILDREN) { + if (field.getType().getComponentType().isAssignableFrom(newValue.getClass())) { + return true; + } else { + assert false : "Child class " + newValue.getClass().getName() + " is not assignable to field \"" + field.getName() + "\" of type " + field.getType().getName(); + return false; + } + } + } + } + throw new IllegalArgumentException(); + } + /** Returns all declared fields in the class hierarchy. */ private static Field[] getAllFields(Class clazz) { Field[] declaredFields = clazz.getDeclaredFields(); @@ -660,4 +692,5 @@ p.print(" "); } } + } diff -r dfc4b73e79e8 -r fbeda94727f8 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 Fri Jul 12 10:12:06 2013 -0700 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Jul 15 17:58:17 2013 -0700 @@ -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 dfc4b73e79e8 -r fbeda94727f8 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Fri Jul 12 10:12:06 2013 -0700 +++ b/src/share/vm/runtime/arguments.cpp Mon Jul 15 17:58:17 2013 -0700 @@ -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()