KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > asm > commons > JSRInlinerAdapter


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package org.objectweb.asm.commons;
31
32 import java.util.AbstractMap JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.BitSet JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.LinkedList JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Set JavaDoc;
41
42 import org.objectweb.asm.Label;
43 import org.objectweb.asm.MethodVisitor;
44 import org.objectweb.asm.Opcodes;
45 import org.objectweb.asm.Type;
46 import org.objectweb.asm.tree.AbstractInsnNode;
47 import org.objectweb.asm.tree.InsnList;
48 import org.objectweb.asm.tree.InsnNode;
49 import org.objectweb.asm.tree.JumpInsnNode;
50 import org.objectweb.asm.tree.LabelNode;
51 import org.objectweb.asm.tree.LookupSwitchInsnNode;
52 import org.objectweb.asm.tree.MethodNode;
53 import org.objectweb.asm.tree.TableSwitchInsnNode;
54 import org.objectweb.asm.tree.TryCatchBlockNode;
55 import org.objectweb.asm.tree.LocalVariableNode;
56
57 /**
58  * A {@link org.objectweb.asm.MethodAdapter} that removes JSR instructions and
59  * inlines the referenced subroutines.
60  *
61  * <b>Explanation of how it works</b> TODO
62  *
63  * @author Niko Matsakis
64  */

65 public class JSRInlinerAdapter extends MethodNode implements Opcodes {
66
67     private final static boolean LOGGING = false;
68
69     /**
70      * The visitor to which we will emit a translation of this method without
71      * internal subroutines.
72      */

73     private MethodVisitor mv;
74
75     /**
76      * For each label that is jumped to by a JSR, we create a Subroutine
77      * instance. Map<LabelNode,Subroutine> is the generic type.
78      */

79     private final Map JavaDoc subroutineHeads = new HashMap JavaDoc();
80
81     /**
82      * This subroutine instance denotes the line of execution that is not
83      * contained within any subroutine; i.e., the "subroutine" that is executing
84      * when a method first begins.
85      */

86     private final Subroutine mainSubroutine = new Subroutine();
87
88     /**
89      * This BitSet contains the index of every instruction that belongs to more
90      * than one subroutine. This should not happen often.
91      */

92     private final BitSet JavaDoc dualCitizens = new BitSet JavaDoc();
93
94     /**
95      * Creates a new JSRInliner.
96      *
97      * @param mv the <code>MethodVisitor</code> to send the resulting inlined
98      * method code to (use <code>null</code> for none).
99      * @param access the method's access flags (see {@link Opcodes}). This
100      * parameter also indicates if the method is synthetic and/or
101      * deprecated.
102      * @param name the method's name.
103      * @param desc the method's descriptor (see {@link Type}).
104      * @param signature the method's signature. May be <tt>null</tt>.
105      * @param exceptions the internal names of the method's exception classes
106      * (see {@link Type#getInternalName() getInternalName}). May be
107      * <tt>null</tt>.
108      */

109     public JSRInlinerAdapter(
110         final MethodVisitor mv,
111         final int access,
112         final String JavaDoc name,
113         final String JavaDoc desc,
114         final String JavaDoc signature,
115         final String JavaDoc[] exceptions)
116     {
117         super(access, name, desc, signature, exceptions);
118         this.mv = mv;
119     }
120
121     /**
122      * Detects a JSR instruction and sets a flag to indicate we will need to do
123      * inlining.
124      */

125     public void visitJumpInsn(final int opcode, final Label lbl) {
126         super.visitJumpInsn(opcode, lbl);
127         LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
128         if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
129             subroutineHeads.put(ln, new Subroutine());
130         }
131     }
132
133     /**
134      * If any JSRs were seen, triggers the inlining process. Otherwise, forwards
135      * the byte codes untouched.
136      */

