1
1
package datadog .trace .agent .tooling ;
2
2
3
+ import static java .util .Arrays .asList ;
4
+ import static java .util .Collections .emptyList ;
5
+
3
6
import datadog .trace .api .cache .DDCache ;
4
7
import datadog .trace .api .cache .DDCaches ;
8
+ import java .util .HashMap ;
9
+ import java .util .List ;
5
10
import java .util .Map ;
6
11
import net .bytebuddy .jar .asm .ClassReader ;
7
12
import net .bytebuddy .jar .asm .ClassVisitor ;
12
17
/** Shades advice bytecode by applying relocations to all references. */
13
18
public final class AdviceShader {
14
19
private final Map <String , String > relocations ;
20
+ private final List <String > helperNames ;
15
21
16
22
private volatile Remapper remapper ;
17
23
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
+ */
18
38
public static AdviceShader with (Map <String , String > relocations ) {
19
39
if (relocations != null ) {
20
- return new AdviceShader (relocations );
40
+ return new AdviceShader (relocations , emptyList () );
21
41
}
22
42
return null ;
23
43
}
24
44
25
- private AdviceShader (Map <String , String > relocations ) {
45
+ private AdviceShader (Map <String , String > relocations , List < String > helperNames ) {
26
46
this .relocations = relocations ;
47
+ this .helperNames = helperNames ;
27
48
}
28
49
29
50
/** Applies shading before calling the given {@link ClassVisitor}. */
@@ -42,13 +63,28 @@ public byte[] shadeClass(byte[] bytecode) {
42
63
return cw .toByteArray ();
43
64
}
44
65
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
+
45
75
final class AdviceMapper extends Remapper {
46
76
private final DDCache <String , String > mappingCache = DDCaches .newFixedSizeCache (64 );
47
77
48
78
/** Flattened sequence of old-prefix, new-prefix relocations. */
49
79
private final String [] prefixes ;
50
80
81
+ private final Map <String , String > helperMapping ;
82
+
51
83
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
+ }
52
88
// convert relocations to a flattened sequence: old-prefix, new-prefix, etc.
53
89
this .prefixes = new String [relocations .size () * 2 ];
54
90
int i = 0 ;
@@ -68,6 +104,10 @@ final class AdviceMapper extends Remapper {
68
104
69
105
@ Override
70
106
public String map (String internalName ) {
107
+ String uniqueName = helperMapping .get (internalName );
108
+ if (uniqueName != null ) {
109
+ return uniqueName ;
110
+ }
71
111
if (internalName .startsWith ("java/" )
72
112
|| internalName .startsWith ("datadog/" )
73
113
|| internalName .startsWith ("net/bytebuddy/" )) {
0 commit comments