# HG changeset patch # User Doug Simon # Date 1437488122 -7200 # Node ID 706aa848a8d7128dcb5692964aefeaed99fd22f4 # Parent 9bbd878b17af8a9485dbe0ed9b2ec683300ab4f5# Parent b6d504612b3fde098b7701924c284ec0ac187b63 Merge with basic-graal diff -r 9bbd878b17af -r 706aa848a8d7 .hgignore --- a/.hgignore Tue Jul 21 15:16:01 2015 +0200 +++ b/.hgignore Tue Jul 21 16:15:22 2015 +0200 @@ -87,7 +87,7 @@ jacoco.exec workingsets.xml .buildbot/ -graal.options +jvmci.options agent/build/* agent/make/filelist agent/make/sa17.tar.gz diff -r 9bbd878b17af -r 706aa848a8d7 .hgtags --- a/.hgtags Tue Jul 21 15:16:01 2015 +0200 +++ b/.hgtags Tue Jul 21 16:15:22 2015 +0200 @@ -617,3 +617,4 @@ f4822d12204179e6a3e7aaf98991b6171670cbf2 jdk8u45-b11 dc29108bcbcbfcd49eaa9135368306dc85db73a6 jdk8u45-b12 efbf340fc7f56e49735111c23cef030413146409 jdk8u45-b13 +3c622007e098d8905d8e0947362a3894a629a5f1 graal-0.8 diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAAssertionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAAssertionsTest.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test.ea; + +import jdk.internal.jvmci.code.*; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.compiler.test.*; + +public class PEAAssertionsTest extends GraalCompilerTest { + + public static Object field; + + public static void snippet1(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualized(object); + } + + @Test + public void test1() { + test("snippet1", 1); + } + + public static void snippet2(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualized(object); + field = object; // assert here + } + + @Test(expected = SourceStackTrace.class) + public void test2() { + test("snippet2", 1); + } + + public static void snippet3(int i) { + Integer object = new Integer(i); + field = object; + GraalDirectives.ensureVirtualized(object); // assert here + } + + @Test(expected = SourceStackTrace.class) + public void test3() { + test("snippet3", 1); + } + + public static void snippetHere1(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualizedHere(object); + } + + @Test + public void testHere1() { + test("snippetHere1", 1); + } + + public static void snippetHere2(int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualizedHere(object); + field = object; + } + + @Test + public void testHere2() { + test("snippetHere2", 1); + } + + public static void snippetHere3(int i) { + Integer object = new Integer(i); + field = object; + GraalDirectives.ensureVirtualizedHere(object); // assert here + } + + @Test(expected = SourceStackTrace.class) + public void testHere3() { + test("snippetHere3", 1); + } + + public static void snippetBoxing1(int i) { + Integer object = i; + GraalDirectives.ensureVirtualizedHere(object); // assert here + } + + @Test(expected = SourceStackTrace.class) + public void testBoxing1() { + test("snippetBoxing1", 1); + } + + public static void snippetBoxing2(int i) { + Integer object = i; + GraalDirectives.ensureVirtualized(object); // assert here + field = object; + } + + @Test(expected = SourceStackTrace.class) + public void testBoxing2() { + test("snippetBoxing2", 1); + } + + public static void snippetControlFlow1(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + GraalDirectives.ensureVirtualized(object); + } + field = object; + } + + @Test + public void testControlFlow1() { + test("snippetControlFlow1", true, 1); + } + + public static void snippetControlFlow2(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + GraalDirectives.ensureVirtualized(object); + } else { + GraalDirectives.ensureVirtualized(object); + } + field = object; // assert here + } + + @Test(expected = SourceStackTrace.class) + public void testControlFlow2() { + test("snippetControlFlow2", true, 1); + } + + public static void snippetControlFlow3(boolean b, int i) { + Integer object = new Integer(i); + GraalDirectives.ensureVirtualized(object); + if (b) { + field = 1; + } else { + field = 2; + } + field = object; // assert here + } + + @Test(expected = SourceStackTrace.class) + public void testControlFlow3() { + test("snippetControlFlow3", true, 1); + } + + public static void snippetControlFlow4(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + field = object; + } else { + field = 2; + } + GraalDirectives.ensureVirtualized(object); // assert here + } + + @Test(expected = SourceStackTrace.class) + public void testControlFlow4() { + test("snippetControlFlow4", true, 1); + } + + public static void snippetControlFlow5(boolean b, int i) { + Integer object = new Integer(i); + if (b) { + field = object; + } else { + field = 2; + } + GraalDirectives.ensureVirtualizedHere(object); // assert here + } + + @Test(expected = SourceStackTrace.class) + public void testControlFlow5() { + test("snippetControlFlow5", true, 1); + } + + public static final class TestClass { + Object a; + Object b; + } + + public static void snippetIndirect1(boolean b, int i) { + Integer object = new Integer(i); + TestClass t = new TestClass(); + t.a = object; + GraalDirectives.ensureVirtualized(object); + + if (b) { + field = t; // assert here + } else { + field = 2; + } + } + + @Test(expected = SourceStackTrace.class) + public void testIndirect1() { + test("snippetIndirect1", true, 1); + } + + public static void snippetIndirect2(boolean b, int i) { + Integer object = new Integer(i); + TestClass t = new TestClass(); + t.a = object; + GraalDirectives.ensureVirtualized(t); + + if (b) { + field = object; + } else { + field = 2; + } + } + + @Test + public void testIndirect2() { + test("snippetIndirect2", true, 1); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDirectStaticCallOp.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 2015, 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.amd64; + +import jdk.internal.jvmci.hotspot.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.asm.amd64.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp; +import com.oracle.graal.lir.asm.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; + +/** + * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an + * inline cache so it's just a patchable call site. + */ +@Opcode("CALL_DIRECT") +final class AMD64HotSpotDirectStaticCallOp extends DirectCallOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64HotSpotDirectStaticCallOp.class); + + private final InvokeKind invokeKind; + private final HotSpotVMConfig config; + + AMD64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) { + super(TYPE, target, result, parameters, temps, state); + assert invokeKind.isDirect(); + this.invokeKind = invokeKind; + this.config = config; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); + super.emitCode(crb, masm); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ConstantPoolSubstitutionsTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ConstantPoolSubstitutionsTests.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, 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.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.StructuredGraph.*; + +import jdk.internal.jvmci.debug.*; +import jdk.internal.jvmci.debug.Debug.*; +import sun.misc.*; +import sun.reflect.*; + +public class ConstantPoolSubstitutionsTests extends GraalCompilerTest { + + protected StructuredGraph test(final String snippet) { + try (Scope s = Debug.scope("ConstantPoolSubstitutionsTests", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + compile(graph.method(), graph); + assertNotInGraph(graph, Invoke.class); + Debug.dump(graph, snippet); + return graph; + } catch (Throwable e) { + throw Debug.handle(e); + } + } + + protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class clazz) { + for (Node node : graph.getNodes()) { + if (clazz.isInstance(node)) { + fail(node.toString()); + } + } + return graph; + } + + @Test + public void testGetSize() { + ConstantPool cp = SharedSecrets.getJavaLangAccess().getConstantPool(Object.class); + test("getSize", cp); + } + + @Test + public void testGetIntAt() { + test("getIntAt"); + } + + @Test + public void testGetLongAt() { + test("getLongAt"); + } + + @Test + public void testGetFloatAt() { + test("getFloatAt"); + } + + @Test + public void testGetDoubleAt() { + test("getDoubleAt"); + } + + // @Test + public void testGetUTF8At() { + test("getUTF8At"); + } + + public int getSize(ConstantPool cp) { + return cp.getSize(); + } + + public int getIntAt(ConstantPool cp) { + return cp.getIntAt(0); + } + + public long getLongAt(ConstantPool cp) { + return cp.getLongAt(0); + } + + public float getFloatAt(ConstantPool cp) { + return cp.getFloatAt(0); + } + + public double getDoubleAt(ConstantPool cp) { + return cp.getDoubleAt(0); + } + + public String getUTF8At(ConstantPool cp) { + return cp.getUTF8At(0); + } + +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMapBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMapBuilder.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2009, 2015, 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 jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.framemap.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.hotspot.*; +import jdk.internal.jvmci.meta.*; + +public final class HotSpotReferenceMapBuilder extends ReferenceMapBuilder { + + private int maxRegisterSize; + + private final ArrayList objectValues; + private int objectCount; + + private final TargetDescription target; + private final int totalFrameSize; + + public HotSpotReferenceMapBuilder(TargetDescription target, int totalFrameSize) { + this.objectValues = new ArrayList<>(); + this.objectCount = 0; + + this.target = target; + this.totalFrameSize = totalFrameSize; + } + + @Override + public void addLiveValue(Value v) { + if (isConstant(v)) { + return; + } + LIRKind lirKind = v.getLIRKind(); + if (!lirKind.isValue()) { + objectValues.add(v); + if (lirKind.isUnknownReference()) { + objectCount++; + } else { + objectCount += lirKind.getReferenceCount(); + } + } + if (isRegister(v)) { + int size = target.getSizeInBytes(lirKind.getPlatformKind()); + if (size > maxRegisterSize) { + maxRegisterSize = size; + } + } + } + + @Override + public ReferenceMap finish(LIRFrameState state) { + Location[] objects = new Location[objectCount]; + Location[] derivedBase = new Location[objectCount]; + int[] sizeInBytes = new int[objectCount]; + + int idx = 0; + for (Value obj : objectValues) { + LIRKind kind = obj.getLIRKind(); + int bytes = bytesPerElement(kind); + if (kind.isUnknownReference()) { + throw JVMCIError.unimplemented("derived references not yet implemented"); + } else { + Location base = null; + if (kind.isDerivedReference()) { + Variable baseVariable = (Variable) kind.getDerivedReferenceBase(); + Value baseValue = state.getLiveBasePointers().get(baseVariable.index); + assert baseValue.getPlatformKind().getVectorLength() == 1 && baseValue.getLIRKind().isReference(0) && !baseValue.getLIRKind().isDerivedReference(); + base = toLocation(baseValue, 0); + } + + for (int i = 0; i < kind.getPlatformKind().getVectorLength(); i++) { + if (kind.isReference(i)) { + objects[idx] = toLocation(obj, i * bytes); + derivedBase[idx] = base; + sizeInBytes[idx] = bytes; + idx++; + } + } + } + } + + return new HotSpotReferenceMap(objects, derivedBase, sizeInBytes, maxRegisterSize); + } + + private int bytesPerElement(LIRKind kind) { + PlatformKind platformKind = kind.getPlatformKind(); + return target.getSizeInBytes(platformKind) / platformKind.getVectorLength(); + } + + private Location toLocation(Value v, int offset) { + if (isRegister(v)) { + return Location.subregister(asRegister(v), offset); + } else { + StackSlot s = asStackSlot(v); + return Location.stack(s.getOffset(totalFrameSize) + offset); + } + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ConstantPoolSubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ConstantPoolSubstitutions.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, 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.replacements; + +import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; + +import com.oracle.graal.api.replacements.*; +import com.oracle.graal.hotspot.word.*; +import com.oracle.graal.word.*; + +import sun.reflect.*; + +/** + * Substitutions for {@link sun.reflect.ConstantPool} methods. + */ +@ClassSubstitution(sun.reflect.ConstantPool.class) +public class ConstantPoolSubstitutions { + + /** + * Get the metaspace {@code ConstantPool} pointer for the given holder class. + * + * @param constantPoolOop the holder class as {@link Object} + * @return a metaspace {@code ConstantPool} pointer + */ + private static Word metaspaceConstantPool(Object constantPoolOop) { + // ConstantPool.constantPoolOop is in fact the holder class. + Class constantPoolHolder = (Class) constantPoolOop; + KlassPointer klass = ClassGetHubNode.readClass(constantPoolHolder); + return klass.readWord(instanceKlassConstantsOffset(), INSTANCE_KLASS_CONSTANTS); + } + + @MethodSubstitution(isStatic = false) + private static int getSize0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop) { + return metaspaceConstantPool(constantPoolOop).readInt(constantPoolLengthOffset()); + } + + @MethodSubstitution(isStatic = false) + private static int getIntAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) { + return metaspaceConstantPool(constantPoolOop).readInt(constantPoolSize() + index * wordSize()); + } + + @MethodSubstitution(isStatic = false) + private static long getLongAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) { + return metaspaceConstantPool(constantPoolOop).readLong(constantPoolSize() + index * wordSize()); + } + + @MethodSubstitution(isStatic = false) + private static float getFloatAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) { + return metaspaceConstantPool(constantPoolOop).readFloat(constantPoolSize() + index * wordSize()); + } + + @MethodSubstitution(isStatic = false) + private static double getDoubleAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) { + return metaspaceConstantPool(constantPoolOop).readDouble(constantPoolSize() + index * wordSize()); + } + +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, 2015, 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.replacements.arraycopy; + +import static jdk.internal.jvmci.meta.LocationIdentity.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.nodes.memory.*; +import com.oracle.graal.nodes.spi.*; + +@NodeInfo +public class ArrayCopyUnrollNode extends ArrayRangeWriteNode implements MemoryCheckpoint.Single, Lowerable, MemoryAccess { + + public static final NodeClass TYPE = NodeClass.create(ArrayCopyUnrollNode.class); + + @Input protected ValueNode src; + @Input protected ValueNode srcPos; + @Input protected ValueNode dest; + @Input protected ValueNode destPos; + @Input protected ValueNode length; + + private Kind elementKind; + + private int unrolledLength; + + @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess; + + public ArrayCopyUnrollNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, int unrolledLength, Kind elementKind) { + super(TYPE, StampFactory.forKind(Kind.Void)); + this.src = src; + this.srcPos = srcPos; + this.dest = dest; + this.destPos = destPos; + this.length = length; + this.unrolledLength = unrolledLength; + assert elementKind != null && elementKind != Kind.Illegal; + this.elementKind = elementKind; + } + + public ValueNode getSource() { + return src; + } + + public ValueNode getSourcePosition() { + return srcPos; + } + + public ValueNode getDestination() { + return dest; + } + + public ValueNode getDestinationPosition() { + return destPos; + } + + @Override + public ValueNode getLength() { + return length; + } + + @Override + public ValueNode getArray() { + return dest; + } + + @Override + public ValueNode getIndex() { + return destPos; + } + + @Override + public boolean isObjectArray() { + return elementKind == Kind.Object; + } + + @Override + public boolean isInitialization() { + return false; + } + + @NodeIntrinsic + public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter int unrolledLength, @ConstantNodeParameter Kind elementKind); + + public int getUnrollLength() { + return unrolledLength; + } + + public Kind getElementKind() { + return elementKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + if (elementKind != null) { + return NamedLocationIdentity.getArrayLocation(elementKind); + } + return any(); + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + public void setLastLocationAccess(MemoryNode lla) { + updateUsagesInterface(lastLocationAccess, lla); + lastLocationAccess = lla; + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ConstantLoadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/ConstantLoadTest.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.micro; + +import org.junit.*; + +import com.oracle.graal.jtt.*; + +public class ConstantLoadTest extends JTTTest { + + private static final class MyClass { + public long a; + public long b; + + MyClass(long a, long b) { + this.a = a; + this.b = b; + } + } + + private static final MyClass myClass = new MyClass(Long.MIN_VALUE, Long.MAX_VALUE); + private static final long myLong = Long.MAX_VALUE; + + public static long test(int arg) { + if (arg == 0) { + return myClass.a / arg + myLong; + } + if (arg == 1) { + return myClass.b - arg + myLong; + } + long r = 1; + for (int i = 0; i < arg; i++) { + r *= i; + } + return r; + } + + @Test + public void run0() throws Throwable { + runTest("test", 0); + } + + @Test + public void run1() throws Throwable { + runTest("test", -1); + } + + @Test + public void run2() throws Throwable { + runTest("test", 1); + } + + @Test + public void run3() throws Throwable { + runTest("test", 2); + } + +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/VarArgs_Unroll.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/VarArgs_Unroll.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2015, 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.jtt.micro; + +import org.junit.*; + +import com.oracle.graal.jtt.*; + +/* + */ +public class VarArgs_Unroll extends JTTTest { + + public static boolean test(String a, String b) { + return check(a, b); + } + + private static boolean check(String... args) { + if (args.length == 0) { + return true; + } + String s = args[0]; + for (String t : args) { + if (!t.equals(s)) { + return false; + } + } + return true; + } + + @Test + public void run0() throws Throwable { + runTest("test", "ab", "ab"); + } + + @Test + public void run1() throws Throwable { + runTest("test", "ab", "abc"); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/ConstantStackCastTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir.jtt/src/com/oracle/graal/lir/jtt/ConstantStackCastTest.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.jtt; + +import static jdk.internal.jvmci.code.ValueUtil.*; +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; + +/** + * Tests move from a constant to a wider stack slot (e.g. byte constant to integer stack slot). + */ +public class ConstantStackCastTest extends LIRTest { + + private static class LoadConstantStackSpec extends LIRTestSpecification { + protected final LIRKind dstKind; + protected final LIRKind srcKind; + + public LoadConstantStackSpec(LIRKind dstKind, LIRKind srcKind) { + this.dstKind = dstKind; + this.srcKind = srcKind; + } + + @Override + public void generate(LIRGeneratorTool gen, Value value) { + FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder(); + // create slots + StackSlotValue s1 = frameMapBuilder.allocateSpillSlot(dstKind); + // move stuff around + Value srcValue = isConstant(value) ? getConstant(srcKind, value) : value; + gen.emitMove(s1, srcValue); + gen.emitBlackhole(s1); + setResult(gen.emitMove(s1)); + } + + private static PrimitiveConstant getConstant(LIRKind srcKind, Value value) { + + switch ((Kind) srcKind.getPlatformKind()) { + case Byte: + return JavaConstant.forByte((byte) asConstant(value).asInt()); + default: + throw JVMCIError.shouldNotReachHere("Kind not supported: " + srcKind); + } + } + } + + private static final LoadConstantStackSpec stackCopyByte = new LoadConstantStackSpec(LIRKind.value(Kind.Int), LIRKind.value(Kind.Byte)); + + @LIRIntrinsic + public static byte testCopyByte(@SuppressWarnings("unused") LoadConstantStackSpec spec, byte value) { + return value; + } + + public byte testByte(byte value) { + return testCopyByte(stackCopyByte, value); + } + + @Test + public void runByte() throws Throwable { + runTest("testByte", (byte) 0); + } + +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LiveValueSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LiveValueSet.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014, 2015, 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.lir.dfa; + +import jdk.internal.jvmci.meta.*; + +abstract class LiveValueSet> { + + public abstract void put(Value v); + + public abstract void remove(Value v); + + public abstract void putAll(S s); + + public abstract S copy(); +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarker.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2014, 2015, 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.lir.dfa; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.debug.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.framemap.*; + +public abstract class LocationMarker, S extends LiveValueSet> { + + private final LIR lir; + private final BlockMap liveInMap; + private final BlockMap liveOutMap; + + protected final FrameMap frameMap; + + protected LocationMarker(LIR lir, FrameMap frameMap) { + this.lir = lir; + this.frameMap = frameMap; + liveInMap = new BlockMap<>(lir.getControlFlowGraph()); + liveOutMap = new BlockMap<>(lir.getControlFlowGraph()); + } + + protected abstract S newLiveValueSet(); + + protected abstract boolean shouldProcessValue(Value operand); + + protected abstract void processState(LIRInstruction op, LIRFrameState info, S values); + + @SuppressWarnings("unchecked") + void build() { + UniqueWorkList worklist = new UniqueWorkList<>(lir.getControlFlowGraph().getBlocks().size()); + for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) { + worklist.add((T) lir.getControlFlowGraph().getBlocks().get(i)); + } + for (AbstractBlockBase block : lir.getControlFlowGraph().getBlocks()) { + liveInMap.put(block, newLiveValueSet()); + } + while (!worklist.isEmpty()) { + AbstractBlockBase block = worklist.poll(); + processBlock(block, worklist); + } + } + + /** + * Merge outSet with in-set of successors. + */ + private boolean updateOutBlock(AbstractBlockBase block) { + S union = newLiveValueSet(); + for (T succ : block.getSuccessors()) { + union.putAll(liveInMap.get(succ)); + } + S outSet = liveOutMap.get(block); + // check if changed + if (outSet == null || !union.equals(outSet)) { + liveOutMap.put(block, union); + return true; + } + return false; + } + + private void processBlock(AbstractBlockBase block, UniqueWorkList worklist) { + if (updateOutBlock(block)) { + try (Indent indent = Debug.logAndIndent("handle block %s", block)) { + currentSet = liveOutMap.get(block).copy(); + List instructions = lir.getLIRforBlock(block); + for (int i = instructions.size() - 1; i >= 0; i--) { + LIRInstruction inst = instructions.get(i); + processInstructionBottomUp(inst); + } + liveInMap.put(block, currentSet); + currentSet = null; + worklist.addAll(block.getPredecessors()); + } + } + } + + private static final EnumSet REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG); + private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object); + + private S currentSet; + + /** + * Process all values of an instruction bottom-up, i.e. definitions before usages. Values that + * start or end at the current operation are not included. + */ + private void processInstructionBottomUp(LIRInstruction op) { + try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) { + // kills + + op.visitEachTemp(defConsumer); + op.visitEachOutput(defConsumer); + if (frameMap != null && op.destroysCallerSavedRegisters()) { + for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) { + defConsumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET); + } + } + + // gen - values that are considered alive for this state + op.visitEachAlive(useConsumer); + op.visitEachState(useConsumer); + // mark locations + op.forEachState(stateConsumer); + // gen + op.visitEachInput(useConsumer); + } + } + + InstructionStateProcedure stateConsumer = new InstructionStateProcedure() { + public void doState(LIRInstruction inst, LIRFrameState info) { + processState(inst, info, currentSet); + } + }; + + ValueConsumer useConsumer = new ValueConsumer() { + public void visitValue(Value operand, OperandMode mode, EnumSet flags) { + if (shouldProcessValue(operand)) { + // no need to insert values and derived reference + if (Debug.isLogEnabled()) { + Debug.log("set operand: %s", operand); + } + currentSet.put(operand); + } + } + }; + + ValueConsumer defConsumer = new ValueConsumer() { + public void visitValue(Value operand, OperandMode mode, EnumSet flags) { + if (shouldProcessValue(operand)) { + if (Debug.isLogEnabled()) { + Debug.log("clear operand: %s", operand); + } + currentSet.remove(operand); + } else { + assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s", + operand, mode); + } + } + }; +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/LocationMarkerPhase.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2014, 2015, 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.lir.dfa; + +import static jdk.internal.jvmci.code.ValueUtil.*; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; + +/** + * Mark all live references for a frame state. The frame state use this information to build the OOP + * maps. + */ +public final class LocationMarkerPhase extends AllocationPhase { + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build(); + } + + private static final class Marker> extends LocationMarker.RegStackValueSet> { + + private final class RegStackValueSet extends LiveValueSet.RegStackValueSet> { + + private final ValueSet registers; + private final ValueSet stack; + private Set extraStack; + + public RegStackValueSet() { + registers = new ValueSet(); + stack = new ValueSet(); + } + + private RegStackValueSet(RegStackValueSet s) { + registers = new ValueSet(s.registers); + stack = new ValueSet(s.stack); + if (s.extraStack != null) { + extraStack = new HashSet<>(s.extraStack); + } + } + + @Override + public Marker.RegStackValueSet copy() { + return new RegStackValueSet(this); + } + + @Override + public void put(Value v) { + if (isRegister(v)) { + int index = asRegister(v).getReferenceMapIndex(); + registers.put(index, v); + } else if (isStackSlot(v)) { + int index = frameMap.offsetForStackSlot(asStackSlot(v)); + assert index >= 0; + if (index % 4 == 0) { + stack.put(index / 4, v); + } else { + if (extraStack == null) { + extraStack = new HashSet<>(); + } + extraStack.add(v); + } + } + } + + @Override + public void putAll(RegStackValueSet v) { + registers.putAll(v.registers); + stack.putAll(v.stack); + if (v.extraStack != null) { + if (extraStack == null) { + extraStack = new HashSet<>(); + } + extraStack.addAll(v.extraStack); + } + } + + @Override + public void remove(Value v) { + if (isRegister(v)) { + int index = asRegister(v).getReferenceMapIndex(); + registers.put(index, null); + } else if (isStackSlot(v)) { + int index = frameMap.offsetForStackSlot(asStackSlot(v)); + assert index >= 0; + if (index % 4 == 0) { + stack.put(index / 4, null); + } else if (extraStack != null) { + extraStack.remove(v); + } + } + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (obj instanceof Marker.RegStackValueSet) { + RegStackValueSet other = (RegStackValueSet) obj; + return registers.equals(other.registers) && stack.equals(other.stack) && Objects.equals(extraStack, other.extraStack); + } else { + return false; + } + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + public void addLiveValues(ReferenceMapBuilder refMap) { + registers.addLiveValues(refMap); + stack.addLiveValues(refMap); + if (extraStack != null) { + for (Value v : extraStack) { + refMap.addLiveValue(v); + } + } + } + } + + private final RegisterAttributes[] registerAttributes; + + private Marker(LIR lir, FrameMap frameMap) { + super(lir, frameMap); + this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap(); + } + + @Override + protected Marker.RegStackValueSet newLiveValueSet() { + return new RegStackValueSet(); + } + + @Override + protected boolean shouldProcessValue(Value operand) { + return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal; + } + + /** + * This method does the actual marking. + */ + @Override + protected void processState(LIRInstruction op, LIRFrameState info, RegStackValueSet values) { + if (!info.hasDebugInfo()) { + info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved()); + } + + ReferenceMapBuilder refMap = frameMap.newReferenceMapBuilder(); + frameMap.addLiveValues(refMap); + values.addLiveValues(refMap); + + info.debugInfo().setReferenceMap(refMap.finish(info)); + } + + /** + * Gets an object describing the attributes of a given register according to this register + * configuration. + */ + private RegisterAttributes attributes(Register reg) { + return registerAttributes[reg.number]; + } + + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/MarkBasePointersPhase.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.dfa; + +import java.util.*; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.compiler.common.alloc.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.lir.gen.*; +import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory; +import com.oracle.graal.lir.phases.*; + +/** + * Record all derived reference base pointers in a frame state. + */ +public final class MarkBasePointersPhase extends AllocationPhase { + + @Override + protected > void run(TargetDescription target, LIRGenerationResult lirGenRes, List codeEmittingOrder, List linearScanOrder, SpillMoveFactory spillMoveFactory, + RegisterAllocationConfig registerAllocationConfig) { + new Marker(lirGenRes.getLIR(), null).build(); + } + + private static final class Marker> extends LocationMarker.BasePointersSet> { + + private final class BasePointersSet extends LiveValueSet.BasePointersSet> { + + private final ValueSet variables; + + public BasePointersSet() { + variables = new ValueSet(); + } + + private BasePointersSet(BasePointersSet s) { + variables = new ValueSet(s.variables); + } + + @Override + public Marker.BasePointersSet copy() { + return new BasePointersSet(this); + } + + @Override + public void put(Value v) { + Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase(); + variables.put(base.index, base); + } + + @Override + public void putAll(BasePointersSet v) { + variables.putAll(v.variables); + } + + @Override + public void remove(Value v) { + Variable base = (Variable) v.getLIRKind().getDerivedReferenceBase(); + variables.put(base.index, null); + } + + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (obj instanceof Marker.BasePointersSet) { + BasePointersSet other = (BasePointersSet) obj; + return variables.equals(other.variables); + } else { + return false; + } + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + } + + private Marker(LIR lir, FrameMap frameMap) { + super(lir, frameMap); + } + + @Override + protected Marker.BasePointersSet newLiveValueSet() { + return new BasePointersSet(); + } + + @Override + protected boolean shouldProcessValue(Value operand) { + return operand.getLIRKind().isDerivedReference(); + } + + @Override + protected void processState(LIRInstruction op, LIRFrameState info, BasePointersSet values) { + info.setLiveBasePointers(new ValueSet(values.variables)); + } + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/UniqueWorkList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/UniqueWorkList.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, 2015, 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.lir.dfa; + +import java.util.*; + +import com.oracle.graal.compiler.common.cfg.*; + +/** + * Ensures that an element is only in the worklist once. + * + * @param + */ +class UniqueWorkList> extends ArrayDeque { + private static final long serialVersionUID = 8009554570990975712L; + BitSet valid; + + public UniqueWorkList(int size) { + this.valid = new BitSet(size); + } + + @Override + public T poll() { + T result = super.poll(); + if (result != null) { + valid.set(result.getId(), false); + } + return result; + } + + @Override + public boolean add(T pred) { + if (!valid.get(pred.getId())) { + valid.set(pred.getId(), true); + return super.add(pred); + } + return false; + } + + @Override + public boolean addAll(Collection collection) { + boolean changed = false; + for (T element : collection) { + if (!valid.get(element.getId())) { + valid.set(element.getId(), true); + super.add(element); + changed = true; + } + } + return changed; + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/ValueSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/dfa/ValueSet.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2014, 2015, 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.lir.dfa; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.framemap.*; + +public final class ValueSet { + private Value[] values; + + ValueSet() { + values = Value.NO_VALUES; + } + + ValueSet(ValueSet other) { + int limit = other.values.length; + while (limit > 0) { + if (other.values[limit - 1] == null) { + limit--; + continue; + } + break; + } + values = new Value[limit]; + System.arraycopy(other.values, 0, values, 0, values.length); + } + + public Value get(int index) { + return values[index]; + } + + void put(int index, Value value) { + if (value != null && value.getLIRKind().isValue()) { + return; + } + if (values.length <= index) { + if (value == null) { + return; + } + Value[] newValues = new Value[index + 1]; + System.arraycopy(values, 0, newValues, 0, values.length); + values = newValues; + values[index] = value; + } else { + values[index] = value; + } + } + + public void putAll(ValueSet stack) { + Value[] otherValues = stack.values; + int limit = otherValues.length; + if (limit > values.length) { + while (limit > 0) { + if (otherValues[limit - 1] == null) { + limit--; + continue; + } + break; + } + if (limit > values.length) { + Value[] newValues = new Value[limit]; + System.arraycopy(values, 0, newValues, 0, values.length); + values = newValues; + } + } + for (int i = 0; i < limit; i++) { + Value value = otherValues[i]; + if (value != null) { + values[i] = value; + } + } + } + + @Override + public boolean equals(Object other) { + if (other instanceof ValueSet) { + ValueSet that = (ValueSet) other; + int limit = Math.min(values.length, that.values.length); + for (int i = 0; i < limit; i++) { + if (!Objects.equals(values[i], that.values[i])) { + return false; + } + } + for (int i = limit; i < values.length; i++) { + if (values[i] != null) { + return false; + } + } + for (int i = limit; i < that.values.length; i++) { + if (that.values[i] != null) { + return false; + } + } + return true; + } + return false; + } + + public void addLiveValues(ReferenceMapBuilder refMap) { + for (Value v : values) { + if (v != null) { + refMap.addLiveValue(v); + } + } + } + + public void forEach(LIRInstruction inst, OperandMode mode, EnumSet flags, InstructionValueProcedure proc) { + for (int i = 0; i < values.length; i++) { + if (values[i] != null) { + values[i] = proc.doValue(inst, values[i], mode, flags); + } + } + } + + public void forEach(LIRInstruction inst, OperandMode mode, EnumSet flags, InstructionValueConsumer consumer) { + for (Value v : values) { + if (v != null) { + consumer.visitValue(inst, v, mode, flags); + } + } + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("["); + boolean comma = false; + + for (int i = 0; i < values.length; i++) { + if (values[i] != null) { + if (comma) { + sb.append(", "); + } else { + comma = true; + } + + sb.append(i); + sb.append(": "); + sb.append(values[i]); + } + } + sb.append(']'); + return sb.toString(); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/ReferenceMapBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/ReferenceMapBuilder.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, 2015, 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.lir.framemap; + +import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.meta.*; + +import com.oracle.graal.lir.*; + +public abstract class ReferenceMapBuilder { + + public abstract void addLiveValue(Value value); + + public abstract ReferenceMap finish(LIRFrameState state); +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CanonicalizableLocation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CanonicalizableLocation.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, 2015, 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; + +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodes.memory.address.*; + +public interface CanonicalizableLocation { + ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool); +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeValueMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeValueMap.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 2014, 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 jdk.internal.jvmci.meta.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; + +public interface NodeValueMap { + + /** + * Returns the operand that has been previously initialized by + * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code + * generation error to ask for the operand of ValueNode that doesn't have one yet. + * + * @param node A node that produces a result value. + */ + Value operand(Node node); + + /** + * @return {@code true} if there is an {@link Value operand} associated with the {@code node} in + * the current block. + */ + boolean hasOperand(Node node); + + /** + * Associates {@code operand} with the {@code node} in the current block. + * + * @return {@code operand} + */ + Value setResult(ValueNode node, Value operand); + + /** + * Gets the the {@link ValueNode} that produced a {@code value}. If the {@code value} is not + * associated with a {@link ValueNode} {@code null} is returned. + * + * This method is intended for debugging purposes only. + */ + ValueNode valueForOperand(Value value); +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, 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.virtual; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; + +@NodeInfo +public final class EnsureVirtualizedNode extends FixedWithNextNode implements Virtualizable, Lowerable { + + public static final NodeClass TYPE = NodeClass.create(EnsureVirtualizedNode.class); + + @Input ValueNode object; + private final boolean localOnly; + + public EnsureVirtualizedNode(ValueNode object, boolean localOnly) { + super(TYPE, StampFactory.forVoid()); + this.object = object; + this.localOnly = localOnly; + } + + public void virtualize(VirtualizerTool tool) { + State state = tool.getObjectState(object); + if (state != null && state.getState() == EscapeState.Virtual) { + if (state.getVirtualObject() instanceof VirtualBoxingNode) { + Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", state.getVirtualObject().type().getName()); + throw GraphUtil.approxSourceException(this, exception); + } + if (!localOnly) { + state.setEnsureVirtualized(true); + } + tool.delete(); + } + } + + public void lower(LoweringTool tool) { + ensureVirtualFailure(this, object.stamp()); + } + + public static void ensureVirtualFailure(Node location, Stamp stamp) { + Throwable exception = new VerificationError("Object should not be materialized (stamp=%s):", stamp); + throw GraphUtil.approxSourceException(location, exception); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DerivedOopTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/DerivedOopTest.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, 2015, 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.replacements.test; + +import java.util.*; + +import jdk.internal.jvmci.meta.*; + +import org.junit.*; + +import com.oracle.graal.api.directives.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import com.oracle.graal.graphbuilderconf.*; +import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; +import com.oracle.graal.nodes.*; +import com.oracle.graal.replacements.*; +import com.oracle.graal.word.*; +import com.oracle.graal.word.nodes.*; + +/** + * Tests for derived oops in reference maps. + */ +public class DerivedOopTest extends GraalCompilerTest implements Snippets { + + private static class Pointers { + public long basePointer; + public long internalPointer; + + public long delta() { + return internalPointer - basePointer; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Pointers)) { + return false; + } + + Pointers other = (Pointers) obj; + return this.delta() == other.delta(); + } + + @Override + public int hashCode() { + return (int) delta(); + } + } + + private static class Result { + public Pointers beforeGC; + public Pointers afterGC; + + public Result() { + beforeGC = new Pointers(); + afterGC = new Pointers(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((afterGC == null) ? 0 : afterGC.hashCode()); + result = prime * result + ((beforeGC == null) ? 0 : beforeGC.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Result)) { + return false; + } + Result other = (Result) obj; + return Objects.equals(this.beforeGC, other.beforeGC) && Objects.equals(this.afterGC, other.afterGC); + } + } + + @Test + public void testFieldOffset() { + Result r = new Result(); + test("fieldOffsetSnippet", r, 16L); + + Assert.assertEquals(r.beforeGC.delta(), r.afterGC.delta()); + } + + static long getRawPointer(Object obj) { + // fake implementation for interpreter + return obj.hashCode(); + } + + static long getRawPointerIntrinsic(Object obj) { + return Word.fromObject(obj).rawValue(); + } + + public static Result fieldOffsetSnippet(Result obj, long offset) { + long internalPointer = getRawPointer(obj) + offset; + + // make sure the internal pointer is computed before the safepoint + GraalDirectives.blackhole(internalPointer); + + obj.beforeGC.basePointer = getRawPointer(obj); + obj.beforeGC.internalPointer = internalPointer; + + System.gc(); + + obj.afterGC.basePointer = getRawPointer(obj); + obj.afterGC.internalPointer = internalPointer; + + return obj; + } + + @Override + protected Plugins getDefaultGraphBuilderPlugins() { + Plugins plugins = super.getDefaultGraphBuilderPlugins(); + Registration r = new Registration(plugins.getInvocationPlugins(), DerivedOopTest.class); + + ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getRawPointerIntrinsic"); + r.register1("getRawPointer", Object.class, new InvocationPlugin() { + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { + b.intrinsify(targetMethod, intrinsic, new ValueNode[]{arg}); + return true; + } + }); + + return plugins; + } + + @Override + protected boolean checkHighTierGraph(StructuredGraph graph) { + assert graph.getNodes().filter(WordCastNode.class).count() > 0 : "DerivedOopTest.toLong should be intrinsified"; + return super.checkHighTierGraph(graph); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl.disable --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl.disable Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,21 @@ +/* + * This tests that simple arithmetic gets inlined. + */ +function add(a, b) { + deoptimizeWhenCompiled(a == 50); + return a + b; +} + + +function test() { + i = 0; + while (i < 100) { + i = add(i, 1); + } + return i; +} + +function main() { + waitForOptimization(callUntilOptimized(test, 1 == 2)); + test(); +} diff -r 9bbd878b17af -r 706aa848a8d7 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/MockLanguage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/MockLanguage.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 2015, 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.test; + +import com.oracle.truffle.api.TruffleLanguage; + +public abstract class MockLanguage extends TruffleLanguage { + public MockLanguage(Env env) { + super(env); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/BytecodeFrame.java --- a/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/BytecodeFrame.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/BytecodeFrame.java Tue Jul 21 16:15:22 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -197,7 +197,7 @@ assert values.length > i + 1 : String.format("missing second word %s", this); assert values[i + 1] == null || values[i + 1].getKind() == Kind.Illegal : this; } - assert derivedOk || ValueUtil.isIllegal(values[i]) || !values[i].getLIRKind().isDerivedReference() : "Unexpected derived value: " + values[i]; + assert derivedOk || ValueUtil.isIllegal(values[i]) || !values[i].getLIRKind().isUnknownReference() : "Unexpected derived value: " + values[i]; } } return true; diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/DebugInfo.java --- a/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/DebugInfo.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/DebugInfo.java Tue Jul 21 16:15:22 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -24,8 +24,6 @@ import java.util.*; -import jdk.internal.jvmci.meta.*; - /** * Represents the debugging information for a particular point of execution. This information * includes: @@ -41,8 +39,8 @@ public final class DebugInfo { private final BytecodePosition bytecodePosition; - private final ReferenceMap referenceMap; - @SuppressWarnings("unused") private final Value[] virtualObjectMapping; + private ReferenceMap referenceMap; + @SuppressWarnings("unused") private final VirtualObject[] virtualObjectMapping; private RegisterSaveLayout calleeSaveInfo; /** @@ -50,17 +48,19 @@ * * @param codePos the {@linkplain BytecodePosition code position} or {@linkplain BytecodeFrame * frame} info - * @param referenceMap the reference map * @param virtualObjectMapping the mapping of {@link VirtualObject}s to their real values */ - public DebugInfo(BytecodePosition codePos, ReferenceMap referenceMap, Value[] virtualObjectMapping) { + public DebugInfo(BytecodePosition codePos, VirtualObject[] virtualObjectMapping) { this.bytecodePosition = codePos; - this.referenceMap = referenceMap; this.virtualObjectMapping = virtualObjectMapping; } public DebugInfo(BytecodePosition codePos) { - this(codePos, null, null); + this(codePos, null); + } + + public void setReferenceMap(ReferenceMap referenceMap) { + this.referenceMap = referenceMap; } /** diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/ReferenceMap.java --- a/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/ReferenceMap.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/ReferenceMap.java Tue Jul 21 16:15:22 2015 +0200 @@ -22,24 +22,5 @@ */ package jdk.internal.jvmci.code; -import jdk.internal.jvmci.meta.*; - public abstract class ReferenceMap { - - /** - * Empty out the reference map. - */ - public abstract void reset(); - - /** - * Add {@code value} to the current set of reference values. - * - * @param v - */ - public abstract void addLiveValue(Value v); - - /** - * Perform any final encoding needed before use. - */ - public abstract void finish(); } diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/TargetDescription.java --- a/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/TargetDescription.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.code/src/jdk/internal/jvmci/code/TargetDescription.java Tue Jul 21 16:15:22 2015 +0200 @@ -29,7 +29,7 @@ * Represents the target machine for a compiler, including the CPU architecture, the size of * pointers and references, alignment of stacks, caches, etc. */ -public abstract class TargetDescription { +public class TargetDescription { public final Architecture arch; @@ -136,6 +136,4 @@ return LIRKind.Illegal; } } - - public abstract ReferenceMap createReferenceMap(boolean hasRegisters, int stackSlotCount, int totalFrameSize); } diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot.amd64/src/jdk/internal/jvmci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java --- a/jvmci/jdk.internal.jvmci.hotspot.amd64/src/jdk/internal/jvmci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot.amd64/src/jdk/internal/jvmci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java Tue Jul 21 16:15:22 2015 +0200 @@ -103,7 +103,7 @@ final int stackFrameAlignment = 16; final int implicitNullCheckLimit = 4096; final boolean inlineObjects = true; - return new HotSpotTargetDescription(createArchitecture(config), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + return new TargetDescription(createArchitecture(config), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); } protected HotSpotConstantReflectionProvider createConstantReflection(HotSpotJVMCIRuntimeProvider runtime) { diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java --- a/jvmci/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java Tue Jul 21 16:15:22 2015 +0200 @@ -44,7 +44,7 @@ final int stackFrameAlignment = 16; final int implicitNullCheckLimit = 4096; final boolean inlineObjects = false; - return new HotSpotTargetDescription(createArchitecture(config), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + return new TargetDescription(createArchitecture(config), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); } protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotRegisterConfig.java --- a/jvmci/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot.sparc/src/jdk/internal/jvmci/hotspot/sparc/SPARCHotSpotRegisterConfig.java Tue Jul 21 16:15:22 2015 +0200 @@ -110,7 +110,8 @@ // and the current register handler would ignore this fact if the called // method still does not modify registers, in fact o7 is modified by the Call instruction // There would be some extra handlin necessary to be able to handle the o7 properly for local usage - o0, o1, o2, o3, o4, o5, /*o6, o7,*/ + g1, g4, g5, + o0, o1, o2, o3, o4, o5, /*o6,o7,*/ l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ //f0, f1, f2, f3, f4, f5, f6, f7, @@ -125,6 +126,7 @@ // @formatter:off registers = new Register[]{ // TODO this is not complete + g1, g4, g5, o0, o1, o2, o3, o4, o5, /*o6, o7,*/ l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/CompilerToVMImpl.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/CompilerToVMImpl.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/CompilerToVMImpl.java Tue Jul 21 16:15:22 2015 +0200 @@ -25,6 +25,7 @@ import static jdk.internal.jvmci.hotspot.InitTimer.*; import jdk.internal.jvmci.code.*; +import jdk.internal.jvmci.common.*; import jdk.internal.jvmci.meta.*; /** @@ -72,19 +73,39 @@ public native Object resolveConstantInPool(long metaspaceConstantPool, int cpi); - public native Object resolvePossiblyCachedConstantInPool(long metaspaceConstantPool, int cpi); + public Object resolvePossiblyCachedConstantInPool(long metaspaceConstantPool, int cpi) { + JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), ""); + return resolvePossiblyCachedConstantInPool0(metaspaceConstantPool, cpi); + } + + private native Object resolvePossiblyCachedConstantInPool0(long metaspaceConstantPool, int cpi); @Override public native int lookupNameAndTypeRefIndexInPool(long metaspaceConstantPool, int cpi); @Override - public native String lookupNameRefInPool(long metaspaceConstantPool, int cpi); + public String lookupNameRefInPool(long metaspaceConstantPool, int cpi) { + JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), ""); + return lookupNameRefInPool0(metaspaceConstantPool, cpi); + } + + private native String lookupNameRefInPool0(long metaspaceConstantPool, int cpi); @Override - public native String lookupSignatureRefInPool(long metaspaceConstantPool, int cpi); + public String lookupSignatureRefInPool(long metaspaceConstantPool, int cpi) { + JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), ""); + return lookupSignatureRefInPool0(metaspaceConstantPool, cpi); + } + + private native String lookupSignatureRefInPool0(long metaspaceConstantPool, int cpi); @Override - public native int lookupKlassRefIndexInPool(long metaspaceConstantPool, int cpi); + public int lookupKlassRefIndexInPool(long metaspaceConstantPool, int cpi) { + JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), ""); + return lookupKlassRefIndexInPool0(metaspaceConstantPool, cpi); + } + + private native int lookupKlassRefIndexInPool0(long metaspaceConstantPool, int cpi); public native long constantPoolKlassAt(long metaspaceConstantPool, int cpi); @@ -97,10 +118,20 @@ @Override public native long resolveField(long metaspaceConstantPool, int cpi, byte opcode, long[] info); - public native int constantPoolRemapInstructionOperandFromCache(long metaspaceConstantPool, int cpi); + public int constantPoolRemapInstructionOperandFromCache(long metaspaceConstantPool, int cpi) { + JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), ""); + return constantPoolRemapInstructionOperandFromCache0(metaspaceConstantPool, cpi); + } + + private native int constantPoolRemapInstructionOperandFromCache0(long metaspaceConstantPool, int cpi); @Override - public native Object lookupAppendixInPool(long metaspaceConstantPool, int cpi); + public Object lookupAppendixInPool(long metaspaceConstantPool, int cpi) { + JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), ""); + return lookupAppendixInPool0(metaspaceConstantPool, cpi); + } + + private native Object lookupAppendixInPool0(long metaspaceConstantPool, int cpi); @Override public native void initializeConfiguration(HotSpotVMConfig config); @@ -191,7 +222,12 @@ public native long getTimeStamp(); - public native String getSymbol(long metaspaceSymbol); + public String getSymbol(long metaspaceSymbol) { + JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), ""); + return getSymbol0(metaspaceSymbol); + } + + private native String getSymbol0(long metaspaceSymbol); public native void resolveInvokeDynamic(long metaspaceConstantPool, int index); diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantPool.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantPool.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantPool.java Tue Jul 21 16:15:22 2015 +0200 @@ -26,15 +26,24 @@ import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; import java.lang.invoke.*; +import java.util.*; import jdk.internal.jvmci.common.*; import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.options.*; /** * Implementation of {@link ConstantPool} for HotSpot. */ public class HotSpotConstantPool implements ConstantPool, HotSpotProxified { + public static class Options { + // @formatter:off + @Option(help = "Use Java code to access the constant pool cache and resolved references array", type = OptionType.Expert) + public static final OptionValue UseConstantPoolCacheJavaCode = new OptionValue<>(false); + // @formatter:on + } + /** * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. */ @@ -179,8 +188,232 @@ private final long metaspaceConstantPool; private volatile LookupTypeCacheElement lastLookupType; + /** + * The constant pool cache of this constant pool. + */ + private final Cache cache; + + /** + * Represents a {@code ConstantPoolCache}. The cache needs to be lazy since the constant pool + * cache is created when the methods of this class are rewritten and rewriting happens when the + * class is linked. + */ + private final class Cache { + + private long address; + + public Cache() { + // Maybe the constant pool cache already exists... + queryAddress(); + } + + /** + * Queries the current value of {@code ConstantPool::_cache} if the current address is null. + */ + private void queryAddress() { + if (address == 0) { + address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolCacheOffset); + } + } + + /** + * Returns whether a constant pool cache for this constant pool exists. + * + * @return true if it exists, false otherwise + */ + public boolean exists() { + queryAddress(); + return address != 0; + } + + /** + * Represents a {@code ConstantPoolCacheEntry}. + */ + private final class Entry { + + private final long address; + + public Entry(final long address) { + this.address = address; + } + + /** + * {@code ConstantPoolCacheEntry::_indices} is volatile of type {@code intx}. + * + * @return value of field {@code _indices} + */ + private long getIndices() { + assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; + return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryIndicesOffset); + } + + /** + * {@code ConstantPoolCacheEntry::_f1} is volatile of type {@code Metadata*}. + * + * @return value of field {@code _f1} + */ + private long getF1() { + assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; + return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF1Offset); + } + + /** + * {@code ConstantPoolCacheEntry::_f2} is volatile of type {@code intx}. + * + * @return value of field {@code _f2} + */ + private long getF2() { + assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; + return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF2Offset); + } + + /** + * {@code ConstantPoolCacheEntry::_flags} is volatile of type {@code intx}. + * + * @return flag bits + */ + private long flags() { + assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; + return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryFlagsOffset); + } + + private boolean isF1Null() { + final long f1 = getF1(); + return f1 == 0; + } + + /** + * Returns the constant pool index for this entry. See + * {@code ConstantPoolCacheEntry::constant_pool_index()} + * + * @return the constant pool index for this entry + */ + public int getConstantPoolIndex() { + return ((int) getIndices()) & runtime().getConfig().constantPoolCacheEntryCpIndexMask; + } + + /** + * See {@code ConstantPoolCache::has_appendix()}. + * + * @return true if there is an appendix, false otherwise + */ + private boolean hasAppendix() { + return (!isF1Null()) && (flags() & (1 << runtime().getConfig().constantPoolCacheEntryHasAppendixShift)) != 0; + } + + /** + * See {@code ConstantPoolCache::appendix_if_resolved()}. + */ + public Object getAppendixIfResolved() { + if (!hasAppendix()) { + return null; + } + final int index = ((int) getF2()) + runtime().getConfig().constantPoolCacheEntryIndyResolvedReferencesAppendixOffset; + return resolvedReferences.getArray()[index]; + } + } + + /** + * Get the constant pool cache entry at index {@code index}. + * + * @param index index of entry to return + * @return constant pool cache entry at given index + */ + public Entry getEntryAt(int index) { + queryAddress(); + assert exists(); + HotSpotVMConfig config = runtime().getConfig(); + return new Entry(address + config.constantPoolCacheSize + config.constantPoolCacheEntrySize * index); + } + + /** + * Maps the constant pool cache index back to a constant pool index. See + * {@code ConstantPool::remap_instruction_operand_from_cache}. + * + * @param index the constant pool cache index + * @return constant pool index + */ + public int constantPoolCacheIndexToConstantPoolIndex(int index) { + final int cacheIndex = index - runtime().getConfig().constantPoolCpCacheIndexTag; + return getEntryAt(cacheIndex).getConstantPoolIndex(); + } + + } + + /** + * Resolved references of this constant pool. + */ + private final ResolvedReferences resolvedReferences = new ResolvedReferences(); + + /** + * Hide the resolved references array in a private class so it cannot be accessed directly. The + * reason is the resolved references array is created when the constant pool cache is created. + * + * @see Cache + */ + private final class ResolvedReferences { + + /** + * Pointer to the {@code ConstantPool::_resolved_references} array. + */ + private Object[] resolvedReferences; + + /** + * Map of constant pool indexes to {@code ConstantPool::_resolved_references} indexes. + */ + private final HashMap referenceMap = new HashMap<>(); + + /** + * Returns the {@code ConstantPool::_resolved_references} array for this constant pool. + * + * @return resolved references array if exists, null otherwise + */ + public Object[] getArray() { + if (resolvedReferences == null) { + final long handle = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolResolvedReferencesOffset); + if (handle != 0) { + resolvedReferences = (Object[]) runtime().getCompilerToVM().readUncompressedOop(handle + runtime().getConfig().handleHandleOffset); + fillReferenceMap(); + } + } + return resolvedReferences; + } + + /** + * Fills the {@link #referenceMap} with all the values from + * {@code ConstantPool::_reference_map} for faster lookup. + */ + private void fillReferenceMap() { + // It is possible there is a resolved references array but no reference map. + final long address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolReferenceMapOffset); + if (address != 0) { + final int length = unsafe.getInt(null, address + runtime().getConfig().arrayU1LengthOffset); + for (int i = 0; i < length; i++) { + final int value = unsafe.getShort(address + runtime().getConfig().arrayU2DataOffset + i * Short.BYTES); + referenceMap.put(value, i); + } + } + } + + /** + * See {@code ConstantPool::cp_to_object_index}. + * + * @param cpi constant pool index + * @return resolved references array index + */ + public int constantPoolIndexToResolvedReferencesIndex(int cpi) { + final Integer index = referenceMap.get(cpi); + // We might not find the index for jsr292 call. + return (index == null) ? -1 : index; + } + + } + public HotSpotConstantPool(long metaspaceConstantPool) { this.metaspaceConstantPool = metaspaceConstantPool; + + // Cache constructor needs metaspaceConstantPool. + cache = new Cache(); } /** @@ -201,7 +434,7 @@ * @param opcode bytecode to convert the index for * @return constant pool index */ - private static int toConstantPoolIndex(int rawIndex, int opcode) { + private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { int index; if (opcode == Bytecodes.INVOKEDYNAMIC) { index = rawIndex; @@ -348,7 +581,12 @@ * @return name as {@link String} */ private String getNameRefAt(int index) { - return runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index); + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + final int nameRefIndex = getNameRefIndexAt(getNameAndTypeRefIndexAt(index)); + return new HotSpotSymbol(getEntryAt(nameRefIndex)).asString(); + } else { + return runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index); + } } /** @@ -372,7 +610,12 @@ * @return signature as {@link String} */ private String getSignatureRefAt(int index) { - return runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index); + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + final int signatureRefIndex = getSignatureRefIndexAt(getNameAndTypeRefIndexAt(index)); + return new HotSpotSymbol(getEntryAt(signatureRefIndex)).asString(); + } else { + return runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index); + } } /** @@ -389,13 +632,38 @@ } /** - * Gets the klass reference index constant pool entry at index {@code index}. + * Gets the klass reference index constant pool entry at index {@code index}. See + * {@code ConstantPool::klass_ref_index_at}. + * + * @param index constant pool index + * @param cached whether to go through the constant pool cache + * @return klass reference index + */ + private int getKlassRefIndexAt(int index, boolean cached) { + int cpi = index; + if (cached && cache.exists()) { + // change byte-ordering and go via cache + cpi = cache.constantPoolCacheIndexToConstantPoolIndex(index); + } + assertTagIsFieldOrMethod(cpi); + final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + cpi * runtime().getHostJVMCIBackend().getTarget().wordSize); + // klass ref index is in the low 16-bits. + return refIndex & 0xFFFF; + } + + /** + * Gets the klass reference index constant pool entry at index {@code index}. See + * {@code ConstantPool::klass_ref_index_at}. * * @param index constant pool index * @return klass reference index */ private int getKlassRefIndexAt(int index) { - return runtime().getCompilerToVM().lookupKlassRefIndexInPool(metaspaceConstantPool, index); + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + return getKlassRefIndexAt(index, true); + } else { + return runtime().getCompilerToVM().lookupKlassRefIndexInPool(metaspaceConstantPool, index); + } } /** @@ -406,10 +674,14 @@ * @return klass reference index */ private int getUncachedKlassRefIndexAt(int index) { - assert getTagAt(index) == JVM_CONSTANT.Fieldref || getTagAt(index) == JVM_CONSTANT.MethodRef || getTagAt(index) == JVM_CONSTANT.InterfaceMethodref; - final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); - // klass ref index is in the low 16-bits. - return refIndex & 0xFFFF; + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + return getKlassRefIndexAt(index, false); + } else { + assertTagIsFieldOrMethod(index); + final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + // klass ref index is in the low 16-bits. + return refIndex & 0xFFFF; + } } /** @@ -428,7 +700,19 @@ * @param tag expected tag */ private void assertTag(int index, JVM_CONSTANT tag) { - assert getTagAt(index) == tag : "constant pool tag at index " + index + " is " + getTagAt(index) + " but expected " + tag; + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; + } + + /** + * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, + * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. + * + * @param index constant pool index + */ + private void assertTagIsFieldOrMethod(int index) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; } @Override @@ -455,7 +739,38 @@ final int opcode = -1; // opcode is not used return lookupType(cpi, opcode); case String: - Object string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(metaspaceConstantPool, cpi); + /* + * Normally, we would expect a String here, but anonymous classes can have + * "pseudo strings" (arbitrary live objects) patched into a String entry. Such + * entries do not have a symbol in the constant pool slot. + */ + Object string; + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + // See: ConstantPool::resolve_constant_at_impl + /* + * Note: Call getArray() before constantPoolIndexToResolvedReferencesIndex() + * because it fills the map if the array exists. + */ + Object[] localResolvedReferences = resolvedReferences.getArray(); + final int index = resolvedReferences.constantPoolIndexToResolvedReferencesIndex(cpi); + assert index >= 0; + // See: ConstantPool::string_at_impl + string = localResolvedReferences[index]; + if (string != null) { + assert string instanceof String || getEntryAt(index) == 0L; + return HotSpotObjectConstantImpl.forObject(string); + } else { + final long metaspaceSymbol = getEntryAt(cpi); + if (metaspaceSymbol != 0L) { + HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol); + string = symbol.asString().intern(); + // See: ConstantPool::string_at_put + localResolvedReferences[index] = string; + } + } + } else { + string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(metaspaceConstantPool, cpi); + } return HotSpotObjectConstantImpl.forObject(string); case MethodHandle: case MethodHandleInError: @@ -471,7 +786,18 @@ @Override public String lookupUtf8(int cpi) { assertTag(cpi, JVM_CONSTANT.Utf8); - return runtime().getCompilerToVM().getSymbol(getEntryAt(cpi)); + String s; + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + HotSpotSymbol symbol = new HotSpotSymbol(getEntryAt(cpi)); + s = symbol.asString(); + // It shouldn't but just in case something went wrong... + if (s == null) { + throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool"); + } + } else { + s = runtime().getCompilerToVM().getSymbol(getEntryAt(cpi)); + } + return s; } @Override @@ -482,12 +808,26 @@ @Override public JavaConstant lookupAppendix(int cpi, int opcode) { assert Bytecodes.isInvoke(opcode); - final int index = toConstantPoolIndex(cpi, opcode); - Object result = runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, index); - if (result == null) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + + Object appendix = null; + + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + if (!cache.exists()) { + // Nothing to load yet. + return null; + } + final int cacheIndex = decodeConstantPoolCacheIndex(index); + Cache.Entry entry = cache.getEntryAt(cacheIndex); + appendix = entry.getAppendixIfResolved(); + } else { + appendix = runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, index); + } + + if (appendix == null) { return null; } else { - return HotSpotObjectConstantImpl.forObject(result); + return HotSpotObjectConstantImpl.forObject(appendix); } } @@ -502,7 +842,17 @@ HotSpotVMConfig config = runtime.getConfig(); if ((metaspacePointer & config.compilerToVMSymbolTag) != 0) { final long metaspaceSymbol = metaspacePointer & ~config.compilerToVMSymbolTag; - String name = runtime.getCompilerToVM().getSymbol(metaspaceSymbol); + String name; + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol); + name = symbol.asString(); + // It shouldn't but just in case something went wrong... + if (name == null) { + throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool"); + } + } else { + name = runtime.getCompilerToVM().getSymbol(metaspaceSymbol); + } return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";"); } else { assert (metaspacePointer & config.compilerToVMKlassTag) == 0; @@ -512,7 +862,7 @@ @Override public JavaMethod lookupMethod(int cpi, int opcode) { - final int index = toConstantPoolIndex(cpi, opcode); + final int index = rawIndexToConstantPoolIndex(cpi, opcode); final long metaspaceMethod = runtime().getCompilerToVM().lookupMethodInPool(metaspaceConstantPool, index, (byte) opcode); if (metaspaceMethod != 0L) { HotSpotResolvedJavaMethod result = HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod); @@ -550,7 +900,7 @@ @Override public JavaField lookupField(int cpi, int opcode) { - final int index = toConstantPoolIndex(cpi, opcode); + final int index = rawIndexToConstantPoolIndex(cpi, opcode); final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); final int nameIndex = getNameRefIndexAt(nameAndTypeIndex); String name = lookupUtf8(nameIndex); @@ -597,14 +947,44 @@ case Bytecodes.LDC2_W: index = cpi; break; - case Bytecodes.INVOKEDYNAMIC: + case Bytecodes.INVOKEDYNAMIC: { // invokedynamic instructions point to a constant pool cache entry. - index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag; - index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index); + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + // index = decodeConstantPoolCacheIndex(cpi) + + // runtime().getConfig().constantPoolCpCacheIndexTag; + // index = cache.constantPoolCacheIndexToConstantPoolIndex(index); + final int cacheIndex = cpi; + index = cache.getEntryAt(decodeInvokedynamicIndex(cacheIndex)).getConstantPoolIndex(); + // JVMCIError.guarantee(index == x, index + " != " + x); + } else { + index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag; + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index); + } break; + } + case Bytecodes.GETSTATIC: + case Bytecodes.PUTSTATIC: + case Bytecodes.GETFIELD: + case Bytecodes.PUTFIELD: + case Bytecodes.INVOKEVIRTUAL: + case Bytecodes.INVOKESPECIAL: + case Bytecodes.INVOKESTATIC: + case Bytecodes.INVOKEINTERFACE: { + // invoke and field instructions point to a constant pool cache entry. + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + // index = rawIndexToConstantPoolIndex(cpi, opcode); + // index = cache.constantPoolCacheIndexToConstantPoolIndex(index); + final int cacheIndex = cpi; + index = cache.getEntryAt(cacheIndex).getConstantPoolIndex(); + // JVMCIError.guarantee(index == x, index + " != " + x); + } else { + index = rawIndexToConstantPoolIndex(cpi, opcode); + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index); + } + break; + } default: - index = toConstantPoolIndex(cpi, opcode); - index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index); + throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); } final JVM_CONSTANT tag = getTagAt(index); @@ -633,7 +1013,7 @@ switch (tag) { case MethodRef: if (Bytecodes.isInvokeHandleAlias(opcode)) { - final int methodRefCacheIndex = toConstantPoolIndex(cpi, opcode); + final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); if (isInvokeHandle(methodRefCacheIndex, type)) { runtime().getCompilerToVM().resolveInvokeHandle(metaspaceConstantPool, methodRefCacheIndex); } @@ -652,7 +1032,13 @@ } private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { - assertTag(runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + int index; + if (Options.UseConstantPoolCacheJavaCode.getValue()) { + index = cache.constantPoolCacheIndexToConstantPoolIndex(methodRefCacheIndex); + } else { + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, methodRefCacheIndex); + } + assertTag(index, JVM_CONSTANT.MethodRef); return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameRefAt(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess()); } diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotReferenceMap.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotReferenceMap.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotReferenceMap.java Tue Jul 21 16:15:22 2015 +0200 @@ -22,107 +22,22 @@ */ package jdk.internal.jvmci.hotspot; -import static jdk.internal.jvmci.code.ValueUtil.*; - import java.util.*; import jdk.internal.jvmci.code.*; -import jdk.internal.jvmci.common.*; -import jdk.internal.jvmci.meta.*; public final class HotSpotReferenceMap extends ReferenceMap { - private Location[] objects; - private Location[] derivedBase; - private int[] sizeInBytes; - private int maxRegisterSize; - - private ArrayList objectValues; - private int objectCount; - - private final TargetDescription target; - private final int totalFrameSize; - - public HotSpotReferenceMap(TargetDescription target, int totalFrameSize) { - this.target = target; - this.objectCount = 0; - this.totalFrameSize = totalFrameSize; - } - - @Override - public void reset() { - objects = null; - derivedBase = null; - sizeInBytes = null; - maxRegisterSize = 0; - - objectValues = new ArrayList<>(); - objectCount = 0; - } + final Location[] objects; + final Location[] derivedBase; + final int[] sizeInBytes; + final int maxRegisterSize; - @Override - public void addLiveValue(Value v) { - if (isConstant(v)) { - return; - } - LIRKind lirKind = v.getLIRKind(); - if (!lirKind.isValue()) { - objectValues.add(v); - if (lirKind.isDerivedReference()) { - objectCount++; - } else { - objectCount += lirKind.getReferenceCount(); - } - } - if (isRegister(v)) { - int size = target.getSizeInBytes(lirKind.getPlatformKind()); - if (size > maxRegisterSize) { - maxRegisterSize = size; - } - } - } - - @Override - public void finish() { - objects = new Location[objectCount]; - derivedBase = new Location[objectCount]; - sizeInBytes = new int[objectCount]; - - int idx = 0; - for (Value obj : objectValues) { - LIRKind kind = obj.getLIRKind(); - int bytes = bytesPerElement(kind); - if (kind.isDerivedReference()) { - throw JVMCIError.unimplemented("derived references not yet implemented"); - } else { - for (int i = 0; i < kind.getPlatformKind().getVectorLength(); i++) { - if (kind.isReference(i)) { - objects[idx] = toLocation(obj, i * bytes); - derivedBase[idx] = null; - sizeInBytes[idx] = bytes; - idx++; - } - } - } - } - - assert idx == objectCount; - objectValues = null; - objectCount = 0; - } - - private int bytesPerElement(LIRKind kind) { - PlatformKind platformKind = kind.getPlatformKind(); - return target.getSizeInBytes(platformKind) / platformKind.getVectorLength(); - } - - private Location toLocation(Value v, int offset) { - if (isRegister(v)) { - return Location.subregister(asRegister(v), offset); - } else { - StackSlot s = asStackSlot(v); - return Location.stack(s.getOffset(totalFrameSize) + offset); - } + public HotSpotReferenceMap(Location[] objects, Location[] derivedBase, int[] sizeInBytes, int maxRegisterSize) { + this.objects = objects; + this.derivedBase = derivedBase; + this.sizeInBytes = sizeInBytes; + this.maxRegisterSize = maxRegisterSize; } @Override @@ -137,7 +52,7 @@ } if (obj instanceof HotSpotReferenceMap) { HotSpotReferenceMap that = (HotSpotReferenceMap) obj; - if (Arrays.equals(objects, that.objects) && this.target.equals(that.target)) { + if (Arrays.equals(objects, that.objects)) { return true; } } diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectType.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectType.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectType.java Tue Jul 21 16:15:22 2015 +0200 @@ -88,6 +88,8 @@ long prototypeMarkWord(); + int layoutHelper(); + HotSpotResolvedObjectType getEnclosingType(); ResolvedJavaMethod getClassInitializer(); diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl.java Tue Jul 21 16:15:22 2015 +0200 @@ -430,7 +430,7 @@ assert !isInterface(); HotSpotVMConfig config = runtime().getConfig(); - final int layoutHelper = unsafe.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); + final int layoutHelper = layoutHelper(); assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance"; // See: Klass::layout_helper_size_in_bytes @@ -442,6 +442,11 @@ return needsSlowPath ? -size : size; } + public int layoutHelper() { + HotSpotVMConfig config = runtime().getConfig(); + return unsafe.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); + } + public synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { HotSpotResolvedJavaMethod method = null; if (methodCache == null) { diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSymbol.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSymbol.java Tue Jul 21 16:15:22 2015 +0200 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2013, 2015, 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 jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.common.UnsafeAccess.*; +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; + +import java.io.*; +import java.util.*; + +/** + * Represents a metaspace {@code Symbol}. + */ +public class HotSpotSymbol { + + private final long metaspaceSymbol; + + public HotSpotSymbol(long metaspaceSymbol) { + assert metaspaceSymbol != 0; + this.metaspaceSymbol = metaspaceSymbol; + } + + /** + * Decodes this {@code Symbol} and returns the symbol string as {@link java.lang.String}. + * + * @return the decoded string, or null if there was a decoding error + */ + public String asString() { + return readModifiedUTF8(asByteArray()); + } + + /** + * Reads the modified UTF-8 string in {@code buf} and converts it to a {@link String}. The + * implementation is taken from {@link java.io.DataInputStream#readUTF(DataInput)} and adapted + * to operate on a {@code byte} array directly for performance reasons. + * + * @see java.io.DataInputStream#readUTF(DataInput) + */ + private static String readModifiedUTF8(byte[] buf) { + final int utflen = buf.length; + byte[] bytearr = null; + char[] chararr = new char[utflen]; + + int c; + int char2; + int char3; + int count = 0; + int chararrCount = 0; + + bytearr = buf; + + while (count < utflen) { + c = bytearr[count] & 0xff; + if (c > 127) { + break; + } + count++; + chararr[chararrCount++] = (char) c; + } + + while (count < utflen) { + c = bytearr[count] & 0xff; + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + /* 0xxxxxxx */ + count++; + chararr[chararrCount++] = (char) c; + break; + case 12: + case 13: + /* 110x xxxx 10xx xxxx */ + count += 2; + if (count > utflen) { + // malformed input: partial character at end + return null; + } + char2 = bytearr[count - 1]; + if ((char2 & 0xC0) != 0x80) { + // malformed input around byte + return null; + } + chararr[chararrCount++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + /* 1110 xxxx 10xx xxxx 10xx xxxx */ + count += 3; + if (count > utflen) { + // malformed input: partial character at end + return null; + } + char2 = bytearr[count - 2]; + char3 = bytearr[count - 1]; + if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { + // malformed input around byte + return null; + } + chararr[chararrCount++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); + break; + default: + /* 10xx xxxx, 1111 xxxx */ + // malformed input around byte + return null; + } + } + // The number of chars produced may be less than utflen + char[] value = Arrays.copyOf(chararr, chararrCount); + return new String(value); + } + + private byte[] asByteArray() { + final int length = getLength(); + byte[] result = new byte[length]; + for (int index = 0; index < length; index++) { + result[index] = getByteAt(index); + } + return result; + } + + private int getLength() { + return unsafe.getShort(metaspaceSymbol + runtime().getConfig().symbolLengthOffset); + } + + private byte getByteAt(int index) { + return unsafe.getByte(metaspaceSymbol + runtime().getConfig().symbolBodyOffset + index); + } +} diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotTargetDescription.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotTargetDescription.java Tue Jul 21 15:16:01 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2014, 2015, 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 jdk.internal.jvmci.hotspot; - -import jdk.internal.jvmci.code.*; - -public class HotSpotTargetDescription extends TargetDescription { - - public HotSpotTargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects) { - super(arch, isMP, stackAlignment, implicitNullCheckLimit, inlineObjects); - } - - @Override - public ReferenceMap createReferenceMap(boolean hasRegisters, int stackSlotCount, int totalFrameSize) { - return new HotSpotReferenceMap(this, totalFrameSize); - } -} diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfig.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfig.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfig.java Tue Jul 21 16:15:22 2015 +0200 @@ -808,6 +808,8 @@ @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset; @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset; + @HotSpotVMField(name = "Handle::_handle", type = "oop*", get = HotSpotVMField.Type.OFFSET) @Stable public int handleHandleOffset; + @HotSpotVMField(name = "Klass::_prototype_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int prototypeMarkWordOffset; @HotSpotVMField(name = "Klass::_subklass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int subklassOffset; @HotSpotVMField(name = "Klass::_next_sibling", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int nextSiblingOffset; @@ -1090,11 +1092,29 @@ @HotSpotVMType(name = "ConstantPool", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolSize; @HotSpotVMField(name = "ConstantPool::_tags", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolTagsOffset; + @HotSpotVMField(name = "ConstantPool::_cache", type = "ConstantPoolCache*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheOffset; @HotSpotVMField(name = "ConstantPool::_pool_holder", type = "InstanceKlass*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolHolderOffset; @HotSpotVMField(name = "ConstantPool::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolLengthOffset; + @HotSpotVMField(name = "ConstantPool::_resolved_references", type = "jobject", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolResolvedReferencesOffset; + @HotSpotVMField(name = "ConstantPool::_reference_map", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolReferenceMapOffset; @HotSpotVMConstant(name = "ConstantPool::CPCACHE_INDEX_TAG") @Stable public int constantPoolCpCacheIndexTag; + @HotSpotVMType(name = "ConstantPoolCache", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolCacheSize; + @HotSpotVMField(name = "ConstantPoolCache::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheLengthOffset; + + @HotSpotVMType(name = "ConstantPoolCacheEntry", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolCacheEntrySize; + @HotSpotVMField(name = "ConstantPoolCacheEntry::_indices", type = "intx", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryIndicesOffset; + @HotSpotVMField(name = "ConstantPoolCacheEntry::_f1", type = "volatile Metadata*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryF1Offset; + @HotSpotVMField(name = "ConstantPoolCacheEntry::_f2", type = "intx", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryF2Offset; + @HotSpotVMField(name = "ConstantPoolCacheEntry::_flags", type = "intx", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryFlagsOffset; + + @HotSpotVMConstant(name = "ConstantPoolCacheEntry::has_appendix_shift") @Stable public int constantPoolCacheEntryHasAppendixShift; + + @HotSpotVMConstant(name = "ConstantPoolCacheEntry::cp_index_mask") @Stable public int constantPoolCacheEntryCpIndexMask; + + @HotSpotVMConstant(name = "ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset") @Stable public int constantPoolCacheEntryIndyResolvedReferencesAppendixOffset; + @HotSpotVMConstant(name = "JVM_CONSTANT_Utf8") @Stable public int jvmConstantUtf8; @HotSpotVMConstant(name = "JVM_CONSTANT_Integer") @Stable public int jvmConstantInteger; @HotSpotVMConstant(name = "JVM_CONSTANT_Long") @Stable public int jvmConstantLong; diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVmSymbols.java --- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVmSymbols.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVmSymbols.java Tue Jul 21 16:15:22 2015 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, 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 @@ -24,6 +24,8 @@ import static jdk.internal.jvmci.common.UnsafeAccess.*; import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; + +import jdk.internal.jvmci.common.*; import sun.misc.*; /** @@ -43,6 +45,17 @@ HotSpotVMConfig config = runtime.getConfig(); assert config.vmSymbolsFirstSID <= index && index < config.vmSymbolsSIDLimit : "index " + index + " is out of bounds"; assert config.symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken"; - return runtime.getCompilerToVM().getSymbol(unsafe.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize)); + final long metaspaceSymbol = unsafe.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize); + if (HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue()) { + HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol); + String s = symbol.asString(); + // It shouldn't but just in case something went wrong... + if (s == null) { + throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool"); + } + return s; + } else { + return runtime.getCompilerToVM().getSymbol(metaspaceSymbol); + } } } diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LIRKind.java --- a/jvmci/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LIRKind.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/LIRKind.java Tue Jul 21 16:15:22 2015 +0200 @@ -27,7 +27,7 @@ /** * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the * low level representation of the value, and a {@link #referenceMask} that describes the location - * of object references in the value. + * of object references in the value, and optionally a {@link #derivedReferenceBase}. * *

Constructing {@link LIRKind} instances

* @@ -37,49 +37,54 @@ * *

* If the result value is created from one or more input values, the {@link LIRKind} should be - * created with {@link LIRKind#derive}(inputs). If the result has a different {@link PlatformKind} - * than the inputs, {@link LIRKind#derive}(inputs).{@link #changeType}(resultKind) should be used. + * created with {@link LIRKind#combine}(inputs). If the result has a different {@link PlatformKind} + * than the inputs, {@link LIRKind#combine}(inputs).{@link #changeType}(resultKind) should be used. *

* If the result is an exact copy of one of the inputs, {@link Value#getLIRKind()} can be used. Note * that this is only correct for move-like operations, like conditional move or compare-and-swap. - * For convert operations, {@link LIRKind#derive} should be used. + * For convert operations, {@link LIRKind#combine} should be used. *

* If it is known that the result will be a reference (e.g. pointer arithmetic where the end result * is a valid oop), {@link LIRKind#reference} should be used. *

* If it is known that the result will neither be a reference nor be derived from a reference, * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very - * likely wrong, and {@link LIRKind#derive} should be used instead. + * likely wrong, and {@link LIRKind#combine} should be used instead. *

- * If it is known that the result is derived from a reference, {@link LIRKind#derivedReference} can - * be used. In most cases, {@link LIRKind#derive} should be used instead, since it is able to detect - * this automatically. + * If it is known that the result is derived from a reference in a way that the garbage collector + * can not track, {@link LIRKind#unknownReference} can be used. In most cases, + * {@link LIRKind#combine} should be used instead, since it is able to detect this automatically. */ public final class LIRKind { /** - * The non-type. This uses {@link #derivedReference}, so it can never be part of an oop map. + * The non-type. This uses {@link #unknownReference}, so it can never be part of an oop map. */ - public static final LIRKind Illegal = derivedReference(Kind.Illegal); + public static final LIRKind Illegal = unknownReference(Kind.Illegal); private final PlatformKind platformKind; private final int referenceMask; - private static final int DERIVED_REFERENCE = -1; + private AllocatableValue derivedReferenceBase; - private LIRKind(PlatformKind platformKind, int referenceMask) { + private static final int UNKNOWN_REFERENCE = -1; + + private LIRKind(PlatformKind platformKind, int referenceMask, AllocatableValue derivedReferenceBase) { this.platformKind = platformKind; this.referenceMask = referenceMask; + this.derivedReferenceBase = derivedReferenceBase; + + assert derivedReferenceBase == null || !derivedReferenceBase.getLIRKind().isDerivedReference() : "derived reference can't have another derived reference as base"; } /** * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should * be only used when it's guaranteed that the value is not even indirectly derived from a - * reference. Otherwise, {@link #derive(Value...)} should be used instead. + * reference. Otherwise, {@link #combine(Value...)} should be used instead. */ public static LIRKind value(PlatformKind platformKind) { assert platformKind != Kind.Object : "Object should always be used as reference type"; - return new LIRKind(platformKind, 0); + return new LIRKind(platformKind, 0, null); } /** @@ -87,37 +92,62 @@ * reference. */ public static LIRKind reference(PlatformKind platformKind) { + return derivedReference(platformKind, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a derived reference. + */ + public static LIRKind derivedReference(PlatformKind platformKind, AllocatableValue base) { int length = platformKind.getVectorLength(); assert 0 < length && length < 32 : "vector of " + length + " references not supported"; - return new LIRKind(platformKind, (1 << length) - 1); + return new LIRKind(platformKind, (1 << length) - 1, base); } /** * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived - * from a reference. Values of this {@link LIRKind} can not be live at safepoints. In most - * cases, this should not be called directly. {@link #derive} should be used instead to - * automatically propagate this information. + * from a reference in a non-linear way. Values of this {@link LIRKind} can not be live at + * safepoints. In most cases, this should not be called directly. {@link #combine} should be + * used instead to automatically propagate this information. */ - public static LIRKind derivedReference(PlatformKind platformKind) { - return new LIRKind(platformKind, DERIVED_REFERENCE); + public static LIRKind unknownReference(PlatformKind platformKind) { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Create a derived reference. + * + * @param base An {@link AllocatableValue} containing the base pointer of the derived reference. + */ + public LIRKind makeDerivedReference(AllocatableValue base) { + assert !isUnknownReference() && derivedReferenceBase == null; + if (Value.ILLEGAL.equals(base)) { + return makeUnknownReference(); + } else { + if (isValue()) { + return derivedReference(platformKind, base); + } else { + return new LIRKind(platformKind, referenceMask, base); + } + } } /** * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the - * inputs. If all inputs are values, the result is a value. Otherwise, the result is a derived + * inputs. If all inputs are values, the result is a value. Otherwise, the result is an unknown * reference. * * This method should be used to construct the result {@link LIRKind} of any operation that * modifies values (e.g. arithmetics). */ - public static LIRKind derive(Value... inputs) { + public static LIRKind combine(Value... inputs) { assert inputs.length > 0; for (Value input : inputs) { LIRKind kind = input.getLIRKind(); - if (kind.isDerivedReference()) { + if (kind.isUnknownReference()) { return kind; } else if (!kind.isValue()) { - return kind.makeDerivedReference(); + return kind.makeUnknownReference(); } } @@ -128,10 +158,10 @@ /** * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the * inputs. If all inputs are values (references), the result is a value (reference). Otherwise, - * the result is a derived reference. + * the result is an unknown reference. * - * This method should be used to construct the result {@link LIRKind} of merge operation that do - * not modify values (e.g. phis). + * This method should be used to construct the result {@link LIRKind} of merge operation that + * does not modify values (e.g. phis). */ public static LIRKind merge(Value... inputs) { assert inputs.length > 0; @@ -143,6 +173,42 @@ } /** + * Helper method to construct derived reference kinds. Returns the base value of a reference or + * derived reference. For values it returns {@code null}, and for unknown references it returns + * {@link Value#ILLEGAL}. + */ + public static AllocatableValue derivedBaseFromValue(AllocatableValue value) { + LIRKind kind = value.getLIRKind(); + if (kind.isValue()) { + return null; + } else if (kind.isDerivedReference()) { + return kind.getDerivedReferenceBase(); + } else if (kind.isUnknownReference()) { + return Value.ILLEGAL; + } else { + // kind is a reference + return value; + } + } + + /** + * Helper method to construct derived reference kinds. If one of {@code base1} or {@code base2} + * are set, it creates a derived reference using it as the base. If both are set, the result is + * an unknown reference. + */ + public static LIRKind combineDerived(LIRKind kind, AllocatableValue base1, AllocatableValue base2) { + if (base1 == null && base2 == null) { + return kind; + } else if (base1 == null) { + return kind.makeDerivedReference(base2); + } else if (base2 == null) { + return kind.makeDerivedReference(base1); + } else { + return kind.makeUnknownReference(); + } + } + + /** * @see #merge(Value...) */ public static LIRKind merge(Iterable kinds) { @@ -150,14 +216,13 @@ for (LIRKind kind : kinds) { - assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind); - - if (kind.isDerivedReference()) { + if (kind.isUnknownReference()) { /** - * Kind is a derived reference therefore the result can only be also a derived + * Kind is an unknown reference, therefore the result can only be also an unknown * reference. */ - return kind; + mergeKind = kind; + break; } if (mergeKind == null) { mergeKind = kind; @@ -168,29 +233,38 @@ /* Kind is a value. */ if (mergeKind.referenceMask != 0) { /* - * Inputs consists of values and references. Make the result a derived + * Inputs consists of values and references. Make the result an unknown * reference. */ - return mergeKind.makeDerivedReference(); + mergeKind = mergeKind.makeUnknownReference(); + break; } /* Check that other inputs are also values. */ } else { /* Kind is a reference. */ if (mergeKind.referenceMask != kind.referenceMask) { /* - * Reference maps do not match so the result can only be a derived reference. + * Reference maps do not match so the result can only be an unknown reference. */ - return mergeKind.makeDerivedReference(); + mergeKind = mergeKind.makeUnknownReference(); + break; } } } - assert mergeKind != null; + assert mergeKind != null && verifyMerge(mergeKind, kinds); // all inputs are values or references, just return one of them return mergeKind; } + private static boolean verifyMerge(LIRKind mergeKind, Iterable kinds) { + for (LIRKind kind : kinds) { + assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind); + } + return true; + } + /** * Create a new {@link LIRKind} with the same reference information and a new * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this, @@ -199,17 +273,17 @@ public LIRKind changeType(PlatformKind newPlatformKind) { if (newPlatformKind == platformKind) { return this; - } else if (isDerivedReference()) { - return derivedReference(newPlatformKind); + } else if (isUnknownReference()) { + return unknownReference(newPlatformKind); } else if (referenceMask == 0) { // value type - return new LIRKind(newPlatformKind, 0); + return LIRKind.value(newPlatformKind); } else { // reference type int newLength = Math.min(32, newPlatformKind.getVectorLength()); int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength)); - assert newReferenceMask != DERIVED_REFERENCE; - return new LIRKind(newPlatformKind, newReferenceMask); + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); } } @@ -218,11 +292,11 @@ * new kind is longer than this, the reference positions are repeated to fill the vector. */ public LIRKind repeat(PlatformKind newPlatformKind) { - if (isDerivedReference()) { - return derivedReference(newPlatformKind); + if (isUnknownReference()) { + return unknownReference(newPlatformKind); } else if (referenceMask == 0) { // value type - return new LIRKind(newPlatformKind, 0); + return LIRKind.value(newPlatformKind); } else { // reference type int oldLength = platformKind.getVectorLength(); @@ -235,16 +309,17 @@ newReferenceMask |= referenceMask << i; } - assert newReferenceMask != DERIVED_REFERENCE; - return new LIRKind(newPlatformKind, newReferenceMask); + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); } } /** - * Create a new {@link LIRKind} with the same type, but marked as containing a derivedReference. + * Create a new {@link LIRKind} with the same type, but marked as containing an + * {@link LIRKind#unknownReference}. */ - public LIRKind makeDerivedReference() { - return new LIRKind(platformKind, DERIVED_REFERENCE); + public LIRKind makeUnknownReference() { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); } /** @@ -255,15 +330,37 @@ } /** - * Check whether this value is derived from a reference. If this returns {@code true}, this - * value must not be live at safepoints. + * Check whether this value is a derived reference. */ public boolean isDerivedReference() { - return referenceMask == DERIVED_REFERENCE; + return getDerivedReferenceBase() != null; + } + + /** + * Get the base value of a derived reference. + */ + public AllocatableValue getDerivedReferenceBase() { + return derivedReferenceBase; + } + + /** + * Change the base value of a derived reference. This must be called on derived references only. + */ + public void setDerivedReferenceBase(AllocatableValue derivedReferenceBase) { + assert isDerivedReference(); + this.derivedReferenceBase = derivedReferenceBase; + } + + /** + * Check whether this value is derived from a reference in a non-linear way. If this returns + * {@code true}, this value must not be live at safepoints. + */ + public boolean isUnknownReference() { + return referenceMask == UNKNOWN_REFERENCE; } public int getReferenceCount() { - assert !isDerivedReference(); + assert !isUnknownReference(); return Integer.bitCount(referenceMask); } @@ -276,7 +373,7 @@ */ public boolean isReference(int idx) { assert 0 <= idx && idx < platformKind.getVectorLength() : "invalid index " + idx + " in " + this; - return !isDerivedReference() && (referenceMask & 1 << idx) != 0; + return !isUnknownReference() && (referenceMask & 1 << idx) != 0; } /** @@ -290,7 +387,7 @@ public String toString() { if (isValue()) { return platformKind.name(); - } else if (isDerivedReference()) { + } else if (isUnknownReference()) { return platformKind.name() + "[*]"; } else { StringBuilder ret = new StringBuilder(); @@ -340,7 +437,7 @@ * (phi-)moves from e.g. integer to short can happen. Therefore we compare stack kinds. */ if (toStackKind(src.getPlatformKind()).equals(toStackKind(dst.getPlatformKind()))) { - return !src.isDerivedReference() || dst.isDerivedReference(); + return !src.isUnknownReference() || dst.isUnknownReference(); } return false; } diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/NamedLocationIdentity.java --- a/jvmci/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/NamedLocationIdentity.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.meta/src/jdk/internal/jvmci/meta/NamedLocationIdentity.java Tue Jul 21 16:15:22 2015 +0200 @@ -29,18 +29,17 @@ /** * A {@link LocationIdentity} with a name. */ -public final class NamedLocationIdentity extends LocationIdentity implements FormatWithToString { +public class NamedLocationIdentity extends LocationIdentity implements FormatWithToString { /** * Map for asserting all {@link NamedLocationIdentity} instances have a unique name. */ static class DB { - private static final HashMap map = new HashMap<>(); + private static final HashSet map = new HashSet<>(); - static boolean checkUnique(NamedLocationIdentity identity) { - NamedLocationIdentity oldValue = map.put(identity.name, identity); - if (oldValue != null) { - throw new AssertionError("identity " + identity + " already exists"); + static boolean checkUnique(String name) { + if (!map.add(name)) { + throw new AssertionError("identity " + name + " already exists"); } return true; } @@ -49,9 +48,10 @@ private final String name; private final boolean immutable; - private NamedLocationIdentity(String name, boolean immutable) { + protected NamedLocationIdentity(String name, boolean immutable) { this.name = name; this.immutable = immutable; + assert DB.checkUnique(name); } /** @@ -82,9 +82,7 @@ * @param immutable true if the location is immutable */ private static NamedLocationIdentity create(String name, boolean immutable) { - NamedLocationIdentity id = new NamedLocationIdentity(name, immutable); - assert DB.checkUnique(id); - return id; + return new NamedLocationIdentity(name, immutable); } @Override diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.options.processor/src/jdk/internal/jvmci/options/processor/JVMCIJars.java --- a/jvmci/jdk.internal.jvmci.options.processor/src/jdk/internal/jvmci/options/processor/JVMCIJars.java Tue Jul 21 15:16:01 2015 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2015, 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 jdk.internal.jvmci.options.processor; - -import java.io.*; -import java.util.*; -import java.util.stream.*; -import java.util.zip.*; - -public class JVMCIJars implements Iterable { - private final List jars = new ArrayList<>(2); - - public JVMCIJars() { - String classPath = System.getProperty("java.class.path"); - for (String e : classPath.split(File.pathSeparator)) { - if (e.endsWith(File.separatorChar + "graal.jar") || e.endsWith(File.separatorChar + "graal-truffle.jar")) { - try { - jars.add(new ZipFile(e)); - } catch (IOException ioe) { - throw new InternalError(ioe); - } - } - } - if (jars.size() != 2) { - throw new InternalError("Could not find graal.jar or graal-truffle.jar on class path: " + classPath); - } - } - - public Iterator iterator() { - Stream entries = jars.stream().flatMap(ZipFile::stream); - return entries.iterator(); - } - - public InputStream getInputStream(String classFilePath) throws IOException { - for (ZipFile jar : jars) { - ZipEntry entry = jar.getEntry(classFilePath); - if (entry != null) { - return jar.getInputStream(entry); - } - } - return null; - } -} diff -r 9bbd878b17af -r 706aa848a8d7 jvmci/jdk.internal.jvmci.sparc/src/jdk/internal/jvmci/sparc/SPARC.java --- a/jvmci/jdk.internal.jvmci.sparc/src/jdk/internal/jvmci/sparc/SPARC.java Tue Jul 21 15:16:01 2015 +0200 +++ b/jvmci/jdk.internal.jvmci.sparc/src/jdk/internal/jvmci/sparc/SPARC.java Tue Jul 21 16:15:22 2015 +0200 @@ -286,8 +286,10 @@ public PlatformKind getLargestStorableKind(RegisterCategory category) { if (category.equals(CPU)) { return Kind.Long; + } else if (category.equals(FPUd)) { + return Kind.Double; } else if (category.equals(FPUs)) { - return Kind.Double; + return Kind.Float; } else { return Kind.Illegal; } @@ -316,6 +318,10 @@ return true; } + public static boolean isGlobalRegister(Register r) { + return isCPURegister(r) && g0.number <= r.number && r.number <= g7.number; + } + public static boolean isSingleFloatRegister(Register r) { return r.name.startsWith("f"); } diff -r 9bbd878b17af -r 706aa848a8d7 make/defs.make --- a/make/defs.make Tue Jul 21 15:16:01 2015 +0200 +++ b/make/defs.make Tue Jul 21 16:15:22 2015 +0200 @@ -376,6 +376,7 @@ CONDITIONAL_EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_SERVICES_DIR)/jdk.internal.jvmci.hotspot.events.EventProvider endif +EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotConstantPool EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotConstantReflectionProvider EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotResolvedJavaFieldImpl diff -r 9bbd878b17af -r 706aa848a8d7 mx.jvmci/mx_jvmci.py diff -r 9bbd878b17af -r 706aa848a8d7 mx.jvmci/mx_jvmci_makefile.py --- a/mx.jvmci/mx_jvmci_makefile.py Tue Jul 21 15:16:01 2015 +0200 +++ b/mx.jvmci/mx_jvmci_makefile.py Tue Jul 21 16:15:22 2015 +0200 @@ -55,8 +55,7 @@ if not opts.selectedDists: opts.selectedDists = [d.name for d in mx_jvmci.jdkDeployedDists if d.partOfHotSpot] mf = Makefile() - commandline = " ".join(["mx.sh", "makefile"] + args) - if do_build_makefile(mf, opts.selectedDists, commandline): + if do_build_makefile(mf, opts.selectedDists): contents = mf.generate() if opts.output == None: print contents @@ -128,7 +127,7 @@ -def do_build_makefile(mf, selectedDists, commandline): +def do_build_makefile(mf, selectedDists): java = mx.java() bootClassPath = java.bootclasspath() bootClassPath = bootClassPath.replace(os.path.realpath(java.jdk), "$(ABS_BOOTDIR)") diff -r 9bbd878b17af -r 706aa848a8d7 mx.jvmci/suite.py --- a/mx.jvmci/suite.py Tue Jul 21 15:16:01 2015 +0200 +++ b/mx.jvmci/suite.py Tue Jul 21 16:15:22 2015 +0200 @@ -9,9 +9,9 @@ # ------------- Libraries ------------- "HCFDIS" : { - "path" : "lib/hcfdis-2.jar", - "urls" : ["http://lafo.ssw.uni-linz.ac.at/hcfdis-2.jar"], - "sha1" : "bc8b2253436485e9dbaf81771c259ccfa1a24c80", + "path" : "lib/hcfdis-3.jar", + "urls" : ["http://lafo.ssw.uni-linz.ac.at/hcfdis-3.jar"], + "sha1" : "a71247c6ddb90aad4abf7c77e501acc60674ef57", }, "C1VISUALIZER_DIST" : { diff -r 9bbd878b17af -r 706aa848a8d7 src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp --- a/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp Tue Jul 21 15:16:01 2015 +0200 +++ b/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp Tue Jul 21 16:15:22 2015 +0200 @@ -76,10 +76,11 @@ _instructions->relocate(pc + NativeMovConstReg::add_offset, internal_word_Relocation::spec((address) dest)); } TRACE_jvmci_3("relocating at %p (+%d) with destination at %d", pc, pc_offset, data_offset); - } else { + }else { + int const_size = align_size_up(_constants->end()-_constants->start(), CodeEntryAlignment); NativeMovRegMem* load = nativeMovRegMem_at(pc); - // The base pointer is set 4k off (see SPARCLoadConstantTableBaseOp) - load->set_offset(data_offset - (1<<12)); + // This offset must match with SPARCLoadConstantTableBaseOp.emitCode + load->set_offset(- (const_size - data_offset + Assembler::min_simm13())); TRACE_jvmci_3("relocating ld at %p (+%d) with destination at %d", pc, pc_offset, data_offset); } } diff -r 9bbd878b17af -r 706aa848a8d7 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Tue Jul 21 15:16:01 2015 +0200 +++ b/src/share/vm/code/nmethod.cpp Tue Jul 21 16:15:22 2015 +0200 @@ -43,6 +43,21 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" +#ifdef TARGET_ARCH_x86 +# include "nativeInst_x86.hpp" +#endif +#ifdef TARGET_ARCH_sparc +# include "nativeInst_sparc.hpp" +#endif +#ifdef TARGET_ARCH_zero +# include "nativeInst_zero.hpp" +#endif +#ifdef TARGET_ARCH_arm +# include "nativeInst_arm.hpp" +#endif +#ifdef TARGET_ARCH_ppc +# include "nativeInst_ppc.hpp" +#endif #ifdef SHARK #include "shark/sharkCompiler.hpp" #endif @@ -2610,6 +2625,14 @@ memcpy(scopes_data_begin(), buffer, size); } +// When using JVMCI the address might be off by the size of a call instruction. +bool nmethod::is_deopt_entry(address pc) { + return pc == deopt_handler_begin() +#ifdef JVMCI + || pc == (deopt_handler_begin() + NativeCall::instruction_size) +#endif // JVMCI + ; +} #ifdef ASSERT static PcDesc* linear_search(nmethod* nm, int pc_offset, bool approximate) { diff -r 9bbd878b17af -r 706aa848a8d7 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Tue Jul 21 15:16:01 2015 +0200 +++ b/src/share/vm/code/nmethod.hpp Tue Jul 21 16:15:22 2015 +0200 @@ -694,24 +694,7 @@ // Deopt // Return true is the PC is one would expect if the frame is being deopted. bool is_deopt_pc (address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } - - // (thomaswue) When using jvmci, the address might be off by 5 (because this is the size of the call instruction. - // (thomaswue) TODO: Replace this by a more general mechanism. - // (sanzinger) SPARC has another offset, looked for some variable existing in HotSpot which describes this offset, but i have not - // found anything. - bool is_deopt_entry (address pc) { - return pc == deopt_handler_begin() -#ifdef JVMCI - || pc == deopt_handler_begin() + -#ifdef TARGET_ARCH_sparc - 8 -#endif // sparc -#ifdef TARGET_ARCH_x86 - 5 -#endif // x86 -#endif // JVMCI - ; - } + bool is_deopt_entry(address pc); bool is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin(); } // Accessor/mutator for the original pc of a frame before a frame was deopted. address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } diff -r 9bbd878b17af -r 706aa848a8d7 src/share/vm/jvmci/jvmciCompilerToVM.cpp --- a/src/share/vm/jvmci/jvmciCompilerToVM.cpp Tue Jul 21 15:16:01 2015 +0200 +++ b/src/share/vm/jvmci/jvmciCompilerToVM.cpp Tue Jul 21 16:15:22 2015 +0200 @@ -1072,16 +1072,16 @@ {CC"shouldInlineMethod", CC"("METASPACE_METHOD")Z", FN_PTR(shouldInlineMethod)}, {CC"lookupType", CC"("STRING CLASS"Z)"METASPACE_KLASS, FN_PTR(lookupType)}, {CC"resolveConstantInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolveConstantInPool)}, - {CC"resolvePossiblyCachedConstantInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, - {CC"lookupNameRefInPool", CC"("METASPACE_CONSTANT_POOL"I)"STRING, FN_PTR(lookupNameRefInPool)}, + {CC"resolvePossiblyCachedConstantInPool0", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, + {CC"lookupNameRefInPool0", CC"("METASPACE_CONSTANT_POOL"I)"STRING, FN_PTR(lookupNameRefInPool)}, {CC"lookupNameAndTypeRefIndexInPool", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, - {CC"lookupSignatureRefInPool", CC"("METASPACE_CONSTANT_POOL"I)"STRING, FN_PTR(lookupSignatureRefInPool)}, - {CC"lookupKlassRefIndexInPool", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)}, + {CC"lookupSignatureRefInPool0", CC"("METASPACE_CONSTANT_POOL"I)"STRING, FN_PTR(lookupSignatureRefInPool)}, + {CC"lookupKlassRefIndexInPool0", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)}, {CC"constantPoolKlassAt", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS, FN_PTR(constantPoolKlassAt)}, {CC"lookupKlassInPool", CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS, FN_PTR(lookupKlassInPool)}, - {CC"lookupAppendixInPool", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)}, + {CC"lookupAppendixInPool0", CC"("METASPACE_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)}, {CC"lookupMethodInPool", CC"("METASPACE_CONSTANT_POOL"IB)"METASPACE_METHOD, FN_PTR(lookupMethodInPool)}, - {CC"constantPoolRemapInstructionOperandFromCache", CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, + {CC"constantPoolRemapInstructionOperandFromCache0",CC"("METASPACE_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, {CC"resolveField", CC"("METASPACE_CONSTANT_POOL"IB[J)"METASPACE_KLASS, FN_PTR(resolveField)}, {CC"resolveInvokeDynamic", CC"("METASPACE_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeDynamic)}, {CC"resolveInvokeHandle", CC"("METASPACE_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeHandle)}, @@ -1109,7 +1109,7 @@ {CC"allocateCompileId", CC"("METASPACE_METHOD"I)I", FN_PTR(allocateCompileId)}, {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)}, {CC"hasCompiledCodeForOSR", CC"("METASPACE_METHOD"II)Z", FN_PTR(hasCompiledCodeForOSR)}, - {CC"getSymbol", CC"(J)"STRING, FN_PTR(getSymbol)}, + {CC"getSymbol0", CC"(J)"STRING, FN_PTR(getSymbol)}, {CC"getTimeStamp", CC"()J", FN_PTR(getTimeStamp)}, {CC"getNextStackFrame", CC"("HS_STACK_FRAME_REF "[JI)"HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)}, {CC"materializeVirtualObjects", CC"("HS_STACK_FRAME_REF"Z)V", FN_PTR(materializeVirtualObjects)}, diff -r 9bbd878b17af -r 706aa848a8d7 src/share/vm/jvmci/jvmciJavaAccess.hpp --- a/src/share/vm/jvmci/jvmciJavaAccess.hpp Tue Jul 21 15:16:01 2015 +0200 +++ b/src/share/vm/jvmci/jvmciJavaAccess.hpp Tue Jul 21 16:15:22 2015 +0200 @@ -155,7 +155,7 @@ oop_field(DebugInfo, bytecodePosition, "Ljdk/internal/jvmci/code/BytecodePosition;") \ oop_field(DebugInfo, referenceMap, "Ljdk/internal/jvmci/code/ReferenceMap;") \ oop_field(DebugInfo, calleeSaveInfo, "Ljdk/internal/jvmci/code/RegisterSaveLayout;") \ - objArrayOop_field(DebugInfo, virtualObjectMapping, "[Ljdk/internal/jvmci/meta/Value;") \ + objArrayOop_field(DebugInfo, virtualObjectMapping, "[Ljdk/internal/jvmci/code/VirtualObject;") \ end_class \ start_class(HotSpotReferenceMap) \ objArrayOop_field(HotSpotReferenceMap, objects, "[Ljdk/internal/jvmci/code/Location;") \ diff -r 9bbd878b17af -r 706aa848a8d7 src/share/vm/runtime/handles.hpp --- a/src/share/vm/runtime/handles.hpp Tue Jul 21 15:16:01 2015 +0200 +++ b/src/share/vm/runtime/handles.hpp Tue Jul 21 16:15:22 2015 +0200 @@ -62,6 +62,7 @@ // used operators for ease of use. class Handle VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; private: oop* _handle; diff -r 9bbd878b17af -r 706aa848a8d7 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Tue Jul 21 15:16:01 2015 +0200 +++ b/src/share/vm/runtime/vmStructs.cpp Tue Jul 21 16:15:22 2015 +0200 @@ -1010,6 +1010,9 @@ /*********************************/ \ /* JNIHandles and JNIHandleBlock */ \ /*********************************/ \ + \ + nonstatic_field(Handle, _handle, oop*) \ + \ static_field(JNIHandles, _global_handles, JNIHandleBlock*) \ static_field(JNIHandles, _weak_global_handles, JNIHandleBlock*) \ static_field(JNIHandles, _deleted_handle, oop) \ @@ -1742,6 +1745,8 @@ /* JNIHandles and JNIHandleBlock */ \ /*********************************/ \ \ + declare_toplevel_type(Handle) \ + \ declare_toplevel_type(JNIHandles) \ declare_toplevel_type(JNIHandleBlock) \ declare_toplevel_type(jobject) \ @@ -2538,9 +2543,22 @@ declare_constant(ConstantPoolCacheEntry::is_final_shift) \ declare_constant(ConstantPoolCacheEntry::is_forced_virtual_shift) \ declare_constant(ConstantPoolCacheEntry::is_vfinal_shift) \ + declare_constant(ConstantPoolCacheEntry::has_appendix_shift) \ + declare_constant(ConstantPoolCacheEntry::has_method_type_shift) \ declare_constant(ConstantPoolCacheEntry::is_field_entry_shift) \ declare_constant(ConstantPoolCacheEntry::tos_state_shift) \ \ + declare_constant(ConstantPoolCacheEntry::cp_index_bits) \ + declare_constant(ConstantPoolCacheEntry::cp_index_mask) \ + declare_constant(ConstantPoolCacheEntry::bytecode_1_shift) \ + declare_constant(ConstantPoolCacheEntry::bytecode_1_mask) \ + declare_constant(ConstantPoolCacheEntry::bytecode_2_shift) \ + declare_constant(ConstantPoolCacheEntry::bytecode_2_mask) \ + \ + declare_constant(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset) \ + declare_constant(ConstantPoolCacheEntry::_indy_resolved_references_method_type_offset) \ + declare_constant(ConstantPoolCacheEntry::_indy_resolved_references_entries) \ + \ /***************************************/ \ /* java_lang_Thread::ThreadStatus enum */ \ /***************************************/ \