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: