@@ -102,16 +102,23 @@ public class FieldBackedProvider implements InstrumentationContextProvider {
102102 /** fields-accessor-interface-name -> fields-accessor-interface-dynamic-type */
103103 private final Map <String , DynamicType .Unloaded <?>> fieldAccessorInterfaces ;
104104
105+ private final AgentBuilder .Transformer fieldAccessorInterfacesInjector ;
106+
105107 /** context-store-type-name -> context-store-type-name-dynamic-type */
106108 private final Map <String , DynamicType .Unloaded <?>> contextStoreImplementations ;
107109
110+ private final AgentBuilder .Transformer contextStoreImplementationsInjector ;
111+
108112 private final boolean fieldInjectionEnabled ;
109113
110114 public FieldBackedProvider (final Instrumenter .Default instrumenter ) {
111115 this .instrumenter = instrumenter ;
112116 byteBuddy = new ByteBuddy ();
113117 fieldAccessorInterfaces = generateFieldAccessorInterfaces ();
118+ fieldAccessorInterfacesInjector = bootstrapHelperInjector (fieldAccessorInterfaces .values ());
114119 contextStoreImplementations = generateContextStoreImplementationClasses ();
120+ contextStoreImplementationsInjector =
121+ bootstrapHelperInjector (contextStoreImplementations .values ());
115122 fieldInjectionEnabled = Config .get ().isRuntimeContextFieldInjection ();
116123 }
117124
@@ -125,46 +132,11 @@ public AgentBuilder.Identified.Extendable instrumentationTransformer(
125132 */
126133 builder =
127134 builder .transform (getTransformerForASMVisitor (getContextStoreReadsRewritingVisitor ()));
128-
129- /**
130- * We inject into bootstrap classloader because field accessor interfaces are needed by
131- * context store implementations. Unfortunately this forces us to remove stored type checking
132- * because actual classes may not be available at this point.
133- */
134- builder = builder .transform (bootstrapHelperInjector (fieldAccessorInterfaces .values ()));
135-
136- /**
137- * We inject context store implementation into bootstrap classloader because same
138- * implementation may be used by different instrumentations and it has to use same static map
139- * in case of fallback to map-backed storage.
140- */
141- builder = builder .transform (bootstrapHelperInjector (contextStoreImplementations .values ()));
135+ builder = injectHelpersIntoBootstrapClassloader (builder );
142136 }
143137 return builder ;
144138 }
145139
146- /** Get transformer that forces helper injection onto bootstrap classloader. */
147- private AgentBuilder .Transformer bootstrapHelperInjector (
148- final Collection <DynamicType .Unloaded <?>> helpers ) {
149- return new AgentBuilder .Transformer () {
150- final HelperInjector injector = HelperInjector .forDynamicTypes (helpers );
151-
152- @ Override
153- public DynamicType .Builder <?> transform (
154- final DynamicType .Builder <?> builder ,
155- final TypeDescription typeDescription ,
156- final ClassLoader classLoader ,
157- final JavaModule module ) {
158- return injector .transform (
159- builder ,
160- typeDescription ,
161- // context store implementation classes will always go to the bootstrap
162- BOOTSTRAP_CLASSLOADER ,
163- module );
164- }
165- };
166- }
167-
168140 private AsmVisitorWrapper getContextStoreReadsRewritingVisitor () {
169141 return new AsmVisitorWrapper () {
170142 @ Override
@@ -328,9 +300,49 @@ public void visitLdcInsn(final Object value) {
328300 };
329301 }
330302
303+ private AgentBuilder .Identified .Extendable injectHelpersIntoBootstrapClassloader (
304+ AgentBuilder .Identified .Extendable builder ) {
305+ /**
306+ * We inject into bootstrap classloader because field accessor interfaces are needed by context
307+ * store implementations. Unfortunately this forces us to remove stored type checking because
308+ * actual classes may not be available at this point.
309+ */
310+ builder = builder .transform (fieldAccessorInterfacesInjector );
311+
312+ /**
313+ * We inject context store implementation into bootstrap classloader because same implementation
314+ * may be used by different instrumentations and it has to use same static map in case of
315+ * fallback to map-backed storage.
316+ */
317+ builder = builder .transform (contextStoreImplementationsInjector );
318+ return builder ;
319+ }
320+
321+ /** Get transformer that forces helper injection onto bootstrap classloader. */
322+ private AgentBuilder .Transformer bootstrapHelperInjector (
323+ final Collection <DynamicType .Unloaded <?>> helpers ) {
324+ return new AgentBuilder .Transformer () {
325+ final HelperInjector injector = HelperInjector .forDynamicTypes (helpers );
326+
327+ @ Override
328+ public DynamicType .Builder <?> transform (
329+ final DynamicType .Builder <?> builder ,
330+ final TypeDescription typeDescription ,
331+ final ClassLoader classLoader ,
332+ final JavaModule module ) {
333+ return injector .transform (
334+ builder ,
335+ typeDescription ,
336+ // context store implementation classes will always go to the bootstrap
337+ BOOTSTRAP_CLASSLOADER ,
338+ module );
339+ }
340+ };
341+ }
342+
331343 @ Override
332344 public AgentBuilder .Identified .Extendable additionalInstrumentation (
333- AgentBuilder .Identified .Extendable builder , final AgentBuilder . RawMatcher muzzleMatcher ) {
345+ AgentBuilder .Identified .Extendable builder ) {
334346
335347 if (fieldInjectionEnabled ) {
336348 for (final Map .Entry <String , String > entry : instrumenter .contextStore ().entrySet ()) {
@@ -344,16 +356,19 @@ public AgentBuilder.Identified.Extendable additionalInstrumentation(
344356 safeHasSuperType (named (entry .getKey ())).and (not (isInterface ())),
345357 instrumenter .classLoaderMatcher ())
346358 .and (safeToInjectFieldsMatcher ())
347- /**
348- * By adding the muzzleMatcher here, we are adding risk that the rules for injecting
349- * the classes into the classloader and the rules for adding the field to the class
350- * might be different. However the consequences are much greater if the class is not
351- * injected but the field is added, since that results in a NoClassDef error.
352- */
353- .and (muzzleMatcher )
354- .transform (
355- getTransformerForASMVisitor (
356- getFieldInjectionVisitor (entry .getKey (), entry .getValue ())));
359+ .transform (AgentBuilder .Transformer .NoOp .INSTANCE );
360+
361+ /**
362+ * We inject helpers here as well as when instrumentation is applied to ensure that helpers
363+ * are present even if instrumented classes are not loaded, but classes with state fields
364+ * added are loaded (e.g. sun.net.www.protocol.https.HttpsURLConnectionImpl).
365+ */
366+ builder = injectHelpersIntoBootstrapClassloader (builder );
367+
368+ builder =
369+ builder .transform (
370+ getTransformerForASMVisitor (
371+ getFieldInjectionVisitor (entry .getKey (), entry .getValue ())));
357372 }
358373 }
359374 return builder ;
0 commit comments