diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 8956cb33219..611a9f55ad6 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -193,15 +193,17 @@ module java.base { java.logging; exports jdk.internal.classfile to jdk.jartool, - jdk.jlink; + jdk.jlink, + jdk.jshell; exports jdk.internal.classfile.attribute to jdk.jartool; exports jdk.internal.classfile.constantpool to jdk.jartool; + exports jdk.internal.classfile.instruction to + jdk.jshell; exports jdk.internal.org.objectweb.asm to jdk.jfr, - jdk.jlink, - jdk.jshell; + jdk.jlink; exports jdk.internal.org.objectweb.asm.tree to jdk.jfr, jdk.jlink; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java index 88a8f96883e..ca2282341c0 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java @@ -24,17 +24,17 @@ */ package jdk.jshell.execution; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Label; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.classfile.Classfile; +import jdk.internal.classfile.ClassTransform; +import jdk.internal.classfile.instruction.BranchInstruction; /** * An implementation of {@link jdk.jshell.spi.ExecutionControl} which executes @@ -74,43 +74,31 @@ public class LocalExecutionControl extends DirectExecutionControl { .toArray(ClassBytecodes[]::new)); } + private static final String CANCEL_CLASS = "REPL.$Cancel$"; + private static final ClassDesc CD_Cancel = ClassDesc.of(CANCEL_CLASS); + private static final ClassDesc CD_ThreadDeath = ClassDesc.of("java.lang.ThreadDeath"); + private static final MethodTypeDesc MTD_void = MethodTypeDesc.of(ConstantDescs.CD_void); + private static byte[] instrument(byte[] classFile) { - var reader = new ClassReader(classFile); - var writer = new ClassWriter(reader, 0); - reader.accept(new ClassVisitor(Opcodes.ASM9, writer) { - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - return new MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) { - @Override - public void visitJumpInsn(int opcode, Label label) { - visitMethodInsn(Opcodes.INVOKESTATIC, "REPL/$Cancel$", "stopCheck", "()V", false); - super.visitJumpInsn(opcode, label); - } - }; - } - }, 0); - return writer.toByteArray(); + return Classfile.parse(classFile) + .transform(ClassTransform.transformingMethodBodies((cob, coe) -> { + if (coe instanceof BranchInstruction) + cob.invokestatic(CD_Cancel, "stopCheck", MTD_void); + cob.with(coe); + })); } private static ClassBytecodes genCancelClass() { - var cancelWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - cancelWriter.visit(Opcodes.V19, Opcodes.ACC_PUBLIC, "REPL/$Cancel$", null, "java/lang/Object", null); - cancelWriter.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_VOLATILE, "allStop", "Z", null, null); - var checkVisitor = cancelWriter.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "stopCheck", "()V", null, null); - checkVisitor.visitCode(); - checkVisitor.visitFieldInsn(Opcodes.GETSTATIC, "REPL/$Cancel$", "allStop", "Z"); - var skip = new Label(); - checkVisitor.visitJumpInsn(Opcodes.IFEQ, skip); - checkVisitor.visitTypeInsn(Opcodes.NEW, "java/lang/ThreadDeath"); - checkVisitor.visitInsn(Opcodes.DUP); - checkVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/ThreadDeath", "", "()V", false); - checkVisitor.visitInsn(Opcodes.ATHROW); - checkVisitor.visitLabel(skip); - checkVisitor.visitInsn(Opcodes.RETURN); - checkVisitor.visitMaxs(0, 0); - checkVisitor.visitEnd(); - cancelWriter.visitEnd(); - return new ClassBytecodes("REPL.$Cancel$", cancelWriter.toByteArray()); + return new ClassBytecodes(CANCEL_CLASS, Classfile.build(CD_Cancel, clb -> + clb.withFlags(Classfile.ACC_PUBLIC) + .withField("allStop", ConstantDescs.CD_boolean, Classfile.ACC_PUBLIC | Classfile.ACC_STATIC | Classfile.ACC_VOLATILE) + .withMethodBody("stopCheck", MTD_void, Classfile.ACC_PUBLIC | Classfile.ACC_STATIC, cob -> + cob.getstatic(CD_Cancel, "allStop", ConstantDescs.CD_boolean) + .ifThenElse(tb -> tb.new_(CD_ThreadDeath) + .dup() + .invokespecial(CD_ThreadDeath, "", MTD_void) + .athrow(), + eb -> eb.return_())))); } @Override @@ -118,7 +106,7 @@ public class LocalExecutionControl extends DirectExecutionControl { protected String invoke(Method doitMethod) throws Exception { if (allStop == null) { super.load(new ClassBytecodes[]{ genCancelClass() }); - allStop = findClass("REPL.$Cancel$").getDeclaredField("allStop"); + allStop = findClass(CANCEL_CLASS).getDeclaredField("allStop"); } allStop.set(null, false); diff --git a/test/jdk/jdk/classfile/TEST.properties b/test/jdk/jdk/classfile/TEST.properties index 9215ccc3ce4..41aaa61dc62 100644 --- a/test/jdk/jdk/classfile/TEST.properties +++ b/test/jdk/jdk/classfile/TEST.properties @@ -1,4 +1,4 @@ -maxOutputSize = 500000 +maxOutputSize = 2500000 enablePreview = true modules = \ java.base/jdk.internal.classfile \