Skip to content

Commit 4a13c3b

Browse files
committed
Fix JDWP method invocation and add tests
- Fix null ClassLoader NPE in ReferenceTypeCommandSet (Error 113) - Fix getNoDeclaredInterfaces() -> getNoInterfaces() for interface resolution - Extract MethodResolver utility class for shared method resolution logic - Implement InterfaceType methods/methodsWithGeneric commands - Add .gitignore for __pycache__/ - Add test_method_invocation.py with 23 integration tests
1 parent b8b9878 commit 4a13c3b

9 files changed

Lines changed: 742 additions & 125 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ classlib.pack.gz
1616
/.metadata
1717
/.idea/
1818
/.wiki/
19+
__pycache__/

core/src/classpath/ext/gnu/classpath/jdwp/JdwpConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ public static final class InterfaceType
131131
public static final byte CS_VALUE = 5;
132132

133133
// commands
134+
public static final byte METHODS = 1;
135+
public static final byte METHOD_WITH_GENERIC = 2;
134136
}
135137

136138
public static final class Method

core/src/classpath/ext/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java

Lines changed: 12 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import java.lang.reflect.Member;
6060
import java.nio.ByteBuffer;
6161
import org.jnode.vm.classmgr.VmType;
62-
import org.jnode.vm.classmgr.VmNormalClass;
6362
import org.jnode.vm.classmgr.VmMethod;
6463

