1 54 package org.logicalcobwebs.cglib.core; 55 56 import java.lang.reflect.Constructor ; 57 import java.lang.reflect.Member ; 58 import java.lang.reflect.Method ; 59 import java.math.BigDecimal ; 60 import java.math.BigInteger ; 61 import java.util.*; 62 import org.logicalcobwebs.asm.Label; 63 import org.logicalcobwebs.asm.Type; 64 65 public class EmitUtils { 66 private static final Signature CSTRUCT_NULL = 67 TypeUtils.parseConstructor(""); 68 private static final Signature CSTRUCT_THROWABLE = 69 TypeUtils.parseConstructor("Throwable"); 70 71 private static final Signature GET_NAME = 72 TypeUtils.parseSignature("String getName()"); 73 private static final Signature HASH_CODE = 74 TypeUtils.parseSignature("int hashCode()"); 75 private static final Signature EQUALS = 76 TypeUtils.parseSignature("boolean equals(Object)"); 77 private static final Signature STRING_LENGTH = 78 TypeUtils.parseSignature("int length()"); 79 private static final Signature STRING_CHAR_AT = 80 TypeUtils.parseSignature("char charAt(int)"); 81 private static final Signature FOR_NAME = 82 TypeUtils.parseSignature("Class forName(String)"); 83 private static final Signature DOUBLE_TO_LONG_BITS = 84 TypeUtils.parseSignature("long doubleToLongBits(double)"); 85 private static final Signature FLOAT_TO_INT_BITS = 86 TypeUtils.parseSignature("int floatToIntBits(float)"); 87 private static final Signature TO_STRING = 88 TypeUtils.parseSignature("String toString()"); 89 private static final Signature APPEND_STRING = 90 TypeUtils.parseSignature("StringBuffer append(String)"); 91 private static final Signature APPEND_INT = 92 TypeUtils.parseSignature("StringBuffer append(int)"); 93 private static final Signature APPEND_DOUBLE = 94 TypeUtils.parseSignature("StringBuffer append(double)"); 95 private static final Signature APPEND_FLOAT = 96 TypeUtils.parseSignature("StringBuffer append(float)"); 97 private static final Signature APPEND_CHAR = 98 TypeUtils.parseSignature("StringBuffer append(char)"); 99 private static final Signature APPEND_LONG = 100 TypeUtils.parseSignature("StringBuffer append(long)"); 101 private static final Signature APPEND_BOOLEAN = 102 TypeUtils.parseSignature("StringBuffer append(boolean)"); 103 private static final Signature LENGTH = 104 TypeUtils.parseSignature("int length()"); 105 private static final Signature SET_LENGTH = 106 TypeUtils.parseSignature("void setLength(int)"); 107 private static final Signature GET_DECLARED_METHOD = 108 TypeUtils.parseSignature("java.lang.reflect.Method getDeclaredMethod(String, Class[])"); 109 110 public static final ArrayDelimiters DEFAULT_DELIMITERS = new ArrayDelimiters("{", ", ", "}"); 111 112 private EmitUtils() { 113 } 114 115 public static void factory_method(ClassEmitter ce, Signature sig) { 116 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, sig, null, null); 117 e.new_instance_this(); 118 e.dup(); 119 e.load_args(); 120 e.invoke_constructor_this(TypeUtils.parseConstructor(sig.getArgumentTypes())); 121 e.return_value(); 122 e.end_method(); 123 } 124 125 public static void null_constructor(ClassEmitter ce) { 126 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_NULL, null, null); 127 e.load_this(); 128 e.super_invoke_constructor(); 129 e.return_value(); 130 e.end_method(); 131 } 132 133 140 public static void process_array(CodeEmitter e, Type type, ProcessArrayCallback callback) { 141 Type componentType = TypeUtils.getComponentType(type); 142 Local array = e.make_local(); 143 Local loopvar = e.make_local(Type.INT_TYPE); 144 Label loopbody = e.make_label(); 145 Label checkloop = e.make_label(); 146 e.store_local(array); 147 e.push(0); 148 e.store_local(loopvar); 149 e.goTo(checkloop); 150 151 e.mark(loopbody); 152 e.load_local(array); 153 e.load_local(loopvar); 154 e.array_load(componentType); 155 callback.processElement(componentType); 156 e.iinc(loopvar, 1); 157 158 e.mark(checkloop); 159 e.load_local(loopvar); 160 e.load_local(array); 161 e.arraylength(); 162 e.if_icmp(e.LT, loopbody); 163 } 164 165 172 public static void process_arrays(CodeEmitter e, Type type, ProcessArrayCallback callback) { 173 Type componentType = TypeUtils.getComponentType(type); 174 Local array1 = e.make_local(); 175 Local array2 = e.make_local(); 176 Local loopvar = e.make_local(Type.INT_TYPE); 177 Label loopbody = e.make_label(); 178 Label checkloop = e.make_label(); 179 e.store_local(array1); 180 e.store_local(array2); 181 e.push(0); 182 e.store_local(loopvar); 183 e.goTo(checkloop); 184 185 e.mark(loopbody); 186 e.load_local(array1); 187 e.load_local(loopvar); 188 e.array_load(componentType); 189 e.load_local(array2); 190 e.load_local(loopvar); 191 e.array_load(componentType); 192 callback.processElement(componentType); 193 e.iinc(loopvar, 1); 194 195 e.mark(checkloop); 196 e.load_local(loopvar); 197 e.load_local(array1); 198 e.arraylength(); 199 e.if_icmp(e.LT, loopbody); 200 } 201 202 public static void string_switch(CodeEmitter e, String [] strings, int switchStyle, ObjectSwitchCallback callback) { 203 try { 204 switch (switchStyle) { 205 case Constants.SWITCH_STYLE_TRIE: 206 string_switch_trie(e, strings, callback); 207 break; 208 case Constants.SWITCH_STYLE_HASH: 209 string_switch_hash(e, strings, callback, false); 210 break; 211 case Constants.SWITCH_STYLE_HASHONLY: 212 string_switch_hash(e, strings, callback, true); 213 break; 214 default: 215 throw new IllegalArgumentException ("unknown switch style " + switchStyle); 216 } 217 } catch (RuntimeException ex) { 218 throw ex; 219 } catch (Error ex) { 220 throw ex; 221 } catch (Exception ex) { 222 throw new CodeGenerationException(ex); 223 } 224 } 225 226 private static void string_switch_trie(final CodeEmitter e, 227 String [] strings, 228 final ObjectSwitchCallback callback) throws Exception { 229 final Label def = e.make_label(); 230 final Label end = e.make_label(); 231 final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() { 232 public Object transform(Object value) { 233 return new Integer (((String )value).length()); 234 } 235 }); 236 e.dup(); 237 e.invoke_virtual(Constants.TYPE_STRING, STRING_LENGTH); 238 e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() { 239 public void processCase(int key, Label ignore_end) throws Exception { 240 List bucket = (List)buckets.get(new Integer (key)); 241 stringSwitchHelper(e, bucket, callback, def, end, 0); 242 } 243 public void processDefault() { 244 e.goTo(def); 245 } 246 }); 247 e.mark(def); 248 e.pop(); 249 callback.processDefault(); 250 e.mark(end); 251 } 252 253 private static void stringSwitchHelper(final CodeEmitter e, 254 List strings, 255 final ObjectSwitchCallback callback, 256 final Label def, 257 final Label end, 258 final int index) throws Exception { 259 final int len = ((String )strings.get(0)).length(); 260 final Map buckets = CollectionUtils.bucket(strings, new Transformer() { 261 public Object transform(Object value) { 262 return new Integer (((String )value).charAt(index)); 263 } 264 }); 265 e.dup(); 266 e.push(index); 267 e.invoke_virtual(Constants.TYPE_STRING, STRING_CHAR_AT); 268 e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() { 269 public void processCase(int key, Label ignore_end) throws Exception { 270 List bucket = (List)buckets.get(new Integer (key)); 271 if (index + 1 == len) { 272 e.pop(); 273 callback.processCase(bucket.get(0), end); 274 } else { 275 stringSwitchHelper(e, bucket, callback, def, end, index + 1); 276 } 277 } 278 public void processDefault() { 279 e.goTo(def); 280 } 281 }); 282 } 283 284 static int[] getSwitchKeys(Map buckets) { 285 int[] keys = new int[buckets.size()]; 286 int index = 0; 287 for (Iterator it = buckets.keySet().iterator(); it.hasNext();) { 288 keys[index++] = ((Integer )it.next()).intValue(); 289 } 290 Arrays.sort(keys); 291 return keys; 292 } 293 294 private static void string_switch_hash(final CodeEmitter e, 295 final String [] strings, 296 final ObjectSwitchCallback callback, 297 final boolean skipEquals) throws Exception { 298 final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() { 299 public Object transform(Object value) { 300 return new Integer (value.hashCode()); 301 } 302 }); 303 final Label def = e.make_label(); 304 final Label end = e.make_label(); 305 e.dup(); 306 e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE); 307 e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() { 308 public void processCase(int key, Label ignore_end) throws Exception { 309 List bucket = (List)buckets.get(new Integer (key)); 310 Label next = null; 311 if (skipEquals && bucket.size() == 1) { 312 callback.processCase((String )bucket.get(0), end); 313 } else { 314 for (Iterator it = bucket.iterator(); it.hasNext();) { 315 String string = (String )it.next(); 316 if (next != null) { 317 e.mark(next); 318 } 319 if (it.hasNext()) { 320 e.dup(); 321 } 322 e.push(string); 323 e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS); 324 if (it.hasNext()) { 325 e.if_jump(e.EQ, next = e.make_label()); 326 e.pop(); 327 } else { 328 e.if_jump(e.EQ, def); 329 } 330 callback.processCase(string, end); 331 } 332 } 333 } 334 public void processDefault() { 335 e.pop(); 336 } 337 }); 338 e.mark(def); 339 callback.processDefault(); 340 e.mark(end); 341 } 342 343 public static void load_class_this(CodeEmitter e) { 344 load_class_helper(e, e.getClassEmitter().getClassType()); 345 } 346 347 public static void load_class(CodeEmitter e, Type type) { 348 if (TypeUtils.isPrimitive(type)) { 349 if (type == Type.VOID_TYPE) { 350 throw new IllegalArgumentException ("cannot load void type"); 351 } 352 e.getstatic(TypeUtils.getBoxedType(type), "TYPE", Constants.TYPE_CLASS); 353 } else { 354 load_class_helper(e, type); 355 } 356 } 357 358 private static void load_class_helper(CodeEmitter e, final Type type) { 359 if (e.isStaticHook()) { 360 e.push(TypeUtils.emulateClassGetName(type)); 362 e.invoke_static(Constants.TYPE_CLASS, FOR_NAME); 363 } else { 364 ClassEmitter ce = e.getClassEmitter(); 365 String typeName = TypeUtils.emulateClassGetName(type); 366 String fieldName = getFieldName(typeName); 367 if (!ce.isFieldDeclared(fieldName)) { 368 ce.declare_field(Constants.PRIVATE_FINAL_STATIC, fieldName, Constants.TYPE_CLASS, null, null); 369 CodeEmitter hook = ce.getStaticHook(); 370 hook.push(typeName); 371 hook.invoke_static(Constants.TYPE_CLASS, FOR_NAME); 372 hook.putstatic(ce.getClassType(), fieldName, Constants.TYPE_CLASS); 373 } 374 e.getfield(fieldName); 375 } 376 } 377 378 private static String getFieldName(String typeName) { 379 return "CGLIB$load_class$" + escapeType(typeName); 380 } 381 382 private static String escapeType(String s) { 383 StringBuffer sb = new StringBuffer (); 384 for (int i = 0, len = s.length(); i < len; i++) { 385 char c = s.charAt(i); 386 switch (c) { 387 case '$': sb.append("$24"); break; 388 case '.': sb.append("$2E"); break; 389 case '[': sb.append("$5B"); break; 390 case ';': sb.append("$3B"); break; 391 default: 392 sb.append(c); 393 } 394 } 395 return sb.toString(); 396 } 397 398 public static void push_array(CodeEmitter e, Object [] array) { 399 e.push(array.length); 400 e.newarray(Type.getType(array.getClass().getComponentType())); 401 for (int i = 0; i < array.length; i++) { 402 e.dup(); 403 e.push(i); 404 push_object(e, array[i]); 405 e.aastore(); 406 } 407 } 408 409 public static void push_object(CodeEmitter e, Object obj) { 410 if (obj == null) { 411 e.aconst_null(); 412 } else { 413 Class type = obj.getClass(); 414 if (type.isArray()) { 415 push_array(e, (Object [])obj); 416 } else if (obj instanceof String ) { 417 e.push((String )obj); 418 } else if (obj instanceof Class ) { 419 load_class(e, Type.getType((Class )obj)); 420 } else if (obj instanceof BigInteger ) { 421 e.new_instance(Constants.TYPE_BIG_INTEGER); 422 e.dup(); 423 e.push(obj.toString()); 424 e.invoke_constructor(Constants.TYPE_BIG_INTEGER); 425 } else if (obj instanceof BigDecimal ) { 426 e.new_instance(Constants.TYPE_BIG_DECIMAL); 427 e.dup(); 428 e.push(obj.toString()); 429 e.invoke_constructor(Constants.TYPE_BIG_DECIMAL); 430 } else { 431 throw new IllegalArgumentException ("unknown type: " + obj.getClass()); 432 } 433 } 434 } 435 436 public static void hash_code(CodeEmitter e, Type type, int multiplier, Customizer customizer) { 437 if (TypeUtils.isArray(type)) { 438 hash_array(e, type, multiplier, customizer); 439 } else { 440 e.swap(Type.INT_TYPE, type); 441 e.push(multiplier); 442 e.math(e.MUL, Type.INT_TYPE); 443 e.swap(type, Type.INT_TYPE); 444 if (TypeUtils.isPrimitive(type)) { 445 hash_primitive(e, type); 446 } else { 447 hash_object(e, type, customizer); 448 } 449 e.math(e.ADD, Type.INT_TYPE); 450 } 451 } 452 453 private static void hash_array(final CodeEmitter e, Type type, final int multiplier, final Customizer customizer) { 454 Label skip = e.make_label(); 455 Label end = e.make_label(); 456 e.dup(); 457 e.ifnull(skip); 458 EmitUtils.process_array(e, type, new ProcessArrayCallback() { 459 public void processElement(Type type) { 460 hash_code(e, type, multiplier, customizer); 461 } 462 }); 463 e.goTo(end); 464 e.mark(skip); 465 e.pop(); 466 e.mark(end); 467 } 468 469 private static void hash_object(CodeEmitter e, Type type, Customizer customizer) { 470 Label skip = e.make_label(); 472 Label end = e.make_label(); 473 e.dup(); 474 e.ifnull(skip); 475 if (customizer != null) { 476 customizer.customize(e, type); 477 } 478 e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE); 479 e.goTo(end); 480 e.mark(skip); 481 e.pop(); 482 e.push(0); 483 e.mark(end); 484 } 485 486 private static void hash_primitive(CodeEmitter e, Type type) { 487 switch (type.getSort()) { 488 case Type.BOOLEAN: 489 e.push(1); 491 e.math(e.XOR, Type.INT_TYPE); 492 break; 493 case Type.FLOAT: 494 e.invoke_static(Constants.TYPE_FLOAT, FLOAT_TO_INT_BITS); 496 break; 497 case Type.DOUBLE: 498 e.invoke_static(Constants.TYPE_DOUBLE, DOUBLE_TO_LONG_BITS); 500 case Type.LONG: 502 hash_long(e); 503 } 504 } 505 506 private static void hash_long(CodeEmitter e) { 507 e.dup2(); 509 e.push(32); 510 e.math(e.USHR, Type.LONG_TYPE); 511 e.math(e.XOR, Type.LONG_TYPE); 512 e.cast_numeric(Type.LONG_TYPE, Type.INT_TYPE); 513 } 514 515 519 526 public static void not_equals(final CodeEmitter e, Type type, final Label notEquals, final Customizer customizer) { 527 (new ProcessArrayCallback() { 528 public void processElement(Type type) { 529 not_equals_helper(e, type, notEquals, customizer, this); 530 } 531 }).processElement(type); 532 } 533 534 private static void not_equals_helper(CodeEmitter e, 535 Type type, 536 Label notEquals, 537 Customizer customizer, 538 ProcessArrayCallback callback) { 539 if (TypeUtils.isPrimitive(type)) { 540 e.if_cmp(type, e.NE, notEquals); 541 } else { 542 Label end = e.make_label(); 543 nullcmp(e, notEquals, end); 544 if (TypeUtils.isArray(type)) { 545 Label checkContents = e.make_label(); 546 e.dup2(); 547 e.arraylength(); 548 e.swap(); 549 e.arraylength(); 550 e.if_icmp(e.EQ, checkContents); 551 e.pop2(); 552 e.goTo(notEquals); 553 e.mark(checkContents); 554 EmitUtils.process_arrays(e, type, callback); 555 } else { 556 if (customizer != null) { 557 customizer.customize(e, type); 558 e.swap(); 559 customizer.customize(e, type); 560 } 561 e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS); 562 e.if_jump(e.EQ, notEquals); 563 } 564 e.mark(end); 565 } 566 } 567 568 575 private static void nullcmp(CodeEmitter e, Label oneNull, Label bothNull) { 576 e.dup2(); 577 Label nonNull = e.make_label(); 578 Label oneNullHelper = e.make_label(); 579 Label end = e.make_label(); 580 e.ifnonnull(nonNull); 581 e.ifnonnull(oneNullHelper); 582 e.pop2(); 583 e.goTo(bothNull); 584 585 e.mark(nonNull); 586 e.ifnull(oneNullHelper); 587 e.goTo(end); 588 589 e.mark(oneNullHelper); 590 e.pop2(); 591 e.goTo(oneNull); 592 593 e.mark(end); 594 } 595 596 609 610 public static void append_string(final CodeEmitter e, 611 Type type, 612 final ArrayDelimiters delims, 613 final Customizer customizer) { 614 final ArrayDelimiters d = (delims != null) ? delims : DEFAULT_DELIMITERS; 615 ProcessArrayCallback callback = new ProcessArrayCallback() { 616 public void processElement(Type type) { 617 append_string_helper(e, type, d, customizer, this); 618 e.push(d.inside); 619 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); 620 } 621 }; 622 append_string_helper(e, type, d, customizer, callback); 623 } 624 625 private static void append_string_helper(CodeEmitter e, 626 Type type, 627 ArrayDelimiters delims, 628 Customizer customizer, 629 ProcessArrayCallback callback) { 630 Label skip = e.make_label(); 631 Label end = e.make_label(); 632 if (TypeUtils.isPrimitive(type)) { 633 switch (type.getSort()) { 634 case Type.INT: 635 case Type.SHORT: 636 case Type.BYTE: 637 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_INT); 638 break; 639 case Type.DOUBLE: 640 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_DOUBLE); 641 break; 642 case Type.FLOAT: 643 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_FLOAT); 644 break; 645 case Type.LONG: 646 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_LONG); 647 break; 648 case Type.BOOLEAN: 649 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_BOOLEAN); 650 break; 651 case Type.CHAR: 652 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_CHAR); 653 break; 654 } 655 } else if (TypeUtils.isArray(type)) { 656 e.dup(); 657 e.ifnull(skip); 658 e.swap(); 659 if (delims != null && delims.before != null && !"".equals(delims.before)) { 660 e.push(delims.before); 661 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); 662 e.swap(); 663 } 664 EmitUtils.process_array(e, type, callback); 665 shrinkStringBuffer(e, 2); 666 if (delims != null && delims.after != null && !"".equals(delims.after)) { 667 e.push(delims.after); 668 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); 669 } 670 } else { 671 e.dup(); 672 e.ifnull(skip); 673 if (customizer != null) { 674 customizer.customize(e, type); 675 } 676 e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING); 677 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); 678 } 679 e.goTo(end); 680 e.mark(skip); 681 e.pop(); 682 e.push("null"); 683 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); 684 e.mark(end); 685 } 686 687 private static void shrinkStringBuffer(CodeEmitter e, int amt) { 688 e.dup(); 689 e.dup(); 690 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, LENGTH); 691 e.push(amt); 692 e.math(e.SUB, Type.INT_TYPE); 693 e.invoke_virtual(Constants.TYPE_STRING_BUFFER, SET_LENGTH); 694 } 695 696 public static class ArrayDelimiters { 697 private String before; 698 private String inside; 699 private String after; 700 701 public ArrayDelimiters(String before, String inside, String after) { 702 this.before = before; 703 this.inside = inside; 704 this.after = after; 705 } 706 } 707 708 public static void load_method(CodeEmitter e, Method method) { 709 load_class(e, Type.getType(method.getDeclaringClass())); 710 e.push(method.getName()); 711 push_object(e, method.getParameterTypes()); 712 e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHOD); 713 } 714 715 private interface ParameterTyper { 716 Class [] getParameterTypes(Object member); 717 } 718 719 public static void method_switch(CodeEmitter e, 720 Method [] methods, 721 ObjectSwitchCallback callback) { 722 member_switch_helper(e, Arrays.asList(methods), callback, true, new ParameterTyper() { 723 public Class [] getParameterTypes(Object member) { 724 return ((Method )member).getParameterTypes(); 725 } 726 }); 727 } 728 729 public static void constructor_switch(CodeEmitter e, 730 Constructor [] cstructs, 731 ObjectSwitchCallback callback) { 732 member_switch_helper(e, Arrays.asList(cstructs), callback, false, new ParameterTyper() { 733 public Class [] getParameterTypes(Object member) { 734 return ((Constructor )member).getParameterTypes(); 735 } 736 }); 737 } 738 739 private static void member_switch_helper(final CodeEmitter e, 740 List members, 741 final ObjectSwitchCallback callback, 742 boolean useName, 743 final ParameterTyper typer) { 744 try { 745 final Map cache = new HashMap(); 746 final ParameterTyper cached = new ParameterTyper() { 747 public Class [] getParameterTypes(Object member) { 748 Class [] types = (Class [])cache.get(member); 749 if (types == null) { 750 cache.put(member, types = typer.getParameterTypes(member)); 751 } 752 return types; 753 } 754 }; 755 final Label def = e.make_label(); 756 final Label end = e.make_label(); 757 if (useName) { 758 e.swap(); 759 final Map buckets = CollectionUtils.bucket(members, new Transformer() { 760 public Object transform(Object value) { 761 return ((Member )value).getName(); 762 } 763 }); 764 String [] names = (String [])buckets.keySet().toArray(new String [buckets.size()]); 765 EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 766 public void processCase(Object key, Label dontUseEnd) throws Exception { 767 member_helper_size(e, (List)buckets.get(key), callback, cached, def, end); 768 } 769 public void processDefault() throws Exception { 770 e.goTo(def); 771 } 772 }); 773 } else { 774 member_helper_size(e, members, callback, cached, def, end); 775 } 776 e.mark(def); 777 e.pop(); 778 callback.processDefault(); 779 e.mark(end); 780 } catch (RuntimeException ex) { 781 throw ex; 782 } catch (Error ex) { 783 throw ex; 784 } catch (Exception ex) { 785 throw new CodeGenerationException(ex); 786 } 787 } 788 789 private static void member_helper_size(final CodeEmitter e, 790 List members, 791 final ObjectSwitchCallback callback, 792 final ParameterTyper typer, 793 final Label def, 794 final Label end) throws Exception { 795 final Map buckets = CollectionUtils.bucket(members, new Transformer() { 796 public Object transform(Object value) { 797 return new Integer (typer.getParameterTypes(value).length); 798 } 799 }); 800 e.dup(); 801 e.arraylength(); 802 e.process_switch(EmitUtils.getSwitchKeys(buckets), new ProcessSwitchCallback() { 803 public void processCase(int key, Label dontUseEnd) throws Exception { 804 List bucket = (List)buckets.get(new Integer (key)); 805 member_helper_type(e, bucket, callback, typer, def, end, new BitSet()); 806 } 807 public void processDefault() throws Exception { 808 e.goTo(def); 809 } 810 }); 811 } 812 813 private static void member_helper_type(final CodeEmitter e, 814 List members, 815 final ObjectSwitchCallback callback, 816 final ParameterTyper typer, 817 final Label def, 818 final Label end, 819 final BitSet checked) throws Exception { 820 if (members.size() == 1) { 821 Member member = (Member )members.get(0); 822 Class [] types = typer.getParameterTypes(member); 823 for (int i = 0; i < types.length; i++) { 825 if (checked == null || !checked.get(i)) { 826 e.dup(); 827 e.aaload(i); 828 e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); 829 e.push(types[i].getName()); 830 e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS); 831 e.if_jump(e.EQ, def); 832 } 833 } 834 e.pop(); 835 callback.processCase(member, end); 836 } else { 837 Class [] example = typer.getParameterTypes(members.get(0)); 839 Map buckets = null; 840 int index = -1; 841 for (int i = 0; i < example.length; i++) { 842 final int j = i; 843 Map test = CollectionUtils.bucket(members, new Transformer() { 844 public Object transform(Object value) { 845 return typer.getParameterTypes(value)[j].getName(); 846 } 847 }); 848 if (buckets == null || test.size() > buckets.size()) { 849 buckets = test; 850 index = i; 851 } 852 } 853 if (buckets == null) { 854 e.goTo(def); 857 } else { 858 checked.set(index); 859 860 e.dup(); 861 e.aaload(index); 862 e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); 863 864 final Map fbuckets = buckets; 865 String [] names = (String [])buckets.keySet().toArray(new String [buckets.size()]); 866 EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 867 public void processCase(Object key, Label dontUseEnd) throws Exception { 868 member_helper_type(e, (List)fbuckets.get(key), callback, typer, def, end, checked); 869 } 870 public void processDefault() throws Exception { 871 e.goTo(def); 872 } 873 }); 874 } 875 } 876 } 877 878 public static void wrap_throwable(Block block, Type wrapper) { 879 CodeEmitter e = block.getCodeEmitter(); 880 e.catch_exception(block, Constants.TYPE_THROWABLE); 881 e.new_instance(wrapper); 882 e.dup_x1(); 883 e.swap(); 884 e.invoke_constructor(wrapper, CSTRUCT_THROWABLE); 885 e.athrow(); 886 } 887 888 public static void add_properties(ClassEmitter ce, String [] names, Type[] types) { 889 for (int i = 0; i < names.length; i++) { 890 String fieldName = "$cglib_prop_" + names[i]; 891 ce.declare_field(Constants.ACC_PRIVATE, fieldName, types[i], null, null); 892 EmitUtils.add_property(ce, names[i], types[i], fieldName); 893 } 894 } 895 896 public static void add_property(ClassEmitter ce, String name, Type type, String fieldName) { 897 String property = TypeUtils.upperFirst(name); 898 CodeEmitter e; 899 e = ce.begin_method(Constants.ACC_PUBLIC, 900 new Signature("get" + property, 901 type, 902 Constants.TYPES_EMPTY), 903 null, 904 null); 905 e.load_this(); 906 e.getfield(fieldName); 907 e.return_value(); 908 e.end_method(); 909 910 e = ce.begin_method(Constants.ACC_PUBLIC, 911 new Signature("set" + property, 912 Type.VOID_TYPE, 913 new Type[]{ type }), 914 null, 915 null); 916 e.load_this(); 917 e.load_arg(0); 918 e.putfield(fieldName); 919 e.return_value(); 920 e.end_method(); 921 } 922 } 923 | Popular Tags |