137     public void visitEnd() {
138         if (!subroutineHeads.isEmpty()) {
139             markSubroutines();
140             if (LOGGING) {
141                 log(mainSubroutine.toString());
142                 Iterator JavaDoc it = subroutineHeads.values().iterator();
143                 while (it.hasNext()) {
144                     Subroutine sub = (Subroutine) it.next();
145                     log(sub.toString());
146                 }
147             }
148             emitCode();
149         }
150
151         // Forward the translate opcodes on if appropriate:
152
if (mv != null) {
153             accept(mv);
154         }
155     }
156
157     /**
158      * Walks the method and determines which internal subroutine(s), if any,
159      * each instruction is a method of.
160      */

161     private void markSubroutines() {
162         BitSet JavaDoc anyvisited = new BitSet JavaDoc();
163
164         // First walk the main subroutine and find all those instructions which
165
// can be reached without invoking any JSR at all
166
markSubroutineWalk(mainSubroutine, 0, anyvisited);
167
168         // Go through the head of each subroutine and find any nodes reachable
169
// to that subroutine without following any JSR links.
170
for (Iterator JavaDoc it = subroutineHeads.entrySet().iterator(); it.hasNext();)
171         {
172             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
173             LabelNode lab = (LabelNode) entry.getKey();
174             Subroutine sub = (Subroutine) entry.getValue();
175             int index = instructions.indexOf(lab);
176             markSubroutineWalk(sub, index, anyvisited);
177         }
178     }
179
180     /**
181      * Performs a depth first search walking the normal byte code path starting
182      * at <code>index</code>, and adding each instruction encountered into
183      * the subroutine <code>sub</code>. After this walk is complete, iterates
184      * over the exception handlers to ensure that we also include those byte
185      * codes which are reachable through an exception that may be thrown during
186      * the execution of the subroutine. Invoked from
187      * <code>markSubroutines()</code>.
188      *
189      * @param sub TODO.
190      * @param index TODO.
191      * @param anyvisited TODO.
192      */

193     private void markSubroutineWalk(
194         final Subroutine sub,
195         final int index,
196         final BitSet JavaDoc anyvisited)
197     {
198         if (LOGGING) {
199             log("markSubroutineWalk: sub=" + sub + " index=" + index);
200         }
201
202         // First find those instructions reachable via normal execution
203
markSubroutineWalkDFS(sub, index, anyvisited);
204
205         // Now, make sure we also include any applicable exception handlers
206
boolean loop = true;
207         while (loop) {
208             loop = false;
209             for (Iterator JavaDoc it = tryCatchBlocks.iterator(); it.hasNext();) {
210                 TryCatchBlockNode trycatch = (TryCatchBlockNode) it.next();
211
212                 if (LOGGING) {
213                     log("Scanning try/catch " + trycatch);
214                 }
215
216                 // If the handler has already been processed, skip it.
217
int handlerindex = instructions.indexOf(trycatch.handler);
218                 if (sub.instructions.get(handlerindex)) {
219                     continue;
220                 }
221
222                 int startindex = instructions.indexOf(trycatch.start);
223                 int endindex = instructions.indexOf(trycatch.end);
224                 int nextbit = sub.instructions.nextSetBit(startindex);
225                 if (nextbit != -1 && nextbit < endindex) {
226                     if (LOGGING) {
227                         log("Adding exception handler: " + startindex + "-"
228                                 + endindex + " due to " + nextbit + " handler "
229                                 + handlerindex);
230                     }
231                     markSubroutineWalkDFS(sub, handlerindex, anyvisited);
232                     loop = true;
233                 }
234             }
235         }
236     }
237
238     /**
239      * Performs a simple DFS of the instructions, assigning each to the
240      * subroutine <code>sub</code>. Starts from <code>index</code>.
241      * Invoked only by <code>markSubroutineWalk()</code>.
242      *
243      * @param sub TODO.
244      * @param index TODO.
245      * @param anyvisited TODO.
246      */

