2

I patched the java.lang.ref.Reference class to call a custom native method whenever get() is called. The patched class is prepended to the bootstrap classpath.

When I start a sample program I see lot of print outs coming from my native method (as expected) as there are lot of References used internally by the JDK.

The strange behavior starts in my main method. All I'm doing is creating a WeakReference to an object, deleting the strong one and calling get(). For whatever reason the native method I added does not seem to be called in run mode and I do not get any print outs nor other events that are happening inside the native.

If I start the program in debug mode everything works as expected, i.e. the native method is called.

If I change the WeakReference to a SoftReference it always works, also in normal run mode.

I even tried adding other code (like a System.out.println to the get()) but that also did not work. The printing somehow stops for my WeakReference when running in non-debug mode. In debug it always works.

Sometimes I even get a lot of events / print outs from Finalizers after my main, during shut down. So it really seems like the Reference class somehow behaves differently.

Haasip Satang
  • 457
  • 3
  • 17

1 Answers1

5

java.lang.ref.Reference.get() is a JVM intrinsic method.

This means that once the method is JIT-compiled, its Java implementation is not called anymore. HotSpot compiler replaces a call to Reference.get with a special manually optimized sequence hardcoded in HotSpot sources.

At JVM startup the method is not yet JIT-compiled, i.e. its Java implementation is interpreted, and intrinsic does not work.

SoftReference overrides the method, so Reference.get intrinsic does not work for it either.

You may disable this intrinsic with the following JVM flags, and your modified version will always work, even after the method is JIT-compiled:

-XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_Reference_get

Here is the list of other intrinsic methods in JDK.

apangin
  • 92,924
  • 10
  • 193
  • 247
  • You are the man! Wasn't aware of the hardcoded intrinsics and hence excluded JIT from my considerations as naively I thought "will be JIT compiled, but logic will remain". The flags did not work though. Neither `-XX:DisableIntrinsic=_Reference_get` nor what was suggested [here](https://stackoverflow.com/questions/30370959/how-to-disable-intrinsics-usage-for-the-jit-compiler) to disable all. `-XX:CompileCommand="exclude java/lang/ref/Reference get"` did the job though, but I think I better go with a subclass of `WeakReference` and dynamically replace all code to use that one instead. Thanks! – Haasip Satang Jul 19 '18 at 09:57
  • @HaasipSatang Ah, right: `-XX:DisableIntrinsic` disables C2 intrinsic, but the method is still intrinsified by C1. – apangin Jul 19 '18 at 13:09