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;
55
56 import java.io.*;
57 import java.lang.reflect.*;
58 import java.util.*;
59 /***
60 * Abstract base class for code generators
61 * @author baliuka
62 */
63 abstract class CodeGenerator {
64 private static final String FIND_CLASS = "CGLIB$findClass";
65 private static final Map primitiveMethods = new HashMap();
66 private static final Map primitiveToWrapper = new HashMap();
67 private static String debugLocation;
68 private static RuntimePermission DEFINE_CGLIB_CLASS_IN_JAVA_PACKAGE_PERMISSION =
69 new RuntimePermission("defineCGLIBClassInJavaPackage");
70
71 private final ClassLoader loader;
72 private String methodName;
73 private Class returnType;
74 private Class[] parameterTypes;
75 private Class superclass;
76 private boolean needsFindClass;
77
78 private Map locals = new HashMap();
79 private Map localTypes = new HashMap();
80 private int nextLocal;
81 private boolean inMethod;
82
83 private LinkedList handlerStack = new LinkedList();
84 private LinkedList handlerList = new LinkedList();
85
86 private Map fieldInfo = new HashMap();
87 private String className;
88
89 private CodeGeneratorBackend backend;
90 private boolean debug = false;
91
92 protected CodeGenerator(String className, Class superclass, ClassLoader loader) {
93 if (loader == null) {
94 throw new IllegalArgumentException("ClassLoader is required");
95 }
96 this.loader = loader;
97 this.className = className;
98 this.superclass = superclass;
99 backend = new BCELBackend(className, superclass);
100 }
101
102 protected void setInterface(boolean flag) {
103 backend.setInterface(flag);
104 }
105
106 protected void setDebug(boolean debug) {
107 this.debug = debug;
108 backend.setDebug(debug);
109 }
110
111 protected String getClassName() {
112 return className;
113 }
114
115 protected Class getSuperclass() {
116 return superclass;
117 }
118
119 public static void setDebugLocation(String debugLocation) {
120 CodeGenerator.debugLocation = debugLocation;
121 }
122
123 /***
124 * method used to generate code
125 */
126 abstract protected void generate() throws Exception;
127
128 public Class define() {
129 try {
130 generate();
131 if (needsFindClass) {
132 generateFindClass();
133 }
134
135 byte[] bytes = backend.getBytes();
136 if (debugLocation != null) {
137 OutputStream out = new FileOutputStream(new File(new File(debugLocation), className + ".cglib"));
138 out.write(bytes);
139 out.close();
140 }
141 return defineClass(className, bytes, loader);
142 } catch (RuntimeException e) {
143 throw e;
144 } catch (Exception e) {
145 throw new CodeGenerationException(e);
146 } catch (Error e) {
147 throw e;
148 } catch (Throwable t) {
149 // almost impossible
150 throw new CodeGenerationException(t);
151 }
152 }
153
154
155 private static Class defineClass(String className, byte b[], ClassLoader loader)
156 throws Exception {
157
158 Method m = MethodConstants.DEFINE_CLASS;
159 // protected method invocaton
160 boolean flag = m.isAccessible();
161 m.setAccessible(true);
162
163 SecurityManager sm = System.getSecurityManager();
164 if ( className != null && className.startsWith("java.") && sm != null ) {
165 sm.checkPermission( DEFINE_CGLIB_CLASS_IN_JAVA_PACKAGE_PERMISSION );
166 }
167
168 //way depricated in jdk to define classes,
169 // doe's not throws SecurityException if class name starts with "java."
170 Object[] args = new Object[]{ b, new Integer(0), new Integer(b.length) };
171 Class result = (Class)m.invoke(loader, args);
172 m.setAccessible(flag);
173
174 return result;
175 }
176
177 static {
178 primitiveMethods.put(Boolean.TYPE, MethodConstants.BOOLEAN_VALUE);
179 primitiveMethods.put(Character.TYPE, MethodConstants.CHAR_VALUE);
180 primitiveMethods.put(Long.TYPE, MethodConstants.LONG_VALUE);
181 primitiveMethods.put(Double.TYPE, MethodConstants.DOUBLE_VALUE);
182 primitiveMethods.put(Float.TYPE, MethodConstants.FLOAT_VALUE);
183 primitiveMethods.put(Short.TYPE, MethodConstants.INT_VALUE);
184 primitiveMethods.put(Integer.TYPE, MethodConstants.INT_VALUE);
185 primitiveMethods.put(Byte.TYPE, MethodConstants.INT_VALUE);
186
187 primitiveToWrapper.put(Boolean.TYPE, Boolean.class);
188 primitiveToWrapper.put(Character.TYPE, Character.class);
189 primitiveToWrapper.put(Long.TYPE, Long.class);
190 primitiveToWrapper.put(Double.TYPE, Double.class);
191 primitiveToWrapper.put(Float.TYPE, Float.class);
192 primitiveToWrapper.put(Short.TYPE, Short.class);
193 primitiveToWrapper.put(Integer.TYPE, Integer.class);
194 primitiveToWrapper.put(Byte.TYPE, Byte.class);
195 }
196
197 protected void declare_interfaces(Class[] interfaces) {
198 for (int i = 0; i < interfaces.length; i++) {
199 declare_interface(interfaces[i]);
200 }
201 }
202
203 protected void declare_interface(Class iface) {
204 backend.declare_interface(iface);
205 }
206
207 protected void begin_method(int modifiers, Class returnType, String methodName,
208 Class[] parameterTypes, Class[] exceptionTypes) {
209 checkInMethod();
210 this.methodName = methodName;
211 this.returnType = returnType;
212 this.parameterTypes = parameterTypes;
213 backend.begin_method(modifiers, returnType, methodName, parameterTypes, exceptionTypes);
214 setNextLocal();
215 }
216
217 protected int getDefaultModifiers(Method method) {
218 int modifiers = method.getModifiers();
219 return Modifier.FINAL
220 | (modifiers
221 & ~Modifier.ABSTRACT
222 & ~Modifier.NATIVE
223 & ~Modifier.SYNCHRONIZED);
224 }
225
226 protected void begin_method(Method method) {
227 begin_method(method, getDefaultModifiers(method));
228 }
229
230 protected void begin_method(Method method, int modifiers) {
231 begin_method(modifiers, method.getReturnType(), method.getName(),
232 method.getParameterTypes(), method.getExceptionTypes());
233 }
234
235 protected void begin_constructor(Constructor constructor) {
236 begin_constructor(constructor.getParameterTypes());
237 }
238
239 protected void begin_constructor() {
240 begin_constructor(Constants.TYPES_EMPTY);
241 }
242
243 protected void begin_constructor(Class[] parameterTypes) {
244 checkInMethod();
245 this.returnType = Void.TYPE;
246 this.parameterTypes = parameterTypes;
247 backend.begin_constructor(parameterTypes);
248 setNextLocal();
249 }
250
251 protected void begin_static() {
252 checkInMethod();
253 this.returnType = Void.TYPE;
254 this.parameterTypes = Constants.TYPES_EMPTY;
255 backend.begin_static();
256 setNextLocal();
257 }
258
259 private void checkInMethod() {
260 if (inMethod) {
261 throw new IllegalStateException("cannot nest methods");
262 }
263 }
264
265 private void setNextLocal() {
266 nextLocal = 1 + getStackSize(parameterTypes);
267 }
268
269 protected void end_method() {
270 backend.end_method();
271 parameterTypes = null;
272 returnType = null;
273 methodName = null;
274 locals.clear();
275 localTypes.clear();
276 if (handlerStack.size() > 0) {
277 throw new IllegalStateException("unclosed exception handler");
278 }
279 handlerList.clear();
280 inMethod = false;
281 }
282
283 /***
284 * Allocates and fills an Object[] array with the arguments to the
285 * current method. Primitive values are inserted as their boxed
286 * (Object) equivalents.
287 */
288 protected void create_arg_array() {
289 /* generates:
290 Object[] args = new Object[]{ arg1, new Integer(arg2) };
291 */
292 push(parameterTypes.length);
293 newarray();
294 for (int i = 0; i < parameterTypes.length; i++) {
295 dup();
296 push(i);
297 load_arg(i);
298 box(parameterTypes[i]);
299 aastore();
300 }
301 }
302
303 protected Object begin_handler() {
304 int ref = handlerList.size();
305 Object[] range = new Object[]{ backend.start_range(), null };
306 handlerList.add(range);
307 handlerStack.add(range);
308 return new Integer(ref);
309 }
310
311 protected void end_handler() {
312 if (handlerStack.size() == 0) {
313 throw new IllegalStateException("mismatched handler boundaries");
314 }
315 Object[] range = (Object[])handlerStack.removeLast();
316 range[1] = backend.end_range();
317 }
318
319 protected void handle_exception(Object handler, Class exceptionType) {
320 int ref = ((Integer)handler).intValue();
321 if (handlerList.size() <= ref) {
322 throw new IllegalArgumentException("unknown handler reference: " + ref);
323 }
324 Object[] range = (Object[])handlerList.get(ref);
325 if (range[1] == null) {
326 throw new IllegalStateException("end of handler is unset");
327 }
328 backend.handle_exception(range[0], range[1], exceptionType);
329 }
330
331 protected void ifeq(Object label) { backend.ifeq(label); }
332 protected void ifne(Object label) { backend.ifne(label); }
333 protected void iflt(Object label) { backend.iflt(label); }
334 protected void ifge(Object label) { backend.ifge(label); }
335 protected void ifgt(Object label) { backend.ifgt(label); }
336 protected void ifle(Object label) { backend.ifle(label); }
337 protected void goTo(Object label) { backend.goTo(label); }
338 protected void ifnull(Object label) { backend.ifnull(label); }
339 protected void ifnonnull(Object label) { backend.ifnonnull(label); }
340 protected void if_icmplt(Object label) { backend.if_icmplt(label); }
341 protected void if_icmpne(Object label) { backend.if_icmpne(label); }
342 protected void if_icmpeq(Object label) { backend.if_icmpeq(label); }
343 protected void nop(Object label) { backend.nop(label); }
344 protected void imul() { backend.imul(); }
345 protected void iadd() { backend.iadd(); }
346 protected void lushr() { backend.lushr(); }
347 protected void lxor() { backend.lxor(); }
348 protected void ixor() { backend.ixor(); }
349 protected void l2i() { backend.l2i(); }
350 protected void dcmpg() { backend.dcmpg(); }
351 protected void fcmpg() { backend.fcmpg(); }
352 protected void lcmp() { backend.lcmp(); }
353 protected void pop() { backend.pop(); }
354 protected void pop2() { backend.pop2(); }
355 protected void dup() { backend.dup(); }
356 protected void dup2() { backend.dup2(); }
357 protected void dup_x1() { backend.dup_x1(); }
358 protected void dup_x2() { backend.dup_x2(); }
359 protected void swap() { backend.swap(); }
360 protected void aconst_null() { backend.aconst_null(); }
361
362 protected void push(int i) {
363 if (i < 0) {
364 backend.ldc(i);
365 } else if (i <= 5) {
366 backend.iconst(i);
367 } else if (i <= Byte.MAX_VALUE) {
368 backend.bipush((byte)i);
369 } else if (i <= Short.MAX_VALUE) {
370 backend.sipush((short)i);
371 } else {
372 backend.ldc(i);
373 }
374 }
375
376 protected void push(long value) {
377 if (value == 0L || value == 1L) {
378 backend.lconst(value);
379 } else {
380 backend.ldc(value);
381 }
382 }
383
384 protected void push(float value) {
385 if (value == 0f || value == 1f || value == 2f) {
386 backend.fconst(value);
387 } else {
388 backend.ldc(value);
389 }
390 }
391 protected void push(double value) {
392 if (value == 0d || value == 1d) {
393 backend.dconst(value);
394 } else {
395 backend.ldc(value);
396 }
397 }
398
399 protected void push(String value) {
400 backend.ldc(value);
401 }
402
403 protected void push(Object[] array) {
404 push(array.length);
405 newarray(array.getClass().getComponentType());
406 for (int i = 0; i < array.length; i++) {
407 dup();
408 push(i);
409 push_object(array[i]);
410 aastore();
411 }
412 }
413
414 protected void push_object(Object obj) {
415 if (obj == null) {
416 aconst_null();
417 } else {
418 Class type = obj.getClass();
419 if (type.isArray()) {
420 push((Object[])obj);
421 } else if (obj instanceof String) {
422 push((String)obj);
423 } else if (obj instanceof Class) {
424 load_class((Class)obj);
425 } else if (obj.getClass().getSuperclass().equals(Number.class)) {
426 throw new IllegalArgumentException("not implemented yet");
427 } else {
428 throw new IllegalArgumentException("unknown type: " + obj.getClass());
429 }
430 }
431 }
432
433 protected void newarray() {
434 newarray(Object.class);
435 }
436
437 protected void newarray(Class clazz) {
438 if (clazz.isPrimitive()) {
439 backend.newarray(clazz);
440 } else {
441 backend.anewarray(clazz);
442 }
443 }
444
445 protected void arraylength() {
446 backend.arraylength();
447 }
448
449 protected void array_load(Class clazz) {
450 if (clazz.isPrimitive()) {
451 if (clazz.equals(Long.TYPE)) {
452 backend.laload();
453 } else if (clazz.equals(Double.TYPE)) {
454 backend.daload();
455 } else if (clazz.equals(Float.TYPE)) {
456 backend.faload();
457 } else if (clazz.equals(Short.TYPE)) {
458 backend.saload();
459 } else if (clazz.equals(Character.TYPE)) {
460 backend.caload();
461 } else if (clazz.equals(Integer.TYPE)) {
462 backend.iaload();
463 } else {
464 backend.baload();
465 }
466 } else {
467 backend.aaload();
468 }
469 }
470
471 protected void array_store(Class clazz) {
472 if (clazz.isPrimitive()) {
473 if (clazz.equals(Long.TYPE)) {
474 backend.lastore();
475 } else if (clazz.equals(Double.TYPE)) {
476 backend.dastore();
477 } else if (clazz.equals(Float.TYPE)) {
478 backend.fastore();
479 } else if (clazz.equals(Short.TYPE)) {
480 backend.sastore();
481 } else if (clazz.equals(Character.TYPE)) {
482 backend.castore();
483 } else if (clazz.equals(Integer.TYPE)) {
484 backend.iastore();
485 } else {
486 backend.bastore();
487 }
488 } else {
489 backend.aastore();
490 }
491 }
492
493 protected void load_this() {
494 backend.aload(0);
495 }
496
497 protected void load_class_this() {
498 load_class_helper(className);
499 }
500
501 protected void load_class(Class clazz) {
502 if (clazz.isPrimitive()) {
503 if (clazz.equals(Void.TYPE)) {
504 throw new IllegalArgumentException("cannot load void type");
505 }
506 try {
507 getfield(((Class)primitiveToWrapper.get(clazz)).getDeclaredField("TYPE"));
508 } catch (NoSuchFieldException e) {
509 throw new CodeGenerationException(e);
510 }
511 } else {
512 load_class_helper(clazz.getName());
513 }
514 }
515
516 private void load_class_helper(String className) {
517 needsFindClass = true;
518 push(className);
519 invoke_static_this(FIND_CLASS, Class.class, Constants.TYPES_STRING);
520 }
521
522 /***
523 * Pushes all of the arguments of the current method onto the stack.
524 */
525 protected void load_args() {
526 load_args(0, parameterTypes.length);
527 }
528
529 /***
530 * Pushes the specified argument of the current method onto the stack.
531 * @param index the zero-based index into the argument list
532 */
533 protected void load_arg(int index) {
534 load_local(parameterTypes[index], 1 + skipArgs(index));
535 }
536
537 // zero-based (see load_this)
538 protected void load_args(int fromArg, int count) {
539 int pos = 1 + skipArgs(fromArg);
540 for (int i = 0; i < count; i++) {
541 Class t = parameterTypes[fromArg + i];
542 load_local(t, pos);
543 pos += getStackSize(t);
544 }
545 }
546
547 private int skipArgs(int numArgs) {
548 int amount = 0;
549 for (int i = 0; i < numArgs; i++) {
550 amount += getStackSize(parameterTypes[i]);
551 }
552 return amount;
553 }
554
555 private void load_local(Class t, int pos) {
556 if (t != null && t.isPrimitive()) {
557 if (t.equals(Long.TYPE)) {
558 backend.lload(pos);
559 } else if (t.equals(Double.TYPE)) {
560 backend.dload(pos);
561 } else if (t.equals(Float.TYPE)) {
562 backend.fload(pos);
563 } else {
564 backend.iload(pos);
565 }
566 } else {
567 backend.aload(pos);
568 }
569 }
570
571 private void store_local(Class t, int index) {
572 if (t != null && t.isPrimitive()) {
573 if (t.equals(Long.TYPE)) {
574 backend.lstore(index);
575 } else if (t.equals(Double.TYPE)) {
576 backend.dstore(index);
577 } else if (t.equals(Float.TYPE)) {
578 backend.fstore(index);
579 } else {
580 backend.istore(index);
581 }
582 } else {
583 backend.astore(index);
584 }
585 }
586
587 protected void iinc(Object local, int amount) {
588 backend.iinc(getLocal(local), amount);
589 }
590
591 protected void store_local(Object local) {
592 store_local((Class)localTypes.get(local), getLocal(local));
593 }
594
595 protected void load_local(Object local) {
596 load_local((Class)localTypes.get(local), getLocal(local));
597 }
598
599 private int getLocal(Object local) {
600 return ((Integer)locals.get(local)).intValue();
601 }
602
603 protected void return_value() {
604 if (returnType.isPrimitive()) {
605 if (returnType.equals(Void.TYPE)) {
606 backend.returnVoid();
607 } else if (returnType.equals(Long.TYPE)) {
608 backend.lreturn();
609 } else if (returnType.equals(Double.TYPE)) {
610 backend.dreturn();
611 } else if (returnType.equals(Float.TYPE)) {
612 backend.freturn();
613 } else {
614 backend.ireturn();
615 }
616 } else {
617 backend.areturn();
618 }
619 }
620
621 protected void declare_field(int modifiers, Class type, String name) {
622 if (getFieldInfo(name) != null) {
623 throw new IllegalArgumentException("Field \"" + name + "\" already exists");
624 }
625 backend.declare_field(modifiers, type, name);
626 fieldInfo.put(name, new FieldInfo(Modifier.isStatic(modifiers), type));
627 }
628
629 private FieldInfo getFieldInfo(String name) {
630 return (FieldInfo)fieldInfo.get(name);
631 }
632
633 private static class FieldInfo {
634 private boolean staticFlag;
635 private Class type;
636
637 public FieldInfo(boolean staticFlag, Class type) {
638 this.staticFlag = staticFlag;
639 this.type = type;
640 }
641
642 public boolean isStatic() {
643 return staticFlag;
644 }
645
646 public Class getType() {
647 return type;
648 }
649 }
650
651 protected void getfield(String name) {
652 FieldInfo info = getFieldInfo(name);
653 if (info.isStatic()) {
654 backend.getstatic(className, name, info.getType());
655 } else {
656 backend.getfield(className, name, info.getType());
657 }
658 }
659
660 protected void putfield(String name) {
661 FieldInfo info = getFieldInfo(name);
662 if (info.isStatic()) {
663 backend.putstatic(className, name, info.getType());
664 } else {
665 backend.putfield(className, name, info.getType());
666 }
667 }
668
669 protected void super_getfield(String name) throws NoSuchFieldException {
670 // TODO: search up entire superclass chain?
671 getfield(superclass.getDeclaredField(name));
672 }
673
674 protected void super_putfield(String name) throws NoSuchFieldException {
675 putfield(superclass.getDeclaredField(name));
676 }
677
678 protected void getfield(Field field) {
679
680 if (Modifier.isStatic(field.getModifiers())) {
681 backend.getstatic(field.getDeclaringClass().getName(),
682 field.getName(),
683 field.getType());
684 } else {
685 backend.getfield(field.getDeclaringClass().getName(),
686 field.getName(),
687 field.getType());
688 }
689 }
690
691 protected void putfield(Field field) {
692 if (Modifier.isStatic(field.getModifiers())) {
693 backend.putstatic(field.getDeclaringClass().getName(),
694 field.getName(),
695 field.getType());
696 } else {
697 backend.putfield(field.getDeclaringClass().getName(),
698 field.getName(),
699 field.getType());
700 }
701 }
702
703 protected void invoke(Method method) {
704 if (method.getDeclaringClass().isInterface()) {
705 backend.invoke_interface(method.getDeclaringClass().getName(), method.getName(),
706 method.getReturnType(), method.getParameterTypes());
707 } else if (Modifier.isStatic(method.getModifiers())) {
708 backend.invoke_static(method.getDeclaringClass().getName(), method.getName(),
709 method.getReturnType(), method.getParameterTypes());
710 } else {
711 backend.invoke_virtual(method.getDeclaringClass().getName(), method.getName(),
712 method.getReturnType(), method.getParameterTypes());
713 }
714 }
715
716 protected void super_invoke(Method method) {
717
718 backend.invoke_special(superclass.getName(), method.getName(),
719 method.getReturnType(), method.getParameterTypes());
720 }
721
722 protected void invoke_virtual_this(String methodName, Class returnType, Class[] parameterTypes) {
723 backend.invoke_virtual(className, methodName, returnType, parameterTypes);
724 }
725
726 protected void invoke_static_this(String methodName, Class returnType, Class[] parameterTypes) {
727
728 backend.invoke_static(className, methodName, returnType, parameterTypes);
729 }
730
731 protected void super_invoke() {
732 backend.invoke_special(superclass.getName(), methodName, returnType, parameterTypes);
733 }
734
735 protected void invoke_constructor(String className, Class[] parameterTypes) {
736 backend.invoke_special(className, Constants.CONSTRUCTOR_NAME, Void.TYPE, parameterTypes);
737 }
738
739 protected void invoke_constructor(Class type) {
740 invoke_constructor(type, Constants.TYPES_EMPTY);
741 }
742
743 protected void invoke(Constructor constructor) {
744 invoke_constructor(constructor.getDeclaringClass(), constructor.getParameterTypes());
745 }
746
747 protected void invoke_constructor(Class type, Class[] parameterTypes) {
748 invoke_constructor(type.getName(), parameterTypes);
749 }
750
751 private static int getStackSize(Class type) {
752 return (type.equals(Double.TYPE) || type.equals(Long.TYPE)) ? 2 : 1;
753 }
754
755 static int getStackSize(Class[] classes) {
756 int size = 0;
757 for (int i = 0; i < classes.length; i++) {
758 size += getStackSize(classes[i]);
759 }
760 return size;
761 }
762
763 protected void super_invoke(Constructor constructor) {
764 super_invoke_constructor(constructor.getParameterTypes());
765 }
766
767 protected void super_invoke_constructor() {
768 invoke_constructor(superclass.getName(), Constants.TYPES_EMPTY);
769 }
770
771 protected void super_invoke_constructor(Class[] parameterTypes) {
772 invoke_constructor(superclass.getName(), parameterTypes);
773 }
774
775 protected void invoke_constructor_this() {
776 invoke_constructor_this(Constants.TYPES_EMPTY);
777 }
778
779 protected void invoke_constructor_this(Class[] parameterTypes) {
780 invoke_constructor(className, parameterTypes);
781 }
782
783 protected void new_instance_this() {
784 backend.new_instance(className);
785 }
786
787 protected void new_instance(String className) {
788 backend.new_instance(className);
789 }
790
791 protected void new_instance(Class clazz) {
792 new_instance(clazz.getName());
793 }
794
795 protected void aaload(int index) {
796 push(index);
797 aaload();
798 }
799
800 protected void aaload() { backend.aaload(); }
801 protected void aastore() { backend.aastore(); }
802 protected void athrow() { backend.athrow(); }
803
804 protected Object make_label() {
805 return new Object();
806 }
807
808 protected Object make_local() {
809 return make_local(null);
810 }
811
812 protected Object make_local(Class type) {
813 Object local = new Object();
814 locals.put(local, new Integer(nextLocal));
815 localTypes.put(local, type);
816 nextLocal += (type == null) ? 1 : getStackSize(type);
817 return local;
818 }
819
820 /***
821 * Pushes a zero onto the stack if the argument is a primitive class, or a null otherwise.
822 */
823 protected void zero_or_null(Class type) {
824 if (type.isPrimitive()) {
825 if (type.equals(Double.TYPE)) {
826 push(0d);
827 } else if (type.equals(Long.TYPE)) {
828 push(0L);
829 } else if (type.equals(Float.TYPE)) {
830 push(0f);
831 } else if (type.equals(Void.TYPE)) {
832 // ignore
833 } else {
834 push(0);
835 }
836 } else {
837 aconst_null();
838 }
839 }
840
841 /***
842 * Unboxes the object on the top of the stack. If the object is null, the
843 * unboxed primitive value becomes zero.
844 */
845 protected void unbox_or_zero(Class type) {
846 if (type.isPrimitive()) {
847 if (!type.equals(Void.TYPE)) {
848 Object nonNull = make_label();
849 Object end = make_label();
850 dup();
851 ifnonnull(nonNull);
852 pop();
853 zero_or_null(type);
854 goTo(end);
855 nop(nonNull);
856 unbox(type);
857 nop(end);
858 }
859 } else {
860 checkcast(type);
861 }
862 }
863
864 /***
865 * If the argument is a primitive class, replaces the primitive value
866 * on the top of the stack with the wrapped (Object) equivalent. For
867 * example, char -> Character.
868 * If the class is Void, a null is pushed onto the stack instead.
869 * @param clazz the class indicating the current type of the top stack value
870 */
871 protected void box(Class clazz) {
872 if (clazz.isPrimitive()) {
873 if (clazz.equals(Void.TYPE)) {
874 aconst_null();
875 } else {
876 Class wrapper = (Class)primitiveToWrapper.get(clazz);
877 new_instance(wrapper);
878 if (getStackSize(clazz) == 2) {
879 // Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
880 dup_x2();
881 dup_x2();
882 pop();
883 } else {
884 // p -> po -> opo -> oop -> o
885 dup_x1();
886 swap();
887 }
888 invoke_constructor(wrapper, new Class[]{ clazz });
889 }
890 }
891 }
892
893 /***
894 * If the argument is a primitive class, replaces the object
895 * on the top of the stack with the unwrapped (primitive)
896 * equivalent. For example, Character -> char.
897 * @param clazz the class indicating the desired type of the top stack value
898 * @return true if the value was unboxed
899 */
900 protected void unbox(Class clazz) {
901 if (clazz.isPrimitive()) {
902 if (!clazz.equals(Void.TYPE)) {
903 Method convert = (Method)primitiveMethods.get(clazz);
904 checkcast(convert.getDeclaringClass());
905 invoke(convert);
906 }
907 } else {
908 checkcast(clazz);
909 }
910 }
911
912 protected void checkcast_this() {
913 backend.checkcast(className);
914 }
915
916 protected void checkcast(Class clazz) {
917 // TODO: necessary?
918 // if (clazz.isArray()) {
919 // append(new CHECKCAST(cp.addArrayClass((ArrayType)type)));
920 if (clazz.equals(Object.class)) {
921 // ignore
922 } else {
923 backend.checkcast(clazz.getName());
924 }
925 }
926
927 protected void instance_of(Class clazz) {
928 backend.instance_of(clazz.getName());
929 }
930
931 protected void instance_of_this() {
932 backend.instance_of(className);
933 }
934
935 protected void generateNullConstructor() {
936 begin_constructor();
937 load_this();
938 super_invoke_constructor();
939 return_value();
940 end_method();
941 }
942
943 private void generateFindClass() {
944 /* generates:
945 static private Class findClass(String name) throws Exception {
946 try {
947 return Class.forName(name);
948 } catch (java.lang.ClassNotFoundException cne) {
949 throw new java.lang.NoClassDefFoundError(cne.getMessage());
950 }
951 }
952 */
953 begin_method(Modifier.PRIVATE | Modifier.STATIC,
954 Class.class,
955 FIND_CLASS,
956 Constants.TYPES_STRING,
957 null);
958 Object eh = begin_handler();
959 load_this();
960 invoke(MethodConstants.FOR_NAME);
961 return_value();
962 end_handler();
963
964 handle_exception(eh, ClassNotFoundException.class);
965 invoke(MethodConstants.THROWABLE_GET_MESSAGE);
966 new_instance(NoClassDefFoundError.class);
967 dup_x1();
968 swap();
969 invoke_constructor(NoClassDefFoundError.class, Constants.TYPES_STRING);
970 athrow();
971 end_method();
972 }
973
974 protected interface ProcessArrayCallback {
975 public void processElement(Class type);
976 }
977
978 /***
979 * Process an array on the stack. Assumes the top item on the stack
980 * is an array of the specified type. For each element in the array,
981 * puts the element on the stack and triggers the callback.
982 * @param type the type of the array (type.isArray() must be true)
983 * @param callback the callback triggered for each element
984 */
985 protected void process_array(Class type, ProcessArrayCallback callback) {
986 Class compType = type.getComponentType();
987 Object array = make_local();
988 Object loopvar = make_local(Integer.TYPE);
989 Object loopbody = make_label();
990 Object checkloop = make_label();
991 store_local(array);
992 push(0);
993 store_local(loopvar);
994 goTo(checkloop);
995
996 nop(loopbody);
997 load_local(array);
998 load_local(loopvar);
999 array_load(compType);
1000 callback.processElement(compType);
1001 iinc(loopvar, 1);
1002
1003 nop(checkloop);
1004 load_local(loopvar);
1005 load_local(array);
1006 arraylength();
1007 if_icmplt(loopbody);
1008 }
1009
1010 /***
1011 * Process two arrays on the stack in parallel. Assumes the top two items on the stack
1012 * are arrays of the specified class. The arrays must be the same length. For each pair
1013 * of elements in the arrays, puts the pair on the stack and triggers the callback.
1014 * @param clazz the type of the arrays (clazz.isArray() must be true)
1015 * @param callback the callback triggered for each pair of elements
1016 */
1017 protected void process_arrays(Class clazz, ProcessArrayCallback callback) {
1018 Class compType = clazz.getComponentType();
1019 Object array1 = make_local();
1020 Object array2 = make_local();
1021 Object loopvar = make_local(Integer.TYPE);
1022 Object loopbody = make_label();
1023 Object checkloop = make_label();
1024 store_local(array1);
1025 store_local(array2);
1026 push(0);
1027 store_local(loopvar);
1028 goTo(checkloop);
1029
1030 nop(loopbody);
1031 load_local(array1);
1032 load_local(loopvar);
1033 array_load(compType);
1034 load_local(array2);
1035 load_local(loopvar);
1036 array_load(compType);
1037 callback.processElement(compType);
1038 iinc(loopvar, 1);
1039
1040 nop(checkloop);
1041 load_local(loopvar);
1042 load_local(array1);
1043 arraylength();
1044 if_icmplt(loopbody);
1045 }
1046
1047 /***
1048 * Branches to the specified label if the top two items on the stack
1049 * are not equal. The items must both be of the specified
1050 * class. Equality is determined by comparing primitive values
1051 * directly and by invoking the <code>equals</code> method for
1052 * Objects. Arrays are recursively processed in the same manner.
1053 */
1054 protected void not_equals(Class clazz, final Object notEquals) {
1055 (new ProcessArrayCallback() {
1056 public void processElement(Class type) {
1057 not_equals_helper(type, notEquals, this);
1058 }
1059 }).processElement(clazz);
1060 }
1061
1062 private void not_equals_helper(Class clazz, Object notEquals, ProcessArrayCallback callback) {
1063 if (clazz.isPrimitive()) {
1064 if (returnType.equals(Double.TYPE)) {
1065 dcmpg();
1066 ifne(notEquals);
1067 } else if (returnType.equals(Long.TYPE)) {
1068 lcmp();
1069 ifne(notEquals);
1070 } else if (returnType.equals(Float.TYPE)) {
1071 fcmpg();
1072 ifne(notEquals);
1073 } else {
1074 if_icmpne(notEquals);
1075 }
1076 } else {
1077 Object end = make_label();
1078 nullcmp(notEquals, end);
1079 if (clazz.isArray()) {
1080 Object checkContents = make_label();
1081 dup2();
1082 arraylength();
1083 swap();
1084 arraylength();
1085 if_icmpeq(checkContents);
1086 pop2();
1087 goTo(notEquals);
1088 nop(checkContents);
1089 process_arrays(clazz, callback);
1090 } else {
1091 invoke(MethodConstants.EQUALS);
1092 ifeq(notEquals);
1093 }
1094 nop(end);
1095 }
1096 }
1097
1098 protected void throw_exception(Class type, String msg) {
1099 new_instance(type);
1100 dup();
1101 push(msg);
1102 invoke_constructor(type, new Class[]{ String.class });
1103 athrow();
1104
1105 }
1106
1107 /***
1108 * If both objects on the top of the stack are non-null, does nothing.
1109 * If one is null, or both are null, both are popped off and execution
1110 * branches to the respective label.
1111 * @param oneNull label to branch to if only one of the objects is null
1112 * @param bothNull label to branch to if both of the objects are null
1113 */
1114 protected void nullcmp(Object oneNull, Object bothNull) {
1115 dup2();
1116 Object nonNull = make_label();
1117 Object oneNullHelper = make_label();
1118 Object end = make_label();
1119 ifnonnull(nonNull);
1120 ifnonnull(oneNullHelper);
1121 pop2();
1122 goTo(bothNull);
1123
1124 nop(nonNull);
1125 ifnull(oneNullHelper);
1126 goTo(end);
1127
1128 nop(oneNullHelper);
1129 pop2();
1130 goTo(oneNull);
1131
1132 nop(end);
1133 }
1134
1135 protected void generateFactoryMethod(Method method) {
1136 begin_method(method);
1137 new_instance_this();
1138 dup();
1139 load_args();
1140 invoke_constructor_this(method.getParameterTypes());
1141 return_value();
1142 end_method();
1143 }
1144 }
This page was automatically generated by Maven