1 cananian 1.2.2.2 // InSwitch.java, created Sun Sep 13 22:49:21 1998 by cananian
 2 cananian 1.2     // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
 3 cananian 1.2     // Licensed under the terms of the GNU GPL; see COPYING for details.
 4 cananian 1.1     package harpoon.IR.Bytecode;
 5 cananian 1.1     
 6 cananian 1.1     import harpoon.Util.Util;
 7 cananian 1.1     
 8 cananian 1.1     /**
 9 cananian 1.1      * <code>InSwitch</code> is used for the <code>tableswitch</code> and
10 cananian 1.1      * <code>lookupswitch</code> java bytecode instructions.
11 cananian 1.1      * It is a control-transfer instruction.  It should have exactly
12 cananian 1.1      * one predecessor.  The first successor will be the default
13 cananian 1.1      * target; each subsequent successor corresponds to a <code>case</code>
14 cananian 1.1      * of the switch statement; the match key can be looked up using the
15 cananian 1.1      * <code>key</code> method.
16 cananian 1.1      *
17 cananian 1.1      * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
18 cananian 1.3      * @version $Id: InSwitch.java,v 1.3 2002/02/25 21:04:17 cananian Exp $
19 cananian 1.1      * @see Instr
20 cananian 1.1      */
21 cananian 1.1     public class InSwitch extends InCti {
22 cananian 1.2.2.1   final int keys[];
23 cananian 1.1     
24 cananian 1.1       /** Constructor.  Creates an <code>InSwitch</code> from a chunk of
25 cananian 1.1        *  bytecode starting at the given pc.
26 cananian 1.1        *  @exception Error if the opcode at <code>code[pc]</code> doesn't
27 cananian 1.1        *             correspond to a <code>tableswitch</code> or
28 cananian 1.1        *             <code>lookupswitch</code>.
29 cananian 1.1        */
30 cananian 1.1       public InSwitch(String sourcefile, int linenumber, byte[] code, int pc) {
31 cananian 1.1         super(sourcefile, linenumber, code, pc);
32 cananian 1.1         int pad = 3-(pc%4);
33 cananian 1.1         if (code[pc]==Op.LOOKUPSWITCH) {
34 cananian 1.1           int npairs = s4(code, pc+pad+5);
35 cananian 1.1           if (npairs<0) throw new Error("Invalid npairs in lookupswitch.");
36 cananian 1.1           keys = new int[npairs+1];
37 cananian 1.1           // keys[0] is invalid; the first succ. is the default branch target.
38 cananian 1.1           for (int i=0; i<npairs; i++)
39 cananian 1.1             keys[i+1] = s4(code,pc+pad+9+(8*i));
40 cananian 1.1         } else if (code[pc]==Op.TABLESWITCH) {
41 cananian 1.1           int low = s4(code, pc+pad+5);
42 cananian 1.1           int high= s4(code, pc+pad+9);
43 cananian 1.1           int npairs=high-low+1;
44 cananian 1.1           if (low>high) throw new Error("Invalid low/high in tableswitch.");
45 cananian 1.1           keys = new int[npairs+1];
46 cananian 1.1           // again, keys[0] is invalid.  No key for default target.
47 cananian 1.1           for (int i=0; i<npairs; i++)
48 cananian 1.1             keys[i+1]=low+i;
49 cananian 1.1         } else throw new Error("InSwitch constructor given invalid opcode.");
50 cananian 1.1       }
51 cananian 1.1       /** 
52 cananian 1.1        * Returns the case key corresponding to the given branch target index.<p>
53 cananian 1.1        * <code>InSwitch.key(n)</code> corresponds to 
54 cananian 1.1        * <code>InSwitch.next()[n]</code> for 
55 cananian 1.1        * <code>0<n<InSwitch.next().length</code>.
56 cananian 1.1        * @exception Error if the default target or
57 cananian 1.1        *                  an instruction not corresponding to a target is given.
58 cananian 1.1        */
59 cananian 1.1       public int key(int index) {
60 cananian 1.1         if (index<0) throw new Error("Invalid key lookup index.");
61 cananian 1.1         if (index==0) throw new Error("No key for default target.");
62 cananian 1.1         return keys[index];
63 cananian 1.1       }
64 cananian 1.1       /** Return human-readable instruction string. */
65 cananian 1.1       public String toString() {
66 cananian 1.1         StringBuffer sb = new StringBuffer(Op.toString(opcode));
67 cananian 1.1         Instr[] targets = next();
68 cananian 1.1         sb.append(" { default: goto #"); sb.append(targets[0].getID());
69 cananian 1.1         for (int i=1; i<targets.length; i++)
70 cananian 1.1           sb.append("; case "+keys[i]+": goto #"+targets[i].getID());
71 cananian 1.1         sb.append(" }");
72 cananian 1.1         return sb.toString();
73 cananian 1.1       }
74 cananian 1.1     
75 cananian 1.1       // utility.
76 cananian 1.1       /** Make signed 4-bit int from four bytes. */
77 cananian 1.1       int s4(byte[] code, int pc) {
78 cananian 1.1         return 
79 cananian 1.1           ( u1(code,pc)   << 24) |
80 cananian 1.1           ( u1(code,pc+1) << 16) |
81 cananian 1.1           ( u1(code,pc+2) <<  8) |
82 cananian 1.1           ( u1(code,pc+3) <<  0);
83 cananian 1.1       }
84 cananian 1.1       /** Make integer from <i>unsigned</i> byte. */
85 cananian 1.1       int u1(byte[] code, int pc) { return ((int)code[pc])&0xFF; }
86 cananian 1.1     }
87 cananian 1.1     
88 cananian 1.1     // set emacs indentation style.
89 cananian 1.1     // Local Variables:
90 cananian 1.1     // c-basic-offset:2
91 cananian 1.1     // End: