changeset 15102:175111728365

improve canBeStaticallyBound
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Mon, 14 Apr 2014 15:08:30 -0700
parents 9f7eac122d61
children 9dc7efd43c44
files graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java src/share/vm/runtime/vmStructs.cpp
diffstat 7 files changed, 41 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Mon Apr 14 15:07:55 2014 -0700
+++ b/graal/com.oracle.graal.api.meta.test/src/com/oracle/graal/api/meta/test/TestResolvedJavaMethod.java	Mon Apr 14 15:08:30 2014 -0700
@@ -131,16 +131,18 @@
     public void canBeStaticallyBoundTest() {
         for (Map.Entry<Method, ResolvedJavaMethod> e : methods.entrySet()) {
             ResolvedJavaMethod m = e.getValue();
-            assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey().getModifiers()));
+            assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey()));
         }
         for (Map.Entry<Constructor<?>, ResolvedJavaMethod> e : constructors.entrySet()) {
             ResolvedJavaMethod m = e.getValue();
-            assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey().getModifiers()));
+            assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey()));
         }
     }
 
-    private static boolean canBeStaticallyBound(int modifiers) {
-        return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)) && !Modifier.isAbstract(modifiers);
+    private static boolean canBeStaticallyBound(Member method) {
+        int modifiers = method.getModifiers();
+        return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(method.getDeclaringClass().getModifiers())) &&
+                        !Modifier.isAbstract(modifiers);
     }
 
     private static String methodWithExceptionHandlers(String p1, Object o2) {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Mon Apr 14 15:07:55 2014 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Mon Apr 14 15:08:30 2014 -0700
@@ -35,10 +35,10 @@
      * Returns the bytecode of this method, if the method has code. The returned byte array does not
      * contain breakpoints or non-Java bytecodes. This may return null if the
      * {@link #getDeclaringClass() holder} is not {@link ResolvedJavaType#isLinked() linked}.
-     * 
+     *
      * The contained constant pool indices may not be the ones found in the original class file but
      * they can be used with the Graal API (e.g. methods in {@link ConstantPool}).
-     * 
+     *
      * @return the bytecode of the method, or {@code null} if {@code getCodeSize() == 0} or if the
      *         code is not ready.
      */
@@ -47,7 +47,7 @@
     /**
      * Returns the size of the bytecode of this method, if the method has code. This is equivalent
      * to {@link #getCode()}. {@code length} if the method has code.
-     * 
+     *
      * @return the size of the bytecode in bytes, or 0 if no bytecode is available
      */
     int getCodeSize();
@@ -84,10 +84,10 @@
 
     /**
      * Returns {@code true} if this method is a default method; returns {@code false} otherwise.
-     * 
+     *
      * A default method is a public non-abstract instance method, that is, a non-static method with
      * a body, declared in an interface type.
-     * 
+     *
      * @return true if and only if this method is a default method as defined by the Java Language
      *         Specification.
      */
@@ -95,22 +95,22 @@
 
     /**
      * Checks whether this method is a class initializer.
-     * 
+     *
      * @return {@code true} if the method is a class initializer
      */
     boolean isClassInitializer();
 
     /**
      * Checks whether this method is a constructor.
-     * 
+     *
      * @return {@code true} if the method is a constructor
      */
     boolean isConstructor();
 
     /**
      * Checks whether this method can be statically bound (usually, that means it is final or
-     * private or static, but not abstract).
-     * 
+     * private or static, but not abstract, or the declaring class is final)
+     *
      * @return {@code true} if this method can be statically bound
      */
     boolean canBeStaticallyBound();
@@ -143,7 +143,7 @@
     /**
      * Returns the annotation for the specified type of this method, if such an annotation is
      * present.
-     * 
+     *
      * @param annotationClass the Class object corresponding to the annotation type
      * @return this element's annotation for the specified annotation type if present on this
      *         method, else {@code null}
@@ -153,7 +153,7 @@
     /**
      * Returns an array of arrays that represent the annotations on the formal parameters, in
      * declaration order, of this method.
-     * 
+     *
      * @see Method#getParameterAnnotations()
      */
     Annotation[][] getParameterAnnotations();
@@ -161,7 +161,7 @@
     /**
      * Returns an array of {@link Type} objects that represent the formal parameter types, in
      * declaration order, of this method.
-     * 
+     *
      * @see Method#getGenericParameterTypes()
      */
     Type[] getGenericParameterTypes();
@@ -192,7 +192,7 @@
      * Invokes the underlying method represented by this object, on the specified object with the
      * specified parameters. This method is similar to a reflective method invocation by
      * {@link Method#invoke}.
-     * 
+     *
      * @param receiver The receiver for the invocation, or {@code null} if it is a static method.
      * @param arguments The arguments for the invocation.
      * @return The value returned by the method invocation, or {@code null} if the return type is
@@ -204,7 +204,7 @@
      * Uses the constructor represented by this object to create and initialize a new instance of
      * the constructor's declaring class, with the specified initialization parameters. This method
      * is similar to a reflective instantiation by {@link Constructor#newInstance}.
-     * 
+     *
      * @param arguments The arguments for the constructor.
      * @return The newly created and initialized object.
      */
@@ -212,14 +212,14 @@
 
     /**
      * Gets the encoding of (that is, a constant representing the value of) this method.
-     * 
+     *
      * @return a constant representing a reference to this method
      */
     Constant getEncoding();
 
     /**
      * Checks if this method is present in the virtual table.
-     * 
+     *
      * @return true is this method is present in the virtual table
      */
     boolean isInVirtualMethodTable();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Apr 14 15:07:55 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Apr 14 15:08:30 2014 -0700
@@ -1056,6 +1056,7 @@
     @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline;
     @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline;
     @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden;
+    @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex;
 
     @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
     @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Apr 14 15:07:55 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Mon Apr 14 15:08:30 2014 -0700
@@ -187,7 +187,7 @@
     @Override
     public boolean canBeStaticallyBound() {
         int modifiers = getModifiers();
-        return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)) && !Modifier.isAbstract(modifiers);
+        return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(holder.getModifiers())) && !Modifier.isAbstract(modifiers);
     }
 
     @Override
@@ -616,8 +616,11 @@
      * @return virtual table index
      */
     private int getVtableIndex() {
+        assert !Modifier.isInterface(holder.getModifiers());
         HotSpotVMConfig config = runtime().getConfig();
-        return unsafe.getInt(metaspaceMethod + config.methodVtableIndexOffset);
+        int result = unsafe.getInt(metaspaceMethod + config.methodVtableIndexOffset);
+        assert result >= config.nonvirtualVtableIndex : "must be linked";
+        return result;
     }
 
     public SpeculationLog getSpeculationLog() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Mon Apr 14 15:07:55 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Mon Apr 14 15:08:30 2014 -0700
@@ -55,7 +55,7 @@
 
     /**
      * Gets the target method for this invocation instruction.
-     * 
+     *
      * @return the target method
      */
     public ResolvedJavaMethod targetMethod() {
@@ -76,7 +76,7 @@
 
     /**
      * Gets the instruction that produces the receiver object for this invocation, if any.
-     * 
+     *
      * @return the instruction that produces the receiver object for this invocation if any,
      *         {@code null} if this invocation does not take a receiver object
      */
@@ -86,7 +86,7 @@
 
     /**
      * Checks whether this is an invocation of a static method.
-     * 
+     *
      * @return {@code true} if the invocation is a static invocation
      */
     public boolean isStatic() {
@@ -138,18 +138,17 @@
                 return this;
             }
 
-            // check if the exact type of the receiver can be determined
+            assert targetMethod.getDeclaringClass().asExactType() == null : "should have been handled by canBeStaticallyBound";
+
+            // check if the type of the receiver can narrow the result
             ValueNode receiver = receiver();
-            ResolvedJavaType exact = targetMethod.getDeclaringClass().asExactType();
-            if (exact == null && ObjectStamp.isExactType(receiver)) {
-                exact = ObjectStamp.typeOrNull(receiver);
-            }
-            if (exact != null) {
+            ResolvedJavaType type = ObjectStamp.typeOrNull(receiver);
+            if (type != null) {
                 // either the holder class is exact, or the receiver object has an exact type
-                ResolvedJavaMethod exactMethod = exact.resolveMethod(targetMethod);
-                if (exactMethod != null) {
+                ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod);
+                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || ObjectStamp.isExactType(receiver))) {
                     invokeKind = InvokeKind.Special;
-                    targetMethod = exactMethod;
+                    targetMethod = resolvedMethod;
                     return this;
                 }
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon Apr 14 15:07:55 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon Apr 14 15:08:30 2014 -0700
@@ -814,7 +814,7 @@
                         if (!Objects.equals(type, ObjectStamp.typeOrNull(receiver))) {
                             ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod());
                             if (method != null) {
-                                if (Modifier.isFinal(method.getModifiers()) || Modifier.isFinal(type.getModifiers())) {
+                                if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) {
                                     callTarget.setInvokeKind(InvokeKind.Special);
                                     callTarget.setTargetMethod(method);
                                 }
--- a/src/share/vm/runtime/vmStructs.cpp	Mon Apr 14 15:07:55 2014 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Mon Apr 14 15:08:30 2014 -0700
@@ -2423,6 +2423,7 @@
   declare_constant(Method::_force_inline)                                 \
   declare_constant(Method::_dont_inline)                                  \
   declare_constant(Method::_hidden)                                       \
+  declare_constant(Method::nonvirtual_vtable_index)                       \
                                                                           \
   declare_constant(ConstMethod::_has_linenumber_table)                    \
   declare_constant(ConstMethod::_has_checked_exceptions)                  \