11package datadog .trace .agent .tooling ;
22
3+ import static java .util .Arrays .asList ;
4+ import static java .util .Collections .emptyList ;
5+
36import datadog .trace .api .cache .DDCache ;
47import datadog .trace .api .cache .DDCaches ;
8+ import java .util .HashMap ;
9+ import java .util .List ;
510import java .util .Map ;
611import net .bytebuddy .jar .asm .ClassReader ;
712import net .bytebuddy .jar .asm .ClassVisitor ;
1217/** Shades advice bytecode by applying relocations to all references. */
1318public final class AdviceShader {
1419 private final Map <String , String > relocations ;
20+ private final List <String > helperNames ;
1521
1622 private volatile Remapper remapper ;
1723
24+ /**
25+ * Used when installing {@link InstrumenterModule}s. Ensures any injected helpers have unique
26+ * names so the original and relocated modules can inject helpers into the same class-loader.
27+ */
28+ public static AdviceShader with (InstrumenterModule module ) {
29+ if (module .adviceShading () != null ) {
30+ return new AdviceShader (module .adviceShading (), asList (module .helperClassNames ()));
31+ }
32+ return null ;
33+ }
34+
35+ /** Used to generate and check muzzle references. Only applies relocations declared in modules. */
1836 public static AdviceShader with (Map <String , String > relocations ) {
1937 if (relocations != null ) {
20- return new AdviceShader (relocations );
38+ return new AdviceShader (relocations , emptyList () );
2139 }
2240 return null ;
2341 }
2442
25- private AdviceShader (Map <String , String > relocations ) {
43+ private AdviceShader (Map <String , String > relocations , List < String > helperNames ) {
2644 this .relocations = relocations ;
45+ this .helperNames = helperNames ;
2746 }
2847
2948 /** Applies shading before calling the given {@link ClassVisitor}. */
@@ -42,13 +61,29 @@ public byte[] shadeClass(byte[] bytecode) {
4261 return cw .toByteArray ();
4362 }
4463
64+ /** Generates a unique shaded name for the given helper. */
65+ public String uniqueHelper (String dottedName ) {
66+ int packageEnd = dottedName .lastIndexOf ('.' );
67+ if (packageEnd > 0 ) {
68+ return dottedName .substring (0 , packageEnd + 1 ) + "shaded" + dottedName .substring (packageEnd );
69+ }
70+ return dottedName ;
71+ }
72+
4573 final class AdviceMapper extends Remapper {
4674 private final DDCache <String , String > mappingCache = DDCaches .newFixedSizeCache (64 );
4775
4876 /** Flattened sequence of old-prefix, new-prefix relocations. */
4977 private final String [] prefixes ;
5078
79+ private final Map <String , String > helperMapping ;
80+
5181 AdviceMapper () {
82+ // record the unique names that we've given to injected helpers
83+ this .helperMapping = new HashMap <>(helperNames .size () + 1 , 1f );
84+ for (String h : helperNames ) {
85+ this .helperMapping .put (h .replace ('.' , '/' ), uniqueHelper (h ).replace ('.' , '/' ));
86+ }
5287 // convert relocations to a flattened sequence: old-prefix, new-prefix, etc.
5388 this .prefixes = new String [relocations .size () * 2 ];
5489 int i = 0 ;
@@ -68,6 +103,10 @@ final class AdviceMapper extends Remapper {
68103
69104 @ Override
70105 public String map (String internalName ) {
106+ String uniqueName = helperMapping .get (internalName );
107+ if (uniqueName != null ) {
108+ return uniqueName ;
109+ }
71110 if (internalName .startsWith ("java/" )
72111 || internalName .startsWith ("datadog/" )
73112 || internalName .startsWith ("net/bytebuddy/" )) {
0 commit comments