Commit 1535c68e authored by ebruneton's avatar ebruneton

- split the ClassReader accept() method into several methods (readField,...

- split the ClassReader accept() method into several methods (readField, readMethod, readCode, readFrame, etc), each using local variables with the smallest possible scope. Required the addition of a Context helper class. Makes the code more readable, a little bit bigger (+4%), but also faster (1.12 speedup for the deserialize performance test).
- switched to the Java code style conventions, applied Eclipse auto format on all files.
parent 48f5c811
This diff is collapsed.
This diff is collapsed.
......@@ -46,10 +46,8 @@ import org.objectweb.asm.Type;
public class Adapt extends ClassLoader {
@Override
protected synchronized Class<?> loadClass(
final String name,
final boolean resolve) throws ClassNotFoundException
{
protected synchronized Class<?> loadClass(final String name,
final boolean resolve) throws ClassNotFoundException {
if (name.startsWith("java.")) {
System.err.println("Adapt: loading class '" + name
+ "' without on the fly adaptation");
......@@ -109,46 +107,30 @@ class TraceFieldClassAdapter extends ClassVisitor implements Opcodes {
}
@Override
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces)
{
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
owner = name;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public FieldVisitor visitField(
final int access,
final String name,
final String desc,
final String signature,
final Object value)
{
FieldVisitor fv = super.visitField(access, name, desc, signature, value);
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
FieldVisitor fv = super
.visitField(access, name, desc, signature, value);
if ((access & ACC_STATIC) == 0) {
Type t = Type.getType(desc);
int size = t.getSize();
// generates getter method
String gDesc = "()" + desc;
MethodVisitor gv = cv.visitMethod(ACC_PRIVATE,
"_get" + name,
gDesc,
null,
null);
gv.visitFieldInsn(GETSTATIC,
"java/lang/System",
"err",
MethodVisitor gv = cv.visitMethod(ACC_PRIVATE, "_get" + name,
gDesc, null, null);
gv.visitFieldInsn(GETSTATIC, "java/lang/System", "err",
"Ljava/io/PrintStream;");
gv.visitLdcInsn("_get" + name + " called");
gv.visitMethodInsn(INVOKEVIRTUAL,
"java/io/PrintStream",
"println",
gv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(Ljava/lang/String;)V");
gv.visitVarInsn(ALOAD, 0);
gv.visitFieldInsn(GETFIELD, owner, name, desc);
......@@ -158,19 +140,12 @@ class TraceFieldClassAdapter extends ClassVisitor implements Opcodes {
// generates setter method
String sDesc = "(" + desc + ")V";
MethodVisitor sv = cv.visitMethod(ACC_PRIVATE,
"_set" + name,
sDesc,
null,
null);
sv.visitFieldInsn(GETSTATIC,
"java/lang/System",
"err",
MethodVisitor sv = cv.visitMethod(ACC_PRIVATE, "_set" + name,
sDesc, null, null);
sv.visitFieldInsn(GETSTATIC, "java/lang/System", "err",
"Ljava/io/PrintStream;");
sv.visitLdcInsn("_set" + name + " called");
sv.visitMethodInsn(INVOKEVIRTUAL,
"java/io/PrintStream",
"println",
sv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
"(Ljava/lang/String;)V");
sv.visitVarInsn(ALOAD, 0);
sv.visitVarInsn(t.getOpcode(ILOAD), 1);
......@@ -183,17 +158,9 @@ class TraceFieldClassAdapter extends ClassVisitor implements Opcodes {
}
@Override
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions)
{
MethodVisitor mv = cv.visitMethod(access,
name,
desc,
signature,
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
return mv == null ? null : new TraceFieldCodeAdapter(mv, owner);
}
......@@ -209,12 +176,8 @@ class TraceFieldCodeAdapter extends MethodVisitor implements Opcodes {
}
@Override
public void visitFieldInsn(
final int opcode,
final String owner,
final String name,
final String desc)
{
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
if (owner.equals(this.owner)) {
if (opcode == GETFIELD) {
// replaces GETFIELD f by INVOKESPECIAL _getf
......
......@@ -64,7 +64,8 @@ public class Analysis implements Opcodes {
MethodNode method = methods.get(i);
if (method.instructions.size() > 0) {
if (!analyze(cn, method)) {
Analyzer<?> a = new Analyzer<BasicValue>(new BasicVerifier());
Analyzer<?> a = new Analyzer<BasicValue>(
new BasicVerifier());
try {
a.analyze(cn.name, method);
} catch (Exception ignored) {
......@@ -73,22 +74,22 @@ public class Analysis implements Opcodes {
Textifier t = new Textifier() {
@Override
public void visitMaxs(
final int maxStack,
final int maxLocals)
{
public void visitMaxs(final int maxStack,
final int maxLocals) {
for (int i = 0; i < text.size(); ++i) {
StringBuffer s = new StringBuffer(frames[i] == null
? "null"
: frames[i].toString());
StringBuffer s = new StringBuffer(
frames[i] == null ? "null"
: frames[i].toString());
while (s.length() < Math.max(20, maxStack
+ maxLocals + 1))
{
+ maxLocals + 1)) {
s.append(' ');
}
System.err.print(Integer.toString(i + 1000)
.substring(1)
+ " " + s + " : " + text.get(i));
+ " "
+ s
+ " : "
+ text.get(i));
}
System.err.println();
}
......@@ -110,9 +111,9 @@ public class Analysis implements Opcodes {
* (in the control flow graph).
*/
public static boolean analyze(final ClassNode c, final MethodNode m)
throws Exception
{
Analyzer<SourceValue> a = new Analyzer<SourceValue>(new SourceInterpreter());
throws Exception {
Analyzer<SourceValue> a = new Analyzer<SourceValue>(
new SourceInterpreter());
Frame<SourceValue>[] frames = a.analyze(c.name, m);
// for each xLOAD instruction, we find the xSTORE instructions that can
......@@ -123,8 +124,7 @@ public class Analysis implements Opcodes {
AbstractInsnNode insn = m.instructions.get(i);
int opcode = insn.getOpcode();
if ((opcode >= ILOAD && opcode <= ALOAD) || opcode == IINC) {
int var = opcode == IINC
? ((IincInsnNode) insn).var
int var = opcode == IINC ? ((IincInsnNode) insn).var
: ((VarInsnNode) insn).var;
Frame<SourceValue> f = frames[i];
if (f != null) {
......@@ -148,9 +148,8 @@ public class Analysis implements Opcodes {
if (opcode >= ISTORE && opcode <= ASTORE) {
if (!stores.contains(insn)) {
ok = false;
System.err.println("method " + m.name
+ ", instruction " + i
+ ": useless store instruction");
System.err.println("method " + m.name + ", instruction "
+ i + ": useless store instruction");
}
}
}
......
......@@ -43,14 +43,13 @@ import org.objectweb.asm.Type;
public class Annotations {
public static void foo(final @NotNull
String arg)
{
public static void foo(final @NotNull String arg) {
System.out.println(arg);
}
public static void main(final String[] args) throws Exception {
System.out.println("Calling foo(null) results in a NullPointerException:");
System.out
.println("Calling foo(null) results in a NullPointerException:");
try {
foo(null);
} catch (Exception e) {
......@@ -63,18 +62,11 @@ public class Annotations {
cr.accept(new ClassVisitor(Opcodes.ASM4, cw) {
@Override
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions)
{
public MethodVisitor visitMethod(final int access,
final String name, final String desc,
final String signature, final String[] exceptions) {
final Type[] args = Type.getArgumentTypes(desc);
MethodVisitor v = cv.visitMethod(access,
name,
desc,
signature,
MethodVisitor v = cv.visitMethod(access, name, desc, signature,
exceptions);
return new MethodVisitor(Opcodes.ASM4, v) {
......@@ -82,13 +74,10 @@ public class Annotations {
@Override
public AnnotationVisitor visitParameterAnnotation(
final int parameter,
final String desc,
final boolean visible)
{
final int parameter, final String desc,
final boolean visible) {
AnnotationVisitor av;
av = mv.visitParameterAnnotation(parameter,
desc,
av = mv.visitParameterAnnotation(parameter, desc,
visible);
if (desc.equals("LNotNull;")) {
params.add(new Integer(parameter));
......@@ -113,10 +102,8 @@ public class Annotations {
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn("Argument " + param
+ " must not be null");
mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
c,
"<init>",
d);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, c,
"<init>", d);
mv.visitInsn(Opcodes.ATHROW);
mv.visitLabel(end);
}
......@@ -128,8 +115,7 @@ public class Annotations {
Class<?> c = new ClassLoader() {
@Override
public Class<?> loadClass(final String name)
throws ClassNotFoundException
{
throws ClassNotFoundException {
if (name.equals(n)) {
byte[] b = cw.toByteArray();
return defineClass(name, b, 0, b.length);
......@@ -139,7 +125,8 @@ public class Annotations {
}.loadClass(n);
System.out.println();
System.out.println("Calling foo(null) on the transformed class results in an IllegalArgumentException:");
System.out.println("Calling foo(null) on the transformed class results"
+ " in an IllegalArgumentException:");
Method m = c.getMethod("foo", new Class<?>[] { String.class });
try {
m.invoke(null, new Object[] { null });
......
......@@ -31,7 +31,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.CLASS)
public @interface NotNull
{
public @interface NotNull {
String value() default "";
}
......@@ -29,6 +29,7 @@
*/
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Map;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ByteVector;
......@@ -39,6 +40,7 @@ import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.Textifiable;
import org.objectweb.asm.util.TraceClassVisitor;
/**
......@@ -55,7 +57,8 @@ public class Attributes extends ClassLoader {
byte[] b = cw.toByteArray();
// stores the adapted class on disk
FileOutputStream fos = new FileOutputStream("CommentAttribute.class.new");
FileOutputStream fos = new FileOutputStream(
"CommentAttribute.class.new");
try {
fos.write(b);
} finally {
......@@ -76,43 +79,26 @@ class AddCommentClassAdapter extends ClassVisitor implements Opcodes {
}
@Override
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces)
{
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
visitAttribute(new CommentAttribute("this is a class comment"));
}
@Override
public FieldVisitor visitField(
final int access,
final String name,
final String desc,
final String signature,
final Object value)
{
FieldVisitor fv = super.visitField(access, name, desc, signature, value);
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
FieldVisitor fv = super
.visitField(access, name, desc, signature, value);
fv.visitAttribute(new CommentAttribute("this is a field comment"));
return fv;
}
@Override
public MethodVisitor visitMethod(
final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions)
{
MethodVisitor mv = cv.visitMethod(access,
name,
desc,
signature,
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
if (mv != null) {
mv.visitAttribute(new CommentAttribute("this is a method comment"));
......@@ -121,7 +107,7 @@ class AddCommentClassAdapter extends ClassVisitor implements Opcodes {
}
}
class CommentAttribute extends Attribute {
class CommentAttribute extends Attribute implements Textifiable {
private String comment;
......@@ -140,25 +126,19 @@ class CommentAttribute extends Attribute {
}
@Override
protected Attribute read(
final ClassReader cr,
final int off,
final int len,
final char[] buf,
final int codeOff,
final Label[] labels)
{
protected Attribute read(final ClassReader cr, final int off,
final int len, final char[] buf, final int codeOff,
final Label[] labels) {
return new CommentAttribute(cr.readUTF8(off, buf));
}
@Override
protected ByteVector write(
final ClassWriter cw,
final byte[] code,
final int len,
final int maxStack,
final int maxLocals)
{
protected ByteVector write(final ClassWriter cw, final byte[] code,
final int len, final int maxStack, final int maxLocals) {
return new ByteVector().putShort(cw.newUTF8(comment));
}
public void textify(StringBuffer buf, Map<Label, String> labelNames) {
buf.append(": " + comment + "\n");
}
}
......@@ -98,7 +98,7 @@ public class IndyCompile extends ClassLoader {
/**
* Returns the maximum variable index used in this expression.
*
*
* @return the maximum variable index used in this expression, or -1 if
* no variable is used.
*/
......@@ -112,12 +112,7 @@ public class IndyCompile extends ClassLoader {
byte[] compile(final String name) {
// class header
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_7,
ACC_PUBLIC,
name,
null,
"java/lang/Object",
null);
cw.visit(V1_7, ACC_PUBLIC, name, null, "java/lang/Object", null);
// eval method type
StringBuilder desc = new StringBuilder("(");
......@@ -125,13 +120,10 @@ public class IndyCompile extends ClassLoader {
desc.append("Ljava/lang/Object;");
}
desc.append(")Ljava/lang/Object;");
// eval method
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC,
"eval",
desc.toString(),
null,
null);
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "eval",
desc.toString(), null, null);
compile(mv);
mv.visitInsn(ARETURN);
// max stack and max locals automatically computed
......@@ -148,11 +140,9 @@ public class IndyCompile extends ClassLoader {
*/
abstract void compile(MethodVisitor mv);
private static Handle getHandle(
final String name,
final String optArgs)
{
return new Handle(H_INVOKESTATIC,
private static Handle getHandle(final String name, final String optArgs) {
return new Handle(
H_INVOKESTATIC,
"RT",
name,
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;"
......@@ -307,8 +297,7 @@ public class IndyCompile extends ClassLoader {
// tests if e1 is false
mv.visitInsn(DUP);
// convert to a boolean
mv.visitInvokeDynamicInsn("asBoolean",
"(Ljava/lang/Object;)Z",
mv.visitInvokeDynamicInsn("asBoolean", "(Ljava/lang/Object;)Z",
UNARY);
Label end = new Label();
......@@ -339,8 +328,7 @@ public class IndyCompile extends ClassLoader {
// tests if e1 is true
mv.visitInsn(DUP);
// convert to a boolean
mv.visitInvokeDynamicInsn("asBoolean",
"(Ljava/lang/Object;)Z",
mv.visitInvokeDynamicInsn("asBoolean", "(Ljava/lang/Object;)Z",
UNARY);
Label end = new Label();
mv.visitJumpInsn(IFNE, end);
......@@ -374,8 +362,7 @@ public class IndyCompile extends ClassLoader {
// compiles e, and applies 'not'
e.compile(mv);
mv.visitInvokeDynamicInsn("not",
"(Ljava/lang/Object;)Ljava/lang/Object;",
UNARY);
"(Ljava/lang/Object;)Ljava/lang/Object;", UNARY);
}
}
}
......@@ -60,12 +60,8 @@ public class RT {
/**
* bootstrap method for constant
*/
public static CallSite cst(
Lookup lookup,
String name,
MethodType type,
Object constant)
{
public static CallSite cst(Lookup lookup, String name, MethodType type,
Object constant) {
return new ConstantCallSite(MethodHandles.constant(Object.class,
constant));
}
......@@ -76,7 +72,8 @@ public class RT {
public static CallSite unary(Lookup lookup, String name, MethodType type) {
MethodHandle target;
if (name.equals("asBoolean")) {
target = MethodHandles.explicitCastArguments(MethodHandles.identity(Object.class),
target = MethodHandles.explicitCastArguments(
MethodHandles.identity(Object.class),
MethodType.methodType(boolean.class, Object.class));
} else { // "not"
target = MethodHandles.explicitCastArguments(NOT,
......@@ -109,18 +106,17 @@ public class RT {
* {@link RT#unary(Lookup, String, MethodType)}
*/
public static class UnayOps {
public static Object not(boolean b) {
return !b;
}
}
private static final MethodHandle NOT;
static {
try {
NOT = MethodHandles.publicLookup().findStatic(UnayOps.class,
"not",
NOT = MethodHandles.publicLookup().findStatic(UnayOps.class, "not",
MethodType.methodType(Object.class, boolean.class));
} catch (ReflectiveOperationException e) {
throw new LinkageError(e.getMessage(), e);
......@@ -139,9 +135,9 @@ public class RT {
* computed and two new guards will be installed.
*/
static class BinaryOpCallSite extends MutableCallSite {
private final String opName;
final MethodHandle fallback;
public BinaryOpCallSite(String opName, MethodType type) {
......@@ -155,8 +151,8 @@ public class RT {
// don't forget that && and || are lazy !!
// System.out.println("fallback called with "+opName+'('+v1.getClass()+','+v2.getClass()+')');
Class< ? extends Object> class1 = v1.getClass();
Class< ? extends Object> class2 = v2.getClass();
Class<? extends Object> class1 = v1.getClass();
Class<? extends Object> class2 = v2.getClass();
MethodHandle op = lookupBinaryOp(opName, class1, class2);
// convert arguments
......@@ -164,9 +160,7 @@ public class RT {
MethodType opType = op.type();
if (opType.parameterType(0) == String.class) {
if (opType.parameterType(1) == String.class) {
op = MethodHandles.filterArguments(op,
0,
TO_STRING,
op = MethodHandles.filterArguments(op, 0, TO_STRING,
TO_STRING);
} else {
op = MethodHandles.filterArguments(op, 0, TO_STRING);
......@@ -180,52 +174,44 @@ public class RT {
}
// prepare guard
MethodHandle guard = MethodHandles.guardWithTest(TEST1.bindTo(class1),
MethodHandles.guardWithTest(TEST2.bindTo(class2),
op,
fallback),
fallback);
MethodHandle guard = MethodHandles.guardWithTest(TEST1
.bindTo(class1), MethodHandles.guardWithTest(
TEST2.bindTo(class2), op, fallback), fallback);
// install the inlining cache
setTarget(guard);
return op.invokeWithArguments(v1, v2);
}
public static boolean test1(Class< ? > v1Class, Object v1, Object v2) {
public static boolean test1(Class<?> v1Class, Object v1, Object v2) {
return v1.getClass() == v1Class;
}
public static boolean test2(Class< ? > v2Class, Object v1, Object v2) {
public static boolean test2(Class<?> v2Class, Object v1, Object v2) {
return v2.getClass() == v2Class;
}