|
1 /* |
|
2 * Copyright 2001-2004 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 package sun.reflect; |
|
27 |
|
28 class ClassFileAssembler implements ClassFileConstants { |
|
29 private ByteVector vec; |
|
30 private short cpIdx = 0; |
|
31 |
|
32 public ClassFileAssembler() { |
|
33 this(ByteVectorFactory.create()); |
|
34 } |
|
35 |
|
36 public ClassFileAssembler(ByteVector vec) { |
|
37 this.vec = vec; |
|
38 } |
|
39 |
|
40 public ByteVector getData() { |
|
41 return vec; |
|
42 } |
|
43 |
|
44 /** Length in bytes */ |
|
45 public short getLength() { |
|
46 return (short) vec.getLength(); |
|
47 } |
|
48 |
|
49 public void emitMagicAndVersion() { |
|
50 emitInt(0xCAFEBABE); |
|
51 emitShort((short) 0); |
|
52 emitShort((short) 49); |
|
53 } |
|
54 |
|
55 public void emitInt(int val) { |
|
56 emitByte((byte) (val >> 24)); |
|
57 emitByte((byte) ((val >> 16) & 0xFF)); |
|
58 emitByte((byte) ((val >> 8) & 0xFF)); |
|
59 emitByte((byte) (val & 0xFF)); |
|
60 } |
|
61 |
|
62 public void emitShort(short val) { |
|
63 emitByte((byte) ((val >> 8) & 0xFF)); |
|
64 emitByte((byte) (val & 0xFF)); |
|
65 } |
|
66 |
|
67 // Support for labels; package-private |
|
68 void emitShort(short bci, short val) { |
|
69 vec.put(bci, (byte) ((val >> 8) & 0xFF)); |
|
70 vec.put(bci + 1, (byte) (val & 0xFF)); |
|
71 } |
|
72 |
|
73 public void emitByte(byte val) { |
|
74 vec.add(val); |
|
75 } |
|
76 |
|
77 public void append(ClassFileAssembler asm) { |
|
78 append(asm.vec); |
|
79 } |
|
80 |
|
81 public void append(ByteVector vec) { |
|
82 for (int i = 0; i < vec.getLength(); i++) { |
|
83 emitByte(vec.get(i)); |
|
84 } |
|
85 } |
|
86 |
|
87 /** Keeps track of the current (one-based) constant pool index; |
|
88 incremented after emitting one of the following constant pool |
|
89 entries. Can fetch the current constant pool index for use in |
|
90 later entries. Index points at the last valid constant pool |
|
91 entry; initially invalid. It is illegal to fetch the constant |
|
92 pool index before emitting at least one constant pool entry. */ |
|
93 public short cpi() { |
|
94 if (cpIdx == 0) { |
|
95 throw new RuntimeException("Illegal use of ClassFileAssembler"); |
|
96 } |
|
97 return cpIdx; |
|
98 } |
|
99 |
|
100 public void emitConstantPoolUTF8(String str) { |
|
101 // NOTE: can not use str.getBytes("UTF-8") here because of |
|
102 // bootstrapping issues with the character set converters. |
|
103 byte[] bytes = UTF8.encode(str); |
|
104 emitByte(CONSTANT_Utf8); |
|
105 emitShort((short) bytes.length); |
|
106 for (int i = 0; i < bytes.length; i++) { |
|
107 emitByte(bytes[i]); |
|
108 } |
|
109 cpIdx++; |
|
110 } |
|
111 |
|
112 public void emitConstantPoolClass(short index) { |
|
113 emitByte(CONSTANT_Class); |
|
114 emitShort(index); |
|
115 cpIdx++; |
|
116 } |
|
117 |
|
118 public void emitConstantPoolNameAndType(short nameIndex, short typeIndex) { |
|
119 emitByte(CONSTANT_NameAndType); |
|
120 emitShort(nameIndex); |
|
121 emitShort(typeIndex); |
|
122 cpIdx++; |
|
123 } |
|
124 |
|
125 public void emitConstantPoolFieldref |
|
126 (short classIndex, short nameAndTypeIndex) |
|
127 { |
|
128 emitByte(CONSTANT_Fieldref); |
|
129 emitShort(classIndex); |
|
130 emitShort(nameAndTypeIndex); |
|
131 cpIdx++; |
|
132 } |
|
133 |
|
134 public void emitConstantPoolMethodref |
|
135 (short classIndex, short nameAndTypeIndex) |
|
136 { |
|
137 emitByte(CONSTANT_Methodref); |
|
138 emitShort(classIndex); |
|
139 emitShort(nameAndTypeIndex); |
|
140 cpIdx++; |
|
141 } |
|
142 |
|
143 public void emitConstantPoolInterfaceMethodref |
|
144 (short classIndex, short nameAndTypeIndex) |
|
145 { |
|
146 emitByte(CONSTANT_InterfaceMethodref); |
|
147 emitShort(classIndex); |
|
148 emitShort(nameAndTypeIndex); |
|
149 cpIdx++; |
|
150 } |
|
151 |
|
152 public void emitConstantPoolString(short utf8Index) { |
|
153 emitByte(CONSTANT_String); |
|
154 emitShort(utf8Index); |
|
155 cpIdx++; |
|
156 } |
|
157 |
|
158 //---------------------------------------------------------------------- |
|
159 // Opcodes. Keeps track of maximum stack and locals. Make a new |
|
160 // assembler for each piece of assembled code, then append the |
|
161 // result to the previous assembler's class file. |
|
162 // |
|
163 |
|
164 private int stack = 0; |
|
165 private int maxStack = 0; |
|
166 private int maxLocals = 0; |
|
167 |
|
168 private void incStack() { |
|
169 setStack(stack + 1); |
|
170 } |
|
171 |
|
172 private void decStack() { |
|
173 --stack; |
|
174 } |
|
175 |
|
176 public short getMaxStack() { |
|
177 return (short) maxStack; |
|
178 } |
|
179 |
|
180 public short getMaxLocals() { |
|
181 return (short) maxLocals; |
|
182 } |
|
183 |
|
184 /** It's necessary to be able to specify the number of arguments at |
|
185 the beginning of the method (which translates to the initial |
|
186 value of max locals) */ |
|
187 public void setMaxLocals(int maxLocals) { |
|
188 this.maxLocals = maxLocals; |
|
189 } |
|
190 |
|
191 /** Needed to do flow control. Returns current stack depth. */ |
|
192 public int getStack() { |
|
193 return stack; |
|
194 } |
|
195 |
|
196 /** Needed to do flow control. */ |
|
197 public void setStack(int value) { |
|
198 stack = value; |
|
199 if (stack > maxStack) { |
|
200 maxStack = stack; |
|
201 } |
|
202 } |
|
203 |
|
204 /////////////// |
|
205 // Constants // |
|
206 /////////////// |
|
207 |
|
208 public void opc_aconst_null() { |
|
209 emitByte(opc_aconst_null); |
|
210 incStack(); |
|
211 } |
|
212 |
|
213 public void opc_sipush(short constant) { |
|
214 emitByte(opc_sipush); |
|
215 emitShort(constant); |
|
216 incStack(); |
|
217 } |
|
218 |
|
219 public void opc_ldc(byte cpIdx) { |
|
220 emitByte(opc_ldc); |
|
221 emitByte(cpIdx); |
|
222 incStack(); |
|
223 } |
|
224 |
|
225 ///////////////////////////////////// |
|
226 // Local variable loads and stores // |
|
227 ///////////////////////////////////// |
|
228 |
|
229 public void opc_iload_0() { |
|
230 emitByte(opc_iload_0); |
|
231 if (maxLocals < 1) maxLocals = 1; |
|
232 incStack(); |
|
233 } |
|
234 |
|
235 public void opc_iload_1() { |
|
236 emitByte(opc_iload_1); |
|
237 if (maxLocals < 2) maxLocals = 2; |
|
238 incStack(); |
|
239 } |
|
240 |
|
241 public void opc_iload_2() { |
|
242 emitByte(opc_iload_2); |
|
243 if (maxLocals < 3) maxLocals = 3; |
|
244 incStack(); |
|
245 } |
|
246 |
|
247 public void opc_iload_3() { |
|
248 emitByte(opc_iload_3); |
|
249 if (maxLocals < 4) maxLocals = 4; |
|
250 incStack(); |
|
251 } |
|
252 |
|
253 public void opc_lload_0() { |
|
254 emitByte(opc_lload_0); |
|
255 if (maxLocals < 2) maxLocals = 2; |
|
256 incStack(); |
|
257 incStack(); |
|
258 } |
|
259 |
|
260 public void opc_lload_1() { |
|
261 emitByte(opc_lload_1); |
|
262 if (maxLocals < 3) maxLocals = 3; |
|
263 incStack(); |
|
264 incStack(); |
|
265 } |
|
266 |
|
267 public void opc_lload_2() { |
|
268 emitByte(opc_lload_2); |
|
269 if (maxLocals < 4) maxLocals = 4; |
|
270 incStack(); |
|
271 incStack(); |
|
272 } |
|
273 |
|
274 public void opc_lload_3() { |
|
275 emitByte(opc_lload_3); |
|
276 if (maxLocals < 5) maxLocals = 5; |
|
277 incStack(); |
|
278 incStack(); |
|
279 } |
|
280 |
|
281 public void opc_fload_0() { |
|
282 emitByte(opc_fload_0); |
|
283 if (maxLocals < 1) maxLocals = 1; |
|
284 incStack(); |
|
285 } |
|
286 |
|
287 public void opc_fload_1() { |
|
288 emitByte(opc_fload_1); |
|
289 if (maxLocals < 2) maxLocals = 2; |
|
290 incStack(); |
|
291 } |
|
292 |
|
293 public void opc_fload_2() { |
|
294 emitByte(opc_fload_2); |
|
295 if (maxLocals < 3) maxLocals = 3; |
|
296 incStack(); |
|
297 } |
|
298 |
|
299 public void opc_fload_3() { |
|
300 emitByte(opc_fload_3); |
|
301 if (maxLocals < 4) maxLocals = 4; |
|
302 incStack(); |
|
303 } |
|
304 |
|
305 public void opc_dload_0() { |
|
306 emitByte(opc_dload_0); |
|
307 if (maxLocals < 2) maxLocals = 2; |
|
308 incStack(); |
|
309 incStack(); |
|
310 } |
|
311 |
|
312 public void opc_dload_1() { |
|
313 emitByte(opc_dload_1); |
|
314 if (maxLocals < 3) maxLocals = 3; |
|
315 incStack(); |
|
316 incStack(); |
|
317 } |
|
318 |
|
319 public void opc_dload_2() { |
|
320 emitByte(opc_dload_2); |
|
321 if (maxLocals < 4) maxLocals = 4; |
|
322 incStack(); |
|
323 incStack(); |
|
324 } |
|
325 |
|
326 public void opc_dload_3() { |
|
327 emitByte(opc_dload_3); |
|
328 if (maxLocals < 5) maxLocals = 5; |
|
329 incStack(); |
|
330 incStack(); |
|
331 } |
|
332 |
|
333 public void opc_aload_0() { |
|
334 emitByte(opc_aload_0); |
|
335 if (maxLocals < 1) maxLocals = 1; |
|
336 incStack(); |
|
337 } |
|
338 |
|
339 public void opc_aload_1() { |
|
340 emitByte(opc_aload_1); |
|
341 if (maxLocals < 2) maxLocals = 2; |
|
342 incStack(); |
|
343 } |
|
344 |
|
345 public void opc_aload_2() { |
|
346 emitByte(opc_aload_2); |
|
347 if (maxLocals < 3) maxLocals = 3; |
|
348 incStack(); |
|
349 } |
|
350 |
|
351 public void opc_aload_3() { |
|
352 emitByte(opc_aload_3); |
|
353 if (maxLocals < 4) maxLocals = 4; |
|
354 incStack(); |
|
355 } |
|
356 |
|
357 public void opc_aaload() { |
|
358 emitByte(opc_aaload); |
|
359 decStack(); |
|
360 } |
|
361 |
|
362 public void opc_astore_0() { |
|
363 emitByte(opc_astore_0); |
|
364 if (maxLocals < 1) maxLocals = 1; |
|
365 decStack(); |
|
366 } |
|
367 |
|
368 public void opc_astore_1() { |
|
369 emitByte(opc_astore_1); |
|
370 if (maxLocals < 2) maxLocals = 2; |
|
371 decStack(); |
|
372 } |
|
373 |
|
374 public void opc_astore_2() { |
|
375 emitByte(opc_astore_2); |
|
376 if (maxLocals < 3) maxLocals = 3; |
|
377 decStack(); |
|
378 } |
|
379 |
|
380 public void opc_astore_3() { |
|
381 emitByte(opc_astore_3); |
|
382 if (maxLocals < 4) maxLocals = 4; |
|
383 decStack(); |
|
384 } |
|
385 |
|
386 //////////////////////// |
|
387 // Stack manipulation // |
|
388 //////////////////////// |
|
389 |
|
390 public void opc_pop() { |
|
391 emitByte(opc_pop); |
|
392 decStack(); |
|
393 } |
|
394 |
|
395 public void opc_dup() { |
|
396 emitByte(opc_dup); |
|
397 incStack(); |
|
398 } |
|
399 |
|
400 public void opc_dup_x1() { |
|
401 emitByte(opc_dup_x1); |
|
402 incStack(); |
|
403 } |
|
404 |
|
405 public void opc_swap() { |
|
406 emitByte(opc_swap); |
|
407 } |
|
408 |
|
409 /////////////////////////////// |
|
410 // Widening conversions only // |
|
411 /////////////////////////////// |
|
412 |
|
413 public void opc_i2l() { |
|
414 emitByte(opc_i2l); |
|
415 } |
|
416 |
|
417 public void opc_i2f() { |
|
418 emitByte(opc_i2f); |
|
419 } |
|
420 |
|
421 public void opc_i2d() { |
|
422 emitByte(opc_i2d); |
|
423 } |
|
424 |
|
425 public void opc_l2f() { |
|
426 emitByte(opc_l2f); |
|
427 } |
|
428 |
|
429 public void opc_l2d() { |
|
430 emitByte(opc_l2d); |
|
431 } |
|
432 |
|
433 public void opc_f2d() { |
|
434 emitByte(opc_f2d); |
|
435 } |
|
436 |
|
437 ////////////////// |
|
438 // Control flow // |
|
439 ////////////////// |
|
440 |
|
441 public void opc_ifeq(short bciOffset) { |
|
442 emitByte(opc_ifeq); |
|
443 emitShort(bciOffset); |
|
444 decStack(); |
|
445 } |
|
446 |
|
447 /** Control flow with forward-reference BCI. Stack assumes |
|
448 straight-through control flow. */ |
|
449 public void opc_ifeq(Label l) { |
|
450 short instrBCI = getLength(); |
|
451 emitByte(opc_ifeq); |
|
452 l.add(this, instrBCI, getLength(), getStack() - 1); |
|
453 emitShort((short) -1); // Must be patched later |
|
454 } |
|
455 |
|
456 public void opc_if_icmpeq(short bciOffset) { |
|
457 emitByte(opc_if_icmpeq); |
|
458 emitShort(bciOffset); |
|
459 setStack(getStack() - 2); |
|
460 } |
|
461 |
|
462 /** Control flow with forward-reference BCI. Stack assumes straight |
|
463 control flow. */ |
|
464 public void opc_if_icmpeq(Label l) { |
|
465 short instrBCI = getLength(); |
|
466 emitByte(opc_if_icmpeq); |
|
467 l.add(this, instrBCI, getLength(), getStack() - 2); |
|
468 emitShort((short) -1); // Must be patched later |
|
469 } |
|
470 |
|
471 public void opc_goto(short bciOffset) { |
|
472 emitByte(opc_goto); |
|
473 emitShort(bciOffset); |
|
474 } |
|
475 |
|
476 /** Control flow with forward-reference BCI. Stack assumes straight |
|
477 control flow. */ |
|
478 public void opc_goto(Label l) { |
|
479 short instrBCI = getLength(); |
|
480 emitByte(opc_goto); |
|
481 l.add(this, instrBCI, getLength(), getStack()); |
|
482 emitShort((short) -1); // Must be patched later |
|
483 } |
|
484 |
|
485 public void opc_ifnull(short bciOffset) { |
|
486 emitByte(opc_ifnull); |
|
487 emitShort(bciOffset); |
|
488 decStack(); |
|
489 } |
|
490 |
|
491 /** Control flow with forward-reference BCI. Stack assumes straight |
|
492 control flow. */ |
|
493 public void opc_ifnull(Label l) { |
|
494 short instrBCI = getLength(); |
|
495 emitByte(opc_ifnull); |
|
496 l.add(this, instrBCI, getLength(), getStack() - 1); |
|
497 emitShort((short) -1); // Must be patched later |
|
498 decStack(); |
|
499 } |
|
500 |
|
501 public void opc_ifnonnull(short bciOffset) { |
|
502 emitByte(opc_ifnonnull); |
|
503 emitShort(bciOffset); |
|
504 decStack(); |
|
505 } |
|
506 |
|
507 /** Control flow with forward-reference BCI. Stack assumes straight |
|
508 control flow. */ |
|
509 public void opc_ifnonnull(Label l) { |
|
510 short instrBCI = getLength(); |
|
511 emitByte(opc_ifnonnull); |
|
512 l.add(this, instrBCI, getLength(), getStack() - 1); |
|
513 emitShort((short) -1); // Must be patched later |
|
514 decStack(); |
|
515 } |
|
516 |
|
517 ///////////////////////// |
|
518 // Return instructions // |
|
519 ///////////////////////// |
|
520 |
|
521 public void opc_ireturn() { |
|
522 emitByte(opc_ireturn); |
|
523 setStack(0); |
|
524 } |
|
525 |
|
526 public void opc_lreturn() { |
|
527 emitByte(opc_lreturn); |
|
528 setStack(0); |
|
529 } |
|
530 |
|
531 public void opc_freturn() { |
|
532 emitByte(opc_freturn); |
|
533 setStack(0); |
|
534 } |
|
535 |
|
536 public void opc_dreturn() { |
|
537 emitByte(opc_dreturn); |
|
538 setStack(0); |
|
539 } |
|
540 |
|
541 public void opc_areturn() { |
|
542 emitByte(opc_areturn); |
|
543 setStack(0); |
|
544 } |
|
545 |
|
546 public void opc_return() { |
|
547 emitByte(opc_return); |
|
548 setStack(0); |
|
549 } |
|
550 |
|
551 ////////////////////// |
|
552 // Field operations // |
|
553 ////////////////////// |
|
554 |
|
555 public void opc_getstatic(short fieldIndex, int fieldSizeInStackSlots) { |
|
556 emitByte(opc_getstatic); |
|
557 emitShort(fieldIndex); |
|
558 setStack(getStack() + fieldSizeInStackSlots); |
|
559 } |
|
560 |
|
561 public void opc_putstatic(short fieldIndex, int fieldSizeInStackSlots) { |
|
562 emitByte(opc_putstatic); |
|
563 emitShort(fieldIndex); |
|
564 setStack(getStack() - fieldSizeInStackSlots); |
|
565 } |
|
566 |
|
567 public void opc_getfield(short fieldIndex, int fieldSizeInStackSlots) { |
|
568 emitByte(opc_getfield); |
|
569 emitShort(fieldIndex); |
|
570 setStack(getStack() + fieldSizeInStackSlots - 1); |
|
571 } |
|
572 |
|
573 public void opc_putfield(short fieldIndex, int fieldSizeInStackSlots) { |
|
574 emitByte(opc_putfield); |
|
575 emitShort(fieldIndex); |
|
576 setStack(getStack() - fieldSizeInStackSlots - 1); |
|
577 } |
|
578 |
|
579 //////////////////////// |
|
580 // Method invocations // |
|
581 //////////////////////// |
|
582 |
|
583 /** Long and double arguments and return types count as 2 arguments; |
|
584 other values count as 1. */ |
|
585 public void opc_invokevirtual(short methodIndex, |
|
586 int numArgs, |
|
587 int numReturnValues) |
|
588 { |
|
589 emitByte(opc_invokevirtual); |
|
590 emitShort(methodIndex); |
|
591 setStack(getStack() - numArgs - 1 + numReturnValues); |
|
592 } |
|
593 |
|
594 /** Long and double arguments and return types count as 2 arguments; |
|
595 other values count as 1. */ |
|
596 public void opc_invokespecial(short methodIndex, |
|
597 int numArgs, |
|
598 int numReturnValues) |
|
599 { |
|
600 emitByte(opc_invokespecial); |
|
601 emitShort(methodIndex); |
|
602 setStack(getStack() - numArgs - 1 + numReturnValues); |
|
603 } |
|
604 |
|
605 /** Long and double arguments and return types count as 2 arguments; |
|
606 other values count as 1. */ |
|
607 public void opc_invokestatic(short methodIndex, |
|
608 int numArgs, |
|
609 int numReturnValues) |
|
610 { |
|
611 emitByte(opc_invokestatic); |
|
612 emitShort(methodIndex); |
|
613 setStack(getStack() - numArgs + numReturnValues); |
|
614 } |
|
615 |
|
616 /** Long and double arguments and return types count as 2 arguments; |
|
617 other values count as 1. */ |
|
618 public void opc_invokeinterface(short methodIndex, |
|
619 int numArgs, |
|
620 byte count, |
|
621 int numReturnValues) |
|
622 { |
|
623 emitByte(opc_invokeinterface); |
|
624 emitShort(methodIndex); |
|
625 emitByte(count); |
|
626 emitByte((byte) 0); |
|
627 setStack(getStack() - numArgs - 1 + numReturnValues); |
|
628 } |
|
629 |
|
630 ////////////////// |
|
631 // Array length // |
|
632 ////////////////// |
|
633 |
|
634 public void opc_arraylength() { |
|
635 emitByte(opc_arraylength); |
|
636 } |
|
637 |
|
638 ///////// |
|
639 // New // |
|
640 ///////// |
|
641 |
|
642 public void opc_new(short classIndex) { |
|
643 emitByte(opc_new); |
|
644 emitShort(classIndex); |
|
645 incStack(); |
|
646 } |
|
647 |
|
648 //////////// |
|
649 // Athrow // |
|
650 //////////// |
|
651 |
|
652 public void opc_athrow() { |
|
653 emitByte(opc_athrow); |
|
654 setStack(1); |
|
655 } |
|
656 |
|
657 ////////////////////////////// |
|
658 // Checkcast and instanceof // |
|
659 ////////////////////////////// |
|
660 |
|
661 /** Assumes the checkcast succeeds */ |
|
662 public void opc_checkcast(short classIndex) { |
|
663 emitByte(opc_checkcast); |
|
664 emitShort(classIndex); |
|
665 } |
|
666 |
|
667 public void opc_instanceof(short classIndex) { |
|
668 emitByte(opc_instanceof); |
|
669 emitShort(classIndex); |
|
670 } |
|
671 } |