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