Source code: com/chaoswg/xtc4y/classdesc/code/instructions/LookupSwitchInstruction.java
1 //$Header: /cvsroot/xtc4y/xtc4y/src/com/chaoswg/xtc4y/classdesc/code/instructions/LookupSwitchInstruction.java,v 1.2 2003/08/26 12:35:25 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/08/26 12:35:25 $, by $Author: toggm $ *
9 * Version: $Revision: 1.2 $ *
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 number of entries, an
30 * int defining the default jump address and a set of entries where each
31 * entry consists of two ints, the case number and the jump address. The end
32 * of a LookupSwitch Instruction is aligned to 4 byte and therefore gaps
33 * are filled up with nop's. !The empty instructions are filled up before the
34 * default jump adress and the numberOfEntries
35 * That means: (1byte+4bytes+4bytes+(4bytes+4bytes)*+((index+length)%4))
36 * @author Mike Toggweiler
37 **/
38 public class LookupSwitchInstruction extends Instruction {
39 private int numberOfEntries;
40 private int defaultJumpAdress;
41 private int[] cases;
42 private int[] jumps;
43 private int gap;
44
45 private Instruction defaultInstr;
46 private Instruction[] jumpInstr;
47
48 private DataInputStream dis;
49 /**
50 * Opcode of the lookup switch instructions
51 **/
52 public static final byte LOOKUPSWITCH = (byte)171;
53
54 /**
55 * Creates an LookupSwitchInstruction and initializes it from a
56 * DataInputStream
57 * @param dis the DataInputStream to read from
58 * @param cp the constant pool to resolve indices
59 **/
60 protected LookupSwitchInstruction(DataInputStream dis, ConstantPool cp)
61 throws IOException {
62 super(LOOKUPSWITCH);
63
64 //store temporary the datainputstream to read the gap from
65 this.dis = dis;
66 }
67
68 /**
69 * Set the index of this instruction, is set by the code container
70 * @param index
71 **/
72 public void setIndex(short index) {
73 super.setIndex(index);
74
75 if (dis == null) {
76 return;
77 }
78
79 //read the remaining gap, is depedant on the index of the switch
80 //instruction
81 gap = (index % 4);
82 if (gap == 0) {
83 gap = 1;
84 }
85 else {
86 gap++;
87 }
88 gap = 4 - gap;
89 try {
90 for (int i=0; i<gap; ++i) {
91 //throw away byte
92 dis.readUnsignedByte();
93 }
94 defaultJumpAdress = dis.readInt();
95 numberOfEntries = dis.readInt();
96
97 cases = new int[numberOfEntries];
98 jumps = new int[numberOfEntries];
99 jumpInstr = new Instruction[numberOfEntries];
100 for (int i=0; i<numberOfEntries; ++i) {
101 cases[i] = dis.readInt();
102 jumps[i] = dis.readInt();
103 }
104 }
105 catch (IOException ioe) {
106 //do nothing
107 //TBD: log
108 }
109
110 //free dis reference
111 dis = null;
112 }
113
114 /**
115 * Resolve indices of instructions.
116 * By default do nothing
117 * @param code the code container where to resolve the indices
118 **/
119 public void resolveIndices(Code code) {
120 for (int i=0; i<numberOfEntries; ++i) {
121 jumpInstr[i] = code.getInstructionAt((short)(jumps[i]+getIndex()));
122 }
123
124 defaultInstr = code.getInstructionAt((short)defaultJumpAdress);
125 }
126
127 /**
128 * Write the instruction onto the DataOutputStream, using the
129 * constant pool to register variables. .
130 * @param dos the DataOutputStream to write on
131 * @param cp The constant pool to register variables
132 **/
133 public final void write(DataOutputStream dos, ConstantPool cp)
134 throws IOException {
135 super.write(dos, cp);
136
137 for (int i=0; i<gap; ++i) {
138 dos.writeByte(UnaryInstruction.NOP);
139 }
140 dos.writeInt(defaultInstr.getIndex());
141 dos.writeInt(numberOfEntries);
142 for (int i=0; i<numberOfEntries; ++i) {
143 dos.writeInt(cases[i]);
144 dos.writeInt(jumpInstr[i].getIndex()-getIndex());
145 }
146 }
147
148 /**
149 * @return the number of bytes used in this command
150 **/
151 public int getNumberOfUsedBytes() {
152 //return command + numberOfEntries + defaultJumpAddr +
153 //numberOfEntries*(case + jumpAddr) + gap
154 return 1 + 4 + 4 + numberOfEntries*(4+4) + gap;
155 }
156 }