Just An Application

November 24, 2009

InvokeDynamic And MethodHandles On Snow Leopard: Part Three

Filed under: Java, JSR292, MethodHandles, OpenJDK7, Snow Leopard — Tags: , , , , — Simon Lewis @ 1:02 pm

A Functioning MethodHandle

Switching to the 32-bit VM does indeed result in a fully functioning MethodHandle.


    Macintosh:tmp simon$ build/bsd-i586/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic DynTest
    type == (java.lang.String)void
    handle == print(java.io.PrintStream,java.lang.String)void
    Hello World via a MethodHandle !

One thing to note is the presence of the void qualifier on the call to the invoke() method.

    handle.<void>invoke(System.out, "Hello World via a MethodHandle !\n");

This specifies the return type of the method being invoked and is necessary.

If it is not specified it defaults to Object and in this case you get this.


    Macintosh:tmp simon$ build/bsd-i586/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic DynTest
    type == (java.lang.String)void
    handle == print(java.io.PrintStream,java.lang.String)void
    java.dyn.WrongMethodTypeException: (Ljava/lang/String;)V cannot be called as (Ljava/io/PrintStream;Ljava/lang/String;)Ljava/lang/Object;
	    at DynTest.main(DynTest.java:24)

Equally it is an error if the wrong type is specified, for example,

    handle.<boolean>invoke(System.out, "Hello World via a MethodHandle !\n");

gets you this


    ...

    java.dyn.WrongMethodTypeException: (Ljava/lang/String;)V cannot be called as (Ljava/io/PrintStream;Ljava/lang/String;)Z
	    at DynTest.main(DynTest.java:24)

It is also an error to call a method via a MethodHandle with the wrong number of arguments, or the wrong argument types. In short MethodHandles are type-safe at runtime.

I believe that MethodHandles are also intended to be access-controlled, but at the current time they do not appear to be or not in the ways I would expect them to be. However, this is probably just a function of the state of my particular build and/or the current state of the implementation.

For example, given this class definition


    package other;

    public final class Foo
    {
        public Foo()
        {
        }
	
        //
	
        void localMethod()
        {
            System.out.println("Foo.localMethod()");
        }
	
        private void privateMethod()
        {
            System.out.println("Foo.privateMethod()");
        }
	
        private static void privateStaticMethod()
        {
            System.out.println("Foo.privateStaticMethod()");
        }
    }

I would not have expected this to work.


    package test;

    import java.dyn.MethodHandle;
    import java.dyn.MethodHandles;
    import java.dyn.MethodType;

    import other.Foo;

    public final class MethodHandleAccessTestOne
    {
        public static void main(String[] theArgs)
        {
            try 
            {
                MethodType type = MethodType.make(Void.TYPE);
			
                System.out.print("type == ");
                System.out.println(type);
			
                MethodHandle handle = MethodHandles.lookup().findStatic(Foo.class, "privateStaticMethod", type);
			
                System.out.print("handle == ");
                System.out.println(handle);
			
                handle.invoke();
            }
            catch (Throwable t) 
            {
                t.printStackTrace();
            }
        }
    }

but it does


    Macintosh:tmp simon$ build/bsd-i586/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic test.MethodHandleAccessTestOne
    type == ()void
    handle == privateStaticMethod()void
    Foo.privateStaticMethod()

This does not work


    package test;

    import java.dyn.MethodHandle;
    import java.dyn.MethodHandles;
    import java.dyn.MethodType;

    import other.Foo;

    public final class MethodHandleAccessTestTwo
    {
        public static void main(String[] theArgs)
        {
            try 
            {
                MethodType type = MethodType.make(Void.TYPE);
			
                System.out.print("type == ");
                System.out.println(type);
			
                MethodHandle handle = MethodHandles.lookup().findVirtual(Foo.class, "localMethod", type);
			
                System.out.print("handle == ");
                System.out.println(handle);
			
                Foo foo = new Foo();
			
                System.out.print("foo == ");
                System.out.println(foo);
                handle.invoke(foo);
            }
            catch (Throwable t) 
            {
                t.printStackTrace();
            }
        }
    }

but on the basis of the error message I am not really sure if it is not working for the right reason


    Macintosh:tmp simon$ /Users/simon/Scratch/xper/jdk7-bsd/build/bsd-i586/bin/java -classpath . -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic test.MethodHandleAccessTestTwo
    type == ()void
    handle == Adapted[localMethod](java.lang.Object)void
    foo == other.Foo@19efb05
    java.lang.NoClassDefFoundError: other/Foo
	    at test.MethodHandleAccessTestTwo.main(MethodHandleAccessTestTwo.java:30)


Copyright (c) 2009 By Simon Lewis. All Rights Reserved.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: