mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-16 00:19:27 +00:00
8156738: Use StackWalker for DynamicLinker.getLinkedCallSiteLocation
Reviewed-by: hannesw, sundar
This commit is contained in:
parent
1de3636e0f
commit
860e71a134
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -83,6 +83,7 @@
|
||||
|
||||
package jdk.dynalink;
|
||||
|
||||
import java.lang.StackWalker.StackFrame;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
@ -172,6 +173,8 @@ public final class DynamicLinker {
|
||||
private static final String INITIAL_LINK_METHOD_NAME = "linkCallSite";
|
||||
private static final String INVOKE_PACKAGE_PREFIX = "java.lang.invoke.";
|
||||
|
||||
private static final StackWalker stackWalker = StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES);
|
||||
|
||||
private final LinkerServices linkerServices;
|
||||
private final GuardedInvocationTransformer prelinkTransformer;
|
||||
private final boolean syncOnRelink;
|
||||
@ -300,21 +303,16 @@ public final class DynamicLinker {
|
||||
* site is being linked.
|
||||
*/
|
||||
public static StackTraceElement getLinkedCallSiteLocation() {
|
||||
final StackTraceElement[] trace = new Throwable().getStackTrace();
|
||||
for(int i = 0; i < trace.length - 1; ++i) {
|
||||
final StackTraceElement frame = trace[i];
|
||||
// If we found any of our linking entry points on the stack...
|
||||
if(isRelinkFrame(frame) || isInitialLinkFrame(frame)) {
|
||||
return stackWalker.walk(s -> s
|
||||
// Find one of our linking entry points on the stack...
|
||||
.dropWhile(f -> !(isRelinkFrame(f) || isInitialLinkFrame(f)))
|
||||
.skip(1)
|
||||
// ... then look for the first thing calling it that isn't j.l.invoke
|
||||
for (int j = i + 1; j < trace.length; ++j) {
|
||||
final StackTraceElement frame2 = trace[j];
|
||||
if (!frame2.getClassName().startsWith(INVOKE_PACKAGE_PREFIX)) {
|
||||
return frame2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
.dropWhile(f -> f.getClassName().startsWith(INVOKE_PACKAGE_PREFIX))
|
||||
.findFirst()
|
||||
.map(StackFrame::toStackTraceElement)
|
||||
.orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -326,7 +324,7 @@ public final class DynamicLinker {
|
||||
*
|
||||
* @return {@code true} if this frame represents {@code MethodHandleNatives.linkCallSite()}.
|
||||
*/
|
||||
private static boolean isInitialLinkFrame(final StackTraceElement frame) {
|
||||
private static boolean isInitialLinkFrame(final StackFrame frame) {
|
||||
return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME);
|
||||
}
|
||||
|
||||
@ -339,11 +337,11 @@ public final class DynamicLinker {
|
||||
*
|
||||
* @return {@code true} if this frame represents {@code DynamicLinker.relink()}.
|
||||
*/
|
||||
private static boolean isRelinkFrame(final StackTraceElement frame) {
|
||||
private static boolean isRelinkFrame(final StackFrame frame) {
|
||||
return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME);
|
||||
}
|
||||
|
||||
private static boolean testFrame(final StackTraceElement frame, final String methodName, final String className) {
|
||||
private static boolean testFrame(final StackFrame frame, final String methodName, final String className) {
|
||||
return methodName.equals(frame.getMethodName()) && className.equals(frame.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.dynalink.test;
|
||||
|
||||
import static jdk.dynalink.StandardOperation.CALL_METHOD;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.dynalink.CallSiteDescriptor;
|
||||
import jdk.dynalink.DynamicLinker;
|
||||
import jdk.dynalink.DynamicLinkerFactory;
|
||||
import jdk.dynalink.NamedOperation;
|
||||
import jdk.dynalink.linker.GuardingDynamicLinker;
|
||||
import jdk.dynalink.support.SimpleRelinkableCallSite;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class LinkedCallSiteLocationTest {
|
||||
@Test
|
||||
public void testLinkedCallSiteLocation() throws Throwable {
|
||||
final StackTraceElement[] lastLinked = new StackTraceElement[1];
|
||||
|
||||
final GuardingDynamicLinker testLinker =
|
||||
(r, s) -> { lastLinked[0] = DynamicLinker.getLinkedCallSiteLocation(); return null; };
|
||||
|
||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||
factory.setPrioritizedLinker(testLinker);
|
||||
final DynamicLinker linker = factory.createLinker();
|
||||
final SimpleRelinkableCallSite callSite = new SimpleRelinkableCallSite(
|
||||
new CallSiteDescriptor(
|
||||
MethodHandles.lookup(),
|
||||
new NamedOperation(CALL_METHOD, "foo"),
|
||||
MethodType.methodType(void.class, Object.class)));
|
||||
linker.link(callSite);
|
||||
|
||||
// Test initial linking
|
||||
callSite.dynamicInvoker().invoke(new TestClass1()); final int l1 = getLineNumber();
|
||||
assertLocation(lastLinked[0], l1);
|
||||
|
||||
// Test relinking
|
||||
callSite.dynamicInvoker().invoke(new TestClass2()); final int l2 = getLineNumber();
|
||||
assertLocation(lastLinked[0], l2);
|
||||
}
|
||||
|
||||
private void assertLocation(final StackTraceElement frame, final int lineNumber) {
|
||||
Assert.assertNotNull(frame);
|
||||
Assert.assertEquals(frame.getLineNumber(), lineNumber);
|
||||
Assert.assertEquals(frame.getClassName(), this.getClass().getName());
|
||||
}
|
||||
|
||||
private static int getLineNumber() {
|
||||
return StackWalker.getInstance().walk(s -> s.skip(1).findFirst().get().getLineNumber().getAsInt());
|
||||
}
|
||||
|
||||
public static class TestClass1 {
|
||||
public void foo() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestClass2 {
|
||||
public void foo() {
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user