Skip to content

Commit

Permalink
Add a new test to verify we can reflect invoke toString on a string. …
Browse files Browse the repository at this point in the history
…The uniqueness here is that java.lang.Object.toString is remapped to a static method.

Fix an issue with how we were invoking remapped methods. The Java reflection information lists the method as an instance method. But it's actually remapped to a static method. Same calling convention, but it turns from a callvirt into a call. This was handled through mw.EmitCallvirtReflect, which got removed in the restriction of ReflectionFactory.
fixes #647
  • Loading branch information
wasabii committed Jan 10, 2025
1 parent ff96f10 commit a75c4c0
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 5 deletions.
14 changes: 14 additions & 0 deletions src/IKVM.Java.Tests/java/lang/reflect/StringTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ikvm.tests.java.java.lang.reflect;

import java.lang.reflect.*;

@cli.Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute.Annotation()
public class StringTests {

@cli.Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute.Annotation()
public void canInvokeToStringOnString() throws Throwable {
String test = "test";
test.getClass().getMethod("toString").invoke(test);
}

}
15 changes: 10 additions & 5 deletions src/IKVM.Runtime/Java/Externs/sun/reflect/ReflectionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -729,8 +729,13 @@ internal unsafe FastMethodAccessorImpl(RuntimeJavaMethod mw)
// this instance
if (s != null)
{
// null for static, reference for valuetype/ghost, reference for instance
il.Emit(mw.DeclaringType.IsNonPrimitiveValueType || mw.DeclaringType.IsGhost ? OpCodes.Ldloca : OpCodes.Ldloc, s);
// reference for valuetype/ghost
if (mw.DeclaringType.IsNonPrimitiveValueType || mw.DeclaringType.IsGhost)
il.Emit(OpCodes.Ldloca, s);
else
il.Emit(OpCodes.Ldloc, s);

// finished with s
il.ReleaseTempLocal(s);
}

Expand All @@ -745,11 +750,11 @@ internal unsafe FastMethodAccessorImpl(RuntimeJavaMethod mw)
if (mw.HasCallerID)
il.Emit(OpCodes.Ldarg_2);

// call method
// static Java method is always a call
if (s != null)
il.Emit(OpCodes.Callvirt, mw.GetMethod());
mw.EmitCall(il);
else
il.Emit(OpCodes.Call, mw.GetMethod());
mw.EmitCallvirtReflect(il); // reflection virt may be static (remapped) or non-static

// handle return value
mw.ReturnType.EmitConvSignatureTypeToStackType(il);
Expand Down

0 comments on commit a75c4c0

Please sign in to comment.