Skip to content

Commit

Permalink
Determine primitive type when reflecting methods
Browse files Browse the repository at this point in the history
  • Loading branch information
CalebFenton committed Feb 15, 2016
1 parent b18b421 commit cf80ad3
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 14 deletions.
19 changes: 14 additions & 5 deletions smalivm/resources/test/smalivm/method_reflector_test.smali
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.super Ljava/lang/Object;


.method public static InitCharacterWithChar()V
.method public static initCharacterWithChar()V
.locals 1

# Can't set v0 to "new-instance" at Java level
Expand All @@ -12,7 +12,7 @@
return-void
.end method

.method public static InitBooleanWithBoolean()V
.method public static initBooleanWithBoolean()V
.locals 1

new-instance v0, Ljava/lang/Boolean;
Expand All @@ -21,7 +21,7 @@
return-void
.end method

.method public static ShortValueOfShort()V
.method public static shortValueOfShort()V
.locals 1

invoke-static {v0}, Ljava/lang/Short;->valueOf(S)Ljava/lang/Short;
Expand All @@ -30,11 +30,20 @@
return-void
.end method

.method public static ByteValueOfByte()V
.method public static byteValueOfByte()V
.locals 1

invoke-static {v0}, Ljava/lang/Byte;->valueOf(B)Ljava/lang/Byte;
move-result v0

return-void
.end method
.end method

.method public static getClassMethod()V
.locals 2

invoke-virtual {v0, v1, v2}, Ljava/lang/Class;->getMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
move-result v0

return-void
.end method
32 changes: 31 additions & 1 deletion smalivm/src/main/java/org/cf/smalivm/MethodReflector.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,37 @@ private InvocationArguments getArguments(MethodState mState) throws ClassNotFoun

// Shouldn't need a VM class loader since these are all safe to reflect on the JVM
// Also, some type names are arrays and loadClass only works for component types
Class<?> parameterType = Class.forName(ClassNameUtils.internalToBinary(parameterTypeName));

Class<?> parameterType;
switch (parameterTypeName) {
case "I":
parameterType = int.class;
break;
case "Z":
parameterType = boolean.class;
break;
case "J":
parameterType = long.class;
break;
case "B":
parameterType = byte.class;
break;
case "S":
parameterType = short.class;
break;
case "C":
parameterType = char.class;
break;
case "D":
parameterType = double.class;
break;
case "F":
parameterType = float.class;
break;
default:
parameterType = Class.forName(ClassNameUtils.internalToBinary(parameterTypeName));
break;
}
parameterTypes[i - offset] = parameterType;

if (Utils.getRegisterSize(parameterTypeName) == 2) {
Expand Down
26 changes: 18 additions & 8 deletions smalivm/src/test/java/org/cf/smalivm/MethodReflectorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,49 @@ public void setUp() {
}

@Test
public void castsIntegerToByte() {
public void canCastIntegerToByte() {
byte value = 6;
initial.setRegisters(0, value, "B");
expected.setRegisters(0, Byte.valueOf(value), "Ljava/lang/Byte;");

VMTester.test(CLASS_NAME, "ByteValueOfByte()V", initial, expected);
VMTester.test(CLASS_NAME, "byteValueOfByte()V", initial, expected);
}

@Test
public void initBooleanWithBoolean() {
public void canInitBooleanWithBoolean() {
boolean value = true;
initial.setRegisters(1, value, "Z");
expected.setRegisters(0, Boolean.valueOf(value), "Ljava/lang/Boolean;");

VMTester.test(CLASS_NAME, "InitBooleanWithBoolean()V", initial, expected);
VMTester.test(CLASS_NAME, "initBooleanWithBoolean()V", initial, expected);
}

@Test
public void initCharacterWithChar() {
public void canInitCharacterWithChar() {
char value = 'a';
initial.setRegisters(1, value, "C");
expected.setRegisters(0, Character.valueOf(value), "Ljava/lang/Character;");

VMTester.test(CLASS_NAME, "InitCharacterWithChar()V", initial, expected);
VMTester.test(CLASS_NAME, "initCharacterWithChar()V", initial, expected);
}

@Test
public void shortValueOfShort() {
public void canGetShortValueOfShort() {
short value = 5;
initial.setRegisters(0, value, "S");
expected.setRegisters(0, Short.valueOf(value), "Ljava/lang/Short;");

VMTester.test(CLASS_NAME, "ShortValueOfShort()V", initial, expected);
VMTester.test(CLASS_NAME, "shortValueOfShort()V", initial, expected);
}

@Test
public void handlesNullArgumentProperly() throws NoSuchMethodException, SecurityException {
// Dalvik uses const/4 v1, 0x0 for null
initial.setRegisters(0, System.class, "Ljava/lang/Class;", 1, "currentTimeMillis", "Ljava/lang/String;", 2, 0,
"I");
expected.setRegisters(0, System.class.getMethod("currentTimeMillis", null), "Ljava/lang/reflect/Method;");

VMTester.test(CLASS_NAME, "getClassMethod()V", initial, expected);
}

}

0 comments on commit cf80ad3

Please sign in to comment.