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