changeset 13578:d8143c431d63

Add DynamicNewInstanceNode and use it to intrinsify Unsafe.allocateInstance
author Gilles Duboscq <duboscq@ssw.jku.at>
date Thu, 09 Jan 2014 11:29:56 +0100
parents 6135e289d260
children be2b096a5f69
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotLoweringProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/jdk/UnsafeAllocateInstance01.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java src/share/vm/graal/graalCompilerToVM.cpp src/share/vm/graal/graalRuntime.cpp src/share/vm/graal/graalRuntime.hpp
diffstat 10 files changed, 273 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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);
--- 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);
--- 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());
--- /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");
+    }
+}
--- /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);
+}
--- 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);
+    }
 }
--- 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);
--- 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
--- 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);