Source code: com/chaoswg/xtc4y/classdesc/code/instructions/TableSwitchInstruction.java
1 //$Header: /cvsroot/xtc4y/xtc4y/src/com/chaoswg/xtc4y/classdesc/code/instructions/TableSwitchInstruction.java,v 1.4 2003/09/08 20:57:26 toggm Exp $
2 /******************************************************************************
3 * XTC4y - eXtreme Testing Collection 4 you *
4 * -------------------------------------------------------------------------- *
5 * URL: http://www.chaoswg.com/xtc4y *
6 * Author: Mike Toggweiler (2.dog@gmx.ch) *
7 * *
8 * Last Updated: $Date: 2003/09/08 20:57:26 $, by $Author: toggm $ *
9 * Version: $Revision: 1.4 $ *
10 * -------------------------------------------------------------------------- *
11 * COPYRIGHT: (c) 2003 by Mike Toggweiler *
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 *****************************************************************************/
18 package com.chaoswg.xtc4y.classdesc.code.instructions;
19
20 import java.io.DataInputStream;
21 import java.io.DataOutputStream;
22 import java.io.IOException;
23
24 import com.chaoswg.xtc4y.classdesc.ConstantPool;
25 import com.chaoswg.xtc4y.classdesc.code.Code;
26
27 /**
28 * A Lookup switch instruction is used to represent switch statements.
29 * It consists of the command, an int giving the start number, an int defining
30 * the last number of table entires, an int defining the default jump address
31 * and a set of entries where each entry consists of one int, a jump address.
32 * The end of a TableSwitch Instruction is aligned to 4 byte and therefore
33 * gaps are filled up with nop's.
34 * That means: (1byte+4bytes+4bytes+4bytes+(4bytes)*+((index+length)%4))
35 * TBD: add methods to instanciate a tableswitch without a stream
36 * @author Mike Toggweiler
37 **/
38 public class TableSwitchInstruction extends Instruction {
39 private int startIndex;
40 private int endIndex;
41 private int defaultJumpAdress;
42 private int[] jumps;
43 private int gap;
44
45 private Instruction defaultInstr;
46 private Instruction[] jumpInstr;
47
48 private DataInputStream dis;
49
50 /**
51 * Opcode of int binary instructions
52 **/
53 public static final byte TABLESWITCH = (byte)170;
54
55 /**
56 * Creates an LookupSwitchInstruction and initializes it from a
57 * DataInputStream
58 * @param dis the DataInputStream to read from
59 * @param cp the constant pool to resolve indices
60 **/
61 protected TableSwitchInstruction(DataInputStream dis,
62 ConstantPool cp) throws IOException {
63 super(TABLESWITCH);
64
65 //store temporary the datainputstream to read the gap from
66 this.dis = dis;
67 }
68
69 /**
70 * Set the index of this instruction, is set by the code container
71 * @param index
72 **/
73 public void setIndex(short index) {
74 super.setIndex(index);
75
76 if (dis == null) {
77 return;
78 }
79
80 //read the remaining gap, is depedant on the index of the switch
81 //instruction
82 gap = (index % 4);
83 if (gap == 0) {
84 gap = 1;
85 }
86 else {
87 gap++;
88 }
89 gap = 4 - gap;
90 try {
91 for (int i=0; i<gap; ++i) {
92 //throw away byte
93 dis.readUnsignedByte();
94
95 }
96
97 defaultJumpAdress = dis.readInt();
98 startIndex = dis.readInt();
99 endIndex = dis.readInt();
100
101 jumps = new int[endIndex-startIndex];
102 jumpInstr = new Instruction[endIndex-startIndex];
103 int i,j;
104 for (i=startIndex, j=0; i<endIndex; ++i, ++j) {
105 jumps[j] = dis.readInt();
106 }
107 }
108 catch (IOException ioe) {
109 //do nothing
110 //TBD: log
111 }
112
113 //free dis reference
114 dis = null;
115 }
116
117 /**
118 * Resolve indices of instructions.
119 * By default do nothing
120 * @param code the code container where to resolve the indices
121 **/
122 public void resolveIndices(Code code) {
123 int i, j;
124 for (i=startIndex,j=0; i<endIndex; ++i, ++j) {
125 jumpInstr[j] = code.getInstructionAt((short)(jumps[j]+getIndex()));
126 }
127
128 defaultInstr = code.getInstructionAt((short)defaultJumpAdress);
129 }
130
131 /**
132 * Write the instruction onto the DataOutputStream, using the
133 * constant pool to register variables. .
134 * @param dos the DataOutputStream to write on
135 * @param cp The constant pool to register variables
136 **/
137 public final void write(DataOutputStream dos, ConstantPool cp)
138 throws IOException {
139 super.write(dos, cp);
140 int i,j;
141 for (i=0; i<gap; ++i) {
142 dos.writeByte(UnaryInstruction.NOP);
143 }
144 dos.writeInt(startIndex);
145 dos.writeInt(endIndex);
146 dos.writeInt(defaultInstr.getIndex());
147 for (i=startIndex, j=0; i<endIndex; ++i, ++j) {
148 dos.writeInt(jumpInstr[j].getIndex()-getIndex());
149 }
150 }
151
152 /**
153 * @return the number of bytes used in this command
154 **/
155 public int getNumberOfUsedBytes() {
156 //return command + startIndex + endIndex + defaultJumpAddr +
157 //numberOfEntries*(jumpAddr) + gap
158 return 1 + 4 + 4 + 4 + (endIndex-startIndex)*(4) + gap;
159 }
160 }