Skip to content

Commit

Permalink
wrap primitive return values using correct types in Method.invoke
Browse files Browse the repository at this point in the history
The VM uses Integer and Long instances internally to wrap the results
of dynamic method invocations, but Method.invoke should use the
correct, specific type for the primitive (e.g. Character for char).
  • Loading branch information
dicej committed Feb 23, 2011
1 parent 6014cb9 commit bead78d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 2 deletions.
5 changes: 4 additions & 1 deletion src/classpath-avian.cpp
Expand Up @@ -312,8 +312,11 @@ Avian_java_lang_reflect_Method_invoke
}
});

unsigned returnCode = methodReturnCode(t, method);

return reinterpret_cast<int64_t>
(t->m->processor->invokeArray(t, method, instance, args));
(translateInvokeResult
(t, returnCode, t->m->processor->invokeArray(t, method, instance, args)));
}

extern "C" JNIEXPORT int64_t JNICALL
Expand Down
34 changes: 34 additions & 0 deletions src/classpath-common.h
Expand Up @@ -286,6 +286,40 @@ makeStackTraceElement(Thread* t, object e)
return makeStackTraceElement(t, class_, method, file, line);
}

object
translateInvokeResult(Thread* t, unsigned returnCode, object o)
{
switch (returnCode) {
case ByteField:
return makeByte(t, intValue(t, o));

case BooleanField:
return makeBoolean(t, intValue(t, o) != 0);

case CharField:
return makeChar(t, intValue(t, o));

case ShortField:
return makeShort(t, intValue(t, o));

case FloatField:
return makeFloat(t, intValue(t, o));

case IntField:
case LongField:
case ObjectField:
case VoidField:
return o;

case DoubleField:
return makeDouble(t, longValue(t, o));
break;

default:
abort(t);
}
}

} // namespace vm

#endif//CLASSPATH_COMMON_H
5 changes: 4 additions & 1 deletion src/classpath-openjdk.cpp
Expand Up @@ -3162,6 +3162,8 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments)
instance = 0;
}

unsigned returnCode = methodReturnCode(t, vmMethod);

object result;
if (args) {
result = t->m->processor->invokeArray
Expand All @@ -3170,7 +3172,8 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments)
result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0);
}

return reinterpret_cast<uint64_t>(makeLocalReference(t, result));
return reinterpret_cast<uint64_t>
(makeLocalReference(t, translateInvokeResult(t, returnCode, result)));
}

extern "C" JNIEXPORT jobject JNICALL
Expand Down
58 changes: 58 additions & 0 deletions test/Reflection.java
Expand Up @@ -2,12 +2,70 @@
import java.lang.reflect.Field;

public class Reflection {
public static boolean booleanMethod() {
return true;
}

public static byte byteMethod() {
return 1;
}

public static char charMethod() {
return '2';
}

public static short shortMethod() {
return 3;
}

public static int intMethod() {
return 4;
}

public static float floatMethod() {
return 5.0f;
}

public static long longMethod() {
return 6;
}

public static double doubleMethod() {
return 7.0;
}

public static void expect(boolean v) {
if (! v) throw new RuntimeException();
}

public static void main(String[] args) throws Exception {
Class system = Class.forName("java.lang.System");
Field out = system.getDeclaredField("out");
Class output = Class.forName("java.io.PrintStream");
Method println = output.getDeclaredMethod("println", String.class);

println.invoke(out.get(null), "Hello, World!");

expect((Boolean) Reflection.class.getMethod("booleanMethod").invoke(null));

expect(1 == (Byte) Reflection.class.getMethod("byteMethod").invoke(null));

expect('2' == (Character) Reflection.class.getMethod
("charMethod").invoke(null));

expect(3 == (Short) Reflection.class.getMethod
("shortMethod").invoke(null));

expect(4 == (Integer) Reflection.class.getMethod
("intMethod").invoke(null));

expect(5.0 == (Float) Reflection.class.getMethod
("floatMethod").invoke(null));

expect(6 == (Long) Reflection.class.getMethod
("longMethod").invoke(null));

expect(7.0 == (Double) Reflection.class.getMethod
("doubleMethod").invoke(null));
}
}

0 comments on commit bead78d

Please sign in to comment.