001/***
002 * ASM: a very small and fast Java bytecode manipulation framework
003 * Copyright (c) 2000-2011 INRIA, France Telecom
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 * 1. Redistributions of source code must retain the above copyright
010 *    notice, this list of conditions and the following disclaimer.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 *    notice, this list of conditions and the following disclaimer in the
013 *    documentation and/or other materials provided with the distribution.
014 * 3. Neither the name of the copyright holders nor the names of its
015 *    contributors may be used to endorse or promote products derived from
016 *    this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028 * THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package io.ebean.enhance.asm.commons;
031
032import io.ebean.enhance.asm.Label;
033import io.ebean.enhance.asm.MethodVisitor;
034import io.ebean.enhance.asm.Opcodes;
035import io.ebean.enhance.asm.Type;
036import io.ebean.enhance.asm.tree.AbstractInsnNode;
037import io.ebean.enhance.asm.tree.InsnList;
038import io.ebean.enhance.asm.tree.InsnNode;
039import io.ebean.enhance.asm.tree.JumpInsnNode;
040import io.ebean.enhance.asm.tree.LabelNode;
041import io.ebean.enhance.asm.tree.LocalVariableNode;
042import io.ebean.enhance.asm.tree.LookupSwitchInsnNode;
043import io.ebean.enhance.asm.tree.MethodNode;
044import io.ebean.enhance.asm.tree.TableSwitchInsnNode;
045import io.ebean.enhance.asm.tree.TryCatchBlockNode;
046
047import java.util.AbstractMap;
048import java.util.ArrayList;
049import java.util.BitSet;
050import java.util.HashMap;
051import java.util.Iterator;
052import java.util.LinkedList;
053import java.util.List;
054import java.util.Map;
055import java.util.Set;
056
057/**
058 * A {@link MethodVisitor} that removes JSR instructions and
059 * inlines the referenced subroutines.
060 * 
061 * <b>Explanation of how it works</b> TODO
062 * 
063 * @author Niko Matsakis
064 */
065public class JSRInlinerAdapter extends MethodNode implements Opcodes {
066
067    private static final boolean LOGGING = false;
068
069    /**
070     * For each label that is jumped to by a JSR, we create a BitSet instance.
071     */
072    private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
073
074    /**
075     * This subroutine instance denotes the line of execution that is not
076     * contained within any subroutine; i.e., the "subroutine" that is executing
077     * when a method first begins.
078     */
079    private final BitSet mainSubroutine = new BitSet();
080
081    /**
082     * This BitSet contains the index of every instruction that belongs to more
083     * than one subroutine. This should not happen often.
084     */
085    final BitSet dualCitizens = new BitSet();
086
087    /**
088     * Creates a new JSRInliner. <i>Subclasses must not use this
089     * constructor</i>. Instead, they must use the
090     * {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String, String, String[])}
091     * version.
092     * 
093     * @param mv
094     *            the <code>MethodVisitor</code> to send the resulting inlined
095     *            method code to (use <code>null</code> for none).
096     * @param access
097     *            the method's access flags (see {@link Opcodes}). This
098     *            parameter also indicates if the method is synthetic and/or
099     *            deprecated.
100     * @param name
101     *            the method's name.
102     * @param desc
103     *            the method's descriptor (see {@link Type}).
104     * @param signature
105     *            the method's signature. May be <tt>null</tt>.
106     * @param exceptions
107     *            the internal names of the method's exception classes (see
108     *            {@link Type#getInternalName() getInternalName}). May be
109     *            <tt>null</tt>.
110     * @throws IllegalStateException
111     *             If a subclass calls this constructor.
112     */
113    public JSRInlinerAdapter(final MethodVisitor mv, final int access,
114                             final String name, final String desc, final String signature,
115                             final String[] exceptions) {
116        this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
117        if (getClass() != JSRInlinerAdapter.class) {
118            throw new IllegalStateException();
119        }
120    }
121
122    /**
123     * Creates a new JSRInliner.
124     * 
125     * @param api
126     *            the ASM API version implemented by this visitor. Must be one
127     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
128     * @param mv
129     *            the <code>MethodVisitor</code> to send the resulting inlined
130     *            method code to (use <code>null</code> for none).
131     * @param access
132     *            the method's access flags (see {@link Opcodes}). This
133     *            parameter also indicates if the method is synthetic and/or
134     *            deprecated.
135     * @param name
136     *            the method's name.
137     * @param desc
138     *            the method's descriptor (see {@link Type}).
139     * @param signature
140     *            the method's signature. May be <tt>null</tt>.
141     * @param exceptions
142     *            the internal names of the method's exception classes (see
143     *            {@link Type#getInternalName() getInternalName}). May be
144     *            <tt>null</tt>.
145     */
146    protected JSRInlinerAdapter(final int api, final MethodVisitor mv,
147            final int access, final String name, final String desc,
148            final String signature, final String[] exceptions) {
149        super(api, access, name, desc, signature, exceptions);
150        this.mv = mv;
151    }
152
153    /**
154     * Detects a JSR instruction and sets a flag to indicate we will need to do
155     * inlining.
156     */
157    @Override
158    public void visitJumpInsn(final int opcode, final Label lbl) {
159        super.visitJumpInsn(opcode, lbl);
160        LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
161        if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
162            subroutineHeads.put(ln, new BitSet());
163        }
164    }
165
166    /**
167     * If any JSRs were seen, triggers the inlining process. Otherwise, forwards
168     * the byte codes untouched.
169     */
170    @Override
171    public void visitEnd() {
172        if (!subroutineHeads.isEmpty()) {
173            markSubroutines();
174            if (LOGGING) {
175                log(mainSubroutine.toString());
176                Iterator<BitSet> it = subroutineHeads.values().iterator();
177                while (it.hasNext()) {
178                    BitSet sub = it.next();
179                    log(sub.toString());
180                }
181            }
182            emitCode();
183        }
184
185        // Forward the translate opcodes on if appropriate:
186        if (mv != null) {
187            accept(mv);
188        }
189    }
190
191    /**
192     * Walks the method and determines which internal subroutine(s), if any,
193     * each instruction is a method of.
194     */
195    private void markSubroutines() {
196        BitSet anyvisited = new BitSet();
197
198        // First walk the main subroutine and find all those instructions which
199        // can be reached without invoking any JSR at all
200        markSubroutineWalk(mainSubroutine, 0, anyvisited);
201
202        // Go through the head of each subroutine and find any nodes reachable
203        // to that subroutine without following any JSR links.
204        for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads
205                .entrySet().iterator(); it.hasNext();) {
206            Map.Entry<LabelNode, BitSet> entry = it.next();
207            LabelNode lab = entry.getKey();
208            BitSet sub = entry.getValue();
209            int index = instructions.indexOf(lab);
210            markSubroutineWalk(sub, index, anyvisited);
211        }
212    }
213
214    /**
215     * Performs a depth first search walking the normal byte code path starting
216     * at <code>index</code>, and adding each instruction encountered into the
217     * subroutine <code>sub</code>. After this walk is complete, iterates over
218     * the exception handlers to ensure that we also include those byte codes
219     * which are reachable through an exception that may be thrown during the
220     * execution of the subroutine. Invoked from <code>markSubroutines()</code>.
221     * 
222     * @param sub
223     *            the subroutine whose instructions must be computed.
224     * @param index
225     *            an instruction of this subroutine.
226     * @param anyvisited
227     *            indexes of the already visited instructions, i.e. marked as
228     *            part of this subroutine or any previously computed subroutine.
229     */
230    private void markSubroutineWalk(final BitSet sub, final int index,
231            final BitSet anyvisited) {
232        if (LOGGING) {
233            log("markSubroutineWalk: sub=" + sub + " index=" + index);
234        }
235
236        // First find those instructions reachable via normal execution
237        markSubroutineWalkDFS(sub, index, anyvisited);
238
239        // Now, make sure we also include any applicable exception handlers
240        boolean loop = true;
241        while (loop) {
242            loop = false;
243            for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
244                    .hasNext();) {
245                TryCatchBlockNode trycatch = it.next();
246
247                if (LOGGING) {
248                    // TODO use of default toString().
249                    log("Scanning try/catch " + trycatch);
250                }
251
252                // If the handler has already been processed, skip it.
253                int handlerindex = instructions.indexOf(trycatch.handler);
254                if (sub.get(handlerindex)) {
255                    continue;
256                }
257
258                int startindex = instructions.indexOf(trycatch.start);
259                int endindex = instructions.indexOf(trycatch.end);
260                int nextbit = sub.nextSetBit(startindex);
261                if (nextbit != -1 && nextbit < endindex) {
262                    if (LOGGING) {
263                        log("Adding exception handler: " + startindex + '-'
264                                + endindex + " due to " + nextbit + " handler "
265                                + handlerindex);
266                    }
267                    markSubroutineWalkDFS(sub, handlerindex, anyvisited);
268                    loop = true;
269                }
270            }
271        }
272    }
273
274    /**
275     * Performs a simple DFS of the instructions, assigning each to the
276     * subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
277     * by <code>markSubroutineWalk()</code>.
278     * 
279     * @param sub
280     *            the subroutine whose instructions must be computed.
281     * @param index
282     *            an instruction of this subroutine.
283     * @param anyvisited
284     *            indexes of the already visited instructions, i.e. marked as
285     *            part of this subroutine or any previously computed subroutine.
286     */
287    private void markSubroutineWalkDFS(final BitSet sub, int index,
288            final BitSet anyvisited) {
289        while (true) {
290            AbstractInsnNode node = instructions.get(index);
291
292            // don't visit a node twice
293            if (sub.get(index)) {
294                return;
295            }
296            sub.set(index);
297
298            // check for those nodes already visited by another subroutine
299            if (anyvisited.get(index)) {
300                dualCitizens.set(index);
301                if (LOGGING) {
302                    log("Instruction #" + index + " is dual citizen.");
303                }
304            }
305            anyvisited.set(index);
306
307            if (node.getType() == AbstractInsnNode.JUMP_INSN
308                    && node.getOpcode() != JSR) {
309                // we do not follow recursively called subroutines here; but any
310                // other sort of branch we do follow
311                JumpInsnNode jnode = (JumpInsnNode) node;
312                int destidx = instructions.indexOf(jnode.label);
313                markSubroutineWalkDFS(sub, destidx, anyvisited);
314            }
315            if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
316                TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
317                int destidx = instructions.indexOf(tsnode.dflt);
318                markSubroutineWalkDFS(sub, destidx, anyvisited);
319                for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
320                    LabelNode l = tsnode.labels.get(i);
321                    destidx = instructions.indexOf(l);
322                    markSubroutineWalkDFS(sub, destidx, anyvisited);
323                }
324            }
325            if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
326                LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
327                int destidx = instructions.indexOf(lsnode.dflt);
328                markSubroutineWalkDFS(sub, destidx, anyvisited);
329                for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
330                    LabelNode l = lsnode.labels.get(i);
331                    destidx = instructions.indexOf(l);
332                    markSubroutineWalkDFS(sub, destidx, anyvisited);
333                }
334            }
335
336            // check to see if this opcode falls through to the next instruction
337            // or not; if not, return.
338            switch (instructions.get(index).getOpcode()) {
339            case GOTO:
340            case RET:
341            case TABLESWITCH:
342            case LOOKUPSWITCH:
343            case IRETURN:
344            case LRETURN:
345            case FRETURN:
346            case DRETURN:
347            case ARETURN:
348            case RETURN:
349            case ATHROW:
350                /*
351                 * note: this either returns from this subroutine, or a parent
352                 * subroutine which invoked it
353                 */
354                return;
355            }
356
357            // Use tail recursion here in the form of an outer while loop to
358            // avoid our stack growing needlessly:
359            index++;
360
361            // We implicitly assumed above that execution can always fall
362            // through to the next instruction after a JSR. But a subroutine may
363            // never return, in which case the code after the JSR is unreachable
364            // and can be anything. In particular, it can seem to fall off the
365            // end of the method, so we must handle this case here (we could
366            // instead detect whether execution can return or not from a JSR,
367            // but this is more complicated).
368            if (index >= instructions.size()) {
369                return;
370            }
371        }
372    }
373
374    /**
375     * Creates the new instructions, inlining each instantiation of each
376     * subroutine until the code is fully elaborated.
377     */
378    private void emitCode() {
379        LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
380        // Create an instantiation of the "root" subroutine, which is just the
381        // main routine
382        worklist.add(new Instantiation(null, mainSubroutine));
383
384        // Emit instantiations of each subroutine we encounter, including the
385        // main subroutine
386        InsnList newInstructions = new InsnList();
387        List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
388        List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
389        while (!worklist.isEmpty()) {
390            Instantiation inst = worklist.removeFirst();
391            emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks,
392                    newLocalVariables);
393        }
394        instructions = newInstructions;
395        tryCatchBlocks = newTryCatchBlocks;
396        localVariables = newLocalVariables;
397    }
398
399    /**
400     * Emits one instantiation of one subroutine, specified by
401     * <code>instant</code>. May add new instantiations that are invoked by this
402     * one to the <code>worklist</code> parameter, and new try/catch blocks to
403     * <code>newTryCatchBlocks</code>.
404     * 
405     * @param instant
406     *            the instantiation that must be performed.
407     * @param worklist
408     *            list of the instantiations that remain to be done.
409     * @param newInstructions
410     *            the instruction list to which the instantiated code must be
411     *            appended.
412     * @param newTryCatchBlocks
413     *            the exception handler list to which the instantiated handlers
414     *            must be appended.
415     */
416    private void emitSubroutine(final Instantiation instant,
417            final List<Instantiation> worklist, final InsnList newInstructions,
418            final List<TryCatchBlockNode> newTryCatchBlocks,
419            final List<LocalVariableNode> newLocalVariables) {
420        LabelNode duplbl = null;
421
422        if (LOGGING) {
423            log("--------------------------------------------------------");
424            log("Emitting instantiation of subroutine " + instant.subroutine);
425        }
426
427        // Emit the relevant instructions for this instantiation, translating
428        // labels and jump targets as we go:
429        for (int i = 0, c = instructions.size(); i < c; i++) {
430            AbstractInsnNode insn = instructions.get(i);
431            Instantiation owner = instant.findOwner(i);
432
433            // Always remap labels:
434            if (insn.getType() == AbstractInsnNode.LABEL) {
435                // Translate labels into their renamed equivalents.
436                // Avoid adding the same label more than once. Note
437                // that because we own this instruction the gotoTable
438                // and the rangeTable will always agree.
439                LabelNode ilbl = (LabelNode) insn;
440                LabelNode remap = instant.rangeLabel(ilbl);
441                if (LOGGING) {
442                    // TODO use of default toString().
443                    log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
444                }
445                if (remap != duplbl) {
446                    newInstructions.add(remap);
447                    duplbl = remap;
448                }
449                continue;
450            }
451
452            // We don't want to emit instructions that were already
453            // emitted by a subroutine higher on the stack. Note that
454            // it is still possible for a given instruction to be
455            // emitted twice because it may belong to two subroutines
456            // that do not invoke each other.
457            if (owner != instant) {
458                continue;
459            }
460
461            if (LOGGING) {
462                log("Emitting inst #" + i);
463            }
464
465            if (insn.getOpcode() == RET) {
466                // Translate RET instruction(s) to a jump to the return label
467                // for the appropriate instantiation. The problem is that the
468                // subroutine may "fall through" to the ret of a parent
469                // subroutine; therefore, to find the appropriate ret label we
470                // find the lowest subroutine on the stack that claims to own
471                // this instruction. See the class javadoc comment for an
472                // explanation on why this technique is safe (note: it is only
473                // safe if the input is verifiable).
474                LabelNode retlabel = null;
475                for (Instantiation p = instant; p != null; p = p.previous) {
476                    if (p.subroutine.get(i)) {
477                        retlabel = p.returnLabel;
478                    }
479                }
480                if (retlabel == null) {
481                    // This is only possible if the mainSubroutine owns a RET
482                    // instruction, which should never happen for verifiable
483                    // code.
484                    throw new RuntimeException("Instruction #" + i
485                            + " is a RET not owned by any subroutine");
486                }
487                newInstructions.add(new JumpInsnNode(GOTO, retlabel));
488            } else if (insn.getOpcode() == JSR) {
489                LabelNode lbl = ((JumpInsnNode) insn).label;
490                BitSet sub = subroutineHeads.get(lbl);
491                Instantiation newinst = new Instantiation(instant, sub);
492                LabelNode startlbl = newinst.gotoLabel(lbl);
493
494                if (LOGGING) {
495                    log(" Creating instantiation of subr " + sub);
496                }
497
498                // Rather than JSRing, we will jump to the inline version and
499                // push NULL for what was once the return value. This hack
500                // allows us to avoid doing any sort of data flow analysis to
501                // figure out which instructions manipulate the old return value
502                // pointer which is now known to be unneeded.
503                newInstructions.add(new InsnNode(ACONST_NULL));
504                newInstructions.add(new JumpInsnNode(GOTO, startlbl));
505                newInstructions.add(newinst.returnLabel);
506
507                // Insert this new instantiation into the queue to be emitted
508                // later.
509                worklist.add(newinst);
510            } else {
511                newInstructions.add(insn.clone(instant));
512            }
513        }
514
515        // Emit try/catch blocks that are relevant to this method.
516        for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
517                .hasNext();) {
518            TryCatchBlockNode trycatch = it.next();
519
520            if (LOGGING) {
521                // TODO use of default toString().
522                log("try catch block original labels=" + trycatch.start + '-'
523                        + trycatch.end + "->" + trycatch.handler);
524            }
525
526            final LabelNode start = instant.rangeLabel(trycatch.start);
527            final LabelNode end = instant.rangeLabel(trycatch.end);
528
529            // Ignore empty try/catch regions
530            if (start == end) {
531                if (LOGGING) {
532                    log(" try catch block empty in this subroutine");
533                }
534                continue;
535            }
536
537            final LabelNode handler = instant.gotoLabel(trycatch.handler);
538
539            if (LOGGING) {
540                // TODO use of default toString().
541                log(" try catch block new labels=" + start + '-' + end + "->"
542                        + handler);
543            }
544
545            if (start == null || end == null || handler == null) {
546                throw new RuntimeException("Internal error!");
547            }
548
549            newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler,
550                    trycatch.type));
551        }
552
553        for (Iterator<LocalVariableNode> it = localVariables.iterator(); it
554                .hasNext();) {
555            LocalVariableNode lvnode = it.next();
556            if (LOGGING) {
557                log("local var " + lvnode.name);
558            }
559            final LabelNode start = instant.rangeLabel(lvnode.start);
560            final LabelNode end = instant.rangeLabel(lvnode.end);
561            if (start == end) {
562                if (LOGGING) {
563                    log("  local variable empty in this sub");
564                }
565                continue;
566            }
567            newLocalVariables.add(new LocalVariableNode(lvnode.name,
568                    lvnode.desc, lvnode.signature, start, end, lvnode.index));
569        }
570    }
571
572    private static void log(final String str) {
573        System.err.println(str);
574    }
575
576    /**
577     * A class that represents an instantiation of a subroutine. Each
578     * instantiation has an associate "stack" --- which is a listing of those
579     * instantiations that were active when this particular instance of this
580     * subroutine was invoked. Each instantiation also has a map from the
581     * original labels of the program to the labels appropriate for this
582     * instantiation, and finally a label to return to.
583     */
584    private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
585
586        /**
587         * Previous instantiations; the stack must be statically predictable to
588         * be inlinable.
589         */
590        final Instantiation previous;
591
592        /**
593         * The subroutine this is an instantiation of.
594         */
595        public final BitSet subroutine;
596
597        /**
598         * This table maps Labels from the original source to Labels pointing at
599         * code specific to this instantiation, for use in remapping try/catch
600         * blocks,as well as gotos.
601         * 
602         * Note that in the presence of dual citizens instructions, that is,
603         * instructions which belong to more than one subroutine due to the
604         * merging of control flow without a RET instruction, we will map the
605         * target label of a GOTO to the label used by the instantiation lowest
606         * on the stack. This avoids code duplication during inlining in most
607         * cases.
608         * 
609         * @see #findOwner(int)
610         */
611        public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
612
613        /**
614         * All returns for this instantiation will be mapped to this label
615         */
616        public final LabelNode returnLabel;
617
618        Instantiation(final Instantiation prev, final BitSet sub) {
619            previous = prev;
620            subroutine = sub;
621            for (Instantiation p = prev; p != null; p = p.previous) {
622                if (p.subroutine == sub) {
623                    throw new RuntimeException("Recursive invocation of " + sub);
624                }
625            }
626
627            // Determine the label to return to when this subroutine terminates
628            // via RET: note that the main subroutine never terminates via RET.
629            if (prev != null) {
630                returnLabel = new LabelNode();
631            } else {
632                returnLabel = null;
633            }
634
635            // Each instantiation will remap the labels from the code above to
636            // refer to its particular copy of its own instructions. Note that
637            // we collapse labels which point at the same instruction into one:
638            // this is fairly common as we are often ignoring large chunks of
639            // instructions, so what were previously distinct labels become
640            // duplicates.
641            LabelNode duplbl = null;
642            for (int i = 0, c = instructions.size(); i < c; i++) {
643                AbstractInsnNode insn = instructions.get(i);
644
645                if (insn.getType() == AbstractInsnNode.LABEL) {
646                    LabelNode ilbl = (LabelNode) insn;
647
648                    if (duplbl == null) {
649                        // if we already have a label pointing at this spot,
650                        // don't recreate it.
651                        duplbl = new LabelNode();
652                    }
653
654                    // Add an entry in the rangeTable for every label
655                    // in the original code which points at the next
656                    // instruction of our own to be emitted.
657                    rangeTable.put(ilbl, duplbl);
658                } else if (findOwner(i) == this) {
659                    // We will emit this instruction, so clear the 'duplbl' flag
660                    // since the next Label will refer to a distinct
661                    // instruction.
662                    duplbl = null;
663                }
664            }
665        }
666
667        /**
668         * Returns the "owner" of a particular instruction relative to this
669         * instantiation: the owner referes to the Instantiation which will emit
670         * the version of this instruction that we will execute.
671         * 
672         * Typically, the return value is either <code>this</code> or
673         * <code>null</code>. <code>this</code> indicates that this
674         * instantiation will generate the version of this instruction that we
675         * will execute, and <code>null</code> indicates that this instantiation
676         * never executes the given instruction.
677         * 
678         * Sometimes, however, an instruction can belong to multiple
679         * subroutines; this is called a "dual citizen" instruction (though it
680         * may belong to more than 2 subroutines), and occurs when multiple
681         * subroutines branch to common points of control. In this case, the
682         * owner is the subroutine that appears lowest on the stack, and which
683         * also owns the instruction in question.
684         * 
685         * @param i
686         *            the index of the instruction in the original code
687         * @return the "owner" of a particular instruction relative to this
688         *         instantiation.
689         */
690        public Instantiation findOwner(final int i) {
691            if (!subroutine.get(i)) {
692                return null;
693            }
694            if (!dualCitizens.get(i)) {
695                return this;
696            }
697            Instantiation own = this;
698            for (Instantiation p = previous; p != null; p = p.previous) {
699                if (p.subroutine.get(i)) {
700                    own = p;
701                }
702            }
703            return own;
704        }
705
706        /**
707         * Looks up the label <code>l</code> in the <code>gotoTable</code>, thus
708         * translating it from a Label in the original code, to a Label in the
709         * inlined code that is appropriate for use by an instruction that
710         * branched to the original label.
711         * 
712         * @param l
713         *            The label we will be translating
714         * @return a label for use by a branch instruction in the inlined code
715         * @see #rangeLabel
716         */
717        public LabelNode gotoLabel(final LabelNode l) {
718            // owner should never be null, because owner is only null
719            // if an instruction cannot be reached from this subroutine
720            Instantiation owner = findOwner(instructions.indexOf(l));
721            return owner.rangeTable.get(l);
722        }
723
724        /**
725         * Looks up the label <code>l</code> in the <code>rangeTable</code>,
726         * thus translating it from a Label in the original code, to a Label in
727         * the inlined code that is appropriate for use by an try/catch or
728         * variable use annotation.
729         * 
730         * @param l
731         *            The label we will be translating
732         * @return a label for use by a try/catch or variable annotation in the
733         *         original code
734         * @see #rangeTable
735         */
736        public LabelNode rangeLabel(final LabelNode l) {
737            return rangeTable.get(l);
738        }
739
740        // AbstractMap implementation
741
742        @Override
743        public Set<Entry<LabelNode, LabelNode>> entrySet() {
744            return null;
745        }
746
747        @Override
748        public LabelNode get(final Object o) {
749            return gotoLabel((LabelNode) o);
750        }
751    }
752}