jdk7 b58, VM doesn't smell good

Rémi Forax forax at univ-mlv.fr
Sun May 10 08:02:30 PDT 2009


The runtime of jdk7 b58 doesn't work too.

java -cp test-classes/ fr.umlv.indy.visitor.test.Main0
Java HotSpot(TM) Server VM warning: JSR 292 method handles are disabled 
in this JVM.  Use -XX:+EnableMethodHandles to enable.
Exception in thread "main" java.lang.UnsatisfiedLinkError: 
sun.dyn.MethodHandleNatives.getConstant(I)I
    at sun.dyn.MethodHandleNatives.getConstant(Native Method)
    at sun.dyn.MethodHandleNatives.<clinit>(MethodHandleNatives.java:133)
    at sun.dyn.MemberName.<init>(MemberName.java:291)
    at java.dyn.MethodHandles$Lookup.unreflect(MethodHandles.java:307)
    at fr.umlv.indy.visitor.AbstractVisitor.<init>(AbstractVisitor.java:41)
    at fr.umlv.indy.visitor.test.Main0$1.<init>(Main0.java:7)
    at fr.umlv.indy.visitor.test.Main0.main(Main0.java:7)

Here, the behavior is Ok, I need to enable method handles.

 java -cp test-classes/ -XX:+EnableMethodHandles 
fr.umlv.indy.visitor.test.Main0
Java HotSpot(TM) Server VM warning: JSR 292 invokedynamic is disabled in 
this JVM.  Use -XX:+EnableInvokeDynamic to enable.
Exception in thread "main" java.lang.NoClassDefFoundError: 
fr/umlv/indy/visitor/AbstractVisitor
    at 
fr.umlv.indy.visitor.AbstractVisitor.genericVisit(AbstractVisitor.java:73)
    at fr.umlv.indy.visitor.test.Main0.main(Main0.java:19)

I love this error message, NoClassDefFound AbstractVisitor in 
genericVisit of AbstractVisitor ??
Ok, perhaps the message is just not the good one.

Moreover, the VM asks for enabling invoke dynamic but the code (below) 
doesn't use it ?
The line 73 of AbstractVisitor.genericVisit is an invokevistual on a 
MethodHandle.
    handle(target.getClass()).<void>invoke(this, target);

It's a regression, this code was working with tl/hotspot (changeset 
738:53d9bf689e80).

I have checked if it is not because the compiler use invokedynamic 
instead of invokevirtual
but this is not the case :
public void genericVisit(java.lang.Object);
  Code:
   0:    aload_0
   1:    aload_1
   2:    invokevirtual    #5; //Method 
java/lang/Object.getClass:()Ljava/lang/Class;
   5:    invokevirtual    #40; //Method 
handle:(Ljava/lang/Class;)Ljava/dyn/MethodHandle;
   8:    aload_0
   9:    aload_1
   10:    invokevirtual    #41; //Method 
java/dyn/MethodHandle.invoke:(Lfr/umlv/indy/visitor/AbstractVisitor;Ljava/lang/Object;)V
   13:    return

Trying to enable invoke dynamic :
java -cp test-classes/ -XX:+EnableInvokeDynamic 
fr.umlv.indy.visitor.test.Main0
Exception in thread "main" java.lang.NoClassDefFoundError: 
fr/umlv/indy/visitor/AbstractVisitor
    at 
fr.umlv.indy.visitor.AbstractVisitor.genericVisit(AbstractVisitor.java:73)
    at fr.umlv.indy.visitor.test.Main0.main(Main0.java:19)

It doesn't work, same stupid error.

It seems that something goes wrong between hotspot code in tl and its 
integration
in jdk7 workspace.

I hope this mail will help !

Rémi
PS: here are the two classes I have used, if you want to reproduce the bug.

-----------------------------------------------------------------------------------------------------------------
package fr.umlv.indy.visitor;

import java.dyn.MethodHandle;
import java.dyn.MethodHandles;
import java.dyn.MethodType;
import java.dyn.MethodHandles.Lookup;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

public abstract class AbstractVisitor {
  private final ConcurrentHashMap<Class<?>, MethodHandle> map;
 
  protected AbstractVisitor() {
    ConcurrentHashMap<Class<?>, MethodHandle> map=
      new ConcurrentHashMap<Class<?>, MethodHandle>();
    
    // should use public lookup but NPE (bug, fixed in mlvm repository)
    // Lookup lookup = MethodHandles.Lookup.PUBLIC_LOOKUP;
    Lookup lookup = MethodHandles.lookup();
    
    for(Method method : getClass().getMethods()) {
      if ("visit".equals(method.getName())) {
        
        Class<?>[] types = method.getParameterTypes();
        if (types.length!=1)
          throw new IllegalStateException("wrong number of parameter 
"+method);
        Class<?> type=types[0];
        if (type.isInterface() || type.isPrimitive() || 
method.getReturnType()!=void.class)
          throw new IllegalStateException("invalid method signature 
"+method);
        
        //System.out.println("register "+method);
        
        // should be not needed but generate currently a NPE
        method.setAccessible(true);
        
        //MethodHandle methodHandle = 
MethodHandles.Lookup.PUBLIC_LOOKUP.unreflect(method);
        MethodHandle methodHandle = lookup.unreflect(method);
        
        //System.out.println("methodHandle type "+methodHandle.type());
        methodHandle = MethodHandles.convertArguments(methodHandle, 
MethodType.make(void.class, AbstractVisitor.class, Object.class));
        
        //System.out.println("mh type "+methodHandle.type());
        
        map.put(type, methodHandle);
      }
    }
    
    this.map=map;
  }
 
  private MethodHandle findNewMethodHandle(Class<?> type) {
    MethodHandle methodHandle=superHandle(type);
    map.put(type, methodHandle);
    return methodHandle;
  }
 
  private MethodHandle superHandle(Class<?> type) {
    ConcurrentHashMap<Class<?>, MethodHandle> map = this.map;
    for(Class<?> 
clazz=type.getSuperclass();clazz!=null;clazz=clazz.getSuperclass()) {
      MethodHandle methodHandle = map.get(clazz);
      if (methodHandle != null) {
        return methodHandle;
      }
    }
    throw new RuntimeException("no visit method applicable for "+type);
  }
 
  public void genericVisit(Object target) {
    handle(target.getClass()).<void>invoke(this, target);
  }
 
  public MethodHandle handle(Class<?> type) {
    MethodHandle methodHandle=map.get(type);
    if (methodHandle!=null) {
      return methodHandle;
    }
    return findNewMethodHandle(type);
  }
 
  public MethodHandle oneApplicable(Class<?> type) {
    MethodHandle oneApplicable=null;
    for(Entry<Class<?>, MethodHandle> entry:map.entrySet()) {
      if (type.isAssignableFrom(entry.getKey())) {
        if (oneApplicable==null)
          oneApplicable=entry.getValue();
        else
          return null;
      }
    }
    return oneApplicable;
  }
}

-------------------------------------------------------------------------------------------------------------------
package fr.umlv.indy.visitor.test;

import fr.umlv.indy.visitor.AbstractVisitor;

public class Main0 {
  public static void main(String[] args) {
    AbstractVisitor visitor=new AbstractVisitor() {
      public void visit(String text) {
        System.out.println("text "+text);
      }
      public void visit(Integer integer) {
        System.out.println("integer "+integer);
      }
      public void visit(Object o) {
        System.out.println("object "+o);
      }
    };
   
    visitor.genericVisit("toto");
    visitor.genericVisit(3);
    visitor.genericVisit(4.0);
  }
}




More information about the mlvm-dev mailing list