-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Agent can inject class into Java 9+ bootstrap class loader #829
Conversation
8a04cf2
to
08a9ed6
Compare
@Godin I would prefer to implement a separate What I don't like about re-using |
08a9ed6
to
1563c40
Compare
@marchof implemented |
1563c40
to
b909550
Compare
b909550
to
1cb7500
Compare
@Godin As a first step I directly fixed Eclipse warnings, hope this is ok for you. Will have a closer look now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions...
org.jacoco.core/src/org/jacoco/core/internal/runtime/ClassInjectionRuntime.java
Outdated
Show resolved
Hide resolved
org.jacoco.core/src/org/jacoco/core/internal/runtime/ClassInjectionRuntime.java
Outdated
Show resolved
Hide resolved
org.jacoco.core.test/src/org/jacoco/core/runtime/RuntimeTestBase.java
Outdated
Show resolved
Hide resolved
org.jacoco.core/src/org/jacoco/core/internal/runtime/ClassInjectionRuntime.java
Outdated
Show resolved
Hide resolved
*/ | ||
public static IRuntime create(final Instrumentation instrumentation) { | ||
try { | ||
redefineJavaBaseModule(instrumentation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the best error handling strategy here?
A) Just check whether we're on Java 9 and then fail if this runtime can't be initialized?
B) Ignore any error while initialization and simply fall back to ModifiedSystemRuntime
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed implementation from second to first.
org.jacoco.core/src/org/jacoco/core/internal/runtime/ClassInjectionRuntime.java
Outdated
Show resolved
Hide resolved
org.jacoco.core/src/org/jacoco/core/internal/runtime/ClassInjectionRuntime.java
Outdated
Show resolved
Hide resolved
org.jacoco.core.test/src/org/jacoco/core/internal/runtime/ClassInjectionRuntimeTest.java
Outdated
Show resolved
Hide resolved
org.jacoco.core/src/org/jacoco/core/internal/runtime/ClassInjectionRuntime.java
Outdated
Show resolved
Hide resolved
5c811d3
to
1c94a07
Compare
Lookup.lookup() // | ||
.bind( // | ||
instrumentation, // | ||
"redefineModule", // |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marchof doh, not only reflection, but even this doesn't work in case of --illegal-access=deny
😢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact
instrumentation.getClass().getMethod(...).invoke(...)
and
Lookup.lookup().bind(instrumentation, ...).invokeWithArguments(...)
are illegal, whereas
java.lang.Instrumentation.class.getMethod(...).invoke(...)
and
Lookup.lookup().findVirtual(java.lang.Instrumentation.class, ...).invokeWithArguments(...)
are legal, because instrumentation.getClass()
is sun.instrument.InstrumentationImpl
and
module java.instrument {
exports java.lang.instrument;
// allow java launcher to load agents in executable JAR files
exports sun.instrument to java.base;
}
71eadd8
to
36655f5
Compare
org.jacoco.core/src/org/jacoco/core/runtime/ClassInjectionRuntime.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Godin I really like this reworked, very concise version, thanks! I came across two minor formal issues, please decide whether you want to address them.
Starting from JDK 9 there is
java.lang.invoke.MethodHandles.Lookup.defineClass
that can define class even in bootstrap classloader
when
java.base
module opensjava.lang
package to module of agent,what can be done by agent itself using
java.lang.instrument.Instrumentation.redefineModule
This way agent can be used with JDKs compiled into bytecode version whose instrumentation is not yet supported, e.g. JDK 13 EA (now each new JDK version is compiled into a new bytecode version). And I believe that majority of people do not compile their code into new bytecode version when testing new JDK EA builds, so this will be already useful for them.
For this use-case such approach is IMO
Furthermore this approach allows to get rid of conflicts with other agents on JDK 9+.
I wrapped reflective calls of these methods into few helper classes to keep compatibility with JDK 5.