Skip to content

Commit 713a41a

Browse files
authored
Simplify type outlines to not implement type.getDeclaringType() and type.getEnclosingType() (#9644)
These methods are not used for matching purposes, so don't need to be maintained in outlines. There is one use of type.isAnonymousType() in IAST, but this is under a support flag - I could not find any active use of that support flag. To satisfy the original use-case (involving MyBatis) we add a simple anonymous type heuristic to that particular instrumentation, based on the '$number' Java language convention for anonymous class names. ( If necessary we can further enhance that specialized matcher without incurring overhead for all outline parsing ) Note: if anything does touch type.getDeclaringType() / type.getEnclosingType() later on when doing the final transformation then the outline type is automatically inflated to a full type. (This is already the case for other methods that aren't available in type outlines.) We also drop type.getClassFileVersion() from outlines for the same reason.
1 parent 225e336 commit 713a41a

File tree

5 files changed

+25
-70
lines changed

5 files changed

+25
-70
lines changed

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/outline/OutlineTypeParser.java

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.lang.annotation.Annotation;
88
import java.lang.reflect.Field;
99
import java.lang.reflect.Method;
10-
import net.bytebuddy.ClassFileVersion;
1110
import net.bytebuddy.description.type.TypeDescription;
1211
import net.bytebuddy.jar.asm.AnnotationVisitor;
1312
import net.bytebuddy.jar.asm.ClassReader;
@@ -34,17 +33,11 @@ public TypeDescription parse(Class<?> loadedType) {
3433

3534
TypeOutline typeOutline =
3635
new TypeOutline(
37-
ClassFileVersion.ofThisVm().getMinorMajorVersion(),
3836
loadedType.getModifiers(),
3937
loadedType.getName(),
4038
null != superClass ? superClass.getName() : null,
4139
extractTypeNames(loadedType.getInterfaces()));
4240

43-
Class<?> declaringClass = loadedType.getDeclaringClass();
44-
if (null != declaringClass) {
45-
typeOutline.declaredBy(declaringClass.getName());
46-
}
47-
4841
for (Annotation a : loadedType.getDeclaredAnnotations()) {
4942
typeOutline.declare(annotationOutline(Type.getDescriptor(a.annotationType())));
5043
}
@@ -91,7 +84,6 @@ static final class OutlineTypeExtractor extends ClassVisitor {
9184
TypeOutline typeOutline;
9285
FieldOutline fieldOutline;
9386
MethodOutline methodOutline;
94-
boolean selfContained = true;
9587

9688
OutlineTypeExtractor() {
9789
super(OpenedClassReader.ASM_API);
@@ -105,23 +97,7 @@ public void visit(
10597
String signature,
10698
String superName,
10799
String[] interfaces) {
108-
typeOutline = new TypeOutline(version, access, name, superName, interfaces);
109-
}
110-
111-
@Override
112-
public void visitOuterClass(String owner, String name, String descriptor) {
113-
selfContained = false;
114-
}
115-
116-
@Override
117-
public void visitInnerClass(String name, String outerName, String innerName, int access) {
118-
if (typeOutline.getInternalName().equals(name)) {
119-
if (null != outerName) {
120-
typeOutline.declaredBy(outerName);
121-
} else if (null == innerName && !selfContained) {
122-
typeOutline.anonymousType();
123-
}
124-
}
100+
typeOutline = new TypeOutline(access, name, superName, interfaces);
125101
}
126102

127103
@Override

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/outline/TypeFactory.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,6 @@ public TypeList.Generic getInterfaces() {
383383
return outline().getInterfaces();
384384
}
385385

386-
@Override
387-
public TypeDescription getDeclaringType() {
388-
return outline().getDeclaringType();
389-
}
390-
391386
@Override
392387
public boolean isPublic() {
393388
return isPublicFilter.contains(name) || super.isPublic();

dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/outline/TypeOutline.java

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import java.util.ArrayList;
66
import java.util.List;
7-
import net.bytebuddy.ClassFileVersion;
87
import net.bytebuddy.description.annotation.AnnotationDescription;
98
import net.bytebuddy.description.annotation.AnnotationList;
109
import net.bytebuddy.description.field.FieldDescription;
@@ -27,21 +26,17 @@ final class TypeOutline extends WithName {
2726
private static final MethodList<MethodDescription.InDefinedShape> NO_METHODS =
2827
new MethodList.Empty<>();
2928

30-
private final int classFileVersion;
3129
private final int modifiers;
3230
private final String superName;
3331
private final String[] interfaces;
34-
private String declaringName;
35-
private boolean anonymousType;
3632

3733
private List<AnnotationDescription> declaredAnnotations;
3834

3935
private final List<FieldDescription.InDefinedShape> declaredFields = new ArrayList<>();
4036
private final List<MethodDescription.InDefinedShape> declaredMethods = new ArrayList<>();
4137

42-
TypeOutline(int version, int access, String internalName, String superName, String[] interfaces) {
38+
TypeOutline(int access, String internalName, String superName, String[] interfaces) {
4339
super(internalName.replace('/', '.'));
44-
this.classFileVersion = version;
4540
this.modifiers = access & ALLOWED_TYPE_MODIFIERS;
4641
this.superName = superName;
4742
this.interfaces = interfaces;
@@ -72,19 +67,6 @@ public TypeList.Generic getInterfaces() {
7267
return new TypeList.Generic.Explicit(outlines);
7368
}
7469

75-
@Override
76-
public TypeDescription getDeclaringType() {
77-
if (null != declaringName) {
78-
return findType(declaringName.replace('/', '.'));
79-
}
80-
return null;
81-
}
82-
83-
@Override
84-
public TypeDescription getEnclosingType() {
85-
return getDeclaringType(); // equivalent for outline purposes
86-
}
87-
8870
@Override
8971
public int getModifiers() {
9072
return modifiers;
@@ -114,11 +96,6 @@ private boolean matchesMask(int mask) {
11496
return (this.getModifiers() & mask) == mask;
11597
}
11698

117-
@Override
118-
public ClassFileVersion getClassFileVersion() {
119-
return ClassFileVersion.ofMinorMajor(classFileVersion);
120-
}
121-
12299
@Override
123100
public AnnotationList getDeclaredAnnotations() {
124101
return null == declaredAnnotations
@@ -136,15 +113,6 @@ public MethodList<MethodDescription.InDefinedShape> getDeclaredMethods() {
136113
return declaredMethods.isEmpty() ? NO_METHODS : new MethodList.Explicit<>(declaredMethods);
137114
}
138115

139-
@Override
140-
public boolean isAnonymousType() {
141-
return anonymousType;
142-
}
143-
144-
void declaredBy(String declaringName) {
145-
this.declaringName = declaringName;
146-
}
147-
148116
void declare(AnnotationDescription annotation) {
149117
if (null != annotation) {
150118
if (null == declaredAnnotations) {
@@ -165,8 +133,4 @@ void declare(MethodDescription.InDefinedShape method) {
165133
declaredMethods.add(method);
166134
}
167135
}
168-
169-
void anonymousType() {
170-
anonymousType = true;
171-
}
172136
}

dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/outline/OutlineTypeParserTest.groovy

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import spock.lang.Specification
55

66
class OutlineTypeParserTest extends Specification {
77

8-
void 'test modifiers are correct and anonymous classes are detected'() {
8+
void 'test modifiers are correct'() {
99
setup:
1010
final parser = new OutlineTypeParser()
1111
final locator = ClassFileLocators.classFileLocator(Thread.currentThread().contextClassLoader)
@@ -15,12 +15,13 @@ class OutlineTypeParserTest extends Specification {
1515
final outline = parser.parse(bytes)
1616

1717
then:
18-
outline.anonymousType == anonymous
1918
outline.interface == isinterface
2019
outline.abstract == isabstract
2120
outline.annotation == annotation
2221
outline.enum == isenum
2322

23+
// isAnonymousType is no longer supported in outlines for performance reasons
24+
2425
where:
2526
clazz | anonymous | isinterface | isabstract | annotation | isenum
2627
'datadog.trace.agent.test.EnclosedClasses' | false | false | false | false | false

dd-java-agent/instrumentation/iast-instrumenter/src/main/java/datadog/trace/instrumentation/iastinstrumenter/IastInstrumentation.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,30 @@ protected boolean doMatch(TypeDescription target) {
7676
}
7777
};
7878

79+
// this deliberately only considers anonymous types following the Java naming convention
80+
private static final ElementMatcher.Junction<TypeDescription> ANONYMOUS_TYPE_MATCHER =
81+
new ElementMatcher.Junction.ForNonNullValues<TypeDescription>() {
82+
@Override
83+
protected boolean doMatch(TypeDescription target) {
84+
String name = target.getName();
85+
// search the name in reverse until we find a $ or non-digit
86+
for (int end = name.length() - 1, i = end; i > 0; i--) {
87+
char c = name.charAt(i);
88+
if (c == '$' && i < end) {
89+
return true; // only seen digits so far, assume anonymous
90+
} else if (c < '0' || c > '9') {
91+
break; // non-digit character found, assume not anonymous
92+
}
93+
}
94+
return false;
95+
}
96+
};
97+
7998
static {
8099
if (Config.get().isIastAnonymousClassesEnabled()) {
81100
INSTANCE = TRIE_MATCHER;
82101
} else {
83-
INSTANCE = TRIE_MATCHER.and(not(TypeDescription::isAnonymousType));
102+
INSTANCE = TRIE_MATCHER.and(not(ANONYMOUS_TYPE_MATCHER));
84103
}
85104
}
86105
}

0 commit comments

Comments
 (0)