247     private void markSubroutineWalkDFS(
248         final Subroutine sub,
249         int index,
250         final BitSet JavaDoc anyvisited)
251     {
252         while (true) {
253             AbstractInsnNode node = instructions.get(index);
254
255             // don't visit a node twice
256
if (sub.instructions.get(index)) {
257                 return;
258             }
259             sub.instructions.set(index);
260
261             // check for those nodes already visited by another subroutine
262
if (anyvisited.get(index)) {
263                 dualCitizens.set(index);
264                 if (LOGGING) {
265                     log("Instruction #" + index + " is dual citizen.");
266                 }
267             }
268             anyvisited.set(index);
269
270             if (node.getType() == AbstractInsnNode.JUMP_INSN
271                     && node.getOpcode() != JSR)
272             {
273                 // we do not follow recursively called subroutines here; but any
274
// other sort of branch we do follow
275
JumpInsnNode jnode = (JumpInsnNode) node;
276                 int destidx = instructions.indexOf(jnode.label);
277                 markSubroutineWalkDFS(sub, destidx, anyvisited);
278             }
279             if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
280                 TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
281                 int destidx = instructions.indexOf(tsnode.dflt);
282                 markSubroutineWalkDFS(sub, destidx, anyvisited);
283                 for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
284                     LabelNode l = (LabelNode) tsnode.labels.get(i);
285                     destidx = instructions.indexOf(l);
286                     markSubroutineWalkDFS(sub, destidx, anyvisited);
287                 }
288             }
289             if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
290                 LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
291                 int destidx = instructions.indexOf(lsnode.dflt);
292                 markSubroutineWalkDFS(sub, destidx, anyvisited);
293                 for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
294                     LabelNode l = (LabelNode) lsnode.labels.get(i);
295                     destidx = instructions.indexOf(l);
296                     markSubroutineWalkDFS(sub, destidx, anyvisited);
297                 }
298             }
299
300             // check to see if this opcode falls through to the next instruction
301
// or not; if not, return.
302
switch (instructions.get(index).getOpcode()) {
303                 case GOTO:
304                 case RET:
305                 case TABLESWITCH:
306                 case LOOKUPSWITCH:
307                 case IRETURN:
308                 case LRETURN:
309                 case FRETURN:
310                 case DRETURN:
311                 case ARETURN:
312                 case RETURN:
313                 case ATHROW:
314                     /*
315                      * note: this either returns from this subroutine, or a
316                      * parent subroutine which invoked it
317                      */

318                     return;
319             }
320
321             // Use tail recursion here in the form of an outer while loop to
322
// avoid our stack growing needlessly:
323
index++;
324         }
325     }
326
327     /**
328      * Creates the new instructions, inlining each instantiation of each
329      * subroutine until the code is fully elaborated.
330      */

331     private void emitCode() {
332         LinkedList JavaDoc worklist = new LinkedList JavaDoc();
333         // Create an instantiation of the "root" subroutine, which is just the
334
// main routine
335
worklist.add(new Instantiation(null, mainSubroutine));
336
337         // Emit instantiations of each subroutine we encounter, including the
338
// main subroutine
339
InsnList newInstructions = new InsnList();
340         List JavaDoc newTryCatchBlocks = new ArrayList JavaDoc();
341         List JavaDoc newLocalVariables = new ArrayList JavaDoc();
342         while (!worklist.isEmpty()) {
343             Instantiation inst = (Instantiation) worklist.removeFirst();
344             emitSubroutine(inst,
345                     worklist,
346                     newInstructions,
347                     newTryCatchBlocks,
348                     newLocalVariables);
349         }
350         instructions = newInstructions;
351         tryCatchBlocks = newTryCatchBlocks;
352         localVariables = newLocalVariables;
353     }
354
355     /**
356      * Emits one instantiation of one subroutine, specified by
357      * <code>instant</code>. May add new instantiations that are invoked by
358      * this one to the <code>worklist</code> parameter, and new try/catch
359      * blocks to <code>newTryCatchBlocks</code>.
360      *
361      * @param instant TODO.
362      * @param workList TODO.
363      * @param newInstructions TODO.
364      * @param newTryCatchBlocks TODO.
365      */

366     private void emitSubroutine(
367         final Instantiation instant,
368         final List JavaDoc worklist,
369         final InsnList newInstructions,
370         final List JavaDoc newTryCatchBlocks,
371         final List JavaDoc newLocalVariables)
372     {
373         LabelNode duplbl = null;
374
375         if (LOGGING) {
376             log("--------------------------------------------------------");
377             log("Emitting instantiation of subroutine " + instant.subroutine);
378         }
379
380         // Emit the relevant instructions for this instantiation, translating
381
// labels and jump targets as we go:
382
for (int i = 0, c = instructions.size(); i < c; i++) {
383             AbstractInsnNode insn = instructions.get(i);
384             Instantiation owner = instant.findOwner(i);
385
386             // Always remap labels:
387
if (insn.getType() == AbstractInsnNode.LABEL) {
388                 // Translate labels into their renamed equivalents.
389
// Avoid adding the same label more than once. Note
390
// that because we own this instruction the gotoTable
391
// and the rangeTable will always agree.
392
LabelNode ilbl = (LabelNode) insn;
393                 LabelNode remap = instant.rangeLabel(ilbl);
394                 if (LOGGING) {
395                     log("Translating lbl #" + i + ":" + ilbl + " to " + remap);
396                 }
397                 if (remap != duplbl) {
398                     newInstructions.add(remap);
399                     duplbl = remap;
400                 }
401                 continue;
402             }
403
404             // We don't want to emit instructions that were already
405
// emitted by a subroutine higher on the stack. Note that
406
// it is still possible for a given instruction to be
407
// emitted twice because it may belong to two subroutines
408
// that do not invoke each other.
409
if (owner != instant) {
410                 continue;
411             }
412
413             if (LOGGING) {
414                 log("Emitting inst #" + i);
415             }
416
417             if (insn.getOpcode() == RET) {
418                 // Translate RET instruction(s) to a jump to the return label
419
// for the appropriate instantiation. The problem is that the
420
// subroutine may "fall through" to the ret of a parent
421
// subroutine; therefore, to find the appropriate ret label we
422
// find the lowest subroutine on the stack that claims to own
423
// this instruction. See the class javadoc comment for an
424
// explanation on why this technique is safe (note: it is only
425
// safe if the input is verifiable).
426
LabelNode retlabel = null;
427                 for (Instantiation p = instant; p != null; p = p.previous) {
428                     if (p.subroutine.ownsInstruction(i)) {
429                         retlabel = p.returnLabel;
430                     }
431                 }
432                 if (retlabel == null) {
433                     // This is only possible if the mainSubroutine owns a RET
434
// instruction, which should never happen for verifiable
435
// code.
436
throw new RuntimeException JavaDoc("Instruction #" + i
437                             + " is a RET not owned by any subroutine");
438                 }
439                 newInstructions.add(new JumpInsnNode(GOTO, retlabel));
440             } else if (insn.getOpcode() == JSR) {
441                 LabelNode lbl = ((JumpInsnNode) insn).label;
442                 Subroutine sub = (Subroutine) subroutineHeads.get(lbl);
443                 Instantiation newinst = new Instantiation(instant, sub);
444                 LabelNode startlbl = newinst.gotoLabel(lbl);
445
446                 if (LOGGING) {
447                     log(" Creating instantiation of subr " + sub);
448                 }
449
450                 // Rather than JSRing, we will jump to the inline version and
451
// push NULL for what was once the return value. This hack
452
// allows us to avoid doing any sort of data flow analysis to
453
// figure out which instructions manipulate the old return value
454
// pointer which is now known to be unneeded.
455
newInstructions.add(new InsnNode(ACONST_NULL));
456                 newInstructions.add(new JumpInsnNode(GOTO, startlbl));
457                 newInstructions.add(newinst.returnLabel);
458
459                 // Insert this new instantiation into the queue to be emitted
460
// later.
461
worklist.add(newinst);
462             } else {
463                 newInstructions.add(insn.clone(instant));
464             }
465         }
466
467         // Emit try/catch blocks that are relevant to this method.
468
for (Iterator JavaDoc it = tryCatchBlocks.iterator(); it.hasNext();) {
469             TryCatchBlockNode trycatch = (TryCatchBlockNode) it.next();
470
471             if (LOGGING) {
472                 log("try catch block original labels=" + trycatch.start + "-"
473                         + trycatch.end + "->" + trycatch.handler);
474             }
475
476             final LabelNode start = instant.rangeLabel(trycatch.start);
477             final LabelNode end = instant.rangeLabel(trycatch.end);
478
479             // Ignore empty try/catch regions
480
if (start == end) {
481                 if (LOGGING) {
482                     log(" try catch block empty in this subroutine");
483                 }
484                 continue;
485             }
486
487             final LabelNode handler = instant.gotoLabel(trycatch.handler);
488
489             if (LOGGING) {
490                 log(" try catch block new labels=" + start + "-" + end + "->"
491                         + handler);
492             }
493
494             if (start == null || end == null || handler == null) {
495                 throw new RuntimeException JavaDoc("Internal error!");
496             }
497
498             newTryCatchBlocks.add(new TryCatchBlockNode(start,
499                     end,
500                     handler,
501                     trycatch.type));
502         }
503
504         for (Iterator JavaDoc it = localVariables.iterator(); it.hasNext();) {
505             LocalVariableNode lvnode = (LocalVariableNode) it.next();
506             if (LOGGING) {
507                 log("local var " + lvnode.name);
508             }
509             final LabelNode start = instant.rangeLabel(lvnode.start);
510             final LabelNode end = instant.rangeLabel(lvnode.end);
511             if (start == end) {
512                 if (LOGGING) {
513                     log(" local variable empty in this sub");
514                 }
515                 continue;
516             }
517             newLocalVariables.add(new LocalVariableNode(lvnode.name,
518                     lvnode.desc,
519                     lvnode.signature,
520                     start,
521                     end,
522                     lvnode.index));
523         }
524     }
525
526     private void log(final String JavaDoc str) {
527         System.err.println(str);
528     }
529
530     protected static class Subroutine {
531
532         public final BitSet JavaDoc instructions = new BitSet JavaDoc();
533
534         public void addInstruction(final int idx) {
535             instructions.set(idx);
536         }
537
538         public boolean ownsInstruction(final int idx) {
539             return instructions.get(idx);
540         }
541
542         public String JavaDoc toString() {
543             return "Subroutine: " + instructions;
544         }
545     }
546
547     /**
548      * A class that represents an instantiation of a subroutine. Each
549      * instantiation has an associate "stack" --- which is a listing of those
550      * instantiations that were active when this particular instance of this
551      * subroutine was invoked. Each instantiation also has a map from the
552      * original labels of the program to the labels appropriate for this
553      * instantiation, and finally a label to return to.
554      */

