Skip to content

Commit fd668dc

Browse files
committed
8295537: Enhance TRACE_METHOD_LINKAGE to show the target MethodHandle
Reviewed-by: jvernee, redestad, mchung
1 parent 182c215 commit fd668dc

File tree

5 files changed

+75
-14
lines changed

5 files changed

+75
-14
lines changed

src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java

+14-6
Original file line numberDiff line numberDiff line change
@@ -158,21 +158,29 @@ static BoundMethodHandle.SpeciesData speciesDataFor(LambdaForm form) {
158158
final int fieldCount() { return speciesData().fieldCount(); }
159159

160160
@Override
161-
Object internalProperties() {
162-
return "\n& BMH="+internalValues();
161+
Object internalProperties(int indentLevel) {
162+
return "\n" + debugPrefix(indentLevel) + "& BMH=" + internalValues(indentLevel);
163163
}
164164

165165
@Override
166-
final String internalValues() {
166+
final String internalValues(int indentLevel) {
167+
String prefix = debugPrefix(indentLevel);
167168
int count = fieldCount();
168-
if (count == 1) {
169+
if (count == 1 && indentLevel < 0) {
169170
return "[" + arg(0) + "]";
170171
}
171172
StringBuilder sb = new StringBuilder("[");
172173
for (int i = 0; i < count; ++i) {
173-
sb.append("\n ").append(i).append(": ( ").append(arg(i)).append(" )");
174+
Object theArg = arg(i);
175+
sb.append("\n ").append(prefix).append(i);
176+
if (indentLevel >= 0 && theArg instanceof MethodHandle) {
177+
sb.append(": MethodHandle = {").append(((MethodHandle)theArg).debugString(indentLevel+1));
178+
sb.append("\n ").append(prefix).append("}");
179+
} else {
180+
sb.append(": ( ").append(theArg).append(" )");
181+
}
174182
}
175-
return sb.append("\n]").toString();
183+
return sb.append("\n").append(prefix).append("]").toString();
176184
}
177185

178186
/*non-public*/

src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ boolean isCrackable() {
170170
}
171171

172172
@Override
173-
String internalProperties() {
174-
return "\n& DMH.MN="+internalMemberName();
173+
String internalProperties(int indentLevel) {
174+
return "\n" + debugPrefix(indentLevel) + "& DMH.MN=" + internalMemberName();
175175
}
176176

177177
//// Implementation methods.

src/java.base/share/classes/java/lang/invoke/LambdaForm.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -1029,12 +1029,18 @@ else if (result == arity && names.length == arity + 1)
10291029
}
10301030

10311031
public String toString() {
1032+
return debugString(-1);
1033+
}
1034+
1035+
String debugString(int indentLevel) {
1036+
String prefix = MethodHandle.debugPrefix(indentLevel);
10321037
String lambdaName = lambdaName();
1033-
StringBuilder buf = new StringBuilder(lambdaName + "=Lambda(");
1038+
StringBuilder buf = new StringBuilder(lambdaName);
1039+
buf.append("=Lambda(");
10341040
for (int i = 0; i < names.length; i++) {
10351041
if (i == arity) buf.append(")=>{");
10361042
Name n = names[i];
1037-
if (i >= arity) buf.append("\n ");
1043+
if (i >= arity) buf.append("\n ").append(prefix);
10381044
buf.append(n.paramString());
10391045
if (i < arity) {
10401046
if (i+1 < arity) buf.append(",");

src/java.base/share/classes/java/lang/invoke/MethodHandle.java

+29-2
Original file line numberDiff line numberDiff line change
@@ -1688,9 +1688,19 @@ String standardString() {
16881688
}
16891689
/** Return a string with a several lines describing the method handle structure.
16901690
* This string would be suitable for display in an IDE debugger.
1691+
* @param indentLevel If negative, return only information about this MethodHandle.
1692+
* Otherwise, return information about this MethodHandle and (recursively) all other
1693+
* MethodHandles, if any, that are invoked directly or indirectly by this MethodHandle.
1694+
* During the recursion, `indentLevel` is incremented (see
1695+
* BoundMethodHandle.internalValues()) to improve readability of
1696+
* the nested structure.
16911697
*/
1698+
String debugString(int indentLevel) {
1699+
return type + " : " + internalForm().debugString(indentLevel) +
1700+
internalProperties(indentLevel);
1701+
}
16921702
String debugString() {
1693-
return type+" : "+internalForm()+internalProperties();
1703+
return debugString(-1);
16941704
}
16951705

16961706
//// Implementation methods.
@@ -1787,12 +1797,29 @@ boolean isCrackable() {
17871797
}
17881798

17891799
/*non-public*/
1790-
Object internalValues() {
1800+
Object internalValues(int indentLevel) {
17911801
return null;
17921802
}
17931803

1804+
/**
1805+
* Various debugging methods in MethodHandle (and subclasses thereof) and LambdaForm
1806+
* take an `indentLevel` argument, so that {@link java.lang.invoke.MethodHandle.debugString(int)}
1807+
* can return nested structures in a readable fashion. This method returns a string to be
1808+
* prepended to each line at the specified level.
1809+
*/
1810+
static String debugPrefix(int indentLevel) {
1811+
if (indentLevel <= 0) {
1812+
return "";
1813+
}
1814+
return " ".repeat(indentLevel);
1815+
}
1816+
17941817
/*non-public*/
17951818
Object internalProperties() {
1819+
return internalProperties(-1);
1820+
}
1821+
1822+
Object internalProperties(int indentLevel) {
17961823
// Override to something to follow this.form, like "\n& FOO=bar"
17971824
return "";
17981825
}

src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java

+22-2
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,12 @@ static MemberName linkCallSiteImpl(Class<?> caller,
281281
type,
282282
staticArguments,
283283
caller);
284+
if (TRACE_METHOD_LINKAGE) {
285+
MethodHandle target = callSite.getTarget();
286+
System.out.println("linkCallSite target class => " + target.getClass().getName());
287+
System.out.println("linkCallSite target => " + target.debugString(0));
288+
}
289+
284290
if (callSite instanceof ConstantCallSite) {
285291
appendixResult[0] = callSite.dynamicInvoker();
286292
return Invokers.linkToTargetMethod(type);
@@ -298,13 +304,13 @@ static MemberName linkCallSiteTracing(Class<?> caller,
298304
Object bsmReference = bootstrapMethod.internalMemberName();
299305
if (bsmReference == null) bsmReference = bootstrapMethod;
300306
String staticArglist = staticArglistForTrace(staticArguments);
301-
System.out.println("linkCallSite "+caller.getName()+" "+
307+
System.out.println("linkCallSite "+getCallerInfo(caller)+" "+
302308
bsmReference+" "+
303309
name+type+"/"+staticArglist);
304310
try {
305311
MemberName res = linkCallSiteImpl(caller, bootstrapMethod, name, type,
306312
staticArguments, appendixResult);
307-
System.out.println("linkCallSite => "+res+" + "+appendixResult[0]);
313+
System.out.println("linkCallSite linkage => "+res+" + "+appendixResult[0]);
308314
return res;
309315
} catch (Throwable ex) {
310316
ex.printStackTrace(); // print now in case exception is swallowed
@@ -313,6 +319,20 @@ static MemberName linkCallSiteTracing(Class<?> caller,
313319
}
314320
}
315321

322+
/**
323+
* Return a human-readable description of the caller. Something like
324+
* "java.base/java.security.Security.<clinit>(Security.java:82)"
325+
*/
326+
private static String getCallerInfo(Class<?> caller) {
327+
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
328+
if (e.getClassName().equals(caller.getName())) {
329+
return e.toString();
330+
}
331+
}
332+
// fallback if the caller is somehow missing from the stack.
333+
return caller.getName();
334+
}
335+
316336
// this implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant:
317337
static Object linkDynamicConstant(Object callerObj,
318338
Object bootstrapMethodObj,

0 commit comments

Comments
 (0)