1

I want to instrument ScalaCheck compiled with/for scala 2.12, using JDI.

By running javap I have concluded that scalac 2.12.x emits invokedynamic instructions (for some values of x) where scala 2.11 used to generate inner classes, in particular for nested methods/functions.

This presents a challenge, since for performance reasons I would like to set and unset breakpoints on some particular nested functions (result(x: T) in Prop.forAllShrink, to be particular).

Is it possible to instrument invokedynamic code with JDI? If so, how?

I'm new to invokedynamic and unclear about how that mechanism works. My understanding is that your code (the code emitted by scalac in my example) makes a linking decision at every invokedynamic invocation, except that for performance reasons this decision is cached based on a user-specifiable criterion. However, no run-time code generation is performed. This suggests that in principle invokedynamic code should be instrumentable.

I also saw a scary name in some scalac output: deserializeLambda. I'm not quite sure what it entails, but I don't think it means I'm going to have an easy time.

Jonas Kölker
  • 7,680
  • 3
  • 44
  • 51
  • 3
    What's the bootstrap method for that callsite? Can you give me an example? (If the bootstrap method is `java.lang.invoke.LambdaMetafactory.metafactory`, then invoking the lambda will just call a private method - usually one that is given as bootstrap argument. – Johannes Kuhn Dec 15 '20 at 21:17
  • 2
    I’m struggling with the concept of setting breakpoints “for performance reasons”. Besides that, to add to Johannes Kuhn’s comment, when you assume that “no run-time code generation is performed”, the `invokedynamic` must get linked to an existing method, even when the bootstrap method differs from `LambdaMetafactory`. So you can simply set breakpoints in those target methods. – Holger Dec 16 '20 at 10:29
  • Oh, uh, I misspoke. I want to set two breakpoints, such that I can single-step from one to the other, then continue from the second back to the first. The second breakpoint doesn't necessarily have to be a breakpoint, so long as it's a detectable location. Preferably it's stable across ScalaCheck versions, although that's inherently up to what the ScalaCheck people publish. (It's the not-single-stepping from the second location back to the first where the performance gain lies.) – Jonas Kölker Dec 17 '20 at 11:18
  • 2
    The solution remains the same. Identify the already existing methods that will get linked and set the break points there. – Holger Dec 23 '20 at 13:55
  • I think in retrospect I was chasing a red herring: invokedynamic wasn't preventing me from doing things; the method I was looking for had been inlined, and I had jumped* to the conclusion that it was hidden behind invokedynamic stuff. (*) in my defense, the jump was very natural to make: invokedynamic was a big and very visible difference. – Jonas Kölker Jan 01 '21 at 21:24

0 Answers0