mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8345486: Reevaluate the classes in java.lang.classfile.components package
Reviewed-by: mcimadamore, asotona
This commit is contained in:
parent
f3b4350e0f
commit
79eb77b782
33 changed files with 54 additions and 158 deletions
|
@ -60,12 +60,7 @@ import java.util.function.Supplier;
|
|||
* its state must be reset for each traversal; this will happen automatically if
|
||||
* the transform is created with {@link ClassTransform#ofStateful(Supplier)} (or
|
||||
* corresponding methods for other classfile locations.)
|
||||
* <p>
|
||||
* Class transformation sample where code transformation is stateful:
|
||||
* {@snippet lang="java" class="PackageSnippets" region="codeRelabeling"}
|
||||
* <p>
|
||||
* Complex class instrumentation sample chaining multiple transformations:
|
||||
* {@snippet lang="java" class="PackageSnippets" region="classInstrumentation"}
|
||||
*
|
||||
* @param <C> the transform type
|
||||
* @param <E> the element type
|
||||
* @param <B> the builder type
|
||||
|
|
|
@ -25,21 +25,13 @@
|
|||
package java.lang.classfile.snippets;
|
||||
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.components.ClassRemapper;
|
||||
import java.lang.classfile.components.CodeLocalsShifter;
|
||||
import java.lang.classfile.components.CodeRelabeler;
|
||||
import java.lang.classfile.instruction.*;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
@ -326,82 +318,6 @@ class PackageSnippets {
|
|||
// @end
|
||||
}
|
||||
|
||||
void codeRelabeling(ClassModel classModel) {
|
||||
// @start region="codeRelabeling"
|
||||
byte[] newBytes = ClassFile.of().transformClass(classModel,
|
||||
ClassTransform.transformingMethodBodies(
|
||||
CodeTransform.ofStateful(CodeRelabeler::of)));
|
||||
// @end
|
||||
}
|
||||
|
||||
// @start region="classInstrumentation"
|
||||
byte[] classInstrumentation(ClassModel target, ClassModel instrumentor, Predicate<MethodModel> instrumentedMethodsFilter) {
|
||||
var instrumentorCodeMap = instrumentor.methods().stream()
|
||||
.filter(instrumentedMethodsFilter)
|
||||
.collect(Collectors.toMap(mm -> mm.methodName().stringValue() + mm.methodType().stringValue(), mm -> mm.code().orElseThrow()));
|
||||
var targetFieldNames = target.fields().stream().map(f -> f.fieldName().stringValue()).collect(Collectors.toSet());
|
||||
var targetMethods = target.methods().stream().map(m -> m.methodName().stringValue() + m.methodType().stringValue()).collect(Collectors.toSet());
|
||||
var instrumentorClassRemapper = ClassRemapper.of(Map.of(instrumentor.thisClass().asSymbol(), target.thisClass().asSymbol()));
|
||||
return ClassFile.of().transformClass(target,
|
||||
ClassTransform.transformingMethods(
|
||||
instrumentedMethodsFilter,
|
||||
(mb, me) -> {
|
||||
if (me instanceof CodeModel targetCodeModel) {
|
||||
var mm = targetCodeModel.parent().get();
|
||||
//instrumented methods code is taken from instrumentor
|
||||
mb.transformCode(instrumentorCodeMap.get(mm.methodName().stringValue() + mm.methodType().stringValue()),
|
||||
//all references to the instrumentor class are remapped to target class
|
||||
instrumentorClassRemapper.asCodeTransform()
|
||||
.andThen((codeBuilder, instrumentorCodeElement) -> {
|
||||
//all invocations of target methods from instrumentor are inlined
|
||||
if (instrumentorCodeElement instanceof InvokeInstruction inv
|
||||
&& target.thisClass().asInternalName().equals(inv.owner().asInternalName())
|
||||
&& mm.methodName().stringValue().equals(inv.name().stringValue())
|
||||
&& mm.methodType().stringValue().equals(inv.type().stringValue())) {
|
||||
|
||||
//store stacked method parameters into locals
|
||||
var storeStack = new ArrayDeque<StoreInstruction>();
|
||||
int slot = 0;
|
||||
if (!mm.flags().has(AccessFlag.STATIC))
|
||||
storeStack.push(StoreInstruction.of(TypeKind.REFERENCE, slot++));
|
||||
for (var pt : mm.methodTypeSymbol().parameterList()) {
|
||||
var tk = TypeKind.from(pt);
|
||||
storeStack.push(StoreInstruction.of(tk, slot));
|
||||
slot += tk.slotSize();
|
||||
}
|
||||
storeStack.forEach(codeBuilder::with);
|
||||
|
||||
//inlined target locals must be shifted based on the actual instrumentor locals
|
||||
codeBuilder.block(inlinedBlockBuilder -> inlinedBlockBuilder
|
||||
.transform(targetCodeModel, CodeLocalsShifter.of(mm.flags(), mm.methodTypeSymbol())
|
||||
.andThen(CodeRelabeler.of())
|
||||
.andThen((innerBuilder, shiftedTargetCode) -> {
|
||||
//returns must be replaced with jump to the end of the inlined method
|
||||
if (shiftedTargetCode instanceof ReturnInstruction)
|
||||
innerBuilder.goto_(inlinedBlockBuilder.breakLabel());
|
||||
else
|
||||
innerBuilder.with(shiftedTargetCode);
|
||||
})));
|
||||
} else
|
||||
codeBuilder.with(instrumentorCodeElement);
|
||||
}));
|
||||
} else
|
||||
mb.with(me);
|
||||
})
|
||||
.andThen(ClassTransform.endHandler(clb ->
|
||||
//remaining instrumentor fields and methods are injected at the end
|
||||
clb.transform(instrumentor,
|
||||
ClassTransform.dropping(cle ->
|
||||
!(cle instanceof FieldModel fm
|
||||
&& !targetFieldNames.contains(fm.fieldName().stringValue()))
|
||||
&& !(cle instanceof MethodModel mm
|
||||
&& !ConstantDescs.INIT_NAME.equals(mm.methodName().stringValue())
|
||||
&& !targetMethods.contains(mm.methodName().stringValue() + mm.methodType().stringValue())))
|
||||
//and instrumentor class references remapped to target class
|
||||
.andThen(instrumentorClassRemapper)))));
|
||||
}
|
||||
// @end
|
||||
|
||||
void resolverExample() {
|
||||
// @start region="lookup-class-hierarchy-resolver"
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup(); // @replace regex="MethodHandles\.lookup\(\)" replacement="..."
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.lang.classfile.components;
|
||||
package jdk.internal.classfile.components;
|
||||
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.CodeModel;
|
||||
|
@ -58,8 +58,6 @@ import jdk.internal.classfile.impl.ClassPrinterImpl;
|
|||
* <p>
|
||||
* Another use case for {@link ClassPrinter} is to simplify writing of automated tests:
|
||||
* {@snippet lang="java" class="PackageSnippets" region="printNodesInTest"}
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public final class ClassPrinter {
|
||||
|
||||
|
@ -68,8 +66,6 @@ public final class ClassPrinter {
|
|||
|
||||
/**
|
||||
* Level of detail to print or export.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public enum Verbosity {
|
||||
|
||||
|
@ -102,8 +98,6 @@ public final class ClassPrinter {
|
|||
|
||||
/**
|
||||
* Named, traversable, and printable node parent.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface Node {
|
||||
|
||||
|
@ -146,8 +140,6 @@ public final class ClassPrinter {
|
|||
|
||||
/**
|
||||
* A leaf node holding single printable value.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface LeafNode extends Node
|
||||
permits ClassPrinterImpl.LeafNodeImpl {
|
||||
|
@ -161,8 +153,6 @@ public final class ClassPrinter {
|
|||
|
||||
/**
|
||||
* A tree node holding {@link List} of nested nodes.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface ListNode extends Node, List<Node>
|
||||
permits ClassPrinterImpl.ListNodeImpl {
|
||||
|
@ -172,8 +162,6 @@ public final class ClassPrinter {
|
|||
* A tree node holding {@link Map} of nested nodes.
|
||||
* <p>
|
||||
* Each {@link Map.Entry#getKey()} == {@link Map.Entry#getValue()}.{@link #name()}.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface MapNode extends Node, Map<ConstantDesc, Node>
|
||||
permits ClassPrinterImpl.MapNodeImpl {
|
|
@ -22,7 +22,7 @@
|
|||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.lang.classfile.components;
|
||||
package jdk.internal.classfile.components;
|
||||
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.ClassModel;
|
||||
|
@ -53,8 +53,6 @@ import static java.util.Objects.requireNonNull;
|
|||
* <p>
|
||||
* Arrays of reference types are always decomposed, mapped as the base reference
|
||||
* types and composed back to arrays.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface ClassRemapper extends ClassTransform permits ClassRemapperImpl {
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.lang.classfile.components;
|
||||
package jdk.internal.classfile.components;
|
||||
|
||||
import java.lang.classfile.AccessFlags;
|
||||
import java.lang.classfile.CodeTransform;
|
||||
|
@ -37,8 +37,6 @@ import jdk.internal.classfile.impl.CodeLocalsShifterImpl;
|
|||
* newly allocated positions to avoid conflicts during code injection.
|
||||
* Locals pointing to the receiver or to method arguments slots are never shifted.
|
||||
* All locals pointing beyond the method arguments are re-indexed in order of appearance.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface CodeLocalsShifter extends CodeTransform permits CodeLocalsShifterImpl {
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.lang.classfile.components;
|
||||
package jdk.internal.classfile.components;
|
||||
|
||||
import java.lang.classfile.CodeBuilder;
|
||||
import java.lang.classfile.CodeTransform;
|
||||
|
@ -44,8 +44,6 @@ import static java.util.Objects.requireNonNull;
|
|||
* Primary purpose of CodeRelabeler is for repeated injections of the same code blocks.
|
||||
* Repeated injection of the same code block must be relabeled, so each instance of
|
||||
* {@link java.lang.classfile.Label} is bound in the target bytecode exactly once.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface CodeRelabeler extends CodeTransform permits CodeRelabelerImpl {
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.lang.classfile.components;
|
||||
package jdk.internal.classfile.components;
|
||||
|
||||
import java.lang.classfile.CodeTransform;
|
||||
import java.lang.classfile.Label;
|
||||
|
@ -49,8 +49,6 @@ import jdk.internal.classfile.impl.CodeStackTrackerImpl;
|
|||
* int maxStack = stackTracker.maxStackSize().get();
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public sealed interface CodeStackTracker extends CodeTransform permits CodeStackTrackerImpl {
|
||||
|
|
@ -110,8 +110,6 @@
|
|||
* CodeLocalsShifter} and {@link CodeRelabeler} into fully functional class
|
||||
* instrumenting transformation:
|
||||
* {@snippet lang="java" class="PackageSnippets" region="classInstrumentation"}
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
package java.lang.classfile.components;
|
||||
package jdk.internal.classfile.components;
|
||||
|
|
@ -25,10 +25,10 @@
|
|||
package java.lang.classfile.components.snippets;
|
||||
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.components.ClassPrinter;
|
||||
import java.lang.classfile.components.ClassRemapper;
|
||||
import java.lang.classfile.components.CodeLocalsShifter;
|
||||
import java.lang.classfile.components.CodeRelabeler;
|
||||
import jdk.internal.classfile.components.ClassPrinter;
|
||||
import jdk.internal.classfile.components.ClassRemapper;
|
||||
import jdk.internal.classfile.components.CodeLocalsShifter;
|
||||
import jdk.internal.classfile.components.CodeRelabeler;
|
||||
import java.lang.classfile.instruction.InvokeInstruction;
|
||||
import java.lang.classfile.instruction.ReturnInstruction;
|
||||
import java.lang.classfile.instruction.StoreInstruction;
|
|
@ -31,11 +31,11 @@ import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInf
|
|||
import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
|
||||
import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
|
||||
import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
|
||||
import java.lang.classfile.components.ClassPrinter.LeafNode;
|
||||
import java.lang.classfile.components.ClassPrinter.ListNode;
|
||||
import java.lang.classfile.components.ClassPrinter.MapNode;
|
||||
import java.lang.classfile.components.ClassPrinter.Node;
|
||||
import java.lang.classfile.components.ClassPrinter.Verbosity;
|
||||
import jdk.internal.classfile.components.ClassPrinter.LeafNode;
|
||||
import jdk.internal.classfile.components.ClassPrinter.ListNode;
|
||||
import jdk.internal.classfile.components.ClassPrinter.MapNode;
|
||||
import jdk.internal.classfile.components.ClassPrinter.Node;
|
||||
import jdk.internal.classfile.components.ClassPrinter.Verbosity;
|
||||
import java.lang.classfile.constantpool.*;
|
||||
import java.lang.classfile.instruction.*;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
|
|
|
@ -26,7 +26,7 @@ package jdk.internal.classfile.impl;
|
|||
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.attribute.*;
|
||||
import java.lang.classfile.components.ClassRemapper;
|
||||
import jdk.internal.classfile.components.ClassRemapper;
|
||||
import java.lang.classfile.constantpool.Utf8Entry;
|
||||
import java.lang.classfile.instruction.ConstantInstruction.LoadConstantInstruction;
|
||||
import java.lang.classfile.instruction.*;
|
||||
|
|
|
@ -28,7 +28,7 @@ import java.lang.classfile.CodeBuilder;
|
|||
import java.lang.classfile.CodeElement;
|
||||
import java.lang.classfile.Signature;
|
||||
import java.lang.classfile.TypeKind;
|
||||
import java.lang.classfile.components.CodeLocalsShifter;
|
||||
import jdk.internal.classfile.components.CodeLocalsShifter;
|
||||
import java.lang.classfile.instruction.IncrementInstruction;
|
||||
import java.lang.classfile.instruction.LoadInstruction;
|
||||
import java.lang.classfile.instruction.LocalVariable;
|
||||
|
|
|
@ -27,7 +27,7 @@ package jdk.internal.classfile.impl;
|
|||
import java.lang.classfile.CodeBuilder;
|
||||
import java.lang.classfile.CodeElement;
|
||||
import java.lang.classfile.Label;
|
||||
import java.lang.classfile.components.CodeRelabeler;
|
||||
import jdk.internal.classfile.components.CodeRelabeler;
|
||||
import java.lang.classfile.instruction.*;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.lang.classfile.CodeElement;
|
|||
import java.lang.classfile.Label;
|
||||
import java.lang.classfile.Opcode;
|
||||
import java.lang.classfile.TypeKind;
|
||||
import java.lang.classfile.components.CodeStackTracker;
|
||||
import jdk.internal.classfile.components.CodeStackTracker;
|
||||
import java.lang.classfile.instruction.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
|
|
@ -26,7 +26,7 @@ package jdk.internal.classfile.impl;
|
|||
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.attribute.CodeAttribute;
|
||||
import java.lang.classfile.components.ClassPrinter;
|
||||
import jdk.internal.classfile.components.ClassPrinter;
|
||||
import java.lang.classfile.constantpool.ClassEntry;
|
||||
import java.lang.classfile.constantpool.ModuleEntry;
|
||||
import java.lang.classfile.constantpool.PoolEntry;
|
||||
|
|
|
@ -26,7 +26,7 @@ package jdk.internal.classfile.impl.verifier;
|
|||
|
||||
import java.lang.classfile.ClassHierarchyResolver;
|
||||
import java.lang.classfile.ClassModel;
|
||||
import java.lang.classfile.components.ClassPrinter;
|
||||
import jdk.internal.classfile.components.ClassPrinter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
|
@ -81,7 +81,6 @@ module java.base {
|
|||
exports java.lang.annotation;
|
||||
exports java.lang.classfile;
|
||||
exports java.lang.classfile.attribute;
|
||||
exports java.lang.classfile.components;
|
||||
exports java.lang.classfile.constantpool;
|
||||
exports java.lang.classfile.instruction;
|
||||
exports java.lang.constant;
|
||||
|
@ -177,6 +176,8 @@ module java.base {
|
|||
jdk.net,
|
||||
jdk.sctp,
|
||||
jdk.crypto.cryptoki;
|
||||
exports jdk.internal.classfile.components to
|
||||
jdk.jfr;
|
||||
exports jdk.internal.foreign to
|
||||
jdk.incubator.vector;
|
||||
exports jdk.internal.event to
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue