# HG changeset patch # User Gilles Duboscq # Date 1389263396 -3600 # Node ID d8143c431d630d41be0d1c85abbfaab7c4a7c255 # Parent 6135e289d260ed374d6fd58a5abdca4e93b1e98a Add DynamicNewInstanceNode and use it to intrinsify Unsafe.allocateInstance diff -r 6135e289d260 -r d8143c431d63 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Tue Dec 31 17:23:54 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Thu Jan 09 11:29:56 2014 +0100 @@ -1244,6 +1244,7 @@ @Stable public long newArrayAddress; @Stable public long newMultiArrayAddress; @Stable public long dynamicNewArrayAddress; + @Stable public long dynamicNewInstanceAddress; @Stable public long registerFinalizerAddress; @Stable public long threadIsInterruptedAddress; @Stable public long vmMessageAddress; diff -r 6135e289d260 -r d8143c431d63 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Dec 31 17:23:54 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java Thu Jan 09 11:29:56 2014 +0100 @@ -100,6 +100,7 @@ linkForeignCall(providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, NOT_LEAF, NOT_REEXECUTABLE, ANY_LOCATION); linkForeignCall(providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); linkForeignCall(providers, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); + linkForeignCall(providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, INIT_LOCATION); linkForeignCall(providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS); linkForeignCall(providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS); diff -r 6135e289d260 -r d8143c431d63 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Tue Dec 31 17:23:54 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java Thu Jan 09 11:29:56 2014 +0100 @@ -423,6 +423,10 @@ if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { newObjectSnippets.lower((NewInstanceNode) n, registers, tool); } + } else if (n instanceof DynamicNewInstanceNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool); + } } else if (n instanceof NewArrayNode) { if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { newObjectSnippets.lower((NewArrayNode) n, registers, tool); diff -r 6135e289d260 -r d8143c431d63 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Tue Dec 31 17:23:54 2013 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Thu Jan 09 11:29:56 2014 +0100 @@ -130,7 +130,7 @@ @Snippet public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, - @ConstantParameter String typeContext) { + @ConstantParameter boolean constantSize, @ConstantParameter String typeContext) { Object result; Word thread = registerAsWord(threadRegister); Word top = readTlabTop(thread); @@ -139,7 +139,7 @@ if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) { writeTlabTop(thread, newTop); emitPrefetchAllocate(newTop, false); - result = formatObject(hub, size, top, prototypeMarkWord, fillContents); + result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize); } else { new_stub.inc(); result = NewInstanceStubCall.call(hub); @@ -148,6 +148,25 @@ return piCast(verifyOop(result), StampFactory.forNodeIntrinsic()); } + @Snippet + public static Object allocateInstanceDynamic(Class type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter String typeContext) { + Word hub = loadWordFromObject(type, klassOffset()); + if (!hub.equal(Word.zero())) { + int layoutHelper = readLayoutHelper(hub); + /* + * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number, the + * instance size. This size is already passed through align_object_size and scaled to + * bytes. The low order bit is set if instances of this class cannot be allocated using + * the fastpath. + */ + if ((layoutHelper & 1) == 0) { + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION); + return allocateInstance(layoutHelper, hub, prototypeMarkWord, fillContents, threadRegister, false, typeContext); + } + } + return dynamicNewInstanceStub(type); + } + /** * Maximum array length for which fast path allocation is used. */ @@ -186,10 +205,18 @@ } public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class); + public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class); @NodeIntrinsic(ForeignCallNode.class) public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class elementType, int length); + public static Object dynamicNewInstanceStub(Class elementType) { + return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType); + } + + @NodeIntrinsic(ForeignCallNode.class) + public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class elementType); + @Snippet public static Object allocateArrayDynamic(Class elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) { Word hub = loadWordFromObject(elementType, arrayKlassOffset()); @@ -256,21 +283,18 @@ /** * Formats some allocated memory with an object header zeroes out the rest. */ - private static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { + private static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize) { Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord; initializeObjectHeader(memory, prototypeMarkWord, hub); if (fillContents) { - if (size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { + if (constantSize && size <= MAX_UNROLLED_OBJECT_ZEROING_SIZE) { new_seqInit.inc(); explodeLoop(); - for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) { - memory.initializeWord(offset, Word.zero(), INIT_LOCATION); - } } else { new_loopInit.inc(); - for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) { - memory.initializeWord(offset, Word.zero(), INIT_LOCATION); - } + } + for (int offset = instanceHeaderSize(); offset < size; offset += wordSize()) { + memory.initializeWord(offset, Word.zero(), INIT_LOCATION); } } return memory.toObject(); @@ -299,6 +323,7 @@ private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance"); private final SnippetInfo allocateArray = snippet(NewObjectSnippets.class, "allocateArray"); private final SnippetInfo allocateArrayDynamic = snippet(NewObjectSnippets.class, "allocateArrayDynamic"); + private final SnippetInfo allocateInstanceDynamic = snippet(NewObjectSnippets.class, "allocateInstanceDynamic"); private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray"); public Templates(Providers providers, TargetDescription target) { @@ -321,6 +346,7 @@ args.add("prototypeMarkWord", type.prototypeMarkWord()); args.addConst("fillContents", newInstanceNode.fillContents()); args.addConst("threadRegister", registers.getThreadRegister()); + args.addConst("constantSize", true); args.addConst("typeContext", ProfileAllocations.getValue() ? toJavaName(type, false) : ""); SnippetTemplate template = template(args); @@ -356,6 +382,16 @@ template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); } + public void lower(DynamicNewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) { + Arguments args = new Arguments(allocateInstanceDynamic, newInstanceNode.graph().getGuardsStage(), tool.getLoweringStage()); + args.add("type", newInstanceNode.getInstanceType()); + args.addConst("fillContents", newInstanceNode.fillContents()); + args.addConst("threadRegister", registers.getThreadRegister()); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args); + } + public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) { Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage(), tool.getLoweringStage()); args.add("elementType", newArrayNode.getElementType()); diff -r 6135e289d260 -r d8143c431d63 graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAllocateInstance01.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAllocateInstance01.java Thu Jan 09 11:29:56 2014 +0100 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.jtt.jdk; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import sun.misc.*; + +import com.oracle.graal.jtt.*; + +/* + */ +public class UnsafeAllocateInstance01 extends JTTTest { + + private static abstract class AbstractClass { + + } + + int field01 = 42; + + public static int testInstance() throws SecurityException, InstantiationException { + final Unsafe unsafe = getUnsafe(); + UnsafeAllocateInstance01 newObject = (UnsafeAllocateInstance01) unsafe.allocateInstance(UnsafeAllocateInstance01.class); + return newObject.field01; + } + + public static void testArray() throws SecurityException, InstantiationException { + final Unsafe unsafe = getUnsafe(); + unsafe.allocateInstance(UnsafeAllocateInstance01[].class); + } + + public static void testAbstract() throws SecurityException, InstantiationException { + final Unsafe unsafe = getUnsafe(); + unsafe.allocateInstance(AbstractClass.class); + } + + public static void testInterface() throws SecurityException, InstantiationException { + final Unsafe unsafe = getUnsafe(); + unsafe.allocateInstance(List.class); + } + + public static void testClass() throws SecurityException, InstantiationException { + final Unsafe unsafe = getUnsafe(); + unsafe.allocateInstance(Class.class); + } + + public static void testVoid() throws SecurityException, InstantiationException { + final Unsafe unsafe = getUnsafe(); + unsafe.allocateInstance(void.class); + } + + public static void testInt() throws SecurityException, InstantiationException { + final Unsafe unsafe = getUnsafe(); + unsafe.allocateInstance(int.class); + } + + static Unsafe getUnsafe() { + try { + final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + return (Unsafe) unsafeField.get(null); + } catch (Exception e) { + throw new Error(e); + } + } + + @Test + public void run0() throws Throwable { + runTest("testInstance"); + } + + @Test + public void run1() throws Throwable { + runTest("testArray"); + } + + @Test + public void run2() throws Throwable { + runTest("testAbstract"); + } + + @Test + public void run3() throws Throwable { + runTest("testInterface"); + } + + @Test + public void run4() throws Throwable { + runTest("testClass"); + } + + @Test + public void run5() throws Throwable { + runTest("testVoid"); + } + + @Test + public void run6() throws Throwable { + runTest("testInt"); + } +} diff -r 6135e289d260 -r d8143c431d63 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java Thu Jan 09 11:29:56 2014 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.java; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.spi.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.type.*; + +public class DynamicNewInstanceNode extends AbstractNewObjectNode { + + @Input private ValueNode clazz; + + public DynamicNewInstanceNode(ValueNode clazz, boolean fillContents) { + super(StampFactory.objectNonNull(), fillContents); + this.clazz = clazz; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + if (clazz.isConstant()) { + Constant clazzConstant = clazz.asConstant(); + if (clazzConstant.getKind() == Kind.Object && clazzConstant.asObject() instanceof Class) { + Class staticClass = (Class) clazzConstant.asObject(); + ResolvedJavaType type = tool.getMetaAccess().lookupJavaType(staticClass); + return new NewInstanceNode(type, fillContents()); + } + } + return super.canonical(tool); + } + + public ValueNode getInstanceType() { + return clazz; + } + + @NodeIntrinsic + public static native Object allocateInstance(Class clazz, @ConstantNodeParameter boolean fillContents); +} diff -r 6135e289d260 -r d8143c431d63 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java Tue Dec 31 17:23:54 2013 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java Thu Jan 09 11:29:56 2014 +0100 @@ -24,6 +24,10 @@ import static com.oracle.graal.api.code.MemoryBarriers.*; +import java.lang.reflect.*; + +import sun.misc.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.api.replacements.*; import com.oracle.graal.nodes.extended.*; @@ -381,4 +385,18 @@ public static double getDouble(@SuppressWarnings("unused") final Object thisObj, long address) { return DirectReadNode.read(address, Kind.Double); } + + @MethodSubstitution(isStatic = false) + public static Object allocateInstance(final Unsafe thisObj, Class clazz) throws InstantiationException { + if (clazz.isPrimitive()) { + throw new InstantiationException(clazz.getName()); + } + if (clazz.isArray() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { + throw new InstantiationException(clazz.getName()); + } + if (clazz == Class.class) { + thisObj.throwException(new IllegalAccessException(clazz.getName())); + } + return DynamicNewInstanceNode.allocateInstance(clazz, true); + } } diff -r 6135e289d260 -r d8143c431d63 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Tue Dec 31 17:23:54 2013 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Thu Jan 09 11:29:56 2014 +0100 @@ -532,6 +532,7 @@ set_address("newArrayAddress", GraalRuntime::new_array); set_address("newMultiArrayAddress", GraalRuntime::new_multi_array); set_address("dynamicNewArrayAddress", GraalRuntime::dynamic_new_array); + set_address("dynamicNewInstanceAddress", GraalRuntime::dynamic_new_instance); set_address("threadIsInterruptedAddress", GraalRuntime::thread_is_interrupted); set_address("vmMessageAddress", GraalRuntime::vm_message); set_address("identityHashCodeAddress", GraalRuntime::identity_hash_code); diff -r 6135e289d260 -r d8143c431d63 src/share/vm/graal/graalRuntime.cpp --- a/src/share/vm/graal/graalRuntime.cpp Tue Dec 31 17:23:54 2013 +0100 +++ b/src/share/vm/graal/graalRuntime.cpp Thu Jan 09 11:29:56 2014 +0100 @@ -136,6 +136,24 @@ thread->set_vm_result(obj); JRT_END +JRT_ENTRY(void, GraalRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror)) + instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(type_mirror)); + + if (klass == NULL) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_InstantiationException()); + } + + // Create new instance (the receiver) + klass->check_valid_for_instantiation(false, CHECK); + + // Make sure klass gets initialized + klass->initialize(CHECK); + + oop obj = klass->allocate_instance(CHECK); + thread->set_vm_result(obj); +JRT_END + extern void vm_exit(int code); // Enter this method from compiled code handler below. This is where we transition diff -r 6135e289d260 -r d8143c431d63 src/share/vm/graal/graalRuntime.hpp --- a/src/share/vm/graal/graalRuntime.hpp Tue Dec 31 17:23:54 2013 +0100 +++ b/src/share/vm/graal/graalRuntime.hpp Thu Jan 09 11:29:56 2014 +0100 @@ -34,6 +34,7 @@ static void new_array(JavaThread* thread, Klass* klass, jint length); static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); static void dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length); + static void dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror); static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupted); static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3); static jint identity_hash_code(JavaThread* thread, oopDesc* obj);