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+ /**
36+ * Used to generate and check muzzle references. Only applies relocations declared in modules.
37+ */
1838 public static AdviceShader with (Map <String , String > relocations ) {
1939 if (relocations != null ) {
20- return new AdviceShader (relocations );
40+ return new AdviceShader (relocations , emptyList () );
2141 }
2242 return null ;
2343 }
2444
25- private AdviceShader (Map <String , String > relocations ) {
45+ private AdviceShader (Map <String , String > relocations , List < String > helperNames ) {
2646 this .relocations = relocations ;
47+ this .helperNames = helperNames ;
2748 }
2849
2950 /** Applies shading before calling the given {@link ClassVisitor}. */
@@ -42,13 +63,28 @@ public byte[] shadeClass(byte[] bytecode) {
4263 return cw .toByteArray ();
4364 }
4465
66+ /** Generates a unique shaded name for the given helper. */
67+ public String uniqueHelper (String dottedName ) {
68+ int packageEnd = dottedName .lastIndexOf ('.' );
69+ if (packageEnd > 0 ) {
70+ return dottedName .substring (0 , packageEnd + 1 ) + "shaded" + dottedName .substring (packageEnd );
71+ }
72+ return dottedName ;
73+ }
74+
4575 final class AdviceMapper extends Remapper {
4676 private final DDCache <String , String > mappingCache = DDCaches .newFixedSizeCache (64 );
4777
4878 /** Flattened sequence of old-prefix, new-prefix relocations. */
4979 private final String [] prefixes ;
5080
81+ private final Map <String , String > helperMapping ;
82+
5183 AdviceMapper () {
84+ this .helperMapping = new HashMap <>(helperNames .size () + 1 , 1f );
85+ for (String h : helperNames ) {
86+ this .helperMapping .put (h .replace ('.' , '/' ), uniqueHelper (h ).replace ('.' , '/' ));
87+ }
5288 // convert relocations to a flattened sequence: old-prefix, new-prefix, etc.
5389 this .prefixes = new String [relocations .size () * 2 ];
5490 int i = 0 ;
@@ -68,6 +104,10 @@ final class AdviceMapper extends Remapper {
68104
69105 @ Override
70106 public String map (String internalName ) {
107+ String uniqueName = helperMapping .get (internalName );
108+ if (uniqueName != null ) {
109+ return uniqueName ;
110+ }
71111 if (internalName .startsWith ("java/" )
72112 || internalName .startsWith ("datadog/" )
73113 || internalName .startsWith ("net/bytebuddy/" )) {
0 commit comments