1 /*
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 2002 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 */
54 package net.sf.cglib.core;
55
56 import java.io.*;
57 import java.lang.reflect.Method;
58 import java.util.*;
59 import org.objectweb.asm.*;
60
61 /***
62 * @author Juozas Baliuka, Chris Nokleberg
63 */
64 public class CodeEmitter extends RemappingCodeVisitor {
65 private static final Signature BOOLEAN_VALUE =
66 TypeUtils.parseSignature("boolean booleanValue()");
67 private static final Signature CHAR_VALUE =
68 TypeUtils.parseSignature("char charValue()");
69 private static final Signature LONG_VALUE =
70 TypeUtils.parseSignature("long longValue()");
71 private static final Signature DOUBLE_VALUE =
72 TypeUtils.parseSignature("double doubleValue()");
73 private static final Signature FLOAT_VALUE =
74 TypeUtils.parseSignature("float floatValue()");
75 private static final Signature INT_VALUE =
76 TypeUtils.parseSignature("int intValue()");
77 private static final Signature CSTRUCT_NULL =
78 TypeUtils.parseConstructor("");
79 private static final Signature CSTRUCT_STRING =
80 TypeUtils.parseConstructor("String");
81
82 public static final int ADD = Constants.IADD;
83 public static final int MUL = Constants.IMUL;
84 public static final int XOR = Constants.IXOR;
85 public static final int USHR = Constants.IUSHR;
86 public static final int SUB = Constants.ISUB;
87 public static final int DIV = Constants.IDIV;
88 public static final int NEG = Constants.INEG;
89 public static final int REM = Constants.IREM;
90 public static final int AND = Constants.IAND;
91 public static final int OR = Constants.IOR;
92
93 public static final int GT = Constants.IFGT;
94 public static final int LT = Constants.IFLT;
95 public static final int GE = Constants.IFGE;
96 public static final int LE = Constants.IFLE;
97 public static final int NE = Constants.IFNE;
98 public static final int EQ = Constants.IFEQ;
99
100 private ClassEmitter ce;
101 private State state;
102
103 private static class State {
104 int access;
105 Signature sig;
106 Type[] argumentTypes;
107 int localOffset;
108 Type[] exceptionTypes;
109
110 State(int access, Signature sig, Type[] exceptionTypes) {
111 this.access = access;
112 this.sig = sig;
113 this.exceptionTypes = exceptionTypes;
114 localOffset = TypeUtils.isStatic(access) ? 0 : 1;
115 argumentTypes = sig.getArgumentTypes();
116 }
117 }
118
119 CodeEmitter(ClassEmitter ce, CodeVisitor cv, int access, Signature sig, Type[] exceptionTypes) {
120 super(cv, access, sig.getArgumentTypes());
121 this.ce = ce;
122 state = new State(access, sig, exceptionTypes);
123 }
124
125 public CodeEmitter(CodeEmitter wrap) {
126 super(wrap);
127 this.ce = wrap.ce;
128 this.state = wrap.state;
129 }
130
131 public boolean isStaticHook() {
132 return false;
133 }
134
135 public Signature getSignature() {
136 return state.sig;
137 }
138
139 public Type getReturnType() {
140 return state.sig.getReturnType();
141 }
142
143 /* wait until these are needed
144 public Type[] getArgumentTypes() {
145 return state.argumentTypes;
146 }
147
148 public Type[] getExceptionTypes() {
149 return state.getExceptionTypes();
150 }
151 */
152
153 public ClassEmitter getClassEmitter() {
154 return ce;
155 }
156
157 public void end_method() {
158 visitMaxs(0, 0);
159 }
160
161 public Block begin_block() {
162 return new Block(this);
163 }
164
165 public void catch_exception(Block block, Type exception) {
166 if (block.getEnd() == null) {
167 throw new IllegalStateException("end of block is unset");
168 }
169 cv.visitTryCatchBlock(block.getStart(),
170 block.getEnd(),
171 mark(),
172 exception.getInternalName());
173 }
174
175 public void goTo(Label label) { cv.visitJumpInsn(Constants.GOTO, label); }
176 public void ifnull(Label label) { cv.visitJumpInsn(Constants.IFNULL, label); }
177 public void ifnonnull(Label label) { cv.visitJumpInsn(Constants.IFNONNULL, label); }
178
179 public void if_jump(int mode, Label label) {
180 cv.visitJumpInsn(mode, label);
181 }
182
183 public void if_icmp(int mode, Label label) {
184 if_cmp(Type.INT_TYPE, mode, label);
185 }
186
187 public void if_cmp(Type type, int mode, Label label) {
188 int intOp = -1;
189 int jumpmode = mode;
190 switch (mode) {
191 case GE: jumpmode = LT; break;
192 case LE: jumpmode = GT; break;
193 }
194 switch (type.getSort()) {
195 case Type.LONG:
196 cv.visitInsn(Constants.LCMP);
197 break;
198 case Type.DOUBLE:
199 cv.visitInsn(Constants.DCMPG);
200 break;
201 case Type.FLOAT:
202 cv.visitInsn(Constants.FCMPG);
203 break;
204 case Type.ARRAY:
205 case Type.OBJECT:
206 switch (mode) {
207 case EQ:
208 cv.visitJumpInsn(Constants.IF_ACMPEQ, label);
209 return;
210 case NE:
211 cv.visitJumpInsn(Constants.IF_ACMPNE, label);
212 return;
213 }
214 throw new IllegalArgumentException("Bad comparison for type " + type);
215 default:
216 switch (mode) {
217 case EQ: intOp = Constants.IF_ICMPEQ; break;
218 case NE: intOp = Constants.IF_ICMPNE; break;
219 case GE: swap(); /* fall through */
220 case LT: intOp = Constants.IF_ICMPLT; break;
221 case LE: swap(); /* fall through */
222 case GT: intOp = Constants.IF_ICMPGT; break;
223 }
224 cv.visitJumpInsn(intOp, label);
225 return;
226 }
227 if_jump(jumpmode, label);
228 }
229
230 public void pop() { cv.visitInsn(Constants.POP); }
231 public void pop2() { cv.visitInsn(Constants.POP2); }
232 public void dup() { cv.visitInsn(Constants.DUP); }
233 public void dup2() { cv.visitInsn(Constants.DUP2); }
234 public void dup_x1() { cv.visitInsn(Constants.DUP_X1); }
235 public void dup_x2() { cv.visitInsn(Constants.DUP_X2); }
236 public void dup2_x1() { cv.visitInsn(Constants.DUP2_X1); }
237 public void dup2_x2() { cv.visitInsn(Constants.DUP2_X2); }
238 public void swap() { cv.visitInsn(Constants.SWAP); }
239 public void aconst_null() { cv.visitInsn(Constants.ACONST_NULL); }
240
241 public void swap(Type prev, Type type) {
242 if (type.getSize() == 1) {
243 if (prev.getSize() == 1) {
244 swap(); // same as dup_x1(), pop();
245 } else {
246 dup_x2();
247 pop();
248 }
249 } else {
250 if (prev.getSize() == 1) {
251 dup2_x1();
252 pop2();
253 } else {
254 dup2_x2();
255 pop2();
256 }
257 }
258 }
259
260 public void monitorenter() { cv.visitInsn(Constants.MONITORENTER); }
261 public void monitorexit() { cv.visitInsn(Constants.MONITOREXIT); }
262
263 public void math(int op, Type type) { cv.visitInsn(type.getOpcode(op)); }
264
265 public void array_load(Type type) { cv.visitInsn(type.getOpcode(Constants.IALOAD)); }
266 public void array_store(Type type) { cv.visitInsn(type.getOpcode(Constants.IASTORE)); }
267
268 /***
269 * Casts from one primitive numeric type to another
270 */
271 public void cast_numeric(Type from, Type to) {
272 if (from != to) {
273 if (from == Type.DOUBLE_TYPE) {
274 if (to == Type.FLOAT_TYPE) {
275 cv.visitInsn(Constants.D2F);
276 } else if (to == Type.LONG_TYPE) {
277 cv.visitInsn(Constants.D2L);
278 } else {
279 cv.visitInsn(Constants.D2I);
280 cast_numeric(Type.INT_TYPE, to);
281 }
282 } else if (from == Type.FLOAT_TYPE) {
283 if (to == Type.DOUBLE_TYPE) {
284 cv.visitInsn(Constants.F2D);
285 } else if (to == Type.LONG_TYPE) {
286 cv.visitInsn(Constants.F2L);
287 } else {
288 cv.visitInsn(Constants.F2I);
289 cast_numeric(Type.INT_TYPE, to);
290 }
291 } else if (from == Type.LONG_TYPE) {
292 if (to == Type.DOUBLE_TYPE) {
293 cv.visitInsn(Constants.L2D);
294 } else if (to == Type.FLOAT_TYPE) {
295 cv.visitInsn(Constants.L2F);
296 } else {
297 cv.visitInsn(Constants.L2I);
298 cast_numeric(Type.INT_TYPE, to);
299 }
300 } else {
301 if (to == Type.BYTE_TYPE) {
302 cv.visitInsn(Constants.I2B);
303 } else if (to == Type.CHAR_TYPE) {
304 cv.visitInsn(Constants.I2C);
305 } else if (to == Type.DOUBLE_TYPE) {
306 cv.visitInsn(Constants.I2D);
307 } else if (to == Type.FLOAT_TYPE) {
308 cv.visitInsn(Constants.I2F);
309 } else if (to == Type.LONG_TYPE) {
310 cv.visitInsn(Constants.I2L);
311 } else if (to == Type.SHORT_TYPE) {
312 cv.visitInsn(Constants.I2S);
313 }
314 }
315 }
316 }
317
318 public void push(int i) {
319 if (i < -1) {
320 cv.visitLdcInsn(new Integer(i));
321 } else if (i <= 5) {
322 cv.visitInsn(TypeUtils.ICONST(i));
323 } else if (i <= Byte.MAX_VALUE) {
324 cv.visitIntInsn(Constants.BIPUSH, i);
325 } else if (i <= Short.MAX_VALUE) {
326 cv.visitIntInsn(Constants.SIPUSH, i);
327 } else {
328 cv.visitLdcInsn(new Integer(i));
329 }
330 }
331
332 public void push(long value) {
333 if (value == 0L || value == 1L) {
334 cv.visitInsn(TypeUtils.LCONST(value));
335 } else {
336 cv.visitLdcInsn(new Long(value));
337 }
338 }
339
340 public void push(float value) {
341 if (value == 0f || value == 1f || value == 2f) {
342 cv.visitInsn(TypeUtils.FCONST(value));
343 } else {
344 cv.visitLdcInsn(new Float(value));
345 }
346 }
347 public void push(double value) {
348 if (value == 0d || value == 1d) {
349 cv.visitInsn(TypeUtils.DCONST(value));
350 } else {
351 cv.visitLdcInsn(new Double(value));
352 }
353 }
354
355 public void push(String value) {
356 cv.visitLdcInsn(value);
357 }
358
359 public void newarray() {
360 newarray(Constants.TYPE_OBJECT);
361 }
362
363 public void newarray(Type type) {
364 if (TypeUtils.isPrimitive(type)) {
365 cv.visitIntInsn(Constants.NEWARRAY, TypeUtils.NEWARRAY(type));
366 } else {
367 emit_type(Constants.ANEWARRAY, type);
368 }
369 }
370
371 public void arraylength() {
372 cv.visitInsn(Constants.ARRAYLENGTH);
373 }
374
375 public void load_this() {
376 if (TypeUtils.isStatic(state.access)) {
377 throw new IllegalStateException("no 'this' pointer within static method");
378 }
379 cv.visitVarInsn(Constants.ALOAD, 0);
380 }
381
382 /***
383 * Pushes all of the arguments of the current method onto the stack.
384 */
385 public void load_args() {
386 load_args(0, state.argumentTypes.length);
387 }
388
389 /***
390 * Pushes the specified argument of the current method onto the stack.
391 * @param index the zero-based index into the argument list
392 */
393 public void load_arg(int index) {
394 load_local(state.argumentTypes[index],
395 state.localOffset + skipArgs(index));
396 }
397
398 // zero-based (see load_this)
399 public void load_args(int fromArg, int count) {
400 int pos = state.localOffset + skipArgs(fromArg);
401 for (int i = 0; i < count; i++) {
402 Type t = state.argumentTypes[fromArg + i];
403 load_local(t, pos);
404 pos += t.getSize();
405 }
406 }
407
408 private int skipArgs(int numArgs) {
409 int amount = 0;
410 for (int i = 0; i < numArgs; i++) {
411 amount += state.argumentTypes[i].getSize();
412 }
413 return amount;
414 }
415
416 private void load_local(Type t, int pos) {
417 // TODO: make t == null ok?
418 cv.visitVarInsn(t.getOpcode(Constants.ILOAD), pos);
419 }
420
421 private void store_local(Type t, int pos) {
422 // TODO: make t == null ok?
423 cv.visitVarInsn(t.getOpcode(Constants.ISTORE), pos);
424 }
425
426 public void iinc(Local local, int amount) {
427 cv.visitIincInsn(local.getIndex(), amount);
428 }
429
430 public void store_local(Local local) {
431 store_local(local.getType(), local.getIndex());
432 }
433
434 public void load_local(Local local) {
435 load_local(local.getType(), local.getIndex());
436 }
437
438 public void return_value() {
439 cv.visitInsn(state.sig.getReturnType().getOpcode(Constants.IRETURN));
440 }
441
442 public void getfield(String name) {
443 ClassEmitter.FieldInfo info = ce.getFieldInfo(name);
444 int opcode = TypeUtils.isStatic(info.access) ? Constants.GETSTATIC : Constants.GETFIELD;
445 emit_field(opcode, ce.getClassType(), name, info.type);
446 }
447
448 public void putfield(String name) {
449 ClassEmitter.FieldInfo info = ce.getFieldInfo(name);
450 int opcode = TypeUtils.isStatic(info.access) ? Constants.PUTSTATIC : Constants.PUTFIELD;
451 emit_field(opcode, ce.getClassType(), name, info.type);
452 }
453
454 public void super_getfield(String name, Type type) {
455 emit_field(Constants.GETFIELD, ce.getSuperType(), name, type);
456 }
457
458 public void super_putfield(String name, Type type) {
459 emit_field(Constants.PUTFIELD, ce.getSuperType(), name, type);
460 }
461
462 public void super_getstatic(String name, Type type) {
463 emit_field(Constants.GETSTATIC, ce.getSuperType(), name, type);
464 }
465
466 public void super_putstatic(String name, Type type) {
467 emit_field(Constants.PUTSTATIC, ce.getSuperType(), name, type);
468 }
469
470 public void getfield(Type owner, String name, Type type) {
471 emit_field(Constants.GETFIELD, owner, name, type);
472 }
473
474 public void putfield(Type owner, String name, Type type) {
475 emit_field(Constants.PUTFIELD, owner, name, type);
476 }
477
478 public void getstatic(Type owner, String name, Type type) {
479 emit_field(Constants.GETSTATIC, owner, name, type);
480 }
481
482 public void putstatic(Type owner, String name, Type type) {
483 emit_field(Constants.PUTSTATIC, owner, name, type);
484 }
485
486 // package-protected for EmitUtils, try to fix
487 void emit_field(int opcode, Type ctype, String name, Type ftype) {
488 cv.visitFieldInsn(opcode,
489 ctype.getInternalName(),
490 name,
491 ftype.getDescriptor());
492 }
493
494 public void super_invoke() {
495 super_invoke(state.sig);
496 }
497
498 public void super_invoke(Signature sig) {
499 emit_invoke(Constants.INVOKESPECIAL, ce.getSuperType(), sig);
500 }
501
502 public void invoke_constructor(Type type) {
503 invoke_constructor(type, CSTRUCT_NULL);
504 }
505
506 public void super_invoke_constructor() {
507 invoke_constructor(ce.getSuperType());
508 }
509
510 public void invoke_constructor_this() {
511 invoke_constructor(ce.getClassType());
512 }
513
514 private void emit_invoke(int opcode, Type type, Signature sig) {
515 if (sig.getName().equals(Constants.CONSTRUCTOR_NAME) &&
516 ((opcode == Constants.INVOKEVIRTUAL) ||
517 (opcode == Constants.INVOKESTATIC))) {
518 // TODO: error
519 }
520 cv.visitMethodInsn(opcode,
521 type.getInternalName(),
522 sig.getName(),
523 sig.getDescriptor());
524 }
525
526 public void invoke_interface(Type owner, Signature sig) {
527 emit_invoke(Constants.INVOKEINTERFACE, owner, sig);
528 }
529
530 public void invoke_virtual(Type owner, Signature sig) {
531 emit_invoke(Constants.INVOKEVIRTUAL, owner, sig);
532 }
533
534 public void invoke_static(Type owner, Signature sig) {
535 emit_invoke(Constants.INVOKESTATIC, owner, sig);
536 }
537
538 public void invoke_virtual_this(Signature sig) {
539 invoke_virtual(ce.getClassType(), sig);
540 }
541
542 public void invoke_static_this(Signature sig) {
543 invoke_static(ce.getClassType(), sig);
544 }
545
546 public void invoke_constructor(Type type, Signature sig) {
547 emit_invoke(Constants.INVOKESPECIAL, type, sig);
548 }
549
550 public void invoke_constructor_this(Signature sig) {
551 invoke_constructor(ce.getClassType(), sig);
552 }
553
554 public void super_invoke_constructor(Signature sig) {
555 invoke_constructor(ce.getSuperType(), sig);
556 }
557
558 public void new_instance_this() {
559 new_instance(ce.getClassType());
560 }
561
562 public void new_instance(Type type) {
563 emit_type(Constants.NEW, type);
564 }
565
566 private void emit_type(int opcode, Type type) {
567 String desc;
568 if (TypeUtils.isArray(type)) {
569 desc = type.getDescriptor();
570 } else {
571 desc = type.getInternalName();
572 }
573 cv.visitTypeInsn(opcode, desc);
574 }
575
576 public void aaload(int index) {
577 push(index);
578 aaload();
579 }
580
581 public void aaload() { cv.visitInsn(Constants.AALOAD); }
582 public void aastore() { cv.visitInsn(Constants.AASTORE); }
583 public void athrow() { cv.visitInsn(Constants.ATHROW); }
584
585 public Label make_label() {
586 return new Label();
587 }
588
589 public Local make_local() {
590 return make_local(Constants.TYPE_OBJECT);
591 }
592
593 public Local make_local(Type type) {
594 return new Local(nextLocal(type.getSize()), type);
595 }
596
597 public void checkcast_this() {
598 checkcast(ce.getClassType());
599 }
600
601 public void checkcast(Type type) {
602 if (!type.equals(Constants.TYPE_OBJECT)) {
603 emit_type(Constants.CHECKCAST, type);
604 }
605 }
606
607 public void instance_of(Type type) {
608 emit_type(Constants.INSTANCEOF, type);
609 }
610
611 public void instance_of_this() {
612 instance_of(ce.getClassType());
613 }
614
615 public void process_switch(int[] keys, ProcessSwitchCallback callback) {
616 float density;
617 if (keys.length == 0) {
618 density = 0;
619 } else {
620 density = (float)keys.length / (keys[keys.length - 1] - keys[0] + 1);
621 }
622 process_switch(keys, callback, density >= 0.5f);
623 }
624
625 public void process_switch(int[] keys, ProcessSwitchCallback callback, boolean useTable) {
626 if (!isSorted(keys))
627 throw new IllegalArgumentException("keys to switch must be sorted ascending");
628 Label def = make_label();
629 Label end = make_label();
630
631 try {
632 if (keys.length > 0) {
633 int len = keys.length;
634 int min = keys[0];
635 int max = keys[len - 1];
636 int range = max - min + 1;
637
638 if (useTable) {
639 Label[] labels = new Label[range];
640 Arrays.fill(labels, def);
641 for (int i = 0; i < len; i++) {
642 labels[keys[i] - min] = make_label();
643 }
644 cv.visitTableSwitchInsn(min, max, def, labels);
645 for (int i = 0; i < range; i++) {
646 Label label = labels[i];
647 if (label != def) {
648 mark(label);
649 callback.processCase(i + min, end);
650 }
651 }
652 } else {
653 Label[] labels = new Label[len];
654 for (int i = 0; i < len; i++) {
655 labels[i] = make_label();
656 }
657 cv.visitLookupSwitchInsn(def, keys, labels);
658 for (int i = 0; i < len; i++) {
659 mark(labels[i]);
660 callback.processCase(keys[i], end);
661 }
662 }
663 }
664
665 mark(def);
666 callback.processDefault();
667 mark(end);
668
669 } catch (RuntimeException e) {
670 throw e;
671 } catch (Error e) {
672 throw e;
673 } catch (Exception e) {
674 throw new CodeGenerationException(e);
675 }
676 }
677
678 private static boolean isSorted(int[] keys) {
679 for (int i = 1; i < keys.length; i++) {
680 if (keys[i] < keys[i - 1])
681 return false;
682 }
683 return true;
684 }
685
686 public void mark(Label label) {
687 cv.visitLabel(label);
688 }
689
690 Label mark() {
691 Label label = make_label();
692 cv.visitLabel(label);
693 return label;
694 }
695
696 public void push(boolean value) {
697 push(value ? 1 : 0);
698 }
699
700 /***
701 * Toggles the integer on the top of the stack from 1 to 0 or vice versa
702 */
703 public void not() {
704 push(1);
705 math(XOR, Type.INT_TYPE);
706 }
707
708 public void throw_exception(Type type, String msg) {
709 new_instance(type);
710 dup();
711 push(msg);
712 invoke_constructor(type, CSTRUCT_STRING);
713 athrow();
714 }
715
716 /***
717 * If the argument is a primitive class, replaces the primitive value
718 * on the top of the stack with the wrapped (Object) equivalent. For
719 * example, char -> Character.
720 * If the class is Void, a null is pushed onto the stack instead.
721 * @param type the class indicating the current type of the top stack value
722 */
723 public void box(Type type) {
724 if (TypeUtils.isPrimitive(type)) {
725 if (type == Type.VOID_TYPE) {
726 aconst_null();
727 } else {
728 Type boxed = TypeUtils.getBoxedType(type);
729 new_instance(boxed);
730 if (type.getSize() == 2) {
731 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
732 dup_x2();
733 dup_x2();
734 pop();
735 } else {
736 // p -> po -> opo -> oop -> o
737 dup_x1();
738 swap();
739 }
740 invoke_constructor(boxed, new Signature(Constants.CONSTRUCTOR_NAME, Type.VOID_TYPE, new Type[]{ type }));
741 }
742 }
743 }
744
745 /***
746 * If the argument is a primitive class, replaces the object
747 * on the top of the stack with the unwrapped (primitive)
748 * equivalent. For example, Character -> char.
749 * @param type the class indicating the desired type of the top stack value
750 * @return true if the value was unboxed
751 */
752 public void unbox(Type type) {
753 Type t = Constants.TYPE_NUMBER;
754 Signature sig = null;
755 switch (type.getSort()) {
756 case Type.VOID:
757 return;
758 case Type.CHAR:
759 t = Constants.TYPE_CHARACTER;
760 sig = CHAR_VALUE;
761 break;
762 case Type.BOOLEAN:
763 t = Constants.TYPE_BOOLEAN;
764 sig = BOOLEAN_VALUE;
765 break;
766 case Type.DOUBLE:
767 sig = DOUBLE_VALUE;
768 break;
769 case Type.FLOAT:
770 sig = FLOAT_VALUE;
771 break;
772 case Type.LONG:
773 sig = LONG_VALUE;
774 break;
775 case Type.INT:
776 case Type.SHORT:
777 case Type.BYTE:
778 sig = INT_VALUE;
779 }
780
781 if (sig == null) {
782 checkcast(type);
783 } else {
784 checkcast(t);
785 invoke_virtual(t, sig);
786 }
787 }
788
789 /***
790 * Allocates and fills an Object[] array with the arguments to the
791 * current method. Primitive values are inserted as their boxed
792 * (Object) equivalents.
793 */
794 public void create_arg_array() {
795 /* generates:
796 Object[] args = new Object[]{ arg1, new Integer(arg2) };
797 */
798
799 push(state.argumentTypes.length);
800 newarray();
801 for (int i = 0; i < state.argumentTypes.length; i++) {
802 dup();
803 push(i);
804 load_arg(i);
805 box(state.argumentTypes[i]);
806 aastore();
807 }
808 }
809
810
811 /***
812 * Pushes a zero onto the stack if the argument is a primitive class, or a null otherwise.
813 */
814 public void zero_or_null(Type type) {
815 if (TypeUtils.isPrimitive(type)) {
816 switch (type.getSort()) {
817 case Type.DOUBLE:
818 push(0d);
819 break;
820 case Type.LONG:
821 push(0L);
822 break;
823 case Type.FLOAT:
824 push(0f);
825 break;
826 case Type.VOID:
827 aconst_null();
828 default:
829 push(0);
830 }
831 } else {
832 aconst_null();
833 }
834 }
835
836 /***
837 * Unboxes the object on the top of the stack. If the object is null, the
838 * unboxed primitive value becomes zero.
839 */
840 public void unbox_or_zero(Type type) {
841 if (TypeUtils.isPrimitive(type)) {
842 if (type != Type.VOID_TYPE) {
843 Label nonNull = make_label();
844 Label end = make_label();
845 dup();
846 ifnonnull(nonNull);
847 pop();
848 zero_or_null(type);
849 goTo(end);
850 mark(nonNull);
851 unbox(type);
852 mark(end);
853 }
854 } else {
855 checkcast(type);
856 }
857 }
858
859 public void visitMaxs(int maxStack, int maxLocals) {
860 if (!TypeUtils.isAbstract(state.access)) {
861 cv.visitMaxs(0, 0);
862 }
863 }
864
865 public void invoke(Method method) {
866 Class declaring = method.getDeclaringClass();
867 Type owner = Type.getType(declaring);
868 Signature sig = ReflectUtils.getSignature(method);
869 if (declaring.isInterface()) {
870 invoke_interface(owner, sig);
871 } else if (TypeUtils.isStatic(method.getModifiers())) {
872 invoke_static(owner, sig);
873 } else {
874 invoke_virtual(owner, sig);
875 }
876 }
877
878 public void define_attribute(Attribute attrs) {
879 cv.visitAttribute(attrs);
880 }
881 }
This page was automatically generated by Maven