6564
/**
@@ -111,12 +110,15 @@ private void executeSuperclass(ByteBuffer bb, DataOutputStream os)
111110
Class clazz = refId.getType();
112111
Class superClazz = clazz.getSuperclass();
113112

114-
if (superClazz == null) {
115-
os.writeLong(0L);
116-
} else {
117-
ReferenceTypeId clazzId = idMan.getReferenceTypeId(superClazz);
118-
clazzId.write(os);
119-
}
113+
if (superClazz == null)
114+
{
115+
os.writeLong(0L);
116+
}
117+
else
118+
{
119+
ReferenceTypeId clazzId = idMan.getReferenceTypeId(superClazz);
120+
clazzId.write(os);
121+
}
120122
}
121123

122124
private void executeSetValues(ByteBuffer bb, DataOutputStream os)
@@ -225,58 +227,10 @@ private MethodResult invokeMethod(ByteBuffer bb) throws JdwpException,
225227
values[i] = Value.getObj(bb);
226228
}
227229

228-
// Resolve member (method/constructor) from class or superclass using index and parameter count matching
229-
Member member = null;
230+
// Resolve member (method/constructor) from class or superclass using index and parameter count matching.
231+
// Walk the full hierarchy: superclass chain + all implemented interfaces.
230232
VmType vmType = VmType.fromClass(clazz);
231-
VmType searchType = vmType;
232-
while (searchType != null && member == null)
233-
{
234-
int nMethods = searchType.getNoDeclaredMethods();
235-
if (methodIdx >= 0 && methodIdx < nMethods)
236-
{
237-
VmMethod vmMethod = searchType.getDeclaredMethod((int) methodIdx);
238-
if (vmMethod != null)
239-
{
240-
Member candidate = vmMethod.asMember();
241-
int paramCount = (candidate instanceof Method)
242-
? ((Method) candidate).getParameterTypes().length
243-
: ((Constructor) candidate).getParameterTypes().length;
244-
if (paramCount == values.length)
245-
{
246-
member = candidate;
247-
break;
248-
}
249-
}
250-
}
251-
if (searchType instanceof VmNormalClass)
252-
{
253-
searchType = ((VmNormalClass) searchType).getSuperClass();
254-
}
255-
else
256-
{
257-
break;
258-
}
259-
}
260-
261-
// Fallback: search Java reflection declared methods across class hierarchy
262-
if (member == null)
263-
{
264-
Class curClass = clazz;
265-
while (curClass != null && member == null)
266-
{
267-
Method[] declared = curClass.getDeclaredMethods();
268-
if (methodIdx >= 0 && methodIdx < declared.length)
269-
{
270-
Method candidate = declared[(int) methodIdx];
271-
if (candidate.getParameterTypes().length == values.length)
272-
{
273-
member = candidate;
274-
break;
275-
}
276-
}
277-
curClass = curClass.getSuperclass();
278-
}
279-
}
233+
Member member = MethodResolver.resolveForClassType(vmType, clazz, methodIdx, values.length);
280234

281235
if (member == null)
282236
{

core/src/classpath/ext/gnu/classpath/jdwp/processor/InterfaceTypeCommandSet.java

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,18 @@
3939

4040
package gnu.classpath.jdwp.processor;
4141

42+
import gnu.classpath.jdwp.JdwpConstants;
4243
import gnu.classpath.jdwp.exception.JdwpException;
44+
import gnu.classpath.jdwp.exception.JdwpInternalErrorException;
4345
import gnu.classpath.jdwp.exception.NotImplementedException;
46+
import gnu.classpath.jdwp.id.ReferenceTypeId;
47+
import gnu.classpath.jdwp.util.JdwpString;
4448

4549
import java.io.DataOutputStream;
50+
import java.io.IOException;
4651
import java.nio.ByteBuffer;
52+
import org.jnode.vm.classmgr.VmType;
53+
import org.jnode.vm.classmgr.VmMethod;
4754

4855
/**
4956
* A class representing the InterfaceType Command Set.
@@ -53,16 +60,58 @@
5360
public class InterfaceTypeCommandSet
5461
extends CommandSet
5562
{
56-
/**
57-
* There are no commands for this CommandSet at this time so we just throw a
58-
* NotImplementedException whenever it's called.
59-
*
60-
* @throws JdwpException An exception will always be thrown
61-
*/
6263
public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command)
6364
throws JdwpException
6465
{
65-
throw new NotImplementedException(
66-
"No commands for command set InterfaceType implemented.");
66+
try
67+
{
68+
switch (command)
69+
{
70+
case JdwpConstants.CommandSet.InterfaceType.METHODS:
71+
executeMethods(bb, os);
72+
break;
73+
case JdwpConstants.CommandSet.InterfaceType.METHOD_WITH_GENERIC:
74+
executeMethodWithGeneric(bb, os);
75+
break;
76+
default:
77+
throw new NotImplementedException(
78+
"Command " + command + " not found in InterfaceType Command Set.");
79+
}
80+
}
81+
catch (IOException ex)
82+
{
83+
throw new JdwpInternalErrorException(ex);
84+
}
85+
86+
return false;
87+
}
88+
89+
/**
90+
* List methods declared in this interface.
91+
*/
92+
private void executeMethods(ByteBuffer bb, DataOutputStream os)
93+
throws JdwpException, IOException
94+
{
95+
ReferenceTypeId refId = idMan.readReferenceTypeId(bb);
96+
Class clazz = refId.getType();
97+
VmType vmType = VmType.fromClass(clazz);
98+
99+
int count = (vmType == null) ? 0 : vmType.getNoDeclaredMethods();
100+
os.writeInt(count);
101+
for (int i = 0; i < count; i++)
102+
{
103+
VmMethod vmMethod = vmType.getDeclaredMethod(i);
104+
os.writeLong(i);
105+
JdwpString.writeString(os, vmMethod.getName());
106+
JdwpString.writeString(os, vmMethod.getSignature());
107+
os.writeInt(vmMethod.getModifiers());
108+
}
109+
}
110+
111+
private void executeMethodWithGeneric(ByteBuffer bb, DataOutputStream os)
112+
throws JdwpException, IOException
113+
{
114+
// Reuse executeMethods - generic signatures are not tracked separately
115+
executeMethods(bb, os);
67116
}
68117
}

0 commit comments

Comments
 (0)