1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.jdo.impl.enhancer.classfile;
20
21 import java.util.Stack;
22 import java.util.Vector;
23 import java.io.*;
24
25 /***
26 * Subtype of ClassAttribute which describes the "Code" attribute
27 * associated with a method.
28 */
29 public class CodeAttribute extends ClassAttribute {
30 public final static String expectedAttrName = "Code";
31
32
33
34
35 private byte theDataBytes[];
36
37
38 private int maxStack;
39
40
41 private int maxLocals;
42
43
44
45 private byte theCodeBytes[];
46
47
48
49 private Insn theCode;
50
51
52
53 private ExceptionTable exceptionTable;
54
55
56 private AttributeVector codeAttributes;
57
58
59 CodeEnv codeEnv;
60
61
62
63 /***
64 * Return the maximum number of stack entries used by this method
65 */
66 public int stackUsed() {
67 makeValid();
68 return maxStack;
69 }
70
71 /***
72 * Set the maximum number of stack entries used by this method
73 */
74 public void setStackUsed(int used) {
75 makeValid();
76 maxStack = used;
77 }
78
79 /***
80 * Return the maximum number of local variables used by this method
81 */
82 public int localsUsed() {
83 makeValid();
84 return maxLocals;
85 }
86
87 /***
88 * Set the maximum number of local variables used by this method
89 */
90 public void setLocalsUsed(int used) {
91 makeValid();
92 maxLocals = used;
93 }
94
95 /***
96 * Return the java VM byte code sequence for this method - null for
97 * native and abstract methods
98 */
99 public byte[] byteCodes() {
100 makeValid();
101 return theCodeBytes;
102 }
103
104 /***
105 * Return the instruction sequence for this method - initially derived
106 * from the byte code array, but may later be modified
107 */
108 public Insn theCode() {
109 makeValid();
110 if (theCode == null && codeEnv != null) {
111 buildInstructions(codeEnv);
112 }
113 return theCode;
114 }
115
116 /***
117 * Install the instruction sequence for this method - the byte code array
118 * is later updated.
119 */
120 public void setTheCode(Insn insn) {
121 makeValid();
122 if (insn != null && insn.opcode() != Insn.opc_target)
123 throw new InsnError(
124 "The initial instruction in all methods must be a target");
125 theCode = insn;
126 }
127
128 /***
129 * Return the exception ranges and handlers which apply to the code in
130 * this method.
131 */
132 public ExceptionTable exceptionHandlers() {
133 makeValid();
134 return exceptionTable;
135 }
136
137 /***
138 * Return the attributes which apply to this code
139 */
140 public AttributeVector attributes() {
141 makeValid();
142 return codeAttributes;
143 }
144
145 /***
146 * Constructs a CodeAttribute object for construction from scratch
147 */
148 public CodeAttribute(ConstUtf8 attrName,
149 int maxStack, int maxLocals,
150 Insn code,
151 ExceptionTable excTable,
152 AttributeVector codeAttrs) {
153 this(attrName, maxStack, maxLocals, code, null,
154 excTable, codeAttrs, null
155 }
156
157 /***
158 * Constructs a CodeAttribute object
159 */
160 public CodeAttribute(ConstUtf8 attrName,
161 int maxStack, int maxLocals,
162 Insn code, byte[] codeBytes,
163 ExceptionTable excTable,
164 AttributeVector codeAttrs,
165 CodeEnv codeEnv) {
166 super(attrName);
167 this.maxStack = maxStack;
168 this.maxLocals = maxLocals;
169 theCode = code;
170 theCodeBytes = codeBytes;
171 exceptionTable = excTable;
172 codeAttributes = codeAttrs;
173 this.codeEnv = codeEnv;
174 }
175
176 /***
177 * Constructs a CodeAttribute object for later disassembly
178 */
179 public CodeAttribute(ConstUtf8 attrName, byte[] dataBytes, CodeEnv codeEnv) {
180 super(attrName);
181 this.theDataBytes = dataBytes;
182 this.codeEnv = codeEnv;
183 }
184
185 /***
186 * Compares this instance with another for structural equality.
187 */
188
189 public boolean isEqual(Stack msg, Object obj) {
190 if (!(obj instanceof CodeAttribute)) {
191 msg.push("obj/obj.getClass() = "
192 + (obj == null ? null : obj.getClass()));
193 msg.push("this.getClass() = "
194 + this.getClass());
195 return false;
196 }
197 CodeAttribute other = (CodeAttribute)obj;
198
199 if (!super.isEqual(msg, other)) {
200 return false;
201 }
202
203 if (this.stackUsed() != other.stackUsed()) {
204 msg.push(String.valueOf("stackUsed() = "
205 + other.stackUsed()));
206 msg.push(String.valueOf("stackUsed() = "
207 + this.stackUsed()));
208 return false;
209 }
210 if (this.localsUsed() != other.localsUsed()) {
211 msg.push(String.valueOf("localsUsed() = "
212 + other.localsUsed()));
213 msg.push(String.valueOf("localsUsed() = "
214 + this.localsUsed()));
215 return false;
216 }
217
218
219 Insn theCode1 = this.theCode();
220 Insn theCode2 = other.theCode();
221 while (theCode1 != null && theCode2 != null) {
222
223 if (theCode1.opcode() == Insn.opc_target) {
224 theCode1 = theCode1.next();
225 continue;
226 }
227 if (theCode2.opcode() == Insn.opc_target) {
228 theCode2 = theCode2.next();
229 continue;
230 }
231 if (!theCode1.isEqual(msg, theCode2)) {
232 msg.push("theCode()[i] = " + String.valueOf(theCode2));
233 msg.push("theCode()[i] = " + String.valueOf(theCode1));
234 return false;
235 }
236 theCode1 = theCode1.next();
237 theCode2 = theCode2.next();
238 }
239 if (theCode1 == null ^ theCode2 == null) {
240 msg.push("theCode()[i] = " + String.valueOf(theCode2));
241 msg.push("theCode()[i] = " + String.valueOf(theCode1));
242 return false;
243 }
244
245 if (!this.exceptionHandlers().isEqual(msg, other.exceptionHandlers())) {
246 msg.push(String.valueOf("exceptionHandlers() = "
247 + other.exceptionHandlers()));
248 msg.push(String.valueOf("exceptionHandlers() = "
249 + this.exceptionHandlers()));
250 return false;
251 }
252 if (!this.attributes().isEqual(msg, other.attributes())) {
253 msg.push(String.valueOf("attributes() = "
254 + other.attributes()));
255 msg.push(String.valueOf("attributes() = "
256 + this.attributes()));
257 return false;
258 }
259 return true;
260 }
261
262 /* package local methods *//package-summary/html">class="comment"> package local methods *//package-summary.html">
263
264 static CodeAttribute read(ConstUtf8 attrName,
265 DataInputStream data, ConstantPool pool)
266 throws IOException {
267 int maxStack = data.readUnsignedShort();
268 int maxLocals = data.readUnsignedShort();
269 int codeLength = data.readInt();
270 byte codeBytes[] = new byte[codeLength];
271 data.readFully(codeBytes);
272 Insn code = null;
273 CodeEnv codeEnv = new CodeEnv(pool);
274
275 ExceptionTable excTable = ExceptionTable.read(data, codeEnv);
276
277 AttributeVector codeAttrs =
278 AttributeVector.readAttributes(data, codeEnv);
279
280 return new CodeAttribute(attrName, maxStack, maxLocals, code, codeBytes,
281 excTable, codeAttrs, codeEnv);
282 }
283
284
285
286 static CodeAttribute read(ConstUtf8 attrName, int attrLength,
287 DataInputStream data, ConstantPool pool)
288 throws IOException {
289 byte dataBytes[] = new byte[attrLength];
290 data.readFully(dataBytes);
291 return new CodeAttribute(attrName, dataBytes, new CodeEnv(pool));
292 }
293
294 void write(DataOutputStream out) throws IOException {
295 out.writeShort(attrName().getIndex());
296 if (theDataBytes == null) {
297 buildInstructionBytes();
298 ByteArrayOutputStream baos = new ByteArrayOutputStream();
299 DataOutputStream tmpOut = new DataOutputStream(baos);
300 tmpOut.writeShort(maxStack);
301 tmpOut.writeShort(maxLocals);
302 tmpOut.writeInt(theCodeBytes.length);
303 tmpOut.write(theCodeBytes, 0, theCodeBytes.length);
304 exceptionTable.write(tmpOut);
305 codeAttributes.write(tmpOut);
306
307 tmpOut.flush();
308 byte tmpBytes[] = baos.toByteArray();
309 out.writeInt(tmpBytes.length);
310 out.write(tmpBytes, 0, tmpBytes.length);
311 } else {
312 out.writeInt(theDataBytes.length);
313 out.write(theDataBytes, 0, theDataBytes.length);
314 }
315 }
316
317 void print(PrintStream out, int indent) {
318 makeValid();
319 ClassPrint.spaces(out, indent);
320 out.print("Code:");
321 out.print(" max_stack = " + Integer.toString(maxStack));
322 out.print(" max_locals = " + Integer.toString(maxLocals));
323 out.println(" Exceptions:");
324 exceptionTable.print(out, indent+2);
325 ClassPrint.spaces(out, indent);
326 out.println("Code Attributes:");
327 codeAttributes.print(out, indent+2);
328
329 Insn insn = theCode();
330 if (insn != null) {
331 ClassPrint.spaces(out, indent);
332 out.println("Instructions:");
333 while (insn != null) {
334 insn.print(out, indent+2);
335 insn = insn.next();
336 }
337 }
338 }
339
340 /***
341 * Assign offsets to instructions and return the number of bytes.
342 * theCode must be non-null.
343 */
344 private int resolveOffsets() {
345 Insn insn = theCode;
346 int currPC = 0;
347 while (insn != null) {
348 currPC = insn.resolveOffset(currPC);
349 insn = insn.next();
350 }
351 return currPC;
352 }
353
354 int codeSize() {
355 makeValid();
356 return theCodeBytes.length;
357 }
358
359 /***
360 * Derive the instruction list from the instruction byte codes
361 */
362 private void buildInstructions(CodeEnv codeEnv) {
363 if (theCodeBytes != null) {
364 InsnReadEnv insnEnv = new InsnReadEnv(theCodeBytes, codeEnv);
365 theCode = insnEnv.getTarget(0);
366 Insn currInsn = theCode;
367
368
369 while (insnEnv.more()) {
370 Insn newInsn = Insn.read(insnEnv);
371 currInsn.setNext(newInsn);
372 currInsn = newInsn;
373 }
374
375
376 InsnTarget targ;
377 currInsn = theCode;
378 Insn prevInsn = null;
379 while (currInsn != null) {
380 int off = currInsn.offset();
381
382
383 if (off > 0) {
384 targ = codeEnv.findTarget(off);
385 if (targ != null)
386 prevInsn.setNext(targ);
387 }
388 prevInsn = currInsn;
389 currInsn = currInsn.next();
390 }
391
392
393 targ = codeEnv.findTarget(insnEnv.currentPC());
394 if (targ != null)
395 prevInsn.setNext(targ);
396 }
397 }
398
399 /***
400 * Derive the instruction byte codes from the instruction list
401 * This should also recompute stack and variables but for now we
402 * assume that this isn't needed
403 */
404 private void buildInstructionBytes() {
405 if (theCode != null) {
406
407 int size = resolveOffsets();
408 theCodeBytes = new byte[size];
409
410 Insn insn = theCode;
411 int index = 0;
412 while (insn != null) {
413 index = insn.store(theCodeBytes, index);
414 insn = insn.next();
415 }
416 }
417 }
418
419 /*** If theDataBytes is non-null, disassemble this code attribute
420 * from the data bytes. */
421 private void makeValid() {
422 if (theDataBytes != null) {
423 DataInputStream dis = new DataInputStream(
424 new ByteArrayInputStream(theDataBytes));
425 try {
426 maxStack = dis.readUnsignedShort();
427 maxLocals = dis.readUnsignedShort();
428 int codeLength = dis.readInt();
429 theCodeBytes = new byte[codeLength];
430 dis.readFully(theCodeBytes);
431 exceptionTable = ExceptionTable.read(dis, codeEnv);
432 codeAttributes = AttributeVector.readAttributes(dis, codeEnv);
433 } catch (java.io.IOException ioe) {
434 throw new ClassFormatError("IOException while reading code attribute");
435 }
436
437 theDataBytes = null;
438 }
439 }
440 }
441