555     private class Instantiation extends AbstractMap JavaDoc {
556
557         /**
558          * Previous instantiations; the stack must be statically predictable to
559          * be inlinable.
560          */

561         final Instantiation previous;
562
563         /**
564          * The subroutine this is an instantiation of.
565          */

566         public final Subroutine subroutine;
567
568         /**
569          * This table maps Labels from the original source to Labels pointing at
570          * code specific to this instantiation, for use in remapping try/catch
571          * blocks,as well as gotos.
572          *
573          * Note that in the presence of dual citizens instructions, that is,
574          * instructions which belong to more than one subroutine due to the
575          * merging of control flow without a RET instruction, we will map the
576          * target label of a GOTO to the label used by the instantiation lowest
577          * on the stack. This avoids code duplication during inlining in most
578          * cases.
579          *
580          * @see #findOwner(int)
581          */

582         public final Map JavaDoc rangeTable = new HashMap JavaDoc();
583
584         /**
585          * All returns for this instantiation will be mapped to this label
586          */

587         public final LabelNode returnLabel;
588
589         public Instantiation(final Instantiation prev, final Subroutine sub) {
590             previous = prev;
591             subroutine = sub;
592             for (Instantiation p = prev; p != null; p = p.previous) {
593                 if (p.subroutine == sub) {
594                     throw new RuntimeException JavaDoc("Recursive invocation of " + sub);
595                 }
596             }
597
598             // Determine the label to return to when this subroutine terminates
599
// via RET: note that the main subroutine never terminates via RET.
600
if (prev != null) {
601                 returnLabel = new LabelNode();
602             } else {
603                 returnLabel = null;
604             }
605
606             // Each instantiation will remap the labels from the code above to
607
// refer to its particular copy of its own instructions. Note that
608
// we collapse labels which point at the same instruction into one:
609
// this is fairly common as we are often ignoring large chunks of
610
// instructions, so what were previously distinct labels become
611
// duplicates.
612
LabelNode duplbl = null;
613             for (int i = 0, c = instructions.size(); i < c; i++) {
614                 AbstractInsnNode insn = instructions.get(i);
615
616                 if (insn.getType() == AbstractInsnNode.LABEL) {
617                     LabelNode ilbl = (LabelNode) insn;
618
619                     if (duplbl == null) {
620                         // if we already have a label pointing at this spot,
621
// don't recreate it.
622
duplbl = new LabelNode();
623                     }
624
625                     // Add an entry in the rangeTable for every label
626
// in the original code which points at the next
627
// instruction of our own to be emitted.
628
rangeTable.put(ilbl, duplbl);
629                 } else if (findOwner(i) == this) {
630                     // We will emit this instruction, so clear the 'duplbl' flag
631
// since the next Label will refer to a distinct
632
// instruction.
633
duplbl = null;
634                 }
635             }
636         }
637
638         /**
639          * Returns the "owner" of a particular instruction relative to this
640          * instantiation: the owner referes to the Instantiation which will emit
641          * the version of this instruction that we will execute.
642          *
643          * Typically, the return value is either <code>this</code> or
644          * <code>null</code>. <code>this</code> indicates that this
645          * instantiation will generate the version of this instruction that we
646          * will execute, and <code>null</code> indicates that this
647          * instantiation never executes the given instruction.
648          *
649          * Sometimes, however, an instruction can belong to multiple
650          * subroutines; this is called a "dual citizen" instruction (though it
651          * may belong to more than 2 subroutines), and occurs when multiple
652          * subroutines branch to common points of control. In this case, the
653          * owner is the subroutine that appears lowest on the stack, and which
654          * also owns the instruction in question.
655          *
656          * @param i the index of the instruction in the original code
657          * @return the "owner" of a particular instruction relative to this
658          * instantiation.
659          */

660         public Instantiation findOwner(final int i) {
661             if (!subroutine.ownsInstruction(i)) {
662                 return null;
663             }
664             if (!dualCitizens.get(i)) {
665                 return this;
666             }
667             Instantiation own = this;
668             for (Instantiation p = previous; p != null; p = p.previous) {
669                 if (p.subroutine.ownsInstruction(i)) {
670                     own = p;
671                 }
672             }
673             return own;
674         }
675
676         /**
677          * Looks up the label <code>l</code> in the <code>gotoTable</code>,
678          * thus translating it from a Label in the original code, to a Label in
679          * the inlined code that is appropriate for use by an instruction that
680          * branched to the original label.
681          *
682          * @param l The label we will be translating
683          * @return a label for use by a branch instruction in the inlined code
684          * @see #gotoTable
685          */

686         public LabelNode gotoLabel(final LabelNode l) {
687             // owner should never be null, because owner is only null
688
// if an instruction cannot be reached from this subroutine
689
Instantiation owner = findOwner(instructions.indexOf(l));
690             return (LabelNode) owner.rangeTable.get(l);
691         }
692
693         /**
694          * Looks up the label <code>l</code> in the <code>rangeTable</code>,
695          * thus translating it from a Label in the original code, to a Label in
696          * the inlined code that is appropriate for use by an try/catch or
697          * variable use annotation.
698          *
699          * @param l The label we will be translating
700          * @return a label for use by a try/catch or variable annotation in the
701          * original code
702          * @see #rangeTable
703          */

704         public LabelNode rangeLabel(final LabelNode l) {
705             return (LabelNode) rangeTable.get(l);
706         }
707
708         // AbstractMap implementation
709

710         public Set JavaDoc entrySet() {
711             return null;
712         }
713
714         public Object JavaDoc get(final Object JavaDoc o) {
715             return gotoLabel((LabelNode) o);
716         }
717     }
718 }
719
Popular Tags