mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8339742: Refactor ClassFileImpl to allow loading Option classes lazily
Reviewed-by: asotona
This commit is contained in:
parent
c54fc08aa3
commit
d53e405a26
7 changed files with 135 additions and 64 deletions
|
@ -51,7 +51,7 @@ public class AbstractDirectBuilder<M> {
|
|||
}
|
||||
|
||||
public void writeAttribute(Attribute<?> a) {
|
||||
if (Util.isAttributeAllowed(a, context.attributesProcessingOption())) {
|
||||
if (Util.isAttributeAllowed(a, context)) {
|
||||
attributes.withAttribute(a);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.function.Consumer;
|
|||
|
||||
import java.lang.classfile.AttributeMapper;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassFile.*;
|
||||
import java.lang.classfile.ClassBuilder;
|
||||
import java.lang.classfile.ClassHierarchyResolver;
|
||||
import java.lang.classfile.ClassModel;
|
||||
|
@ -41,33 +40,53 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder;
|
|||
import java.lang.classfile.constantpool.Utf8Entry;
|
||||
import jdk.internal.classfile.impl.verifier.VerifierImpl;
|
||||
|
||||
public record ClassFileImpl(StackMapsOption stackMapsOption,
|
||||
DebugElementsOption debugElementsOption,
|
||||
LineNumbersOption lineNumbersOption,
|
||||
AttributesProcessingOption attributesProcessingOption,
|
||||
ConstantPoolSharingOption constantPoolSharingOption,
|
||||
ShortJumpsOption shortJumpsOption,
|
||||
DeadCodeOption deadCodeOption,
|
||||
DeadLabelsOption deadLabelsOption,
|
||||
ClassHierarchyResolverOption classHierarchyResolverOption,
|
||||
AttributeMapperOption attributeMapperOption) implements ClassFile {
|
||||
public final class ClassFileImpl implements ClassFile {
|
||||
|
||||
private Option stackMapsOption;
|
||||
private Option debugElementsOption;
|
||||
private Option lineNumbersOption;
|
||||
private Option attributesProcessingOption;
|
||||
private Option constantPoolSharingOption;
|
||||
private Option shortJumpsOption;
|
||||
private Option deadCodeOption;
|
||||
private Option deadLabelsOption;
|
||||
private Option classHierarchyResolverOption;
|
||||
private Option attributeMapperOption;
|
||||
|
||||
private ClassFileImpl(Option stackMapsOption,
|
||||
Option debugElementsOption,
|
||||
Option lineNumbersOption,
|
||||
Option attributesProcessingOption,
|
||||
Option constantPoolSharingOption,
|
||||
Option shortJumpsOption,
|
||||
Option deadCodeOption,
|
||||
Option deadLabelsOption,
|
||||
Option classHierarchyResolverOption,
|
||||
Option attributeMapperOption) {
|
||||
this.stackMapsOption = stackMapsOption;
|
||||
this.debugElementsOption = debugElementsOption;
|
||||
this.lineNumbersOption = lineNumbersOption;
|
||||
this.attributesProcessingOption = attributesProcessingOption;
|
||||
this.constantPoolSharingOption = constantPoolSharingOption;
|
||||
this.shortJumpsOption = shortJumpsOption;
|
||||
this.deadCodeOption = deadCodeOption;
|
||||
this.deadLabelsOption = deadLabelsOption;
|
||||
this.classHierarchyResolverOption = classHierarchyResolverOption;
|
||||
this.attributeMapperOption = attributeMapperOption;
|
||||
}
|
||||
|
||||
public static final ClassFileImpl DEFAULT_CONTEXT = new ClassFileImpl(
|
||||
StackMapsOption.STACK_MAPS_WHEN_REQUIRED,
|
||||
DebugElementsOption.PASS_DEBUG,
|
||||
LineNumbersOption.PASS_LINE_NUMBERS,
|
||||
AttributesProcessingOption.PASS_ALL_ATTRIBUTES,
|
||||
ConstantPoolSharingOption.SHARED_POOL,
|
||||
ShortJumpsOption.FIX_SHORT_JUMPS,
|
||||
DeadCodeOption.PATCH_DEAD_CODE,
|
||||
DeadLabelsOption.FAIL_ON_DEAD_LABELS,
|
||||
new ClassHierarchyResolverOptionImpl(ClassHierarchyResolver.defaultResolver()),
|
||||
new AttributeMapperOptionImpl(new Function<>() {
|
||||
@Override
|
||||
public AttributeMapper<?> apply(Utf8Entry k) {
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
null, // StackMapsOption.STACK_MAPS_WHEN_REQUIRED
|
||||
null, // DebugElementsOption.PASS_DEBUG,
|
||||
null, // LineNumbersOption.PASS_LINE_NUMBERS,
|
||||
null, // AttributesProcessingOption.PASS_ALL_ATTRIBUTES,
|
||||
null, // ConstantPoolSharingOption.SHARED_POOL,
|
||||
null, // ShortJumpsOption.FIX_SHORT_JUMPS,
|
||||
null, // DeadCodeOption.PATCH_DEAD_CODE,
|
||||
null, // DeadLabelsOption.FAIL_ON_DEAD_LABELS,
|
||||
null, // new ClassHierarchyResolverOptionImpl(ClassHierarchyResolver.defaultResolver()),
|
||||
null // _ -> null
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
|
@ -85,6 +104,8 @@ public record ClassFileImpl(StackMapsOption stackMapsOption,
|
|||
for (var o : options) {
|
||||
if (o instanceof StackMapsOption oo) {
|
||||
smo = oo;
|
||||
} else if (o instanceof ClassHierarchyResolverOption oo) {
|
||||
chro = oo;
|
||||
} else if (o instanceof DebugElementsOption oo) {
|
||||
deo = oo;
|
||||
} else if (o instanceof LineNumbersOption oo) {
|
||||
|
@ -99,8 +120,6 @@ public record ClassFileImpl(StackMapsOption stackMapsOption,
|
|||
dco = oo;
|
||||
} else if (o instanceof DeadLabelsOption oo) {
|
||||
dlo = oo;
|
||||
} else if (o instanceof ClassHierarchyResolverOption oo) {
|
||||
chro = oo;
|
||||
} else if (o instanceof AttributeMapperOption oo) {
|
||||
amo = oo;
|
||||
} else { // null or unknown Option type
|
||||
|
@ -127,8 +146,7 @@ public record ClassFileImpl(StackMapsOption stackMapsOption,
|
|||
|
||||
@Override
|
||||
public byte[] transformClass(ClassModel model, ClassEntry newClassName, ClassTransform transform) {
|
||||
ConstantPoolBuilder constantPool = constantPoolSharingOption() == ConstantPoolSharingOption.SHARED_POOL
|
||||
? ConstantPoolBuilder.of(model)
|
||||
ConstantPoolBuilder constantPool = sharedConstantPool() ? ConstantPoolBuilder.of(model)
|
||||
: ConstantPoolBuilder.of();
|
||||
return build(newClassName, constantPool,
|
||||
new Consumer<ClassBuilder>() {
|
||||
|
@ -141,10 +159,14 @@ public record ClassFileImpl(StackMapsOption stackMapsOption,
|
|||
});
|
||||
}
|
||||
|
||||
public boolean sharedConstantPool() {
|
||||
return constantPoolSharingOption == null || constantPoolSharingOption == ConstantPoolSharingOption.SHARED_POOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VerifyError> verify(ClassModel model) {
|
||||
try {
|
||||
return VerifierImpl.verify(model, classHierarchyResolverOption().classHierarchyResolver(), null);
|
||||
return VerifierImpl.verify(model, classHierarchyResolver(), null);
|
||||
} catch (IllegalArgumentException verifierInitializationError) {
|
||||
return List.of(new VerifyError(verifierInitializationError.getMessage()));
|
||||
}
|
||||
|
@ -159,6 +181,58 @@ public record ClassFileImpl(StackMapsOption stackMapsOption,
|
|||
}
|
||||
}
|
||||
|
||||
public Function<Utf8Entry, AttributeMapper<?>> attributeMapper() {
|
||||
if (attributeMapperOption == null) {
|
||||
return _ -> null;
|
||||
} else {
|
||||
return ((AttributeMapperOption)attributeMapperOption).attributeMapper();
|
||||
}
|
||||
}
|
||||
|
||||
public ClassHierarchyResolver classHierarchyResolver() {
|
||||
if (classHierarchyResolverOption == null) {
|
||||
return ClassHierarchyImpl.DEFAULT_RESOLVER;
|
||||
} else {
|
||||
return ((ClassHierarchyResolverOption)classHierarchyResolverOption).classHierarchyResolver();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean dropDeadLabels() {
|
||||
return (deadLabelsOption != null && deadLabelsOption == DeadLabelsOption.DROP_DEAD_LABELS);
|
||||
}
|
||||
|
||||
public boolean passDebugElements() {
|
||||
return (debugElementsOption == null || debugElementsOption == DebugElementsOption.PASS_DEBUG);
|
||||
}
|
||||
|
||||
public boolean passLineNumbers() {
|
||||
return (lineNumbersOption == null || lineNumbersOption == LineNumbersOption.PASS_LINE_NUMBERS);
|
||||
}
|
||||
|
||||
public AttributesProcessingOption attributesProcessingOption() {
|
||||
return (attributesProcessingOption == null) ? AttributesProcessingOption.PASS_ALL_ATTRIBUTES : (AttributesProcessingOption)attributesProcessingOption;
|
||||
}
|
||||
|
||||
public boolean fixShortJumps() {
|
||||
return (shortJumpsOption == null || shortJumpsOption == ShortJumpsOption.FIX_SHORT_JUMPS);
|
||||
}
|
||||
|
||||
public boolean stackMapsWhenRequired() {
|
||||
return (stackMapsOption == null || stackMapsOption == StackMapsOption.STACK_MAPS_WHEN_REQUIRED);
|
||||
}
|
||||
|
||||
public boolean generateStackMaps() {
|
||||
return (stackMapsOption == StackMapsOption.GENERATE_STACK_MAPS);
|
||||
}
|
||||
|
||||
public boolean dropStackMaps() {
|
||||
return (stackMapsOption == StackMapsOption.DROP_STACK_MAPS);
|
||||
}
|
||||
|
||||
public boolean patchDeadCode() {
|
||||
return (deadCodeOption == null || deadCodeOption == DeadCodeOption.PATCH_DEAD_CODE);
|
||||
}
|
||||
|
||||
public record AttributeMapperOptionImpl(Function<Utf8Entry, AttributeMapper<?>> attributeMapper)
|
||||
implements AttributeMapperOption {
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ public final class ClassReaderImpl
|
|||
this.buffer = classfileBytes;
|
||||
this.classfileLength = classfileBytes.length;
|
||||
this.context = context;
|
||||
this.attributeMapper = this.context.attributeMapperOption().attributeMapper();
|
||||
this.attributeMapper = this.context.attributeMapper();
|
||||
if (classfileLength < 4 || readInt(0) != 0xCAFEBABE) {
|
||||
throw new IllegalArgumentException("Bad magic number");
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ public final class CodeImpl
|
|||
if (!inflated) {
|
||||
if (labels == null)
|
||||
labels = new LabelImpl[codeLength + 1];
|
||||
if (classReader.context().lineNumbersOption() == ClassFile.LineNumbersOption.PASS_LINE_NUMBERS)
|
||||
if (classReader.context().passLineNumbers())
|
||||
inflateLineNumbers();
|
||||
inflateJumpTargets();
|
||||
inflateTypeAnnotations();
|
||||
|
@ -167,7 +167,7 @@ public final class CodeImpl
|
|||
inflateMetadata();
|
||||
boolean doLineNumbers = (lineNumbers != null);
|
||||
generateCatchTargets(consumer);
|
||||
if (classReader.context().debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG)
|
||||
if (classReader.context().passDebugElements())
|
||||
generateDebugElements(consumer);
|
||||
for (int pos=codeStart; pos<codeEnd; ) {
|
||||
if (labels[pos - codeStart] != null)
|
||||
|
|
|
@ -103,7 +103,7 @@ public final class DirectCodeBuilder
|
|||
handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, false));
|
||||
cb.buildContent();
|
||||
} catch (LabelOverflowException loe) {
|
||||
if (context.shortJumpsOption() == ClassFile.ShortJumpsOption.FIX_SHORT_JUMPS) {
|
||||
if (context.fixShortJumps()) {
|
||||
handler.accept(cb = new DirectCodeBuilder(methodInfo, constantPool, context, original, true));
|
||||
cb.buildContent();
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ public final class DirectCodeBuilder
|
|||
setOriginal(original);
|
||||
this.methodInfo = methodInfo;
|
||||
this.transformFwdJumps = transformFwdJumps;
|
||||
this.transformBackJumps = context.shortJumpsOption() == ClassFile.ShortJumpsOption.FIX_SHORT_JUMPS;
|
||||
this.transformBackJumps = context.fixShortJumps();
|
||||
bytecodesBufWriter = (original instanceof CodeImpl cai) ? new BufWriterImpl(constantPool, context, cai.codeLength())
|
||||
: new BufWriterImpl(constantPool, context);
|
||||
this.startLabel = new LabelImpl(this, 0);
|
||||
|
@ -195,7 +195,7 @@ public final class DirectCodeBuilder
|
|||
int endPc = labelToBci(h.tryEnd());
|
||||
int handlerPc = labelToBci(h.handler());
|
||||
if (startPc == -1 || endPc == -1 || handlerPc == -1) {
|
||||
if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) {
|
||||
if (context.dropDeadLabels()) {
|
||||
handlersSize--;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unbound label in exception handler");
|
||||
|
@ -219,7 +219,7 @@ public final class DirectCodeBuilder
|
|||
// Backfill branches for which Label didn't have position yet
|
||||
processDeferredLabels();
|
||||
|
||||
if (context.debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG) {
|
||||
if (context.passDebugElements()) {
|
||||
if (!characterRanges.isEmpty()) {
|
||||
Attribute<?> a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) {
|
||||
|
||||
|
@ -232,7 +232,7 @@ public final class DirectCodeBuilder
|
|||
var start = labelToBci(cr.startScope());
|
||||
var end = labelToBci(cr.endScope());
|
||||
if (start == -1 || end == -1) {
|
||||
if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) {
|
||||
if (context.dropDeadLabels()) {
|
||||
crSize--;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unbound label in character range");
|
||||
|
@ -261,7 +261,7 @@ public final class DirectCodeBuilder
|
|||
b.writeU2(lvSize);
|
||||
for (LocalVariable l : localVariables) {
|
||||
if (!Util.writeLocalVariable(b, l)) {
|
||||
if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) {
|
||||
if (context.dropDeadLabels()) {
|
||||
lvSize--;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unbound label in local variable type");
|
||||
|
@ -284,7 +284,7 @@ public final class DirectCodeBuilder
|
|||
b.writeU2(localVariableTypes.size());
|
||||
for (LocalVariableType l : localVariableTypes) {
|
||||
if (!Util.writeLocalVariable(b, l)) {
|
||||
if (context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS) {
|
||||
if (context.dropDeadLabels()) {
|
||||
lvtSize--;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unbound label in local variable type");
|
||||
|
@ -357,23 +357,20 @@ public final class DirectCodeBuilder
|
|||
}
|
||||
|
||||
if (codeAndExceptionsMatch(codeLength)) {
|
||||
switch (context.stackMapsOption()) {
|
||||
case STACK_MAPS_WHEN_REQUIRED -> {
|
||||
if (context.stackMapsWhenRequired()) {
|
||||
attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null));
|
||||
writeCounters(true, buf);
|
||||
}
|
||||
case GENERATE_STACK_MAPS ->
|
||||
} else if (context.generateStackMaps()) {
|
||||
generateStackMaps(buf);
|
||||
case DROP_STACK_MAPS ->
|
||||
} else if (context.dropStackMaps()) {
|
||||
writeCounters(true, buf);
|
||||
}
|
||||
} else {
|
||||
switch (context.stackMapsOption()) {
|
||||
case STACK_MAPS_WHEN_REQUIRED ->
|
||||
if (context.stackMapsWhenRequired()) {
|
||||
tryGenerateStackMaps(false, buf);
|
||||
case GENERATE_STACK_MAPS ->
|
||||
} else if (context.generateStackMaps()) {
|
||||
generateStackMaps(buf);
|
||||
case DROP_STACK_MAPS ->
|
||||
} else if (context.dropStackMaps()) {
|
||||
writeCounters(false, buf);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,9 +235,9 @@ public final class StackMapGenerator {
|
|||
this.labelContext = labelContext;
|
||||
this.handlers = handlers;
|
||||
this.rawHandlers = new ArrayList<>(handlers.size());
|
||||
this.classHierarchy = new ClassHierarchyImpl(context.classHierarchyResolverOption().classHierarchyResolver());
|
||||
this.patchDeadCode = context.deadCodeOption() == ClassFile.DeadCodeOption.PATCH_DEAD_CODE;
|
||||
this.filterDeadLabels = context.deadLabelsOption() == ClassFile.DeadLabelsOption.DROP_DEAD_LABELS;
|
||||
this.classHierarchy = new ClassHierarchyImpl(context.classHierarchyResolver());
|
||||
this.patchDeadCode = context.patchDeadCode();
|
||||
this.filterDeadLabels = context.dropDeadLabels();
|
||||
this.currentFrame = new Frame(classHierarchy);
|
||||
generate();
|
||||
}
|
||||
|
|
|
@ -102,9 +102,9 @@ public class Util {
|
|||
private static final int ATTRIBUTE_STABILITY_COUNT = AttributeMapper.AttributeStability.values().length;
|
||||
|
||||
public static boolean isAttributeAllowed(final Attribute<?> attr,
|
||||
final ClassFile.AttributesProcessingOption processingOption) {
|
||||
final ClassFileImpl context) {
|
||||
return attr instanceof BoundAttribute
|
||||
? ATTRIBUTE_STABILITY_COUNT - attr.attributeMapper().stability().ordinal() > processingOption.ordinal()
|
||||
? ATTRIBUTE_STABILITY_COUNT - attr.attributeMapper().stability().ordinal() > context.attributesProcessingOption().ordinal()
|
||||
: true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue