http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckMethodAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckMethodAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckMethodAdapter.java new file mode 100644 index 0000000..a7eea05 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckMethodAdapter.java @@ -0,0 +1,1397 @@ +/*** + * 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.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tajo.org.objectweb.asm.tree.MethodNode; +import org.apache.tajo.org.objectweb.asm.tree.analysis.Analyzer; +import org.apache.tajo.org.objectweb.asm.tree.analysis.BasicValue; +import org.apache.tajo.org.objectweb.asm.tree.analysis.BasicVerifier; +import org.apache.tajo.org.objectweb.asm.AnnotationVisitor; +import org.apache.tajo.org.objectweb.asm.Attribute; +import org.apache.tajo.org.objectweb.asm.Handle; +import org.apache.tajo.org.objectweb.asm.Label; +import org.apache.tajo.org.objectweb.asm.MethodVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; +import org.apache.tajo.org.objectweb.asm.Type; + +/** + * A {@link org.apache.tajo.org.objectweb.asm.MethodVisitor} that checks that its methods are properly used. More + * precisely this method adapter checks each instruction individually, i.e., + * each visit method checks some preconditions based <i>only</i> on its + * arguments - such as the fact that the given opcode is correct for a given + * visit method. This adapter can also perform some basic data flow checks (more + * precisely those that can be performed without the full class hierarchy - see + * {@link org.apache.tajo.org.objectweb.asm.tree.analysis.BasicVerifier}). For instance in a + * method whose signature is <tt>void m ()</tt>, the invalid instruction + * IRETURN, or the invalid sequence IADD L2I will be detected if the data flow + * checks are enabled. These checks are enabled by using the + * {@link #CheckMethodAdapter(int,String,String, org.apache.tajo.org.objectweb.asm.MethodVisitor,Map)} constructor. + * They are not performed if any other constructor is used. + * + * @author Eric Bruneton + */ +public class CheckMethodAdapter extends MethodVisitor { + + /** + * The class version number. + */ + public int version; + + /** + * The access flags of the method. + */ + private int access; + + /** + * <tt>true</tt> if the visitCode method has been called. + */ + private boolean startCode; + + /** + * <tt>true</tt> if the visitMaxs method has been called. + */ + private boolean endCode; + + /** + * <tt>true</tt> if the visitEnd method has been called. + */ + private boolean endMethod; + + /** + * Number of visited instructions. + */ + private int insnCount; + + /** + * The already visited labels. This map associate Integer values to pseudo + * code offsets. + */ + private final Map<Label, Integer> labels; + + /** + * The labels used in this method. Every used label must be visited with + * visitLabel before the end of the method (i.e. should be in #labels). + */ + private Set<Label> usedLabels; + + /** + * Number of visited frames in expanded form. + */ + private int expandedFrames; + + /** + * Number of visited frames in compressed form. + */ + private int compressedFrames; + + /** + * Number of instructions before the last visited frame. + */ + private int lastFrame = -1; + + /** + * The exception handler ranges. Each pair of list element contains the + * start and end labels of an exception handler block. + */ + private List<Label> handlers; + + /** + * Code of the visit method to be used for each opcode. + */ + private static final int[] TYPE; + + /** + * The Label.status field. + */ + private static Field labelStatusField; + + static { + String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD" + + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD" + + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA"; + TYPE = new int[s.length()]; + for (int i = 0; i < TYPE.length; ++i) { + TYPE[i] = s.charAt(i) - 'A' - 1; + } + } + + // code to generate the above string + // public static void main (String[] args) { + // int[] TYPE = new int[] { + // 0, //NOP + // 0, //ACONST_NULL + // 0, //ICONST_M1 + // 0, //ICONST_0 + // 0, //ICONST_1 + // 0, //ICONST_2 + // 0, //ICONST_3 + // 0, //ICONST_4 + // 0, //ICONST_5 + // 0, //LCONST_0 + // 0, //LCONST_1 + // 0, //FCONST_0 + // 0, //FCONST_1 + // 0, //FCONST_2 + // 0, //DCONST_0 + // 0, //DCONST_1 + // 1, //BIPUSH + // 1, //SIPUSH + // 7, //LDC + // -1, //LDC_W + // -1, //LDC2_W + // 2, //ILOAD + // 2, //LLOAD + // 2, //FLOAD + // 2, //DLOAD + // 2, //ALOAD + // -1, //ILOAD_0 + // -1, //ILOAD_1 + // -1, //ILOAD_2 + // -1, //ILOAD_3 + // -1, //LLOAD_0 + // -1, //LLOAD_1 + // -1, //LLOAD_2 + // -1, //LLOAD_3 + // -1, //FLOAD_0 + // -1, //FLOAD_1 + // -1, //FLOAD_2 + // -1, //FLOAD_3 + // -1, //DLOAD_0 + // -1, //DLOAD_1 + // -1, //DLOAD_2 + // -1, //DLOAD_3 + // -1, //ALOAD_0 + // -1, //ALOAD_1 + // -1, //ALOAD_2 + // -1, //ALOAD_3 + // 0, //IALOAD + // 0, //LALOAD + // 0, //FALOAD + // 0, //DALOAD + // 0, //AALOAD + // 0, //BALOAD + // 0, //CALOAD + // 0, //SALOAD + // 2, //ISTORE + // 2, //LSTORE + // 2, //FSTORE + // 2, //DSTORE + // 2, //ASTORE + // -1, //ISTORE_0 + // -1, //ISTORE_1 + // -1, //ISTORE_2 + // -1, //ISTORE_3 + // -1, //LSTORE_0 + // -1, //LSTORE_1 + // -1, //LSTORE_2 + // -1, //LSTORE_3 + // -1, //FSTORE_0 + // -1, //FSTORE_1 + // -1, //FSTORE_2 + // -1, //FSTORE_3 + // -1, //DSTORE_0 + // -1, //DSTORE_1 + // -1, //DSTORE_2 + // -1, //DSTORE_3 + // -1, //ASTORE_0 + // -1, //ASTORE_1 + // -1, //ASTORE_2 + // -1, //ASTORE_3 + // 0, //IASTORE + // 0, //LASTORE + // 0, //FASTORE + // 0, //DASTORE + // 0, //AASTORE + // 0, //BASTORE + // 0, //CASTORE + // 0, //SASTORE + // 0, //POP + // 0, //POP2 + // 0, //DUP + // 0, //DUP_X1 + // 0, //DUP_X2 + // 0, //DUP2 + // 0, //DUP2_X1 + // 0, //DUP2_X2 + // 0, //SWAP + // 0, //IADD + // 0, //LADD + // 0, //FADD + // 0, //DADD + // 0, //ISUB + // 0, //LSUB + // 0, //FSUB + // 0, //DSUB + // 0, //IMUL + // 0, //LMUL + // 0, //FMUL + // 0, //DMUL + // 0, //IDIV + // 0, //LDIV + // 0, //FDIV + // 0, //DDIV + // 0, //IREM + // 0, //LREM + // 0, //FREM + // 0, //DREM + // 0, //INEG + // 0, //LNEG + // 0, //FNEG + // 0, //DNEG + // 0, //ISHL + // 0, //LSHL + // 0, //ISHR + // 0, //LSHR + // 0, //IUSHR + // 0, //LUSHR + // 0, //IAND + // 0, //LAND + // 0, //IOR + // 0, //LOR + // 0, //IXOR + // 0, //LXOR + // 8, //IINC + // 0, //I2L + // 0, //I2F + // 0, //I2D + // 0, //L2I + // 0, //L2F + // 0, //L2D + // 0, //F2I + // 0, //F2L + // 0, //F2D + // 0, //D2I + // 0, //D2L + // 0, //D2F + // 0, //I2B + // 0, //I2C + // 0, //I2S + // 0, //LCMP + // 0, //FCMPL + // 0, //FCMPG + // 0, //DCMPL + // 0, //DCMPG + // 6, //IFEQ + // 6, //IFNE + // 6, //IFLT + // 6, //IFGE + // 6, //IFGT + // 6, //IFLE + // 6, //IF_ICMPEQ + // 6, //IF_ICMPNE + // 6, //IF_ICMPLT + // 6, //IF_ICMPGE + // 6, //IF_ICMPGT + // 6, //IF_ICMPLE + // 6, //IF_ACMPEQ + // 6, //IF_ACMPNE + // 6, //GOTO + // 6, //JSR + // 2, //RET + // 9, //TABLESWITCH + // 10, //LOOKUPSWITCH + // 0, //IRETURN + // 0, //LRETURN + // 0, //FRETURN + // 0, //DRETURN + // 0, //ARETURN + // 0, //RETURN + // 4, //GETSTATIC + // 4, //PUTSTATIC + // 4, //GETFIELD + // 4, //PUTFIELD + // 5, //INVOKEVIRTUAL + // 5, //INVOKESPECIAL + // 5, //INVOKESTATIC + // 5, //INVOKEINTERFACE + // -1, //INVOKEDYNAMIC + // 3, //NEW + // 1, //NEWARRAY + // 3, //ANEWARRAY + // 0, //ARRAYLENGTH + // 0, //ATHROW + // 3, //CHECKCAST + // 3, //INSTANCEOF + // 0, //MONITORENTER + // 0, //MONITOREXIT + // -1, //WIDE + // 11, //MULTIANEWARRAY + // 6, //IFNULL + // 6, //IFNONNULL + // -1, //GOTO_W + // -1 //JSR_W + // }; + // for (int i = 0; i < TYPE.length; ++i) { + // System.out.print((char)(TYPE[i] + 1 + 'A')); + // } + // System.out.println(); + // } + + /** + * Constructs a new {@link CheckMethodAdapter} object. This method adapter + * will not perform any data flow check (see + * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). + * <i>Subclasses must not use this constructor</i>. Instead, they must use + * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version. + * + * @param mv + * the method visitor to which this adapter must delegate calls. + */ + public CheckMethodAdapter(final MethodVisitor mv) { + this(mv, new HashMap<Label, Integer>()); + } + + /** + * Constructs a new {@link CheckMethodAdapter} object. This method adapter + * will not perform any data flow check (see + * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). + * <i>Subclasses must not use this constructor</i>. Instead, they must use + * the {@link #CheckMethodAdapter(int, MethodVisitor, Map)} version. + * + * @param mv + * the method visitor to which this adapter must delegate calls. + * @param labels + * a map of already visited labels (in other methods). + */ + public CheckMethodAdapter(final MethodVisitor mv, + final Map<Label, Integer> labels) { + this(Opcodes.ASM4, mv, labels); + } + + /** + * Constructs a new {@link CheckMethodAdapter} object. This method adapter + * will not perform any data flow check (see + * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). + * + * @param mv + * the method visitor to which this adapter must delegate calls. + * @param labels + * a map of already visited labels (in other methods). + */ + protected CheckMethodAdapter(final int api, final MethodVisitor mv, + final Map<Label, Integer> labels) { + super(api, mv); + this.labels = labels; + this.usedLabels = new HashSet<Label>(); + this.handlers = new ArrayList<Label>(); + } + + /** + * Constructs a new {@link CheckMethodAdapter} object. This method adapter + * will perform basic data flow checks. For instance in a method whose + * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the + * invalid sequence IADD L2I will be detected. + * + * @param access + * the method's access flags. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link org.apache.tajo.org.objectweb.asm.Type Type}). + * @param cmv + * the method visitor to which this adapter must delegate calls. + * @param labels + * a map of already visited labels (in other methods). + */ + public CheckMethodAdapter(final int access, final String name, + final String desc, final MethodVisitor cmv, + final Map<Label, Integer> labels) { + this(new MethodNode(access, name, desc, null, null) { + @Override + public void visitEnd() { + Analyzer<BasicValue> a = new Analyzer<BasicValue>( + new BasicVerifier()); + try { + a.analyze("dummy", this); + } catch (Exception e) { + if (e instanceof IndexOutOfBoundsException + && maxLocals == 0 && maxStack == 0) { + throw new RuntimeException( + "Data flow checking option requires valid, non zero maxLocals and maxStack values."); + } + e.printStackTrace(); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw, true); + CheckClassAdapter.printAnalyzerResult(this, a, pw); + pw.close(); + throw new RuntimeException(e.getMessage() + ' ' + + sw.toString()); + } + accept(cmv); + } + }, labels); + this.access = access; + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + checkEndMethod(); + checkDesc(desc, false); + return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible)); + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + checkEndMethod(); + return new CheckAnnotationAdapter(super.visitAnnotationDefault(), false); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { + checkEndMethod(); + checkDesc(desc, false); + return new CheckAnnotationAdapter(super.visitParameterAnnotation( + parameter, desc, visible)); + } + + @Override + public void visitAttribute(final Attribute attr) { + checkEndMethod(); + if (attr == null) { + throw new IllegalArgumentException( + "Invalid attribute (must not be null)"); + } + super.visitAttribute(attr); + } + + @Override + public void visitCode() { + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + throw new RuntimeException("Abstract methods cannot have code"); + } + startCode = true; + super.visitCode(); + } + + @Override + public void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack) { + if (insnCount == lastFrame) { + throw new IllegalStateException( + "At most one frame can be visited at a given code location."); + } + lastFrame = insnCount; + int mLocal; + int mStack; + switch (type) { + case Opcodes.F_NEW: + case Opcodes.F_FULL: + mLocal = Integer.MAX_VALUE; + mStack = Integer.MAX_VALUE; + break; + + case Opcodes.F_SAME: + mLocal = 0; + mStack = 0; + break; + + case Opcodes.F_SAME1: + mLocal = 0; + mStack = 1; + break; + + case Opcodes.F_APPEND: + case Opcodes.F_CHOP: + mLocal = 3; + mStack = 0; + break; + + default: + throw new IllegalArgumentException("Invalid frame type " + type); + } + + if (nLocal > mLocal) { + throw new IllegalArgumentException("Invalid nLocal=" + nLocal + + " for frame type " + type); + } + if (nStack > mStack) { + throw new IllegalArgumentException("Invalid nStack=" + nStack + + " for frame type " + type); + } + + if (type != Opcodes.F_CHOP) { + if (nLocal > 0 && (local == null || local.length < nLocal)) { + throw new IllegalArgumentException( + "Array local[] is shorter than nLocal"); + } + for (int i = 0; i < nLocal; ++i) { + checkFrameValue(local[i]); + } + } + if (nStack > 0 && (stack == null || stack.length < nStack)) { + throw new IllegalArgumentException( + "Array stack[] is shorter than nStack"); + } + for (int i = 0; i < nStack; ++i) { + checkFrameValue(stack[i]); + } + if (type == Opcodes.F_NEW) { + ++expandedFrames; + } else { + ++compressedFrames; + } + if (expandedFrames > 0 && compressedFrames > 0) { + throw new RuntimeException( + "Expanded and compressed frames must not be mixed."); + } + super.visitFrame(type, nLocal, local, nStack, stack); + } + + @Override + public void visitInsn(final int opcode) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 0); + super.visitInsn(opcode); + ++insnCount; + } + + @Override + public void visitIntInsn(final int opcode, final int operand) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 1); + switch (opcode) { + case Opcodes.BIPUSH: + checkSignedByte(operand, "Invalid operand"); + break; + case Opcodes.SIPUSH: + checkSignedShort(operand, "Invalid operand"); + break; + // case Constants.NEWARRAY: + default: + if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) { + throw new IllegalArgumentException( + "Invalid operand (must be an array type code T_...): " + + operand); + } + } + super.visitIntInsn(opcode, operand); + ++insnCount; + } + + @Override + public void visitVarInsn(final int opcode, final int var) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 2); + checkUnsignedShort(var, "Invalid variable index"); + super.visitVarInsn(opcode, var); + ++insnCount; + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 3); + checkInternalName(type, "type"); + if (opcode == Opcodes.NEW && type.charAt(0) == '[') { + throw new IllegalArgumentException( + "NEW cannot be used to create arrays: " + type); + } + super.visitTypeInsn(opcode, type); + ++insnCount; + } + + @Override + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 4); + checkInternalName(owner, "owner"); + checkUnqualifiedName(version, name, "name"); + checkDesc(desc, false); + super.visitFieldInsn(opcode, owner, name, desc); + ++insnCount; + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 5); + if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) { + checkMethodIdentifier(version, name, "name"); + } + checkInternalName(owner, "owner"); + checkMethodDesc(desc); + super.visitMethodInsn(opcode, owner, name, desc); + ++insnCount; + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { + checkStartCode(); + checkEndCode(); + checkMethodIdentifier(version, name, "name"); + checkMethodDesc(desc); + if (bsm.getTag() != Opcodes.H_INVOKESTATIC + && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) { + throw new IllegalArgumentException("invalid handle tag " + + bsm.getTag()); + } + for (int i = 0; i < bsmArgs.length; i++) { + checkLDCConstant(bsmArgs[i]); + } + super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); + ++insnCount; + } + + @Override + public void visitJumpInsn(final int opcode, final Label label) { + checkStartCode(); + checkEndCode(); + checkOpcode(opcode, 6); + checkLabel(label, false, "label"); + checkNonDebugLabel(label); + super.visitJumpInsn(opcode, label); + usedLabels.add(label); + ++insnCount; + } + + @Override + public void visitLabel(final Label label) { + checkStartCode(); + checkEndCode(); + checkLabel(label, false, "label"); + if (labels.get(label) != null) { + throw new IllegalArgumentException("Already visited label"); + } + labels.put(label, new Integer(insnCount)); + super.visitLabel(label); + } + + @Override + public void visitLdcInsn(final Object cst) { + checkStartCode(); + checkEndCode(); + checkLDCConstant(cst); + super.visitLdcInsn(cst); + ++insnCount; + } + + @Override + public void visitIincInsn(final int var, final int increment) { + checkStartCode(); + checkEndCode(); + checkUnsignedShort(var, "Invalid variable index"); + checkSignedShort(increment, "Invalid increment"); + super.visitIincInsn(var, increment); + ++insnCount; + } + + @Override + public void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels) { + checkStartCode(); + checkEndCode(); + if (max < min) { + throw new IllegalArgumentException("Max = " + max + + " must be greater than or equal to min = " + min); + } + checkLabel(dflt, false, "default label"); + checkNonDebugLabel(dflt); + if (labels == null || labels.length != max - min + 1) { + throw new IllegalArgumentException( + "There must be max - min + 1 labels"); + } + for (int i = 0; i < labels.length; ++i) { + checkLabel(labels[i], false, "label at index " + i); + checkNonDebugLabel(labels[i]); + } + super.visitTableSwitchInsn(min, max, dflt, labels); + for (int i = 0; i < labels.length; ++i) { + usedLabels.add(labels[i]); + } + ++insnCount; + } + + @Override + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, + final Label[] labels) { + checkEndCode(); + checkStartCode(); + checkLabel(dflt, false, "default label"); + checkNonDebugLabel(dflt); + if (keys == null || labels == null || keys.length != labels.length) { + throw new IllegalArgumentException( + "There must be the same number of keys and labels"); + } + for (int i = 0; i < labels.length; ++i) { + checkLabel(labels[i], false, "label at index " + i); + checkNonDebugLabel(labels[i]); + } + super.visitLookupSwitchInsn(dflt, keys, labels); + usedLabels.add(dflt); + for (int i = 0; i < labels.length; ++i) { + usedLabels.add(labels[i]); + } + ++insnCount; + } + + @Override + public void visitMultiANewArrayInsn(final String desc, final int dims) { + checkStartCode(); + checkEndCode(); + checkDesc(desc, false); + if (desc.charAt(0) != '[') { + throw new IllegalArgumentException( + "Invalid descriptor (must be an array type descriptor): " + + desc); + } + if (dims < 1) { + throw new IllegalArgumentException( + "Invalid dimensions (must be greater than 0): " + dims); + } + if (dims > desc.lastIndexOf('[') + 1) { + throw new IllegalArgumentException( + "Invalid dimensions (must not be greater than dims(desc)): " + + dims); + } + super.visitMultiANewArrayInsn(desc, dims); + ++insnCount; + } + + @Override + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { + checkStartCode(); + checkEndCode(); + checkLabel(start, false, "start label"); + checkLabel(end, false, "end label"); + checkLabel(handler, false, "handler label"); + checkNonDebugLabel(start); + checkNonDebugLabel(end); + checkNonDebugLabel(handler); + if (labels.get(start) != null || labels.get(end) != null + || labels.get(handler) != null) { + throw new IllegalStateException( + "Try catch blocks must be visited before their labels"); + } + if (type != null) { + checkInternalName(type, "type"); + } + super.visitTryCatchBlock(start, end, handler, type); + handlers.add(start); + handlers.add(end); + } + + @Override + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { + checkStartCode(); + checkEndCode(); + checkUnqualifiedName(version, name, "name"); + checkDesc(desc, false); + checkLabel(start, true, "start label"); + checkLabel(end, true, "end label"); + checkUnsignedShort(index, "Invalid variable index"); + int s = labels.get(start).intValue(); + int e = labels.get(end).intValue(); + if (e < s) { + throw new IllegalArgumentException( + "Invalid start and end labels (end must be greater than start)"); + } + super.visitLocalVariable(name, desc, signature, start, end, index); + } + + @Override + public void visitLineNumber(final int line, final Label start) { + checkStartCode(); + checkEndCode(); + checkUnsignedShort(line, "Invalid line number"); + checkLabel(start, true, "start label"); + super.visitLineNumber(line, start); + } + + @Override + public void visitMaxs(final int maxStack, final int maxLocals) { + checkStartCode(); + checkEndCode(); + endCode = true; + for (Label l : usedLabels) { + if (labels.get(l) == null) { + throw new IllegalStateException("Undefined label used"); + } + } + for (int i = 0; i < handlers.size();) { + Integer start = labels.get(handlers.get(i++)); + Integer end = labels.get(handlers.get(i++)); + if (start == null || end == null) { + throw new IllegalStateException( + "Undefined try catch block labels"); + } + if (end.intValue() <= start.intValue()) { + throw new IllegalStateException( + "Emty try catch block handler range"); + } + } + checkUnsignedShort(maxStack, "Invalid max stack"); + checkUnsignedShort(maxLocals, "Invalid max locals"); + super.visitMaxs(maxStack, maxLocals); + } + + @Override + public void visitEnd() { + checkEndMethod(); + endMethod = true; + super.visitEnd(); + } + + // ------------------------------------------------------------------------- + + /** + * Checks that the visitCode method has been called. + */ + void checkStartCode() { + if (!startCode) { + throw new IllegalStateException( + "Cannot visit instructions before visitCode has been called."); + } + } + + /** + * Checks that the visitMaxs method has not been called. + */ + void checkEndCode() { + if (endCode) { + throw new IllegalStateException( + "Cannot visit instructions after visitMaxs has been called."); + } + } + + /** + * Checks that the visitEnd method has not been called. + */ + void checkEndMethod() { + if (endMethod) { + throw new IllegalStateException( + "Cannot visit elements after visitEnd has been called."); + } + } + + /** + * Checks a stack frame value. + * + * @param value + * the value to be checked. + */ + void checkFrameValue(final Object value) { + if (value == Opcodes.TOP || value == Opcodes.INTEGER + || value == Opcodes.FLOAT || value == Opcodes.LONG + || value == Opcodes.DOUBLE || value == Opcodes.NULL + || value == Opcodes.UNINITIALIZED_THIS) { + return; + } + if (value instanceof String) { + checkInternalName((String) value, "Invalid stack frame value"); + return; + } + if (!(value instanceof Label)) { + throw new IllegalArgumentException("Invalid stack frame value: " + + value); + } else { + usedLabels.add((Label) value); + } + } + + /** + * Checks that the type of the given opcode is equal to the given type. + * + * @param opcode + * the opcode to be checked. + * @param type + * the expected opcode type. + */ + static void checkOpcode(final int opcode, final int type) { + if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) { + throw new IllegalArgumentException("Invalid opcode: " + opcode); + } + } + + /** + * Checks that the given value is a signed byte. + * + * @param value + * the value to be checked. + * @param msg + * an message to be used in case of error. + */ + static void checkSignedByte(final int value, final String msg) { + if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { + throw new IllegalArgumentException(msg + + " (must be a signed byte): " + value); + } + } + + /** + * Checks that the given value is a signed short. + * + * @param value + * the value to be checked. + * @param msg + * an message to be used in case of error. + */ + static void checkSignedShort(final int value, final String msg) { + if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { + throw new IllegalArgumentException(msg + + " (must be a signed short): " + value); + } + } + + /** + * Checks that the given value is an unsigned short. + * + * @param value + * the value to be checked. + * @param msg + * an message to be used in case of error. + */ + static void checkUnsignedShort(final int value, final String msg) { + if (value < 0 || value > 65535) { + throw new IllegalArgumentException(msg + + " (must be an unsigned short): " + value); + } + } + + /** + * Checks that the given value is an {@link Integer}, a{@link Float}, a + * {@link Long}, a {@link Double} or a {@link String}. + * + * @param cst + * the value to be checked. + */ + static void checkConstant(final Object cst) { + if (!(cst instanceof Integer) && !(cst instanceof Float) + && !(cst instanceof Long) && !(cst instanceof Double) + && !(cst instanceof String)) { + throw new IllegalArgumentException("Invalid constant: " + cst); + } + } + + void checkLDCConstant(final Object cst) { + if (cst instanceof Type) { + int s = ((Type) cst).getSort(); + if (s != Type.OBJECT && s != Type.ARRAY && s != Type.METHOD) { + throw new IllegalArgumentException("Illegal LDC constant value"); + } + if (s != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) { + throw new IllegalArgumentException( + "ldc of a constant class requires at least version 1.5"); + } + if (s == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) { + throw new IllegalArgumentException( + "ldc of a method type requires at least version 1.7"); + } + } else if (cst instanceof Handle) { + if ((version & 0xFFFF) < Opcodes.V1_7) { + throw new IllegalArgumentException( + "ldc of a handle requires at least version 1.7"); + } + int tag = ((Handle) cst).getTag(); + if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) { + throw new IllegalArgumentException("invalid handle tag " + tag); + } + } else { + checkConstant(cst); + } + } + + /** + * Checks that the given string is a valid unqualified name. + * + * @param version + * the class version. + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. + */ + static void checkUnqualifiedName(int version, final String name, + final String msg) { + if ((version & 0xFFFF) < Opcodes.V1_5) { + checkIdentifier(name, msg); + } else { + for (int i = 0; i < name.length(); ++i) { + if (".;[/".indexOf(name.charAt(i)) != -1) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be a valid unqualified name): " + name); + } + } + } + } + + /** + * Checks that the given string is a valid Java identifier. + * + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. + */ + static void checkIdentifier(final String name, final String msg) { + checkIdentifier(name, 0, -1, msg); + } + + /** + * Checks that the given substring is a valid Java identifier. + * + * @param name + * the string to be checked. + * @param start + * index of the first character of the identifier (inclusive). + * @param end + * index of the last character of the identifier (exclusive). -1 + * is equivalent to <tt>name.length()</tt> if name is not + * <tt>null</tt>. + * @param msg + * a message to be used in case of error. + */ + static void checkIdentifier(final String name, final int start, + final int end, final String msg) { + if (name == null || (end == -1 ? name.length() <= start : end <= start)) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + if (!Character.isJavaIdentifierStart(name.charAt(start))) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be a valid Java identifier): " + name); + } + int max = end == -1 ? name.length() : end; + for (int i = start + 1; i < max; ++i) { + if (!Character.isJavaIdentifierPart(name.charAt(i))) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be a valid Java identifier): " + name); + } + } + } + + /** + * Checks that the given string is a valid Java identifier. + * + * @param version + * the class version. + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. + */ + static void checkMethodIdentifier(int version, final String name, + final String msg) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + if ((version & 0xFFFF) >= Opcodes.V1_5) { + for (int i = 0; i < name.length(); ++i) { + if (".;[/<>".indexOf(name.charAt(i)) != -1) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be a valid unqualified name): " + name); + } + } + return; + } + if (!Character.isJavaIdentifierStart(name.charAt(0))) { + throw new IllegalArgumentException( + "Invalid " + + msg + + " (must be a '<init>', '<clinit>' or a valid Java identifier): " + + name); + } + for (int i = 1; i < name.length(); ++i) { + if (!Character.isJavaIdentifierPart(name.charAt(i))) { + throw new IllegalArgumentException( + "Invalid " + + msg + + " (must be '<init>' or '<clinit>' or a valid Java identifier): " + + name); + } + } + } + + /** + * Checks that the given string is a valid internal class name. + * + * @param name + * the string to be checked. + * @param msg + * a message to be used in case of error. + */ + static void checkInternalName(final String name, final String msg) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null or empty)"); + } + if (name.charAt(0) == '[') { + checkDesc(name, false); + } else { + checkInternalName(name, 0, -1, msg); + } + } + + /** + * Checks that the given substring is a valid internal class name. + * + * @param name + * the string to be checked. + * @param start + * index of the first character of the identifier (inclusive). + * @param end + * index of the last character of the identifier (exclusive). -1 + * is equivalent to <tt>name.length()</tt> if name is not + * <tt>null</tt>. + * @param msg + * a message to be used in case of error. + */ + static void checkInternalName(final String name, final int start, + final int end, final String msg) { + int max = end == -1 ? name.length() : end; + try { + int begin = start; + int slash; + do { + slash = name.indexOf('/', begin + 1); + if (slash == -1 || slash > max) { + slash = max; + } + checkIdentifier(name, begin, slash, null); + begin = slash + 1; + } while (slash != max); + } catch (IllegalArgumentException _) { + throw new IllegalArgumentException( + "Invalid " + + msg + + " (must be a fully qualified class name in internal form): " + + name); + } + } + + /** + * Checks that the given string is a valid type descriptor. + * + * @param desc + * the string to be checked. + * @param canBeVoid + * <tt>true</tt> if <tt>V</tt> can be considered valid. + */ + static void checkDesc(final String desc, final boolean canBeVoid) { + int end = checkDesc(desc, 0, canBeVoid); + if (end != desc.length()) { + throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + } + + /** + * Checks that a the given substring is a valid type descriptor. + * + * @param desc + * the string to be checked. + * @param start + * index of the first character of the identifier (inclusive). + * @param canBeVoid + * <tt>true</tt> if <tt>V</tt> can be considered valid. + * @return the index of the last character of the type decriptor, plus one. + */ + static int checkDesc(final String desc, final int start, + final boolean canBeVoid) { + if (desc == null || start >= desc.length()) { + throw new IllegalArgumentException( + "Invalid type descriptor (must not be null or empty)"); + } + int index; + switch (desc.charAt(start)) { + case 'V': + if (canBeVoid) { + return start + 1; + } else { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + case 'F': + case 'J': + case 'D': + return start + 1; + case '[': + index = start + 1; + while (index < desc.length() && desc.charAt(index) == '[') { + ++index; + } + if (index < desc.length()) { + return checkDesc(desc, index, false); + } else { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + case 'L': + index = desc.indexOf(';', start); + if (index == -1 || index - start < 2) { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + try { + checkInternalName(desc, start + 1, index, null); + } catch (IllegalArgumentException _) { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + return index + 1; + default: + throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + } + + /** + * Checks that the given string is a valid method descriptor. + * + * @param desc + * the string to be checked. + */ + static void checkMethodDesc(final String desc) { + if (desc == null || desc.length() == 0) { + throw new IllegalArgumentException( + "Invalid method descriptor (must not be null or empty)"); + } + if (desc.charAt(0) != '(' || desc.length() < 3) { + throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + int start = 1; + if (desc.charAt(start) != ')') { + do { + if (desc.charAt(start) == 'V') { + throw new IllegalArgumentException("Invalid descriptor: " + + desc); + } + start = checkDesc(desc, start, false); + } while (start < desc.length() && desc.charAt(start) != ')'); + } + start = checkDesc(desc, start + 1, true); + if (start != desc.length()) { + throw new IllegalArgumentException("Invalid descriptor: " + desc); + } + } + + /** + * Checks that the given label is not null. This method can also check that + * the label has been visited. + * + * @param label + * the label to be checked. + * @param checkVisited + * <tt>true</tt> to check that the label has been visited. + * @param msg + * a message to be used in case of error. + */ + void checkLabel(final Label label, final boolean checkVisited, + final String msg) { + if (label == null) { + throw new IllegalArgumentException("Invalid " + msg + + " (must not be null)"); + } + if (checkVisited && labels.get(label) == null) { + throw new IllegalArgumentException("Invalid " + msg + + " (must be visited first)"); + } + } + + /** + * Checks that the given label is not a label used only for debug purposes. + * + * @param label + * the label to be checked. + */ + private static void checkNonDebugLabel(final Label label) { + Field f = getLabelStatusField(); + int status = 0; + try { + status = f == null ? 0 : ((Integer) f.get(label)).intValue(); + } catch (IllegalAccessException e) { + throw new Error("Internal error"); + } + if ((status & 0x01) != 0) { + throw new IllegalArgumentException( + "Labels used for debug info cannot be reused for control flow"); + } + } + + /** + * Returns the Field object corresponding to the Label.status field. + * + * @return the Field object corresponding to the Label.status field. + */ + private static Field getLabelStatusField() { + if (labelStatusField == null) { + labelStatusField = getLabelField("a"); + if (labelStatusField == null) { + labelStatusField = getLabelField("status"); + } + } + return labelStatusField; + } + + /** + * Returns the field of the Label class whose name is given. + * + * @param name + * a field name. + * @return the field of the Label class whose name is given, or null. + */ + private static Field getLabelField(final String name) { + try { + Field f = Label.class.getDeclaredField(name); + f.setAccessible(true); + return f; + } catch (NoSuchFieldException e) { + return 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/CheckSignatureAdapter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckSignatureAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckSignatureAdapter.java new file mode 100644 index 0000000..96f3e08 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/CheckSignatureAdapter.java @@ -0,0 +1,330 @@ +/*** + * 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.signature.SignatureVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; + +/** + * A {@link org.apache.tajo.org.objectweb.asm.signature.SignatureVisitor} that checks that its methods are properly used. + * + * @author Eric Bruneton + */ +public class CheckSignatureAdapter extends SignatureVisitor { + + /** + * Type to be used to check class signatures. See + * {@link #CheckSignatureAdapter(int, SignatureVisitor) + * CheckSignatureAdapter}. + */ + public static final int CLASS_SIGNATURE = 0; + + /** + * Type to be used to check method signatures. See + * {@link #CheckSignatureAdapter(int, SignatureVisitor) + * CheckSignatureAdapter}. + */ + public static final int METHOD_SIGNATURE = 1; + + /** + * Type to be used to check type signatures.See + * {@link #CheckSignatureAdapter(int, SignatureVisitor) + * CheckSignatureAdapter}. + */ + public static final int TYPE_SIGNATURE = 2; + + private static final int EMPTY = 1; + + private static final int FORMAL = 2; + + private static final int BOUND = 4; + + private static final int SUPER = 8; + + private static final int PARAM = 16; + + private static final int RETURN = 32; + + private static final int SIMPLE_TYPE = 64; + + private static final int CLASS_TYPE = 128; + + private static final int END = 256; + + /** + * Type of the signature to be checked. + */ + private final int type; + + /** + * State of the automaton used to check the order of method calls. + */ + private int state; + + /** + * <tt>true</tt> if the checked type signature can be 'V'. + */ + private boolean canBeVoid; + + /** + * The visitor to which this adapter must delegate calls. May be + * <tt>null</tt>. + */ + private final SignatureVisitor sv; + + /** + * Creates a new {@link CheckSignatureAdapter} object. <i>Subclasses must + * not use this constructor</i>. Instead, they must use the + * {@link #CheckSignatureAdapter(int, int, SignatureVisitor)} version. + * + * @param type + * the type of signature to be checked. See + * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and + * {@link #TYPE_SIGNATURE}. + * @param sv + * the visitor to which this adapter must delegate calls. May be + * <tt>null</tt>. + */ + public CheckSignatureAdapter(final int type, final SignatureVisitor sv) { + this(Opcodes.ASM4, type, sv); + } + + /** + * Creates a new {@link CheckSignatureAdapter} object. + * + * @param api + * the ASM API version implemented by this visitor. Must be one + * of {@link Opcodes#ASM4}. + * @param type + * the type of signature to be checked. See + * {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and + * {@link #TYPE_SIGNATURE}. + * @param sv + * the visitor to which this adapter must delegate calls. May be + * <tt>null</tt>. + */ + protected CheckSignatureAdapter(final int api, final int type, + final SignatureVisitor sv) { + super(api); + this.type = type; + this.state = EMPTY; + this.sv = sv; + } + + // class and method signatures + + @Override + public void visitFormalTypeParameter(final String name) { + if (type == TYPE_SIGNATURE + || (state != EMPTY && state != FORMAL && state != BOUND)) { + throw new IllegalStateException(); + } + CheckMethodAdapter.checkIdentifier(name, "formal type parameter"); + state = FORMAL; + if (sv != null) { + sv.visitFormalTypeParameter(name); + } + } + + @Override + public SignatureVisitor visitClassBound() { + if (state != FORMAL) { + throw new IllegalStateException(); + } + state = BOUND; + SignatureVisitor v = sv == null ? null : sv.visitClassBound(); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + @Override + public SignatureVisitor visitInterfaceBound() { + if (state != FORMAL && state != BOUND) { + throw new IllegalArgumentException(); + } + SignatureVisitor v = sv == null ? null : sv.visitInterfaceBound(); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + // class signatures + + @Override + public SignatureVisitor visitSuperclass() { + if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) { + throw new IllegalArgumentException(); + } + state = SUPER; + SignatureVisitor v = sv == null ? null : sv.visitSuperclass(); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + @Override + public SignatureVisitor visitInterface() { + if (state != SUPER) { + throw new IllegalStateException(); + } + SignatureVisitor v = sv == null ? null : sv.visitInterface(); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + // method signatures + + @Override + public SignatureVisitor visitParameterType() { + if (type != METHOD_SIGNATURE + || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) { + throw new IllegalArgumentException(); + } + state = PARAM; + SignatureVisitor v = sv == null ? null : sv.visitParameterType(); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + @Override + public SignatureVisitor visitReturnType() { + if (type != METHOD_SIGNATURE + || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) { + throw new IllegalArgumentException(); + } + state = RETURN; + SignatureVisitor v = sv == null ? null : sv.visitReturnType(); + CheckSignatureAdapter cv = new CheckSignatureAdapter(TYPE_SIGNATURE, v); + cv.canBeVoid = true; + return cv; + } + + @Override + public SignatureVisitor visitExceptionType() { + if (state != RETURN) { + throw new IllegalStateException(); + } + SignatureVisitor v = sv == null ? null : sv.visitExceptionType(); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + // type signatures + + @Override + public void visitBaseType(final char descriptor) { + if (type != TYPE_SIGNATURE || state != EMPTY) { + throw new IllegalStateException(); + } + if (descriptor == 'V') { + if (!canBeVoid) { + throw new IllegalArgumentException(); + } + } else { + if ("ZCBSIFJD".indexOf(descriptor) == -1) { + throw new IllegalArgumentException(); + } + } + state = SIMPLE_TYPE; + if (sv != null) { + sv.visitBaseType(descriptor); + } + } + + @Override + public void visitTypeVariable(final String name) { + if (type != TYPE_SIGNATURE || state != EMPTY) { + throw new IllegalStateException(); + } + CheckMethodAdapter.checkIdentifier(name, "type variable"); + state = SIMPLE_TYPE; + if (sv != null) { + sv.visitTypeVariable(name); + } + } + + @Override + public SignatureVisitor visitArrayType() { + if (type != TYPE_SIGNATURE || state != EMPTY) { + throw new IllegalStateException(); + } + state = SIMPLE_TYPE; + SignatureVisitor v = sv == null ? null : sv.visitArrayType(); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + @Override + public void visitClassType(final String name) { + if (type != TYPE_SIGNATURE || state != EMPTY) { + throw new IllegalStateException(); + } + CheckMethodAdapter.checkInternalName(name, "class name"); + state = CLASS_TYPE; + if (sv != null) { + sv.visitClassType(name); + } + } + + @Override + public void visitInnerClassType(final String name) { + if (state != CLASS_TYPE) { + throw new IllegalStateException(); + } + CheckMethodAdapter.checkIdentifier(name, "inner class name"); + if (sv != null) { + sv.visitInnerClassType(name); + } + } + + @Override + public void visitTypeArgument() { + if (state != CLASS_TYPE) { + throw new IllegalStateException(); + } + if (sv != null) { + sv.visitTypeArgument(); + } + } + + @Override + public SignatureVisitor visitTypeArgument(final char wildcard) { + if (state != CLASS_TYPE) { + throw new IllegalStateException(); + } + if ("+-=".indexOf(wildcard) == -1) { + throw new IllegalArgumentException(); + } + SignatureVisitor v = sv == null ? null : sv.visitTypeArgument(wildcard); + return new CheckSignatureAdapter(TYPE_SIGNATURE, v); + } + + @Override + public void visitEnd() { + if (state != CLASS_TYPE) { + throw new IllegalStateException(); + } + state = END; + if (sv != null) { + sv.visitEnd(); + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Printer.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Printer.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Printer.java new file mode 100644 index 0000000..20e142d --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Printer.java @@ -0,0 +1,500 @@ +/*** + * 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.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tajo.org.objectweb.asm.Label; +import org.apache.tajo.org.objectweb.asm.Attribute; +import org.apache.tajo.org.objectweb.asm.Handle; +import org.apache.tajo.org.objectweb.asm.Opcodes; + +/** + * An abstract converter from visit events to text. + * + * @author Eric Bruneton + */ +public abstract class Printer { + + /** + * The names of the Java Virtual Machine opcodes. + */ + public static final String[] OPCODES; + + /** + * The names of the for <code>operand</code> parameter values of the + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitIntInsn} method when + * <code>opcode</code> is <code>NEWARRAY</code>. + */ + public static final String[] TYPES; + + /** + * The names of the <code>tag</code> field values for + * {@link org.apache.tajo.org.objectweb.asm.Handle}. + */ + public static final String[] HANDLE_TAG; + + static { + String s = "NOP,ACONST_NULL,ICONST_M1,ICONST_0,ICONST_1,ICONST_2," + + "ICONST_3,ICONST_4,ICONST_5,LCONST_0,LCONST_1,FCONST_0," + + "FCONST_1,FCONST_2,DCONST_0,DCONST_1,BIPUSH,SIPUSH,LDC,,," + + "ILOAD,LLOAD,FLOAD,DLOAD,ALOAD,,,,,,,,,,,,,,,,,,,,,IALOAD," + + "LALOAD,FALOAD,DALOAD,AALOAD,BALOAD,CALOAD,SALOAD,ISTORE," + + "LSTORE,FSTORE,DSTORE,ASTORE,,,,,,,,,,,,,,,,,,,,,IASTORE," + + "LASTORE,FASTORE,DASTORE,AASTORE,BASTORE,CASTORE,SASTORE,POP," + + "POP2,DUP,DUP_X1,DUP_X2,DUP2,DUP2_X1,DUP2_X2,SWAP,IADD,LADD," + + "FADD,DADD,ISUB,LSUB,FSUB,DSUB,IMUL,LMUL,FMUL,DMUL,IDIV,LDIV," + + "FDIV,DDIV,IREM,LREM,FREM,DREM,INEG,LNEG,FNEG,DNEG,ISHL,LSHL," + + "ISHR,LSHR,IUSHR,LUSHR,IAND,LAND,IOR,LOR,IXOR,LXOR,IINC,I2L," + + "I2F,I2D,L2I,L2F,L2D,F2I,F2L,F2D,D2I,D2L,D2F,I2B,I2C,I2S,LCMP," + + "FCMPL,FCMPG,DCMPL,DCMPG,IFEQ,IFNE,IFLT,IFGE,IFGT,IFLE," + + "IF_ICMPEQ,IF_ICMPNE,IF_ICMPLT,IF_ICMPGE,IF_ICMPGT,IF_ICMPLE," + + "IF_ACMPEQ,IF_ACMPNE,GOTO,JSR,RET,TABLESWITCH,LOOKUPSWITCH," + + "IRETURN,LRETURN,FRETURN,DRETURN,ARETURN,RETURN,GETSTATIC," + + "PUTSTATIC,GETFIELD,PUTFIELD,INVOKEVIRTUAL,INVOKESPECIAL," + + "INVOKESTATIC,INVOKEINTERFACE,INVOKEDYNAMIC,NEW,NEWARRAY," + + "ANEWARRAY,ARRAYLENGTH,ATHROW,CHECKCAST,INSTANCEOF," + + "MONITORENTER,MONITOREXIT,,MULTIANEWARRAY,IFNULL,IFNONNULL,"; + OPCODES = new String[200]; + int i = 0; + int j = 0; + int l; + while ((l = s.indexOf(',', j)) > 0) { + OPCODES[i++] = j + 1 == l ? null : s.substring(j, l); + j = l + 1; + } + + s = "T_BOOLEAN,T_CHAR,T_FLOAT,T_DOUBLE,T_BYTE,T_SHORT,T_INT,T_LONG,"; + TYPES = new String[12]; + j = 0; + i = 4; + while ((l = s.indexOf(',', j)) > 0) { + TYPES[i++] = s.substring(j, l); + j = l + 1; + } + + s = "H_GETFIELD,H_GETSTATIC,H_PUTFIELD,H_PUTSTATIC," + + "H_INVOKEVIRTUAL,H_INVOKESTATIC,H_INVOKESPECIAL," + + "H_NEWINVOKESPECIAL,H_INVOKEINTERFACE,"; + HANDLE_TAG = new String[10]; + j = 0; + i = 1; + while ((l = s.indexOf(',', j)) > 0) { + HANDLE_TAG[i++] = s.substring(j, l); + j = l + 1; + } + } + + /** + * The ASM API version implemented by this class. The value of this field + * must be one of {@link Opcodes#ASM4}. + */ + protected final int api; + + /** + * A buffer that can be used to create strings. + */ + protected final StringBuffer buf; + + /** + * The text to be printed. Since the code of methods is not necessarily + * visited in sequential order, one method after the other, but can be + * interlaced (some instructions from method one, then some instructions + * from method two, then some instructions from method one again...), it is + * not possible to print the visited instructions directly to a sequential + * stream. A class is therefore printed in a two steps process: a string + * tree is constructed during the visit, and printed to a sequential stream + * at the end of the visit. This string tree is stored in this field, as a + * string list that can contain other string lists, which can themselves + * contain other string lists, and so on. + */ + public final List<Object> text; + + /** + * Constructs a new {@link Printer}. + */ + protected Printer(final int api) { + this.api = api; + this.buf = new StringBuffer(); + this.text = new ArrayList<Object>(); + } + + /** + * Class header. See {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visit}. + */ + public abstract void visit(final int version, final int access, + final String name, final String signature, final String superName, + final String[] interfaces); + + /** + * Class source. See {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitSource}. + */ + public abstract void visitSource(final String file, final String debug); + + /** + * Class outer class. See + * {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitOuterClass}. + */ + public abstract void visitOuterClass(final String owner, final String name, + final String desc); + + /** + * Class annotation. See + * {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitAnnotation}. + */ + public abstract Printer visitClassAnnotation(final String desc, + final boolean visible); + + /** + * Class attribute. See + * {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitAttribute}. + */ + public abstract void visitClassAttribute(final Attribute attr); + + /** + * Class inner name. See + * {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitInnerClass}. + */ + public abstract void visitInnerClass(final String name, + final String outerName, final String innerName, final int access); + + /** + * Class field. See {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitField}. + */ + public abstract Printer visitField(final int access, final String name, + final String desc, final String signature, final Object value); + + /** + * Class method. See {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitMethod}. + */ + public abstract Printer visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions); + + /** + * Class end. See {@link org.apache.tajo.org.objectweb.asm.ClassVisitor#visitEnd}. + */ + public abstract void visitClassEnd(); + + // ------------------------------------------------------------------------ + // Annotations + // ------------------------------------------------------------------------ + + /** + * Annotation value. See {@link org.apache.tajo.org.objectweb.asm.AnnotationVisitor#visit}. + */ + public abstract void visit(final String name, final Object value); + + /** + * Annotation enum value. See + * {@link org.apache.tajo.org.objectweb.asm.AnnotationVisitor#visitEnum}. + */ + public abstract void visitEnum(final String name, final String desc, + final String value); + + /** + * Nested annotation value. See + * {@link org.apache.tajo.org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + */ + public abstract Printer visitAnnotation(final String name, final String desc); + + /** + * Annotation array value. See + * {@link org.apache.tajo.org.objectweb.asm.AnnotationVisitor#visitArray}. + */ + public abstract Printer visitArray(final String name); + + /** + * Annotation end. See {@link org.apache.tajo.org.objectweb.asm.AnnotationVisitor#visitEnd}. + */ + public abstract void visitAnnotationEnd(); + + // ------------------------------------------------------------------------ + // Fields + // ------------------------------------------------------------------------ + + /** + * Field annotation. See + * {@link org.apache.tajo.org.objectweb.asm.FieldVisitor#visitAnnotation}. + */ + public abstract Printer visitFieldAnnotation(final String desc, + final boolean visible); + + /** + * Field attribute. See + * {@link org.apache.tajo.org.objectweb.asm.FieldVisitor#visitAttribute}. + */ + public abstract void visitFieldAttribute(final Attribute attr); + + /** + * Field end. See {@link org.apache.tajo.org.objectweb.asm.FieldVisitor#visitEnd}. + */ + public abstract void visitFieldEnd(); + + // ------------------------------------------------------------------------ + // Methods + // ------------------------------------------------------------------------ + + /** + * Method default annotation. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + */ + public abstract Printer visitAnnotationDefault(); + + /** + * Method annotation. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitAnnotation}. + */ + public abstract Printer visitMethodAnnotation(final String desc, + final boolean visible); + + /** + * Method parameter annotation. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + */ + public abstract Printer visitParameterAnnotation(final int parameter, + final String desc, final boolean visible); + + /** + * Method attribute. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitAttribute}. + */ + public abstract void visitMethodAttribute(final Attribute attr); + + /** + * Method start. See {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitCode}. + */ + public abstract void visitCode(); + + /** + * Method stack frame. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitFrame}. + */ + public abstract void visitFrame(final int type, final int nLocal, + final Object[] local, final int nStack, final Object[] stack); + + /** + * Method instruction. See {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitInsn} + * . + */ + public abstract void visitInsn(final int opcode); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitIntInsn}. + */ + public abstract void visitIntInsn(final int opcode, final int operand); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitVarInsn}. + */ + public abstract void visitVarInsn(final int opcode, final int var); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitTypeInsn}. + */ + public abstract void visitTypeInsn(final int opcode, final String type); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitFieldInsn}. + */ + public abstract void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + */ + public abstract void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + */ + public abstract void visitInvokeDynamicInsn(String name, String desc, + Handle bsm, Object... bsmArgs); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitJumpInsn}. + */ + public abstract void visitJumpInsn(final int opcode, final Label label); + + /** + * Method label. See {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitLabel}. + */ + public abstract void visitLabel(final Label label); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitLdcInsn}. + */ + public abstract void visitLdcInsn(final Object cst); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitIincInsn}. + */ + public abstract void visitIincInsn(final int var, final int increment); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + */ + public abstract void visitTableSwitchInsn(final int min, final int max, + final Label dflt, final Label... labels); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + */ + public abstract void visitLookupSwitchInsn(final Label dflt, + final int[] keys, final Label[] labels); + + /** + * Method instruction. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + */ + public abstract void visitMultiANewArrayInsn(final String desc, + final int dims); + + /** + * Method exception handler. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + */ + public abstract void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type); + + /** + * Method debug info. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitLocalVariable}. + */ + public abstract void visitLocalVariable(final String name, + final String desc, final String signature, final Label start, + final Label end, final int index); + + /** + * Method debug info. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitLineNumber}. + */ + public abstract void visitLineNumber(final int line, final Label start); + + /** + * Method max stack and max locals. See + * {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitMaxs}. + */ + public abstract void visitMaxs(final int maxStack, final int maxLocals); + + /** + * Method end. See {@link org.apache.tajo.org.objectweb.asm.MethodVisitor#visitEnd}. + */ + public abstract void visitMethodEnd(); + + /** + * Returns the text constructed by this visitor. + * + * @return the text constructed by this visitor. + */ + public List<Object> getText() { + return text; + } + + /** + * Prints the text constructed by this visitor. + * + * @param pw + * the print writer to be used. + */ + public void print(final PrintWriter pw) { + printList(pw, text); + } + + /** + * Appends a quoted string to a given buffer. + * + * @param buf + * the buffer where the string must be added. + * @param s + * the string to be added. + */ + public static void appendString(final StringBuffer buf, final String s) { + buf.append('\"'); + for (int i = 0; i < s.length(); ++i) { + char c = s.charAt(i); + if (c == '\n') { + buf.append("\\n"); + } else if (c == '\r') { + buf.append("\\r"); + } else if (c == '\\') { + buf.append("\\\\"); + } else if (c == '"') { + buf.append("\\\""); + } else if (c < 0x20 || c > 0x7f) { + buf.append("\\u"); + if (c < 0x10) { + buf.append("000"); + } else if (c < 0x100) { + buf.append("00"); + } else if (c < 0x1000) { + buf.append('0'); + } + buf.append(Integer.toString(c, 16)); + } else { + buf.append(c); + } + } + buf.append('\"'); + } + + /** + * Prints the given string tree. + * + * @param pw + * the writer to be used to print the tree. + * @param l + * a string tree, i.e., a string list that can contain other + * string lists, and so on recursively. + */ + static void printList(final PrintWriter pw, final List<?> l) { + for (int i = 0; i < l.size(); ++i) { + Object o = l.get(i); + if (o instanceof List) { + printList(pw, (List<?>) o); + } else { + pw.print(o.toString()); + } + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Textifiable.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Textifiable.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Textifiable.java new file mode 100644 index 0000000..a72feed --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/util/Textifiable.java @@ -0,0 +1,56 @@ +/** + * 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.util.Map; + +import org.apache.tajo.org.objectweb.asm.Label; + +/** + * An {@link org.apache.tajo.org.objectweb.asm.Attribute Attribute} that can print a readable + * representation of itself. + * + * Implementations should construct readable output from an attribute data + * structure. Such representation could be used in unit test assertions. + * + * @author Eugene Kuleshov + */ +public interface Textifiable { + + /** + * Build a human readable representation of this attribute. + * + * @param buf + * a buffer used for printing Java code. + * @param labelNames + * map of label instances to their names. + */ + void textify(StringBuffer buf, Map<Label, String> labelNames); +}
