# HG changeset patch # User Christian Humer # Date 1383060239 -3600 # Node ID 748b8381b1713031611bad4f6c118023a82c4c2c # Parent ba6593e52d2299073e5712c5f9bfe4a42b6ecf7b# Parent 7f55cdeec6af6998adccd9933b72f79c2cd2f38f Merge. diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java Tue Oct 29 16:23:59 2013 +0100 @@ -138,12 +138,18 @@ if (values != null) { if (!type.isArray()) { ResolvedJavaField[] fields = type.getInstanceFields(true); - assert fields.length == values.length : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); + int fieldIndex = 0; for (int i = 0; i < values.length; i++) { - ResolvedJavaField field = fields[i]; + ResolvedJavaField field = fields[fieldIndex++]; Kind valKind = values[i].getKind().getStackKind(); - assert valKind == field.getKind().getStackKind() : field + ": " + valKind + " != " + field.getKind().getStackKind(); + if ((valKind == Kind.Double || valKind == Kind.Long) && field.getKind() == Kind.Int) { + assert fields[fieldIndex].getKind() == Kind.Int; + fieldIndex++; + } else { + assert valKind == field.getKind().getStackKind() : field + ": " + valKind + " != " + field.getKind().getStackKind(); + } } + assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); } else { Kind componentKind = type.getComponentType().getKind().getStackKind(); for (int i = 0; i < values.length; i++) { diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java Tue Oct 29 16:23:59 2013 +0100 @@ -112,11 +112,15 @@ @Override public String toString() { - String annotationSuffix = ""; - if (getKind() != Kind.Object && getPrimitiveAnnotation() != null) { - annotationSuffix = "{" + getPrimitiveAnnotation() + "}"; + if (getKind() == Kind.Illegal) { + return "illegal"; + } else { + String annotationSuffix = ""; + if (getKind() != Kind.Object && getPrimitiveAnnotation() != null) { + annotationSuffix = "{" + getPrimitiveAnnotation() + "}"; + } + return getKind().getJavaName() + "[" + getKind().format(asBoxedValue()) + (getKind() != Kind.Object ? "|0x" + Long.toHexString(primitive) : "") + "]" + annotationSuffix; } - return getKind().getJavaName() + "[" + getKind().format(asBoxedValue()) + (getKind() != Kind.Object ? "|0x" + Long.toHexString(primitive) : "") + "]" + annotationSuffix; } /** @@ -144,6 +148,8 @@ return asDouble(); case Object: return object; + case Illegal: + return this; } throw new IllegalArgumentException(); } @@ -427,6 +433,10 @@ } } + public static Constant forIllegal() { + return new Constant(Kind.Illegal, null, 0); + } + /** * Returns a constant with the default value for the given kind. */ diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThreadFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/CompilerThreadFactory.java Tue Oct 29 16:23:59 2013 +0100 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler; + +import java.util.concurrent.*; + +import com.oracle.graal.debug.*; + +/** + * Facility for creating {@linkplain CompilerThread compiler threads}. + */ +public class CompilerThreadFactory implements ThreadFactory { + + /** + * Capability to get a thread-local debug configuration for the current thread. + */ + public interface DebugConfigAccess { + /** + * Get a thread-local debug configuration for the current thread. This will be null if + * debugging is {@linkplain Debug#isEnabled() disabled}. + */ + GraalDebugConfig getDebugConfig(); + } + + protected final String threadNamePrefix; + protected final DebugConfigAccess debugConfigAccess; + + public CompilerThreadFactory(String threadNamePrefix, DebugConfigAccess debugConfigAccess) { + this.threadNamePrefix = threadNamePrefix; + this.debugConfigAccess = debugConfigAccess; + } + + public Thread newThread(Runnable r) { + return new CompilerThread(r, threadNamePrefix, debugConfigAccess); + } + + /** + * A compiler thread is a daemon thread that runs at {@link Thread#MAX_PRIORITY} and executes in + * the context of a thread-local {@linkplain GraalDebugConfig debug configuration}. + */ + public static class CompilerThread extends Thread { + + private final DebugConfigAccess debugConfigAccess; + + public CompilerThread(Runnable r, String namePrefix, DebugConfigAccess debugConfigAccess) { + super(r); + this.setName(namePrefix + "-" + this.getId()); + this.setPriority(Thread.MAX_PRIORITY); + this.setDaemon(true); + this.debugConfigAccess = debugConfigAccess; + } + + @Override + public void run() { + GraalDebugConfig debugConfig = debugConfigAccess.getDebugConfig(); + try { + super.run(); + } finally { + if (debugConfig != null) { + for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) { + try { + dumpHandler.close(); + } catch (Throwable t) { + } + } + } + } + } + } +} diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java Tue Oct 29 16:23:59 2013 +0100 @@ -87,8 +87,17 @@ changed = true; VirtualObjectState currentField = (VirtualObjectState) objectStates.get(vobj); assert currentField != null; + int pos = 0; for (int i = 0; i < vobj.entryCount(); i++) { - values[i] = toValue(currentField.fieldValues().get(i)); + if (!currentField.fieldValues().get(i).isConstant() || currentField.fieldValues().get(i).asConstant().getKind() != Kind.Illegal) { + values[pos++] = toValue(currentField.fieldValues().get(i)); + } else { + assert currentField.fieldValues().get(i - 1).kind() == Kind.Double || currentField.fieldValues().get(i - 1).kind() == Kind.Long : vobj + " " + i + " " + + currentField.fieldValues().get(i - 1); + } + } + if (pos != vobj.entryCount()) { + values = Arrays.copyOf(values, pos); } } entry.getValue().setValues(values); diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Tue Oct 29 16:23:59 2013 +0100 @@ -34,6 +34,7 @@ import com.oracle.graal.api.code.CallingConvention.Type; import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.CompilerThreadFactory.CompilerThread; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; import com.oracle.graal.hotspot.meta.*; diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerThread.java Mon Oct 28 11:06:51 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.hotspot; - -import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; - -import java.io.*; -import java.util.concurrent.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.printer.*; - -public final class CompilerThread extends Thread { - - public static final ThreadFactory FACTORY = new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - return new CompilerThread(r); - } - }; - - private CompilerThread(Runnable r) { - super(r); - this.setName("GraalCompilerThread-" + this.getId()); - this.setPriority(MAX_PRIORITY); - this.setDaemon(true); - } - - @Override - public void run() { - GraalDebugConfig debugConfig = null; - if (Debug.isEnabled()) { - PrintStream log = runtime().getVMToCompiler().log(); - debugConfig = DebugEnvironment.initialize(log); - } - try { - super.run(); - } finally { - if (debugConfig != null) { - for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) { - try { - dumpHandler.close(); - } catch (Throwable t) { - - } - } - } - } - } -} diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java Tue Oct 29 16:23:59 2013 +0100 @@ -127,6 +127,12 @@ /** * Updates a given stub with respect to the registers it destroys. + *

