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