http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TableSwitchInsnNode.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TableSwitchInsnNode.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TableSwitchInsnNode.java new file mode 100644 index 0000000..a597c29 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TableSwitchInsnNode.java @@ -0,0 +1,113 @@ +/*** + * 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.tree; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.apache.tajo.org.objectweb.asm.Label; +import org.apache.tajo.org.objectweb.asm.MethodVisitor; +import org.apache.tajo.org.objectweb.asm.Opcodes; + +/** + * A node that represents a TABLESWITCH instruction. + * + * @author Eric Bruneton + */ +public class TableSwitchInsnNode extends AbstractInsnNode { + + /** + * The minimum key value. + */ + public int min; + + /** + * The maximum key value. + */ + public int max; + + /** + * Beginning of the default handler block. + */ + public LabelNode dflt; + + /** + * Beginnings of the handler blocks. This list is a list of + * {@link LabelNode} objects. + */ + public List<LabelNode> labels; + + /** + * Constructs a new {@link TableSwitchInsnNode}. + * + * @param min + * the minimum key value. + * @param max + * the maximum key value. + * @param dflt + * beginning of the default handler block. + * @param labels + * beginnings of the handler blocks. <tt>labels[i]</tt> is the + * beginning of the handler block for the <tt>min + i</tt> key. + */ + public TableSwitchInsnNode(final int min, final int max, + final LabelNode dflt, final LabelNode... labels) { + super(Opcodes.TABLESWITCH); + this.min = min; + this.max = max; + this.dflt = dflt; + this.labels = new ArrayList<LabelNode>(); + if (labels != null) { + this.labels.addAll(Arrays.asList(labels)); + } + } + + @Override + public int getType() { + return TABLESWITCH_INSN; + } + + @Override + public void accept(final MethodVisitor mv) { + Label[] labels = new Label[this.labels.size()]; + for (int i = 0; i < labels.length; ++i) { + labels[i] = this.labels.get(i).getLabel(); + } + mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels); + } + + @Override + public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { + return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone( + this.labels, labels)); + } +}
http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TryCatchBlockNode.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TryCatchBlockNode.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TryCatchBlockNode.java new file mode 100644 index 0000000..f04c3dc --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TryCatchBlockNode.java @@ -0,0 +1,94 @@ +/*** + * 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.tree; + +import org.apache.tajo.org.objectweb.asm.MethodVisitor; + +/** + * A node that represents a try catch block. + * + * @author Eric Bruneton + */ +public class TryCatchBlockNode { + + /** + * Beginning of the exception handler's scope (inclusive). + */ + public LabelNode start; + + /** + * End of the exception handler's scope (exclusive). + */ + public LabelNode end; + + /** + * Beginning of the exception handler's code. + */ + public LabelNode handler; + + /** + * Internal name of the type of exceptions handled by the handler. May be + * <tt>null</tt> to catch any exceptions (for "finally" blocks). + */ + public String type; + + /** + * Constructs a new {@link TryCatchBlockNode}. + * + * @param start + * beginning of the exception handler's scope (inclusive). + * @param end + * end of the exception handler's scope (exclusive). + * @param handler + * beginning of the exception handler's code. + * @param type + * internal name of the type of exceptions handled by the + * handler, or <tt>null</tt> to catch any exceptions (for + * "finally" blocks). + */ + public TryCatchBlockNode(final LabelNode start, final LabelNode end, + final LabelNode handler, final String type) { + this.start = start; + this.end = end; + this.handler = handler; + this.type = type; + } + + /** + * Makes the given visitor visit this try catch block. + * + * @param mv + * a method visitor. + */ + public void accept(final MethodVisitor mv) { + mv.visitTryCatchBlock(start.getLabel(), end.getLabel(), + handler == null ? null : handler.getLabel(), type); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TypeInsnNode.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TypeInsnNode.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TypeInsnNode.java new file mode 100644 index 0000000..e6df331 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/TypeInsnNode.java @@ -0,0 +1,90 @@ +/*** + * 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.tree; + +import java.util.Map; + +import org.apache.tajo.org.objectweb.asm.MethodVisitor; + +/** + * A node that represents a type instruction. A type instruction is an + * instruction that takes a type descriptor as parameter. + * + * @author Eric Bruneton + */ +public class TypeInsnNode extends AbstractInsnNode { + + /** + * The operand of this instruction. This operand is an internal name (see + * {@link org.apache.tajo.org.objectweb.asm.Type}). + */ + public String desc; + + /** + * Constructs a new {@link TypeInsnNode}. + * + * @param opcode + * the opcode of the type instruction to be constructed. This + * opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param desc + * the operand of the instruction to be constructed. This operand + * is an internal name (see {@link org.apache.tajo.org.objectweb.asm.Type}). + */ + public TypeInsnNode(final int opcode, final String desc) { + super(opcode); + this.desc = desc; + } + + /** + * Sets the opcode of this instruction. + * + * @param opcode + * the new instruction opcode. This opcode must be NEW, + * ANEWARRAY, CHECKCAST or INSTANCEOF. + */ + public void setOpcode(final int opcode) { + this.opcode = opcode; + } + + @Override + public int getType() { + return TYPE_INSN; + } + + @Override + public void accept(final MethodVisitor mv) { + mv.visitTypeInsn(opcode, desc); + } + + @Override + public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { + return new TypeInsnNode(opcode, desc); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/VarInsnNode.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/VarInsnNode.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/VarInsnNode.java new file mode 100644 index 0000000..afd0d14 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/VarInsnNode.java @@ -0,0 +1,93 @@ +/*** + * 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.tree; + +import java.util.Map; + +import org.apache.tajo.org.objectweb.asm.MethodVisitor; + +/** + * A node that represents a local variable instruction. A local variable + * instruction is an instruction that loads or stores the value of a local + * variable. + * + * @author Eric Bruneton + */ +public class VarInsnNode extends AbstractInsnNode { + + /** + * The operand of this instruction. This operand is the index of a local + * variable. + */ + public int var; + + /** + * Constructs a new {@link VarInsnNode}. + * + * @param opcode + * the opcode of the local variable instruction to be + * constructed. This opcode must be ILOAD, LLOAD, FLOAD, DLOAD, + * ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var + * the operand of the instruction to be constructed. This operand + * is the index of a local variable. + */ + public VarInsnNode(final int opcode, final int var) { + super(opcode); + this.var = var; + } + + /** + * Sets the opcode of this instruction. + * + * @param opcode + * the new instruction opcode. This opcode must be ILOAD, LLOAD, + * FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or + * RET. + */ + public void setOpcode(final int opcode) { + this.opcode = opcode; + } + + @Override + public int getType() { + return VAR_INSN; + } + + @Override + public void accept(final MethodVisitor mv) { + mv.visitVarInsn(opcode, var); + } + + @Override + public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { + return new VarInsnNode(opcode, var); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/Analyzer.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/Analyzer.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/Analyzer.java new file mode 100644 index 0000000..1095dd0 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/Analyzer.java @@ -0,0 +1,549 @@ +/*** + * 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.tree.analysis; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.tajo.org.objectweb.asm.Type; +import org.apache.tajo.org.objectweb.asm.Opcodes; +import org.apache.tajo.org.objectweb.asm.tree.AbstractInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.IincInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.InsnList; +import org.apache.tajo.org.objectweb.asm.tree.JumpInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.LabelNode; +import org.apache.tajo.org.objectweb.asm.tree.LookupSwitchInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.MethodNode; +import org.apache.tajo.org.objectweb.asm.tree.TableSwitchInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.TryCatchBlockNode; +import org.apache.tajo.org.objectweb.asm.tree.VarInsnNode; + +/** + * A semantic bytecode analyzer. <i>This class does not fully check that JSR and + * RET instructions are valid.</i> + * + * @param <V> + * type of the Value used for the analysis. + * + * @author Eric Bruneton + */ +public class Analyzer<V extends Value> implements Opcodes { + + private final Interpreter<V> interpreter; + + private int n; + + private InsnList insns; + + private List<TryCatchBlockNode>[] handlers; + + private Frame<V>[] frames; + + private Subroutine[] subroutines; + + private boolean[] queued; + + private int[] queue; + + private int top; + + /** + * Constructs a new {@link Analyzer}. + * + * @param interpreter + * the interpreter to be used to symbolically interpret the + * bytecode instructions. + */ + public Analyzer(final Interpreter<V> interpreter) { + this.interpreter = interpreter; + } + + /** + * Analyzes the given method. + * + * @param owner + * the internal name of the class to which the method belongs. + * @param m + * the method to be analyzed. + * @return the symbolic state of the execution stack frame at each bytecode + * instruction of the method. The size of the returned array is + * equal to the number of instructions (and labels) of the method. A + * given frame is <tt>null</tt> if and only if the corresponding + * instruction cannot be reached (dead code). + * @throws AnalyzerException + * if a problem occurs during the analysis. + */ + public Frame<V>[] analyze(final String owner, final MethodNode m) + throws AnalyzerException { + if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) { + frames = (Frame<V>[]) new Frame<?>[0]; + return frames; + } + n = m.instructions.size(); + insns = m.instructions; + handlers = (List<TryCatchBlockNode>[]) new List<?>[n]; + frames = (Frame<V>[]) new Frame<?>[n]; + subroutines = new Subroutine[n]; + queued = new boolean[n]; + queue = new int[n]; + top = 0; + + // computes exception handlers for each instruction + for (int i = 0; i < m.tryCatchBlocks.size(); ++i) { + TryCatchBlockNode tcb = m.tryCatchBlocks.get(i); + int begin = insns.indexOf(tcb.start); + int end = insns.indexOf(tcb.end); + for (int j = begin; j < end; ++j) { + List<TryCatchBlockNode> insnHandlers = handlers[j]; + if (insnHandlers == null) { + insnHandlers = new ArrayList<TryCatchBlockNode>(); + handlers[j] = insnHandlers; + } + insnHandlers.add(tcb); + } + } + + // computes the subroutine for each instruction: + Subroutine main = new Subroutine(null, m.maxLocals, null); + List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>(); + Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>(); + findSubroutine(0, main, subroutineCalls); + while (!subroutineCalls.isEmpty()) { + JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0); + Subroutine sub = subroutineHeads.get(jsr.label); + if (sub == null) { + sub = new Subroutine(jsr.label, m.maxLocals, jsr); + subroutineHeads.put(jsr.label, sub); + findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls); + } else { + sub.callers.add(jsr); + } + } + for (int i = 0; i < n; ++i) { + if (subroutines[i] != null && subroutines[i].start == null) { + subroutines[i] = null; + } + } + + // initializes the data structures for the control flow analysis + Frame<V> current = newFrame(m.maxLocals, m.maxStack); + Frame<V> handler = newFrame(m.maxLocals, m.maxStack); + current.setReturn(interpreter.newValue(Type.getReturnType(m.desc))); + Type[] args = Type.getArgumentTypes(m.desc); + int local = 0; + if ((m.access & ACC_STATIC) == 0) { + Type ctype = Type.getObjectType(owner); + current.setLocal(local++, interpreter.newValue(ctype)); + } + for (int i = 0; i < args.length; ++i) { + current.setLocal(local++, interpreter.newValue(args[i])); + if (args[i].getSize() == 2) { + current.setLocal(local++, interpreter.newValue(null)); + } + } + while (local < m.maxLocals) { + current.setLocal(local++, interpreter.newValue(null)); + } + merge(0, current, null); + + init(owner, m); + + // control flow analysis + while (top > 0) { + int insn = queue[--top]; + Frame<V> f = frames[insn]; + Subroutine subroutine = subroutines[insn]; + queued[insn] = false; + + AbstractInsnNode insnNode = null; + try { + insnNode = m.instructions.get(insn); + int insnOpcode = insnNode.getOpcode(); + int insnType = insnNode.getType(); + + if (insnType == AbstractInsnNode.LABEL + || insnType == AbstractInsnNode.LINE + || insnType == AbstractInsnNode.FRAME) { + merge(insn + 1, f, subroutine); + newControlFlowEdge(insn, insn + 1); + } else { + current.init(f).execute(insnNode, interpreter); + subroutine = subroutine == null ? null : subroutine.copy(); + + if (insnNode instanceof JumpInsnNode) { + JumpInsnNode j = (JumpInsnNode) insnNode; + if (insnOpcode != GOTO && insnOpcode != JSR) { + merge(insn + 1, current, subroutine); + newControlFlowEdge(insn, insn + 1); + } + int jump = insns.indexOf(j.label); + if (insnOpcode == JSR) { + merge(jump, current, new Subroutine(j.label, + m.maxLocals, j)); + } else { + merge(jump, current, subroutine); + } + newControlFlowEdge(insn, jump); + } else if (insnNode instanceof LookupSwitchInsnNode) { + LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; + int jump = insns.indexOf(lsi.dflt); + merge(jump, current, subroutine); + newControlFlowEdge(insn, jump); + for (int j = 0; j < lsi.labels.size(); ++j) { + LabelNode label = lsi.labels.get(j); + jump = insns.indexOf(label); + merge(jump, current, subroutine); + newControlFlowEdge(insn, jump); + } + } else if (insnNode instanceof TableSwitchInsnNode) { + TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; + int jump = insns.indexOf(tsi.dflt); + merge(jump, current, subroutine); + newControlFlowEdge(insn, jump); + for (int j = 0; j < tsi.labels.size(); ++j) { + LabelNode label = tsi.labels.get(j); + jump = insns.indexOf(label); + merge(jump, current, subroutine); + newControlFlowEdge(insn, jump); + } + } else if (insnOpcode == RET) { + if (subroutine == null) { + throw new AnalyzerException(insnNode, + "RET instruction outside of a sub routine"); + } + for (int i = 0; i < subroutine.callers.size(); ++i) { + JumpInsnNode caller = subroutine.callers.get(i); + int call = insns.indexOf(caller); + if (frames[call] != null) { + merge(call + 1, frames[call], current, + subroutines[call], subroutine.access); + newControlFlowEdge(insn, call + 1); + } + } + } else if (insnOpcode != ATHROW + && (insnOpcode < IRETURN || insnOpcode > RETURN)) { + if (subroutine != null) { + if (insnNode instanceof VarInsnNode) { + int var = ((VarInsnNode) insnNode).var; + subroutine.access[var] = true; + if (insnOpcode == LLOAD || insnOpcode == DLOAD + || insnOpcode == LSTORE + || insnOpcode == DSTORE) { + subroutine.access[var + 1] = true; + } + } else if (insnNode instanceof IincInsnNode) { + int var = ((IincInsnNode) insnNode).var; + subroutine.access[var] = true; + } + } + merge(insn + 1, current, subroutine); + newControlFlowEdge(insn, insn + 1); + } + } + + List<TryCatchBlockNode> insnHandlers = handlers[insn]; + if (insnHandlers != null) { + for (int i = 0; i < insnHandlers.size(); ++i) { + TryCatchBlockNode tcb = insnHandlers.get(i); + Type type; + if (tcb.type == null) { + type = Type.getObjectType("java/lang/Throwable"); + } else { + type = Type.getObjectType(tcb.type); + } + int jump = insns.indexOf(tcb.handler); + if (newControlFlowExceptionEdge(insn, tcb)) { + handler.init(f); + handler.clearStack(); + handler.push(interpreter.newValue(type)); + merge(jump, handler, subroutine); + } + } + } + } catch (AnalyzerException e) { + throw new AnalyzerException(e.node, "Error at instruction " + + insn + ": " + e.getMessage(), e); + } catch (Exception e) { + throw new AnalyzerException(insnNode, "Error at instruction " + + insn + ": " + e.getMessage(), e); + } + } + + return frames; + } + + private void findSubroutine(int insn, final Subroutine sub, + final List<AbstractInsnNode> calls) throws AnalyzerException { + while (true) { + if (insn < 0 || insn >= n) { + throw new AnalyzerException(null, + "Execution can fall off end of the code"); + } + if (subroutines[insn] != null) { + return; + } + subroutines[insn] = sub.copy(); + AbstractInsnNode node = insns.get(insn); + + // calls findSubroutine recursively on normal successors + if (node instanceof JumpInsnNode) { + if (node.getOpcode() == JSR) { + // do not follow a JSR, it leads to another subroutine! + calls.add(node); + } else { + JumpInsnNode jnode = (JumpInsnNode) node; + findSubroutine(insns.indexOf(jnode.label), sub, calls); + } + } else if (node instanceof TableSwitchInsnNode) { + TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node; + findSubroutine(insns.indexOf(tsnode.dflt), sub, calls); + for (int i = tsnode.labels.size() - 1; i >= 0; --i) { + LabelNode l = tsnode.labels.get(i); + findSubroutine(insns.indexOf(l), sub, calls); + } + } else if (node instanceof LookupSwitchInsnNode) { + LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node; + findSubroutine(insns.indexOf(lsnode.dflt), sub, calls); + for (int i = lsnode.labels.size() - 1; i >= 0; --i) { + LabelNode l = lsnode.labels.get(i); + findSubroutine(insns.indexOf(l), sub, calls); + } + } + + // calls findSubroutine recursively on exception handler successors + List<TryCatchBlockNode> insnHandlers = handlers[insn]; + if (insnHandlers != null) { + for (int i = 0; i < insnHandlers.size(); ++i) { + TryCatchBlockNode tcb = insnHandlers.get(i); + findSubroutine(insns.indexOf(tcb.handler), sub, calls); + } + } + + // if insn does not falls through to the next instruction, return. + switch (node.getOpcode()) { + case GOTO: + case RET: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case LRETURN: + case FRETURN: + case DRETURN: + case ARETURN: + case RETURN: + case ATHROW: + return; + } + insn++; + } + } + + /** + * Returns the symbolic stack frame for each instruction of the last + * recently analyzed method. + * + * @return the symbolic state of the execution stack frame at each bytecode + * instruction of the method. The size of the returned array is + * equal to the number of instructions (and labels) of the method. A + * given frame is <tt>null</tt> if the corresponding instruction + * cannot be reached, or if an error occured during the analysis of + * the method. + */ + public Frame<V>[] getFrames() { + return frames; + } + + /** + * Returns the exception handlers for the given instruction. + * + * @param insn + * the index of an instruction of the last recently analyzed + * method. + * @return a list of {@link TryCatchBlockNode} objects. + */ + public List<TryCatchBlockNode> getHandlers(final int insn) { + return handlers[insn]; + } + + /** + * Initializes this analyzer. This method is called just before the + * execution of control flow analysis loop in #analyze. The default + * implementation of this method does nothing. + * + * @param owner + * the internal name of the class to which the method belongs. + * @param m + * the method to be analyzed. + * @throws AnalyzerException + * if a problem occurs. + */ + protected void init(String owner, MethodNode m) throws AnalyzerException { + } + + /** + * Constructs a new frame with the given size. + * + * @param nLocals + * the maximum number of local variables of the frame. + * @param nStack + * the maximum stack size of the frame. + * @return the created frame. + */ + protected Frame<V> newFrame(final int nLocals, final int nStack) { + return new Frame<V>(nLocals, nStack); + } + + /** + * Constructs a new frame that is identical to the given frame. + * + * @param src + * a frame. + * @return the created frame. + */ + protected Frame<V> newFrame(final Frame<? extends V> src) { + return new Frame<V>(src); + } + + /** + * Creates a control flow graph edge. The default implementation of this + * method does nothing. It can be overriden in order to construct the + * control flow graph of a method (this method is called by the + * {@link #analyze analyze} method during its visit of the method's code). + * + * @param insn + * an instruction index. + * @param successor + * index of a successor instruction. + */ + protected void newControlFlowEdge(final int insn, final int successor) { + } + + /** + * Creates a control flow graph edge corresponding to an exception handler. + * The default implementation of this method does nothing. It can be + * overridden in order to construct the control flow graph of a method (this + * method is called by the {@link #analyze analyze} method during its visit + * of the method's code). + * + * @param insn + * an instruction index. + * @param successor + * index of a successor instruction. + * @return true if this edge must be considered in the data flow analysis + * performed by this analyzer, or false otherwise. The default + * implementation of this method always returns true. + */ + protected boolean newControlFlowExceptionEdge(final int insn, + final int successor) { + return true; + } + + /** + * Creates a control flow graph edge corresponding to an exception handler. + * The default implementation of this method delegates to + * {@link #newControlFlowExceptionEdge(int, int) + * newControlFlowExceptionEdge(int, int)}. It can be overridden in order to + * construct the control flow graph of a method (this method is called by + * the {@link #analyze analyze} method during its visit of the method's + * code). + * + * @param insn + * an instruction index. + * @param tcb + * TryCatchBlockNode corresponding to this edge. + * @return true if this edge must be considered in the data flow analysis + * performed by this analyzer, or false otherwise. The default + * implementation of this method delegates to + * {@link #newControlFlowExceptionEdge(int, int) + * newControlFlowExceptionEdge(int, int)}. + */ + protected boolean newControlFlowExceptionEdge(final int insn, + final TryCatchBlockNode tcb) { + return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler)); + } + + // ------------------------------------------------------------------------- + + private void merge(final int insn, final Frame<V> frame, + final Subroutine subroutine) throws AnalyzerException { + Frame<V> oldFrame = frames[insn]; + Subroutine oldSubroutine = subroutines[insn]; + boolean changes; + + if (oldFrame == null) { + frames[insn] = newFrame(frame); + changes = true; + } else { + changes = oldFrame.merge(frame, interpreter); + } + + if (oldSubroutine == null) { + if (subroutine != null) { + subroutines[insn] = subroutine.copy(); + changes = true; + } + } else { + if (subroutine != null) { + changes |= oldSubroutine.merge(subroutine); + } + } + if (changes && !queued[insn]) { + queued[insn] = true; + queue[top++] = insn; + } + } + + private void merge(final int insn, final Frame<V> beforeJSR, + final Frame<V> afterRET, final Subroutine subroutineBeforeJSR, + final boolean[] access) throws AnalyzerException { + Frame<V> oldFrame = frames[insn]; + Subroutine oldSubroutine = subroutines[insn]; + boolean changes; + + afterRET.merge(beforeJSR, access); + + if (oldFrame == null) { + frames[insn] = newFrame(afterRET); + changes = true; + } else { + changes = oldFrame.merge(afterRET, interpreter); + } + + if (oldSubroutine != null && subroutineBeforeJSR != null) { + changes |= oldSubroutine.merge(subroutineBeforeJSR); + } + if (changes && !queued[insn]) { + queued[insn] = true; + queue[top++] = insn; + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/AnalyzerException.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/AnalyzerException.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/AnalyzerException.java new file mode 100644 index 0000000..bf760e7 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/AnalyzerException.java @@ -0,0 +1,61 @@ +/*** + * 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.tree.analysis; + +import org.apache.tajo.org.objectweb.asm.tree.AbstractInsnNode; + +/** + * Thrown if a problem occurs during the analysis of a method. + * + * @author Bing Ran + * @author Eric Bruneton + */ +public class AnalyzerException extends Exception { + + public final AbstractInsnNode node; + + public AnalyzerException(final AbstractInsnNode node, final String msg) { + super(msg); + this.node = node; + } + + public AnalyzerException(final AbstractInsnNode node, final String msg, + final Throwable exception) { + super(msg, exception); + this.node = node; + } + + public AnalyzerException(final AbstractInsnNode node, final String msg, + final Object expected, final Value encountered) { + super((msg == null ? "Expected " : msg + ": expected ") + expected + + ", but found " + encountered); + this.node = node; + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicInterpreter.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicInterpreter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicInterpreter.java new file mode 100644 index 0000000..07c5900 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicInterpreter.java @@ -0,0 +1,358 @@ +/*** + * 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.tree.analysis; + +import java.util.List; + +import org.apache.tajo.org.objectweb.asm.Type; +import org.apache.tajo.org.objectweb.asm.tree.IntInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.LdcInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.MultiANewArrayInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.TypeInsnNode; +import org.apache.tajo.org.objectweb.asm.Handle; +import org.apache.tajo.org.objectweb.asm.Opcodes; +import org.apache.tajo.org.objectweb.asm.tree.AbstractInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.FieldInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.MethodInsnNode; + +/** + * An {@link Interpreter} for {@link BasicValue} values. + * + * @author Eric Bruneton + * @author Bing Ran + */ +public class BasicInterpreter extends Interpreter<BasicValue> implements + Opcodes { + + public BasicInterpreter() { + super(ASM4); + } + + protected BasicInterpreter(final int api) { + super(api); + } + + @Override + public BasicValue newValue(final Type type) { + if (type == null) { + return BasicValue.UNINITIALIZED_VALUE; + } + switch (type.getSort()) { + case Type.VOID: + return null; + case Type.BOOLEAN: + case Type.CHAR: + case Type.BYTE: + case Type.SHORT: + case Type.INT: + return BasicValue.INT_VALUE; + case Type.FLOAT: + return BasicValue.FLOAT_VALUE; + case Type.LONG: + return BasicValue.LONG_VALUE; + case Type.DOUBLE: + return BasicValue.DOUBLE_VALUE; + case Type.ARRAY: + case Type.OBJECT: + return BasicValue.REFERENCE_VALUE; + default: + throw new Error("Internal error"); + } + } + + @Override + public BasicValue newOperation(final AbstractInsnNode insn) + throws AnalyzerException { + switch (insn.getOpcode()) { + case ACONST_NULL: + return newValue(Type.getObjectType("null")); + case ICONST_M1: + case ICONST_0: + case ICONST_1: + case ICONST_2: + case ICONST_3: + case ICONST_4: + case ICONST_5: + return BasicValue.INT_VALUE; + case LCONST_0: + case LCONST_1: + return BasicValue.LONG_VALUE; + case FCONST_0: + case FCONST_1: + case FCONST_2: + return BasicValue.FLOAT_VALUE; + case DCONST_0: + case DCONST_1: + return BasicValue.DOUBLE_VALUE; + case BIPUSH: + case SIPUSH: + return BasicValue.INT_VALUE; + case LDC: + Object cst = ((LdcInsnNode) insn).cst; + if (cst instanceof Integer) { + return BasicValue.INT_VALUE; + } else if (cst instanceof Float) { + return BasicValue.FLOAT_VALUE; + } else if (cst instanceof Long) { + return BasicValue.LONG_VALUE; + } else if (cst instanceof Double) { + return BasicValue.DOUBLE_VALUE; + } else if (cst instanceof String) { + return newValue(Type.getObjectType("java/lang/String")); + } else if (cst instanceof Type) { + int sort = ((Type) cst).getSort(); + if (sort == Type.OBJECT || sort == Type.ARRAY) { + return newValue(Type.getObjectType("java/lang/Class")); + } else if (sort == Type.METHOD) { + return newValue(Type + .getObjectType("java/lang/invoke/MethodType")); + } else { + throw new IllegalArgumentException("Illegal LDC constant " + + cst); + } + } else if (cst instanceof Handle) { + return newValue(Type + .getObjectType("java/lang/invoke/MethodHandle")); + } else { + throw new IllegalArgumentException("Illegal LDC constant " + + cst); + } + case JSR: + return BasicValue.RETURNADDRESS_VALUE; + case GETSTATIC: + return newValue(Type.getType(((FieldInsnNode) insn).desc)); + case NEW: + return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); + default: + throw new Error("Internal error."); + } + } + + @Override + public BasicValue copyOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { + return value; + } + + @Override + public BasicValue unaryOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { + switch (insn.getOpcode()) { + case INEG: + case IINC: + case L2I: + case F2I: + case D2I: + case I2B: + case I2C: + case I2S: + return BasicValue.INT_VALUE; + case FNEG: + case I2F: + case L2F: + case D2F: + return BasicValue.FLOAT_VALUE; + case LNEG: + case I2L: + case F2L: + case D2L: + return BasicValue.LONG_VALUE; + case DNEG: + case I2D: + case L2D: + case F2D: + return BasicValue.DOUBLE_VALUE; + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case LRETURN: + case FRETURN: + case DRETURN: + case ARETURN: + case PUTSTATIC: + return null; + case GETFIELD: + return newValue(Type.getType(((FieldInsnNode) insn).desc)); + case NEWARRAY: + switch (((IntInsnNode) insn).operand) { + case T_BOOLEAN: + return newValue(Type.getType("[Z")); + case T_CHAR: + return newValue(Type.getType("[C")); + case T_BYTE: + return newValue(Type.getType("[B")); + case T_SHORT: + return newValue(Type.getType("[S")); + case T_INT: + return newValue(Type.getType("[I")); + case T_FLOAT: + return newValue(Type.getType("[F")); + case T_DOUBLE: + return newValue(Type.getType("[D")); + case T_LONG: + return newValue(Type.getType("[J")); + default: + throw new AnalyzerException(insn, "Invalid array type"); + } + case ANEWARRAY: + String desc = ((TypeInsnNode) insn).desc; + return newValue(Type.getType("[" + Type.getObjectType(desc))); + case ARRAYLENGTH: + return BasicValue.INT_VALUE; + case ATHROW: + return null; + case CHECKCAST: + desc = ((TypeInsnNode) insn).desc; + return newValue(Type.getObjectType(desc)); + case INSTANCEOF: + return BasicValue.INT_VALUE; + case MONITORENTER: + case MONITOREXIT: + case IFNULL: + case IFNONNULL: + return null; + default: + throw new Error("Internal error."); + } + } + + @Override + public BasicValue binaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2) + throws AnalyzerException { + switch (insn.getOpcode()) { + case IALOAD: + case BALOAD: + case CALOAD: + case SALOAD: + case IADD: + case ISUB: + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + return BasicValue.INT_VALUE; + case FALOAD: + case FADD: + case FSUB: + case FMUL: + case FDIV: + case FREM: + return BasicValue.FLOAT_VALUE; + case LALOAD: + case LADD: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LSHL: + case LSHR: + case LUSHR: + case LAND: + case LOR: + case LXOR: + return BasicValue.LONG_VALUE; + case DALOAD: + case DADD: + case DSUB: + case DMUL: + case DDIV: + case DREM: + return BasicValue.DOUBLE_VALUE; + case AALOAD: + return BasicValue.REFERENCE_VALUE; + case LCMP: + case FCMPL: + case FCMPG: + case DCMPL: + case DCMPG: + return BasicValue.INT_VALUE; + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + case PUTFIELD: + return null; + default: + throw new Error("Internal error."); + } + } + + @Override + public BasicValue ternaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2, + final BasicValue value3) throws AnalyzerException { + return null; + } + + @Override + public BasicValue naryOperation(final AbstractInsnNode insn, + final List<? extends BasicValue> values) throws AnalyzerException { + int opcode = insn.getOpcode(); + if (opcode == MULTIANEWARRAY) { + return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc)); + } else if (opcode == INVOKEDYNAMIC) { + return newValue(Type + .getReturnType(((InvokeDynamicInsnNode) insn).desc)); + } else { + return newValue(Type.getReturnType(((MethodInsnNode) insn).desc)); + } + } + + @Override + public void returnOperation(final AbstractInsnNode insn, + final BasicValue value, final BasicValue expected) + throws AnalyzerException { + } + + @Override + public BasicValue merge(final BasicValue v, final BasicValue w) { + if (!v.equals(w)) { + return BasicValue.UNINITIALIZED_VALUE; + } + return v; + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicValue.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicValue.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicValue.java new file mode 100644 index 0000000..5782563 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicValue.java @@ -0,0 +1,111 @@ +/*** + * 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.tree.analysis; + +import org.apache.tajo.org.objectweb.asm.Type; + +/** + * A {@link Value} that is represented by its type in a seven types type system. + * This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE, + * REFERENCE and RETURNADDRESS types. + * + * @author Eric Bruneton + */ +public class BasicValue implements Value { + + public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null); + + public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE); + + public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE); + + public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE); + + public static final BasicValue DOUBLE_VALUE = new BasicValue( + Type.DOUBLE_TYPE); + + public static final BasicValue REFERENCE_VALUE = new BasicValue( + Type.getObjectType("java/lang/Object")); + + public static final BasicValue RETURNADDRESS_VALUE = new BasicValue( + Type.VOID_TYPE); + + private final Type type; + + public BasicValue(final Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + public int getSize() { + return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1; + } + + public boolean isReference() { + return type != null + && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY); + } + + @Override + public boolean equals(final Object value) { + if (value == this) { + return true; + } else if (value instanceof BasicValue) { + if (type == null) { + return ((BasicValue) value).type == null; + } else { + return type.equals(((BasicValue) value).type); + } + } else { + return false; + } + } + + @Override + public int hashCode() { + return type == null ? 0 : type.hashCode(); + } + + @Override + public String toString() { + if (this == UNINITIALIZED_VALUE) { + return "."; + } else if (this == RETURNADDRESS_VALUE) { + return "A"; + } else if (this == REFERENCE_VALUE) { + return "R"; + } else { + return type.getDescriptor(); + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicVerifier.java ---------------------------------------------------------------------- diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicVerifier.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicVerifier.java new file mode 100644 index 0000000..9ad66c3 --- /dev/null +++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/tree/analysis/BasicVerifier.java @@ -0,0 +1,433 @@ +/*** + * 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.tree.analysis; + +import java.util.List; + +import org.apache.tajo.org.objectweb.asm.Type; +import org.apache.tajo.org.objectweb.asm.tree.AbstractInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.FieldInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.InvokeDynamicInsnNode; +import org.apache.tajo.org.objectweb.asm.tree.MethodInsnNode; + +/** + * An extended {@link BasicInterpreter} that checks that bytecode instructions + * are correctly used. + * + * @author Eric Bruneton + * @author Bing Ran + */ +public class BasicVerifier extends BasicInterpreter { + + public BasicVerifier() { + super(ASM4); + } + + protected BasicVerifier(final int api) { + super(api); + } + + @Override + public BasicValue copyOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { + Value expected; + switch (insn.getOpcode()) { + case ILOAD: + case ISTORE: + expected = BasicValue.INT_VALUE; + break; + case FLOAD: + case FSTORE: + expected = BasicValue.FLOAT_VALUE; + break; + case LLOAD: + case LSTORE: + expected = BasicValue.LONG_VALUE; + break; + case DLOAD: + case DSTORE: + expected = BasicValue.DOUBLE_VALUE; + break; + case ALOAD: + if (!value.isReference()) { + throw new AnalyzerException(insn, null, "an object reference", + value); + } + return value; + case ASTORE: + if (!value.isReference() + && !BasicValue.RETURNADDRESS_VALUE.equals(value)) { + throw new AnalyzerException(insn, null, + "an object reference or a return address", value); + } + return value; + default: + return value; + } + if (!expected.equals(value)) { + throw new AnalyzerException(insn, null, expected, value); + } + return value; + } + + @Override + public BasicValue unaryOperation(final AbstractInsnNode insn, + final BasicValue value) throws AnalyzerException { + BasicValue expected; + switch (insn.getOpcode()) { + case INEG: + case IINC: + case I2F: + case I2L: + case I2D: + case I2B: + case I2C: + case I2S: + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case NEWARRAY: + case ANEWARRAY: + expected = BasicValue.INT_VALUE; + break; + case FNEG: + case F2I: + case F2L: + case F2D: + case FRETURN: + expected = BasicValue.FLOAT_VALUE; + break; + case LNEG: + case L2I: + case L2F: + case L2D: + case LRETURN: + expected = BasicValue.LONG_VALUE; + break; + case DNEG: + case D2I: + case D2F: + case D2L: + case DRETURN: + expected = BasicValue.DOUBLE_VALUE; + break; + case GETFIELD: + expected = newValue(Type + .getObjectType(((FieldInsnNode) insn).owner)); + break; + case CHECKCAST: + if (!value.isReference()) { + throw new AnalyzerException(insn, null, "an object reference", + value); + } + return super.unaryOperation(insn, value); + case ARRAYLENGTH: + if (!isArrayValue(value)) { + throw new AnalyzerException(insn, null, "an array reference", + value); + } + return super.unaryOperation(insn, value); + case ARETURN: + case ATHROW: + case INSTANCEOF: + case MONITORENTER: + case MONITOREXIT: + case IFNULL: + case IFNONNULL: + if (!value.isReference()) { + throw new AnalyzerException(insn, null, "an object reference", + value); + } + return super.unaryOperation(insn, value); + case PUTSTATIC: + expected = newValue(Type.getType(((FieldInsnNode) insn).desc)); + break; + default: + throw new Error("Internal error."); + } + if (!isSubTypeOf(value, expected)) { + throw new AnalyzerException(insn, null, expected, value); + } + return super.unaryOperation(insn, value); + } + + @Override + public BasicValue binaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2) + throws AnalyzerException { + BasicValue expected1; + BasicValue expected2; + switch (insn.getOpcode()) { + case IALOAD: + expected1 = newValue(Type.getType("[I")); + expected2 = BasicValue.INT_VALUE; + break; + case BALOAD: + if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { + expected1 = newValue(Type.getType("[Z")); + } else { + expected1 = newValue(Type.getType("[B")); + } + expected2 = BasicValue.INT_VALUE; + break; + case CALOAD: + expected1 = newValue(Type.getType("[C")); + expected2 = BasicValue.INT_VALUE; + break; + case SALOAD: + expected1 = newValue(Type.getType("[S")); + expected2 = BasicValue.INT_VALUE; + break; + case LALOAD: + expected1 = newValue(Type.getType("[J")); + expected2 = BasicValue.INT_VALUE; + break; + case FALOAD: + expected1 = newValue(Type.getType("[F")); + expected2 = BasicValue.INT_VALUE; + break; + case DALOAD: + expected1 = newValue(Type.getType("[D")); + expected2 = BasicValue.INT_VALUE; + break; + case AALOAD: + expected1 = newValue(Type.getType("[Ljava/lang/Object;")); + expected2 = BasicValue.INT_VALUE; + break; + case IADD: + case ISUB: + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + expected1 = BasicValue.INT_VALUE; + expected2 = BasicValue.INT_VALUE; + break; + case FADD: + case FSUB: + case FMUL: + case FDIV: + case FREM: + case FCMPL: + case FCMPG: + expected1 = BasicValue.FLOAT_VALUE; + expected2 = BasicValue.FLOAT_VALUE; + break; + case LADD: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LAND: + case LOR: + case LXOR: + case LCMP: + expected1 = BasicValue.LONG_VALUE; + expected2 = BasicValue.LONG_VALUE; + break; + case LSHL: + case LSHR: + case LUSHR: + expected1 = BasicValue.LONG_VALUE; + expected2 = BasicValue.INT_VALUE; + break; + case DADD: + case DSUB: + case DMUL: + case DDIV: + case DREM: + case DCMPL: + case DCMPG: + expected1 = BasicValue.DOUBLE_VALUE; + expected2 = BasicValue.DOUBLE_VALUE; + break; + case IF_ACMPEQ: + case IF_ACMPNE: + expected1 = BasicValue.REFERENCE_VALUE; + expected2 = BasicValue.REFERENCE_VALUE; + break; + case PUTFIELD: + FieldInsnNode fin = (FieldInsnNode) insn; + expected1 = newValue(Type.getObjectType(fin.owner)); + expected2 = newValue(Type.getType(fin.desc)); + break; + default: + throw new Error("Internal error."); + } + if (!isSubTypeOf(value1, expected1)) { + throw new AnalyzerException(insn, "First argument", expected1, + value1); + } else if (!isSubTypeOf(value2, expected2)) { + throw new AnalyzerException(insn, "Second argument", expected2, + value2); + } + if (insn.getOpcode() == AALOAD) { + return getElementValue(value1); + } else { + return super.binaryOperation(insn, value1, value2); + } + } + + @Override + public BasicValue ternaryOperation(final AbstractInsnNode insn, + final BasicValue value1, final BasicValue value2, + final BasicValue value3) throws AnalyzerException { + BasicValue expected1; + BasicValue expected3; + switch (insn.getOpcode()) { + case IASTORE: + expected1 = newValue(Type.getType("[I")); + expected3 = BasicValue.INT_VALUE; + break; + case BASTORE: + if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { + expected1 = newValue(Type.getType("[Z")); + } else { + expected1 = newValue(Type.getType("[B")); + } + expected3 = BasicValue.INT_VALUE; + break; + case CASTORE: + expected1 = newValue(Type.getType("[C")); + expected3 = BasicValue.INT_VALUE; + break; + case SASTORE: + expected1 = newValue(Type.getType("[S")); + expected3 = BasicValue.INT_VALUE; + break; + case LASTORE: + expected1 = newValue(Type.getType("[J")); + expected3 = BasicValue.LONG_VALUE; + break; + case FASTORE: + expected1 = newValue(Type.getType("[F")); + expected3 = BasicValue.FLOAT_VALUE; + break; + case DASTORE: + expected1 = newValue(Type.getType("[D")); + expected3 = BasicValue.DOUBLE_VALUE; + break; + case AASTORE: + expected1 = value1; + expected3 = BasicValue.REFERENCE_VALUE; + break; + default: + throw new Error("Internal error."); + } + if (!isSubTypeOf(value1, expected1)) { + throw new AnalyzerException(insn, "First argument", "a " + + expected1 + " array reference", value1); + } else if (!BasicValue.INT_VALUE.equals(value2)) { + throw new AnalyzerException(insn, "Second argument", + BasicValue.INT_VALUE, value2); + } else if (!isSubTypeOf(value3, expected3)) { + throw new AnalyzerException(insn, "Third argument", expected3, + value3); + } + return null; + } + + @Override + public BasicValue naryOperation(final AbstractInsnNode insn, + final List<? extends BasicValue> values) throws AnalyzerException { + int opcode = insn.getOpcode(); + if (opcode == MULTIANEWARRAY) { + for (int i = 0; i < values.size(); ++i) { + if (!BasicValue.INT_VALUE.equals(values.get(i))) { + throw new AnalyzerException(insn, null, + BasicValue.INT_VALUE, values.get(i)); + } + } + } else { + int i = 0; + int j = 0; + if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { + Type owner = Type.getObjectType(((MethodInsnNode) insn).owner); + if (!isSubTypeOf(values.get(i++), newValue(owner))) { + throw new AnalyzerException(insn, "Method owner", + newValue(owner), values.get(0)); + } + } + String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc + : ((MethodInsnNode) insn).desc; + Type[] args = Type.getArgumentTypes(desc); + while (i < values.size()) { + BasicValue expected = newValue(args[j++]); + BasicValue encountered = values.get(i++); + if (!isSubTypeOf(encountered, expected)) { + throw new AnalyzerException(insn, "Argument " + j, + expected, encountered); + } + } + } + return super.naryOperation(insn, values); + } + + @Override + public void returnOperation(final AbstractInsnNode insn, + final BasicValue value, final BasicValue expected) + throws AnalyzerException { + if (!isSubTypeOf(value, expected)) { + throw new AnalyzerException(insn, "Incompatible return type", + expected, value); + } + } + + protected boolean isArrayValue(final BasicValue value) { + return value.isReference(); + } + + protected BasicValue getElementValue(final BasicValue objectArrayValue) + throws AnalyzerException { + return BasicValue.REFERENCE_VALUE; + } + + protected boolean isSubTypeOf(final BasicValue value, + final BasicValue expected) { + return value.equals(expected); + } +}
