You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2014/08/23 19:38:01 UTC

[12/25] TAJO-906: Runtime code generation for evaluating expression trees.

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/JSRInlinerAdapter.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/JSRInlinerAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/JSRInlinerAdapter.java
new file mode 100644
index 0000000..b64f371
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/JSRInlinerAdapter.java
@@ -0,0 +1,746 @@
+/***
+ * 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.commons;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tajo.org.objectweb.asm.Label;
+import org.apache.tajo.org.objectweb.asm.MethodVisitor;
+import org.apache.tajo.org.objectweb.asm.tree.InsnNode;
+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.Opcodes;
+import org.apache.tajo.org.objectweb.asm.tree.AbstractInsnNode;
+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.LocalVariableNode;
+import org.apache.tajo.org.objectweb.asm.tree.TableSwitchInsnNode;
+import org.apache.tajo.org.objectweb.asm.tree.TryCatchBlockNode;
+
+/**
+ * A {@link org.apache.tajo.org.objectweb.asm.MethodVisitor} that removes JSR instructions and
+ * inlines the referenced subroutines.
+ * 
+ * <b>Explanation of how it works</b> TODO
+ * 
+ * @author Niko Matsakis
+ */
+public class JSRInlinerAdapter extends MethodNode implements Opcodes {
+
+    private static final boolean LOGGING = false;
+
+    /**
+     * For each label that is jumped to by a JSR, we create a BitSet instance.
+     */
+    private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
+
+    /**
+     * This subroutine instance denotes the line of execution that is not
+     * contained within any subroutine; i.e., the "subroutine" that is executing
+     * when a method first begins.
+     */
+    private final BitSet mainSubroutine = new BitSet();
+
+    /**
+     * This BitSet contains the index of every instruction that belongs to more
+     * than one subroutine. This should not happen often.
+     */
+    final BitSet dualCitizens = new BitSet();
+
+    /**
+     * Creates a new JSRInliner. <i>Subclasses must not use this
+     * constructor</i>. Instead, they must use the
+     * {@link #JSRInlinerAdapter(int, org.apache.tajo.org.objectweb.asm.MethodVisitor, int, String, String, String, String[])}
+     * version.
+     * 
+     * @param mv
+     *            the <code>MethodVisitor</code> to send the resulting inlined
+     *            method code to (use <code>null</code> for none).
+     * @param access
+     *            the method's access flags (see {@link Opcodes}). This
+     *            parameter also indicates if the method is synthetic and/or
+     *            deprecated.
+     * @param name
+     *            the method's name.
+     * @param desc
+     *            the method's descriptor (see {@link org.apache.tajo.org.objectweb.asm.Type}).
+     * @param signature
+     *            the method's signature. May be <tt>null</tt>.
+     * @param exceptions
+     *            the internal names of the method's exception classes (see
+     *            {@link org.apache.tajo.org.objectweb.asm.Type#getInternalName() getInternalName}). May be
+     *            <tt>null</tt>.
+     */
+    public JSRInlinerAdapter(final MethodVisitor mv, final int access,
+            final String name, final String desc, final String signature,
+            final String[] exceptions) {
+        this(Opcodes.ASM4, mv, access, name, desc, signature, exceptions);
+    }
+
+    /**
+     * Creates a new JSRInliner.
+     * 
+     * @param api
+     *            the ASM API version implemented by this visitor. Must be one
+     *            of {@link Opcodes#ASM4}.
+     * @param mv
+     *            the <code>MethodVisitor</code> to send the resulting inlined
+     *            method code to (use <code>null</code> for none).
+     * @param access
+     *            the method's access flags (see {@link Opcodes}). This
+     *            parameter also indicates if the method is synthetic and/or
+     *            deprecated.
+     * @param name
+     *            the method's name.
+     * @param desc
+     *            the method's descriptor (see {@link org.apache.tajo.org.objectweb.asm.Type}).
+     * @param signature
+     *            the method's signature. May be <tt>null</tt>.
+     * @param exceptions
+     *            the internal names of the method's exception classes (see
+     *            {@link org.apache.tajo.org.objectweb.asm.Type#getInternalName() getInternalName}). May be
+     *            <tt>null</tt>.
+     */
+    protected JSRInlinerAdapter(final int api, final MethodVisitor mv,
+            final int access, final String name, final String desc,
+            final String signature, final String[] exceptions) {
+        super(api, access, name, desc, signature, exceptions);
+        this.mv = mv;
+    }
+
+    /**
+     * Detects a JSR instruction and sets a flag to indicate we will need to do
+     * inlining.
+     */
+    @Override
+    public void visitJumpInsn(final int opcode, final Label lbl) {
+        super.visitJumpInsn(opcode, lbl);
+        LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
+        if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
+            subroutineHeads.put(ln, new BitSet());
+        }
+    }
+
+    /**
+     * If any JSRs were seen, triggers the inlining process. Otherwise, forwards
+     * the byte codes untouched.
+     */
+    @Override
+    public void visitEnd() {
+        if (!subroutineHeads.isEmpty()) {
+            markSubroutines();
+            if (LOGGING) {
+                log(mainSubroutine.toString());
+                Iterator<BitSet> it = subroutineHeads.values().iterator();
+                while (it.hasNext()) {
+                    BitSet sub = it.next();
+                    log(sub.toString());
+                }
+            }
+            emitCode();
+        }
+
+        // Forward the translate opcodes on if appropriate:
+        if (mv != null) {
+            accept(mv);
+        }
+    }
+
+    /**
+     * Walks the method and determines which internal subroutine(s), if any,
+     * each instruction is a method of.
+     */
+    private void markSubroutines() {
+        BitSet anyvisited = new BitSet();
+
+        // First walk the main subroutine and find all those instructions which
+        // can be reached without invoking any JSR at all
+        markSubroutineWalk(mainSubroutine, 0, anyvisited);
+
+        // Go through the head of each subroutine and find any nodes reachable
+        // to that subroutine without following any JSR links.
+        for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads
+                .entrySet().iterator(); it.hasNext();) {
+            Map.Entry<LabelNode, BitSet> entry = it.next();
+            LabelNode lab = entry.getKey();
+            BitSet sub = entry.getValue();
+            int index = instructions.indexOf(lab);
+            markSubroutineWalk(sub, index, anyvisited);
+        }
+    }
+
+    /**
+     * Performs a depth first search walking the normal byte code path starting
+     * at <code>index</code>, and adding each instruction encountered into the
+     * subroutine <code>sub</code>. After this walk is complete, iterates over
+     * the exception handlers to ensure that we also include those byte codes
+     * which are reachable through an exception that may be thrown during the
+     * execution of the subroutine. Invoked from <code>markSubroutines()</code>.
+     * 
+     * @param sub
+     *            the subroutine whose instructions must be computed.
+     * @param index
+     *            an instruction of this subroutine.
+     * @param anyvisited
+     *            indexes of the already visited instructions, i.e. marked as
+     *            part of this subroutine or any previously computed subroutine.
+     */
+    private void markSubroutineWalk(final BitSet sub, final int index,
+            final BitSet anyvisited) {
+        if (LOGGING) {
+            log("markSubroutineWalk: sub=" + sub + " index=" + index);
+        }
+
+        // First find those instructions reachable via normal execution
+        markSubroutineWalkDFS(sub, index, anyvisited);
+
+        // Now, make sure we also include any applicable exception handlers
+        boolean loop = true;
+        while (loop) {
+            loop = false;
+            for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
+                    .hasNext();) {
+                TryCatchBlockNode trycatch = it.next();
+
+                if (LOGGING) {
+                    // TODO use of default toString().
+                    log("Scanning try/catch " + trycatch);
+                }
+
+                // If the handler has already been processed, skip it.
+                int handlerindex = instructions.indexOf(trycatch.handler);
+                if (sub.get(handlerindex)) {
+                    continue;
+                }
+
+                int startindex = instructions.indexOf(trycatch.start);
+                int endindex = instructions.indexOf(trycatch.end);
+                int nextbit = sub.nextSetBit(startindex);
+                if (nextbit != -1 && nextbit < endindex) {
+                    if (LOGGING) {
+                        log("Adding exception handler: " + startindex + '-'
+                                + endindex + " due to " + nextbit + " handler "
+                                + handlerindex);
+                    }
+                    markSubroutineWalkDFS(sub, handlerindex, anyvisited);
+                    loop = true;
+                }
+            }
+        }
+    }
+
+    /**
+     * Performs a simple DFS of the instructions, assigning each to the
+     * subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
+     * by <code>markSubroutineWalk()</code>.
+     * 
+     * @param sub
+     *            the subroutine whose instructions must be computed.
+     * @param index
+     *            an instruction of this subroutine.
+     * @param anyvisited
+     *            indexes of the already visited instructions, i.e. marked as
+     *            part of this subroutine or any previously computed subroutine.
+     */
+    private void markSubroutineWalkDFS(final BitSet sub, int index,
+            final BitSet anyvisited) {
+        while (true) {
+            AbstractInsnNode node = instructions.get(index);
+
+            // don't visit a node twice
+            if (sub.get(index)) {
+                return;
+            }
+            sub.set(index);
+
+            // check for those nodes already visited by another subroutine
+            if (anyvisited.get(index)) {
+                dualCitizens.set(index);
+                if (LOGGING) {
+                    log("Instruction #" + index + " is dual citizen.");
+                }
+            }
+            anyvisited.set(index);
+
+            if (node.getType() == AbstractInsnNode.JUMP_INSN
+                    && node.getOpcode() != JSR) {
+                // we do not follow recursively called subroutines here; but any
+                // other sort of branch we do follow
+                JumpInsnNode jnode = (JumpInsnNode) node;
+                int destidx = instructions.indexOf(jnode.label);
+                markSubroutineWalkDFS(sub, destidx, anyvisited);
+            }
+            if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
+                TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
+                int destidx = instructions.indexOf(tsnode.dflt);
+                markSubroutineWalkDFS(sub, destidx, anyvisited);
+                for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
+                    LabelNode l = tsnode.labels.get(i);
+                    destidx = instructions.indexOf(l);
+                    markSubroutineWalkDFS(sub, destidx, anyvisited);
+                }
+            }
+            if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
+                LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
+                int destidx = instructions.indexOf(lsnode.dflt);
+                markSubroutineWalkDFS(sub, destidx, anyvisited);
+                for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
+                    LabelNode l = lsnode.labels.get(i);
+                    destidx = instructions.indexOf(l);
+                    markSubroutineWalkDFS(sub, destidx, anyvisited);
+                }
+            }
+
+            // check to see if this opcode falls through to the next instruction
+            // or not; if not, return.
+            switch (instructions.get(index).getOpcode()) {
+            case GOTO:
+            case RET:
+            case TABLESWITCH:
+            case LOOKUPSWITCH:
+            case IRETURN:
+            case LRETURN:
+            case FRETURN:
+            case DRETURN:
+            case ARETURN:
+            case RETURN:
+            case ATHROW:
+                /*
+                 * note: this either returns from this subroutine, or a parent
+                 * subroutine which invoked it
+                 */
+                return;
+            }
+
+            // Use tail recursion here in the form of an outer while loop to
+            // avoid our stack growing needlessly:
+            index++;
+
+            // We implicitly assumed above that execution can always fall
+            // through to the next instruction after a JSR. But a subroutine may
+            // never return, in which case the code after the JSR is unreachable
+            // and can be anything. In particular, it can seem to fall off the
+            // end of the method, so we must handle this case here (we could
+            // instead detect whether execution can return or not from a JSR,
+            // but this is more complicated).
+            if (index >= instructions.size()) {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Creates the new instructions, inlining each instantiation of each
+     * subroutine until the code is fully elaborated.
+     */
+    private void emitCode() {
+        LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
+        // Create an instantiation of the "root" subroutine, which is just the
+        // main routine
+        worklist.add(new Instantiation(null, mainSubroutine));
+
+        // Emit instantiations of each subroutine we encounter, including the
+        // main subroutine
+        InsnList newInstructions = new InsnList();
+        List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
+        List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
+        while (!worklist.isEmpty()) {
+            Instantiation inst = worklist.removeFirst();
+            emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks,
+                    newLocalVariables);
+        }
+        instructions = newInstructions;
+        tryCatchBlocks = newTryCatchBlocks;
+        localVariables = newLocalVariables;
+    }
+
+    /**
+     * Emits one instantiation of one subroutine, specified by
+     * <code>instant</code>. May add new instantiations that are invoked by this
+     * one to the <code>worklist</code> parameter, and new try/catch blocks to
+     * <code>newTryCatchBlocks</code>.
+     * 
+     * @param instant
+     *            the instantiation that must be performed.
+     * @param worklist
+     *            list of the instantiations that remain to be done.
+     * @param newInstructions
+     *            the instruction list to which the instantiated code must be
+     *            appended.
+     * @param newTryCatchBlocks
+     *            the exception handler list to which the instantiated handlers
+     *            must be appended.
+     */
+    private void emitSubroutine(final Instantiation instant,
+            final List<Instantiation> worklist, final InsnList newInstructions,
+            final List<TryCatchBlockNode> newTryCatchBlocks,
+            final List<LocalVariableNode> newLocalVariables) {
+        LabelNode duplbl = null;
+
+        if (LOGGING) {
+            log("--------------------------------------------------------");
+            log("Emitting instantiation of subroutine " + instant.subroutine);
+        }
+
+        // Emit the relevant instructions for this instantiation, translating
+        // labels and jump targets as we go:
+        for (int i = 0, c = instructions.size(); i < c; i++) {
+            AbstractInsnNode insn = instructions.get(i);
+            Instantiation owner = instant.findOwner(i);
+
+            // Always remap labels:
+            if (insn.getType() == AbstractInsnNode.LABEL) {
+                // Translate labels into their renamed equivalents.
+                // Avoid adding the same label more than once. Note
+                // that because we own this instruction the gotoTable
+                // and the rangeTable will always agree.
+                LabelNode ilbl = (LabelNode) insn;
+                LabelNode remap = instant.rangeLabel(ilbl);
+                if (LOGGING) {
+                    // TODO use of default toString().
+                    log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
+                }
+                if (remap != duplbl) {
+                    newInstructions.add(remap);
+                    duplbl = remap;
+                }
+                continue;
+            }
+
+            // We don't want to emit instructions that were already
+            // emitted by a subroutine higher on the stack. Note that
+            // it is still possible for a given instruction to be
+            // emitted twice because it may belong to two subroutines
+            // that do not invoke each other.
+            if (owner != instant) {
+                continue;
+            }
+
+            if (LOGGING) {
+                log("Emitting inst #" + i);
+            }
+
+            if (insn.getOpcode() == RET) {
+                // Translate RET instruction(s) to a jump to the return label
+                // for the appropriate instantiation. The problem is that the
+                // subroutine may "fall through" to the ret of a parent
+                // subroutine; therefore, to find the appropriate ret label we
+                // find the lowest subroutine on the stack that claims to own
+                // this instruction. See the class javadoc comment for an
+                // explanation on why this technique is safe (note: it is only
+                // safe if the input is verifiable).
+                LabelNode retlabel = null;
+                for (Instantiation p = instant; p != null; p = p.previous) {
+                    if (p.subroutine.get(i)) {
+                        retlabel = p.returnLabel;
+                    }
+                }
+                if (retlabel == null) {
+                    // This is only possible if the mainSubroutine owns a RET
+                    // instruction, which should never happen for verifiable
+                    // code.
+                    throw new RuntimeException("Instruction #" + i
+                            + " is a RET not owned by any subroutine");
+                }
+                newInstructions.add(new JumpInsnNode(GOTO, retlabel));
+            } else if (insn.getOpcode() == JSR) {
+                LabelNode lbl = ((JumpInsnNode) insn).label;
+                BitSet sub = subroutineHeads.get(lbl);
+                Instantiation newinst = new Instantiation(instant, sub);
+                LabelNode startlbl = newinst.gotoLabel(lbl);
+
+                if (LOGGING) {
+                    log(" Creating instantiation of subr " + sub);
+                }
+
+                // Rather than JSRing, we will jump to the inline version and
+                // push NULL for what was once the return value. This hack
+                // allows us to avoid doing any sort of data flow analysis to
+                // figure out which instructions manipulate the old return value
+                // pointer which is now known to be unneeded.
+                newInstructions.add(new InsnNode(ACONST_NULL));
+                newInstructions.add(new JumpInsnNode(GOTO, startlbl));
+                newInstructions.add(newinst.returnLabel);
+
+                // Insert this new instantiation into the queue to be emitted
+                // later.
+                worklist.add(newinst);
+            } else {
+                newInstructions.add(insn.clone(instant));
+            }
+        }
+
+        // Emit try/catch blocks that are relevant to this method.
+        for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
+                .hasNext();) {
+            TryCatchBlockNode trycatch = it.next();
+
+            if (LOGGING) {
+                // TODO use of default toString().
+                log("try catch block original labels=" + trycatch.start + '-'
+                        + trycatch.end + "->" + trycatch.handler);
+            }
+
+            final LabelNode start = instant.rangeLabel(trycatch.start);
+            final LabelNode end = instant.rangeLabel(trycatch.end);
+
+            // Ignore empty try/catch regions
+            if (start == end) {
+                if (LOGGING) {
+                    log(" try catch block empty in this subroutine");
+                }
+                continue;
+            }
+
+            final LabelNode handler = instant.gotoLabel(trycatch.handler);
+
+            if (LOGGING) {
+                // TODO use of default toString().
+                log(" try catch block new labels=" + start + '-' + end + "->"
+                        + handler);
+            }
+
+            if (start == null || end == null || handler == null) {
+                throw new RuntimeException("Internal error!");
+            }
+
+            newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler,
+                    trycatch.type));
+        }
+
+        for (Iterator<LocalVariableNode> it = localVariables.iterator(); it
+                .hasNext();) {
+            LocalVariableNode lvnode = it.next();
+            if (LOGGING) {
+                log("local var " + lvnode.name);
+            }
+            final LabelNode start = instant.rangeLabel(lvnode.start);
+            final LabelNode end = instant.rangeLabel(lvnode.end);
+            if (start == end) {
+                if (LOGGING) {
+                    log("  local variable empty in this sub");
+                }
+                continue;
+            }
+            newLocalVariables.add(new LocalVariableNode(lvnode.name,
+                    lvnode.desc, lvnode.signature, start, end, lvnode.index));
+        }
+    }
+
+    private static void log(final String str) {
+        System.err.println(str);
+    }
+
+    /**
+     * A class that represents an instantiation of a subroutine. Each
+     * instantiation has an associate "stack" --- which is a listing of those
+     * instantiations that were active when this particular instance of this
+     * subroutine was invoked. Each instantiation also has a map from the
+     * original labels of the program to the labels appropriate for this
+     * instantiation, and finally a label to return to.
+     */
+    private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
+
+        /**
+         * Previous instantiations; the stack must be statically predictable to
+         * be inlinable.
+         */
+        final Instantiation previous;
+
+        /**
+         * The subroutine this is an instantiation of.
+         */
+        public final BitSet subroutine;
+
+        /**
+         * This table maps Labels from the original source to Labels pointing at
+         * code specific to this instantiation, for use in remapping try/catch
+         * blocks,as well as gotos.
+         * 
+         * Note that in the presence of dual citizens instructions, that is,
+         * instructions which belong to more than one subroutine due to the
+         * merging of control flow without a RET instruction, we will map the
+         * target label of a GOTO to the label used by the instantiation lowest
+         * on the stack. This avoids code duplication during inlining in most
+         * cases.
+         * 
+         * @see #findOwner(int)
+         */
+        public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
+
+        /**
+         * All returns for this instantiation will be mapped to this label
+         */
+        public final LabelNode returnLabel;
+
+        Instantiation(final Instantiation prev, final BitSet sub) {
+            previous = prev;
+            subroutine = sub;
+            for (Instantiation p = prev; p != null; p = p.previous) {
+                if (p.subroutine == sub) {
+                    throw new RuntimeException("Recursive invocation of " + sub);
+                }
+            }
+
+            // Determine the label to return to when this subroutine terminates
+            // via RET: note that the main subroutine never terminates via RET.
+            if (prev != null) {
+                returnLabel = new LabelNode();
+            } else {
+                returnLabel = null;
+            }
+
+            // Each instantiation will remap the labels from the code above to
+            // refer to its particular copy of its own instructions. Note that
+            // we collapse labels which point at the same instruction into one:
+            // this is fairly common as we are often ignoring large chunks of
+            // instructions, so what were previously distinct labels become
+            // duplicates.
+            LabelNode duplbl = null;
+            for (int i = 0, c = instructions.size(); i < c; i++) {
+                AbstractInsnNode insn = instructions.get(i);
+
+                if (insn.getType() == AbstractInsnNode.LABEL) {
+                    LabelNode ilbl = (LabelNode) insn;
+
+                    if (duplbl == null) {
+                        // if we already have a label pointing at this spot,
+                        // don't recreate it.
+                        duplbl = new LabelNode();
+                    }
+
+                    // Add an entry in the rangeTable for every label
+                    // in the original code which points at the next
+                    // instruction of our own to be emitted.
+                    rangeTable.put(ilbl, duplbl);
+                } else if (findOwner(i) == this) {
+                    // We will emit this instruction, so clear the 'duplbl' flag
+                    // since the next Label will refer to a distinct
+                    // instruction.
+                    duplbl = null;
+                }
+            }
+        }
+
+        /**
+         * Returns the "owner" of a particular instruction relative to this
+         * instantiation: the owner referes to the Instantiation which will emit
+         * the version of this instruction that we will execute.
+         * 
+         * Typically, the return value is either <code>this</code> or
+         * <code>null</code>. <code>this</code> indicates that this
+         * instantiation will generate the version of this instruction that we
+         * will execute, and <code>null</code> indicates that this instantiation
+         * never executes the given instruction.
+         * 
+         * Sometimes, however, an instruction can belong to multiple
+         * subroutines; this is called a "dual citizen" instruction (though it
+         * may belong to more than 2 subroutines), and occurs when multiple
+         * subroutines branch to common points of control. In this case, the
+         * owner is the subroutine that appears lowest on the stack, and which
+         * also owns the instruction in question.
+         * 
+         * @param i
+         *            the index of the instruction in the original code
+         * @return the "owner" of a particular instruction relative to this
+         *         instantiation.
+         */
+        public Instantiation findOwner(final int i) {
+            if (!subroutine.get(i)) {
+                return null;
+            }
+            if (!dualCitizens.get(i)) {
+                return this;
+            }
+            Instantiation own = this;
+            for (Instantiation p = previous; p != null; p = p.previous) {
+                if (p.subroutine.get(i)) {
+                    own = p;
+                }
+            }
+            return own;
+        }
+
+        /**
+         * Looks up the label <code>l</code> in the <code>gotoTable</code>, thus
+         * translating it from a Label in the original code, to a Label in the
+         * inlined code that is appropriate for use by an instruction that
+         * branched to the original label.
+         * 
+         * @param l
+         *            The label we will be translating
+         * @return a label for use by a branch instruction in the inlined code
+         * @see #rangeLabel
+         */
+        public LabelNode gotoLabel(final LabelNode l) {
+            // owner should never be null, because owner is only null
+            // if an instruction cannot be reached from this subroutine
+            Instantiation owner = findOwner(instructions.indexOf(l));
+            return owner.rangeTable.get(l);
+        }
+
+        /**
+         * Looks up the label <code>l</code> in the <code>rangeTable</code>,
+         * thus translating it from a Label in the original code, to a Label in
+         * the inlined code that is appropriate for use by an try/catch or
+         * variable use annotation.
+         * 
+         * @param l
+         *            The label we will be translating
+         * @return a label for use by a try/catch or variable annotation in the
+         *         original code
+         * @see #rangeTable
+         */
+        public LabelNode rangeLabel(final LabelNode l) {
+            return rangeTable.get(l);
+        }
+
+        // AbstractMap implementation
+
+        @Override
+        public Set<Map.Entry<LabelNode, LabelNode>> entrySet() {
+            return null;
+        }
+
+        @Override
+        public LabelNode get(final Object o) {
+            return gotoLabel((LabelNode) o);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/LocalVariablesSorter.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/LocalVariablesSorter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/LocalVariablesSorter.java
new file mode 100644
index 0000000..0fdcb1e
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/LocalVariablesSorter.java
@@ -0,0 +1,361 @@
+/***
+ * 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.commons;
+
+import org.apache.tajo.org.objectweb.asm.Label;
+import org.apache.tajo.org.objectweb.asm.MethodVisitor;
+import org.apache.tajo.org.objectweb.asm.Type;
+import org.apache.tajo.org.objectweb.asm.Opcodes;
+
+/**
+ * A {@link org.apache.tajo.org.objectweb.asm.MethodVisitor} that renumbers local variables in their order of
+ * appearance. This adapter allows one to easily add new local variables to a
+ * method. It may be used by inheriting from this class, but the preferred way
+ * of using it is via delegation: the next visitor in the chain can indeed add
+ * new locals when needed by calling {@link #newLocal} on this adapter (this
+ * requires a reference back to this {@link LocalVariablesSorter}).
+ * 
+ * @author Chris Nokleberg
+ * @author Eugene Kuleshov
+ * @author Eric Bruneton
+ */
+public class LocalVariablesSorter extends MethodVisitor {
+
+    private static final Type OBJECT_TYPE = Type
+            .getObjectType("java/lang/Object");
+
+    /**
+     * Mapping from old to new local variable indexes. A local variable at index
+     * i of size 1 is remapped to 'mapping[2*i]', while a local variable at
+     * index i of size 2 is remapped to 'mapping[2*i+1]'.
+     */
+    private int[] mapping = new int[40];
+
+    /**
+     * Array used to store stack map local variable types after remapping.
+     */
+    private Object[] newLocals = new Object[20];
+
+    /**
+     * Index of the first local variable, after formal parameters.
+     */
+    protected final int firstLocal;
+
+    /**
+     * Index of the next local variable to be created by {@link #newLocal}.
+     */
+    protected int nextLocal;
+
+    /**
+     * Indicates if at least one local variable has moved due to remapping.
+     */
+    private boolean changed;
+
+    /**
+     * Creates a new {@link LocalVariablesSorter}. <i>Subclasses must not use
+     * this constructor</i>. Instead, they must use the
+     * {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
+     * 
+     * @param access
+     *            access flags of the adapted method.
+     * @param desc
+     *            the method's descriptor (see {@link Type Type}).
+     * @param mv
+     *            the method visitor to which this adapter delegates calls.
+     */
+    public LocalVariablesSorter(final int access, final String desc,
+            final MethodVisitor mv) {
+        this(Opcodes.ASM4, access, desc, mv);
+    }
+
+    /**
+     * Creates a new {@link LocalVariablesSorter}.
+     * 
+     * @param api
+     *            the ASM API version implemented by this visitor. Must be one
+     *            of {@link Opcodes#ASM4}.
+     * @param access
+     *            access flags of the adapted method.
+     * @param desc
+     *            the method's descriptor (see {@link Type Type}).
+     * @param mv
+     *            the method visitor to which this adapter delegates calls.
+     */
+    protected LocalVariablesSorter(final int api, final int access,
+            final String desc, final MethodVisitor mv) {
+        super(api, mv);
+        Type[] args = Type.getArgumentTypes(desc);
+        nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
+        for (int i = 0; i < args.length; i++) {
+            nextLocal += args[i].getSize();
+        }
+        firstLocal = nextLocal;
+    }
+
+    @Override
+    public void visitVarInsn(final int opcode, final int var) {
+        Type type;
+        switch (opcode) {
+        case Opcodes.LLOAD:
+        case Opcodes.LSTORE:
+            type = Type.LONG_TYPE;
+            break;
+
+        case Opcodes.DLOAD:
+        case Opcodes.DSTORE:
+            type = Type.DOUBLE_TYPE;
+            break;
+
+        case Opcodes.FLOAD:
+        case Opcodes.FSTORE:
+            type = Type.FLOAT_TYPE;
+            break;
+
+        case Opcodes.ILOAD:
+        case Opcodes.ISTORE:
+            type = Type.INT_TYPE;
+            break;
+
+        default:
+            // case Opcodes.ALOAD:
+            // case Opcodes.ASTORE:
+            // case RET:
+            type = OBJECT_TYPE;
+            break;
+        }
+        mv.visitVarInsn(opcode, remap(var, type));
+    }
+
+    @Override
+    public void visitIincInsn(final int var, final int increment) {
+        mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
+    }
+
+    @Override
+    public void visitMaxs(final int maxStack, final int maxLocals) {
+        mv.visitMaxs(maxStack, nextLocal);
+    }
+
+    @Override
+    public void visitLocalVariable(final String name, final String desc,
+            final String signature, final Label start, final Label end,
+            final int index) {
+        int newIndex = remap(index, Type.getType(desc));
+        mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
+    }
+
+    @Override
+    public void visitFrame(final int type, final int nLocal,
+            final Object[] local, final int nStack, final Object[] stack) {
+        if (type != Opcodes.F_NEW) { // uncompressed frame
+            throw new IllegalStateException(
+                    "ClassReader.accept() should be called with EXPAND_FRAMES flag");
+        }
+
+        if (!changed) { // optimization for the case where mapping = identity
+            mv.visitFrame(type, nLocal, local, nStack, stack);
+            return;
+        }
+
+        // creates a copy of newLocals
+        Object[] oldLocals = new Object[newLocals.length];
+        System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
+
+        updateNewLocals(newLocals);
+
+        // copies types from 'local' to 'newLocals'
+        // 'newLocals' already contains the variables added with 'newLocal'
+
+        int index = 0; // old local variable index
+        int number = 0; // old local variable number
+        for (; number < nLocal; ++number) {
+            Object t = local[number];
+            int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
+            if (t != Opcodes.TOP) {
+                Type typ = OBJECT_TYPE;
+                if (t == Opcodes.INTEGER) {
+                    typ = Type.INT_TYPE;
+                } else if (t == Opcodes.FLOAT) {
+                    typ = Type.FLOAT_TYPE;
+                } else if (t == Opcodes.LONG) {
+                    typ = Type.LONG_TYPE;
+                } else if (t == Opcodes.DOUBLE) {
+                    typ = Type.DOUBLE_TYPE;
+                } else if (t instanceof String) {
+                    typ = Type.getObjectType((String) t);
+                }
+                setFrameLocal(remap(index, typ), t);
+            }
+            index += size;
+        }
+
+        // removes TOP after long and double types as well as trailing TOPs
+
+        index = 0;
+        number = 0;
+        for (int i = 0; index < newLocals.length; ++i) {
+            Object t = newLocals[index++];
+            if (t != null && t != Opcodes.TOP) {
+                newLocals[i] = t;
+                number = i + 1;
+                if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
+                    index += 1;
+                }
+            } else {
+                newLocals[i] = Opcodes.TOP;
+            }
+        }
+
+        // visits remapped frame
+        mv.visitFrame(type, number, newLocals, nStack, stack);
+
+        // restores original value of 'newLocals'
+        newLocals = oldLocals;
+    }
+
+    // -------------
+
+    /**
+     * Creates a new local variable of the given type.
+     * 
+     * @param type
+     *            the type of the local variable to be created.
+     * @return the identifier of the newly created local variable.
+     */
+    public int newLocal(final Type type) {
+        Object t;
+        switch (type.getSort()) {
+        case Type.BOOLEAN:
+        case Type.CHAR:
+        case Type.BYTE:
+        case Type.SHORT:
+        case Type.INT:
+            t = Opcodes.INTEGER;
+            break;
+        case Type.FLOAT:
+            t = Opcodes.FLOAT;
+            break;
+        case Type.LONG:
+            t = Opcodes.LONG;
+            break;
+        case Type.DOUBLE:
+            t = Opcodes.DOUBLE;
+            break;
+        case Type.ARRAY:
+            t = type.getDescriptor();
+            break;
+        // case Type.OBJECT:
+        default:
+            t = type.getInternalName();
+            break;
+        }
+        int local = newLocalMapping(type);
+        setLocalType(local, type);
+        setFrameLocal(local, t);
+        changed = true;
+        return local;
+    }
+
+    /**
+     * Notifies subclasses that a new stack map frame is being visited. The
+     * array argument contains the stack map frame types corresponding to the
+     * local variables added with {@link #newLocal}. This method can update
+     * these types in place for the stack map frame being visited. The default
+     * implementation of this method does nothing, i.e. a local variable added
+     * with {@link #newLocal} will have the same type in all stack map frames.
+     * But this behavior is not always the desired one, for instance if a local
+     * variable is added in the middle of a try/catch block: the frame for the
+     * exception handler should have a TOP type for this new local.
+     * 
+     * @param newLocals
+     *            the stack map frame types corresponding to the local variables
+     *            added with {@link #newLocal} (and null for the others). The
+     *            format of this array is the same as in
+     *            {@link MethodVisitor#visitFrame}, except that long and double
+     *            types use two slots. The types for the current stack map frame
+     *            must be updated in place in this array.
+     */
+    protected void updateNewLocals(Object[] newLocals) {
+    }
+
+    /**
+     * Notifies subclasses that a local variable has been added or remapped. The
+     * default implementation of this method does nothing.
+     * 
+     * @param local
+     *            a local variable identifier, as returned by {@link #newLocal
+     *            newLocal()}.
+     * @param type
+     *            the type of the value being stored in the local variable.
+     */
+    protected void setLocalType(final int local, final Type type) {
+    }
+
+    private void setFrameLocal(final int local, final Object type) {
+        int l = newLocals.length;
+        if (local >= l) {
+            Object[] a = new Object[Math.max(2 * l, local + 1)];
+            System.arraycopy(newLocals, 0, a, 0, l);
+            newLocals = a;
+        }
+        newLocals[local] = type;
+    }
+
+    private int remap(final int var, final Type type) {
+        if (var + type.getSize() <= firstLocal) {
+            return var;
+        }
+        int key = 2 * var + type.getSize() - 1;
+        int size = mapping.length;
+        if (key >= size) {
+            int[] newMapping = new int[Math.max(2 * size, key + 1)];
+            System.arraycopy(mapping, 0, newMapping, 0, size);
+            mapping = newMapping;
+        }
+        int value = mapping[key];
+        if (value == 0) {
+            value = newLocalMapping(type);
+            setLocalType(value, type);
+            mapping[key] = value + 1;
+        } else {
+            value--;
+        }
+        if (value != var) {
+            changed = true;
+        }
+        return value;
+    }
+
+    protected int newLocalMapping(final Type type) {
+        int local = nextLocal;
+        nextLocal += type.getSize();
+        return local;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Method.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Method.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Method.java
new file mode 100644
index 0000000..b9bc7c7
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Method.java
@@ -0,0 +1,282 @@
+/***
+ * 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.commons;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tajo.org.objectweb.asm.Type;
+
+/**
+ * A named method descriptor.
+ * 
+ * @author Juozas Baliuka
+ * @author Chris Nokleberg
+ * @author Eric Bruneton
+ */
+public class Method {
+
+    /**
+     * The method name.
+     */
+    private final String name;
+
+    /**
+     * The method descriptor.
+     */
+    private final String desc;
+
+    /**
+     * Maps primitive Java type names to their descriptors.
+     */
+    private static final Map<String, String> DESCRIPTORS;
+
+    static {
+        DESCRIPTORS = new HashMap<String, String>();
+        DESCRIPTORS.put("void", "V");
+        DESCRIPTORS.put("byte", "B");
+        DESCRIPTORS.put("char", "C");
+        DESCRIPTORS.put("double", "D");
+        DESCRIPTORS.put("float", "F");
+        DESCRIPTORS.put("int", "I");
+        DESCRIPTORS.put("long", "J");
+        DESCRIPTORS.put("short", "S");
+        DESCRIPTORS.put("boolean", "Z");
+    }
+
+    /**
+     * Creates a new {@link Method}.
+     * 
+     * @param name
+     *            the method's name.
+     * @param desc
+     *            the method's descriptor.
+     */
+    public Method(final String name, final String desc) {
+        this.name = name;
+        this.desc = desc;
+    }
+
+    /**
+     * Creates a new {@link Method}.
+     * 
+     * @param name
+     *            the method's name.
+     * @param returnType
+     *            the method's return type.
+     * @param argumentTypes
+     *            the method's argument types.
+     */
+    public Method(final String name, final Type returnType,
+            final Type[] argumentTypes) {
+        this(name, Type.getMethodDescriptor(returnType, argumentTypes));
+    }
+
+    /**
+     * Creates a new {@link Method}.
+     * 
+     * @param m
+     *            a java.lang.reflect method descriptor
+     * @return a {@link Method} corresponding to the given Java method
+     *         declaration.
+     */
+    public static Method getMethod(java.lang.reflect.Method m) {
+        return new Method(m.getName(), Type.getMethodDescriptor(m));
+    }
+
+    /**
+     * Creates a new {@link Method}.
+     * 
+     * @param c
+     *            a java.lang.reflect constructor descriptor
+     * @return a {@link Method} corresponding to the given Java constructor
+     *         declaration.
+     */
+    public static Method getMethod(java.lang.reflect.Constructor<?> c) {
+        return new Method("<init>", Type.getConstructorDescriptor(c));
+    }
+
+    /**
+     * Returns a {@link Method} corresponding to the given Java method
+     * declaration.
+     * 
+     * @param method
+     *            a Java method declaration, without argument names, of the form
+     *            "returnType name (argumentType1, ... argumentTypeN)", where
+     *            the types are in plain Java (e.g. "int", "float",
+     *            "java.util.List", ...). Classes of the java.lang package can
+     *            be specified by their unqualified name; all other classes
+     *            names must be fully qualified.
+     * @return a {@link Method} corresponding to the given Java method
+     *         declaration.
+     * @throws IllegalArgumentException
+     *             if <code>method</code> could not get parsed.
+     */
+    public static Method getMethod(final String method)
+            throws IllegalArgumentException {
+        return getMethod(method, false);
+    }
+
+    /**
+     * Returns a {@link Method} corresponding to the given Java method
+     * declaration.
+     * 
+     * @param method
+     *            a Java method declaration, without argument names, of the form
+     *            "returnType name (argumentType1, ... argumentTypeN)", where
+     *            the types are in plain Java (e.g. "int", "float",
+     *            "java.util.List", ...). Classes of the java.lang package may
+     *            be specified by their unqualified name, depending on the
+     *            defaultPackage argument; all other classes names must be fully
+     *            qualified.
+     * @param defaultPackage
+     *            true if unqualified class names belong to the default package,
+     *            or false if they correspond to java.lang classes. For instance
+     *            "Object" means "Object" if this option is true, or
+     *            "java.lang.Object" otherwise.
+     * @return a {@link Method} corresponding to the given Java method
+     *         declaration.
+     * @throws IllegalArgumentException
+     *             if <code>method</code> could not get parsed.
+     */
+    public static Method getMethod(final String method,
+            final boolean defaultPackage) throws IllegalArgumentException {
+        int space = method.indexOf(' ');
+        int start = method.indexOf('(', space) + 1;
+        int end = method.indexOf(')', start);
+        if (space == -1 || start == -1 || end == -1) {
+            throw new IllegalArgumentException();
+        }
+        String returnType = method.substring(0, space);
+        String methodName = method.substring(space + 1, start - 1).trim();
+        StringBuffer sb = new StringBuffer();
+        sb.append('(');
+        int p;
+        do {
+            String s;
+            p = method.indexOf(',', start);
+            if (p == -1) {
+                s = map(method.substring(start, end).trim(), defaultPackage);
+            } else {
+                s = map(method.substring(start, p).trim(), defaultPackage);
+                start = p + 1;
+            }
+            sb.append(s);
+        } while (p != -1);
+        sb.append(')');
+        sb.append(map(returnType, defaultPackage));
+        return new Method(methodName, sb.toString());
+    }
+
+    private static String map(final String type, final boolean defaultPackage) {
+        if ("".equals(type)) {
+            return type;
+        }
+
+        StringBuffer sb = new StringBuffer();
+        int index = 0;
+        while ((index = type.indexOf("[]", index) + 1) > 0) {
+            sb.append('[');
+        }
+
+        String t = type.substring(0, type.length() - sb.length() * 2);
+        String desc = DESCRIPTORS.get(t);
+        if (desc != null) {
+            sb.append(desc);
+        } else {
+            sb.append('L');
+            if (t.indexOf('.') < 0) {
+                if (!defaultPackage) {
+                    sb.append("java/lang/");
+                }
+                sb.append(t);
+            } else {
+                sb.append(t.replace('.', '/'));
+            }
+            sb.append(';');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns the name of the method described by this object.
+     * 
+     * @return the name of the method described by this object.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the descriptor of the method described by this object.
+     * 
+     * @return the descriptor of the method described by this object.
+     */
+    public String getDescriptor() {
+        return desc;
+    }
+
+    /**
+     * Returns the return type of the method described by this object.
+     * 
+     * @return the return type of the method described by this object.
+     */
+    public Type getReturnType() {
+        return Type.getReturnType(desc);
+    }
+
+    /**
+     * Returns the argument types of the method described by this object.
+     * 
+     * @return the argument types of the method described by this object.
+     */
+    public Type[] getArgumentTypes() {
+        return Type.getArgumentTypes(desc);
+    }
+
+    @Override
+    public String toString() {
+        return name + desc;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (!(o instanceof Method)) {
+            return false;
+        }
+        Method other = (Method) o;
+        return name.equals(other.name) && desc.equals(other.desc);
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode() ^ desc.hashCode();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Remapper.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Remapper.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Remapper.java
new file mode 100644
index 0000000..3d02a3a
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/Remapper.java
@@ -0,0 +1,223 @@
+/***
+ * 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.commons;
+
+import org.apache.tajo.org.objectweb.asm.Type;
+import org.apache.tajo.org.objectweb.asm.signature.SignatureReader;
+import org.apache.tajo.org.objectweb.asm.signature.SignatureVisitor;
+import org.apache.tajo.org.objectweb.asm.signature.SignatureWriter;
+import org.apache.tajo.org.objectweb.asm.Handle;
+
+/**
+ * A class responsible for remapping types and names. Subclasses can override
+ * the following methods:
+ * 
+ * <ul>
+ * <li>{@link #map(String)} - map type</li>
+ * <li>{@link #mapFieldName(String, String, String)} - map field name</li>
+ * <li>{@link #mapMethodName(String, String, String)} - map method name</li>
+ * </ul>
+ * 
+ * @author Eugene Kuleshov
+ */
+public abstract class Remapper {
+
+    public String mapDesc(String desc) {
+        Type t = Type.getType(desc);
+        switch (t.getSort()) {
+        case Type.ARRAY:
+            String s = mapDesc(t.getElementType().getDescriptor());
+            for (int i = 0; i < t.getDimensions(); ++i) {
+                s = '[' + s;
+            }
+            return s;
+        case Type.OBJECT:
+            String newType = map(t.getInternalName());
+            if (newType != null) {
+                return 'L' + newType + ';';
+            }
+        }
+        return desc;
+    }
+
+    private Type mapType(Type t) {
+        switch (t.getSort()) {
+        case Type.ARRAY:
+            String s = mapDesc(t.getElementType().getDescriptor());
+            for (int i = 0; i < t.getDimensions(); ++i) {
+                s = '[' + s;
+            }
+            return Type.getType(s);
+        case Type.OBJECT:
+            s = map(t.getInternalName());
+            return s != null ? Type.getObjectType(s) : t;
+        case Type.METHOD:
+            return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
+        }
+        return t;
+    }
+
+    public String mapType(String type) {
+        if (type == null) {
+            return null;
+        }
+        return mapType(Type.getObjectType(type)).getInternalName();
+    }
+
+    public String[] mapTypes(String[] types) {
+        String[] newTypes = null;
+        boolean needMapping = false;
+        for (int i = 0; i < types.length; i++) {
+            String type = types[i];
+            String newType = map(type);
+            if (newType != null && newTypes == null) {
+                newTypes = new String[types.length];
+                if (i > 0) {
+                    System.arraycopy(types, 0, newTypes, 0, i);
+                }
+                needMapping = true;
+            }
+            if (needMapping) {
+                newTypes[i] = newType == null ? type : newType;
+            }
+        }
+        return needMapping ? newTypes : types;
+    }
+
+    public String mapMethodDesc(String desc) {
+        if ("()V".equals(desc)) {
+            return desc;
+        }
+
+        Type[] args = Type.getArgumentTypes(desc);
+        StringBuffer s = new StringBuffer("(");
+        for (int i = 0; i < args.length; i++) {
+            s.append(mapDesc(args[i].getDescriptor()));
+        }
+        Type returnType = Type.getReturnType(desc);
+        if (returnType == Type.VOID_TYPE) {
+            s.append(")V");
+            return s.toString();
+        }
+        s.append(')').append(mapDesc(returnType.getDescriptor()));
+        return s.toString();
+    }
+
+    public Object mapValue(Object value) {
+        if (value instanceof Type) {
+            return mapType((Type) value);
+        }
+        if (value instanceof Handle) {
+            Handle h = (Handle) value;
+            return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName(
+                    h.getOwner(), h.getName(), h.getDesc()),
+                    mapMethodDesc(h.getDesc()));
+        }
+        return value;
+    }
+
+    /**
+     * 
+     * @param typeSignature
+     *            true if signature is a FieldTypeSignature, such as the
+     *            signature parameter of the ClassVisitor.visitField or
+     *            MethodVisitor.visitLocalVariable methods
+     */
+    public String mapSignature(String signature, boolean typeSignature) {
+        if (signature == null) {
+            return null;
+        }
+        SignatureReader r = new SignatureReader(signature);
+        SignatureWriter w = new SignatureWriter();
+        SignatureVisitor a = createRemappingSignatureAdapter(w);
+        if (typeSignature) {
+            r.acceptType(a);
+        } else {
+            r.accept(a);
+        }
+        return w.toString();
+    }
+
+    protected SignatureVisitor createRemappingSignatureAdapter(
+            SignatureVisitor v) {
+        return new RemappingSignatureAdapter(v, this);
+    }
+
+    /**
+     * Map method name to the new name. Subclasses can override.
+     * 
+     * @param owner
+     *            owner of the method.
+     * @param name
+     *            name of the method.
+     * @param desc
+     *            descriptor of the method.
+     * @return new name of the method
+     */
+    public String mapMethodName(String owner, String name, String desc) {
+        return name;
+    }
+
+    /**
+     * Map invokedynamic method name to the new name. Subclasses can override.
+     * 
+     * @param name
+     *            name of the invokedynamic.
+     * @param desc
+     *            descriptor of the invokedynamic.
+     * @return new invokdynamic name.
+     */
+    public String mapInvokeDynamicMethodName(String name, String desc) {
+        return name;
+    }
+
+    /**
+     * Map field name to the new name. Subclasses can override.
+     * 
+     * @param owner
+     *            owner of the field.
+     * @param name
+     *            name of the field
+     * @param desc
+     *            descriptor of the field
+     * @return new name of the field.
+     */
+    public String mapFieldName(String owner, String name, String desc) {
+        return name;
+    }
+
+    /**
+     * Map type name to the new name. Subclasses can override.
+     */
+    public String map(String typeName) {
+        return typeName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingAnnotationAdapter.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingAnnotationAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingAnnotationAdapter.java
new file mode 100644
index 0000000..1909ec2
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingAnnotationAdapter.java
@@ -0,0 +1,79 @@
+/***
+ * 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.commons;
+
+import org.apache.tajo.org.objectweb.asm.AnnotationVisitor;
+import org.apache.tajo.org.objectweb.asm.Opcodes;
+
+/**
+ * An {@link org.apache.tajo.org.objectweb.asm.AnnotationVisitor} adapter for type remapping.
+ * 
+ * @author Eugene Kuleshov
+ */
+public class RemappingAnnotationAdapter extends AnnotationVisitor {
+
+    protected final Remapper remapper;
+
+    public RemappingAnnotationAdapter(final AnnotationVisitor av,
+            final Remapper remapper) {
+        this(Opcodes.ASM4, av, remapper);
+    }
+
+    protected RemappingAnnotationAdapter(final int api,
+            final AnnotationVisitor av, final Remapper remapper) {
+        super(api, av);
+        this.remapper = remapper;
+    }
+
+    @Override
+    public void visit(String name, Object value) {
+        av.visit(name, remapper.mapValue(value));
+    }
+
+    @Override
+    public void visitEnum(String name, String desc, String value) {
+        av.visitEnum(name, remapper.mapDesc(desc), value);
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String name, String desc) {
+        AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
+        return v == null ? null : (v == av ? this
+                : new RemappingAnnotationAdapter(v, remapper));
+    }
+
+    @Override
+    public AnnotationVisitor visitArray(String name) {
+        AnnotationVisitor v = av.visitArray(name);
+        return v == null ? null : (v == av ? this
+                : new RemappingAnnotationAdapter(v, remapper));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingClassAdapter.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingClassAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingClassAdapter.java
new file mode 100644
index 0000000..fd35841
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingClassAdapter.java
@@ -0,0 +1,126 @@
+/***
+ * 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.commons;
+
+import org.apache.tajo.org.objectweb.asm.AnnotationVisitor;
+import org.apache.tajo.org.objectweb.asm.ClassVisitor;
+import org.apache.tajo.org.objectweb.asm.FieldVisitor;
+import org.apache.tajo.org.objectweb.asm.MethodVisitor;
+import org.apache.tajo.org.objectweb.asm.Opcodes;
+
+/**
+ * A {@link org.apache.tajo.org.objectweb.asm.ClassVisitor} for type remapping.
+ * 
+ * @author Eugene Kuleshov
+ */
+public class RemappingClassAdapter extends ClassVisitor {
+
+    protected final Remapper remapper;
+
+    protected String className;
+
+    public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
+        this(Opcodes.ASM4, cv, remapper);
+    }
+
+    protected RemappingClassAdapter(final int api, final ClassVisitor cv,
+            final Remapper remapper) {
+        super(api, cv);
+        this.remapper = remapper;
+    }
+
+    @Override
+    public void visit(int version, int access, String name, String signature,
+            String superName, String[] interfaces) {
+        this.className = name;
+        super.visit(version, access, remapper.mapType(name), remapper
+                .mapSignature(signature, false), remapper.mapType(superName),
+                interfaces == null ? null : remapper.mapTypes(interfaces));
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        AnnotationVisitor av;
+        av = super.visitAnnotation(remapper.mapDesc(desc), visible);
+        return av == null ? null : createRemappingAnnotationAdapter(av);
+    }
+
+    @Override
+    public FieldVisitor visitField(int access, String name, String desc,
+            String signature, Object value) {
+        FieldVisitor fv = super.visitField(access,
+                remapper.mapFieldName(className, name, desc),
+                remapper.mapDesc(desc), remapper.mapSignature(signature, true),
+                remapper.mapValue(value));
+        return fv == null ? null : createRemappingFieldAdapter(fv);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc,
+            String signature, String[] exceptions) {
+        String newDesc = remapper.mapMethodDesc(desc);
+        MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
+                className, name, desc), newDesc, remapper.mapSignature(
+                signature, false),
+                exceptions == null ? null : remapper.mapTypes(exceptions));
+        return mv == null ? null : createRemappingMethodAdapter(access,
+                newDesc, mv);
+    }
+
+    @Override
+    public void visitInnerClass(String name, String outerName,
+            String innerName, int access) {
+        // TODO should innerName be changed?
+        super.visitInnerClass(remapper.mapType(name), outerName == null ? null
+                : remapper.mapType(outerName), innerName, access);
+    }
+
+    @Override
+    public void visitOuterClass(String owner, String name, String desc) {
+        super.visitOuterClass(remapper.mapType(owner), name == null ? null
+                : remapper.mapMethodName(owner, name, desc),
+                desc == null ? null : remapper.mapMethodDesc(desc));
+    }
+
+    protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
+        return new RemappingFieldAdapter(fv, remapper);
+    }
+
+    protected MethodVisitor createRemappingMethodAdapter(int access,
+            String newDesc, MethodVisitor mv) {
+        return new RemappingMethodAdapter(access, newDesc, mv, remapper);
+    }
+
+    protected AnnotationVisitor createRemappingAnnotationAdapter(
+            AnnotationVisitor av) {
+        return new RemappingAnnotationAdapter(av, remapper);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingFieldAdapter.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingFieldAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingFieldAdapter.java
new file mode 100644
index 0000000..72744f9
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingFieldAdapter.java
@@ -0,0 +1,62 @@
+/***
+ * 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.commons;
+
+import org.apache.tajo.org.objectweb.asm.AnnotationVisitor;
+import org.apache.tajo.org.objectweb.asm.FieldVisitor;
+import org.apache.tajo.org.objectweb.asm.Opcodes;
+
+/**
+ * A {@link FieldVisitor} adapter for type remapping.
+ * 
+ * @author Eugene Kuleshov
+ */
+public class RemappingFieldAdapter extends FieldVisitor {
+
+    private final Remapper remapper;
+
+    public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
+        this(Opcodes.ASM4, fv, remapper);
+    }
+
+    protected RemappingFieldAdapter(final int api, final FieldVisitor fv,
+            final Remapper remapper) {
+        super(api, fv);
+        this.remapper = remapper;
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
+                visible);
+        return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
+    }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/7603a3d4/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingMethodAdapter.java
----------------------------------------------------------------------
diff --git a/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingMethodAdapter.java b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingMethodAdapter.java
new file mode 100644
index 0000000..357a44b
--- /dev/null
+++ b/tajo-thirdparty/asm/src/main/java/org/apache/tajo/org/objectweb/asm/commons/RemappingMethodAdapter.java
@@ -0,0 +1,161 @@
+/***
+ * 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.commons;
+
+import org.apache.tajo.org.objectweb.asm.AnnotationVisitor;
+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;
+
+/**
+ * A {@link LocalVariablesSorter} for type mapping.
+ * 
+ * @author Eugene Kuleshov
+ */
+public class RemappingMethodAdapter extends LocalVariablesSorter {
+
+    protected final Remapper remapper;
+
+    public RemappingMethodAdapter(final int access, final String desc,
+            final MethodVisitor mv, final Remapper remapper) {
+        this(Opcodes.ASM4, access, desc, mv, remapper);
+    }
+
+    protected RemappingMethodAdapter(final int api, final int access,
+            final String desc, final MethodVisitor mv, final Remapper remapper) {
+        super(api, access, desc, mv);
+        this.remapper = remapper;
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotationDefault() {
+        AnnotationVisitor av = mv.visitAnnotationDefault();
+        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
+    }
+
+    @Override
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        AnnotationVisitor av = mv.visitAnnotation(remapper.mapDesc(desc),
+                visible);
+        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
+    }
+
+    @Override
+    public AnnotationVisitor visitParameterAnnotation(int parameter,
+            String desc, boolean visible) {
+        AnnotationVisitor av = mv.visitParameterAnnotation(parameter,
+                remapper.mapDesc(desc), visible);
+        return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
+    }
+
+    @Override
+    public void visitFrame(int type, int nLocal, Object[] local, int nStack,
+            Object[] stack) {
+        super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
+                remapEntries(nStack, stack));
+    }
+
+    private Object[] remapEntries(int n, Object[] entries) {
+        for (int i = 0; i < n; i++) {
+            if (entries[i] instanceof String) {
+                Object[] newEntries = new Object[n];
+                if (i > 0) {
+                    System.arraycopy(entries, 0, newEntries, 0, i);
+                }
+                do {
+                    Object t = entries[i];
+                    newEntries[i++] = t instanceof String ? remapper
+                            .mapType((String) t) : t;
+                } while (i < n);
+                return newEntries;
+            }
+        }
+        return entries;
+    }
+
+    @Override
+    public void visitFieldInsn(int opcode, String owner, String name,
+            String desc) {
+        super.visitFieldInsn(opcode, remapper.mapType(owner),
+                remapper.mapFieldName(owner, name, desc),
+                remapper.mapDesc(desc));
+    }
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name,
+            String desc) {
+        super.visitMethodInsn(opcode, remapper.mapType(owner),
+                remapper.mapMethodName(owner, name, desc),
+                remapper.mapMethodDesc(desc));
+    }
+
+    @Override
+    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
+            Object... bsmArgs) {
+        for (int i = 0; i < bsmArgs.length; i++) {
+            bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
+        }
+        super.visitInvokeDynamicInsn(
+                remapper.mapInvokeDynamicMethodName(name, desc),
+                remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
+                bsmArgs);
+    }
+
+    @Override
+    public void visitTypeInsn(int opcode, String type) {
+        super.visitTypeInsn(opcode, remapper.mapType(type));
+    }
+
+    @Override
+    public void visitLdcInsn(Object cst) {
+        super.visitLdcInsn(remapper.mapValue(cst));
+    }
+
+    @Override
+    public void visitMultiANewArrayInsn(String desc, int dims) {
+        super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
+    }
+
+    @Override
+    public void visitTryCatchBlock(Label start, Label end, Label handler,
+            String type) {
+        super.visitTryCatchBlock(start, end, handler, type == null ? null
+                : remapper.mapType(type));
+    }
+
+    @Override
+    public void visitLocalVariable(String name, String desc, String signature,
+            Label start, Label end, int index) {
+        super.visitLocalVariable(name, remapper.mapDesc(desc),
+                remapper.mapSignature(signature, true), start, end, index);
+    }
+}