View Javadoc
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