Invoke's varargs with null param

374 views
Skip to first unread message

Jason Aaron Osgood

unread,
Sep 5, 2014, 1:10:36 PM9/5/14
to reflecta...@googlegroups.com
Hi Nate, Everyone:


Given target method setName( String s ), I was surprised this throw a NPE:

  methodAccess.invoke( instance, index, null );

Looking at ReflectASM unit tests, I saw that this does work:

  methodAccess.invoke( instance, index, (Object) null );

I sorta grasp the Java Lang Spec on this: target method is resolved at compile time, exact match takes precedent. But I still don't grasp why "(Object) null" and "null" are treated differently. (I could look at the byte codes...)

Regardless.

Here's a gist to show how Java handles varargs invocation with variations of null:


It occurs to me, performance crazy microtweakers that we are, that adding zero and single param invoke methods to MethodAccess would prevent the creation of temp object arrays.

  abstract public Object invoke (Object object, int methodIndex, Object... args);
  abstract public Object invoke (Object object, int methodIndex, Object args);
  abstract public Object invoke (Object object, int methodIndex);

I scanned your ASM ClassWriter code generation magic. Ummm. Any chance you have the plain Java version captured some where? 

I must confess that I just use the ASMify feature of the Bytecode Outline plugin to jumpstart my ASM efforts.

My backup plan is to capture the resulting class (byte array) and use JAD to show me what the generated code looks like.


Cheers, Jason

Nate

unread,
Sep 5, 2014, 2:04:39 PM9/5/14
to reflecta...@googlegroups.com
Hey Jason!


On Fri, Sep 5, 2014 at 7:10 PM, Jason Aaron Osgood <zap...@gmail.com> wrote:
Hi Nate, Everyone:


Given target method setName( String s ), I was surprised this throw a NPE:

  methodAccess.invoke( instance, index, null );

Looking at ReflectASM unit tests, I saw that this does work:

  methodAccess.invoke( instance, index, (Object) null );

I sorta grasp the Java Lang Spec on this: target method is resolved at compile time, exact match takes precedent. But I still don't grasp why "(Object) null" and "null" are treated differently. (I could look at the byte codes...)

Eclipse shows this warning for that code: "Type null of the last argument to method invoke(Object, int, Object...) doesn't exactly match the vararg parameter type. Cast to Object[] to confirm the non-varargs invocation, or pass individual arguments of type Object for a varargs invocation."
 

Here's a gist to show how Java handles varargs invocation with variations of null:


It occurs to me, performance crazy microtweakers that we are, that adding zero and single param invoke methods to MethodAccess would prevent the creation of temp object arrays.

  abstract public Object invoke (Object object, int methodIndex, Object... args);
  abstract public Object invoke (Object object, int methodIndex, Object args);
  abstract public Object invoke (Object object, int methodIndex);

True. It would be reasonable to have methods with zero to 5 parameters to avoid allocation for varargs.
 

I scanned your ASM ClassWriter code generation magic. Ummm. Any chance you have the plain Java version captured some where? 

I must confess that I just use the ASMify feature of the Bytecode Outline plugin to jumpstart my ASM efforts.

My backup plan is to capture the resulting class (byte array) and use JAD to show me what the generated code looks like.

I never could get that stupid plugin to work. I use ASM from the command line to dump a class file. ReflectASM started like this, but has since been hand edited. FieldAccess especially, which doesn't need varargs help but has methods to avoid boxing. MethodAccess has not seen much love, since if you care about performance you probably access fields and Kryo mostly accesses fields.

Still, it would be a nice improvement for MethodAccess. It would take some reworking, since you need to generate multiple invoke methods. Just write the code for the method, dump it with ASM, and try to shoehorn it in. :D

-Nate


Jason Aaron Osgood

unread,
Sep 7, 2014, 11:04:10 AM9/7/14
to reflecta...@googlegroups.com
Still, it would be a nice improvement for MethodAccess. It would take some reworking, since you need to generate multiple invoke methods. Just write the code for the method, dump it with ASM, and try to shoehorn it in. :D

I used JD-GUI to reconstitute the proxy for your example SomeClass. 

Maybe its my old age, but I didn't really grok how the generated invoke(...) worked until I saw the generated code. Might be worthwhile to give an (elided) example on the project wiki?

package com.esotericsoftware.reflectasm;

public class MethodAccessTest$SomeClassMethodAccess extends MethodAccess
{
  public Object invoke(Object paramObject, int paramInt, Object[] paramArrayOfObject)
  {
    MethodAccessTest.SomeClass localSomeClass = (MethodAccessTest.SomeClass)paramObject;
    switch (paramInt)
    {
    case 0:
      return localSomeClass.getName();
    case 1:
      localSomeClass.setName((String)paramArrayOfObject[0]);
      return null;
    case 2:
      return Integer.valueOf(localSomeClass.getIntValue());
    case 3:
      localSomeClass.setIntValue(((Integer)paramArrayOfObject[0]).intValue());
      return null;
    case 4:
      return localSomeClass.methodWithManyArguments(((Integer)paramArrayOfObject[0]).intValue(), ((Float)paramArrayOfObject[1]).floatValue(), (Integer)paramArrayOfObject[2], (Float)paramArrayOfObject[3], (MethodAccessTest.SomeClass)paramArrayOfObject[4], (MethodAccessTest.SomeClass)paramArrayOfObject[5], (MethodAccessTest.SomeClass)paramArrayOfObject[6]);
    }
    throw new IllegalArgumentException("Method not found: " + paramInt);
  }
}


There was a prior comment about supporting scalar params (to avoid auto boxing). Good opportunity to look at that too.

I'll noodle with generating multiple invoke(...) methods, as able.

Thanks. 
Reply all
Reply to author
Forward
0 new messages