1 /* 2 * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package vm.runtime.defmeth.shared; 25 26 27 import jdk.internal.org.objectweb.asm.Handle; 28 import jdk.internal.org.objectweb.asm.Type; 29 import nsk.share.TestFailure; 30 import nsk.share.test.TestUtils; 31 import jdk.internal.org.objectweb.asm.Label; 32 import jdk.internal.org.objectweb.asm.MethodVisitor; 33 import static jdk.internal.org.objectweb.asm.Opcodes.*; 34 import jdk.internal.org.objectweb.asm.ClassWriter; 35 import static jdk.internal.org.objectweb.asm.ClassWriter.*; 36 37 import vm.runtime.defmeth.shared.data.*; 38 import vm.runtime.defmeth.shared.data.method.*; 39 import vm.runtime.defmeth.shared.data.method.body.*; 40 import vm.runtime.defmeth.shared.data.method.param.*; 41 import vm.runtime.defmeth.shared.data.method.result.*; 42 43 import java.lang.invoke.CallSite; 44 import java.lang.invoke.MethodHandles; 45 import java.lang.invoke.MethodType; 46 47 import static vm.runtime.defmeth.shared.ExecutionMode.*; 48 49 /** 50 * Constructs class file from {@code Clazz} instance. 51 */ 52 public class ClassFileGenerator implements Visitor { 53 private final ExecutionMode invocationType; 54 55 /** Default major version for generated class files 56 * Used when a class doesn't specify what major version should be specified. */ 57 private final int defaultMajorVer; 58 59 /** Default access flags for generated class files 60 * Used when a class doesn't specify it's own access flags. */ 61 private final int defaultClassAccFlags; 62 63 /** Represent current state of class file traversal. 64 * Used to avoid passing instances around. */ 65 private ClassWriter cw; 66 private MethodVisitor mv; 67 private Tester t; 68 69 private String className; 70 ClassFileGenerator()71 public ClassFileGenerator() { 72 this.defaultMajorVer = 52; 73 this.defaultClassAccFlags = ACC_PUBLIC; 74 this.invocationType = ExecutionMode.DIRECT; 75 } 76 ClassFileGenerator(int ver, int acc, ExecutionMode invocationType)77 public ClassFileGenerator(int ver, int acc, ExecutionMode invocationType) { 78 this.defaultMajorVer = ver; 79 this.defaultClassAccFlags = acc; 80 this.invocationType = invocationType; 81 } 82 83 /** 84 * Produce constructed class file as a {@code byte[]}. 85 * 86 * @return 87 */ getClassFile()88 public byte[] getClassFile() { 89 return cw.toByteArray(); 90 } 91 92 /** 93 * Push integer constant on stack. 94 * 95 * Choose most suitable bytecode to represent integer constant on stack. 96 * 97 * @param value 98 */ pushIntConst(int value)99 private void pushIntConst(int value) { 100 switch (value) { 101 case 0: 102 mv.visitInsn(ICONST_0); 103 break; 104 case 1: 105 mv.visitInsn(ICONST_1); 106 break; 107 case 2: 108 mv.visitInsn(ICONST_2); 109 break; 110 case 3: 111 mv.visitInsn(ICONST_3); 112 break; 113 case 4: 114 mv.visitInsn(ICONST_4); 115 break; 116 case 5: 117 mv.visitInsn(ICONST_5); 118 break; 119 default: 120 mv.visitIntInsn(BIPUSH, value); 121 } 122 } 123 124 @Override visitClass(Clazz clz)125 public void visitClass(Clazz clz) { 126 throw new IllegalStateException("More specific method should be called"); 127 } 128 129 @Override visitMethod(Method m)130 public void visitMethod(Method m) { 131 throw new IllegalStateException("More specific method should be called"); 132 } 133 134 @Override visitConcreteClass(ConcreteClass clz)135 public void visitConcreteClass(ConcreteClass clz) { 136 cw = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS); 137 138 int ver = clz.ver(); 139 int flags = clz.flags(); 140 141 className = clz.intlName(); 142 143 cw.visit((ver != 0) ? ver : defaultMajorVer, 144 ACC_SUPER | ((flags != -1) ? flags : defaultClassAccFlags), 145 className, 146 /* signature */ clz.sig(), 147 clz.parent().intlName(), 148 Util.asStrings(clz.interfaces())); 149 150 { // Default constructor: <init>()V 151 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 152 mv.visitCode(); 153 mv.visitVarInsn(ALOAD, 0); 154 mv.visitMethodInsn(INVOKESPECIAL, clz.parent().intlName(), "<init>", "()V", false); 155 mv.visitInsn(RETURN); 156 mv.visitMaxs(0, 0); 157 mv.visitEnd(); 158 159 mv = null; 160 } 161 162 for (Method m : clz.methods()) { 163 m.visit(this); 164 } 165 166 cw.visitEnd(); 167 } 168 169 @Override visitInterface(Interface intf)170 public void visitInterface(Interface intf) { 171 cw = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS); 172 173 int ver = intf.ver(); 174 int flags = intf.flags(); 175 176 className = intf.intlName(); 177 178 cw.visit( 179 (ver != 0) ? ver : defaultMajorVer, 180 ACC_ABSTRACT | ACC_INTERFACE | ((flags != -1) ? flags : defaultClassAccFlags), 181 className, 182 intf.sig(), 183 "java/lang/Object", 184 Util.asStrings(intf.parents())); 185 186 for (Method m : intf.methods()) { 187 m.visit(this); 188 } 189 190 cw.visitEnd(); 191 } 192 193 @Override visitConcreteMethod(ConcreteMethod m)194 public void visitConcreteMethod(ConcreteMethod m) { 195 mv = cw.visitMethod( 196 m.acc(), 197 m.name(), 198 m.desc(), 199 m.sig(), 200 m.getExceptions()); 201 202 m.body().visit(this); 203 204 mv = null; 205 } 206 207 @Override visitAbstractMethod(AbstractMethod m)208 public void visitAbstractMethod(AbstractMethod m) { 209 cw.visitMethod( 210 ACC_ABSTRACT | m.acc(), 211 m.name(), 212 m.desc(), 213 m.sig(), 214 m.getExceptions()); 215 216 } 217 218 @Override visitDefaultMethod(DefaultMethod m)219 public void visitDefaultMethod(DefaultMethod m) { 220 mv = cw.visitMethod( 221 m.acc(), 222 m.name(), 223 m.desc(), 224 m.sig(), 225 m.getExceptions()); 226 227 m.body().visit(this); 228 229 mv = null; 230 } 231 232 /* ====================================================================== */ 233 234 @Override visitEmptyBody(EmptyBody aThis)235 public void visitEmptyBody(EmptyBody aThis) { 236 mv.visitCode(); 237 mv.visitInsn(RETURN); 238 mv.visitMaxs(0, 0); 239 mv.visitEnd(); 240 } 241 242 @Override visitThrowExBody(ThrowExBody body)243 public void visitThrowExBody(ThrowExBody body) { 244 mv.visitCode(); 245 mv.visitTypeInsn(NEW, body.getExc().intlName()); 246 mv.visitInsn(DUP); 247 //mv.visitLdcInsn(body.getMsg()); 248 //mv.visitMethodInsn(INVOKESPECIAL, body.getExc(), "<init>", "(Ljava/lang/String;)V", false); 249 mv.visitMethodInsn(INVOKESPECIAL, body.getExc().intlName(), "<init>", "()V", false); 250 mv.visitInsn(ATHROW); 251 mv.visitMaxs(0, 0); 252 mv.visitEnd(); 253 } 254 255 @Override visitReturnIntBody(ReturnIntBody body)256 public void visitReturnIntBody(ReturnIntBody body) { 257 mv.visitCode(); 258 //mv.visitIntInsn(BIPUSH, body.getValue()); 259 pushIntConst(body.getValue()); 260 mv.visitInsn(IRETURN); 261 mv.visitMaxs(0, 0); 262 mv.visitEnd(); 263 } 264 265 @Override visitReturnNullBody(ReturnNullBody body)266 public void visitReturnNullBody(ReturnNullBody body) { 267 mv.visitCode(); 268 mv.visitInsn(ACONST_NULL); 269 mv.visitInsn(ARETURN); 270 mv.visitMaxs(0, 0); 271 mv.visitEnd(); 272 } 273 generateCall(CallMethod callSite, ExecutionMode invocationType)274 private void generateCall(CallMethod callSite, ExecutionMode invocationType) { 275 switch (invocationType) { 276 case DIRECT: 277 generateDirectCall(callSite); 278 break; 279 case INVOKE_EXACT: 280 generateMHInvokeCall(callSite, /* isExact = */ true); 281 break; 282 case INVOKE_GENERIC: 283 generateMHInvokeCall(callSite, /* isExact = */ false); 284 break; 285 case INDY: 286 generateIndyCall(callSite); 287 break; 288 default: 289 throw new UnsupportedOperationException(invocationType.toString()); 290 } 291 } 292 prepareParams(CallMethod callSite)293 private void prepareParams(CallMethod callSite) { 294 // Prepare receiver 295 switch(callSite.invokeInsn()) { 296 case SPECIAL: // Put receiver (this) on stack 297 mv.visitVarInsn(ALOAD,0); 298 break; 299 case VIRTUAL: 300 case INTERFACE: // Construct receiver 301 if (callSite.receiverClass() != null) { 302 String receiver = callSite.receiverClass().intlName(); 303 // Construct new instance 304 mv.visitTypeInsn(NEW, receiver); 305 mv.visitInsn(DUP); 306 mv.visitMethodInsn(INVOKESPECIAL, receiver, 307 "<init>", "()V", false); 308 } else { 309 // Use "this" 310 mv.visitVarInsn(ALOAD, 0); 311 } 312 mv.visitVarInsn(ASTORE, 1); 313 mv.visitVarInsn(ALOAD, 1); 314 break; 315 case STATIC: break; 316 } 317 318 // Push parameters on stack 319 for (Param p : callSite.params()) { 320 p.visit(this); 321 } 322 323 } 324 convertToHandle(CallMethod callSite)325 private static Handle convertToHandle(CallMethod callSite) { 326 return new Handle( 327 /* tag */ callSite.invokeInsn().tag(), 328 /* owner */ callSite.staticClass().intlName(), 329 /* name */ callSite.methodName(), 330 /* desc */ callSite.methodDesc(), 331 /* interface */ callSite.isInterface()); 332 } 333 generateBootstrapMethod(CallMethod callSite)334 private Handle generateBootstrapMethod(CallMethod callSite) { 335 String bootstrapName = "bootstrapMethod"; 336 MethodType bootstrapType = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class); 337 338 MethodVisitor bmv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, bootstrapName, bootstrapType.toMethodDescriptorString(), null, null); 339 bmv.visitCode(); 340 341 Handle mh = convertToHandle(callSite); 342 343 String constCallSite = "java/lang/invoke/ConstantCallSite"; 344 bmv.visitTypeInsn(NEW, constCallSite); 345 bmv.visitInsn(DUP); 346 347 bmv.visitLdcInsn(mh); 348 349 bmv.visitMethodInsn(INVOKESPECIAL, constCallSite, "<init>", "(Ljava/lang/invoke/MethodHandle;)V", false); 350 bmv.visitInsn(ARETURN); 351 352 bmv.visitMaxs(0,0); 353 bmv.visitEnd(); 354 355 return new Handle(H_INVOKESTATIC, className, bootstrapName, bootstrapType.toMethodDescriptorString()); 356 } 357 mhCallSiteDesc(CallMethod callSite)358 private static String mhCallSiteDesc(CallMethod callSite) { 359 return (callSite.invokeInsn() != CallMethod.Invoke.STATIC) ? 360 prependType(callSite.methodDesc(), callSite.staticClass().intlName()) : 361 callSite.methodDesc(); // ignore receiver for static call 362 } 363 generateIndyCall(CallMethod callSite)364 private void generateIndyCall(CallMethod callSite) { 365 Handle bootstrap = generateBootstrapMethod(callSite); 366 String callSiteDesc = mhCallSiteDesc(callSite); 367 368 prepareParams(callSite); 369 370 // Call method 371 mv.visitInvokeDynamicInsn(callSite.methodName(), callSiteDesc, bootstrap); 372 373 // Pop method result, if necessary 374 if (callSite.popReturnValue()) { 375 mv.visitInsn(POP); 376 } 377 } 378 generateMHInvokeCall(CallMethod callSite, boolean isExact)379 private void generateMHInvokeCall(CallMethod callSite, boolean isExact) { 380 // Construct a method handle for a callee 381 mv.visitLdcInsn(convertToHandle(callSite)); 382 383 prepareParams(callSite); 384 385 // Call method using MH + MethodHandle.invokeExact 386 mv.visitMethodInsn( 387 INVOKEVIRTUAL, 388 "java/lang/invoke/MethodHandle", 389 isExact ? "invokeExact" : "invoke", 390 mhCallSiteDesc(callSite), 391 false); 392 393 // Pop method result, if necessary 394 if (callSite.popReturnValue()) { 395 mv.visitInsn(POP); 396 } 397 } 398 399 // Prepend type as a first parameter prependType(String desc, String type)400 private static String prependType(String desc, String type) { 401 return desc.replaceFirst("\\(", "(L"+type+";"); 402 } 403 generateDirectCall(CallMethod callSite)404 private void generateDirectCall(CallMethod callSite) { 405 prepareParams(callSite); 406 407 // Call method 408 mv.visitMethodInsn( 409 callSite.invokeInsn().opcode(), 410 callSite.staticClass().intlName(), 411 callSite.methodName(), callSite.methodDesc(), 412 callSite.isInterface()); 413 414 // Pop method result, if necessary 415 if (callSite.popReturnValue()) { 416 mv.visitInsn(POP); 417 } 418 } 419 420 @Override visitCallMethod(CallMethod callSite)421 public void visitCallMethod(CallMethod callSite) { 422 mv.visitCode(); 423 424 generateCall(callSite, ExecutionMode.DIRECT); 425 426 String typeName = callSite.returnType(); 427 428 if (!callSite.popReturnValue()) { 429 // Call produces some value & it isn't popped out of the stack 430 // Need to return it 431 switch (typeName) { 432 // primitive types 433 case "I" : case "B" : case "C" : case "S" : case "Z" : 434 mv.visitInsn(IRETURN); 435 break; 436 case "L": mv.visitInsn(LRETURN); break; 437 case "F": mv.visitInsn(FRETURN); break; 438 case "D": mv.visitInsn(DRETURN); break; 439 case "V": mv.visitInsn(RETURN); break; 440 default: 441 // reference type 442 if ((typeName.startsWith("L") && typeName.endsWith(";")) 443 || typeName.startsWith("[")) 444 { 445 mv.visitInsn(ARETURN); 446 } else { 447 throw new IllegalStateException(typeName); 448 } 449 } 450 } else { 451 // Stack is empty. Plain return is enough. 452 mv.visitInsn(RETURN); 453 } 454 455 mv.visitMaxs(0,0); 456 mv.visitEnd(); 457 } 458 459 @Override visitReturnNewInstanceBody(ReturnNewInstanceBody body)460 public void visitReturnNewInstanceBody(ReturnNewInstanceBody body) { 461 String className = body.getType().intlName(); 462 mv.visitCode(); 463 mv.visitTypeInsn(NEW, className); 464 mv.visitInsn(DUP); 465 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V", false); 466 mv.visitInsn(ARETURN); 467 mv.visitMaxs(0,0); 468 mv.visitEnd(); 469 } 470 471 /* ====================================================================== */ 472 473 @Override visitTester(Tester tester)474 public void visitTester(Tester tester) { 475 // If: 476 // cw = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS); 477 // then: 478 // java.lang.RuntimeException: java.lang.ClassNotFoundException: S 479 // at jdk.internal.org.objectweb.asm.ClassWriter.getCommonSuperClass(ClassWriter.java:1588) 480 // at jdk.internal.org.objectweb.asm.ClassWriter.getMergedType(ClassWriter.java:1559) 481 // at jdk.internal.org.objectweb.asm.Frame.merge(Frame.java:1407) 482 // at jdk.internal.org.objectweb.asm.Frame.merge(Frame.java:1308) 483 // at jdk.internal.org.objectweb.asm.MethodWriter.visitMaxs(MethodWriter.java:1353) 484 //mv.visitMaxs(t.getParams().length > 1 ? t.getParams().length+1 : 2, 2); 485 486 cw = new ClassWriter(COMPUTE_MAXS); 487 488 int testMajorVer = defaultMajorVer; 489 490 // JSR 292 is available starting Java 7 (major version 51) 491 if (invocationType == INVOKE_WITH_ARGS || 492 invocationType == INVOKE_EXACT || 493 invocationType == INVOKE_GENERIC) { 494 testMajorVer = Math.max(defaultMajorVer, 51); 495 } 496 497 className = tester.intlName(); 498 499 cw.visit(testMajorVer, ACC_PUBLIC | ACC_SUPER, className, null, "java/lang/Object", null); 500 501 { // Test.<init> 502 mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 503 mv.visitCode(); 504 mv.visitVarInsn(ALOAD, 0); 505 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 506 mv.visitInsn(RETURN); 507 mv.visitMaxs(0, 0); 508 mv.visitEnd(); 509 510 mv = null; 511 } 512 513 { // public static Test.test()V 514 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "()V", null, null); 515 try { 516 // Generate result handling 517 t = tester; 518 try { 519 tester.getResult().visit(this); 520 } finally { 521 t = null; 522 } 523 } finally { 524 mv = null; 525 } 526 } 527 528 cw.visitEnd(); 529 } 530 531 /* ====================================================================== */ 532 533 @Override visitResultInt(IntResult res)534 public void visitResultInt(IntResult res) { 535 mv.visitCode(); 536 537 generateCall(t.getCall(), invocationType); 538 539 mv.visitIntInsn(BIPUSH, res.getExpected()); 540 mv.visitMethodInsn(INVOKESTATIC, Util.getInternalName(TestUtils.class), "assertEquals", "(II)V", false); 541 542 mv.visitInsn(RETURN); 543 mv.visitMaxs(0, 0); 544 mv.visitEnd(); 545 546 } 547 548 /** 549 * Pseudo code: 550 * <code> 551 * { 552 * try { 553 * I i = new C(); i.m(...); // C.m(); if m is static 554 * Assert.fail(); 555 * } catch (<exception> e) { 556 * Assert.assertEquals(<message>,e.getMessage()); 557 * } catch (Throwable e) { 558 * throw new RuntimeException("...", e); 559 * } 560 * } 561 * </code> 562 */ 563 @Override visitResultThrowExc(ThrowExResult res)564 public void visitResultThrowExc(ThrowExResult res) { 565 mv.visitCode(); 566 567 Label lblBegin = new Label(); 568 Label lblBootstrapMethodError = new Label(); 569 Label lblNoBME = new Label(); 570 if (invocationType == INDY) { 571 mv.visitTryCatchBlock(lblBegin, lblNoBME, lblBootstrapMethodError, "java/lang/BootstrapMethodError"); 572 } 573 574 Label lblExpected = new Label(); 575 mv.visitTryCatchBlock(lblBegin, lblExpected, lblExpected, res.getExc().intlName()); 576 577 Label lblThrowable = new Label(); 578 mv.visitTryCatchBlock(lblBegin, lblExpected, lblThrowable, "java/lang/Throwable"); 579 580 581 mv.visitLabel(lblBegin); 582 583 generateCall(t.getCall(), invocationType); 584 585 586 if (Util.isNonVoid(t.getCall().returnType())) { 587 mv.visitInsn(POP); 588 } 589 590 mv.visitLabel(lblNoBME); 591 592 // throw new TestFailure("No exception was thrown") 593 mv.visitTypeInsn(NEW, "nsk/share/TestFailure"); 594 mv.visitInsn(DUP); 595 mv.visitLdcInsn("No exception was thrown"); 596 mv.visitMethodInsn(INVOKESPECIAL, "nsk/share/TestFailure", "<init>", "(Ljava/lang/String;)V", false); 597 mv.visitInsn(ATHROW); 598 599 // Unwrap exception during call site resolution from BootstrapMethodError 600 if (invocationType == INDY) { 601 // } catch (BootstrapMethodError e) { 602 // throw e.getCause(); 603 // } 604 mv.visitLabel(lblBootstrapMethodError); 605 mv.visitFrame(F_SAME1, 0, null, 1, new Object[] {"java/lang/BootstrapMethodError"}); 606 mv.visitVarInsn(ASTORE, 1); 607 mv.visitVarInsn(ALOAD, 1); 608 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/BootstrapMethodError", "getCause", "()Ljava/lang/Throwable;", false); 609 610 Label lblIsNull = new Label(); 611 mv.visitJumpInsn(IFNULL, lblIsNull); 612 // e.getCause() != null 613 mv.visitVarInsn(ALOAD, 1); 614 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/BootstrapMethodError", "getCause", "()Ljava/lang/Throwable;", false); 615 mv.visitInsn(ATHROW); 616 617 // e.getCause() == null 618 mv.visitLabel(lblIsNull); 619 mv.visitFrame(F_APPEND, 2, new Object[] {TOP, "java/lang/BootstrapMethodError"}, 0, null); 620 mv.visitVarInsn(ALOAD, 1); 621 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/BootstrapMethodError", "getCause", "()Ljava/lang/Throwable;", false); 622 mv.visitInsn(ATHROW); 623 } 624 625 // } catch (<exception> e) { 626 // //if <message> != null 627 // Assert.assertEquals(<message>,e.getMessage()); 628 // } 629 mv.visitLabel(lblExpected); 630 mv.visitFrame(F_FULL, 0, new Object[] {}, 1, new Object[] { res.getExc().intlName() }); 631 632 mv.visitVarInsn(ASTORE, 1); 633 634 // Exception class comparison, if exact match is requested 635 if (res.isExact()) { 636 mv.visitVarInsn(ALOAD, 1); 637 mv.visitLdcInsn(Type.getType("L"+res.getExc().intlName()+";")); 638 mv.visitMethodInsn(INVOKESTATIC, Util.getInternalName(TestUtils.class), "assertExactClass", "(Ljava/lang/Object;Ljava/lang/Class;)V", false); 639 } 640 641 // Compare exception's message, if needed 642 if (res.getMessage() != null) { 643 mv.visitVarInsn(ALOAD, 1); 644 mv.visitLdcInsn(res.getMessage()); 645 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Exception", "getMessage", "()Ljava/lang/String;", false); 646 mv.visitMethodInsn(INVOKESTATIC, Util.getInternalName(TestUtils.class), "assertEquals", "(Ljava/lang/String;Ljava/lang/String;)V", false); 647 } 648 649 mv.visitInsn(RETURN); 650 651 // } catch (Throwable e) { 652 // throw new RuntimeException("Expected exception <exception>", e); 653 // } 654 mv.visitLabel(lblThrowable); 655 mv.visitFrame(F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"}); 656 mv.visitVarInsn(ASTORE, 1); 657 658 // e.printStackTrace(); 659 //mv.visitVarInsn(ALOAD, 1); 660 //mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "printStackTrace", "()V", false); 661 662 // String msg = String.format("Expected exception J, got: %s: %s", 663 // e.getClass(), e.getMessage()); 664 // throw new RuntimeException(msg, e); 665 mv.visitTypeInsn(NEW, Util.getInternalName(TestFailure.class)); 666 mv.visitInsn(DUP); 667 mv.visitLdcInsn("Expected exception " + res.getExc().name() + ", got: %s: %s"); 668 mv.visitInsn(ICONST_2); 669 mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 670 mv.visitInsn(DUP); 671 mv.visitInsn(ICONST_0); 672 mv.visitVarInsn(ALOAD, 1); 673 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false); 674 mv.visitInsn(AASTORE); 675 mv.visitInsn(DUP); 676 mv.visitInsn(ICONST_1); 677 mv.visitVarInsn(ALOAD, 1); 678 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Throwable", "getMessage", "()Ljava/lang/String;", false); 679 mv.visitInsn(AASTORE); 680 mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "format", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;", false); 681 682 mv.visitVarInsn(ALOAD, 1); 683 mv.visitMethodInsn(INVOKESPECIAL, Util.getInternalName(TestFailure.class), "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V", false); 684 mv.visitInsn(ATHROW); 685 // end of lblThrowable 686 687 mv.visitMaxs(0, 0); 688 mv.visitEnd(); 689 } 690 691 @Override visitResultIgnore()692 public void visitResultIgnore() { 693 mv.visitCode(); 694 695 generateCall(t.getCall(), invocationType); 696 697 if (Util.isNonVoid(t.getCall().returnType())) { 698 mv.visitInsn(POP); 699 } 700 701 mv.visitInsn(RETURN); 702 703 mv.visitMaxs(0, 0); 704 mv.visitEnd(); 705 } 706 707 /* ====================================================================== */ 708 709 @Override visitParamInt(IntParam i)710 public void visitParamInt(IntParam i) { 711 pushIntConst(i.value()); 712 } 713 714 @Override visitParamLong(LongParam l)715 public void visitParamLong(LongParam l) { 716 long value = l.value(); 717 718 if (value == 0L) { 719 mv.visitInsn(LCONST_0); 720 } else { 721 mv.visitLdcInsn(new Long(value)); 722 } 723 } 724 725 @Override visitParamFloat(FloatParam f)726 public void visitParamFloat(FloatParam f) { 727 float value = f.value(); 728 729 if (value == 0.0f) { 730 mv.visitInsn(FCONST_0); 731 } else if (value == 1.0f) { 732 mv.visitInsn(FCONST_1); 733 } else if (value == 2.0f) { 734 mv.visitInsn(FCONST_2); 735 } else { 736 mv.visitLdcInsn(new Float(value)); 737 } 738 } 739 740 @Override visitParamDouble(DoubleParam d)741 public void visitParamDouble(DoubleParam d) { 742 double value = d.value(); 743 744 if (value == 0.0d) { 745 mv.visitInsn(DCONST_0); 746 } else if (value == 1.0d) { 747 mv.visitInsn(DCONST_1); 748 } else { 749 mv.visitLdcInsn(new Double(value)); 750 } 751 } 752 753 @Override visitParamNewInstance(NewInstanceParam param)754 public void visitParamNewInstance(NewInstanceParam param) { 755 String className = param.clazz().intlName(); 756 757 mv.visitTypeInsn(NEW, className); 758 mv.visitInsn(DUP); 759 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V", false); 760 } 761 762 @Override visitParamNull()763 public void visitParamNull() { 764 mv.visitInsn(ACONST_NULL); 765 } 766 767 @Override visitParamString(StringParam str)768 public void visitParamString(StringParam str) { 769 mv.visitLdcInsn(str.value()); 770 } 771 } 772