http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/ASMifier.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/ASMifier.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/ASMifier.java new file mode 100644 index 0000000..7fad810 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/ASMifier.java @@ -0,0 +1,1151 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.apache.tajo.org.objectweb.asm.util; + +import java.io.FileInputStream; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import org.apache.tajo.org.objectweb.asm.Label; +import org.apache.tajo.org.objectweb.asm.Type; +import org.apache.tajo.org.objectweb.asm.Attribute; +import org.apache.tajo.org.objectweb.asm.ClassReader; +import org.apache.tajo.org.objectweb.asm.Handle; +import org.apache.tajo.org.objectweb.asm.Opcodes; + +/** + * A {@link Printer} that prints the ASM code to generate the classes if visits. + * + * @author Eric Bruneton + */ +public class ASMifier extends Printer { + + /** + * The name of the visitor variable in the produced code. + */ + protected final String name; + + /** + * Identifier of the annotation visitor variable in the produced code. + */ + protected final int id; + + /** + * The label names. This map associates String values to Label keys. It is + * used only in ASMifierMethodVisitor. + */ + protected Map<Label, String> labelNames; + + /** + * Pseudo access flag used to distinguish class access flags. + */ + private static final int ACCESS_CLASS = 262144; + + /** + * Pseudo access flag used to distinguish field access flags. + */ + private static final int ACCESS_FIELD = 524288; + + /** + * Pseudo access flag used to distinguish inner class flags. + */ + private static final int ACCESS_INNER = 1048576; + + /** + * Constructs a new {@link ASMifier}. <i>Subclasses must not use this + * constructor</i>. Instead, they must use the + * {@link #ASMifier(int, String, int)} version. + */ + public ASMifier() { + this(Opcodes.ASM4, "cw", 0); + } + + /** + * Constructs a new {@link ASMifier}. + * + * @param api + * the ASM API version implemented by this class. Must be one of + * {@link Opcodes#ASM4}. + * @param name + * the name of the visitor variable in the produced code. + * @param id + * identifier of the annotation visitor variable in the produced + * code. + */ + protected ASMifier(final int api, final String name, final int id) { + super(api); + this.name = name; + this.id = id; + } + + /** + * Prints the ASM source code to generate the given class to the standard + * output. + * <p> + * Usage: ASMifier [-debug] <binary class name or class file name> + * + * @param args + * the command line arguments. + * + * @throws Exception + * if the class cannot be found, or if an IO exception occurs. + */ + public static void main(final String[] args) throws Exception { + int i = 0; + int flags = ClassReader.SKIP_DEBUG; + + boolean ok = true; + if (args.length < 1 || args.length > 2) { + ok = false; + } + if (ok && "-debug".equals(args[0])) { + i = 1; + flags = 0; + if (args.length != 2) { + ok = false; + } + } + if (!ok) { + System.err + .println("Prints the ASM code to generate the given class."); + System.err.println("Usage: ASMifier [-debug] " + + "<fully qualified class name or class file name>"); + return; + } + ClassReader cr; + if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1 + || args[i].indexOf('/') > -1) { + cr = new ClassReader(new FileInputStream(args[i])); + } else { + cr = new ClassReader(args[i]); + } + cr.accept(new TraceClassVisitor(null, new ASMifier(), new PrintWriter( + System.out)), flags); + } + + // ------------------------------------------------------------------------ + // Classes + // ------------------------------------------------------------------------ + + @Override + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + String simpleName; + int n = name.lastIndexOf('/'); + if (n == -1) { + simpleName = name; + } else { + text.add("package asm." + name.substring(0, n).replace('/', '.') + + ";\n"); + simpleName = name.substring(n + 1); + } + text.add("import java.util.*;\n"); + text.add("import org.objectweb.asm.*;\n"); + text.add("import org.objectweb.asm.attrs.*;\n"); + text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); + text.add("public static byte[] dump () throws Exception {\n\n"); + text.add("ClassWriter cw = new ClassWriter(0);\n"); + text.add("FieldVisitor fv;\n"); + text.add("MethodVisitor mv;\n"); + text.add("AnnotationVisitor av0;\n\n"); + + buf.setLength(0); + buf.append("cw.visit("); + switch (version) { + case Opcodes.V1_1: + buf.append("V1_1"); + break; + case Opcodes.V1_2: + buf.append("V1_2"); + break; + case Opcodes.V1_3: + buf.append("V1_3"); + break; + case Opcodes.V1_4: + buf.append("V1_4"); + break; + case Opcodes.V1_5: + buf.append("V1_5"); + break; + case Opcodes.V1_6: + buf.append("V1_6"); + break; + case Opcodes.V1_7: + buf.append("V1_7"); + break; + default: + buf.append(version); + break; + } + buf.append(", "); + appendAccess(access | ACCESS_CLASS); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + appendConstant(superName); + buf.append(", "); + if (interfaces != null && interfaces.length > 0) { + buf.append("new String[] {"); + for (int i = 0; i < interfaces.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendConstant(interfaces[i]); + } + buf.append(" }"); + } else { + buf.append("null"); + } + buf.append(");\n\n"); + text.add(buf.toString()); + } + + @Override + public void visitSource(final String file, final String debug) { + buf.setLength(0); + buf.append("cw.visitSource("); + appendConstant(file); + buf.append(", "); + appendConstant(debug); + buf.append(");\n\n"); + text.add(buf.toString()); + } + + @Override + public void visitOuterClass(final String owner, final String name, + final String desc) { + buf.setLength(0); + buf.append("cw.visitOuterClass("); + appendConstant(owner); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(");\n\n"); + text.add(buf.toString()); + } + + @Override + public ASMifier visitClassAnnotation(final String desc, + final boolean visible) { + return visitAnnotation(desc, visible); + } + + @Override + public void visitClassAttribute(final Attribute attr) { + visitAttribute(attr); + } + + @Override + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { + buf.setLength(0); + buf.append("cw.visitInnerClass("); + appendConstant(name); + buf.append(", "); + appendConstant(outerName); + buf.append(", "); + appendConstant(innerName); + buf.append(", "); + appendAccess(access | ACCESS_INNER); + buf.append(");\n\n"); + text.add(buf.toString()); + } + + @Override + public ASMifier visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + buf.setLength(0); + buf.append("{\n"); + buf.append("fv = cw.visitField("); + appendAccess(access | ACCESS_FIELD); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + appendConstant(value); + buf.append(");\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("fv", 0); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + @Override + public ASMifier visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + buf.setLength(0); + buf.append("{\n"); + buf.append("mv = cw.visitMethod("); + appendAccess(access); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + if (exceptions != null && exceptions.length > 0) { + buf.append("new String[] {"); + for (int i = 0; i < exceptions.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendConstant(exceptions[i]); + } + buf.append(" }"); + } else { + buf.append("null"); + } + buf.append(");\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("mv", 0); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + @Override + public void visitClassEnd() { + text.add("cw.visitEnd();\n\n"); + text.add("return cw.toByteArray();\n"); + text.add("}\n"); + text.add("}\n"); + } + + // ------------------------------------------------------------------------ + // Annotations + // ------------------------------------------------------------------------ + + @Override + public void visit(final String name, final Object value) { + buf.setLength(0); + buf.append("av").append(id).append(".visit("); + appendConstant(buf, name); + buf.append(", "); + appendConstant(buf, value); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitEnum(final String name, final String desc, + final String value) { + buf.setLength(0); + buf.append("av").append(id).append(".visitEnum("); + appendConstant(buf, name); + buf.append(", "); + appendConstant(buf, desc); + buf.append(", "); + appendConstant(buf, value); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public ASMifier visitAnnotation(final String name, final String desc) { + buf.setLength(0); + buf.append("{\n"); + buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); + buf.append(id).append(".visitAnnotation("); + appendConstant(buf, name); + buf.append(", "); + appendConstant(buf, desc); + buf.append(");\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("av", id + 1); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + @Override + public ASMifier visitArray(final String name) { + buf.setLength(0); + buf.append("{\n"); + buf.append("AnnotationVisitor av").append(id + 1).append(" = av"); + buf.append(id).append(".visitArray("); + appendConstant(buf, name); + buf.append(");\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("av", id + 1); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + @Override + public void visitAnnotationEnd() { + buf.setLength(0); + buf.append("av").append(id).append(".visitEnd();\n"); + text.add(buf.toString()); + } + + // ------------------------------------------------------------------------ + // Fields + // ------------------------------------------------------------------------ + + @Override + public ASMifier visitFieldAnnotation(final String desc, + final boolean visible) { + return visitAnnotation(desc, visible); + } + + @Override + public void visitFieldAttribute(final Attribute attr) { + visitAttribute(attr); + } + + @Override + public void visitFieldEnd() { + buf.setLength(0); + buf.append(name).append(".visitEnd();\n"); + text.add(buf.toString()); + } + + // ------------------------------------------------------------------------ + // Methods + // ------------------------------------------------------------------------ + + @Override + public ASMifier visitAnnotationDefault() { + buf.setLength(0); + buf.append("{\n").append("av0 = ").append(name) + .append(".visitAnnotationDefault();\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("av", 0); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + @Override + public ASMifier visitMethodAnnotation(final String desc, + final boolean visible) { + return visitAnnotation(desc, visible); + } + + @Override + public ASMifier visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { + buf.setLength(0); + buf.append("{\n").append("av0 = ").append(name) + .append(".visitParameterAnnotation(").append(parameter) + .append(", "); + appendConstant(desc); + buf.append(", ").append(visible).append(");\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("av", 0); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + @Override + public void visitMethodAttribute(final Attribute attr) { + visitAttribute(attr); + } + + @Override + public void visitCode() { + text.add(name + ".visitCode();\n"); + } + + @Override + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { + buf.setLength(0); + switch (type) { + case Opcodes.F_NEW: + case Opcodes.F_FULL: + declareFrameTypes(nLocal, local); + declareFrameTypes(nStack, stack); + if (type == Opcodes.F_NEW) { + buf.append(name).append(".visitFrame(Opcodes.F_NEW, "); + } else { + buf.append(name).append(".visitFrame(Opcodes.F_FULL, "); + } + buf.append(nLocal).append(", new Object[] {"); + appendFrameTypes(nLocal, local); + buf.append("}, ").append(nStack).append(", new Object[] {"); + appendFrameTypes(nStack, stack); + buf.append('}'); + break; + case Opcodes.F_APPEND: + declareFrameTypes(nLocal, local); + buf.append(name).append(".visitFrame(Opcodes.F_APPEND,") + .append(nLocal).append(", new Object[] {"); + appendFrameTypes(nLocal, local); + buf.append("}, 0, null"); + break; + case Opcodes.F_CHOP: + buf.append(name).append(".visitFrame(Opcodes.F_CHOP,") + .append(nLocal).append(", null, 0, null"); + break; + case Opcodes.F_SAME: + buf.append(name).append( + ".visitFrame(Opcodes.F_SAME, 0, null, 0, null"); + break; + case Opcodes.F_SAME1: + declareFrameTypes(1, stack); + buf.append(name).append( + ".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"); + appendFrameTypes(1, stack); + buf.append('}'); + break; + } + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitInsn(final int opcode) { + buf.setLength(0); + buf.append(name).append(".visitInsn(").append(OPCODES[opcode]) + .append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + buf.setLength(0); + buf.append(name) + .append(".visitIntInsn(") + .append(OPCODES[opcode]) + .append(", ") + .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer + .toString(operand)).append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + buf.setLength(0); + buf.append(name).append(".visitVarInsn(").append(OPCODES[opcode]) + .append(", ").append(var).append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + buf.setLength(0); + buf.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]) + .append(", "); + appendConstant(type); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { + buf.setLength(0); + buf.append(this.name).append(".visitFieldInsn(") + .append(OPCODES[opcode]).append(", "); + appendConstant(owner); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + buf.setLength(0); + buf.append(this.name).append(".visitMethodInsn(") + .append(OPCODES[opcode]).append(", "); + appendConstant(owner); + buf.append(", "); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { + buf.setLength(0); + buf.append(this.name).append(".visitInvokeDynamicInsn("); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(", "); + appendConstant(bsm); + buf.append(", new Object[]{"); + for (int i = 0; i < bsmArgs.length; ++i) { + appendConstant(bsmArgs[i]); + if (i != bsmArgs.length - 1) { + buf.append(", "); + } + } + buf.append("});\n"); + text.add(buf.toString()); + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + buf.setLength(0); + declareLabel(label); + buf.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]) + .append(", "); + appendLabel(label); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitLabel(final Label label) { + buf.setLength(0); + declareLabel(label); + buf.append(name).append(".visitLabel("); + appendLabel(label); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitLdcInsn(final Object cst) { + buf.setLength(0); + buf.append(name).append(".visitLdcInsn("); + appendConstant(cst); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitIincInsn(final int var, final int increment) { + buf.setLength(0); + buf.append(name).append(".visitIincInsn(").append(var).append(", ") + .append(increment).append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { + buf.setLength(0); + for (int i = 0; i < labels.length; ++i) { + declareLabel(labels[i]); + } + declareLabel(dflt); + + buf.append(name).append(".visitTableSwitchInsn(").append(min) + .append(", ").append(max).append(", "); + appendLabel(dflt); + buf.append(", new Label[] {"); + for (int i = 0; i < labels.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendLabel(labels[i]); + } + buf.append(" });\n"); + text.add(buf.toString()); + } + + @Override + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { + buf.setLength(0); + for (int i = 0; i < labels.length; ++i) { + declareLabel(labels[i]); + } + declareLabel(dflt); + + buf.append(name).append(".visitLookupSwitchInsn("); + appendLabel(dflt); + buf.append(", new int[] {"); + for (int i = 0; i < keys.length; ++i) { + buf.append(i == 0 ? " " : ", ").append(keys[i]); + } + buf.append(" }, new Label[] {"); + for (int i = 0; i < labels.length; ++i) { + buf.append(i == 0 ? " " : ", "); + appendLabel(labels[i]); + } + buf.append(" });\n"); + text.add(buf.toString()); + } + + @Override + public void visitMultiANewArrayInsn(final String desc, final int dims) { + buf.setLength(0); + buf.append(name).append(".visitMultiANewArrayInsn("); + appendConstant(desc); + buf.append(", ").append(dims).append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { + buf.setLength(0); + declareLabel(start); + declareLabel(end); + declareLabel(handler); + buf.append(name).append(".visitTryCatchBlock("); + appendLabel(start); + buf.append(", "); + appendLabel(end); + buf.append(", "); + appendLabel(handler); + buf.append(", "); + appendConstant(type); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { + buf.setLength(0); + buf.append(this.name).append(".visitLocalVariable("); + appendConstant(name); + buf.append(", "); + appendConstant(desc); + buf.append(", "); + appendConstant(signature); + buf.append(", "); + appendLabel(start); + buf.append(", "); + appendLabel(end); + buf.append(", ").append(index).append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitLineNumber(final int line, final Label start) { + buf.setLength(0); + buf.append(name).append(".visitLineNumber(").append(line).append(", "); + appendLabel(start); + buf.append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + buf.setLength(0); + buf.append(name).append(".visitMaxs(").append(maxStack).append(", ") + .append(maxLocals).append(");\n"); + text.add(buf.toString()); + } + + @Override + public void visitMethodEnd() { + buf.setLength(0); + buf.append(name).append(".visitEnd();\n"); + text.add(buf.toString()); + } + + // ------------------------------------------------------------------------ + // Common methods + // ------------------------------------------------------------------------ + + public ASMifier visitAnnotation(final String desc, final boolean visible) { + buf.setLength(0); + buf.append("{\n").append("av0 = ").append(name) + .append(".visitAnnotation("); + appendConstant(desc); + buf.append(", ").append(visible).append(");\n"); + text.add(buf.toString()); + ASMifier a = createASMifier("av", 0); + text.add(a.getText()); + text.add("}\n"); + return a; + } + + public void visitAttribute(final Attribute attr) { + buf.setLength(0); + buf.append("// ATTRIBUTE ").append(attr.type).append('\n'); + if (attr instanceof ASMifiable) { + if (labelNames == null) { + labelNames = new HashMap<Label, String>(); + } + buf.append("{\n"); + ((ASMifiable) attr).asmify(buf, "attr", labelNames); + buf.append(name).append(".visitAttribute(attr);\n"); + buf.append("}\n"); + } + text.add(buf.toString()); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + protected ASMifier createASMifier(final String name, final int id) { + return new ASMifier(Opcodes.ASM4, name, id); + } + + /** + * Appends a string representation of the given access modifiers to + * {@link #buf buf}. + * + * @param access + * some access modifiers. + */ + void appendAccess(final int access) { + boolean first = true; + if ((access & Opcodes.ACC_PUBLIC) != 0) { + buf.append("ACC_PUBLIC"); + first = false; + } + if ((access & Opcodes.ACC_PRIVATE) != 0) { + buf.append("ACC_PRIVATE"); + first = false; + } + if ((access & Opcodes.ACC_PROTECTED) != 0) { + buf.append("ACC_PROTECTED"); + first = false; + } + if ((access & Opcodes.ACC_FINAL) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_FINAL"); + first = false; + } + if ((access & Opcodes.ACC_STATIC) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_STATIC"); + first = false; + } + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { + if (!first) { + buf.append(" + "); + } + if ((access & ACCESS_CLASS) == 0) { + buf.append("ACC_SYNCHRONIZED"); + } else { + buf.append("ACC_SUPER"); + } + first = false; + } + if ((access & Opcodes.ACC_VOLATILE) != 0 + && (access & ACCESS_FIELD) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_VOLATILE"); + first = false; + } + if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0 + && (access & ACCESS_FIELD) == 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_BRIDGE"); + first = false; + } + if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0 + && (access & ACCESS_FIELD) == 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_VARARGS"); + first = false; + } + if ((access & Opcodes.ACC_TRANSIENT) != 0 + && (access & ACCESS_FIELD) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_TRANSIENT"); + first = false; + } + if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0 + && (access & ACCESS_FIELD) == 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_NATIVE"); + first = false; + } + if ((access & Opcodes.ACC_ENUM) != 0 + && ((access & ACCESS_CLASS) != 0 + || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0)) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_ENUM"); + first = false; + } + if ((access & Opcodes.ACC_ANNOTATION) != 0 + && ((access & ACCESS_CLASS) != 0 || (access & ACCESS_INNER) != 0)) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_ANNOTATION"); + first = false; + } + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_ABSTRACT"); + first = false; + } + if ((access & Opcodes.ACC_INTERFACE) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_INTERFACE"); + first = false; + } + if ((access & Opcodes.ACC_STRICT) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_STRICT"); + first = false; + } + if ((access & Opcodes.ACC_SYNTHETIC) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_SYNTHETIC"); + first = false; + } + if ((access & Opcodes.ACC_DEPRECATED) != 0) { + if (!first) { + buf.append(" + "); + } + buf.append("ACC_DEPRECATED"); + first = false; + } + if (first) { + buf.append('0'); + } + } + + /** + * Appends a string representation of the given constant to the given + * buffer. + * + * @param cst + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double} or {@link String} object. May be <tt>null</tt>. + */ + protected void appendConstant(final Object cst) { + appendConstant(buf, cst); + } + + /** + * Appends a string representation of the given constant to the given + * buffer. + * + * @param buf + * a string buffer. + * @param cst + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double} or {@link String} object. May be <tt>null</tt>. + */ + static void appendConstant(final StringBuffer buf, final Object cst) { + if (cst == null) { + buf.append("null"); + } else if (cst instanceof String) { + appendString(buf, (String) cst); + } else if (cst instanceof Type) { + buf.append("Type.getType(\""); + buf.append(((Type) cst).getDescriptor()); + buf.append("\")"); + } else if (cst instanceof Handle) { + buf.append("new Handle("); + Handle h = (Handle) cst; + buf.append("Opcodes.").append(HANDLE_TAG[h.getTag()]) + .append(", \""); + buf.append(h.getOwner()).append("\", \""); + buf.append(h.getName()).append("\", \""); + buf.append(h.getDesc()).append("\")"); + } else if (cst instanceof Byte) { + buf.append("new Byte((byte)").append(cst).append(')'); + } else if (cst instanceof Boolean) { + buf.append(((Boolean) cst).booleanValue() ? "Boolean.TRUE" + : "Boolean.FALSE"); + } else if (cst instanceof Short) { + buf.append("new Short((short)").append(cst).append(')'); + } else if (cst instanceof Character) { + int c = ((Character) cst).charValue(); + buf.append("new Character((char)").append(c).append(')'); + } else if (cst instanceof Integer) { + buf.append("new Integer(").append(cst).append(')'); + } else if (cst instanceof Float) { + buf.append("new Float(\"").append(cst).append("\")"); + } else if (cst instanceof Long) { + buf.append("new Long(").append(cst).append("L)"); + } else if (cst instanceof Double) { + buf.append("new Double(\"").append(cst).append("\")"); + } else if (cst instanceof byte[]) { + byte[] v = (byte[]) cst; + buf.append("new byte[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]); + } + buf.append('}'); + } else if (cst instanceof boolean[]) { + boolean[] v = (boolean[]) cst; + buf.append("new boolean[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]); + } + buf.append('}'); + } else if (cst instanceof short[]) { + short[] v = (short[]) cst; + buf.append("new short[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append("(short)").append(v[i]); + } + buf.append('}'); + } else if (cst instanceof char[]) { + char[] v = (char[]) cst; + buf.append("new char[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append("(char)") + .append((int) v[i]); + } + buf.append('}'); + } else if (cst instanceof int[]) { + int[] v = (int[]) cst; + buf.append("new int[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]); + } + buf.append('}'); + } else if (cst instanceof long[]) { + long[] v = (long[]) cst; + buf.append("new long[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]).append('L'); + } + buf.append('}'); + } else if (cst instanceof float[]) { + float[] v = (float[]) cst; + buf.append("new float[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]).append('f'); + } + buf.append('}'); + } else if (cst instanceof double[]) { + double[] v = (double[]) cst; + buf.append("new double[] {"); + for (int i = 0; i < v.length; i++) { + buf.append(i == 0 ? "" : ",").append(v[i]).append('d'); + } + buf.append('}'); + } + } + + private void declareFrameTypes(final int n, final Object[] o) { + for (int i = 0; i < n; ++i) { + if (o[i] instanceof Label) { + declareLabel((Label) o[i]); + } + } + } + + private void appendFrameTypes(final int n, final Object[] o) { + for (int i = 0; i < n; ++i) { + if (i > 0) { + buf.append(", "); + } + if (o[i] instanceof String) { + appendConstant(o[i]); + } else if (o[i] instanceof Integer) { + switch (((Integer) o[i]).intValue()) { + case 0: + buf.append("Opcodes.TOP"); + break; + case 1: + buf.append("Opcodes.INTEGER"); + break; + case 2: + buf.append("Opcodes.FLOAT"); + break; + case 3: + buf.append("Opcodes.DOUBLE"); + break; + case 4: + buf.append("Opcodes.LONG"); + break; + case 5: + buf.append("Opcodes.NULL"); + break; + case 6: + buf.append("Opcodes.UNINITIALIZED_THIS"); + break; + } + } else { + appendLabel((Label) o[i]); + } + } + } + + /** + * Appends a declaration of the given label to {@link #buf buf}. This + * declaration is of the form "Label lXXX = new Label();". Does nothing if + * the given label has already been declared. + * + * @param l + * a label. + */ + protected void declareLabel(final Label l) { + if (labelNames == null) { + labelNames = new HashMap<Label, String>(); + } + String name = labelNames.get(l); + if (name == null) { + name = "l" + labelNames.size(); + labelNames.put(l, name); + buf.append("Label ").append(name).append(" = new Label();\n"); + } + } + + /** + * Appends the name of the given label to {@link #buf buf}. The given label + * <i>must</i> already have a name. One way to ensure this is to always call + * {@link #declareLabel declared} before calling this method. + * + * @param l + * a label. + */ + protected void appendLabel(final Label l) { + buf.append(labelNames.get(l)); + } +}
http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckAnnotationAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckAnnotationAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckAnnotationAdapter.java new file mode 100644 index 0000000..48cc077 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckAnnotationAdapter.java @@ -0,0 +1,136 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.apache.tajo.org.objectweb.asm.util; + +import org.apache.tajo.org.objectweb.asm.AnnotationVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; +import org.apache.tajo.org.objectweb.asm.Type; + +/** + * An {@link AnnotationVisitor} that checks that its methods are properly used. + * + * @author Eric Bruneton + */ +public class CheckAnnotationAdapter extends AnnotationVisitor { + + private final boolean named; + + private boolean end; + + public CheckAnnotationAdapter(final AnnotationVisitor av) { + this(av, true); + } + + CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) { + super(Opcodes.ASM4, av); + this.named = named; + } + + @Override + public void visit(final String name, final Object value) { + checkEnd(); + checkName(name); + if (!(value instanceof Byte || value instanceof Boolean + || value instanceof Character || value instanceof Short + || value instanceof Integer || value instanceof Long + || value instanceof Float || value instanceof Double + || value instanceof String || value instanceof Type + || value instanceof byte[] || value instanceof boolean[] + || value instanceof char[] || value instanceof short[] + || value instanceof int[] || value instanceof long[] + || value instanceof float[] || value instanceof double[])) { + throw new IllegalArgumentException("Invalid annotation value"); + } + if (value instanceof Type) { + int sort = ((Type) value).getSort(); + if (sort != Type.OBJECT && sort != Type.ARRAY) { + throw new IllegalArgumentException("Invalid annotation value"); + } + } + if (av != null) { + av.visit(name, value); + } + } + + @Override + public void visitEnum(final String name, final String desc, + final String value) { + checkEnd(); + checkName(name); + CheckMethodAdapter.checkDesc(desc, false); + if (value == null) { + throw new IllegalArgumentException("Invalid enum value"); + } + if (av != null) { + av.visitEnum(name, desc, value); + } + } + + @Override + public AnnotationVisitor visitAnnotation(final String name, + final String desc) { + checkEnd(); + checkName(name); + CheckMethodAdapter.checkDesc(desc, false); + return new CheckAnnotationAdapter(av == null ? null + : av.visitAnnotation(name, desc)); + } + + @Override + public AnnotationVisitor visitArray(final String name) { + checkEnd(); + checkName(name); + return new CheckAnnotationAdapter(av == null ? null + : av.visitArray(name), false); + } + + @Override + public void visitEnd() { + checkEnd(); + end = true; + if (av != null) { + av.visitEnd(); + } + } + + private void checkEnd() { + if (end) { + throw new IllegalStateException( + "Cannot call a visit method after visitEnd has been called"); + } + } + + private void checkName(final String name) { + if (named && name == null) { + throw new IllegalArgumentException( + "Annotation value name must not be null"); + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckClassAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckClassAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckClassAdapter.java new file mode 100644 index 0000000..412c803 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckClassAdapter.java @@ -0,0 +1,914 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.apache.tajo.org.objectweb.asm.util; + +import java.io.FileInputStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.tajo.org.objectweb.asm.AnnotationVisitor; +import org.apache.tajo.org.objectweb.asm.FieldVisitor; +import org.apache.tajo.org.objectweb.asm.Label; +import org.apache.tajo.org.objectweb.asm.Type; +import org.apache.tajo.org.objectweb.asm.tree.ClassNode; +import org.apache.tajo.org.objectweb.asm.tree.MethodNode; +import org.apache.tajo.org.objectweb.asm.tree.analysis.Frame; +import org.apache.tajo.org.objectweb.asm.tree.analysis.SimpleVerifier; +import org.apache.tajo.org.objectweb.asm.Attribute; +import org.apache.tajo.org.objectweb.asm.ClassReader; +import org.apache.tajo.org.objectweb.asm.ClassVisitor; +import org.apache.tajo.org.objectweb.asm.MethodVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; +import org.apache.tajo.org.objectweb.asm.tree.analysis.Analyzer; +import org.apache.tajo.org.objectweb.asm.tree.analysis.BasicValue; + +/** + * A {@link ClassVisitor} that checks that its methods are properly used. More + * precisely this class adapter checks each method call individually, based + * <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i> + * of method calls. For example, the invalid sequence + * <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC, + * "i", "D", null)</tt> will <i>not</i> be detected by this class adapter. + * + * <p> + * <code>CheckClassAdapter</code> can be also used to verify bytecode + * transformations in order to make sure transformed bytecode is sane. For + * example: + * + * <pre> + * InputStream is = ...; // get bytes for the source class + * ClassReader cr = new ClassReader(is); + * ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); + * ClassVisitor cv = new <b>MyClassAdapter</b>(new CheckClassAdapter(cw)); + * cr.accept(cv, 0); + * + * StringWriter sw = new StringWriter(); + * PrintWriter pw = new PrintWriter(sw); + * CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw); + * assertTrue(sw.toString(), sw.toString().length()==0); + * </pre> + * + * Above code runs transformed bytecode trough the + * <code>CheckClassAdapter</code>. It won't be exactly the same verification as + * JVM does, but it run data flow analysis for the code of each method and + * checks that expectations are met for each method instruction. + * + * <p> + * If method bytecode has errors, assertion text will show the erroneous + * instruction number and dump of the failed method with information about + * locals and stack slot for each instruction. For example (format is - + * insnNumber locals : stack): + * + * <pre> + * AnalyzerException: Error at instruction 71: Expected I, but found . + * at Analyzer.analyze(Analyzer.java:289) + * at CheckClassAdapter.verify(CheckClassAdapter.java:135) + * ... + * remove()V + * 00000 LinkedBlockingQueue$Itr . . . . . . . . : + * ICONST_0 + * 00001 LinkedBlockingQueue$Itr . . . . . . . . : I + * ISTORE 2 + * 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . : + * ... + * + * 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . : + * ILOAD 1 + * 00072 <b>?</b> + * INVOKESPECIAL java/lang/Integer.<init> (I)V + * ... + * </pre> + * + * In the above output you can see that variable 1 loaded by + * <code>ILOAD 1</code> instruction at position <code>00071</code> is not + * initialized. You can also see that at the beginning of the method (code + * inserted by the transformation) variable 2 is initialized. + * + * <p> + * Note that when used like that, <code>CheckClassAdapter.verify()</code> can + * trigger additional class loading, because it is using + * <code>SimpleVerifier</code>. + * + * @author Eric Bruneton + */ +public class CheckClassAdapter extends ClassVisitor { + + /** + * The class version number. + */ + private int version; + + /** + * <tt>true</tt> if the visit method has been called. + */ + private boolean start; + + /** + * <tt>true</tt> if the visitSource method has been called. + */ + private boolean source; + + /** + * <tt>true</tt> if the visitOuterClass method has been called. + */ + private boolean outer; + + /** + * <tt>true</tt> if the visitEnd method has been called. + */ + private boolean end; + + /** + * The already visited labels. This map associate Integer values to Label + * keys. + */ + private Map<Label, Integer> labels; + + /** + * <tt>true</tt> if the method code must be checked with a BasicVerifier. + */ + private boolean checkDataFlow; + + /** + * Checks a given class. + * <p> + * Usage: CheckClassAdapter <binary class name or class file name> + * + * @param args + * the command line arguments. + * + * @throws Exception + * if the class cannot be found, or if an IO exception occurs. + */ + public static void main(final String[] args) throws Exception { + if (args.length != 1) { + System.err.println("Verifies the given class."); + System.err.println("Usage: CheckClassAdapter " + + "<fully qualified class name or class file name>"); + return; + } + ClassReader cr; + if (args[0].endsWith(".class")) { + cr = new ClassReader(new FileInputStream(args[0])); + } else { + cr = new ClassReader(args[0]); + } + + verify(cr, false, new PrintWriter(System.err)); + } + + /** + * Checks a given class. + * + * @param cr + * a <code>ClassReader</code> that contains bytecode for the + * analysis. + * @param loader + * a <code>ClassLoader</code> which will be used to load + * referenced classes. This is useful if you are verifiying + * multiple interdependent classes. + * @param dump + * true if bytecode should be printed out not only when errors + * are found. + * @param pw + * write where results going to be printed + */ + public static void verify(final ClassReader cr, final ClassLoader loader, + final boolean dump, final PrintWriter pw) { + ClassNode cn = new ClassNode(); + cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); + + Type syperType = cn.superName == null ? null : Type + .getObjectType(cn.superName); + List<MethodNode> methods = cn.methods; + + List<Type> interfaces = new ArrayList<Type>(); + for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) { + interfaces.add(Type.getObjectType(i.next().toString())); + } + + for (int i = 0; i < methods.size(); ++i) { + MethodNode method = methods.get(i); + SimpleVerifier verifier = new SimpleVerifier( + Type.getObjectType(cn.name), syperType, interfaces, + (cn.access & Opcodes.ACC_INTERFACE) != 0); + Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier); + if (loader != null) { + verifier.setClassLoader(loader); + } + try { + a.analyze(cn.name, method); + if (!dump) { + continue; + } + } catch (Exception e) { + e.printStackTrace(pw); + } + printAnalyzerResult(method, a, pw); + } + pw.flush(); + } + + /** + * Checks a given class + * + * @param cr + * a <code>ClassReader</code> that contains bytecode for the + * analysis. + * @param dump + * true if bytecode should be printed out not only when errors + * are found. + * @param pw + * write where results going to be printed + */ + public static void verify(final ClassReader cr, final boolean dump, + final PrintWriter pw) { + verify(cr, null, dump, pw); + } + + static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a, + final PrintWriter pw) { + Frame<BasicValue>[] frames = a.getFrames(); + Textifier t = new Textifier(); + TraceMethodVisitor mv = new TraceMethodVisitor(t); + + pw.println(method.name + method.desc); + for (int j = 0; j < method.instructions.size(); ++j) { + method.instructions.get(j).accept(mv); + + StringBuffer s = new StringBuffer(); + Frame<BasicValue> f = frames[j]; + if (f == null) { + s.append('?'); + } else { + for (int k = 0; k < f.getLocals(); ++k) { + s.append(getShortName(f.getLocal(k).toString())) + .append(' '); + } + s.append(" : "); + for (int k = 0; k < f.getStackSize(); ++k) { + s.append(getShortName(f.getStack(k).toString())) + .append(' '); + } + } + while (s.length() < method.maxStack + method.maxLocals + 1) { + s.append(' '); + } + pw.print(Integer.toString(j + 100000).substring(1)); + pw.print(" " + s + " : " + t.text.get(t.text.size() - 1)); + } + for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { + method.tryCatchBlocks.get(j).accept(mv); + pw.print(" " + t.text.get(t.text.size() - 1)); + } + pw.println(); + } + + private static String getShortName(final String name) { + int n = name.lastIndexOf('/'); + int k = name.length(); + if (name.charAt(k - 1) == ';') { + k--; + } + return n == -1 ? name : name.substring(n + 1, k); + } + + /** + * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use + * this constructor</i>. Instead, they must use the + * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. + * + * @param cv + * the class visitor to which this adapter must delegate calls. + */ + public CheckClassAdapter(final ClassVisitor cv) { + this(cv, true); + } + + /** + * Constructs a new {@link CheckClassAdapter}. <i>Subclasses must not use + * this constructor</i>. Instead, they must use the + * {@link #CheckClassAdapter(int, ClassVisitor, boolean)} version. + * + * @param cv + * the class visitor to which this adapter must delegate calls. + * @param checkDataFlow + * <tt>true</tt> to perform basic data flow checks, or + * <tt>false</tt> to not perform any data flow check (see + * {@link CheckMethodAdapter}). This option requires valid + * maxLocals and maxStack values. + */ + public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) { + this(Opcodes.ASM4, cv, checkDataFlow); + } + + /** + * Constructs a new {@link CheckClassAdapter}. + * + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param cv + * the class visitor to which this adapter must delegate calls. + * @param checkDataFlow + * <tt>true</tt> to perform basic data flow checks, or + * <tt>false</tt> to not perform any data flow check (see + * {@link CheckMethodAdapter}). This option requires valid + * maxLocals and maxStack values. + */ + protected CheckClassAdapter(final int api, final ClassVisitor cv, + final boolean checkDataFlow) { + super(api, cv); + this.labels = new HashMap<Label, Integer>(); + this.checkDataFlow = checkDataFlow; + } + + // ------------------------------------------------------------------------ + // Implementation of the ClassVisitor interface + // ------------------------------------------------------------------------ + + @Override + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + if (start) { + throw new IllegalStateException("visit must be called only once"); + } + start = true; + checkState(); + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + + Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE + + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM + + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + if (name == null || !name.endsWith("package-info")) { + CheckMethodAdapter.checkInternalName(name, "class name"); + } + if ("java/lang/Object".equals(name)) { + if (superName != null) { + throw new IllegalArgumentException( + "The super class name of the Object class must be 'null'"); + } + } else { + CheckMethodAdapter.checkInternalName(superName, "super class name"); + } + if (signature != null) { + checkClassSignature(signature); + } + if ((access & Opcodes.ACC_INTERFACE) != 0) { + if (!"java/lang/Object".equals(superName)) { + throw new IllegalArgumentException( + "The super class name of interfaces must be 'java/lang/Object'"); + } + } + if (interfaces != null) { + for (int i = 0; i < interfaces.length; ++i) { + CheckMethodAdapter.checkInternalName(interfaces[i], + "interface name at index " + i); + } + } + this.version = version; + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public void visitSource(final String file, final String debug) { + checkState(); + if (source) { + throw new IllegalStateException( + "visitSource can be called only once."); + } + source = true; + super.visitSource(file, debug); + } + + @Override + public void visitOuterClass(final String owner, final String name, + final String desc) { + checkState(); + if (outer) { + throw new IllegalStateException( + "visitOuterClass can be called only once."); + } + outer = true; + if (owner == null) { + throw new IllegalArgumentException("Illegal outer class owner"); + } + if (desc != null) { + CheckMethodAdapter.checkMethodDesc(desc); + } + super.visitOuterClass(owner, name, desc); + } + + @Override + public void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { + checkState(); + CheckMethodAdapter.checkInternalName(name, "class name"); + if (outerName != null) { + CheckMethodAdapter.checkInternalName(outerName, "outer class name"); + } + if (innerName != null) { + int start = 0; + while (start < innerName.length() + && Character.isDigit(innerName.charAt(start))) { + start++; + } + if (start == 0 || start < innerName.length()) { + CheckMethodAdapter.checkIdentifier(innerName, start, -1, + "inner class name"); + } + } + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + + Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE + + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM); + super.visitInnerClass(name, outerName, innerName, access); + } + + @Override + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + checkState(); + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + + Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE + + Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC + + Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + CheckMethodAdapter.checkUnqualifiedName(version, name, "field name"); + CheckMethodAdapter.checkDesc(desc, false); + if (signature != null) { + checkFieldSignature(signature); + } + if (value != null) { + CheckMethodAdapter.checkConstant(value); + } + FieldVisitor av = super + .visitField(access, name, desc, signature, value); + return new CheckFieldAdapter(av); + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + checkState(); + checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE + + Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC + + Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED + + Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE + + Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT + + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + if (!"<init>".equals(name) && !"<clinit>".equals(name)) { + CheckMethodAdapter.checkMethodIdentifier(version, name, + "method name"); + } + CheckMethodAdapter.checkMethodDesc(desc); + if (signature != null) { + checkMethodSignature(signature); + } + if (exceptions != null) { + for (int i = 0; i < exceptions.length; ++i) { + CheckMethodAdapter.checkInternalName(exceptions[i], + "exception name at index " + i); + } + } + CheckMethodAdapter cma; + if (checkDataFlow) { + cma = new CheckMethodAdapter(access, name, desc, super.visitMethod( + access, name, desc, signature, exceptions), labels); + } else { + cma = new CheckMethodAdapter(super.visitMethod(access, name, desc, + signature, exceptions), labels); + } + cma.version = version; + return cma; + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + checkState(); + CheckMethodAdapter.checkDesc(desc, false); + return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); + } + + @Override + public void visitAttribute(final Attribute attr) { + checkState(); + if (attr == null) { + throw new IllegalArgumentException( + "Invalid attribute (must not be null)"); + } + super.visitAttribute(attr); + } + + @Override + public void visitEnd() { + checkState(); + end = true; + super.visitEnd(); + } + + // ------------------------------------------------------------------------ + // Utility methods + // ------------------------------------------------------------------------ + + /** + * Checks that the visit method has been called and that visitEnd has not + * been called. + */ + private void checkState() { + if (!start) { + throw new IllegalStateException( + "Cannot visit member before visit has been called."); + } + if (end) { + throw new IllegalStateException( + "Cannot visit member after visitEnd has been called."); + } + } + + /** + * Checks that the given access flags do not contain invalid flags. This + * method also checks that mutually incompatible flags are not set + * simultaneously. + * + * @param access + * the access flags to be checked + * @param possibleAccess + * the valid access flags. + */ + static void checkAccess(final int access, final int possibleAccess) { + if ((access & ~possibleAccess) != 0) { + throw new IllegalArgumentException("Invalid access flags: " + + access); + } + int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1; + int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1; + int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1; + if (pub + pri + pro > 1) { + throw new IllegalArgumentException( + "public private and protected are mutually exclusive: " + + access); + } + int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1; + int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1; + if (fin + abs > 1) { + throw new IllegalArgumentException( + "final and abstract are mutually exclusive: " + access); + } + } + + /** + * Checks a class signature. + * + * @param signature + * a string containing the signature that must be checked. + */ + public static void checkClassSignature(final String signature) { + // ClassSignature: + // FormalTypeParameters? ClassTypeSignature ClassTypeSignature* + + int pos = 0; + if (getChar(signature, 0) == '<') { + pos = checkFormalTypeParameters(signature, pos); + } + pos = checkClassTypeSignature(signature, pos); + while (getChar(signature, pos) == 'L') { + pos = checkClassTypeSignature(signature, pos); + } + if (pos != signature.length()) { + throw new IllegalArgumentException(signature + ": error at index " + + pos); + } + } + + /** + * Checks a method signature. + * + * @param signature + * a string containing the signature that must be checked. + */ + public static void checkMethodSignature(final String signature) { + // MethodTypeSignature: + // FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) ( + // ^ClassTypeSignature | ^TypeVariableSignature )* + + int pos = 0; + if (getChar(signature, 0) == '<') { + pos = checkFormalTypeParameters(signature, pos); + } + pos = checkChar('(', signature, pos); + while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) { + pos = checkTypeSignature(signature, pos); + } + pos = checkChar(')', signature, pos); + if (getChar(signature, pos) == 'V') { + ++pos; + } else { + pos = checkTypeSignature(signature, pos); + } + while (getChar(signature, pos) == '^') { + ++pos; + if (getChar(signature, pos) == 'L') { + pos = checkClassTypeSignature(signature, pos); + } else { + pos = checkTypeVariableSignature(signature, pos); + } + } + if (pos != signature.length()) { + throw new IllegalArgumentException(signature + ": error at index " + + pos); + } + } + + /** + * Checks a field signature. + * + * @param signature + * a string containing the signature that must be checked. + */ + public static void checkFieldSignature(final String signature) { + int pos = checkFieldTypeSignature(signature, 0); + if (pos != signature.length()) { + throw new IllegalArgumentException(signature + ": error at index " + + pos); + } + } + + /** + * Checks the formal type parameters of a class or method signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkFormalTypeParameters(final String signature, int pos) { + // FormalTypeParameters: + // < FormalTypeParameter+ > + + pos = checkChar('<', signature, pos); + pos = checkFormalTypeParameter(signature, pos); + while (getChar(signature, pos) != '>') { + pos = checkFormalTypeParameter(signature, pos); + } + return pos + 1; + } + + /** + * Checks a formal type parameter of a class or method signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkFormalTypeParameter(final String signature, int pos) { + // FormalTypeParameter: + // Identifier : FieldTypeSignature? (: FieldTypeSignature)* + + pos = checkIdentifier(signature, pos); + pos = checkChar(':', signature, pos); + if ("L[T".indexOf(getChar(signature, pos)) != -1) { + pos = checkFieldTypeSignature(signature, pos); + } + while (getChar(signature, pos) == ':') { + pos = checkFieldTypeSignature(signature, pos + 1); + } + return pos; + } + + /** + * Checks a field type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkFieldTypeSignature(final String signature, int pos) { + // FieldTypeSignature: + // ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature + // + // ArrayTypeSignature: + // [ TypeSignature + + switch (getChar(signature, pos)) { + case 'L': + return checkClassTypeSignature(signature, pos); + case '[': + return checkTypeSignature(signature, pos + 1); + default: + return checkTypeVariableSignature(signature, pos); + } + } + + /** + * Checks a class type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkClassTypeSignature(final String signature, int pos) { + // ClassTypeSignature: + // L Identifier ( / Identifier )* TypeArguments? ( . Identifier + // TypeArguments? )* ; + + pos = checkChar('L', signature, pos); + pos = checkIdentifier(signature, pos); + while (getChar(signature, pos) == '/') { + pos = checkIdentifier(signature, pos + 1); + } + if (getChar(signature, pos) == '<') { + pos = checkTypeArguments(signature, pos); + } + while (getChar(signature, pos) == '.') { + pos = checkIdentifier(signature, pos + 1); + if (getChar(signature, pos) == '<') { + pos = checkTypeArguments(signature, pos); + } + } + return checkChar(';', signature, pos); + } + + /** + * Checks the type arguments in a class type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeArguments(final String signature, int pos) { + // TypeArguments: + // < TypeArgument+ > + + pos = checkChar('<', signature, pos); + pos = checkTypeArgument(signature, pos); + while (getChar(signature, pos) != '>') { + pos = checkTypeArgument(signature, pos); + } + return pos + 1; + } + + /** + * Checks a type argument in a class type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeArgument(final String signature, int pos) { + // TypeArgument: + // * | ( ( + | - )? FieldTypeSignature ) + + char c = getChar(signature, pos); + if (c == '*') { + return pos + 1; + } else if (c == '+' || c == '-') { + pos++; + } + return checkFieldTypeSignature(signature, pos); + } + + /** + * Checks a type variable signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeVariableSignature(final String signature, + int pos) { + // TypeVariableSignature: + // T Identifier ; + + pos = checkChar('T', signature, pos); + pos = checkIdentifier(signature, pos); + return checkChar(';', signature, pos); + } + + /** + * Checks a type signature. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkTypeSignature(final String signature, int pos) { + // TypeSignature: + // Z | C | B | S | I | F | J | D | FieldTypeSignature + + switch (getChar(signature, pos)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + return pos + 1; + default: + return checkFieldTypeSignature(signature, pos); + } + } + + /** + * Checks an identifier. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkIdentifier(final String signature, int pos) { + if (!Character.isJavaIdentifierStart(getChar(signature, pos))) { + throw new IllegalArgumentException(signature + + ": identifier expected at index " + pos); + } + ++pos; + while (Character.isJavaIdentifierPart(getChar(signature, pos))) { + ++pos; + } + return pos; + } + + /** + * Checks a single character. + * + * @param signature + * a string containing the signature that must be checked. + * @param pos + * index of first character to be checked. + * @return the index of the first character after the checked part. + */ + private static int checkChar(final char c, final String signature, int pos) { + if (getChar(signature, pos) == c) { + return pos + 1; + } + throw new IllegalArgumentException(signature + ": '" + c + + "' expected at index " + pos); + } + + /** + * Returns the signature car at the given index. + * + * @param signature + * a signature. + * @param pos + * an index in signature. + * @return the character at the given index, or 0 if there is no such + * character. + */ + private static char getChar(final String signature, int pos) { + return pos < signature.length() ? signature.charAt(pos) : (char) 0; + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckFieldAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckFieldAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckFieldAdapter.java new file mode 100644 index 0000000..2b4b7d1 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckFieldAdapter.java @@ -0,0 +1,100 @@ +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.apache.tajo.org.objectweb.asm.util; + +import org.apache.tajo.org.objectweb.asm.AnnotationVisitor; +import org.apache.tajo.org.objectweb.asm.Attribute; +import org.apache.tajo.org.objectweb.asm.FieldVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; + +/** + * A {@link org.apache.tajo.org.objectweb.asm.FieldVisitor} that checks that its methods are properly used. + */ +public class CheckFieldAdapter extends FieldVisitor { + + private boolean end; + + /** + * Constructs a new {@link CheckFieldAdapter}. <i>Subclasses must not use + * this constructor</i>. Instead, they must use the + * {@link #CheckFieldAdapter(int, FieldVisitor)} version. + * + * @param fv + * the field visitor to which this adapter must delegate calls. + */ + public CheckFieldAdapter(final FieldVisitor fv) { + this(Opcodes.ASM4, fv); + } + + /** + * Constructs a new {@link CheckFieldAdapter}. + * + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param fv + * the field visitor to which this adapter must delegate calls. + */ + protected CheckFieldAdapter(final int api, final FieldVisitor fv) { + super(api, fv); + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + checkEnd(); + CheckMethodAdapter.checkDesc(desc, false); + return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); + } + + @Override + public void visitAttribute(final Attribute attr) { + checkEnd(); + if (attr == null) { + throw new IllegalArgumentException( + "Invalid attribute (must not be null)"); + } + super.visitAttribute(attr); + } + + @Override + public void visitEnd() { + checkEnd(); + end = true; + super.visitEnd(); + } + + private void checkEnd() { + if (end) { + throw new IllegalStateException( + "Cannot call a visit method after visitEnd has been called"); + } + } +}
