avoiding indy code in stack trace

10 views
Skip to first unread message

Jochen Theodorou

unread,
Feb 5, 2024, 11:38:59 AMFeb 5
to jvm-la...@googlegroups.com
Hi all,

if I have a Groovy program like this:

import java.lang.StackWalker
import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE

StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE)
walker.walk (s->s.forEach(l -> println l))

which does bascially the same it does in Java, which is writing out a
bunch of stack frames the stack walker deems worth of retaining. My
first question here would be if @Callersensitive code would actually
take the first of these "frames" to find the caller class. Is it the
same mechanism?

I assume yes, leading to a problem if the trace looks like this:

org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache(IndyInterface.java:336)
run.run(run.groovy:5)
groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:290)

run.groovy with the class "run" should be the caller class, but in this
trace IndyInterface.fromCache appears first, leading me to assume this
is what would be used instead.

In a possible module scenario there would be a Groovy runtime module
which contains the fromCache method, run.groovy would be maybe in a
module A, the target method in module B. I have no problem with module A
requires Groovy and requires B. But B would have to be open to Groovy,
well... let's just say this develops more into bypassing the module
system than anything else.

The reason why fromCache is visible is because of the invokeExact that
is in there calling the final handle. And this is in there because I
need to use something to determine the target of the method call based
on runtime types of receiver and arguments of the method call. So at
least for the first call I am stuck with this invoke call in fromCache.

Or is there a way around this and I am just to stuck to see this?

bye Jochen

Remi Forax

unread,
Feb 23, 2024, 4:02:24 AMFeb 23
to jvm-languages
Hello,
sorry for the late answer.

If you use an invoker like the MethodHandles.exactInvoker() instead of using directly invokeExact() you will not have any stackframes from your vmPlugin.
The idea is that is to have a code like that

public static CallSite bsm(Lookup lookup, String name, MethodType type) {
return new InliningCache(type);
}

private static class InliningCache extends MutableCallSite {
private static final MethodHandle SLOW_PATH;
static {
var lookup = MethodHandles.lookup();
try {
SLOW_PATH = lookup.findVirtual(InliningCache.class, "slowPath", methodType(MethodHandle.class, Object.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new AssertionError(e);
}
}

public InliningCache(MethodType type) {
super(type);
setTarget(MethodHandles.foldArguments(MethodHandles.exactInvoker(type), SLOW_PATH.bindTo(this)));
}

private MethodHandle slowPath(Object Object receiver) {
...
}
}

so your slowpath return a method handle that is call by the exactInvoker, so the method slowPath is not on the stack.

regards,
Rémi
> --
> You received this message because you are subscribed to the Google Groups "JVM
> Languages" group.
> To unsubscribe from this group and stop receiving emails from it, send an email
> to jvm-language...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/jvm-languages/b94a0432-c072-46a8-9a66-56b255f43bbc%40gmx.org.

Jochen Theodorou

unread,
Feb 23, 2024, 11:31:03 AMFeb 23
to jvm-la...@googlegroups.com
On 23.02.24 10:02, Remi Forax wrote:
> Hello,
> sorry for the late answer.

don't worry. Better late than never

> If you use an invoker like the MethodHandles.exactInvoker() instead of using directly invokeExact() you will not have any stackframes from your vmPlugin. > The idea is that is to have a code like that
>
> public static CallSite bsm(Lookup lookup, String name, MethodType type) {
> return new InliningCache(type);
> }
>
> private static class InliningCache extends MutableCallSite {
> private static final MethodHandle SLOW_PATH;
> static {
> var lookup = MethodHandles.lookup();
> try {
> SLOW_PATH = lookup.findVirtual(InliningCache.class, "slowPath", methodType(MethodHandle.class, Object.class));
> } catch (NoSuchMethodException | IllegalAccessException e) {
> throw new AssertionError(e);
> }
> }
>
> public InliningCache(MethodType type) {
> super(type);
> setTarget(MethodHandles.foldArguments(MethodHandles.exactInvoker(type), SLOW_PATH.bindTo(this)));
> }
>
> private MethodHandle slowPath(Object Object receiver) {
> ...
> }
> }
>
> so your slowpath return a method handle that is call by the exactInvoker, so the method slowPath is not on the stack.

ah... with fold it makes now sense to me!


merci beaucoup Remi

Jochen

Reply all
Reply to author
Forward
0 new messages