+ * Any entry in {@code calleeSaveInfo} that {@linkplain SaveRegistersOp#supportsRemove() + * supports} pruning will have {@code destroyedRegisters} + * {@linkplain SaveRegistersOp#remove(Set) removed} as these registers are declared as + * temporaries in the stub's {@linkplain ForeignCallLinkage linkage} (and thus will be saved by + * the stub's caller). * * @param stub the stub to update * @param destroyedRegisters the registers destroyed by the stub @@ -141,10 +147,6 @@ for (Map.Entry e : calleeSaveInfo.entrySet()) { SaveRegistersOp save = e.getValue(); if (save.supportsRemove()) { - // Since the registers destroyed by the stub are declared as temporaries in the - // linkage (see ForeignCallLinkage.getTemporaries()) for the stub, the caller - // will already save these registers and so there's no need for the stub to - // save them again. save.remove(destroyedRegisters); } DebugInfo info = e.getKey() == null ? null : e.getKey().debugInfo(); diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Tue Oct 29 16:23:59 2013 +0100 @@ -39,6 +39,8 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.CompilerThreadFactory.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; import com.oracle.graal.graph.*; @@ -192,7 +194,12 @@ } // Create compilation queue. - compileQueue = new ThreadPoolExecutor(Threads.getValue(), Threads.getValue(), 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), CompilerThread.FACTORY); + CompilerThreadFactory factory = new CompilerThreadFactory("GraalCompilerThread", new DebugConfigAccess() { + public GraalDebugConfig getDebugConfig() { + return Debug.isEnabled() ? DebugEnvironment.initialize(log) : null; + } + }); + compileQueue = new ThreadPoolExecutor(Threads.getValue(), Threads.getValue(), 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); // Create queue status printing thread. if (PrintQueue.getValue()) { diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostLoweringProvider.java Tue Oct 29 16:23:59 2013 +0100 @@ -317,10 +317,19 @@ if (value == null) { omittedValues.set(valuePos); } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { + // Constant.illegal is always the defaultForKind, so it is skipped VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; - WriteNode write = new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true), - (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE, - virtualInstance.field(i).getKind() == Kind.Object); + Kind accessKind; + HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) virtualInstance.field(i); + if (value.kind().getStackKind() != field.getKind().getStackKind()) { + assert value.kind() == Kind.Long || value.kind() == Kind.Double; + accessKind = value.kind(); + } else { + accessKind = field.getKind(); + } + ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, field.offset(), graph); + BarrierType barrierType = (virtualInstance.field(i).getKind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; + WriteNode write = new WriteNode(newObject, value, location, barrierType, virtualInstance.field(i).getKind() == Kind.Object); graph.addAfterFixed(newObject, graph.add(write)); } valuePos++; @@ -338,8 +347,20 @@ if (value == null) { omittedValues.set(valuePos); } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) { - WriteNode write = new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true), - (value.kind() == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.PRECISE : BarrierType.NONE, value.kind() == Kind.Object); + // Constant.illegal is always the defaultForKind, so it is skipped + Kind componentKind = element.getKind(); + Kind accessKind; + if (value.kind().getStackKind() != componentKind.getStackKind()) { + assert value.kind() == Kind.Long || value.kind() == Kind.Double; + accessKind = value.kind(); + } else { + accessKind = componentKind; + } + + int scale = getScalingFactor(componentKind); + ConstantLocationNode location = ConstantLocationNode.create(INIT_LOCATION, accessKind, getArrayBaseOffset(componentKind) + i * scale, graph); + BarrierType barrierType = (componentKind == Kind.Object && !useDeferredInitBarriers()) ? BarrierType.IMPRECISE : BarrierType.NONE; + WriteNode write = new WriteNode(newObject, value, location, barrierType, componentKind == Kind.Object); graph.addAfterFixed(newObject, graph.add(write)); } valuePos++; diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AESCryptSubstitutions.java Tue Oct 29 16:23:59 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.word.*; @@ -41,6 +42,7 @@ public class AESCryptSubstitutions { static final long kOffset; + static final LocationIdentity kLocationIdentity; static final Class AESCryptClass; static { @@ -50,6 +52,7 @@ ClassLoader cl = Launcher.getLauncher().getClassLoader(); AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl); kOffset = UnsafeAccess.unsafe.objectFieldOffset(AESCryptClass.getDeclaredField("K")); + kLocationIdentity = HotSpotResolvedObjectType.fromClass(AESCryptClass).findInstanceFieldWithOffset(kOffset); } catch (Exception ex) { throw new GraalInternalError(ex); } @@ -66,7 +69,7 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, byte[] out, int outOffset, boolean encrypt) { - Object kObject = UnsafeLoadNode.load(rcvr, kOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object kObject = UnsafeLoadNode.load(rcvr, kOffset, Kind.Object, kLocationIdentity); Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); Word outAddr = Word.unsigned(GetObjectAddressNode.get(out) + arrayBaseOffset(Kind.Byte) + outOffset); diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ArrayCopyNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -187,7 +187,7 @@ return; } for (int i = 0; i < length; i++) { - tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i)); + tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i), false); } tool.delete(); if (Debug.isLogEnabled()) { diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CipherBlockChainingSubstitutions.java Tue Oct 29 16:23:59 2013 +0100 @@ -30,6 +30,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node.ConstantNodeParameter; import com.oracle.graal.graph.Node.NodeIntrinsic; +import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.replacements.Snippet.Fold; @@ -42,14 +43,22 @@ public class CipherBlockChainingSubstitutions { private static final long embeddedCipherOffset; + private static final LocationIdentity embeddedCipherLocationIdentity; private static final long rOffset; + private static final LocationIdentity rLocationIdentity; static { try { // Need to use launcher class path as com.sun.crypto.provider.AESCrypt // is normally not on the boot class path ClassLoader cl = Launcher.getLauncher().getClassLoader(); - embeddedCipherOffset = UnsafeAccess.unsafe.objectFieldOffset(Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl).getDeclaredField("embeddedCipher")); - rOffset = UnsafeAccess.unsafe.objectFieldOffset(Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl).getDeclaredField("r")); + + Class feedbackCipherClass = Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl); + embeddedCipherOffset = UnsafeAccess.unsafe.objectFieldOffset(feedbackCipherClass.getDeclaredField("embeddedCipher")); + embeddedCipherLocationIdentity = HotSpotResolvedObjectType.fromClass(feedbackCipherClass).findInstanceFieldWithOffset(embeddedCipherOffset); + + Class cipherBlockChainingClass = Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl); + rOffset = UnsafeAccess.unsafe.objectFieldOffset(cipherBlockChainingClass.getDeclaredField("r")); + rLocationIdentity = HotSpotResolvedObjectType.fromClass(cipherBlockChainingClass).findInstanceFieldWithOffset(rOffset); } catch (Exception ex) { throw new GraalInternalError(ex); } @@ -62,7 +71,7 @@ @MethodSubstitution(isStatic = false) static void encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity); if (getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, true); } else { @@ -72,7 +81,7 @@ @MethodSubstitution(isStatic = false) static void decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) { - Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object embeddedCipher = UnsafeLoadNode.load(rcvr, embeddedCipherOffset, Kind.Object, embeddedCipherLocationIdentity); if (in != out && getAESCryptClass().isInstance(embeddedCipher)) { crypt(rcvr, in, inOffset, inLength, out, outOffset, embeddedCipher, false); } else { @@ -81,8 +90,8 @@ } private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) { - Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.ANY_LOCATION); - Object rObject = UnsafeLoadNode.load(rcvr, rOffset, Kind.Object, LocationIdentity.ANY_LOCATION); + Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, AESCryptSubstitutions.kLocationIdentity); + Object rObject = UnsafeLoadNode.load(rcvr, rOffset, Kind.Object, rLocationIdentity); Word kAddr = (Word) Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)); Word rAddr = (Word) Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte)); Word inAddr = Word.unsigned(GetObjectAddressNode.get(in) + arrayBaseOffset(Kind.Byte) + inOffset); diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -77,10 +77,23 @@ long offset = indexValue.asConstant().asLong(); int entryIndex = state.getVirtualObject().entryIndexForOffset(offset); if (entryIndex != -1) { + Kind entryKind = state.getVirtualObject().entryKind(entryIndex); ValueNode entry = state.getEntry(entryIndex); - if (entry.kind() == value.kind() || state.getVirtualObject().entryKind(entryIndex) == accessKind()) { - tool.setVirtualEntry(state, entryIndex, value()); + if (entry.kind() == value.kind() || entryKind == accessKind()) { + tool.setVirtualEntry(state, entryIndex, value(), true); tool.delete(); + } else { + if ((accessKind() == Kind.Long || accessKind() == Kind.Double) && entryKind == Kind.Int) { + int nextIndex = state.getVirtualObject().entryIndexForOffset(offset + 4); + if (nextIndex != -1) { + Kind nextKind = state.getVirtualObject().entryKind(nextIndex); + if (nextKind == Kind.Int) { + tool.setVirtualEntry(state, entryIndex, value(), true); + tool.setVirtualEntry(state, nextIndex, ConstantNode.forConstant(Constant.forIllegal(), tool.getMetaAccessProvider(), graph()), true); + tool.delete(); + } + } + } } } } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -98,7 +98,7 @@ VirtualObjectNode virtual = state.getVirtualObject(); int entryIndex = virtual.entryIndexForOffset(constantLocation.getDisplacement()); if (entryIndex != -1 && virtual.entryKind(entryIndex) == constantLocation.getValueKind()) { - tool.setVirtualEntry(state, entryIndex, value()); + tool.setVirtualEntry(state, entryIndex, value(), false); tool.delete(); } } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -74,7 +74,7 @@ if (state != null && state.getState() == EscapeState.Virtual) { int fieldIndex = ((VirtualInstanceNode) state.getVirtualObject()).fieldIndex(field()); if (fieldIndex != -1) { - tool.setVirtualEntry(state, fieldIndex, value()); + tool.setVirtualEntry(state, fieldIndex, value(), false); tool.delete(); } } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -76,7 +76,7 @@ ResolvedJavaType componentType = arrayState.getVirtualObject().type().getComponentType(); if (componentType.isPrimitive() || ObjectStamp.isObjectAlwaysNull(value) || componentType.getSuperclass() == null || (ObjectStamp.typeOrNull(value) != null && componentType.isAssignableFrom(ObjectStamp.typeOrNull(value)))) { - tool.setVirtualEntry(arrayState, index, value()); + tool.setVirtualEntry(arrayState, index, value(), false); tool.delete(); } } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java Tue Oct 29 16:23:59 2013 +0100 @@ -84,8 +84,9 @@ * @param state the state. * @param index the index to be set. * @param value the new value for the given index. + * @param unsafe if true, then mismatching value {@link Kind}s will be accepted. */ - void setVirtualEntry(State state, int index, ValueNode value); + void setVirtualEntry(State state, int index, ValueNode value, boolean unsafe); // scalar replacement diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java Tue Oct 29 16:23:59 2013 +0100 @@ -27,7 +27,7 @@ public final class GenericStamp extends Stamp { public enum GenericStampType { - Dependency, Extension, Virtual, Condition, Void + Dependency, Extension, Condition, Void } private final GenericStampType type; diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java Tue Oct 29 16:23:59 2013 +0100 @@ -37,7 +37,6 @@ private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true); private static final Stamp dependencyStamp = new GenericStamp(GenericStampType.Dependency); private static final Stamp extensionStamp = new GenericStamp(GenericStampType.Extension); - private static final Stamp virtualStamp = new GenericStamp(GenericStampType.Virtual); private static final Stamp conditionStamp = new GenericStamp(GenericStampType.Condition); private static final Stamp voidStamp = new GenericStamp(GenericStampType.Void); private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false); @@ -94,10 +93,6 @@ return extensionStamp; } - public static Stamp virtual() { - return virtualStamp; - } - public static Stamp condition() { return conditionStamp; } @@ -163,6 +158,8 @@ return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); case Double: return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble())); + case Illegal: + return illegal(Kind.Illegal); default: throw new GraalInternalError("unexpected kind: %s", kind); } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -119,6 +119,14 @@ used[index] = true; usedCount++; } + if (usedCount == 0) { + List inputSnapshot = inputs().snapshot(); + graph().removeFixed(this); + for (Node input : inputSnapshot) { + tool.removeIfUnused(input); + } + return; + } boolean progress; do { progress = false; diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -36,7 +36,7 @@ private final int length; public VirtualArrayNode(ResolvedJavaType componentType, int length) { - super(true); + super(componentType.getArrayClass(), true); this.componentType = componentType; this.length = length; } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -37,7 +37,7 @@ } public VirtualInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields, boolean hasIdentity) { - super(hasIdentity); + super(type, hasIdentity); this.type = type; this.fields = fields; } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java Tue Oct 29 16:23:59 2013 +0100 @@ -32,8 +32,8 @@ private boolean hasIdentity; - public VirtualObjectNode(boolean hasIdentity) { - super(StampFactory.virtual()); + public VirtualObjectNode(ResolvedJavaType type, boolean hasIdentity) { + super(StampFactory.exactNonNull(type)); this.hasIdentity = hasIdentity; } diff -r ba6593e52d22 -r 748b8381b171 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 Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java Tue Oct 29 16:23:59 2013 +0100 @@ -35,6 +35,7 @@ import com.oracle.graal.api.meta.*; import com.oracle.graal.api.runtime.*; import com.oracle.graal.compiler.*; +import com.oracle.graal.compiler.CompilerThreadFactory.*; import com.oracle.graal.compiler.target.*; import com.oracle.graal.debug.*; import com.oracle.graal.debug.internal.*; @@ -81,7 +82,12 @@ this.skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess()); // Create compilation queue. - compileQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), TruffleCompilerThread.FACTORY); + CompilerThreadFactory factory = new CompilerThreadFactory("TruffleCompilerThread", new DebugConfigAccess() { + public GraalDebugConfig getDebugConfig() { + return Debug.isEnabled() ? DebugEnvironment.initialize(TTY.out().out()) : null; + } + }); + compileQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), factory); final GraphBuilderConfiguration config = GraphBuilderConfiguration.getEagerDefault(); config.setSkippedExceptionTypes(skippedExceptionTypes); diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerThread.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerThread.java Mon Oct 28 11:06:51 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.graal.truffle; - -import java.util.concurrent.*; - -import com.oracle.graal.compiler.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.printer.*; - -public final class TruffleCompilerThread extends Thread { - - public static final ThreadFactory FACTORY = new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - return new TruffleCompilerThread(r); - } - }; - - private TruffleCompilerThread(Runnable r) { - super(r); - this.setName("TruffleCompilerThread-" + this.getId()); - this.setPriority(MAX_PRIORITY); - this.setDaemon(true); - } - - @Override - public void run() { - GraalDebugConfig debugConfig = null; - if (Debug.isEnabled()) { - debugConfig = DebugEnvironment.initialize(System.out); - } - try { - super.run(); - } finally { - if (debugConfig != null) { - for (DebugDumpHandler dumpHandler : debugConfig.dumpHandlers()) { - try { - dumpHandler.close(); - } catch (Throwable t) { - - } - } - } - } - } -} diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java Tue Oct 29 16:23:59 2013 +0100 @@ -132,13 +132,14 @@ } /** - * Sets the phi node's input at the given index to the given value. + * Sets the phi node's input at the given index to the given value, adding new phi inputs as + * needed. * * @param node The phi node whose input should be changed. * @param index The index of the phi input to be changed. * @param value The new value for the phi input. */ - public void setPhiInput(final PhiNode node, final int index, final ValueNode value) { + public void initializePhiInput(final PhiNode node, final int index, final ValueNode value) { add(new Effect() { @Override @@ -149,7 +150,7 @@ @Override public void apply(StructuredGraph graph, ArrayList obsoleteNodes) { assert node.isAlive() && value.isAlive() && index >= 0; - node.setValueAt(index, value); + node.initializeValueAt(index, value); } }); } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java Tue Oct 29 16:23:59 2013 +0100 @@ -208,20 +208,26 @@ } } - private void ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { + /** + * @return true if materialization happened, false if not. + */ + private boolean ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) { assert obj != null; if (obj.getState() == EscapeState.Virtual) { metric.increment(); state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Materialized, effects); + assert !obj.isVirtual(); + return true; } else { assert obj.getState() == EscapeState.Materialized; + return false; } - assert !obj.isVirtual(); } - private void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) { - ensureMaterialized(state, obj, materializeBefore, effects, metric); + private boolean replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) { + boolean materialized = ensureMaterialized(state, obj, materializeBefore, effects, metric); effects.replaceFirstInput(usage, value, obj.getMaterializedValue()); + return materialized; } @Override @@ -275,8 +281,7 @@ protected class MergeProcessor extends EffectsClosure.MergeProcessor { private final HashMap materializedPhis = new HashMap<>(); - private final IdentityHashMap valuePhis = new IdentityHashMap<>(); - private final IdentityHashMap valueObjectMergePhis = new IdentityHashMap<>(); + private final IdentityHashMap valuePhis = new IdentityHashMap<>(); private final IdentityHashMap valueObjectVirtuals = new IdentityHashMap<>(); public MergeProcessor(Block mergeBlock) { @@ -292,21 +297,13 @@ return result; } - private PhiNode[] getValuePhis(VirtualObjectNode virtual) { - PhiNode[] result = valuePhis.get(virtual); - if (result == null) { - result = new PhiNode[virtual.entryCount()]; - valuePhis.put(virtual, result); - } - return result; - } - - private PhiNode[] getValueObjectMergePhis(PhiNode phi, int entryCount) { - PhiNode[] result = valueObjectMergePhis.get(phi); + private PhiNode[] getValuePhis(ValueNode key, int entryCount) { + PhiNode[] result = valuePhis.get(key); if (result == null) { result = new PhiNode[entryCount]; - valueObjectMergePhis.put(phi, result); + valuePhis.put(key, result); } + assert result.length == entryCount; return result; } @@ -319,194 +316,299 @@ return result; } + /** + * Merge all predecessor block states into one block state. This is an iterative process, + * because merging states can lead to materializations which make previous parts of the + * merging operation invalid. The merging process is executed until a stable state has been + * reached. This method needs to be careful to place the effects of the merging operation + * into the correct blocks. + * + * @param states the predecessor block states of the merge + */ @Override protected void merge(List states) { super.merge(states); - /* - * Iterative processing: Merging the materialized/virtual state of virtual objects can - * lead to new materializations, which can lead to new materializations because of phis, - * and so on. - */ - + // calculate the set of virtual objects that exist in all predecessors HashSet virtualObjTemp = new HashSet<>(states.get(0).getVirtualObjects()); for (int i = 1; i < states.size(); i++) { virtualObjTemp.retainAll(states.get(i).getVirtualObjects()); } + ObjectState[] objStates = new ObjectState[states.size()]; boolean materialized; do { mergeEffects.clear(); afterMergeEffects.clear(); materialized = false; for (VirtualObjectNode object : virtualObjTemp) { - ObjectState[] objStates = new ObjectState[states.size()]; - for (int i = 0; i < states.size(); i++) { - objStates[i] = states.get(i).getObjectStateOptional(object); - assert objStates[i] != null; + for (int i = 0; i < objStates.length; i++) { + objStates[i] = states.get(i).getObjectState(object); } + + // determine if all inputs are virtual or the same materialized value int virtual = 0; ObjectState startObj = objStates[0]; boolean locksMatch = true; - ValueNode singleValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); + ValueNode uniqueMaterializedValue = startObj.isVirtual() ? null : startObj.getMaterializedValue(); for (ObjectState obj : objStates) { if (obj.isVirtual()) { virtual++; - singleValue = null; - } else { - if (obj.getMaterializedValue() != singleValue) { - singleValue = null; - } + uniqueMaterializedValue = null; + locksMatch &= obj.locksEqual(startObj); + } else if (obj.getMaterializedValue() != uniqueMaterializedValue) { + uniqueMaterializedValue = null; } - locksMatch &= obj.locksEqual(startObj); } - if (virtual < states.size() || !locksMatch) { - if (singleValue == null) { + if (virtual == objStates.length && locksMatch) { + materialized |= mergeObjectStates(object, objStates, states); + } else { + if (uniqueMaterializedValue != null) { + newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null)); + } else { PhiNode materializedValuePhi = getCachedPhi(object, Kind.Object); mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi"); - for (int i = 0; i < states.size(); i++) { - BlockT state = states.get(i); + for (int i = 0; i < objStates.length; i++) { ObjectState obj = objStates[i]; - materialized |= obj.isVirtual(); Block predecessor = mergeBlock.getPredecessors().get(i); - ensureMaterialized(state, obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue()); } newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null)); - } else { - newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Materialized, null)); } - } else { - assert virtual == states.size(); - ValueNode[] values = startObj.getEntries().clone(); - PhiNode[] phis = getValuePhis(object); - for (int index = 0; index < values.length; index++) { - for (int i = 1; i < states.size(); i++) { - ValueNode[] fields = objStates[i].getEntries(); - if (phis[index] == null && values[index] != fields[index]) { - Kind kind = values[index].kind(); - if (kind == Kind.Illegal) { - // Can happen if one of the values is virtual and is only - // materialized in the following loop. - kind = Kind.Object; - } - phis[index] = new PhiNode(kind, merge); - } - } - } - outer: for (int index = 0; index < values.length; index++) { - if (phis[index] != null) { - mergeEffects.addFloatingNode(phis[index], "virtualMergePhi"); - for (int i = 0; i < states.size(); i++) { - if (!objStates[i].isVirtual()) { - break outer; - } - ValueNode[] fields = objStates[i].getEntries(); - if (fields[index] instanceof VirtualObjectNode) { - ObjectState obj = states.get(i).getObjectState((VirtualObjectNode) fields[index]); - materialized |= obj.isVirtual(); - Block predecessor = mergeBlock.getPredecessors().get(i); - ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); - fields[index] = obj.getMaterializedValue(); - } - afterMergeEffects.addPhiInput(phis[index], fields[index]); - } - values[index] = phis[index]; - } - } - newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, startObj.getLocks())); } } for (PhiNode phi : merge.phis()) { if (usages.isMarked(phi) && phi.type() == PhiType.Value) { - materialized |= processPhi(phi, states); + materialized |= processPhi(phi, states, virtualObjTemp); } } } while (materialized); } - private boolean processPhi(PhiNode phi, List states) { - aliases.set(phi, null); - assert states.size() == phi.valueCount(); - int virtualInputs = 0; - boolean materialized = false; - VirtualObjectNode sameObject = null; - ResolvedJavaType sameType = null; - int sameEntryCount = -1; - boolean hasIdentity = false; - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = phi.valueAt(i); - ObjectState obj = getObjectState(states.get(i), value); - if (obj != null) { - if (obj.isVirtual()) { - virtualInputs++; - if (i == 0) { - sameObject = obj.virtual; - sameType = obj.virtual.type(); - sameEntryCount = obj.virtual.entryCount(); - } else { - if (sameObject != obj.virtual) { - sameObject = null; + /** + * Try to merge multiple virtual object states into a single object state. If the incoming + * object states are compatible, then this method will create PhiNodes for the object's + * entries where needed. If they are incompatible, then all incoming virtual objects will be + * materialized, and a PhiNode for the materialized values will be created. Object states + * can be incompatible if they contain {@code long} or {@code double} values occupying two + * {@code int} slots in such a way that that their values cannot be merged using PhiNodes. + * + * @param object the virtual object that should be associated with the merged object state + * @param objStates the incoming object states (all of which need to be virtual) + * @param blockStates the predecessor block states of the merge + * @return true if materialization happened during the merge, false otherwise + */ + private boolean mergeObjectStates(VirtualObjectNode object, ObjectState[] objStates, List blockStates) { + boolean compatible = true; + ValueNode[] values = objStates[0].getEntries().clone(); + + // determine all entries that have a two-slot value + Kind[] twoSlotKinds = null; + outer: for (int i = 0; i < objStates.length; i++) { + ValueNode[] entries = objStates[i].getEntries(); + int valueIndex = 0; + while (valueIndex < values.length) { + Kind otherKind = entries[valueIndex].kind(); + Kind entryKind = object.entryKind(valueIndex); + if (entryKind == Kind.Int && (otherKind == Kind.Long || otherKind == Kind.Double)) { + if (twoSlotKinds == null) { + twoSlotKinds = new Kind[values.length]; + } + if (twoSlotKinds[valueIndex] != null && twoSlotKinds[valueIndex] != otherKind) { + compatible = false; + break outer; + } + twoSlotKinds[valueIndex] = otherKind; + // skip the next entry + valueIndex++; + } else { + assert entryKind.getStackKind() == otherKind.getStackKind() : entryKind + " vs " + otherKind; + } + valueIndex++; + } + } + if (compatible && twoSlotKinds != null) { + // if there are two-slot values then make sure the incoming states can be merged + outer: for (int valueIndex = 0; valueIndex < values.length; valueIndex++) { + if (twoSlotKinds[valueIndex] != null) { + assert valueIndex < object.entryCount() - 1 && object.entryKind(valueIndex) == Kind.Int && object.entryKind(valueIndex + 1) == Kind.Int; + for (int i = 0; i < objStates.length; i++) { + ValueNode value = objStates[i].getEntry(valueIndex); + Kind valueKind = value.kind(); + if (valueKind != twoSlotKinds[valueIndex]) { + ValueNode nextValue = objStates[i].getEntry(valueIndex + 1); + if (value.isConstant() && value.asConstant().equals(Constant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(Constant.INT_0)) { + // rewrite to a zero constant of the larger kind + objStates[i].setEntry(valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], merge.graph())); + objStates[i].setEntry(valueIndex + 1, ConstantNode.forConstant(Constant.forIllegal(), tool.getMetaAccessProvider(), merge.graph())); + } else { + compatible = false; + break outer; + } } - if (sameType != obj.virtual.type()) { - sameType = null; - } - if (sameEntryCount != obj.virtual.entryCount()) { - sameEntryCount = -1; - } - hasIdentity |= obj.virtual.hasIdentity(); } - } else { - afterMergeEffects.setPhiInput(phi, i, obj.getMaterializedValue()); } } } - boolean materialize = false; - if (virtualInputs == 0) { - // nothing to do... - } else if (virtualInputs == phi.valueCount()) { - if (sameObject != null) { - addAndMarkAlias(sameObject, phi); - } else if (sameType != null && sameEntryCount != -1) { - if (!hasIdentity) { - VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual); + + if (compatible) { + // virtual objects are compatible: create phis for all entries that need them + PhiNode[] phis = getValuePhis(object, object.entryCount()); + int valueIndex = 0; + while (valueIndex < values.length) { + for (int i = 1; i < objStates.length; i++) { + ValueNode[] fields = objStates[i].getEntries(); + if (phis[valueIndex] == null && values[valueIndex] != fields[valueIndex]) { + phis[valueIndex] = new PhiNode(values[valueIndex].kind(), merge); + } + } + if (twoSlotKinds != null && twoSlotKinds[valueIndex] != null) { + // skip an entry after a long/double value that occupies two int slots + valueIndex++; + phis[valueIndex] = null; + values[valueIndex] = ConstantNode.forConstant(Constant.forIllegal(), tool.getMetaAccessProvider(), merge.graph()); + } + valueIndex++; + } + + boolean materialized = false; + for (int i = 0; i < values.length; i++) { + PhiNode phi = phis[i]; + if (phi != null) { + mergeEffects.addFloatingNode(phi, "virtualMergePhi"); + if (object.entryKind(i) == Kind.Object) { + materialized |= mergeObjectEntry(objStates, blockStates, phi, i); + } else { + mergePrimitiveEntry(objStates, phi, i); + } + values[i] = phi; + } + } + newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks())); + return materialized; + } else { + // not compatible: materialize in all predecessors + PhiNode materializedValuePhi = getCachedPhi(object, Kind.Object); + for (int i = 0; i < blockStates.size(); i++) { + ObjectState obj = objStates[i]; + Block predecessor = mergeBlock.getPredecessors().get(i); + ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue()); + } + newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null)); + return true; + } + } - PhiNode[] phis = getValueObjectMergePhis(phi, virtual.entryCount()); - for (int i = 0; i < virtual.entryCount(); i++) { - assert virtual.entryKind(i) != Kind.Object; - if (phis[i] == null) { - phis[i] = new PhiNode(virtual.entryKind(i), merge); - } - mergeEffects.addFloatingNode(phis[i], "valueObjectPhi"); - for (int i2 = 0; i2 < phi.valueCount(); i2++) { - afterMergeEffects.addPhiInput(phis[i], getObjectState(states.get(i2), phi.valueAt(i2)).getEntry(i)); - } + /** + * Fill the inputs of the PhiNode corresponding to one {@link Kind#Object} entry in the + * virtual object. + * + * @return true if materialization happened during the merge, false otherwise + */ + private boolean mergeObjectEntry(ObjectState[] objStates, List blockStates, PhiNode phi, int entryIndex) { + boolean materialized = false; + for (int i = 0; i < objStates.length; i++) { + if (!objStates[i].isVirtual()) { + break; + } + ValueNode[] entries = objStates[i].getEntries(); + if (entries[entryIndex] instanceof VirtualObjectNode) { + ObjectState obj = blockStates.get(i).getObjectState((VirtualObjectNode) entries[entryIndex]); + Block predecessor = mergeBlock.getPredecessors().get(i); + materialized |= ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE); + entries[entryIndex] = obj.getMaterializedValue(); + } + afterMergeEffects.addPhiInput(phi, entries[entryIndex]); + } + return materialized; + } + + /** + * Fill the inputs of the PhiNode corresponding to one primitive entry in the virtual + * object. + */ + private void mergePrimitiveEntry(ObjectState[] objStates, PhiNode phi, int entryIndex) { + for (ObjectState state : objStates) { + if (!state.isVirtual()) { + break; + } + afterMergeEffects.addPhiInput(phi, state.getEntries()[entryIndex]); + } + } + + /** + * Examine a PhiNode and try to replace it with merging of virtual objects if all its inputs + * refer to virtual object states. In order for the merging to happen, all incoming object + * states need to be compatible and without object identity (meaning that their object + * identity if not used later on). + * + * @param phi the PhiNode that should be processed + * @param states the predecessor block states of the merge + * @param mergedVirtualObjects the set of virtual objects that exist in all incoming states, + * and therefore also exist in the merged state + * @return true if materialization happened during the merge, false otherwise + */ + private boolean processPhi(PhiNode phi, List states, Set mergedVirtualObjects) { + aliases.set(phi, null); + assert states.size() == phi.valueCount(); + + // determine how many inputs are virtual and if they're all the same virtual object + int virtualInputs = 0; + ObjectState[] objStates = new ObjectState[states.size()]; + boolean uniqueVirtualObject = true; + for (int i = 0; i < objStates.length; i++) { + ObjectState obj = objStates[i] = getObjectState(states.get(i), phi.valueAt(i)); + if (obj != null) { + if (obj.isVirtual()) { + if (objStates[0] == null || objStates[0].virtual != obj.virtual) { + uniqueVirtualObject = false; } + virtualInputs++; + } + } + } + if (virtualInputs == objStates.length) { + if (uniqueVirtualObject) { + // all inputs refer to the same object: just make the phi node an alias + addAndMarkAlias(objStates[0].virtual, phi); + return false; + } else { + // all inputs are virtual: check if they're compatible and without identity + boolean compatible = true; + ObjectState firstObj = objStates[0]; + for (int i = 0; i < objStates.length; i++) { + ObjectState obj = objStates[i]; + boolean hasIdentity = obj.virtual.hasIdentity() && mergedVirtualObjects.contains(obj.virtual); + if (hasIdentity || firstObj.virtual.type() != obj.virtual.type() || firstObj.virtual.entryCount() != obj.virtual.entryCount() || !firstObj.locksEqual(obj)) { + compatible = false; + break; + } + } + + if (compatible) { + VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual); mergeEffects.addFloatingNode(virtual, "valueObjectNode"); - newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, null)); + + boolean materialized = mergeObjectStates(virtual, objStates, states); addAndMarkAlias(virtual, virtual); addAndMarkAlias(virtual, phi); - } else { - materialize = true; + return materialized; } - } else { - materialize = true; } - } else { - materialize = true; } - if (materialize) { - for (int i = 0; i < phi.valueCount(); i++) { - ValueNode value = phi.valueAt(i); - ObjectState obj = getObjectState(states.get(i), value); - if (obj != null) { - materialized |= obj.isVirtual(); - Block predecessor = mergeBlock.getPredecessors().get(i); - replaceWithMaterialized(value, phi, predecessor.getEndNode(), states.get(i), obj, blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI); - } + // otherwise: materialize all phi inputs + boolean materialized = false; + for (int i = 0; i < objStates.length; i++) { + ObjectState obj = objStates[i]; + if (obj != null) { + Block predecessor = mergeBlock.getPredecessors().get(i); + materialized |= ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_PHI); + afterMergeEffects.initializePhiInput(phi, i, obj.getMaterializedValue()); } } return materialized; @@ -531,10 +633,8 @@ void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) { if (node.isAlive()) { aliases.set(node, virtual); - if (node.recordsUsages()) { - for (Node usage : node.usages()) { - markVirtualUsages(usage); - } + for (Node usage : node.usages()) { + markVirtualUsages(usage); } } } diff -r ba6593e52d22 -r 748b8381b171 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Mon Oct 28 11:06:51 2013 +0100 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java Tue Oct 29 16:23:59 2013 +0100 @@ -80,22 +80,26 @@ } @Override - public void setVirtualEntry(State objectState, int index, ValueNode value) { + public void setVirtualEntry(State objectState, int index, ValueNode value, boolean unsafe) { ObjectState obj = (ObjectState) objectState; assert obj != null && obj.isVirtual() : "not virtual: " + obj; - ObjectState valueState = closure.getObjectState(state, value); ValueNode newValue; - if (valueState == null) { - newValue = getReplacedValue(value); - assert obj.getEntry(index) == null || obj.getEntry(index).kind() == newValue.kind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); + if (value == null) { + newValue = null; } else { - if (valueState.getState() != EscapeState.Virtual) { - newValue = valueState.getMaterializedValue(); - assert newValue.kind() == Kind.Object; + ObjectState valueState = closure.getObjectState(state, value); + if (valueState == null) { + newValue = getReplacedValue(value); + assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).kind() == newValue.kind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue)); } else { - newValue = valueState.getVirtualObject(); + if (valueState.getState() != EscapeState.Virtual) { + newValue = valueState.getMaterializedValue(); + assert newValue.kind() == Kind.Object; + } else { + newValue = valueState.getVirtualObject(); + } + assert obj.getEntry(index) == null || isObjectEntry(obj.getEntry(index)); } - assert obj.getEntry(index) == null || isObjectEntry(obj.getEntry(index)); } obj.setEntry(index, newValue); } diff -r ba6593e52d22 -r 748b8381b171 mxtool/mx.py --- a/mxtool/mx.py Mon Oct 28 11:06:51 2013 +0100 +++ b/mxtool/mx.py Tue Oct 29 16:23:59 2013 +0100 @@ -34,6 +34,7 @@ import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal, xml.sax.saxutils, tempfile, fnmatch import textwrap +import socket import xml.parsers.expat import shutil, re, xml.dom.minidom from collections import Callable @@ -2534,7 +2535,7 @@ suppliedParser = parser is not None - parser = parser if suppliedParser else ArgumentParser(prog='mx build') + parser = parser if suppliedParser else ArgumentParser(prog='mx clean') parser.add_argument('--no-native', action='store_false', dest='native', help='do not clean native projects') parser.add_argument('--no-java', action='store_false', dest='java', help='do not clean Java projects') @@ -2600,8 +2601,56 @@ print 'mx {0} {1}\n\n{2}\n'.format(name, usage, doc) def projectgraph(args, suite=None): - """create dot graph for project structure ("mx projectgraph | dot -Tpdf -oprojects.pdf")""" - + """create graph for project structure ("mx projectgraph | dot -Tpdf -oprojects.pdf" or "mx projectgraph --igv")""" + + parser = ArgumentParser(prog='mx projectgraph') + parser.add_argument('--igv', action='store_true', help='output to IGV listening on 127.0.0.1:4444') + parser.add_argument('--igv-format', action='store_true', help='output graph in IGV format') + + args = parser.parse_args(args) + + if args.igv or args.igv_format: + ids = {} + nextToIndex = {} + igv = XMLDoc() + igv.open('graphDocument') + igv.open('group') + igv.open('properties') + igv.element('p', {'name' : 'name'}, 'GraalProjectDependencies') + igv.close('properties') + igv.open('graph', {'name' : 'dependencies'}) + igv.open('nodes') + for p in sorted_deps(includeLibs=True): + ident = len(ids) + ids[p.name] = str(ident) + igv.open('node', {'id' : str(ident)}) + igv.open('properties') + igv.element('p', {'name' : 'name'}, p.name) + igv.close('properties') + igv.close('node') + igv.close('nodes') + igv.open('edges') + for p in projects(): + fromIndex = 0 + for dep in p.canonical_deps(): + toIndex = nextToIndex.get(dep, 0) + nextToIndex[dep] = toIndex + 1 + igv.element('edge', {'from' : ids[p.name], 'fromIndex' : str(fromIndex), 'to' : ids[dep], 'toIndex' : str(toIndex), 'label' : 'dependsOn'}) + fromIndex = fromIndex + 1 + igv.close('edges') + igv.close('graph') + igv.close('group') + igv.close('graphDocument') + + if args.igv: + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(('127.0.0.1', 4444)) + s.send(igv.xml()) + else: + print igv.xml(indent=' ', newl='\n'); + return + + print 'digraph projects {' print 'rankdir=BT;' print 'node [shape=rect];' diff -r ba6593e52d22 -r 748b8381b171 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Mon Oct 28 11:06:51 2013 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Tue Oct 29 16:23:59 2013 +0100 @@ -914,7 +914,8 @@ fields->sort(compare); for (int i = 0; i < fields->length(); i++) { intptr_t val; - StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(svIndex)); + ScopeValue* scope_field = sv->field_at(svIndex); + StackValue* value = StackValue::create_stack_value(fr, reg_map, scope_field); int offset = fields->at(i)._offset; BasicType type = fields->at(i)._type; switch (type) { @@ -923,6 +924,37 @@ obj->obj_field_put(offset, value->get_obj()()); break; + // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. + case T_INT: case T_FLOAT: { // 4 bytes. + assert(value->type() == T_INT, "Agreement."); + bool big_value = false; + if (i+1 < fields->length() && fields->at(i+1)._type == T_INT) { + if (scope_field->is_location()) { + Location::Type type = ((LocationValue*) scope_field)->location().type(); + if (type == Location::dbl || type == Location::lng) { + big_value = true; + } + } + if (scope_field->is_constant_int()) { + ScopeValue* next_scope_field = sv->field_at(svIndex + 1); + if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) { + big_value = true; + } + } + } + + if (big_value) { + i++; + assert(i < fields->length(), "second T_INT field needed"); + assert(fields->at(i)._type == T_INT, "T_INT field needed"); + } else { + val = value->get_int(); + obj->int_field_put(offset, (jint)*((jint*)&val)); + break; + } + } + /* no break */ + case T_LONG: case T_DOUBLE: { assert(value->type() == T_INT, "Agreement."); StackValue* low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++svIndex)); @@ -939,12 +971,6 @@ obj->long_field_put(offset, res); break; } - // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - obj->int_field_put(offset, (jint)*((jint*)&val)); - break; case T_SHORT: case T_CHAR: // 2 bytes assert(value->type() == T_INT, "Agreement.");