On Jun 11, 2011, at 2:18 PM, Attila Szegedi wrote:

> And BTW, attempts at using invoke() or invokeExact() didn't work either… They 
> all behave strangely. What's the sanctioned way to pass an array explicitly 
> as a vararg argument?

See the updated example below.  The javadoc for invokeWithArguments contains 
rules that imply the behavior you are seeing.  In other words, earlier 
implementations were broken.

If you call a varargs method with invokeExact, no transformations will be done. 
 This is the most direct way to turn off the varargs transformation (of 
collecting arguments into an array).  But this requires explicit, static typing.

Except for invokeExact, a varargs method routinely performs the varargs 
transformation.  By analogy with the Java language, you can only avoid the 
varargs transformation if you supply an explicitly typed (statically typed) 
array for the last argument.  If the last argument is not an explicitly typed 
array, the argument will be taken to be a single element of an implicitly 
specified argument array.  That's what is happening in your example.

More specifically, the convenience method invokeWithArguments works like a 
plain invoke but only on Object types.  It cannot express static array types 
(Object[] or int[]) so it cannot  bypass the varargs transformation.

There's one more thing you can do:  turn off the "varargs bit" with 
asFixedArity.  That's probably the most direct way to avoid the varargs 
transformation, in the setting of untyped (Object-only) programming.

-- John



public class TestVarArgInvoke {
  public static void main(String[] args) throws Throwable {
    java.lang.invoke.MethodHandle x =
    java.lang.invoke.MethodHandles.publicLookup().unreflect(
        TestVarArgInvoke.class.getMethod("x", int.class, int[].class));
    for (int i = 0; i < 20; i++) {
      try {
        System.out.print("case "+i+": ");
        test(x, i);
      } catch (Exception ex) {
        System.out.print("*** throw "+ex); ex.printStackTrace();
      }
    }
  }
  static void test(java.lang.invoke.MethodHandle x, int i) throws Throwable {
    switch (i) {
    case 0: x.invokeWithArguments(
        new TestVarArgInvoke(), 1, new int[] { 2 });
        /*
java.lang.ClassCastException: [I cannot be cast to 
java.lang.Numberjava.lang.ClassCastException: [I cannot be cast to 
java.lang.Number
        at 
sun.invoke.util.ValueConversions.primitiveConversion(ValueConversions.java:231)
        at 
sun.invoke.util.ValueConversions.unboxInteger(ValueConversions.java:76)
        at 
java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:571)
        at 
java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:568)
        at TestVarArgInvoke.main(TestVarArgInvoke.java:7)
         */
        return;
    case 1: x.asFixedArity().invokeWithArguments(
        new TestVarArgInvoke(), 1, new int[] { 2 }); return;
    case 2: x.invokeExact(new TestVarArgInvoke(), 1, new int[] { 2 }); return;
    case 3: x.invoke(new TestVarArgInvoke(), 1, new int[] { 2 }); return;
    case 4: x.invoke((Object)new TestVarArgInvoke(), (Object)1, new int[] { 2 
}); return;
    case 5: x.invoke((Object)new TestVarArgInvoke(), (Object)1, (Object) new 
int[] { 2 });
        /*
java.lang.ClassCastException: [I cannot be cast to 
java.lang.Numberjava.lang.ClassCastException: [I cannot be cast to 
java.lang.Number
        at 
sun.invoke.util.ValueConversions.primitiveConversion(ValueConversions.java:231)
        at 
sun.invoke.util.ValueConversions.unboxInteger(ValueConversions.java:76)
        at TestVarArgInvoke.test(TestVarArgInvoke.java:33)
        at TestVarArgInvoke.main(TestVarArgInvoke.java:9)
         */
        return;
    case 6: x.invokeExact(new TestVarArgInvoke(), 1, 2);
        /*
java.lang.invoke.WrongMethodTypeException: (LTestVarArgInvoke;I[I)V cannot be 
called as (LTestVarArgInvoke;II)Vjava.lang.invoke.WrongMethodTypeException: 
(LTestVarArgInvoke;I[I)V cannot be called as (LTestVarArgInvoke;II)V
        at TestVarArgInvoke.test(TestVarArgInvoke.java:37)
        at TestVarArgInvoke.main(TestVarArgInvoke.java:9)
         */
        return;
    }
    System.out.println();
  }

  public void x(int a, int... b) {
    System.out.println(a+java.util.Arrays.toString(b));
  }
}

_______________________________________________
mlvm-dev mailing list
[email protected]
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to