001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.bc2ir; 014 015import static org.jikesrvm.classloader.BytecodeConstants.*; 016import static org.jikesrvm.classloader.ClassLoaderConstants.*; 017import static org.jikesrvm.compilers.opt.OptimizingCompilerException.opt_assert; 018import static org.jikesrvm.compilers.opt.bc2ir.IRGenOptions.*; 019import static org.jikesrvm.compilers.opt.driver.OptConstants.NO; 020import static org.jikesrvm.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI; 021import static org.jikesrvm.compilers.opt.driver.OptConstants.YES; 022import static org.jikesrvm.compilers.opt.ir.Operators.*; 023import static org.jikesrvm.osr.OSRConstants.*; 024 025import java.util.ArrayList; 026import java.util.Enumeration; 027 028import org.jikesrvm.VM; 029import org.jikesrvm.adaptive.controller.Controller; 030import org.jikesrvm.classloader.BytecodeStream; 031import org.jikesrvm.classloader.FieldReference; 032import org.jikesrvm.classloader.MethodReference; 033import org.jikesrvm.classloader.RVMClass; 034import org.jikesrvm.classloader.RVMField; 035import org.jikesrvm.classloader.RVMMethod; 036import org.jikesrvm.classloader.RVMType; 037import org.jikesrvm.classloader.TypeReference; 038import org.jikesrvm.compilers.baseline.SwitchBranchProfile; 039import org.jikesrvm.compilers.common.CompiledMethod; 040import org.jikesrvm.compilers.common.CompiledMethods; 041import org.jikesrvm.compilers.opt.ClassLoaderProxy; 042import org.jikesrvm.compilers.opt.FieldAnalysis; 043import org.jikesrvm.compilers.opt.OptimizingCompilerException; 044import org.jikesrvm.compilers.opt.Simplifier; 045import org.jikesrvm.compilers.opt.StaticFieldReader; 046import org.jikesrvm.compilers.opt.driver.OptimizingCompiler; 047import org.jikesrvm.compilers.opt.inlining.CompilationState; 048import org.jikesrvm.compilers.opt.inlining.InlineDecision; 049import org.jikesrvm.compilers.opt.inlining.InlineSequence; 050import org.jikesrvm.compilers.opt.inlining.Inliner; 051import org.jikesrvm.compilers.opt.ir.ALoad; 052import org.jikesrvm.compilers.opt.ir.AStore; 053import org.jikesrvm.compilers.opt.ir.Athrow; 054import org.jikesrvm.compilers.opt.ir.BasicBlock; 055import org.jikesrvm.compilers.opt.ir.Binary; 056import org.jikesrvm.compilers.opt.ir.BoundsCheck; 057import org.jikesrvm.compilers.opt.ir.CacheOp; 058import org.jikesrvm.compilers.opt.ir.Call; 059import org.jikesrvm.compilers.opt.ir.Empty; 060import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock; 061import org.jikesrvm.compilers.opt.ir.GetField; 062import org.jikesrvm.compilers.opt.ir.GetStatic; 063import org.jikesrvm.compilers.opt.ir.Goto; 064import org.jikesrvm.compilers.opt.ir.GuardedBinary; 065import org.jikesrvm.compilers.opt.ir.GuardedUnary; 066import org.jikesrvm.compilers.opt.ir.IRTools; 067import org.jikesrvm.compilers.opt.ir.IfCmp; 068import org.jikesrvm.compilers.opt.ir.InstanceOf; 069import org.jikesrvm.compilers.opt.ir.Instruction; 070import org.jikesrvm.compilers.opt.ir.LookupSwitch; 071import org.jikesrvm.compilers.opt.ir.MonitorOp; 072import org.jikesrvm.compilers.opt.ir.Move; 073import org.jikesrvm.compilers.opt.ir.Multianewarray; 074import org.jikesrvm.compilers.opt.ir.New; 075import org.jikesrvm.compilers.opt.ir.NewArray; 076import org.jikesrvm.compilers.opt.ir.NullCheck; 077import org.jikesrvm.compilers.opt.ir.Operator; 078import org.jikesrvm.compilers.opt.ir.OsrBarrier; 079import org.jikesrvm.compilers.opt.ir.OsrPoint; 080import org.jikesrvm.compilers.opt.ir.PutField; 081import org.jikesrvm.compilers.opt.ir.PutStatic; 082import org.jikesrvm.compilers.opt.ir.Register; 083import org.jikesrvm.compilers.opt.ir.ResultCarrier; 084import org.jikesrvm.compilers.opt.ir.StoreCheck; 085import org.jikesrvm.compilers.opt.ir.TableSwitch; 086import org.jikesrvm.compilers.opt.ir.Trap; 087import org.jikesrvm.compilers.opt.ir.TypeCheck; 088import org.jikesrvm.compilers.opt.ir.Unary; 089import org.jikesrvm.compilers.opt.ir.ZeroCheck; 090import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand; 091import org.jikesrvm.compilers.opt.ir.operand.BranchOperand; 092import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand; 093import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand; 094import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand; 095import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand; 096import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand; 097import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand; 098import org.jikesrvm.compilers.opt.ir.operand.LocationOperand; 099import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand; 100import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; 101import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand; 102import org.jikesrvm.compilers.opt.ir.operand.Operand; 103import org.jikesrvm.compilers.opt.ir.operand.OsrTypeInfoOperand; 104import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 105import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand; 106import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand; 107import org.jikesrvm.compilers.opt.ir.operand.TypeOperand; 108import org.jikesrvm.osr.ObjectHolder; 109import org.jikesrvm.osr.bytecodes.InvokeStatic; 110import org.jikesrvm.runtime.Entrypoints; 111import org.jikesrvm.runtime.Magic; 112import org.vmmagic.pragma.NoInline; 113import org.vmmagic.unboxed.Address; 114import org.vmmagic.unboxed.Offset; 115 116/** 117 * This class translates from bytecode to HIR. 118 * <p> 119 * The only public entry point is BC2IR.generateHIR. 120 * generateHIR is passed an argument GenerationContext. 121 * The context is assumed to be "empty" but "initialized." Invoking 122 * generateHIR on a context results in it being "filled in" with the HIR 123 * for the method (and for any inlined methods) as specified by the 124 * state of the context. 125 * <p> 126 * The basic idea is to abstractly interpret the bytecode stream, 127 * translating it into a register-based IR along the way. At each program 128 * point BC2IR has an abstract stack and an abstract local variable array. 129 * Based on this, and on the bytecode, it can generate instructions. 130 * It also does a number of forward flow-sensitive dataflow analyses and 131 * optimistic optimizations in the process. There's lots of details in 132 * John Whaley's master thesis from MIT. However, one needs to be careful 133 * because this code has substantial diverged from the system described in 134 * his thesis. 135 * Some optimizations/features described in Johns's thesis are not implemented 136 * here. Some optimizations/features implemented here are not described 137 * in John's thesis. 138 * In particular this code takes a different approach to JSRs (inlining them), 139 * and has more advanced and effective implementation of the inlining 140 * transformation. 141 * 142 * 143 * @see IRGenOptions 144 * @see GenerationContext 145 * @see ConvertBCtoHIR 146 */ 147public final class BC2IR { 148 /** 149 * Dummy slot. 150 * Used to deal with the fact the longs/doubles take 151 * two words of stack space/local space to represent. 152 * This field needs to be accessed by several of the IR classes, 153 * but is not intended to be referenced by general client code. 154 */ 155 public static final DummyStackSlot DUMMY = new DummyStackSlot(); 156 157 /** 158 * Generate HIR as specified by the argument GenerationContext. 159 * As a result of calling this method, the cfg field of the generation 160 * context is populated with basic blocks and instructions. 161 * Additionally, other fields of the generation context will be modified 162 * to summarize what happened during IR generation. 163 * <p> 164 * This is the only external entry point to BC2IR. 165 * <p> 166 * Note: most clients should be calling methods in 167 * ConvertBCtoHIR or in Inliner rather than invoking 168 * BC2IR.generateHIR directly. 169 * 170 * @param context the generation context 171 */ 172 public static void generateHIR(GenerationContext context) { 173 new BC2IR(context).generateHIR(); 174 } 175 176 ////////////////////////////////////////// 177 // vvv Implementation details below vvv // 178 ////////////////////////////////////////// 179 /** 180 * The generation context. 181 */ 182 private GenerationContext gc; 183 184 /** 185 * Bytecodes for the method being generated. 186 */ 187 private BytecodeStream bcodes; 188 189 // Fields to support generation of instructions/blocks 190 /** 191 * The set of BasicBlockLEs we are generating 192 */ 193 private BBSet blocks; 194 195 /** 196 * Bytecode index of current instruction. 197 */ 198 private int instrIndex; 199 200 // OSR field 201 private boolean osrGuardedInline = false; 202 203 /** 204 * OSR field: TODO rework this mechanism! 205 * adjustment of bcIndex of instructions because of 206 * specialized bytecode. 207 */ 208 private int bciAdjustment; 209 210 /** 211 * Last instruction generated (for ELIM_COPY_LOCALS) 212 */ 213 private Instruction lastInstr; 214 215 /** 216 * Does basic block end here? 217 */ 218 private boolean endOfBasicBlock; 219 220 /** 221 * Do we fall through to the next basic block? 222 */ 223 private boolean fallThrough; 224 225 /** 226 * Current BBLE. 227 */ 228 private BasicBlockLE currentBBLE; 229 230 /** 231 * Current simulated stack state. 232 */ 233 private OperandStack stack; 234 235 /** 236 * Current state of local variables. 237 */ 238 private Operand[] _localState; 239 240 /** 241 * Index of next basic block. 242 */ 243 private int runoff; 244 245 private Operand currentGuard; 246 247 /** 248 * Was something inlined? 249 */ 250 private boolean inlinedSomething; 251 252 /** 253 * OSR: used for PSEUDO_InvokeStatic to recover the type info 254 */ 255 private int param1, param2; 256 257 /** 258 * osr barrier needs type information of locals and stacks, 259 * it has to be created before a _callHelper. 260 * only when the call site is going to be inlined, the instruction 261 * is inserted before the call site. 262 */ 263 private Instruction lastOsrBarrier = null; 264 265 /** 266 * Debugging with method_to_print. Switch following 2 267 * to both be non-final. Set {@link #DBG_SELECTIVE} to true. 268 * {@link #DBG_SELECTED} will then be {@code true} when the method matches. 269 * You must also uncomment the assignment to DBG_SELECTIVE in 270 * {@link #start(GenerationContext)}. 271 */ 272 private static final boolean DBG_SELECTIVE = false; 273 static final boolean DBG_SELECTED = false; 274 275 ////////// 276 // End of field declarations 277 ////////// 278 279 /** 280 * Construct the BC2IR object for the generation context. 281 * After the constructor completes, we're ready to start generating 282 * HIR from bytecode 0 of context.method. 283 * 284 * @param context the context to generate HIR into 285 */ 286 private BC2IR(GenerationContext context) { 287 start(context); 288 for (int argIdx = 0, localIdx = 0; argIdx < context.getArguments().length;) { 289 TypeReference argType = context.getArguments()[argIdx].getType(); 290 _localState[localIdx++] = context.getArguments()[argIdx++]; 291 if (argType.isLongType() || argType.isDoubleType()) { 292 _localState[localIdx++] = DUMMY; 293 } 294 } 295 finish(context); 296 } 297 298 @NoInline 299 private void start(GenerationContext context) { 300 gc = context; 301 // To use the following you need to change the declarations 302 // above the constructor 303 if (DBG_SELECTIVE) { 304 VM.sysWrite("Whoops! you need to uncomment the assignment to DBG_SELECTED"); 305// DBG_SELECTED = gc.methodIsSelectedForDebuggingWithMethodToPrint(); 306 } 307 308 if (context.getMethod().isForOsrSpecialization()) { 309 bcodes = context.getMethod().getOsrSynthesizedBytecodes(); 310 } else { 311 bcodes = context.getMethod().getBytecodes(); 312 } 313 314 // initialize the local state from context.arguments 315 _localState = new Operand[context.getMethod().getLocalWords()]; 316 317 if (context.getMethod().isForOsrSpecialization()) { 318 this.bciAdjustment = context.getMethod().getOsrPrologueLength(); 319 } else { 320 this.bciAdjustment = 0; 321 } 322 323 this.osrGuardedInline = VM.runningVM && 324 context.getOptions().OSR_GUARDED_INLINING && 325 !context.getMethod().isForOsrSpecialization() && 326 OptimizingCompiler.getAppStarted() && 327 (Controller.options != null) && 328 Controller.options.ENABLE_RECOMPILATION; 329 } 330 331 private void finish(GenerationContext context) { 332 // Initialize simulated stack. 333 stack = new OperandStack(context.getMethod().getOperandWords()); 334 // Initialize BBSet. 335 blocks = new BBSet(context, bcodes, _localState); 336 // Finish preparing to generate from bytecode 0 337 currentBBLE = blocks.getEntry(); 338 gc.getPrologue().insertOut(currentBBLE.block); 339 if (DBG_CFG || DBG_SELECTED) { 340 db("Added CFG edge from " + gc.getPrologue() + " to " + currentBBLE.block); 341 } 342 runoff = currentBBLE.max; 343 } 344 345 /** 346 * Main generation loop. 347 */ 348 private void generateHIR() { 349 // Constructor initialized generation state to start 350 // generating from bytecode 0, so get the ball rolling. 351 if (DBG_BB || DBG_SELECTED) db("bbl: " + printBlocks()); 352 generateFrom(0); 353 // While there are more blocks that need it, pick one and generate it. 354 for (currentBBLE = blocks.getNextEmptyBlock(currentBBLE); currentBBLE != null; currentBBLE = 355 blocks.getNextEmptyBlock(currentBBLE)) { 356 // Found a block. Set the generation state appropriately. 357 currentBBLE.clearSelfRegen(); 358 runoff = Math.min(blocks.getNextBlockBytecodeIndex(currentBBLE), currentBBLE.max); 359 if (currentBBLE.stackState == null) { 360 stack.clear(); 361 } else { 362 stack = currentBBLE.stackState.deepCopy(); 363 } 364 _localState = currentBBLE.copyLocalState(); 365 if (DBG_BB || DBG_SELECTED) db("bbl: " + printBlocks()); 366 // Generate it! 367 generateFrom(currentBBLE.low); 368 } 369 // Construct initial code order, commit to recursive inlines, 370 // insert any synthetic blocks. 371 if (DBG_BB || DBG_SELECTED) db("doing final pass over basic blocks: " + printBlocks()); 372 blocks.finalPass(inlinedSomething); 373 } 374 375 // pops the length off the stack 376 // 377 public Instruction generateAnewarray(TypeReference arrayTypeRef, TypeReference elementTypeRef) { 378 if (arrayTypeRef == null) { 379 if (VM.VerifyAssertions) opt_assert(elementTypeRef != null); 380 arrayTypeRef = elementTypeRef.getArrayTypeForElementType(); 381 } 382 if (elementTypeRef == null) { 383 elementTypeRef = arrayTypeRef.getArrayElementType(); 384 } 385 386 RegisterOperand t = gc.getTemps().makeTemp(arrayTypeRef); 387 t.setPreciseType(); 388 markGuardlessNonNull(t); 389 // We can do early resolution of the array type if the element type 390 // is already initialized. 391 RVMType arrayType = arrayTypeRef.peekType(); 392 Operator op; 393 TypeOperand arrayOp; 394 395 if ((arrayType != null) && (arrayType.isInitialized() || arrayType.isInBootImage())) { 396 op = NEWARRAY; 397 arrayOp = makeTypeOperand(arrayType); 398 t.setExtant(); 399 } else { 400 RVMType elementType = elementTypeRef.peekType(); 401 if ((elementType != null) && (elementType.isInitialized() || elementType.isInBootImage())) { 402 arrayType = arrayTypeRef.resolve(); 403 arrayType.resolve(); 404 arrayType.instantiate(); 405 op = NEWARRAY; 406 arrayOp = makeTypeOperand(arrayType); 407 t.setExtant(); 408 } else { 409 op = NEWARRAY_UNRESOLVED; 410 arrayOp = makeTypeOperand(arrayTypeRef); 411 } 412 } 413 Instruction s = NewArray.create(op, t, arrayOp, popInt()); 414 push(t.copyD2U()); 415 rectifyStateWithErrorHandler(); 416 rectifyStateWithExceptionHandler(TypeReference.JavaLangNegativeArraySizeException); 417 return s; 418 } 419 420 /** 421 * Generate instructions for a basic block. 422 * May discover other basic blocks that need to be generated along the way. 423 * 424 * @param fromIndex bytecode index to start from 425 */ 426 private void generateFrom(int fromIndex) { 427 if (DBG_BB || DBG_SELECTED) { 428 db("generating code into " + currentBBLE + " with runoff " + runoff); 429 } 430 currentBBLE.setGenerated(); 431 endOfBasicBlock = fallThrough = false; 432 lastInstr = null; 433 bcodes.reset(fromIndex); 434 while (true) { 435 // Must keep currentBBLE.high up-to-date in case we try to jump into 436 // the middle of the block we're currently generating. Simply updating 437 // high once endsBasicBlock is true doesn't enable us to catch this case. 438 currentBBLE.high = instrIndex = bcodes.index(); 439 int code = bcodes.nextInstruction(); 440 if (DBG_BCPARSE) { 441 db("parsing " + 442 instrIndex + 443 " " + 444 code + 445 " : 0x" + 446 Integer.toHexString(code) + 447 " " + 448 JBC_name(code)); 449 } 450 Instruction s = null; 451 452 lastOsrBarrier = null; 453 454 switch (code) { 455 case JBC_nop: 456 break; 457 458 case JBC_aconst_null: 459 push(new NullConstantOperand()); 460 break; 461 462 case JBC_iconst_m1: 463 case JBC_iconst_0: 464 case JBC_iconst_1: 465 case JBC_iconst_2: 466 case JBC_iconst_3: 467 case JBC_iconst_4: 468 case JBC_iconst_5: 469 push(new IntConstantOperand(code - JBC_iconst_0)); 470 break; 471 472 case JBC_lconst_0: 473 case JBC_lconst_1: 474 pushDual(new LongConstantOperand(code - JBC_lconst_0)); 475 break; 476 477 case JBC_fconst_0: 478 push(new FloatConstantOperand(0.f)); 479 break; 480 481 case JBC_fconst_1: 482 push(new FloatConstantOperand(1.f)); 483 break; 484 485 case JBC_fconst_2: 486 push(new FloatConstantOperand(2.f)); 487 break; 488 489 case JBC_dconst_0: 490 pushDual(new DoubleConstantOperand(0.)); 491 break; 492 493 case JBC_dconst_1: 494 pushDual(new DoubleConstantOperand(1.)); 495 break; 496 497 case JBC_bipush: 498 push(new IntConstantOperand(bcodes.getByteValue())); 499 break; 500 501 case JBC_sipush: 502 push(new IntConstantOperand(bcodes.getShortValue())); 503 break; 504 505 case JBC_ldc: 506 push(getConstantOperand(bcodes.getConstantIndex())); 507 break; 508 509 case JBC_ldc_w: 510 push(getConstantOperand(bcodes.getWideConstantIndex())); 511 break; 512 513 case JBC_ldc2_w: 514 pushDual(getConstantOperand(bcodes.getWideConstantIndex())); 515 break; 516 517 case JBC_iload: 518 s = do_iload(bcodes.getLocalNumber()); 519 break; 520 521 case JBC_lload: 522 s = do_lload(bcodes.getLocalNumber()); 523 break; 524 525 case JBC_fload: 526 s = do_fload(bcodes.getLocalNumber()); 527 break; 528 529 case JBC_dload: 530 s = do_dload(bcodes.getLocalNumber()); 531 break; 532 533 case JBC_aload: 534 s = do_aload(bcodes.getLocalNumber()); 535 break; 536 537 case JBC_iload_0: 538 case JBC_iload_1: 539 case JBC_iload_2: 540 case JBC_iload_3: 541 s = do_iload(code - JBC_iload_0); 542 break; 543 544 case JBC_lload_0: 545 case JBC_lload_1: 546 case JBC_lload_2: 547 case JBC_lload_3: 548 s = do_lload(code - JBC_lload_0); 549 break; 550 551 case JBC_fload_0: 552 case JBC_fload_1: 553 case JBC_fload_2: 554 case JBC_fload_3: 555 s = do_fload(code - JBC_fload_0); 556 break; 557 558 case JBC_dload_0: 559 case JBC_dload_1: 560 case JBC_dload_2: 561 case JBC_dload_3: 562 s = do_dload(code - JBC_dload_0); 563 break; 564 565 case JBC_aload_0: 566 case JBC_aload_1: 567 case JBC_aload_2: 568 case JBC_aload_3: 569 s = do_aload(code - JBC_aload_0); 570 break; 571 572 case JBC_iaload: { 573 Operand index = popInt(); 574 Operand ref = pop(); 575 clearCurrentGuard(); 576 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 577 break; 578 } 579 if (VM.VerifyAssertions) { 580 assertIsType(ref, TypeReference.IntArray); 581 } 582 s = _aloadHelper(INT_ALOAD, ref, index, TypeReference.Int); 583 } 584 break; 585 586 case JBC_laload: { 587 Operand index = popInt(); 588 Operand ref = pop(); 589 clearCurrentGuard(); 590 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 591 break; 592 } 593 if (VM.VerifyAssertions) { 594 assertIsType(ref, TypeReference.LongArray); 595 } 596 s = _aloadHelper(LONG_ALOAD, ref, index, TypeReference.Long); 597 } 598 break; 599 600 case JBC_faload: { 601 Operand index = popInt(); 602 Operand ref = pop(); 603 clearCurrentGuard(); 604 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 605 break; 606 } 607 if (VM.VerifyAssertions) { 608 assertIsType(ref, TypeReference.FloatArray); 609 } 610 s = _aloadHelper(FLOAT_ALOAD, ref, index, TypeReference.Float); 611 } 612 break; 613 614 case JBC_daload: { 615 Operand index = popInt(); 616 Operand ref = pop(); 617 clearCurrentGuard(); 618 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 619 break; 620 } 621 if (VM.VerifyAssertions) { 622 assertIsType(ref, TypeReference.DoubleArray); 623 } 624 s = _aloadHelper(DOUBLE_ALOAD, ref, index, TypeReference.Double); 625 } 626 break; 627 628 case JBC_aaload: { 629 Operand index = popInt(); 630 Operand ref = pop(); 631 clearCurrentGuard(); 632 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 633 break; 634 } 635 TypeReference type = getRefTypeOf(ref).getArrayElementType(); 636 if (VM.VerifyAssertions) opt_assert(type.isReferenceType()); 637 s = _aloadHelper(REF_ALOAD, ref, index, type); 638 } 639 break; 640 641 case JBC_baload: { 642 Operand index = popInt(); 643 Operand ref = pop(); 644 clearCurrentGuard(); 645 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 646 break; 647 } 648 TypeReference type = getArrayTypeOf(ref); 649 if (VM.VerifyAssertions) { 650 opt_assert(type == TypeReference.ByteArray || type == TypeReference.BooleanArray); 651 } 652 if (type == TypeReference.ByteArray) { 653 s = _aloadHelper(BYTE_ALOAD, ref, index, TypeReference.Byte); 654 } else { 655 s = _aloadHelper(UBYTE_ALOAD, ref, index, TypeReference.Boolean); 656 } 657 } 658 break; 659 660 case JBC_caload: { 661 Operand index = popInt(); 662 Operand ref = pop(); 663 clearCurrentGuard(); 664 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 665 break; 666 } 667 if (VM.VerifyAssertions) { 668 assertIsType(ref, TypeReference.CharArray); 669 } 670 s = _aloadHelper(USHORT_ALOAD, ref, index, TypeReference.Char); 671 } 672 break; 673 674 case JBC_saload: { 675 Operand index = popInt(); 676 Operand ref = pop(); 677 clearCurrentGuard(); 678 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 679 break; 680 } 681 if (VM.VerifyAssertions) { 682 assertIsType(ref, TypeReference.ShortArray); 683 } 684 s = _aloadHelper(SHORT_ALOAD, ref, index, TypeReference.Short); 685 } 686 break; 687 688 case JBC_istore: 689 s = do_store(bcodes.getLocalNumber(), popInt()); 690 break; 691 692 case JBC_lstore: 693 s = do_store(bcodes.getLocalNumber(), popLong()); 694 break; 695 696 case JBC_fstore: 697 s = do_store(bcodes.getLocalNumber(), popFloat()); 698 break; 699 700 case JBC_dstore: 701 s = do_store(bcodes.getLocalNumber(), popDouble()); 702 break; 703 704 case JBC_astore: 705 s = do_astore(bcodes.getLocalNumber()); 706 break; 707 708 case JBC_istore_0: 709 case JBC_istore_1: 710 case JBC_istore_2: 711 case JBC_istore_3: 712 s = do_store(code - JBC_istore_0, popInt()); 713 break; 714 715 case JBC_lstore_0: 716 case JBC_lstore_1: 717 case JBC_lstore_2: 718 case JBC_lstore_3: 719 s = do_store(code - JBC_lstore_0, popLong()); 720 break; 721 722 case JBC_fstore_0: 723 case JBC_fstore_1: 724 case JBC_fstore_2: 725 case JBC_fstore_3: 726 s = do_store(code - JBC_fstore_0, popFloat()); 727 break; 728 729 case JBC_dstore_0: 730 case JBC_dstore_1: 731 case JBC_dstore_2: 732 case JBC_dstore_3: 733 s = do_store(code - JBC_dstore_0, popDouble()); 734 break; 735 736 case JBC_astore_0: 737 case JBC_astore_1: 738 case JBC_astore_2: 739 case JBC_astore_3: 740 s = do_astore(code - JBC_astore_0); 741 break; 742 743 case JBC_iastore: { 744 Operand val = popInt(); 745 Operand index = popInt(); 746 Operand ref = pop(); 747 clearCurrentGuard(); 748 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 749 break; 750 } 751 if (VM.VerifyAssertions) { 752 assertIsType(ref, TypeReference.IntArray); 753 } 754 s = 755 AStore.create(INT_ASTORE, 756 val, 757 ref, 758 index, 759 new LocationOperand(TypeReference.Int), 760 getCurrentGuard()); 761 } 762 break; 763 764 case JBC_lastore: { 765 Operand val = popLong(); 766 Operand index = popInt(); 767 Operand ref = pop(); 768 clearCurrentGuard(); 769 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 770 break; 771 } 772 if (VM.VerifyAssertions) { 773 assertIsType(ref, TypeReference.LongArray); 774 } 775 s = 776 AStore.create(LONG_ASTORE, 777 val, 778 ref, 779 index, 780 new LocationOperand(TypeReference.Long), 781 getCurrentGuard()); 782 } 783 break; 784 785 case JBC_fastore: { 786 Operand val = popFloat(); 787 Operand index = popInt(); 788 Operand ref = pop(); 789 clearCurrentGuard(); 790 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 791 break; 792 } 793 if (VM.VerifyAssertions) { 794 assertIsType(ref, TypeReference.FloatArray); 795 } 796 s = 797 AStore.create(FLOAT_ASTORE, 798 val, 799 ref, 800 index, 801 new LocationOperand(TypeReference.Float), 802 getCurrentGuard()); 803 } 804 break; 805 806 case JBC_dastore: { 807 Operand val = popDouble(); 808 Operand index = popInt(); 809 Operand ref = pop(); 810 clearCurrentGuard(); 811 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 812 break; 813 } 814 if (VM.VerifyAssertions) { 815 assertIsType(ref, TypeReference.DoubleArray); 816 } 817 s = 818 AStore.create(DOUBLE_ASTORE, 819 val, 820 ref, 821 index, 822 new LocationOperand(TypeReference.Double), 823 getCurrentGuard()); 824 } 825 break; 826 827 case JBC_aastore: { 828 Operand val = pop(); 829 Operand index = popInt(); 830 Operand ref = pop(); 831 clearCurrentGuard(); 832 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 833 break; 834 } 835 TypeReference type = getRefTypeOf(ref).getArrayElementType(); 836 if (VM.VerifyAssertions) opt_assert(type.isReferenceType()); 837 if (do_CheckStore(ref, val, type)) { 838 break; 839 } 840 s = AStore.create(REF_ASTORE, val, ref, index, new LocationOperand(type), getCurrentGuard()); 841 } 842 break; 843 844 case JBC_bastore: { 845 Operand val = popInt(); 846 Operand index = popInt(); 847 Operand ref = pop(); 848 clearCurrentGuard(); 849 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 850 break; 851 } 852 TypeReference type = getArrayTypeOf(ref); 853 if (VM.VerifyAssertions) { 854 opt_assert(type == TypeReference.ByteArray || type == TypeReference.BooleanArray); 855 } 856 if (type == TypeReference.ByteArray) { 857 type = TypeReference.Byte; 858 } else { 859 type = TypeReference.Boolean; 860 } 861 s = AStore.create(BYTE_ASTORE, val, ref, index, new LocationOperand(type), getCurrentGuard()); 862 } 863 break; 864 865 case JBC_castore: { 866 Operand val = popInt(); 867 Operand index = popInt(); 868 Operand ref = pop(); 869 clearCurrentGuard(); 870 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 871 break; 872 } 873 if (VM.VerifyAssertions) { 874 assertIsType(ref, TypeReference.CharArray); 875 } 876 s = 877 AStore.create(SHORT_ASTORE, 878 val, 879 ref, 880 index, 881 new LocationOperand(TypeReference.Char), 882 getCurrentGuard()); 883 } 884 break; 885 886 case JBC_sastore: { 887 Operand val = popInt(); 888 Operand index = popInt(); 889 Operand ref = pop(); 890 clearCurrentGuard(); 891 if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) { 892 break; 893 } 894 if (VM.VerifyAssertions) { 895 assertIsType(ref, TypeReference.ShortArray); 896 } 897 s = 898 AStore.create(SHORT_ASTORE, 899 val, 900 ref, 901 index, 902 new LocationOperand(TypeReference.Short), 903 getCurrentGuard()); 904 } 905 break; 906 907 case JBC_pop: 908 stack.pop(); 909 break; 910 911 case JBC_pop2: 912 stack.pop2(); 913 break; 914 915 case JBC_dup: { 916 Operand op1 = stack.pop(); 917 stack.push(op1); 918 s = pushCopy(op1); 919 } 920 break; 921 922 case JBC_dup_x1: { 923 Operand op1 = stack.pop(); 924 Operand op2 = stack.pop(); 925 stack.push(op1); 926 stack.push(op2); 927 s = pushCopy(op1); 928 } 929 break; 930 931 case JBC_dup_x2: { 932 Operand op1 = stack.pop(); 933 Operand op2 = stack.pop(); 934 Operand op3 = stack.pop(); 935 stack.push(op1); 936 stack.push(op3); 937 stack.push(op2); 938 s = pushCopy(op1); 939 } 940 break; 941 942 case JBC_dup2: { 943 Operand op1 = stack.pop(); 944 Operand op2 = stack.pop(); 945 stack.push(op2); 946 stack.push(op1); 947 s = pushCopy(op2); 948 if (s != null) { 949 appendInstruction(s); 950 s = null; 951 } 952 s = pushCopy(op1); 953 } 954 break; 955 956 case JBC_dup2_x1: { 957 Operand op1 = stack.pop(); 958 Operand op2 = stack.pop(); 959 Operand op3 = stack.pop(); 960 stack.push(op2); 961 stack.push(op1); 962 stack.push(op3); 963 s = pushCopy(op2); 964 if (s != null) { 965 appendInstruction(s); 966 s = null; 967 } 968 s = pushCopy(op1); 969 } 970 break; 971 972 case JBC_dup2_x2: { 973 Operand op1 = stack.pop(); 974 Operand op2 = stack.pop(); 975 Operand op3 = stack.pop(); 976 Operand op4 = stack.pop(); 977 stack.push(op2); 978 stack.push(op1); 979 stack.push(op4); 980 stack.push(op3); 981 s = pushCopy(op2); 982 if (s != null) { 983 appendInstruction(s); 984 s = null; 985 } 986 s = pushCopy(op1); 987 } 988 break; 989 990 case JBC_swap: { 991 stack.swap(); 992 } 993 break; 994 995 case JBC_iadd: { 996 Operand op2 = popInt(); 997 Operand op1 = popInt(); 998 s = _binaryHelper(INT_ADD, op1, op2, TypeReference.Int); 999 } 1000 break; 1001 1002 case JBC_ladd: { 1003 Operand op2 = popLong(); 1004 Operand op1 = popLong(); 1005 s = _binaryDualHelper(LONG_ADD, op1, op2, TypeReference.Long); 1006 } 1007 break; 1008 1009 case JBC_fadd: { 1010 Operand op2 = popFloat(); 1011 Operand op1 = popFloat(); 1012 s = _binaryHelper(FLOAT_ADD, op1, op2, TypeReference.Float); 1013 } 1014 break; 1015 1016 case JBC_dadd: { 1017 Operand op2 = popDouble(); 1018 Operand op1 = popDouble(); 1019 s = _binaryDualHelper(DOUBLE_ADD, op1, op2, TypeReference.Double); 1020 } 1021 break; 1022 1023 case JBC_isub: { 1024 Operand op2 = popInt(); 1025 Operand op1 = popInt(); 1026 s = _binaryHelper(INT_SUB, op1, op2, TypeReference.Int); 1027 } 1028 break; 1029 1030 case JBC_lsub: { 1031 Operand op2 = popLong(); 1032 Operand op1 = popLong(); 1033 s = _binaryDualHelper(LONG_SUB, op1, op2, TypeReference.Long); 1034 } 1035 break; 1036 1037 case JBC_fsub: { 1038 Operand op2 = popFloat(); 1039 Operand op1 = popFloat(); 1040 s = _binaryHelper(FLOAT_SUB, op1, op2, TypeReference.Float); 1041 } 1042 break; 1043 1044 case JBC_dsub: { 1045 Operand op2 = popDouble(); 1046 Operand op1 = popDouble(); 1047 s = _binaryDualHelper(DOUBLE_SUB, op1, op2, TypeReference.Double); 1048 } 1049 break; 1050 1051 case JBC_imul: { 1052 Operand op2 = popInt(); 1053 Operand op1 = popInt(); 1054 s = _binaryHelper(INT_MUL, op1, op2, TypeReference.Int); 1055 } 1056 break; 1057 1058 case JBC_lmul: { 1059 Operand op2 = popLong(); 1060 Operand op1 = popLong(); 1061 s = _binaryDualHelper(LONG_MUL, op1, op2, TypeReference.Long); 1062 } 1063 break; 1064 1065 case JBC_fmul: { 1066 Operand op2 = popFloat(); 1067 Operand op1 = popFloat(); 1068 s = _binaryHelper(FLOAT_MUL, op1, op2, TypeReference.Float); 1069 } 1070 break; 1071 1072 case JBC_dmul: { 1073 Operand op2 = popDouble(); 1074 Operand op1 = popDouble(); 1075 s = _binaryDualHelper(DOUBLE_MUL, op1, op2, TypeReference.Double); 1076 } 1077 break; 1078 1079 case JBC_idiv: { 1080 clearCurrentGuard(); 1081 Operand op2 = popInt(); 1082 Operand op1 = popInt(); 1083 if (do_IntZeroCheck(op2)) { 1084 break; 1085 } 1086 s = _guardedBinaryHelper(INT_DIV, op1, op2, getCurrentGuard(), TypeReference.Int); 1087 } 1088 break; 1089 1090 case JBC_ldiv: { 1091 clearCurrentGuard(); 1092 Operand op2 = popLong(); 1093 Operand op1 = popLong(); 1094 if (do_LongZeroCheck(op2)) { 1095 break; 1096 } 1097 s = _guardedBinaryDualHelper(LONG_DIV, op1, op2, getCurrentGuard(), TypeReference.Long); 1098 } 1099 break; 1100 1101 case JBC_fdiv: { 1102 Operand op2 = popFloat(); 1103 Operand op1 = popFloat(); 1104 s = _binaryHelper(FLOAT_DIV, op1, op2, TypeReference.Float); 1105 } 1106 break; 1107 1108 case JBC_ddiv: { 1109 Operand op2 = popDouble(); 1110 Operand op1 = popDouble(); 1111 s = _binaryDualHelper(DOUBLE_DIV, op1, op2, TypeReference.Double); 1112 } 1113 break; 1114 1115 case JBC_irem: { 1116 clearCurrentGuard(); 1117 Operand op2 = popInt(); 1118 Operand op1 = popInt(); 1119 if (do_IntZeroCheck(op2)) { 1120 break; 1121 } 1122 s = _guardedBinaryHelper(INT_REM, op1, op2, getCurrentGuard(), TypeReference.Int); 1123 } 1124 break; 1125 1126 case JBC_lrem: { 1127 clearCurrentGuard(); 1128 Operand op2 = popLong(); 1129 Operand op1 = popLong(); 1130 if (do_LongZeroCheck(op2)) { 1131 break; 1132 } 1133 s = _guardedBinaryDualHelper(LONG_REM, op1, op2, getCurrentGuard(), TypeReference.Long); 1134 } 1135 break; 1136 1137 case JBC_frem: { 1138 Operand op2 = popFloat(); 1139 Operand op1 = popFloat(); 1140 s = _binaryHelper(FLOAT_REM, op1, op2, TypeReference.Float); 1141 } 1142 break; 1143 1144 case JBC_drem: { 1145 Operand op2 = popDouble(); 1146 Operand op1 = popDouble(); 1147 s = _binaryDualHelper(DOUBLE_REM, op1, op2, TypeReference.Double); 1148 } 1149 break; 1150 1151 case JBC_ineg: 1152 s = _unaryHelper(INT_NEG, popInt(), TypeReference.Int); 1153 break; 1154 1155 case JBC_lneg: 1156 s = _unaryDualHelper(LONG_NEG, popLong(), TypeReference.Long); 1157 break; 1158 1159 case JBC_fneg: 1160 s = _unaryHelper(FLOAT_NEG, popFloat(), TypeReference.Float); 1161 break; 1162 1163 case JBC_dneg: 1164 s = _unaryDualHelper(DOUBLE_NEG, popDouble(), TypeReference.Double); 1165 break; 1166 1167 case JBC_ishl: { 1168 Operand op2 = popShiftInt(false); 1169 Operand op1 = popInt(); 1170 s = _binaryHelper(INT_SHL, op1, op2, TypeReference.Int); 1171 } 1172 break; 1173 1174 case JBC_lshl: { 1175 Operand op2 = popShiftInt(true); 1176 Operand op1 = popLong(); 1177 s = _binaryDualHelper(LONG_SHL, op1, op2, TypeReference.Long); 1178 } 1179 break; 1180 1181 case JBC_ishr: { 1182 Operand op2 = popShiftInt(false); 1183 Operand op1 = popInt(); 1184 s = _binaryHelper(INT_SHR, op1, op2, TypeReference.Int); 1185 } 1186 break; 1187 1188 case JBC_lshr: { 1189 Operand op2 = popShiftInt(true); 1190 Operand op1 = popLong(); 1191 s = _binaryDualHelper(LONG_SHR, op1, op2, TypeReference.Long); 1192 } 1193 break; 1194 1195 case JBC_iushr: { 1196 Operand op2 = popShiftInt(false); 1197 Operand op1 = popInt(); 1198 s = _binaryHelper(INT_USHR, op1, op2, TypeReference.Int); 1199 } 1200 break; 1201 1202 case JBC_lushr: { 1203 Operand op2 = popShiftInt(true); 1204 Operand op1 = popLong(); 1205 s = _binaryDualHelper(LONG_USHR, op1, op2, TypeReference.Long); 1206 } 1207 break; 1208 1209 case JBC_iand: { 1210 Operand op2 = popInt(); 1211 Operand op1 = popInt(); 1212 s = _binaryHelper(INT_AND, op1, op2, TypeReference.Int); 1213 } 1214 break; 1215 1216 case JBC_land: { 1217 Operand op2 = popLong(); 1218 Operand op1 = popLong(); 1219 s = _binaryDualHelper(LONG_AND, op1, op2, TypeReference.Long); 1220 } 1221 break; 1222 1223 case JBC_ior: { 1224 Operand op2 = popInt(); 1225 Operand op1 = popInt(); 1226 s = _binaryHelper(INT_OR, op1, op2, TypeReference.Int); 1227 } 1228 break; 1229 1230 case JBC_lor: { 1231 Operand op2 = popLong(); 1232 Operand op1 = popLong(); 1233 s = _binaryDualHelper(LONG_OR, op1, op2, TypeReference.Long); 1234 } 1235 break; 1236 1237 case JBC_ixor: { 1238 Operand op2 = popInt(); 1239 Operand op1 = popInt(); 1240 s = _binaryHelper(INT_XOR, op1, op2, TypeReference.Int); 1241 } 1242 break; 1243 1244 case JBC_lxor: { 1245 Operand op2 = popLong(); 1246 Operand op1 = popLong(); 1247 s = _binaryDualHelper(LONG_XOR, op1, op2, TypeReference.Long); 1248 } 1249 break; 1250 1251 case JBC_iinc: { 1252 int index = bcodes.getLocalNumber(); 1253 s = do_iinc(index, bcodes.getIncrement()); 1254 } 1255 break; 1256 1257 case JBC_i2l: 1258 s = _unaryDualHelper(INT_2LONG, popInt(), TypeReference.Long); 1259 break; 1260 1261 case JBC_i2f: 1262 s = _unaryHelper(INT_2FLOAT, popInt(), TypeReference.Float); 1263 break; 1264 1265 case JBC_i2d: 1266 s = _unaryDualHelper(INT_2DOUBLE, popInt(), TypeReference.Double); 1267 break; 1268 1269 case JBC_l2i: 1270 s = _unaryHelper(LONG_2INT, popLong(), TypeReference.Int); 1271 break; 1272 1273 case JBC_l2f: 1274 s = _unaryHelper(LONG_2FLOAT, popLong(), TypeReference.Float); 1275 break; 1276 1277 case JBC_l2d: 1278 s = _unaryDualHelper(LONG_2DOUBLE, popLong(), TypeReference.Double); 1279 break; 1280 1281 case JBC_f2i: 1282 s = _unaryHelper(FLOAT_2INT, popFloat(), TypeReference.Int); 1283 break; 1284 1285 case JBC_f2l: 1286 s = _unaryDualHelper(FLOAT_2LONG, popFloat(), TypeReference.Long); 1287 break; 1288 1289 case JBC_f2d: 1290 s = _unaryDualHelper(FLOAT_2DOUBLE, popFloat(), TypeReference.Double); 1291 break; 1292 1293 case JBC_d2i: 1294 s = _unaryHelper(DOUBLE_2INT, popDouble(), TypeReference.Int); 1295 break; 1296 1297 case JBC_d2l: 1298 s = _unaryDualHelper(DOUBLE_2LONG, popDouble(), TypeReference.Long); 1299 break; 1300 1301 case JBC_d2f: 1302 s = _unaryHelper(DOUBLE_2FLOAT, popDouble(), TypeReference.Float); 1303 break; 1304 1305 case JBC_int2byte: 1306 s = _unaryHelper(INT_2BYTE, popInt(), TypeReference.Byte); 1307 break; 1308 1309 case JBC_int2char: 1310 s = _unaryHelper(INT_2USHORT, popInt(), TypeReference.Char); 1311 break; 1312 1313 case JBC_int2short: 1314 s = _unaryHelper(INT_2SHORT, popInt(), TypeReference.Short); 1315 break; 1316 1317 case JBC_lcmp: { 1318 Operand op2 = popLong(); 1319 Operand op1 = popLong(); 1320 s = _binaryHelper(LONG_CMP, op1, op2, TypeReference.Int); 1321 } 1322 break; 1323 1324 case JBC_fcmpl: { 1325 Operand op2 = popFloat(); 1326 Operand op1 = popFloat(); 1327 s = _binaryHelper(FLOAT_CMPL, op1, op2, TypeReference.Int); 1328 } 1329 break; 1330 1331 case JBC_fcmpg: { 1332 Operand op2 = popFloat(); 1333 Operand op1 = popFloat(); 1334 s = _binaryHelper(FLOAT_CMPG, op1, op2, TypeReference.Int); 1335 } 1336 break; 1337 1338 case JBC_dcmpl: { 1339 Operand op2 = popDouble(); 1340 Operand op1 = popDouble(); 1341 s = _binaryHelper(DOUBLE_CMPL, op1, op2, TypeReference.Int); 1342 } 1343 break; 1344 1345 case JBC_dcmpg: { 1346 Operand op2 = popDouble(); 1347 Operand op1 = popDouble(); 1348 s = _binaryHelper(DOUBLE_CMPG, op1, op2, TypeReference.Int); 1349 } 1350 break; 1351 1352 case JBC_ifeq: 1353 s = _intIfHelper(ConditionOperand.EQUAL()); 1354 break; 1355 1356 case JBC_ifne: 1357 s = _intIfHelper(ConditionOperand.NOT_EQUAL()); 1358 break; 1359 1360 case JBC_iflt: 1361 s = _intIfHelper(ConditionOperand.LESS()); 1362 break; 1363 1364 case JBC_ifge: 1365 s = _intIfHelper(ConditionOperand.GREATER_EQUAL()); 1366 break; 1367 1368 case JBC_ifgt: 1369 s = _intIfHelper(ConditionOperand.GREATER()); 1370 break; 1371 1372 case JBC_ifle: 1373 s = _intIfHelper(ConditionOperand.LESS_EQUAL()); 1374 break; 1375 1376 case JBC_if_icmpeq: 1377 s = _intIfCmpHelper(ConditionOperand.EQUAL()); 1378 break; 1379 1380 case JBC_if_icmpne: 1381 s = _intIfCmpHelper(ConditionOperand.NOT_EQUAL()); 1382 break; 1383 1384 case JBC_if_icmplt: 1385 s = _intIfCmpHelper(ConditionOperand.LESS()); 1386 break; 1387 1388 case JBC_if_icmpge: 1389 s = _intIfCmpHelper(ConditionOperand.GREATER_EQUAL()); 1390 break; 1391 1392 case JBC_if_icmpgt: 1393 s = _intIfCmpHelper(ConditionOperand.GREATER()); 1394 break; 1395 1396 case JBC_if_icmple: 1397 s = _intIfCmpHelper(ConditionOperand.LESS_EQUAL()); 1398 break; 1399 1400 case JBC_if_acmpeq: 1401 s = _refIfCmpHelper(ConditionOperand.EQUAL()); 1402 break; 1403 1404 case JBC_if_acmpne: 1405 s = _refIfCmpHelper(ConditionOperand.NOT_EQUAL()); 1406 break; 1407 1408 case JBC_goto: { 1409 int offset = bcodes.getBranchOffset(); 1410 if (offset != 3) { 1411 // skip generating frivolous goto's 1412 s = _gotoHelper(offset); 1413 } 1414 } 1415 break; 1416 1417 case JBC_jsr: 1418 s = _jsrHelper(bcodes.getBranchOffset()); 1419 break; 1420 1421 case JBC_ret: 1422 s = _retHelper(bcodes.getLocalNumber()); 1423 break; 1424 1425 case JBC_tableswitch: { 1426 bcodes.alignSwitch(); 1427 Operand op0 = popInt(); 1428 int defaultoff = bcodes.getDefaultSwitchOffset(); 1429 int low = bcodes.getLowSwitchValue(); 1430 int high = bcodes.getHighSwitchValue(); 1431 int number = high - low + 1; 1432 if (CF_TABLESWITCH && op0 instanceof IntConstantOperand) { 1433 int v1 = ((IntConstantOperand) op0).value; 1434 int match = bcodes.computeTableSwitchOffset(v1, low, high); 1435 int offset = match == 0 ? defaultoff : match; 1436 bcodes.skipTableSwitchOffsets(number); 1437 if (DBG_CF) { 1438 db("changed tableswitch to goto because index (" + v1 + ") is constant"); 1439 } 1440 s = _gotoHelper(offset); 1441 break; 1442 } 1443 s = 1444 TableSwitch.create(TABLESWITCH, 1445 op0, 1446 null, 1447 null, 1448 new IntConstantOperand(low), 1449 new IntConstantOperand(high), 1450 generateTarget(defaultoff), 1451 null, 1452 number * 2); 1453 for (int i = 0; i < number; ++i) { 1454 TableSwitch.setTarget(s, i, generateTarget(bcodes.getTableSwitchOffset(i))); 1455 } 1456 bcodes.skipTableSwitchOffsets(number); 1457 1458 // Set branch probabilities 1459 SwitchBranchProfile sp = gc.getSwitchProfile(instrIndex - bciAdjustment); 1460 if (sp == null) { 1461 float approxProb = 1.0f / (number + 1); // number targets + default 1462 TableSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(approxProb)); 1463 for (int i = 0; i < number; ++i) { 1464 TableSwitch.setBranchProfile(s, i, new BranchProfileOperand(approxProb)); 1465 } 1466 } else { 1467 TableSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(sp.getDefaultProbability())); 1468 for (int i = 0; i < number; ++i) { 1469 TableSwitch.setBranchProfile(s, i, new BranchProfileOperand(sp.getCaseProbability(i))); 1470 } 1471 } 1472 } 1473 break; 1474 1475 case JBC_lookupswitch: { 1476 bcodes.alignSwitch(); 1477 Operand op0 = popInt(); 1478 int defaultoff = bcodes.getDefaultSwitchOffset(); 1479 int numpairs = bcodes.getSwitchLength(); 1480 if (numpairs == 0) { 1481 s = _gotoHelper(defaultoff); 1482 break; 1483 } 1484 if (CF_LOOKUPSWITCH && op0 instanceof IntConstantOperand) { 1485 int v1 = ((IntConstantOperand) op0).value; 1486 int match = bcodes.computeLookupSwitchOffset(v1, numpairs); 1487 int offset = match == 0 ? defaultoff : match; 1488 bcodes.skipLookupSwitchPairs(numpairs); 1489 if (DBG_CF) { 1490 db("changed lookupswitch to goto because index (" + v1 + ") is constant"); 1491 } 1492 s = _gotoHelper(offset); 1493 break; 1494 } 1495 1496 // Construct switch 1497 s = LookupSwitch.create(LOOKUPSWITCH, op0, null, null, generateTarget(defaultoff), null, numpairs * 3); 1498 for (int i = 0; i < numpairs; ++i) { 1499 LookupSwitch.setMatch(s, i, new IntConstantOperand(bcodes.getLookupSwitchValue(i))); 1500 LookupSwitch.setTarget(s, i, generateTarget(bcodes.getLookupSwitchOffset(i))); 1501 } 1502 bcodes.skipLookupSwitchPairs(numpairs); 1503 1504 // Set branch probabilities 1505 SwitchBranchProfile sp = gc.getSwitchProfile(instrIndex - bciAdjustment); 1506 if (sp == null) { 1507 float approxProb = 1.0f / (numpairs + 1); // num targets + default 1508 LookupSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(approxProb)); 1509 for (int i = 0; i < numpairs; ++i) { 1510 LookupSwitch.setBranchProfile(s, i, new BranchProfileOperand(approxProb)); 1511 } 1512 } else { 1513 LookupSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(sp.getDefaultProbability())); 1514 for (int i = 0; i < numpairs; ++i) { 1515 LookupSwitch.setBranchProfile(s, i, new BranchProfileOperand(sp.getCaseProbability(i))); 1516 } 1517 } 1518 } 1519 break; 1520 1521 case JBC_ireturn: 1522 _returnHelper(INT_MOVE, popInt()); 1523 break; 1524 1525 case JBC_lreturn: 1526 _returnHelper(LONG_MOVE, popLong()); 1527 break; 1528 1529 case JBC_freturn: 1530 _returnHelper(FLOAT_MOVE, popFloat()); 1531 break; 1532 1533 case JBC_dreturn: 1534 _returnHelper(DOUBLE_MOVE, popDouble()); 1535 break; 1536 1537 case JBC_areturn: { 1538 Operand op0 = popRef(); 1539 if (VM.VerifyAssertions && !op0.isDefinitelyNull()) { 1540 TypeReference retType = op0.getType(); 1541 assertIsAssignable(gc.getMethod().getReturnType(), retType); 1542 } 1543 _returnHelper(REF_MOVE, op0); 1544 } 1545 break; 1546 1547 case JBC_return: 1548 _returnHelper(null, null); 1549 break; 1550 1551 case JBC_getstatic: { 1552 // field resolution 1553 FieldReference ref = bcodes.getFieldReference(); 1554 boolean unresolved = ref.needsDynamicLink(bcodes.getMethod()); 1555 LocationOperand fieldOp = makeStaticFieldRef(ref); 1556 Operand offsetOp; 1557 TypeReference fieldType = ref.getFieldContentsType(); 1558 RegisterOperand t = gc.getTemps().makeTemp(fieldType); 1559 if (unresolved) { 1560 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1561 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy())); 1562 offsetOp = offsetrop; 1563 rectifyStateWithErrorHandler(); 1564 } else { 1565 RVMField field = ref.peekResolvedField(); 1566 offsetOp = new AddressConstantOperand(field.getOffset()); 1567 1568 // use results of field analysis to refine type of result 1569 RVMType ft = fieldType.peekType(); 1570 if (ft != null && ft.isClassType()) { 1571 TypeReference concreteType = FieldAnalysis.getConcreteType(field); 1572 if (concreteType != null) { 1573 if (concreteType == fieldType) { 1574 t.setDeclaredType(); 1575 t.setPreciseType(); 1576 } else { 1577 fieldType = concreteType; 1578 t.setPreciseType(concreteType); 1579 } 1580 } 1581 } 1582 1583 // optimization: if the field is final and either 1584 // initialized or we're writing the bootimage and the field 1585 // is from a suitable class, then get the value at compile 1586 // time. 1587 if (gc.getOptions().SIMPLIFY_CHASE_FINAL_FIELDS && field.isFinal()) { 1588 RVMClass declaringClass = field.getDeclaringClass(); 1589 1590 boolean initializedClassAtRuntime = VM.runningVM & declaringClass.isInitialized(); 1591 boolean fieldFromRVMInternalClassInBootImage = declaringClass.isInBootImage() && 1592 declaringClass.getDescriptor().isRVMDescriptor(); 1593 // We cannot assume that non-public fields from the host JVM's class library are present in 1594 // the class library used by Jikes RVM: only public fields are part of the API. 1595 boolean publicFieldInBootImage = declaringClass.isInBootImage() && 1596 field.isPublic(); 1597 1598 if (initializedClassAtRuntime || fieldFromRVMInternalClassInBootImage || 1599 publicFieldInBootImage) { 1600 try { 1601 ConstantOperand rhs = StaticFieldReader.getStaticFieldValue(field); 1602 // VM.sysWrite("Replaced getstatic of "+field+" with "+rhs+"\n"); 1603 push(rhs, fieldType); 1604 break; 1605 } catch (NoSuchFieldException e) { 1606 if (VM.runningVM) { 1607 throw new Error("Unexpected exception", e); 1608 } else { 1609 // Field not found during bootstrap due to chasing a field 1610 // only valid in the bootstrap JVM. 1611 1612 // Although we try to avoid most cases where this could happen, we cannot 1613 // avoid all. For example, a NoSuchFieldException can occur when we're trying 1614 // to optimize a public field from Jikes RVM's class library that's not present 1615 // in the host JVM's class library (example: a field from an internal 1616 // helper class). 1617 } 1618 } 1619 } 1620 } else if (field.isRuntimeFinal()) { 1621 if (VM.VerifyAssertions) opt_assert(fieldType.isBooleanType()); 1622 boolean rhsBool = field.getRuntimeFinalValue(); 1623 push(new IntConstantOperand(rhsBool ? 1 : 0)); 1624 break; 1625 } 1626 } 1627 1628 s = GetStatic.create(GETSTATIC, t, offsetOp, fieldOp); 1629 if (fieldOp.mayBeVolatile()) { 1630 appendInstruction(s); 1631 s = Empty.create(READ_CEILING); 1632 } 1633 1634 push(t.copyD2U(), fieldType); 1635 } 1636 break; 1637 1638 case JBC_putstatic: { 1639 // field resolution 1640 FieldReference ref = bcodes.getFieldReference(); 1641 boolean unresolved = ref.needsDynamicLink(bcodes.getMethod()); 1642 LocationOperand fieldOp = makeStaticFieldRef(ref); 1643 Operand offsetOp; 1644 if (unresolved) { 1645 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1646 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy())); 1647 offsetOp = offsetrop; 1648 rectifyStateWithErrorHandler(); 1649 } else { 1650 RVMField field = ref.peekResolvedField(); 1651 offsetOp = new AddressConstantOperand(field.getOffset()); 1652 } 1653 1654 TypeReference fieldType = ref.getFieldContentsType(); 1655 Operand r = pop(fieldType); 1656 if (fieldOp.mayBeVolatile()) { 1657 appendInstruction(Empty.create(WRITE_FLOOR)); 1658 } 1659 s = PutStatic.create(PUTSTATIC, r, offsetOp, fieldOp); 1660 if (fieldOp.mayBeVolatile()) { 1661 appendInstruction(s); 1662 s = Empty.create(FENCE); 1663 } 1664 } 1665 break; 1666 1667 case JBC_getfield: { 1668 // field resolution 1669 FieldReference ref = bcodes.getFieldReference(); 1670 boolean unresolved = ref.needsDynamicLink(bcodes.getMethod()); 1671 LocationOperand fieldOp = makeInstanceFieldRef(ref); 1672 Operand offsetOp; 1673 TypeReference fieldType = ref.getFieldContentsType(); 1674 RVMField field = null; 1675 RegisterOperand t = gc.getTemps().makeTemp(fieldType); 1676 if (unresolved) { 1677 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1678 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy())); 1679 offsetOp = offsetrop; 1680 rectifyStateWithErrorHandler(); 1681 } else { 1682 field = ref.peekResolvedField(); 1683 offsetOp = new AddressConstantOperand(field.getOffset()); 1684 1685 // use results of field analysis to refine type. 1686 RVMType ft = fieldType.peekType(); 1687 if (ft != null && ft.isClassType()) { 1688 TypeReference concreteType = FieldAnalysis.getConcreteType(field); 1689 if (concreteType != null) { 1690 if (concreteType == fieldType) { 1691 t.setDeclaredType(); 1692 t.setPreciseType(); 1693 } else { 1694 fieldType = concreteType; 1695 t.setType(concreteType); 1696 t.setPreciseType(); 1697 } 1698 } 1699 } 1700 } 1701 1702 Operand op1 = pop(); 1703 clearCurrentGuard(); 1704 if (do_NullCheck(op1)) { 1705 break; 1706 } 1707 1708 // optimization: if the field is final and referenced by a 1709 // constant reference then get the value at compile time. 1710 // NB avoid String fields 1711 if (op1.isConstant() && field.isFinal()) { 1712 try { 1713 ConstantOperand rhs = 1714 StaticFieldReader.getFieldValueAsConstant(field, op1.asObjectConstant().value); 1715 push(rhs, fieldType); 1716 break; 1717 } catch (NoSuchFieldException e) { 1718 if (VM.runningVM) { // this is unexpected 1719 throw new Error("Unexpected exception", e); 1720 } else { 1721 // Field not found during bootstrap due to chasing a field 1722 // only valid in the bootstrap JVM 1723 } 1724 } 1725 } 1726 1727 s = GetField.create(GETFIELD, t, op1, offsetOp, fieldOp, getCurrentGuard()); 1728 if (fieldOp.mayBeVolatile()) { 1729 appendInstruction(s); 1730 s = Empty.create(READ_CEILING); 1731 } 1732 1733 push(t.copyD2U(), fieldType); 1734 } 1735 break; 1736 1737 case JBC_putfield: { 1738 // field resolution 1739 FieldReference ref = bcodes.getFieldReference(); 1740 boolean unresolved = ref.needsDynamicLink(bcodes.getMethod()); 1741 LocationOperand fieldOp = makeInstanceFieldRef(ref); 1742 TypeReference fieldType = ref.getFieldContentsType(); 1743 Operand offsetOp; 1744 if (unresolved) { 1745 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1746 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy())); 1747 offsetOp = offsetrop; 1748 rectifyStateWithErrorHandler(); 1749 } else { 1750 RVMField field = ref.peekResolvedField(); 1751 offsetOp = new AddressConstantOperand(field.getOffset()); 1752 } 1753 1754 Operand val = pop(fieldType); 1755 Operand obj = popRef(); 1756 clearCurrentGuard(); 1757 if (do_NullCheck(obj)) { 1758 break; 1759 } 1760 1761 if (fieldOp.mayBeVolatile()) { 1762 appendInstruction(Empty.create(WRITE_FLOOR)); 1763 } 1764 s = PutField.create(PUTFIELD, val, obj, offsetOp, fieldOp, getCurrentGuard()); 1765 if (fieldOp.mayBeVolatile()) { 1766 appendInstruction(s); 1767 s = Empty.create(FENCE); 1768 } 1769 } 1770 break; 1771 1772 case JBC_invokevirtual: { 1773 MethodReference ref = bcodes.getMethodReference(); 1774 1775 // See if this is a magic method (Address, Word, etc.) 1776 // If it is, generate the inline code and we are done. 1777 if (ref.isMagic()) { 1778 boolean generated = GenerateMagic.generateMagic(this, gc, ref); 1779 if (generated) break; // all done. 1780 } 1781 1782 /* just create an osr barrier right before _callHelper 1783 * changes the states of locals and stacks. 1784 */ 1785 if (this.osrGuardedInline) { 1786 lastOsrBarrier = _createOsrBarrier(); 1787 } 1788 1789 if (ref.isMiranda()) { 1790 // An invokevirtual that is really an invokeinterface. 1791 s = _callHelper(ref, MethodOperand.INTERFACE(ref, null)); 1792 if (s == null) 1793 break; 1794 Operand receiver = Call.getParam(s, 0); 1795 RVMClass receiverType = (RVMClass) receiver.getType().peekType(); 1796 // null check on this parameter of call 1797 clearCurrentGuard(); 1798 if (do_NullCheck(receiver)) { 1799 // call will always raise null pointer exception 1800 s = null; 1801 break; 1802 } 1803 Call.setGuard(s, getCurrentGuard()); 1804 1805 // Attempt to resolve the interface call to a particular virtual method. 1806 // This is independent of whether or not the static type of the receiver is 1807 // known to implement the interface and it is not that case that being able 1808 // to prove one implies the other. 1809 RVMMethod vmeth = null; 1810 if (receiverType != null && receiverType.isInitialized() && !receiverType.isInterface()) { 1811 vmeth = ClassLoaderProxy.lookupMethod(receiverType, ref); 1812 } 1813 if (vmeth != null) { 1814 MethodReference vmethRef = vmeth.getMemberRef().asMethodReference(); 1815 MethodOperand mop = MethodOperand.VIRTUAL(vmethRef, vmeth); 1816 if (receiver.isConstant() || (receiver.isRegister() && receiver.asRegister().isPreciseType())) { 1817 mop.refine(vmeth, true); 1818 } 1819 Call.setMethod(s, mop); 1820 boolean unresolved = vmethRef.needsDynamicLink(bcodes.getMethod()); 1821 if (unresolved) { 1822 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1823 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy())); 1824 Call.setAddress(s, offsetrop); 1825 rectifyStateWithErrorHandler(); 1826 } else { 1827 Call.setAddress(s, new AddressConstantOperand(vmeth.getOffset())); 1828 } 1829 1830 // Attempt to inline virtualized call. 1831 if (maybeInlineMethod(shouldInline(s, 1832 receiver.isConstant() || 1833 (receiver.isRegister() && receiver.asRegister().isExtant()), 1834 instrIndex - bciAdjustment), s)) { 1835 return; 1836 } 1837 } 1838 1839 } else { 1840 // A normal invokevirtual. Create call instruction. 1841 boolean unresolved = ref.needsDynamicLink(bcodes.getMethod()); 1842 RVMMethod target = ref.peekResolvedMethod(); 1843 MethodOperand methOp = MethodOperand.VIRTUAL(ref, target); 1844 1845 s = _callHelper(ref, methOp); 1846 if (s == null) 1847 break; 1848 1849 // Handle possibility of dynamic linking. 1850 // Must be done before null_check! 1851 if (unresolved) { 1852 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1853 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy())); 1854 Call.setAddress(s, offsetrop); 1855 rectifyStateWithErrorHandler(); 1856 } else { 1857 if (VM.VerifyAssertions) opt_assert(target != null); 1858 Call.setAddress(s, new AddressConstantOperand(target.getOffset())); 1859 } 1860 1861 // null check receiver 1862 Operand receiver = Call.getParam(s, 0); 1863 clearCurrentGuard(); 1864 if (do_NullCheck(receiver)) { 1865 // call will always raise null pointer exception 1866 s = null; 1867 break; 1868 } 1869 Call.setGuard(s, getCurrentGuard()); 1870 1871 // Use compile time type of receiver to try reduce the number 1872 // of targets. 1873 // If we succeed, we'll update meth and s's method operand. 1874 boolean isExtant = false; 1875 boolean isPreciseType = false; 1876 TypeReference tr = null; 1877 if (receiver.isRegister()) { 1878 RegisterOperand rop = receiver.asRegister(); 1879 isExtant = rop.isExtant(); 1880 isPreciseType = rop.isPreciseType(); 1881 tr = rop.getType(); 1882 } else { 1883 isExtant = true; 1884 isPreciseType = true; 1885 tr = receiver.getType(); 1886 } 1887 RVMType type = tr.peekType(); 1888 if (type != null && type.isResolved()) { 1889 if (type.isClassType()) { 1890 RVMMethod vmeth = target; 1891 if (target == null || type != target.getDeclaringClass()) { 1892 vmeth = ClassLoaderProxy.lookupMethod(type.asClass(), ref); 1893 } 1894 if (vmeth != null) { 1895 methOp.refine(vmeth, isPreciseType || type.asClass().isFinal()); 1896 } 1897 } else { 1898 // Array: will always be calling the method defined in java.lang.Object 1899 if (VM.VerifyAssertions) opt_assert(target != null, "Huh? Target method must already be resolved if receiver is array"); 1900 methOp.refine(target, true); 1901 } 1902 } 1903 1904 // Consider inlining it. 1905 if (maybeInlineMethod(shouldInline(s, isExtant, instrIndex - bciAdjustment), s)) { 1906 return; 1907 } 1908 } 1909 1910 // noninlined CALL must be treated as potential throw of anything 1911 rectifyStateWithExceptionHandlers(); 1912 } 1913 break; 1914 1915 case JBC_invokespecial: { 1916 MethodReference ref = bcodes.getMethodReference(); 1917 RVMMethod target = ref.resolveInvokeSpecial(); 1918 1919 /* just create an osr barrier right before _callHelper 1920 * changes the states of locals and stacks. 1921 */ 1922 if (this.osrGuardedInline) { 1923 lastOsrBarrier = _createOsrBarrier(); 1924 } 1925 1926 s = _callHelper(ref, MethodOperand.SPECIAL(ref, target)); 1927 if (s == null) 1928 break; 1929 1930 // Handle possibility of dynamic linking. Must be done before null_check! 1931 // NOTE: different definition of unresolved due to semantics of invokespecial. 1932 if (target == null) { 1933 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1934 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy())); 1935 Call.setAddress(s, offsetrop); 1936 rectifyStateWithErrorHandler(); 1937 } else { 1938 Call.setAddress(s, new AddressConstantOperand(target.getOffset())); 1939 } 1940 1941 // null check receiver 1942 Operand receiver = Call.getParam(s, 0); 1943 clearCurrentGuard(); 1944 if (do_NullCheck(receiver)) { 1945 // call will always raise null pointer exception 1946 s = null; 1947 break; 1948 } 1949 Call.setGuard(s, getCurrentGuard()); 1950 1951 // Consider inlining it. 1952 if (maybeInlineMethod(shouldInline(s, false, instrIndex - bciAdjustment), s)) { 1953 return; 1954 } 1955 1956 // noninlined CALL must be treated as potential throw of anything 1957 rectifyStateWithExceptionHandlers(); 1958 } 1959 break; 1960 1961 case JBC_invokestatic: { 1962 MethodReference ref = bcodes.getMethodReference(); 1963 1964 // See if this is a magic method (Magic, Address, Word, etc.) 1965 // If it is, generate the inline code and we are done. 1966 if (ref.isMagic()) { 1967 boolean generated = GenerateMagic.generateMagic(this, gc, ref); 1968 if (generated) break; 1969 } 1970 1971 // A non-magical invokestatic. Create call instruction. 1972 boolean unresolved = ref.needsDynamicLink(bcodes.getMethod()); 1973 RVMMethod target = ref.peekResolvedMethod(); 1974 1975 /* just create an osr barrier right before _callHelper 1976 * changes the states of locals and stacks. 1977 */ 1978 if (this.osrGuardedInline) { 1979 lastOsrBarrier = _createOsrBarrier(); 1980 } 1981 1982 s = _callHelper(ref, MethodOperand.STATIC(ref, target)); 1983 if (s == null) 1984 break; 1985 1986 if (Call.conforms(s)) { 1987 MethodOperand methOp = Call.getMethod(s); 1988 if (methOp.getTarget() == target) { 1989 // Handle possibility of dynamic linking. 1990 if (unresolved) { 1991 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 1992 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy())); 1993 Call.setAddress(s, offsetrop); 1994 rectifyStateWithErrorHandler(); 1995 } else { 1996 Call.setAddress(s, new AddressConstantOperand(target.getOffset())); 1997 } 1998 1999 // Consider inlining it. 2000 if (maybeInlineMethod(shouldInline(s, false, instrIndex - bciAdjustment), s)) { 2001 return; 2002 } 2003 } 2004 } 2005 // noninlined CALL must be treated as potential throw of anything 2006 rectifyStateWithExceptionHandlers(); 2007 } 2008 break; 2009 2010 case JBC_invokeinterface: { 2011 MethodReference ref = bcodes.getMethodReference(); 2012 bcodes.alignInvokeInterface(); 2013 RVMMethod resolvedMethod = null; 2014 resolvedMethod = ref.peekInterfaceMethod(); 2015 2016 /* just create an osr barrier right before _callHelper 2017 * changes the states of locals and stacks. 2018 */ 2019 if (this.osrGuardedInline) { 2020 lastOsrBarrier = _createOsrBarrier(); 2021 } 2022 2023 s = _callHelper(ref, MethodOperand.INTERFACE(ref, resolvedMethod)); 2024 if (s == null) 2025 break; 2026 2027 Operand receiver = Call.getParam(s, 0); 2028 RVMClass receiverType = (RVMClass) receiver.getType().peekType(); 2029 boolean requiresImplementsTest = VM.BuildForIMTInterfaceInvocation; 2030 2031 // Invokeinterface requires a dynamic type check 2032 // to ensure that the receiver object actually 2033 // implements the interface. This is necessary 2034 // because the verifier does not detect incompatible class changes. 2035 // Depending on the implementation of interface dispatching 2036 // we are using, we may have to make this test explicit 2037 // in the calling sequence if we can't prove at compile time 2038 // that it is not needed. 2039 if (requiresImplementsTest && resolvedMethod == null) { 2040 // Sigh. Can't even resolve the reference to figure out what interface 2041 // method we are trying to call. Therefore we must make generate a call 2042 // to an out-of-line typechecking routine to handle it at runtime. 2043 RVMMethod target = Entrypoints.unresolvedInvokeinterfaceImplementsTestMethod; 2044 Instruction callCheck = 2045 Call.create2(CALL, 2046 null, 2047 new AddressConstantOperand(target.getOffset()), 2048 MethodOperand.STATIC(target), 2049 new IntConstantOperand(ref.getId()), 2050 receiver.copy()); 2051 if (gc.getOptions().H2L_NO_CALLEE_EXCEPTIONS) { 2052 callCheck.markAsNonPEI(); 2053 } 2054 2055 appendInstruction(callCheck); 2056 callCheck.bcIndex = RUNTIME_SERVICES_BCI; 2057 2058 requiresImplementsTest = false; // the above call subsumes the test 2059 rectifyStateWithErrorHandler(); // Can raise incompatible class change error. 2060 } 2061 2062 // null check on this parameter of call. Must be done after dynamic linking! 2063 clearCurrentGuard(); 2064 if (do_NullCheck(receiver)) { 2065 // call will always raise null pointer exception 2066 s = null; 2067 break; 2068 } 2069 Call.setGuard(s, getCurrentGuard()); 2070 2071 if (requiresImplementsTest) { 2072 // We know what interface method the program wants to invoke. 2073 // Attempt to avoid inserting the type check by seeing if the 2074 // known static type of the receiver implements the desired interface. 2075 RVMType interfaceType = resolvedMethod.getDeclaringClass(); 2076 if (receiverType != null && receiverType.isResolved() && !receiverType.isInterface()) { 2077 byte doesImplement = 2078 ClassLoaderProxy.includesType(interfaceType.getTypeRef(), receiverType.getTypeRef()); 2079 requiresImplementsTest = doesImplement != YES; 2080 } 2081 } 2082 2083 // Attempt to resolve the interface call to a particular virtual method. 2084 // This is independent of whether or not the static type of the receiver is 2085 // known to implement the interface and it is not that case that being able 2086 // to prove one implies the other. 2087 RVMMethod vmeth = null; 2088 if (receiverType != null && receiverType.isInitialized() && !receiverType.isInterface()) { 2089 vmeth = ClassLoaderProxy.lookupMethod(receiverType, ref); 2090 } 2091 if (vmeth != null) { 2092 MethodReference vmethRef = vmeth.getMemberRef().asMethodReference(); 2093 // We're going to virtualize the call. Must inject the 2094 // DTC to ensure the receiver implements the interface if 2095 // requiresImplementsTest is still true. 2096 // Note that at this point requiresImplementsTest => resolvedMethod != null 2097 if (requiresImplementsTest) { 2098 RegisterOperand checkedReceiver = gc.getTemps().makeTemp(receiver); 2099 appendInstruction(TypeCheck.create(MUST_IMPLEMENT_INTERFACE, 2100 checkedReceiver, 2101 receiver.copy(), 2102 makeTypeOperand(resolvedMethod.getDeclaringClass()), 2103 getCurrentGuard())); 2104 checkedReceiver.refine(resolvedMethod.getDeclaringClass().getTypeRef()); 2105 Call.setParam(s, 0, checkedReceiver.copyRO()); 2106 receiver = checkedReceiver; 2107 rectifyStateWithErrorHandler(); // Can raise incompatible class change error. 2108 } 2109 MethodOperand mop = MethodOperand.VIRTUAL(vmethRef, vmeth); 2110 if (receiver.isConstant() || receiver.asRegister().isPreciseType()) { 2111 mop.refine(vmeth, true); 2112 } 2113 Call.setMethod(s, mop); 2114 boolean unresolved = vmethRef.needsDynamicLink(bcodes.getMethod()); 2115 if (unresolved) { 2116 RegisterOperand offsetrop = gc.getTemps().makeTempOffset(); 2117 appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy())); 2118 Call.setAddress(s, offsetrop); 2119 rectifyStateWithErrorHandler(); 2120 } else { 2121 Call.setAddress(s, new AddressConstantOperand(vmeth.getOffset())); 2122 } 2123 2124 // Attempt to inline virtualized call. 2125 if (maybeInlineMethod(shouldInline(s, 2126 receiver.isConstant() || receiver.asRegister().isExtant(), 2127 instrIndex - bciAdjustment), s)) { 2128 return; 2129 } 2130 } else { 2131 // We can't virtualize the call; 2132 // try to inline a predicted target for the interface invocation 2133 // inline code will include DTC to ensure receiver implements the interface. 2134 if (resolvedMethod != null && 2135 maybeInlineMethod(shouldInline(s, false, instrIndex - bciAdjustment), s)) { 2136 return; 2137 } else { 2138 if (requiresImplementsTest) { 2139 RegisterOperand checkedReceiver = gc.getTemps().makeTemp(receiver); 2140 appendInstruction(TypeCheck.create(MUST_IMPLEMENT_INTERFACE, 2141 checkedReceiver, 2142 receiver.copy(), 2143 makeTypeOperand(resolvedMethod.getDeclaringClass()), 2144 getCurrentGuard())); 2145 checkedReceiver.refine(resolvedMethod.getDeclaringClass().getTypeRef()); 2146 Call.setParam(s, 0, checkedReceiver.copyRO()); 2147 // don't have to rectify with error handlers; rectify call below subsumes. 2148 } 2149 } 2150 } 2151 2152 // CALL must be treated as potential throw of anything 2153 rectifyStateWithExceptionHandlers(); 2154 } 2155 break; 2156 2157 case JBC_invokedynamic: 2158 OptimizingCompilerException.UNREACHABLE(); 2159 break; 2160 2161 case JBC_new: { 2162 TypeReference klass = bcodes.getTypeReference(); 2163 RegisterOperand t = gc.getTemps().makeTemp(klass); 2164 t.setPreciseType(); 2165 markGuardlessNonNull(t); 2166 Operator operator; 2167 TypeOperand klassOp; 2168 RVMClass klassType = (RVMClass) klass.peekType(); 2169 if (klassType != null && (klassType.isInitialized() || klassType.isInBootImage())) { 2170 klassOp = makeTypeOperand(klassType); 2171 operator = NEW; 2172 t.setExtant(); 2173 } else { 2174 operator = NEW_UNRESOLVED; 2175 klassOp = makeTypeOperand(klass); 2176 } 2177 s = New.create(operator, t, klassOp); 2178 push(t.copyD2U()); 2179 rectifyStateWithErrorHandler(); 2180 } 2181 break; 2182 2183 case JBC_newarray: { 2184 RVMType array = bcodes.getPrimitiveArrayType(); 2185 TypeOperand arrayOp = makeTypeOperand(array); 2186 RegisterOperand t = gc.getTemps().makeTemp(array.getTypeRef()); 2187 t.setPreciseType(); 2188 t.setExtant(); 2189 markGuardlessNonNull(t); 2190 s = NewArray.create(NEWARRAY, t, arrayOp, popInt()); 2191 push(t.copyD2U()); 2192 rectifyStateWithExceptionHandler(TypeReference.JavaLangNegativeArraySizeException); 2193 } 2194 break; 2195 2196 case JBC_anewarray: { 2197 TypeReference elementTypeRef = bcodes.getTypeReference(); 2198 s = generateAnewarray(null, elementTypeRef); 2199 } 2200 break; 2201 2202 case JBC_arraylength: { 2203 Operand op1 = pop(); 2204 clearCurrentGuard(); 2205 if (do_NullCheck(op1)) { 2206 break; 2207 } 2208 if (VM.VerifyAssertions) { 2209 opt_assert(getArrayTypeOf(op1).isArrayType()); 2210 } 2211 RegisterOperand t = gc.getTemps().makeTempInt(); 2212 s = GuardedUnary.create(ARRAYLENGTH, t, op1, getCurrentGuard()); 2213 push(t.copyD2U()); 2214 } 2215 break; 2216 2217 case JBC_athrow: { 2218 Operand op0 = pop(); 2219 clearCurrentGuard(); 2220 if (do_NullCheck(op0)) { 2221 break; 2222 } 2223 TypeReference type = getRefTypeOf(op0); 2224 if (VM.VerifyAssertions) assertIsAssignable(TypeReference.JavaLangThrowable, type); 2225 if (!gc.getMethod().isInterruptible()) { 2226 // prevent code motion in or out of uninterruptible code sequence 2227 appendInstruction(Empty.create(UNINT_END)); 2228 } 2229 endOfBasicBlock = true; 2230 BasicBlock definiteTarget = rectifyStateWithExceptionHandler(type, true); 2231 if (definiteTarget != null) { 2232 appendInstruction(CacheOp.create(SET_CAUGHT_EXCEPTION, op0)); 2233 s = Goto.create(GOTO, definiteTarget.makeJumpTarget()); 2234 definiteTarget.setExceptionHandlerWithNormalIn(); 2235 } else { 2236 s = Athrow.create(ATHROW, op0); 2237 } 2238 } 2239 break; 2240 2241 case JBC_checkcast: { 2242 TypeReference typeRef = bcodes.getTypeReference(); 2243 boolean classLoading = couldCauseClassLoading(typeRef); 2244 Operand op2 = pop(); 2245 if (typeRef.isWordLikeType()) { 2246 op2 = op2.copy(); 2247 if (op2 instanceof RegisterOperand) { 2248 ((RegisterOperand) op2).setType(typeRef); 2249 } 2250 push(op2); 2251 if (DBG_CF) db("skipped gen of checkcast to word type " + typeRef); 2252 break; 2253 } 2254 if (VM.VerifyAssertions) opt_assert(op2.isRef()); 2255 if (CF_CHECKCAST && !classLoading) { 2256 if (op2.isDefinitelyNull()) { 2257 push(op2); 2258 if (DBG_CF) db("skipped gen of null checkcast"); 2259 break; 2260 } 2261 TypeReference type = getRefTypeOf(op2); // non-null, null case above 2262 byte typeTestResult = ClassLoaderProxy.includesType(typeRef, type); 2263 if (typeTestResult == YES) { 2264 push(op2); 2265 if (DBG_CF) { 2266 db("skipped gen of checkcast of " + op2 + " from " + typeRef + " to " + type); 2267 } 2268 break; 2269 } 2270 if (typeTestResult == NO) { 2271 if (isNonNull(op2)) { 2272 // Definite class cast exception 2273 endOfBasicBlock = true; 2274 appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.CheckCast())); 2275 rectifyStateWithExceptionHandler(TypeReference.JavaLangClassCastException); 2276 if (DBG_CF) db("Converted checkcast into unconditional trap"); 2277 break; 2278 } else { 2279 // At runtime either it is null and the checkcast succeeds or it is non-null 2280 // and a class cast exception is raised 2281 RegisterOperand refinedOp2 = gc.getTemps().makeTemp(op2); 2282 s = TypeCheck.create(CHECKCAST, refinedOp2, op2.copy(), makeTypeOperand(typeRef.peekType())); 2283 refinedOp2.refine(TypeReference.NULL_TYPE); 2284 push(refinedOp2.copyRO()); 2285 rectifyStateWithExceptionHandler(TypeReference.JavaLangClassCastException); 2286 if (DBG_CF) db("Narrowed type downstream of checkcast to NULL"); 2287 break; 2288 } 2289 } 2290 } 2291 2292 RegisterOperand refinedOp2 = gc.getTemps().makeTemp(op2); 2293 if (classLoading) { 2294 s = TypeCheck.create(CHECKCAST_UNRESOLVED, refinedOp2, op2.copy(), makeTypeOperand(typeRef)); 2295 } else { 2296 TypeOperand typeOp = makeTypeOperand(typeRef.peekType()); 2297 if (isNonNull(op2)) { 2298 s = TypeCheck.create(CHECKCAST_NOTNULL, refinedOp2, op2.copy(), typeOp, copyGuardFromOperand(op2)); 2299 } else { 2300 s = TypeCheck.create(CHECKCAST, refinedOp2, op2.copy(), typeOp); 2301 } 2302 } 2303 refinedOp2.refine(typeRef); 2304 push(refinedOp2.copyRO()); 2305 rectifyStateWithExceptionHandler(TypeReference.JavaLangClassCastException); 2306 if (classLoading) rectifyStateWithErrorHandler(); 2307 } 2308 break; 2309 2310 case JBC_instanceof: { 2311 TypeReference typeRef = bcodes.getTypeReference(); 2312 boolean classLoading = couldCauseClassLoading(typeRef); 2313 Operand op2 = pop(); 2314 if (VM.VerifyAssertions) opt_assert(op2.isRef()); 2315 if (CF_INSTANCEOF && !classLoading) { 2316 if (op2.isDefinitelyNull()) { 2317 push(new IntConstantOperand(0)); 2318 if (DBG_CF) db("skipped gen of null instanceof"); 2319 break; 2320 } 2321 TypeReference type = getRefTypeOf(op2); // non-null 2322 int answer = ClassLoaderProxy.includesType(typeRef, type); 2323 if (answer == YES && isNonNull(op2)) { 2324 push(new IntConstantOperand(1)); 2325 if (DBG_CF) { 2326 db(op2 + " instanceof " + typeRef + " is always true "); 2327 } 2328 break; 2329 } else if (answer == NO) { 2330 if (DBG_CF) { 2331 db(op2 + " instanceof " + typeRef + " is always false "); 2332 } 2333 push(new IntConstantOperand(0)); 2334 break; 2335 } 2336 } 2337 2338 RegisterOperand t = gc.getTemps().makeTempInt(); 2339 if (classLoading) { 2340 s = InstanceOf.create(INSTANCEOF_UNRESOLVED, t, makeTypeOperand(typeRef), op2); 2341 } else { 2342 TypeOperand typeOp = makeTypeOperand(typeRef.peekType()); 2343 if (isNonNull(op2)) { 2344 s = InstanceOf.create(INSTANCEOF_NOTNULL, t, typeOp, op2, copyGuardFromOperand(op2)); 2345 } else { 2346 s = InstanceOf.create(INSTANCEOF, t, typeOp, op2); 2347 } 2348 } 2349 2350 push(t.copyD2U()); 2351 if (classLoading) rectifyStateWithErrorHandler(); 2352 } 2353 break; 2354 2355 case JBC_monitorenter: { 2356 Operand op0 = pop(); 2357 clearCurrentGuard(); 2358 if (do_NullCheck(op0)) { 2359 break; 2360 } 2361 if (VM.VerifyAssertions) opt_assert(op0.isRef()); 2362 s = MonitorOp.create(MONITORENTER, op0, getCurrentGuard()); 2363 } 2364 break; 2365 2366 case JBC_monitorexit: { 2367 Operand op0 = pop(); 2368 clearCurrentGuard(); 2369 if (do_NullCheck(op0)) { 2370 break; 2371 } 2372 s = MonitorOp.create(MONITOREXIT, op0, getCurrentGuard()); 2373 rectifyStateWithExceptionHandler(TypeReference.JavaLangIllegalMonitorStateException); 2374 } 2375 break; 2376 2377 case JBC_wide: { 2378 int widecode = bcodes.getWideOpcode(); 2379 int index = bcodes.getWideLocalNumber(); 2380 switch (widecode) { 2381 case JBC_iload: 2382 s = do_iload(index); 2383 break; 2384 2385 case JBC_lload: 2386 s = do_lload(index); 2387 break; 2388 2389 case JBC_fload: 2390 s = do_fload(index); 2391 break; 2392 2393 case JBC_dload: 2394 s = do_dload(index); 2395 break; 2396 2397 case JBC_aload: 2398 s = do_aload(index); 2399 break; 2400 2401 case JBC_istore: 2402 s = do_store(index, popInt()); 2403 break; 2404 2405 case JBC_lstore: 2406 s = do_store(index, popLong()); 2407 break; 2408 2409 case JBC_fstore: 2410 s = do_store(index, popFloat()); 2411 break; 2412 2413 case JBC_dstore: 2414 s = do_store(index, popDouble()); 2415 break; 2416 2417 case JBC_astore: 2418 s = do_astore(index); 2419 break; 2420 2421 case JBC_iinc: 2422 s = do_iinc(index, bcodes.getWideIncrement()); 2423 break; 2424 2425 case JBC_ret: 2426 s = _retHelper(index); 2427 break; 2428 2429 default: 2430 OptimizingCompilerException.UNREACHABLE(); 2431 break; 2432 } 2433 } 2434 break; 2435 2436 case JBC_multianewarray: { 2437 TypeReference arrayType = bcodes.getTypeReference(); 2438 int dimensions = bcodes.getArrayDimension(); 2439 2440 if (dimensions == 1) { 2441 s = generateAnewarray(arrayType, null); 2442 } else { 2443 TypeOperand typeOp = makeTypeOperand(arrayType); 2444 RegisterOperand result = gc.getTemps().makeTemp(arrayType); 2445 markGuardlessNonNull(result); 2446 result.setPreciseType(); 2447 TypeReference innermostElementTypeRef = arrayType.getInnermostElementType(); 2448 RVMType innermostElementType = innermostElementTypeRef.peekType(); 2449 if (innermostElementType != null && (innermostElementType.isInitialized() || innermostElementType.isInBootImage())) { 2450 result.setExtant(); 2451 } 2452 s = Multianewarray.create(NEWOBJMULTIARRAY, result, typeOp, dimensions); 2453 for (int i = 0; i < dimensions; i++) { 2454 Multianewarray.setDimension(s, dimensions - i - 1, popInt()); 2455 } 2456 push(result.copyD2U()); 2457 rectifyStateWithErrorHandler(); 2458 rectifyStateWithExceptionHandler(TypeReference.JavaLangNegativeArraySizeException); 2459 } 2460 } 2461 break; 2462 2463 case JBC_ifnull: 2464 s = _refIfNullHelper(ConditionOperand.EQUAL()); 2465 break; 2466 2467 case JBC_ifnonnull: 2468 s = _refIfNullHelper(ConditionOperand.NOT_EQUAL()); 2469 break; 2470 2471 case JBC_goto_w: { 2472 int offset = bcodes.getWideBranchOffset(); 2473 if (offset != 5) { 2474 // skip generating frivolous goto's 2475 s = _gotoHelper(offset); 2476 } 2477 } 2478 break; 2479 2480 case JBC_jsr_w: 2481 s = _jsrHelper(bcodes.getWideBranchOffset()); 2482 break; 2483 2484 case JBC_impdep1: { 2485 if (VM.BuildForAdaptiveSystem) { 2486 int pseudo_opcode = bcodes.nextPseudoInstruction(); 2487 switch (pseudo_opcode) { 2488 case PSEUDO_LoadIntConst: { 2489 int value = bcodes.readIntConst(); 2490 2491 if (VM.TraceOnStackReplacement) { 2492 VM.sysWriteln("PSEUDO_LoadIntConst " + value); 2493 } 2494 2495 push(new IntConstantOperand(value)); 2496 2497 // used for PSEUDO_InvokeStatic to recover the type info 2498 param1 = param2; 2499 param2 = value; 2500 2501 break; 2502 } 2503 case PSEUDO_LoadLongConst: { 2504 long value = bcodes.readLongConst(); 2505 2506 if (VM.TraceOnStackReplacement) { 2507 VM.sysWriteln("PSEUDO_LoadLongConst " + value); 2508 } 2509 2510 pushDual(new LongConstantOperand(value)); 2511 break; 2512 } 2513 case PSEUDO_LoadWordConst: { 2514 Address a = 2515 (VM.BuildFor32Addr) ? Address.fromIntSignExtend(bcodes.readIntConst()) : Address.fromLong(bcodes.readLongConst()); 2516 2517 push(new AddressConstantOperand(a)); 2518 2519 if (VM.TraceOnStackReplacement) { 2520 VM.sysWrite("PSEUDO_LoadWordConst 0x"); 2521 } 2522 VM.sysWrite(a); 2523 VM.sysWriteln(); 2524 2525 break; 2526 } 2527 case PSEUDO_LoadFloatConst: { 2528 int ibits = bcodes.readIntConst(); 2529 float value = Float.intBitsToFloat(ibits); 2530 2531 if (VM.TraceOnStackReplacement) { 2532 VM.sysWriteln("PSEUDO_LoadFloatConst " + value); 2533 } 2534 2535 push(new FloatConstantOperand(value, Offset.zero())); 2536 break; 2537 } 2538 2539 case PSEUDO_LoadDoubleConst: { 2540 long lbits = bcodes.readLongConst(); 2541 2542 double value = Magic.longBitsAsDouble(lbits); 2543 2544 if (VM.TraceOnStackReplacement) { 2545 VM.sysWriteln("PSEUDO_LoadDoubleConst " + lbits); 2546 } 2547 2548 pushDual(new DoubleConstantOperand(value, Offset.zero())); 2549 break; 2550 } 2551 2552 case PSEUDO_LoadRetAddrConst: { 2553 int value = bcodes.readIntConst(); 2554 2555 if (VM.TraceOnStackReplacement) { 2556 VM.sysWriteln("PSEUDO_LoadRetAddrConst " + value); 2557 } 2558 2559 push(new ReturnAddressOperand(value)); 2560 break; 2561 } 2562 case PSEUDO_InvokeStatic: { 2563 /* pseudo invoke static for getRefAt and cleanRefAt, both must be resolved already */ 2564 int targetidx = bcodes.readIntConst(); 2565 RVMMethod meth = InvokeStatic.targetMethod(targetidx); 2566 2567 if (VM.TraceOnStackReplacement) { 2568 VM.sysWriteln("PSEUDO_Invoke " + meth + "\n"); 2569 } 2570 2571 s = _callHelper(meth.getMemberRef().asMethodReference(), MethodOperand.STATIC(meth)); 2572 if (s == null) 2573 break; 2574 Call.setAddress(s, new AddressConstantOperand(meth.getOffset())); 2575 2576 /* try to set the type of return register */ 2577 if (targetidx == GETREFAT) { 2578 Object realObj = ObjectHolder.getRefAt(param1, param2); 2579 2580 if (VM.VerifyAssertions) opt_assert(realObj != null); 2581 2582 TypeReference klass = Magic.getObjectType(realObj).getTypeRef(); 2583 2584 RegisterOperand op0 = gc.getTemps().makeTemp(klass); 2585 Call.setResult(s, op0); 2586 pop(); // pop the old one and push the new return type. 2587 push(op0.copyD2U(), klass); 2588 } 2589 2590 // CALL must be treated as potential throw of anything 2591 rectifyStateWithExceptionHandlers(); 2592 break; 2593 } 2594 case PSEUDO_InvokeCompiledMethod: { 2595 int cmid = bcodes.readIntConst(); 2596 int origBCIdx = bcodes.readIntConst(); // skip it 2597 CompiledMethod cm = CompiledMethods.getCompiledMethod(cmid); 2598 RVMMethod meth = cm.getMethod(); 2599 2600 if (VM.TraceOnStackReplacement) { 2601 VM.sysWriteln("PSEUDO_InvokeCompiledMethod " + meth + "\n"); 2602 } 2603 2604 /* the bcIndex should be adjusted to the original */ 2605 s = _callHelper(meth.getMemberRef().asMethodReference(), 2606 MethodOperand.COMPILED(meth, cm.getOsrJTOCoffset())); 2607 if (s == null) 2608 break; 2609 2610 // adjust the bcindex of s to the original bytecode's index 2611 // it should be able to give the correct exception handling 2612 s.bcIndex = origBCIdx + bciAdjustment; 2613 2614 rectifyStateWithExceptionHandlers(); 2615 break; 2616 } 2617 case PSEUDO_ParamInitEnd: { 2618 // indicates the place to insert method prologue and stack 2619 // overflow checks. 2620 // opt compiler should consider this too 2621 2622 break; 2623 } 2624 default: 2625 if (VM.TraceOnStackReplacement) { 2626 VM.sysWriteln("OSR Error, no such pseudo opcode : " + pseudo_opcode); 2627 } 2628 2629 OptimizingCompilerException.UNREACHABLE(); 2630 break; 2631 } 2632 break; 2633 } else { 2634 OptimizingCompilerException.UNREACHABLE(); 2635 } 2636 } 2637 default: 2638 OptimizingCompilerException.UNREACHABLE(); 2639 break; 2640 } 2641 2642 if (s != null && !currentBBLE.isSelfRegen()) { 2643 appendInstruction(s); 2644 } 2645 2646 // check runoff 2647 if (VM.VerifyAssertions) opt_assert(bcodes.index() <= runoff); 2648 if (!endOfBasicBlock && bcodes.index() == runoff) { 2649 if (DBG_BB || DBG_SELECTED) { 2650 db("runoff occurred! current basic block: " + currentBBLE + ", runoff = " + runoff); 2651 } 2652 endOfBasicBlock = fallThrough = true; 2653 } 2654 if (endOfBasicBlock) { 2655 if (currentBBLE.isSelfRegen()) { 2656 // This block ended in a goto that jumped into the middle of it. 2657 // Through away all out edges from this block, they're out of date 2658 // because we're going to have to regenerate this block. 2659 currentBBLE.block.deleteOut(); 2660 if (DBG_CFG || DBG_SELECTED) { 2661 db("Deleted all out edges of " + currentBBLE.block); 2662 } 2663 return; 2664 } 2665 if (fallThrough) { 2666 if (VM.VerifyAssertions) opt_assert(bcodes.index() < bcodes.length()); 2667 // Get/Create fallthrough BBLE and record it as 2668 // currentBBLE's fallThrough. 2669 currentBBLE.fallThrough = getOrCreateBlock(bcodes.index()); 2670 currentBBLE.block.insertOut(currentBBLE.fallThrough.block); 2671 } 2672 return; 2673 } 2674 } 2675 } 2676 2677 Instruction _unaryHelper(Operator operator, Operand val, TypeReference type) { 2678 RegisterOperand t = gc.getTemps().makeTemp(type); 2679 Instruction s = Unary.create(operator, t, val); 2680 Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s); 2681 if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) { 2682 gc.getTemps().release(t); 2683 push(Move.getClearVal(s)); 2684 return null; 2685 } else { 2686 push(t.copyD2U()); 2687 return s; 2688 } 2689 } 2690 2691 Instruction _unaryDualHelper(Operator operator, Operand val, TypeReference type) { 2692 RegisterOperand t = gc.getTemps().makeTemp(type); 2693 Instruction s = Unary.create(operator, t, val); 2694 Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s); 2695 if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) { 2696 gc.getTemps().release(t); 2697 pushDual(Move.getClearVal(s)); 2698 return null; 2699 } else { 2700 pushDual(t.copyD2U()); 2701 return s; 2702 } 2703 } 2704 2705 public Instruction _binaryHelper(Operator operator, Operand op1, Operand op2, 2706 TypeReference type) { 2707 RegisterOperand t = gc.getTemps().makeTemp(type); 2708 Instruction s = Binary.create(operator, t, op1, op2); 2709 Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s); 2710 if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) { 2711 gc.getTemps().release(t); 2712 push(Move.getClearVal(s)); 2713 return null; 2714 } else { 2715 push(t.copyD2U()); 2716 return s; 2717 } 2718 } 2719 2720 private Instruction _guardedBinaryHelper(Operator operator, Operand op1, Operand op2, 2721 Operand guard, TypeReference type) { 2722 RegisterOperand t = gc.getTemps().makeTemp(type); 2723 Instruction s = GuardedBinary.create(operator, t, op1, op2, guard); 2724 Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s); 2725 if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) { 2726 gc.getTemps().release(t); 2727 push(Move.getClearVal(s)); 2728 return null; 2729 } else { 2730 push(t.copyD2U()); 2731 return s; 2732 } 2733 } 2734 2735 private Instruction _binaryDualHelper(Operator operator, Operand op1, Operand op2, 2736 TypeReference type) { 2737 RegisterOperand t = gc.getTemps().makeTemp(type); 2738 Instruction s = Binary.create(operator, t, op1, op2); 2739 Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s); 2740 if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) { 2741 gc.getTemps().release(t); 2742 pushDual(Move.getClearVal(s)); 2743 return null; 2744 } else { 2745 pushDual(t.copyD2U()); 2746 return s; 2747 } 2748 } 2749 2750 private Instruction _guardedBinaryDualHelper(Operator operator, Operand op1, Operand op2, 2751 Operand guard, TypeReference type) { 2752 RegisterOperand t = gc.getTemps().makeTemp(type); 2753 Instruction s = GuardedBinary.create(operator, t, op1, op2, guard); 2754 Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s); 2755 if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) { 2756 gc.getTemps().release(t); 2757 pushDual(Move.getClearVal(s)); 2758 return null; 2759 } else { 2760 pushDual(t.copyD2U()); 2761 return s; 2762 } 2763 } 2764 2765 Instruction _moveHelper(Operator operator, Operand val, TypeReference type) { 2766 RegisterOperand t = gc.getTemps().makeTemp(type); 2767 push(t.copyD2U()); 2768 Instruction s = Move.create(operator, t, val); 2769 s.position = gc.getInlineSequence(); 2770 s.bcIndex = instrIndex; 2771 return s; 2772 } 2773 2774 private Instruction _moveDualHelper(Operator operator, Operand val, TypeReference type) { 2775 RegisterOperand t = gc.getTemps().makeTemp(type); 2776 pushDual(t.copyD2U()); 2777 Instruction s = Move.create(operator, t, val); 2778 s.position = gc.getInlineSequence(); 2779 s.bcIndex = instrIndex; 2780 return s; 2781 } 2782 2783 public Instruction _aloadHelper(Operator operator, Operand ref, Operand index, 2784 TypeReference type) { 2785 RegisterOperand t = gc.getTemps().makeTemp(type); 2786 t.setDeclaredType(); 2787 LocationOperand loc = new LocationOperand(type); 2788 Instruction s = ALoad.create(operator, t, ref, index, loc, getCurrentGuard()); 2789 t = t.copyD2U(); 2790 if (type.isLongType() || type.isDoubleType()) { 2791 pushDual(t); 2792 } else { 2793 push(t); 2794 } 2795 return s; 2796 } 2797 2798 /** 2799 * Pop method parameters off the expression stack. 2800 * If a non-void return, then create a result operand and push it 2801 * on the stack. 2802 * Create the call instruction and initialize all its operands. 2803 * 2804 * @param meth the method to call 2805 * @param methOp data about the method 2806 * 2807 * @return the newly created call instruction 2808 */ 2809 private Instruction _callHelper(MethodReference meth, MethodOperand methOp) { 2810 int numHiddenParams = methOp.isStatic() ? 0 : 1; 2811 TypeReference[] params = meth.getParameterTypes(); 2812 Instruction s = Call.create(CALL, null, null, null, null, params.length + numHiddenParams); 2813 if (gc.getOptions().H2L_NO_CALLEE_EXCEPTIONS) { 2814 s.markAsNonPEI(); 2815 } 2816 for (int i = params.length - 1; i >= 0; i--) { 2817 try { 2818 Call.setParam(s, i + numHiddenParams, pop(params[i])); 2819 } catch (OptimizingCompilerException.IllegalUpcast e) { 2820 throw new Error("Illegal upcast creating call to " + meth + " from " + gc.getMethod() + " argument " + i, e); 2821 } 2822 } 2823 if (numHiddenParams != 0) { 2824 Operand ref = pop(); 2825 Call.setParam(s, 0, ref); 2826 } 2827 Call.setMethod(s, methOp); 2828 2829 // need to set it up early because the inlining oracle use it 2830 s.position = gc.getInlineSequence(); 2831 // no longer used by the inline oracle as it is incorrectly adjusted by OSR, 2832 // can't adjust it here as it will effect the exception handler maps 2833 s.bcIndex = instrIndex; 2834 2835 TypeReference rtype = meth.getReturnType(); 2836 if (rtype.isVoidType()) { 2837 return s; 2838 } else { 2839 RegisterOperand t = gc.getTemps().makeTemp(rtype); 2840 Call.setResult(s, t); 2841 Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s); 2842 if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) { 2843 gc.getTemps().release(t); 2844 push(Move.getClearVal(s), rtype); 2845 return null; 2846 } else { 2847 push(t.copyD2U(), rtype); 2848 return s; 2849 } 2850 } 2851 } 2852 2853 private void _returnHelper(Operator operator, Operand val) { 2854 if (gc.getResultReg() != null) { 2855 TypeReference returnType = val.getType(); 2856 RegisterOperand ret = new RegisterOperand(gc.getResultReg(), returnType); 2857 boolean returningRegister = false; 2858 if (val.isRegister()) { 2859 returningRegister = true; 2860 ret.setInheritableFlags(val.asRegister()); 2861 setGuardForRegOp(ret, copyGuardFromOperand(val)); 2862 } 2863 appendInstruction(Move.create(operator, ret, val)); 2864 // pass analysis facts about val back to our caller 2865 if (gc.getResult() == null) { 2866 if (returningRegister) { 2867 gc.setResult(ret.copyD2U()); 2868 } else { 2869 gc.setResult(val.copy()); 2870 } 2871 } else { 2872 Operand meet = Operand.meet(gc.getResult(), val, gc.getResultReg()); 2873 // Return value can't be forced to bottom...violation of Java spec. 2874 if (VM.VerifyAssertions) opt_assert(meet != null); 2875 gc.setResult(meet); 2876 } 2877 } 2878 if (gc.getMethod().isObjectInitializer() && gc.getMethod().getDeclaringClass().declaresFinalInstanceField()) { 2879 /* JMM Compliance. Must insert StoreStore barrier before returning from constructor of class with final instance fields */ 2880 appendInstruction(Empty.create(WRITE_FLOOR)); 2881 } 2882 appendInstruction(gc.getEpilogue().makeGOTO()); 2883 currentBBLE.block.insertOut(gc.getEpilogue()); 2884 if (DBG_CFG || DBG_SELECTED) { 2885 db("Added CFG edge from " + currentBBLE.block + " to " + gc.getEpilogue()); 2886 } 2887 endOfBasicBlock = true; 2888 } 2889 2890 //// APPEND INSTRUCTION. 2891 /** 2892 * Append an instruction to the current basic block. 2893 * 2894 * @param s instruction to append 2895 */ 2896 public void appendInstruction(Instruction s) { 2897 currentBBLE.block.appendInstruction(s); 2898 s.position = gc.getInlineSequence(); 2899 s.bcIndex = instrIndex; 2900 lastInstr = s; 2901 if (DBG_INSTR || DBG_SELECTED) db("-> " + s.bcIndex + ":\t" + s); 2902 } 2903 2904 //// MAKE A FIELD REFERENCE. 2905 /** 2906 * Make a field reference operand referring to the given field with the 2907 * given type. 2908 * 2909 * @param f desired field 2910 * @return a new location operand 2911 */ 2912 private LocationOperand makeStaticFieldRef(FieldReference f) { 2913 return new LocationOperand(f); 2914 } 2915 2916 private LocationOperand makeInstanceFieldRef(FieldReference f) { 2917 return new LocationOperand(f); 2918 } 2919 2920 //// MAKE A TYPE REFERENCE. 2921 /** 2922 * Make a type operand that refers to the given type. 2923 * 2924 * @param type desired type 2925 * @return a new type operand 2926 */ 2927 private TypeOperand makeTypeOperand(TypeReference type) { 2928 if (VM.VerifyAssertions) opt_assert(type != null); 2929 return new TypeOperand(type); 2930 } 2931 2932 /** 2933 * Make a type operand that refers to the given type. 2934 * 2935 * @param type desired type 2936 * @return a new type operand 2937 */ 2938 private TypeOperand makeTypeOperand(RVMType type) { 2939 if (VM.VerifyAssertions) opt_assert(type != null); 2940 return new TypeOperand(type); 2941 } 2942 2943 private boolean couldCauseClassLoading(TypeReference typeRef) { 2944 RVMType type = typeRef.peekType(); 2945 if (type == null) return true; 2946 if (type.isInitialized()) return false; 2947 if (type.isArrayType()) return !type.isResolved(); 2948 if (type.isClassType() && type.asClass().isInBootImage()) return false; 2949 return true; 2950 } 2951 2952 /** 2953 * Fetch the value of the next operand, a constant, from the bytecode 2954 * stream. 2955 * @param index constant pool index 2956 * @return the value of a literal constant from the bytecode stream, 2957 * encoding as a constant IR operand 2958 */ 2959 public Operand getConstantOperand(int index) { 2960 byte desc = bcodes.getConstantType(index); 2961 RVMClass declaringClass = bcodes.getDeclaringClass(); 2962 switch (desc) { 2963 case CP_INT: 2964 return ClassLoaderProxy.getIntFromConstantPool(declaringClass, index); 2965 case CP_FLOAT: 2966 return ClassLoaderProxy.getFloatFromConstantPool(declaringClass, index); 2967 case CP_STRING: 2968 return ClassLoaderProxy.getStringFromConstantPool(declaringClass, index); 2969 case CP_LONG: 2970 return ClassLoaderProxy.getLongFromConstantPool(declaringClass, index); 2971 case CP_DOUBLE: 2972 return ClassLoaderProxy.getDoubleFromConstantPool(declaringClass, index); 2973 case CP_CLASS: 2974 return ClassLoaderProxy.getClassFromConstantPool(declaringClass, index); 2975 default: 2976 if (VM.VerifyAssertions) { 2977 String msg = "invalid literal type: 0x" + Integer.toHexString(desc); 2978 opt_assert(VM.NOT_REACHED, msg); 2979 } 2980 return null; 2981 } 2982 } 2983 2984 //// LOAD LOCAL VARIABLE ONTO STACK. 2985 /** 2986 * Simulates a load from a given local variable of an int. 2987 * 2988 * @param index local variable number 2989 * @return {@code null} if no instruction is necessary, a move instruction 2990 * otherwise 2991 */ 2992 private Instruction do_iload(int index) { 2993 Operand r = getLocal(index); 2994 if (VM.VerifyAssertions) opt_assert(r.isIntLike()); 2995 if (LOCALS_ON_STACK) { 2996 push(r); 2997 return null; 2998 } else { 2999 return _moveHelper(INT_MOVE, r, TypeReference.Int); 3000 } 3001 } 3002 3003 /** 3004 * Simulates a load from a given local variable of a float. 3005 * 3006 * @param index local variable number 3007 * @return {@code null} if no instruction is necessary, a move instruction 3008 * otherwise 3009 */ 3010 private Instruction do_fload(int index) { 3011 Operand r = getLocal(index); 3012 if (VM.VerifyAssertions) opt_assert(r.isFloat()); 3013 if (LOCALS_ON_STACK) { 3014 push(r); 3015 return null; 3016 } else { 3017 return _moveHelper(FLOAT_MOVE, r, TypeReference.Float); 3018 } 3019 } 3020 3021 /** 3022 * Simulates a load from a given local variable of a reference. 3023 * 3024 * @param index local variable number 3025 * @return {@code null} if no instruction is necessary, a move instruction 3026 * otherwise 3027 */ 3028 private Instruction do_aload(int index) { 3029 Operand r = getLocal(index); 3030 if (VM.VerifyAssertions && !(r.isRef() || r.isAddress())) { 3031 String msg = r + " not ref, but a " + r.getType(); 3032 opt_assert(VM.NOT_REACHED, msg); 3033 } 3034 if (LOCALS_ON_STACK) { 3035 push(r); 3036 return null; 3037 } else { 3038 return _moveHelper(REF_MOVE, r, r.getType()); 3039 } 3040 } 3041 3042 /** 3043 * Simulates a load from a given local variable of a long. 3044 * 3045 * @param index local variable number 3046 * @return {@code null} if no instruction is necessary, a move instruction 3047 * otherwise 3048 */ 3049 private Instruction do_lload(int index) { 3050 Operand r = getLocalDual(index); 3051 if (VM.VerifyAssertions) opt_assert(r.isLong()); 3052 if (LOCALS_ON_STACK) { 3053 pushDual(r); 3054 return null; 3055 } else { 3056 return _moveDualHelper(LONG_MOVE, r, TypeReference.Long); 3057 } 3058 } 3059 3060 /** 3061 * Simulates a load from a given local variable of a double. 3062 * 3063 * @param index local variable number 3064 * @return {@code null} if no instruction is necessary, a move instruction 3065 * otherwise 3066 */ 3067 private Instruction do_dload(int index) { 3068 Operand r = getLocalDual(index); 3069 if (VM.VerifyAssertions) opt_assert(r.isDouble()); 3070 if (LOCALS_ON_STACK) { 3071 pushDual(r); 3072 return null; 3073 } else { 3074 return _moveDualHelper(DOUBLE_MOVE, r, TypeReference.Double); 3075 } 3076 } 3077 3078 //// INCREMENT A LOCAL VARIABLE. 3079 /** 3080 * Simulates the incrementing of a given int local variable. 3081 * 3082 * @param index local variable number 3083 * @param amount amount to increment by 3084 * @return the generated instruction, never {@code null} 3085 */ 3086 private Instruction do_iinc(int index, int amount) { 3087 Operand r = getLocal(index); 3088 if (VM.VerifyAssertions) opt_assert(r.isIntLike()); 3089 if (LOCALS_ON_STACK) { 3090 replaceLocalsOnStack(index, TypeReference.Int); 3091 } 3092 RegisterOperand op0 = gc.makeLocal(index, TypeReference.Int); 3093 if (r instanceof IntConstantOperand) { 3094 // do constant folding. 3095 int res = amount + ((IntConstantOperand) r).value; 3096 IntConstantOperand val = new IntConstantOperand(res); 3097 if (CP_IN_LOCALS) { 3098 setLocal(index, val); 3099 } else { 3100 setLocal(index, op0); 3101 } 3102 Instruction s = Move.create(INT_MOVE, op0, val); 3103 s.position = gc.getInlineSequence(); 3104 s.bcIndex = instrIndex; 3105 return s; 3106 } 3107 setLocal(index, op0); 3108 return Binary.create(INT_ADD, op0, r, new IntConstantOperand(amount)); 3109 } 3110 3111 //// POP FROM STACK AND STORE INTO LOCAL VARIABLE. 3112 /** 3113 * Simulates a store into a given local variable of an int/long/double/float 3114 * 3115 * @param index local variable number 3116 * @param op1 the value to store 3117 * @return {@code null} if no instruction is necessary, the generated 3118 * instruction otherwise 3119 */ 3120 private Instruction do_store(int index, Operand op1) { 3121 TypeReference type = op1.getType(); 3122 boolean Dual = (type.isLongType() || type.isDoubleType()); 3123 if (LOCALS_ON_STACK) { 3124 replaceLocalsOnStack(index, type); 3125 } 3126 if (ELIM_COPY_LOCALS) { 3127 if (op1 instanceof RegisterOperand) { 3128 RegisterOperand rop1 = (RegisterOperand) op1; 3129 Register r1 = rop1.getRegister(); 3130 if (lastInstr != null && 3131 ResultCarrier.conforms(lastInstr) && 3132 ResultCarrier.hasResult(lastInstr) && 3133 !r1.isLocal() && 3134 r1 == ResultCarrier.getResult(lastInstr).getRegister()) { 3135 if (DBG_ELIMCOPY) db("eliminated copy " + op1 + " to" + index); 3136 RegisterOperand newop0 = gc.makeLocal(index, rop1); 3137 ResultCarrier.setResult(lastInstr, newop0); 3138 if (Dual) { 3139 setLocalDual(index, newop0); 3140 } else { 3141 setLocal(index, newop0); 3142 } 3143 gc.getTemps().release(rop1); 3144 return null; 3145 } 3146 } 3147 } 3148 RegisterOperand op0 = 3149 (op1 instanceof RegisterOperand) ? gc.makeLocal(index, (RegisterOperand) op1) : gc.makeLocal(index, 3150 type); 3151 Operand set = op0; 3152 if (CP_IN_LOCALS) { 3153 set = (op1 instanceof RegisterOperand) ? op0 : op1; 3154 } 3155 if (Dual) { 3156 setLocalDual(index, set); 3157 } else { 3158 setLocal(index, set); 3159 } 3160 Instruction s = Move.create(IRTools.getMoveOp(type), op0, op1); 3161 s.position = gc.getInlineSequence(); 3162 s.bcIndex = instrIndex; 3163 return s; 3164 } 3165 3166 /** 3167 * Simulates a store into a given local variable of an object ref. 3168 * 3169 * @param index local variable number 3170 * @return {@code null} if no instruction is necessary, the generated 3171 * instruction otherwise 3172 */ 3173 private Instruction do_astore(int index) { 3174 Operand op1 = pop(); 3175 if (op1 instanceof ReturnAddressOperand) { 3176 setLocal(index, op1); 3177 return null; 3178 } 3179 boolean doConstantProp = false; 3180 if ((op1 instanceof NullConstantOperand) || (op1 instanceof AddressConstantOperand)) { 3181 doConstantProp = true; 3182 } 3183 TypeReference type = op1.getType(); 3184 if (LOCALS_ON_STACK) { 3185 replaceLocalsOnStack(index, type); 3186 } 3187 if (ELIM_COPY_LOCALS) { 3188 if (op1 instanceof RegisterOperand) { 3189 RegisterOperand rop1 = (RegisterOperand) op1; 3190 Register r1 = rop1.getRegister(); 3191 if (lastInstr != null && 3192 ResultCarrier.conforms(lastInstr) && 3193 ResultCarrier.hasResult(lastInstr) && 3194 !r1.isLocal() && 3195 r1 == ResultCarrier.getResult(lastInstr).getRegister()) { 3196 if (DBG_ELIMCOPY) { 3197 db("eliminated copy " + op1 + " to " + index); 3198 } 3199 RegisterOperand newop0 = gc.makeLocal(index, rop1); 3200 ResultCarrier.setResult(lastInstr, newop0); 3201 setLocal(index, newop0); 3202 gc.getTemps().release(rop1); 3203 return null; 3204 } 3205 } 3206 } 3207 RegisterOperand op0; 3208 if (op1 instanceof RegisterOperand) { 3209 RegisterOperand rop1 = (RegisterOperand) op1; 3210 op0 = gc.makeLocal(index, rop1); 3211 if (hasGuard(rop1)) { 3212 RegisterOperand g0 = gc.makeNullCheckGuard(op0.getRegister()); 3213 appendInstruction(Move.create(GUARD_MOVE, g0.copyRO(), copyGuardFromOperand(rop1))); 3214 setGuardForRegOp(op0, g0); 3215 } 3216 } else { 3217 op0 = gc.makeLocal(index, type); 3218 } 3219 if (CP_IN_LOCALS) { 3220 setLocal(index, doConstantProp ? op1 : op0); 3221 } else { 3222 setLocal(index, op0); 3223 } 3224 Instruction s = Move.create(REF_MOVE, op0, op1); 3225 s.position = gc.getInlineSequence(); 3226 s.bcIndex = instrIndex; 3227 return s; 3228 } 3229 3230 //// PUSH OPERAND ONTO THE STACK. 3231 /** 3232 * Push a single width operand (int, float, ref, ...) on the simulated stack. 3233 * 3234 * @param r operand to push 3235 */ 3236 public void push(Operand r) { 3237 if (VM.VerifyAssertions) opt_assert(r.instruction == null); 3238 stack.push(r); 3239 } 3240 3241 /** 3242 * Push a double width operand (long, double) on the simulated stack. 3243 * 3244 * @param r operand to push 3245 */ 3246 void pushDual(Operand r) { 3247 if (VM.VerifyAssertions) opt_assert(r.instruction == null); 3248 stack.push(DUMMY); 3249 stack.push(r); 3250 } 3251 3252 /** 3253 * Push an operand of the specified type on the simulated stack. 3254 * 3255 * @param r operand to push 3256 * @param type data type of operand 3257 */ 3258 void push(Operand r, TypeReference type) { 3259 if (VM.VerifyAssertions) opt_assert(r.instruction == null); 3260 if (type.isVoidType()) { 3261 return; 3262 } 3263 if (type.isLongType() || type.isDoubleType()) { 3264 pushDual(r); 3265 } else { 3266 push(r); 3267 } 3268 } 3269 3270 /** 3271 * Pushes a copy of the given operand onto simulated stack. 3272 * 3273 * @param op1 operand to push 3274 * @return always {@code null} 3275 */ 3276 private Instruction pushCopy(Operand op1) { 3277 if (VM.VerifyAssertions) opt_assert(op1.instruction == null); 3278 if (op1 instanceof RegisterOperand) { 3279 RegisterOperand reg = (RegisterOperand) op1; 3280 if (!reg.getRegister().isLocal()) { 3281 lastInstr = null; // to prevent eliminating this temporary. 3282 } 3283 stack.push(reg.copy()); 3284 } else { 3285 stack.push(op1.copy()); 3286 } 3287 return null; 3288 } 3289 3290 //// POP OPERAND FROM THE STACK. 3291 /** 3292 * Pops an operand from the stack. No type checking is performed. 3293 * @return the popped operand 3294 */ 3295 Operand pop() { 3296 return stack.pop(); 3297 } 3298 3299 /** 3300 * Pops an int operand from the stack. 3301 * @return the popped operand 3302 */ 3303 public Operand popInt() { 3304 Operand r = pop(); 3305 if (VM.VerifyAssertions) opt_assert(r.isIntLike()); 3306 return r; 3307 } 3308 3309 /** 3310 * Pops a float operand from the stack. 3311 * @return the popped operand 3312 */ 3313 Operand popFloat() { 3314 Operand r = pop(); 3315 if (VM.VerifyAssertions) opt_assert(r.isFloat()); 3316 return r; 3317 } 3318 3319 /** 3320 * Pops a ref operand from the stack. 3321 * @return the popped operand 3322 */ 3323 public Operand popRef() { 3324 Operand r = pop(); 3325 if (VM.VerifyAssertions) opt_assert(r.isRef() || r.isAddress()); 3326 return r; 3327 } 3328 3329 /** 3330 * Pops an address operand from the stack. 3331 * @return the popped operand 3332 */ 3333 public Operand popAddress() { 3334 Operand r = pop(); 3335 if (VM.VerifyAssertions) opt_assert(r.isAddress()); 3336 return r; 3337 } 3338 3339 /** 3340 * Pops a long operand from the stack. 3341 * @return the popped operand 3342 */ 3343 Operand popLong() { 3344 Operand r = pop(); 3345 if (VM.VerifyAssertions) opt_assert(r.isLong()); 3346 popDummy(); 3347 return r; 3348 } 3349 3350 /** 3351 * Pops a double operand from the stack. 3352 * @return the popped operand 3353 */ 3354 Operand popDouble() { 3355 Operand r = pop(); 3356 if (VM.VerifyAssertions) opt_assert(r.isDouble()); 3357 popDummy(); 3358 return r; 3359 } 3360 3361 /** 3362 * Pops a dummy operand from the stack. 3363 */ 3364 void popDummy() { 3365 Operand r = pop(); 3366 if (VM.VerifyAssertions) opt_assert(r == DUMMY); 3367 } 3368 3369 /** 3370 * Pops an operand of the given type from the stack. 3371 * @param type the expected type of the operand 3372 * @return the popped operand 3373 */ 3374 Operand pop(TypeReference type) { 3375 Operand r = pop(); 3376 // Can't assert the following due to approximations by 3377 // ClassLoaderProxy.findCommonSuperclass 3378 // if (VM.VerifyAssertions) assertIsType(r, type); 3379 // Avoid upcasts of magic types to regular j.l.Objects 3380// if (VM.VerifyAssertions && (type == TypeReference.JavaLangObject)) 3381// opt_assert(!r.getType().isMagicType()); 3382 if (VM.VerifyAssertions) { 3383 if ((type == TypeReference.JavaLangObject) && 3384 (r.getType().isMagicType()) && 3385 !gc.getMethod().getDeclaringClass().getTypeRef().isMagicType()) { 3386 throw new OptimizingCompilerException.IllegalUpcast(r.getType()); 3387 } 3388 } 3389 if (type.isLongType() || type.isDoubleType()) { 3390 popDummy(); 3391 } 3392 return r; 3393 } 3394 3395 /** 3396 * Pop an int from the stack to be used in a shift. A shift only uses the 3397 * bottom 5 or 6 bits of an int so the upper bits must be masked to conform 3398 * with the semantics of xx_SHx. NB the opt compiler shift operators allow that 3399 * {@code (x << 16) << 16 == x << 32}, which isn't true in the bytecode 3400 * @param longShift is this a shift of a long 3401 * @return the operand containing the amount to shift by 3402 */ 3403 private Operand popShiftInt(boolean longShift) { 3404 Operand op = popInt(); 3405 if (op instanceof IntConstantOperand) { 3406 int val = op.asIntConstant().value; 3407 if (!longShift) { 3408 if ((val > 0) && (val <= 31)) { 3409 return op; 3410 } else { 3411 return new IntConstantOperand(val & 0x1F); 3412 } 3413 } else { 3414 if ((val > 0) && (val <= 63)) { 3415 return op; 3416 } else { 3417 return new IntConstantOperand(val & 0x3F); 3418 } 3419 } 3420 } else { 3421 Instruction s = 3422 _binaryHelper(INT_AND, op, new IntConstantOperand(longShift ? 0x3F : 0x1f), TypeReference.Int); 3423 if (s != null && !currentBBLE.isSelfRegen()) { 3424 appendInstruction(s); 3425 } 3426 return popInt(); 3427 } 3428 } 3429 3430 //// SUBROUTINES. 3431 private Instruction _jsrHelper(int offset) { 3432 // (1) notify the BBSet that we have reached a JSR bytecode. 3433 // This enables the more complex JSR-aware implementation of 3434 // BBSet.getOrCreateBlock. 3435 blocks.seenJSR(); 3436 3437 // (2) push return address on expression stack 3438 push(new ReturnAddressOperand(bcodes.index())); 3439 3440 // (3) generate GOTO to subroutine body. 3441 BranchOperand branch = generateTarget(offset); 3442 return Goto.create(GOTO, branch); 3443 } 3444 3445 private Instruction _retHelper(int var) { 3446 // (1) consume the return address from the specified local variable 3447 Operand local = getLocal(var); 3448 ReturnAddressOperand ra = (ReturnAddressOperand) local; 3449 setLocal(var, null); // must set local null before calling getOrCreateBlock!! 3450 BasicBlockLE rb = getOrCreateBlock(ra.retIndex); 3451 3452 // (2) generate a GOTO to the return site. 3453 currentBBLE.block.insertOut(rb.block); 3454 endOfBasicBlock = true; 3455 if (DBG_CFG || DBG_SELECTED) db("Added CFG edge from " + currentBBLE.block + " to " + rb.block); 3456 return Goto.create(GOTO, rb.block.makeJumpTarget()); 3457 } 3458 3459 //// GET TYPE OF AN OPERAND. 3460 /** 3461 * Returns the data type of the given operand, assuming that the operand is 3462 * an array reference. (and not a {@code null} constant.) 3463 * 3464 * @param op operand to get type of 3465 * @return operand's data type 3466 */ 3467 public TypeReference getArrayTypeOf(Operand op) { 3468 if (VM.VerifyAssertions) opt_assert(!op.isDefinitelyNull()); 3469 return op.getType(); 3470 } 3471 3472 /** 3473 * Returns the data type of the given operand, assuming that the operand is 3474 * a reference. (and not a {@code null} constant.) 3475 * 3476 * @param op operand to get type of 3477 * @return operand's data type 3478 */ 3479 private TypeReference getRefTypeOf(Operand op) { 3480 if (VM.VerifyAssertions) opt_assert(!op.isDefinitelyNull()); 3481 return op.getType(); 3482 } 3483 3484 //// HELPER FUNCTIONS FOR ASSERTION VERIFICATION 3485 /** 3486 * Assert that the given operand is of the given type, or of 3487 * a subclass of the given type. 3488 * 3489 * @param op operand to check 3490 * @param type expected type of operand 3491 */ 3492 public void assertIsType(Operand op, TypeReference type) { 3493 if (VM.VerifyAssertions) { 3494 if (op.isDefinitelyNull()) { 3495 opt_assert(type.isReferenceType()); 3496 } else if (op.isIntLike()) { 3497 opt_assert(type.isIntLikeType()); 3498 } else { 3499 TypeReference type1 = op.getType(); 3500 if (ClassLoaderProxy.includesType(type, type1) == NO) { 3501 String msg = op + ": " + type + " is not assignable with " + type1; 3502 opt_assert(VM.NOT_REACHED, msg); 3503 } 3504 } 3505 } 3506 } 3507 3508 /** 3509 * Assert that the given child type is a subclass of the given parent type. 3510 * 3511 * @param parentType parent type 3512 * @param childType child type 3513 */ 3514 private void assertIsAssignable(TypeReference parentType, TypeReference childType) { 3515 if (VM.VerifyAssertions) { 3516 if (childType.isUnboxedType()) { 3517 //TODO: This should be opt_assert(gc.method.getReturnType() == retType.isUnboxedType()); 3518 // but all word types are converted into addresses and thus the assertion fails. This should be fixed. 3519 opt_assert(parentType.isUnboxedType()); 3520 } else { 3521 // fudge to deal with conservative approximation 3522 // in ClassLoaderProxy.findCommonSuperclass 3523 if (childType != TypeReference.JavaLangObject) { 3524 if (ClassLoaderProxy.includesType(parentType, childType) == NO) { 3525 VM.sysWriteln("type reference equality " + (parentType == childType)); 3526 Enumeration<InlineSequence> callHierarchy = gc.getInlineSequence().enumerateFromRoot(); 3527 while (callHierarchy.hasMoreElements()) { 3528 VM.sysWriteln(callHierarchy.nextElement().toString()); 3529 } 3530 String msg = parentType + " not assignable with " + childType; 3531 opt_assert(VM.NOT_REACHED, msg); 3532 } 3533 } 3534 } 3535 } 3536 } 3537 3538 //// DEBUGGING. 3539 /** 3540 * Print a debug string to the sysWrite stream 3541 * 3542 * @param val string to print 3543 */ 3544 private void db(String val) { 3545 VM.sysWrite("IRGEN " + bcodes.getDeclaringClass() + "." + gc.getMethod().getName() + ":" + val + "\n"); 3546 } 3547 3548 /** 3549 * @return a string representation of the current basic block set. 3550 */ 3551 private String printBlocks() { 3552 StringBuilder res = new StringBuilder(); 3553 for (Enumeration<BasicBlockLE> e = blocks.contents(); e.hasMoreElements();) { 3554 BasicBlockLE b = e.nextElement(); 3555 if (b == currentBBLE) { 3556 res.append("*"); 3557 } 3558 res.append(b.toString()); 3559 res.append(" "); 3560 } 3561 return res.toString(); 3562 } 3563 3564 //// GENERATE CHECK INSTRUCTIONS. 3565 public static boolean isNonNull(Operand op) { 3566 if (op instanceof RegisterOperand) { 3567 RegisterOperand rop = (RegisterOperand) op; 3568 if (VM.VerifyAssertions) { 3569 opt_assert((rop.getGuard() == null) || 3570 (rop.getGuard() instanceof RegisterOperand) || 3571 (rop.getGuard() instanceof TrueGuardOperand)); 3572 } 3573 return rop.getGuard() != null; 3574 } else { 3575 return op.isConstant(); 3576 } 3577 } 3578 3579 public static boolean hasGuard(RegisterOperand rop) { 3580 return rop.getGuard() != null; 3581 } 3582 3583 public static boolean hasLessConservativeGuard(RegisterOperand rop1, RegisterOperand rop2) { 3584 if (rop1.getGuard() == rop2.getGuard()) { 3585 return false; 3586 } 3587 if (rop1.getGuard() instanceof Operand) { 3588 if (rop2.getGuard() instanceof Operand) { 3589 Operand op1 = rop1.getGuard(); 3590 Operand op2 = rop2.getGuard(); 3591 if (op2 instanceof TrueGuardOperand) { 3592 // rop2 is top therefore rop1 can't be less conservative! 3593 return false; 3594 } else { 3595 return !(op1.similar(op2)); 3596 } 3597 } else { 3598 return true; 3599 } 3600 } else { 3601 // rop1 is bottom, therefore is most conservative guard possible 3602 return false; 3603 } 3604 } 3605 3606 public void markGuardlessNonNull(RegisterOperand rop) { 3607 RegisterOperand g = gc.makeNullCheckGuard(rop.getRegister()); 3608 appendInstruction(Move.create(GUARD_MOVE, g, new TrueGuardOperand())); 3609 rop.setGuard(g.copy()); 3610 } 3611 3612 public static Operand copyGuardFromOperand(Operand op) { 3613 if (op instanceof RegisterOperand) { 3614 RegisterOperand rop = (RegisterOperand) op; 3615 if (VM.VerifyAssertions) { 3616 opt_assert((rop.getGuard() == null) || 3617 (rop.getGuard() instanceof RegisterOperand) || 3618 (rop.getGuard() instanceof TrueGuardOperand)); 3619 } 3620 if (rop.getGuard() == null) { 3621 return null; 3622 } else { 3623 return rop.getGuard().copy(); 3624 } 3625 } 3626 if (VM.VerifyAssertions) { 3627 opt_assert(op.isConstant()); 3628 } 3629 return new TrueGuardOperand(); 3630 } 3631 3632 public static void setGuardForRegOp(RegisterOperand rop, Operand guard) { 3633 rop.setGuard(guard); 3634 } 3635 3636 private void setCurrentGuard(Operand guard) { 3637 if (currentGuard instanceof RegisterOperand) { 3638 if (VM.VerifyAssertions) { 3639 opt_assert(!(guard instanceof TrueGuardOperand)); 3640 } 3641 // shouldn't happen given current generation --dave. 3642 RegisterOperand combined = gc.getTemps().makeTempValidation(); 3643 appendInstruction(Binary.create(GUARD_COMBINE, combined, getCurrentGuard(), guard.copy())); 3644 currentGuard = combined; 3645 } else { 3646 currentGuard = guard; 3647 } 3648 } 3649 3650 public void clearCurrentGuard() { 3651 currentGuard = null; 3652 } 3653 3654 public Operand getCurrentGuard() { 3655 // This check is needed for when guards are (unsafely) turned off 3656 if (currentGuard != null) { 3657 return currentGuard.copy(); 3658 } 3659 return null; 3660 } 3661 3662 /** 3663 * Generates a null-check instruction for the given operand. 3664 * @param ref the reference to check for null 3665 * @return {@code true} if an unconditional throw is generated, {@code false} otherwise 3666 */ 3667 public boolean do_NullCheck(Operand ref) { 3668 if (gc.noNullChecks()) { 3669 setCurrentGuard(new TrueGuardOperand()); 3670 return false; 3671 } 3672 if (ref.isDefinitelyNull()) { 3673 if (DBG_CF) db("generating definite exception: null_check of definitely null"); 3674 endOfBasicBlock = true; 3675 rectifyStateWithNullPtrExceptionHandler(); 3676 appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.NullPtr())); 3677 return true; 3678 } 3679 if (ref instanceof RegisterOperand) { 3680 RegisterOperand rop = (RegisterOperand) ref; 3681 if (hasGuard(rop)) { 3682 Operand guard = copyGuardFromOperand(rop); 3683 setCurrentGuard(guard); 3684 if (DBG_ELIMNULL) { 3685 db("null check of " + ref + " is not necessary; guarded by " + guard); 3686 } 3687 return false; 3688 } 3689 // rop is possibly null, insert the null check, 3690 // rectify with exception handler, update the guard state. 3691 RegisterOperand guard = gc.makeNullCheckGuard(rop.getRegister()); 3692 appendInstruction(NullCheck.create(NULL_CHECK, guard, ref.copy())); 3693 rectifyStateWithNullPtrExceptionHandler(); 3694 setCurrentGuard(guard); 3695 setGuardForRegOp(rop, guard); 3696 if (DBG_ELIMNULL) db(rop + " is guarded by " + guard); 3697 // Now, try to leverage this null check by updating 3698 // other unguarded (and thus potentially null) 3699 // RegisterOperands representing the same Register. 3700 if (rop.getRegister().isLocal()) { 3701 // We want to learn that downstream of this nullcheck, other 3702 // uses of this local variable will also be non-null. 3703 // BUT, we MUST NOT just directly set the guard of the appropriate 3704 // element of our locals array (operands in the local array 3705 // may appear in previously generated instructions). 3706 // Therefore we call getLocal (which internally makes a copy), 3707 // mark the copy with the new guard 3708 // and finally store the copy back into the local state. 3709 int number = gc.getLocalNumberFor(rop.getRegister(), rop.getType()); 3710 if (number != -1) { 3711 Operand loc = getLocal(number); 3712 if (loc instanceof RegisterOperand) { 3713 if (DBG_ELIMNULL) { 3714 db("setting local #" + number + "(" + loc + ") to non-null"); 3715 } 3716 setGuardForRegOp((RegisterOperand) loc, guard); 3717 } 3718 setLocal(number, loc); 3719 } 3720 } 3721 // At least within this basic block we know that all subsequent uses 3722 // of ref will be non null, since they are guarded by the null check 3723 // instruction we just inserted. Update all RegisterOperands with 3724 // this register currently on the expression stack appropriately. 3725 // Stack rectification will ensure that we don't propagate this 3726 // non-nullness to a use that is not dominated by the null check in 3727 // the current basic block. 3728 for (int i = stack.getSize() - 1; i >= 0; --i) { 3729 Operand sop = stack.getFromTop(i); 3730 if (sop instanceof RegisterOperand) { 3731 RegisterOperand sreg = (RegisterOperand) sop; 3732 if (sreg.getRegister() == rop.getRegister()) { 3733 if (hasGuard(sreg)) { 3734 if (DBG_ELIMNULL) { 3735 db(sreg + " on stack already with guard " + copyGuardFromOperand(sreg)); 3736 } 3737 } else { 3738 if (DBG_ELIMNULL) { 3739 db("setting " + sreg + " on stack to be guarded by " + guard); 3740 } 3741 setGuardForRegOp(sreg, guard); 3742 } 3743 } 3744 } 3745 } 3746 return false; 3747 } else { 3748 // cannot be null becuase it's not in a register. 3749 if (DBG_ELIMNULL) { 3750 db("skipped generation of a null-check instruction for non-register " + ref); 3751 } 3752 setCurrentGuard(new TrueGuardOperand()); 3753 return false; 3754 } 3755 } 3756 3757 /** 3758 * Generates a boundscheck instruction for the given operand and index. 3759 * @param ref the array reference 3760 * @param index the array index 3761 * @return {@code true} if an unconditional throw is generated, {@code false} otherwise 3762 */ 3763 public boolean do_BoundsCheck(Operand ref, Operand index) { 3764 // Unsafely eliminate all bounds checks 3765 if (gc.noBoundsChecks()) { 3766 return false; 3767 } 3768 RegisterOperand guard = gc.getTemps().makeTempValidation(); 3769 appendInstruction(BoundsCheck.create(BOUNDS_CHECK, guard, ref.copy(), index.copy(), getCurrentGuard())); 3770 setCurrentGuard(guard); 3771 rectifyStateWithArrayBoundsExceptionHandler(); 3772 return false; 3773 } 3774 3775 /** 3776 * Generates a check for 0 for the given operand 3777 * @param div the value to check 3778 * @return {@code true} if an unconditional trap is generated, {@code false} otherwise 3779 */ 3780 private boolean do_IntZeroCheck(Operand div) { 3781 if (div instanceof IntConstantOperand) { 3782 if (((IntConstantOperand) div).value == 0) { 3783 endOfBasicBlock = true; 3784 rectifyStateWithArithmeticExceptionHandler(); 3785 appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.DivByZero())); 3786 return true; 3787 } else { 3788 if (DBG_CF) { 3789 db("skipped gen of int_zero_check of " + div.asIntConstant().value); 3790 } 3791 setCurrentGuard(new TrueGuardOperand()); 3792 return false; 3793 } 3794 } 3795 RegisterOperand guard = gc.getTemps().makeTempValidation(); 3796 appendInstruction(ZeroCheck.create(INT_ZERO_CHECK, guard, div.copy())); 3797 setCurrentGuard(guard); 3798 rectifyStateWithArithmeticExceptionHandler(); 3799 return false; 3800 } 3801 3802 /** 3803 * Generates a checks for 0 for the given operand 3804 * @param div the value to check 3805 * @return {@code true} if an unconditional trap is generated, {@code false} otherwise 3806 */ 3807 private boolean do_LongZeroCheck(Operand div) { 3808 if (div instanceof LongConstantOperand) { 3809 if (((LongConstantOperand) div).value == 0) { 3810 endOfBasicBlock = true; 3811 rectifyStateWithArithmeticExceptionHandler(); 3812 appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.DivByZero())); 3813 return true; 3814 } else { 3815 if (DBG_CF) { 3816 db("skipped gen of long_zero_check of " + div.asLongConstant().value); 3817 } 3818 setCurrentGuard(new TrueGuardOperand()); 3819 return false; 3820 } 3821 } 3822 RegisterOperand guard = gc.getTemps().makeTempValidation(); 3823 appendInstruction(ZeroCheck.create(LONG_ZERO_CHECK, guard, div.copy())); 3824 setCurrentGuard(guard); 3825 rectifyStateWithArithmeticExceptionHandler(); 3826 return false; 3827 } 3828 3829 /** 3830 * Generate a storecheck for the given array and elem 3831 * @param ref the array reference 3832 * @param elem the element to be written to the array 3833 * @param elemType the type of the array references elements 3834 * @return {@code true} if an unconditional throw is generated, {@code false} otherwise 3835 */ 3836 private boolean do_CheckStore(Operand ref, Operand elem, TypeReference elemType) { 3837 if (gc.noCheckStoreChecks()) return false; 3838 3839 if (CF_CHECKSTORE) { 3840 // NOTE: BE WARY OF ADDITIONAL OPTIMZATIONS. 3841 // ARRAY SUBTYPING IS SUBTLE (see JLS 10.10) --dave 3842 if (elem.isDefinitelyNull()) { 3843 if (DBG_TYPE) db("skipping checkstore of null constant"); 3844 return false; 3845 } 3846 if (elemType.isArrayType()) { 3847 TypeReference elemType2 = elemType; 3848 do { 3849 elemType2 = elemType2.getArrayElementType(); 3850 } while (elemType2.isArrayType()); 3851 RVMType et2 = elemType2.peekType(); 3852 if (et2 != null) { 3853 if (et2.isPrimitiveType() || et2.isUnboxedType() || ((RVMClass) et2).isFinal()) { 3854 TypeReference myElemType = getRefTypeOf(elem); 3855 if (myElemType == elemType) { 3856 if (DBG_TYPE) { 3857 db("eliminating checkstore to an array with a final element type " + elemType); 3858 } 3859 return false; 3860 } else { 3861 // run time check is still necessary 3862 } 3863 } 3864 } 3865 } else { 3866 // elemType is class 3867 RVMType et = elemType.peekType(); 3868 if (et != null && ((RVMClass) et).isFinal()) { 3869 if (getRefTypeOf(elem) == elemType) { 3870 if (DBG_TYPE) { 3871 db("eliminating checkstore to an array with a final element type " + elemType); 3872 } 3873 return false; 3874 } else { 3875 // run time check is still necessary 3876 } 3877 } 3878 } 3879 } 3880 3881 RegisterOperand guard = gc.getTemps().makeTempValidation(); 3882 if (isNonNull(elem)) { 3883 RegisterOperand newGuard = gc.getTemps().makeTempValidation(); 3884 appendInstruction(Binary.create(GUARD_COMBINE, newGuard, copyGuardFromOperand(elem), getCurrentGuard())); 3885 appendInstruction(StoreCheck.create(OBJARRAY_STORE_CHECK_NOTNULL, 3886 guard, 3887 ref.copy(), 3888 elem.copy(), 3889 newGuard.copy())); 3890 } else { 3891 appendInstruction(StoreCheck.create(OBJARRAY_STORE_CHECK, guard, ref.copy(), elem.copy(), getCurrentGuard())); 3892 } 3893 setCurrentGuard(guard); 3894 rectifyStateWithArrayStoreExceptionHandler(); 3895 return false; 3896 } 3897 3898 //// GENERATE BRANCHING INSTRUCTIONS. 3899 /** 3900 * Gets or creates a block at the specified target. 3901 * Rectifies current state with target state. 3902 * Instructions to rectify state are appended to currentBBLE. 3903 * If the target is between bcodes.index() and runoff, runoff is 3904 * updated to be target. 3905 * 3906 * @param target target index 3907 * @return a block, never {@code null} 3908 */ 3909 private BasicBlockLE getOrCreateBlock(int target) { 3910 return getOrCreateBlock(target, currentBBLE, stack, _localState); 3911 } 3912 3913 /** 3914 * Get or create a block at the specified target. 3915 * If simStack is non-{@code null}, rectifies stack state with target stack state. 3916 * If simLocals is non-{@code null}, rectifies local state with target local state. 3917 * Any instructions needed to rectify stack/local state are appended to from. 3918 * If the target is between bcodes.index() and runoff, runoff is 3919 * updated to be target. 3920 * 3921 * @param target target index 3922 * @param from the block from which control is being transfered 3923 * and to which stack rectification instructions are added. 3924 * @param simStack stack state to rectify, or {@code null} 3925 * @param simLocals local state to rectify, or {@code null} 3926 * @return a block, never {@code null} 3927 */ 3928 private BasicBlockLE getOrCreateBlock(int target, BasicBlockLE from, OperandStack simStack, Operand[] simLocals) { 3929 if ((target > bcodes.index()) && (target < runoff)) { 3930 if (DBG_BB || DBG_SELECTED) db("updating runoff from " + runoff + " to " + target); 3931 runoff = target; 3932 } 3933 return blocks.getOrCreateBlock(target, from, simStack, simLocals); 3934 } 3935 3936 private BranchOperand generateTarget(int offset) { 3937 BasicBlockLE targetbble = getOrCreateBlock(offset + instrIndex); 3938 currentBBLE.block.insertOut(targetbble.block); 3939 endOfBasicBlock = true; 3940 if (DBG_CFG || DBG_SELECTED) { 3941 db("Added CFG edge from " + currentBBLE.block + " to " + targetbble.block); 3942 } 3943 return targetbble.block.makeJumpTarget(); 3944 } 3945 3946 // GOTO 3947 private Instruction _gotoHelper(int offset) { 3948 return Goto.create(GOTO, generateTarget(offset)); 3949 } 3950 3951 // helper function for if?? bytecodes 3952 private Instruction _intIfHelper(ConditionOperand cond) { 3953 int offset = bcodes.getBranchOffset(); 3954 Operand op0 = popInt(); 3955 if (offset == 3) { 3956 return null; // remove frivolous IFs 3957 } 3958 if (CF_INTIF && op0 instanceof IntConstantOperand) { 3959 int c = cond.evaluate(((IntConstantOperand) op0).value, 0); 3960 if (c == ConditionOperand.TRUE) { 3961 if (DBG_CF) { 3962 db(cond + ": changed branch to goto because predicate (" + op0 + ") is constant true"); 3963 } 3964 return _gotoHelper(offset); 3965 } else if (c == ConditionOperand.FALSE) { 3966 if (DBG_CF) { 3967 db(cond + ": eliminated branch because predicate (" + op0 + ") is constant false"); 3968 } 3969 return null; 3970 } 3971 } 3972 fallThrough = true; 3973 if (!(op0 instanceof RegisterOperand)) { 3974 if (DBG_CF) db("generated int_ifcmp of " + op0 + " with 0"); 3975 RegisterOperand guard = gc.getTemps().makeTempValidation(); 3976 return IfCmp.create(INT_IFCMP, 3977 guard, 3978 op0, 3979 new IntConstantOperand(0), 3980 cond, 3981 generateTarget(offset), 3982 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 3983 } 3984 RegisterOperand val = (RegisterOperand) op0; 3985 BranchOperand branch = null; 3986 if (lastInstr != null) { 3987 switch (lastInstr.getOpcode()) { 3988 case INSTANCEOF_opcode: 3989 case INSTANCEOF_UNRESOLVED_opcode: { 3990 if (DBG_TYPE) db("last instruction was instanceof"); 3991 RegisterOperand res = InstanceOf.getResult(lastInstr); 3992 if (DBG_TYPE) db("result was in " + res + ", we are checking " + val); 3993 if (val.getRegister() != res.getRegister()) { 3994 break; // not our value 3995 } 3996 Operand ref = InstanceOf.getRef(lastInstr); 3997 // should've been constant folded anyway 3998 if (!(ref instanceof RegisterOperand)) { 3999 break; 4000 } 4001 RegisterOperand guard = null; 4002 // Propagate types and non-nullness along the CFG edge where we 4003 // know that refReg is an instanceof type2 4004 RegisterOperand refReg = (RegisterOperand) ref; 4005 TypeReference type2 = InstanceOf.getType(lastInstr).getTypeRef(); 4006 if (cond.isNOT_EQUAL()) { 4007 // IS an instance of on the branch-taken edge 4008 boolean generated = false; 4009 if (refReg.getRegister().isLocal()) { 4010 int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType()); 4011 if (locNum != -1) { 4012 Operand loc = getLocal(locNum); 4013 if (loc instanceof RegisterOperand) { 4014 if (DBG_TYPE) { 4015 db(val + 4016 " is from instanceof test, propagating new type of " + 4017 refReg + 4018 " (" + 4019 type2 + 4020 ") to basic block at " + 4021 offset); 4022 } 4023 RegisterOperand locr = (RegisterOperand) loc; 4024 RegisterOperand tlocr = locr.copyU2U(); 4025 guard = gc.makeNullCheckGuard(tlocr.getRegister()); 4026 setGuardForRegOp(tlocr, guard.copyD2U()); 4027 tlocr.clearDeclaredType(); 4028 tlocr.clearPreciseType(); 4029 tlocr.setType(type2); 4030 setLocal(locNum, tlocr); 4031 branch = generateTarget(offset); 4032 generated = true; 4033 setLocal(locNum, locr); 4034 } 4035 } 4036 } 4037 if (!generated) { 4038 branch = generateTarget(offset); 4039 } 4040 } else if (cond.isEQUAL()) { 4041 // IS an instance of on the fallthrough edge. 4042 branch = generateTarget(offset); 4043 if (refReg.getRegister().isLocal()) { 4044 int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType()); 4045 if (locNum != -1) { 4046 Operand loc = getLocal(locNum); 4047 if (loc instanceof RegisterOperand) { 4048 if (DBG_TYPE) { 4049 db(val + 4050 " is from instanceof test, propagating new type of " + 4051 refReg + 4052 " (" + 4053 type2 + 4054 ") along fallthrough edge"); 4055 } 4056 RegisterOperand locr = (RegisterOperand) loc; 4057 guard = gc.makeNullCheckGuard(locr.getRegister()); 4058 setGuardForRegOp(locr, guard.copyD2U()); 4059 locr.clearDeclaredType(); 4060 locr.clearPreciseType(); 4061 locr.setType(type2); 4062 setLocal(locNum, loc); 4063 } 4064 } 4065 } 4066 } 4067 if (guard == null) { 4068 guard = gc.getTemps().makeTempValidation(); 4069 } 4070 return IfCmp.create(INT_IFCMP, 4071 guard, 4072 val, 4073 new IntConstantOperand(0), 4074 cond, 4075 branch, 4076 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 4077 } 4078 case INSTANCEOF_NOTNULL_opcode: { 4079 if (DBG_TYPE) db("last instruction was instanceof"); 4080 RegisterOperand res = InstanceOf.getResult(lastInstr); 4081 if (DBG_TYPE) { 4082 db("result was in " + res + ", we are checking " + val); 4083 } 4084 if (val.getRegister() != res.getRegister()) { 4085 break; // not our value 4086 } 4087 Operand ref = InstanceOf.getRef(lastInstr); 4088 // should've been constant folded anyway 4089 if (!(ref instanceof RegisterOperand)) { 4090 break; 4091 } 4092 // Propagate types along the CFG edge where we know that 4093 // refReg is an instanceof type2 4094 RegisterOperand refReg = (RegisterOperand) ref; 4095 TypeReference type2 = InstanceOf.getType(lastInstr).getTypeRef(); 4096 if (cond.isNOT_EQUAL()) { 4097 // IS an instance of on the branch-taken edge 4098 boolean generated = false; 4099 if (refReg.getRegister().isLocal()) { 4100 int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType()); 4101 if (locNum != -1) { 4102 Operand loc = getLocal(locNum); 4103 if (loc instanceof RegisterOperand) { 4104 if (DBG_TYPE) { 4105 db(val + 4106 " is from instanceof test, propagating new type of " + 4107 refReg + 4108 " (" + 4109 type2 + 4110 ") to basic block at " + 4111 offset); 4112 } 4113 RegisterOperand locr = (RegisterOperand) loc; 4114 RegisterOperand tlocr = locr.copyU2U(); 4115 tlocr.clearDeclaredType(); 4116 tlocr.clearPreciseType(); 4117 tlocr.setType(type2); 4118 setLocal(locNum, tlocr); 4119 branch = generateTarget(offset); 4120 generated = true; 4121 setLocal(locNum, locr); 4122 } 4123 } 4124 } 4125 if (!generated) { 4126 branch = generateTarget(offset); 4127 } 4128 } else if (cond.isEQUAL()) { 4129 // IS an instance of on the fallthrough edge. 4130 branch = generateTarget(offset); 4131 if (refReg.getRegister().isLocal()) { 4132 int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType()); 4133 if (locNum != -1) { 4134 Operand loc = getLocal(locNum); 4135 if (loc instanceof RegisterOperand) { 4136 if (DBG_TYPE) { 4137 db(val + 4138 " is from instanceof test, propagating new type of " + 4139 refReg + 4140 " (" + 4141 type2 + 4142 ") along fallthrough edge"); 4143 } 4144 RegisterOperand locr = (RegisterOperand) loc; 4145 locr.setType(type2); 4146 locr.clearDeclaredType(); 4147 setLocal(locNum, loc); 4148 } 4149 } 4150 } 4151 } 4152 RegisterOperand guard = gc.getTemps().makeTempValidation(); 4153 return IfCmp.create(INT_IFCMP, 4154 guard, 4155 val, 4156 new IntConstantOperand(0), 4157 cond, 4158 branch, 4159 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 4160 } 4161 case DOUBLE_CMPG_opcode: 4162 case DOUBLE_CMPL_opcode: 4163 case FLOAT_CMPG_opcode: 4164 case FLOAT_CMPL_opcode: 4165 case LONG_CMP_opcode: { 4166 RegisterOperand res = Binary.getResult(lastInstr); 4167 if (val.getRegister() != res.getRegister()) { 4168 break; // not our value 4169 } 4170 Operator operator = null; 4171 switch (lastInstr.getOpcode()) { 4172 case DOUBLE_CMPG_opcode: 4173 cond.translateCMPG(); 4174 operator = DOUBLE_IFCMP; 4175 break; 4176 case DOUBLE_CMPL_opcode: 4177 cond.translateCMPL(); 4178 operator = DOUBLE_IFCMP; 4179 break; 4180 case FLOAT_CMPG_opcode: 4181 cond.translateCMPG(); 4182 operator = FLOAT_IFCMP; 4183 break; 4184 case FLOAT_CMPL_opcode: 4185 cond.translateCMPL(); 4186 operator = FLOAT_IFCMP; 4187 break; 4188 case LONG_CMP_opcode: 4189 operator = LONG_IFCMP; 4190 break; 4191 default: 4192 OptimizingCompilerException.UNREACHABLE(); 4193 break; 4194 } 4195 Operand val1 = Binary.getClearVal1(lastInstr); 4196 Operand val2 = Binary.getClearVal2(lastInstr); 4197 if (!(val1 instanceof RegisterOperand)) { 4198 // swap operands 4199 Operand temp = val1; 4200 val1 = val2; 4201 val2 = temp; 4202 cond = cond.flipOperands(); 4203 } 4204 lastInstr.remove(); 4205 lastInstr = null; 4206 branch = generateTarget(offset); 4207 RegisterOperand guard = gc.getTemps().makeTempValidation(); 4208 return IfCmp.create(operator, 4209 guard, 4210 val1, 4211 val2, 4212 cond, 4213 branch, 4214 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 4215 } 4216 default: 4217 // Fall through and Insert INT_IFCMP 4218 break; 4219 } 4220 } 4221 branch = generateTarget(offset); 4222 RegisterOperand guard = gc.getTemps().makeTempValidation(); 4223 return IfCmp.create(INT_IFCMP, 4224 guard, 4225 val, 4226 new IntConstantOperand(0), 4227 cond, 4228 branch, 4229 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 4230 } 4231 4232 // helper function for if_icmp?? bytecodes 4233 private Instruction _intIfCmpHelper(ConditionOperand cond) { 4234 int offset = bcodes.getBranchOffset(); 4235 Operand op1 = popInt(); 4236 Operand op0 = popInt(); 4237 if (offset == 3) { 4238 return null; // remove frivolous INF_IFCMPs 4239 } 4240 if (!(op0 instanceof RegisterOperand)) { 4241 // swap operands 4242 Operand temp = op0; 4243 op0 = op1; 4244 op1 = temp; 4245 cond = cond.flipOperands(); 4246 } 4247 if (CF_INTIFCMP && (op0 instanceof IntConstantOperand) && (op1 instanceof IntConstantOperand)) { 4248 int c = cond.evaluate(((IntConstantOperand) op0).value, ((IntConstantOperand) op1).value); 4249 if (c == ConditionOperand.TRUE) { 4250 if (DBG_CF) { 4251 db(cond + ": changed branch to goto because predicate (" + op0 + ", " + op1 + ") is constant true"); 4252 } 4253 return _gotoHelper(offset); 4254 } else if (c == ConditionOperand.FALSE) { 4255 if (DBG_CF) { 4256 db(cond + ": eliminated branch because predicate (" + op0 + "," + op1 + ") is constant false"); 4257 } 4258 return null; 4259 } 4260 } 4261 fallThrough = true; 4262 RegisterOperand guard = gc.getTemps().makeTempValidation(); 4263 return IfCmp.create(INT_IFCMP, 4264 guard, 4265 op0, 4266 op1, 4267 cond, 4268 generateTarget(offset), 4269 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 4270 } 4271 4272 // helper function for ifnull/ifnonnull bytecodes 4273 private Instruction _refIfNullHelper(ConditionOperand cond) { 4274 if (VM.VerifyAssertions) opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL()); 4275 int offset = bcodes.getBranchOffset(); 4276 Operand op0 = popRef(); 4277 if (offset == 3) { 4278 return null; // remove frivolous REF_IFs 4279 } 4280 if (CF_REFIF) { 4281 if (op0.isDefinitelyNull()) { 4282 if (cond.isEQUAL()) { 4283 if (DBG_CF) { 4284 db(cond + ": changed branch to goto because predicate is true"); 4285 } 4286 return _gotoHelper(offset); 4287 } else { 4288 if (DBG_CF) { 4289 db(cond + ": eliminated branch because predicate is false"); 4290 } 4291 return null; 4292 } 4293 } 4294 if (isNonNull(op0)) { 4295 if (cond.isNOT_EQUAL()) { 4296 if (DBG_CF) { 4297 db(cond + ": changed branch to goto because predicate is true"); 4298 } 4299 return _gotoHelper(offset); 4300 } else { 4301 if (DBG_CF) { 4302 db(cond + ": eliminated branch because predicate is false"); 4303 } 4304 return null; 4305 } 4306 } 4307 } 4308 RegisterOperand ref = (RegisterOperand) op0; 4309 BranchOperand branch = null; 4310 RegisterOperand guard = null; 4311 4312 // Check for incorrect null checks on unboxed types 4313 if (ref.getType().isUnboxedType()) { 4314 throw new OptimizingCompilerException("Detected incorrect null check of unboxed type in " + 4315 gc.getMethod() + " at bytecode index " + instrIndex + " from class " + 4316 gc.getMethod().getDeclaringClass() + 4317 " . Use the methods provided on the unboxed types to do null checks!"); 4318 } 4319 4320 if (cond.isEQUAL()) { 4321 branch = generateTarget(offset); 4322 if (ref.getRegister().isLocal()) { 4323 int locNum = gc.getLocalNumberFor(ref.getRegister(), ref.getType()); 4324 if (locNum != -1) { 4325 Operand loc = getLocal(locNum); 4326 if (loc instanceof RegisterOperand) { 4327 RegisterOperand locr = (RegisterOperand) loc; 4328 guard = gc.makeNullCheckGuard(locr.getRegister()); 4329 setGuardForRegOp(locr, guard.copyD2U()); 4330 setLocal(locNum, loc); 4331 } 4332 } 4333 } 4334 } else { 4335 boolean generated = false; 4336 if (ref.getRegister().isLocal()) { 4337 int locNum = gc.getLocalNumberFor(ref.getRegister(), ref.getType()); 4338 if (locNum != -1) { 4339 Operand loc = getLocal(locNum); 4340 if (loc instanceof RegisterOperand) { 4341 RegisterOperand locr = (RegisterOperand) loc; 4342 RegisterOperand tlocr = locr.copyU2U(); 4343 guard = gc.makeNullCheckGuard(locr.getRegister()); 4344 setGuardForRegOp(tlocr, guard.copyD2U()); 4345 setLocal(locNum, tlocr); 4346 branch = generateTarget(offset); 4347 generated = true; 4348 setLocal(locNum, locr); 4349 } 4350 } 4351 } 4352 if (!generated) { 4353 branch = generateTarget(offset); 4354 } 4355 } 4356 fallThrough = true; 4357 if (guard == null) { 4358 guard = gc.getTemps().makeTempValidation(); 4359 } 4360 return IfCmp.create(REF_IFCMP, 4361 guard, 4362 ref, 4363 new NullConstantOperand(), 4364 cond, 4365 branch, 4366 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 4367 } 4368 4369 // helper function for if_acmp?? bytecodes 4370 private Instruction _refIfCmpHelper(ConditionOperand cond) { 4371 if (VM.VerifyAssertions) opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL()); 4372 int offset = bcodes.getBranchOffset(); 4373 Operand op1 = popRef(); 4374 Operand op0 = popRef(); 4375 if (offset == 3) { 4376 return null; // remove frivolous REF_IFCMPs 4377 } 4378 if (!(op0 instanceof RegisterOperand)) { 4379 // swap operands 4380 Operand temp = op0; 4381 op0 = op1; 4382 op1 = temp; 4383 cond = cond.flipOperands(); 4384 } 4385 if (CF_REFIFCMP && op0.isDefinitelyNull() && op1.isDefinitelyNull()) { 4386 if (cond.isEQUAL()) { 4387 if (DBG_CF) { 4388 db(cond + ": changed branch to goto because predicate is true"); 4389 } 4390 return _gotoHelper(offset); 4391 } else { 4392 if (DBG_CF) { 4393 db(cond + ": eliminated branch because predicate is false"); 4394 } 4395 return null; 4396 } 4397 } 4398 4399 // Check for incorrect comparison operators on unboxed types 4400 if (op0.isRegister()) { 4401 RegisterOperand op0Reg = op0.asRegister(); 4402 if (op0Reg.getType().isUnboxedType()) { 4403 throw new OptimizingCompilerException("Detected incorrect comparison of unboxed types in " + 4404 gc.getMethod() + " at bytecode index " + instrIndex + " from class " + 4405 gc.getMethod().getDeclaringClass() + 4406 " . Use the methods provided on the unboxed types to do comparisons!"); 4407 } 4408 } 4409 if (op1.isRegister()) { 4410 RegisterOperand op1Reg = op1.asRegister(); 4411 if (op1Reg.getType().isUnboxedType()) { 4412 throw new OptimizingCompilerException("Detected incorrect comparison of unboxed types in " + 4413 gc.getMethod() + " at bytecode index " + instrIndex + " from class " + 4414 gc.getMethod().getDeclaringClass() + 4415 " . Use the methods provided on the unboxed types to do comparisons!"); 4416 } 4417 } 4418 4419 fallThrough = true; 4420 RegisterOperand guard = gc.getTemps().makeTempValidation(); 4421 return IfCmp.create(REF_IFCMP, 4422 guard, 4423 op0, 4424 op1, 4425 cond, 4426 generateTarget(offset), 4427 gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0)); 4428 } 4429 4430////REPLACE LOCALS ON STACK. 4431 // 4432 4433 4434 4435 /** 4436 * Replaces copies of local {@code <#index,type>} with 4437 * newly-generated temporaries, and generates the necessary move instructions. 4438 * @param index the local's index 4439 * @param type the local's type 4440 */ 4441 private void replaceLocalsOnStack(int index, TypeReference type) { 4442 int i; 4443 int size = stack.getSize(); 4444 for (i = 0; i < size; ++i) { 4445 Operand op = stack.getFromTop(i); 4446 if (gc.isLocal(op, index, type)) { 4447 RegisterOperand lop = (RegisterOperand) op; 4448 RegisterOperand t = gc.getTemps().makeTemp(lop); 4449 Instruction s = Move.create(IRTools.getMoveOp(t.getType()), t, op); 4450 stack.replaceFromTop(i, t.copyD2U()); 4451 s.position = gc.getInlineSequence(); 4452 s.bcIndex = instrIndex; 4453 if (DBG_LOCAL || DBG_SELECTED) { 4454 db("replacing local " + index + " at " + i + " from tos with " + t); 4455 } 4456 appendInstruction(s); 4457 } 4458 } 4459 } 4460 4461 ////////// 4462 // EXCEPTION HANDLERS. 4463 4464 ////////// 4465 // Some common cases to make the code more readable... 4466 4467 private BasicBlock rectifyStateWithNullPtrExceptionHandler() { 4468 return rectifyStateWithNullPtrExceptionHandler(false); 4469 } 4470 4471 private BasicBlock rectifyStateWithArrayBoundsExceptionHandler() { 4472 return rectifyStateWithArrayBoundsExceptionHandler(false); 4473 } 4474 4475 private BasicBlock rectifyStateWithArithmeticExceptionHandler() { 4476 return rectifyStateWithArithmeticExceptionHandler(false); 4477 } 4478 4479 private BasicBlock rectifyStateWithArrayStoreExceptionHandler() { 4480 return rectifyStateWithArrayStoreExceptionHandler(false); 4481 } 4482 4483 private BasicBlock rectifyStateWithErrorHandler() { 4484 return rectifyStateWithErrorHandler(false); 4485 } 4486 4487 public void rectifyStateWithExceptionHandlers() { 4488 rectifyStateWithExceptionHandlers(false); 4489 } 4490 4491 public BasicBlock rectifyStateWithExceptionHandler(TypeReference exceptionType) { 4492 return rectifyStateWithExceptionHandler(exceptionType, false); 4493 } 4494 4495 private BasicBlock rectifyStateWithNullPtrExceptionHandler(boolean linkToExitIfUncaught) { 4496 TypeReference et = TypeReference.JavaLangNullPointerException; 4497 return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught); 4498 } 4499 4500 private BasicBlock rectifyStateWithArrayBoundsExceptionHandler(boolean linkToExitIfUncaught) { 4501 TypeReference et = TypeReference.JavaLangArrayIndexOutOfBoundsException; 4502 return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught); 4503 } 4504 4505 private BasicBlock rectifyStateWithArithmeticExceptionHandler(boolean linkToExitIfUncaught) { 4506 TypeReference et = TypeReference.JavaLangArithmeticException; 4507 return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught); 4508 } 4509 4510 private BasicBlock rectifyStateWithArrayStoreExceptionHandler(boolean linkToExitIfUncaught) { 4511 TypeReference et = TypeReference.JavaLangArrayStoreException; 4512 return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught); 4513 } 4514 4515 private BasicBlock rectifyStateWithErrorHandler(boolean linkToExitIfUncaught) { 4516 TypeReference et = TypeReference.JavaLangError; 4517 return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught); 4518 } 4519 4520 // If exactly 1 catch block is guarenteed to catch the exception, 4521 // then we return it. 4522 // Returning null means that no such block was found. 4523 private BasicBlock rectifyStateWithExceptionHandler(TypeReference exceptionType, 4524 boolean linkToExitIfUncaught) { 4525 currentBBLE.block.setCanThrowExceptions(); 4526 int catchTargets = 0; 4527 if (DBG_EX) db("\tchecking exceptions of " + currentBBLE.block); 4528 if (currentBBLE.handlers != null) { 4529 for (HandlerBlockLE xbble : currentBBLE.handlers) { 4530 if (DBG_EX) db("\texception block " + xbble.entryBlock); 4531 byte mustCatch = xbble.mustCatchException(exceptionType); 4532 if (mustCatch != NO || xbble.mayCatchException(exceptionType) != NO) { 4533 if (DBG_EX) { 4534 db("PEI of type " + exceptionType + " could be caught by " + xbble + " rectifying locals"); 4535 } 4536 catchTargets++; 4537 blocks.rectifyLocals(_localState, xbble); 4538 currentBBLE.block.insertOut(xbble.entryBlock); 4539 if (DBG_CFG || DBG_SELECTED) { 4540 db("Added CFG edge from " + currentBBLE.block + " to " + xbble.entryBlock); 4541 } 4542 } 4543 if (mustCatch == YES) { 4544 if (DBG_EX) { 4545 db("\t" + xbble + " will defintely catch exceptions of type " + exceptionType); 4546 } 4547 if (DBG_EX && catchTargets == 1) { 4548 db("\t and it is the only target"); 4549 } 4550 return (catchTargets == 1) ? xbble.entryBlock : null; 4551 } 4552 } 4553 } 4554 // Now, consider the enclosing exception context. 4555 // NOTE: Because the locals of the current method can't 4556 // possibly matter to the locals of the enclosing method, it is 4557 // sufficient to add a CFG edge (no need to rectify locals). 4558 // It is the responsibility of the BC2IR object generating the 4559 // caller method to ensure that the exposed handler blocks are 4560 // generated if they are reachable from a callee. 4561 // See maybeInlineMethod. 4562 if (gc.getEnclosingHandlers() != null) { 4563 for (Enumeration<BasicBlock> e = gc.getEnclosingHandlers().enumerator(); e.hasMoreElements();) { 4564 ExceptionHandlerBasicBlock xbb = (ExceptionHandlerBasicBlock) e.nextElement(); 4565 byte mustCatch = xbb.mustCatchException(exceptionType); 4566 if (mustCatch != NO || xbb.mayCatchException(exceptionType) != NO) { 4567 if (DBG_EX) { 4568 db("PEI of type " + exceptionType + " could be caught by enclosing handler " + xbb); 4569 } 4570 catchTargets++; 4571 currentBBLE.block.insertOut(xbb); 4572 if (DBG_CFG || DBG_SELECTED) { 4573 db("Added CFG edge from " + currentBBLE.block + " to " + xbb); 4574 } 4575 } 4576 if (mustCatch == YES) { 4577 if (DBG_EX) { 4578 db("\t" + xbb + " will defintely catch exceptions of type " + exceptionType); 4579 } 4580 if (DBG_EX && catchTargets == 1) { 4581 db("\t and it is the only target"); 4582 } 4583 return (catchTargets == 1) ? xbb : null; 4584 } 4585 } 4586 } 4587 // If we get to here, then we didn't find a handler block that 4588 // is guarenteed to catch the exception. Therefore deal with the 4589 // possibly uncaught exception. 4590 currentBBLE.block.setMayThrowUncaughtException(); 4591 if (linkToExitIfUncaught) { 4592 if (DBG_EX) { 4593 db("added explicit edge from " + currentBBLE + " to outermost exit"); 4594 } 4595 currentBBLE.block.insertOut(gc.getExit()); 4596 if (DBG_CFG || DBG_SELECTED) { 4597 db("Added CFG edge from " + currentBBLE.block + " to exit"); 4598 } 4599 } 4600 return null; 4601 } 4602 4603 /* 4604 * Very similar to the above, but since we aren't told what might be thrown, 4605 * we are forced to connect to every in scope handler and can't 4606 * identify a definite target. 4607 * 4608 */ 4609 private void rectifyStateWithExceptionHandlers(boolean linkToExitIfUncaught) { 4610 currentBBLE.block.setCanThrowExceptions(); 4611 currentBBLE.block.setMayThrowUncaughtException(); 4612 if (linkToExitIfUncaught) { 4613 if (DBG_EX) { 4614 db("PEI of unknown type caused edge from " + currentBBLE + " to outermost exit"); 4615 } 4616 currentBBLE.block.insertOut(gc.getExit()); 4617 if (DBG_CFG || DBG_SELECTED) { 4618 db("Added CFG edge from " + currentBBLE.block + " to exit"); 4619 } 4620 } 4621 if (currentBBLE.handlers != null) { 4622 for (HandlerBlockLE xbble : currentBBLE.handlers) { 4623 if (DBG_EX) { 4624 db("PEI of unknown type could be caught by " + xbble + " rectifying locals"); 4625 } 4626 blocks.rectifyLocals(_localState, xbble); 4627 currentBBLE.block.insertOut(xbble.entryBlock); 4628 if (DBG_CFG || DBG_SELECTED) { 4629 db("Added CFG edge from " + currentBBLE.block + " to " + xbble.entryBlock); 4630 } 4631 } 4632 } 4633 // Now, consider the enclosing exception context; ditto NOTE above. 4634 if (gc.getEnclosingHandlers() != null) { 4635 for (Enumeration<BasicBlock> e = gc.getEnclosingHandlers().enumerator(); e.hasMoreElements();) { 4636 ExceptionHandlerBasicBlock xbb = (ExceptionHandlerBasicBlock) e.nextElement(); 4637 if (DBG_EX) { 4638 db("PEI of unknown type could be caught by enclosing handler " + xbb); 4639 } 4640 currentBBLE.block.insertOut(xbb); 4641 if (DBG_CFG || DBG_SELECTED) { 4642 db("Added CFG edge from " + currentBBLE.block + " to " + xbb); 4643 } 4644 } 4645 } 4646 } 4647 4648 ////////// 4649 // INLINING support 4650 ////////// 4651 /** 4652 * Should we inline a call site? 4653 * 4654 * @param call the call instruction being considered for inlining 4655 * @param isExtant is the receiver of a virtual method an extant object? 4656 * @param realBCI the real bytecode index of the call instruction, not adjusted because of OSR 4657 * @return the inline decision (which cannot be {@code null}) 4658 */ 4659 private InlineDecision shouldInline(Instruction call, boolean isExtant, int realBCI) { 4660 if (Call.getMethod(call).getTarget() == null) { 4661 return InlineDecision.NO("Target method is null"); 4662 } 4663 CompilationState state = new CompilationState(call, isExtant, gc.getOptions(), gc.getOriginalCompiledMethod(), realBCI); 4664 InlineDecision d = gc.getInlinePlan().shouldInline(state); 4665 return d; 4666 } 4667 4668 /** 4669 * Attempt to inline a method. This may fail. 4670 * 4671 * @param inlDec the inline decision for this call site 4672 * @param callSite the call instruction we are attempting to inline 4673 * @return {@code true} if inlining succeeded, {@code false} otherwise 4674 */ 4675 private boolean maybeInlineMethod(InlineDecision inlDec, Instruction callSite) { 4676 if (inlDec.isNO()) { 4677 return false; 4678 } 4679 4680 // Insert OsrBarrier point before the callsite which is going to be 4681 // inlined. The callee can find this barrier via its generation context. 4682 4683 // verify it 4684 if (this.osrGuardedInline) { 4685 if (VM.VerifyAssertions) opt_assert(lastOsrBarrier != null); 4686 gc.saveOSRBarrierForInst(lastOsrBarrier, callSite); 4687 } 4688 4689 // Execute the inline decision. 4690 // NOTE: It is tempting to wrap the call to Inliner.execute in 4691 // a try/catch block that suppresses MagicNotImplemented failures 4692 // by "backing out" the attempted inlining of a method that contained 4693 // an unimplemented magic. Unfortunately, this is somewhat hard to do 4694 // cleanly, since exceptional control flow can inject control flow graph 4695 // edges from inlinedContext to blocks in the enclosing caller CFG. 4696 // These are not easy to find and remove because inlinedContext is not 4697 // well-formed (the exception was thrown while generating the IR, in 4698 // particular before calling finalPass, therefore the inlined CFG 4699 // is not formed and finding all of its member blocks is somewhat awkward). 4700 // We could write code to deal with this, but since in practice the 4701 // opt compiler implements all but a few fringe magics, it is just fine 4702 // to completely give up rather than take heroic measures here. 4703 // In a few cases we do care about, we use NoInlinePragma to 4704 // prevent the opt compiler from inlining a method that contains an 4705 // unimplemented magic. 4706 GenerationContext inlinedContext = 4707 Inliner.execute(inlDec, gc, currentBBLE.block.exceptionHandlers, callSite); 4708 4709 inlinedSomething = true; 4710 // TODO: We're currently not keeping track if any of the 4711 // enclosing exception handlers are actually reachable from 4712 // this inlined callee. 4713 // Therefore we simply force all of them to be generated wrt 4714 // the state of the local variables in currentBBLE. 4715 // This can result in generating unreachable handlers 4716 // (if no PEI can reach them) and in generating suboptimal 4717 // catch blocks (by merging in currentBBLE's local state 4718 // into catch blocks that can't actually be reached from the inlined CFG). 4719 // I strongly suspect it's not worth worrying about this..... 4720 // dead code elimination should zap the unreachable handlers, 4721 // and we shouldn't care too much about the 4722 // optimization possibilities lost by the extra local rectification. 4723 // Especially since the odds of currentBBLE actually having 4724 // unreachable handler blocks is darn close to zero. --dave 9/21/99. 4725 // NOTE: No need to add CFG edges (they were added as needed 4726 // during generation of the callee) 4727 if (currentBBLE.handlers != null) { 4728 for (HandlerBlockLE handler : currentBBLE.handlers) { 4729 blocks.rectifyLocals(_localState, handler); 4730 } 4731 } 4732 if (inlinedContext.getEpilogue() != null) { 4733 // Wrap a synthetic BBLE around GenerationContext.epilogue and 4734 // pass it as from to getOrCreateBlock. 4735 // This causes any compensation code inserted by getOrCreateBlock 4736 // into the epilogue of the inlined method (see inlineTest7) 4737 BasicBlockLE epilogueBBLE = new BasicBlockLE(0); 4738 epilogueBBLE.block = inlinedContext.getEpilogue(); 4739 if (inlinedContext.getResult() != null) { 4740 // If the call has a result, _callHelper allocated a new 4741 // temp for it and pushed it onto the expression stack. 4742 // But, since we successfully inlined the call and 4743 // inlinedContext.epilogue != null, 4744 // we can use inlinedContext.result to obtain better 4745 // downstream information about the inlined callee's return value. 4746 // Therefore we'll pop the old callSite.result off the stack 4747 // and push result instead. 4748 // NOTE: It's critical that we pop callSite.result 4749 // _before_ we copy the stack state into epilogueBBLE! 4750 // Otherwise we'll end up with bogus code in the inlined 4751 // method's prologue due to stack saving!!!! 4752 TypeReference resultType = Call.getResult(callSite).getType(); 4753 pop(resultType); // throw away callSite.result 4754 } 4755 blocks.rectifyStacks(currentBBLE.block, stack, epilogueBBLE); 4756 if (inlinedContext.getResult() != null) { 4757 TypeReference resultType = Call.getResult(callSite).getType(); 4758 push(inlinedContext.getResult(), resultType); 4759 } 4760 epilogueBBLE.copyIntoLocalState(_localState); 4761 BasicBlockLE afterBBLE = blocks.getOrCreateBlock(bcodes.index(), epilogueBBLE, stack, _localState); 4762 // Create the InliningBlockLE and initialize fallThrough links. 4763 InliningBlockLE inlinedCallee = new InliningBlockLE(inlinedContext, epilogueBBLE); 4764 currentBBLE.fallThrough = inlinedCallee; 4765 currentBBLE.block.insertOut(inlinedCallee.gc.getCfg().firstInCodeOrder()); 4766 epilogueBBLE.fallThrough = afterBBLE; 4767 epilogueBBLE.block.insertOut(epilogueBBLE.fallThrough.block); 4768 } else { 4769 // All exits from the callee were via throws. 4770 // Therefore the next basic block is unreachable (unless 4771 // there is a branch to it from somewhere else in the current method, 4772 // which will naturally be handled when we generate the branch). 4773 InliningBlockLE inlinedCallee = new InliningBlockLE(inlinedContext, null); 4774 currentBBLE.fallThrough = inlinedCallee; 4775 currentBBLE.block.insertOut(inlinedCallee.gc.getCfg().firstInCodeOrder()); 4776 } 4777 endOfBasicBlock = true; 4778 return true; 4779 } 4780 4781 /* create an OSR Barrier instruction at the current position. 4782 */ 4783 private Instruction _createOsrBarrier() { 4784 ArrayList<Operand> livevars = new ArrayList<Operand>(); 4785 4786 /* for local variables, we have to use helper to make a register. */ 4787 /* ltypes and stypes should be the full length 4788 * WARNING: what's the order of DUMMY and LONG? 4789 */ 4790 int localnum = _localState.length; 4791 byte[] ltypes = new byte[localnum]; 4792 4793 int num_llocals = 0; 4794 for (int i = 0, n = _localState.length; i < n; i++) { 4795 Operand op = _localState[i]; 4796 4797 if ((op != null) && (op != DUMMY)) { 4798 livevars.add(_loadLocalForOSR(op)); 4799 num_llocals++; 4800 4801 if (op instanceof ReturnAddressOperand) { 4802 ltypes[i] = ReturnAddressTypeCode; 4803 } else { 4804 TypeReference typ = op.getType(); 4805 if (typ.isWordLikeType() || (typ == TypeReference.NULL_TYPE)) { 4806 ltypes[i] = WordTypeCode; 4807 } else { 4808 ltypes[i] = typ.getName().parseForTypeCode(); 4809 } 4810 } 4811 4812 } else { 4813 ltypes[i] = VoidTypeCode; 4814 } 4815 } 4816 int stacknum = stack.getSize(); 4817 byte[] stypes = new byte[stacknum]; 4818 4819 /* the variable on stack can be used directly ? */ 4820 int num_lstacks = 0; 4821 for (int i = 0, n = stack.getSize(); i < n; i++) { 4822 Operand op = stack.getFromBottom(i); 4823 4824 if ((op != null) && (op != DUMMY)) { 4825 4826 if (op.isRegister()) { 4827 livevars.add(op.asRegister().copyU2U()); 4828 } else { 4829 livevars.add(op.copy()); 4830 } 4831 4832 num_lstacks++; 4833 4834 if (op instanceof ReturnAddressOperand) { 4835 stypes[i] = ReturnAddressTypeCode; 4836 } else { 4837 TypeReference typ = op.getType(); 4838 if (typ.isWordLikeType() || (typ == TypeReference.NULL_TYPE)) { 4839 stypes[i] = WordTypeCode; 4840 } else { 4841 /* for stack operand, reverse the order for long and double */ 4842 byte tcode = typ.getName().parseForTypeCode(); 4843 if ((tcode == LongTypeCode) || (tcode == DoubleTypeCode)) { 4844 stypes[i - 1] = tcode; 4845 stypes[i] = VoidTypeCode; 4846 } else { 4847 stypes[i] = tcode; 4848 } 4849 } 4850 } 4851 4852 } else { 4853 stypes[i] = VoidTypeCode; 4854 } 4855 } 4856 4857 Instruction barrier = OsrBarrier.create(OSR_BARRIER, null, // temporarily 4858 num_llocals + num_lstacks); 4859 4860 for (int i = 0, n = livevars.size(); i < n; i++) { 4861 Operand op = livevars.get(i); 4862 if (op instanceof ReturnAddressOperand) { 4863 int tgtpc = ((ReturnAddressOperand) op).retIndex - gc.getMethod().getOsrPrologueLength(); 4864 op = new IntConstantOperand(tgtpc); 4865 } else if (op instanceof LongConstantOperand) { 4866 op = _prepareLongConstant(op); 4867 } else if (op instanceof DoubleConstantOperand) { 4868 op = _prepareDoubleConstant(op); 4869 } 4870 4871 if (VM.VerifyAssertions) opt_assert(op != null); 4872 4873 OsrBarrier.setElement(barrier, i, op); 4874 } 4875 4876 // patch type info operand 4877 OsrTypeInfoOperand typeinfo = new OsrTypeInfoOperand(ltypes, stypes); 4878 4879 OsrBarrier.setTypeInfo(barrier, typeinfo); 4880 4881 /* if the current method is for specialization, the bcIndex 4882 * has to be adjusted at "OsrPointConstructor". 4883 */ 4884 barrier.position = gc.getInlineSequence(); 4885 barrier.bcIndex = instrIndex; 4886 4887 return barrier; 4888 } 4889 4890 /** 4891 * special process for long/double constants 4892 * @param op a long constant 4893 * @return a new operand 4894 */ 4895 private Operand _prepareLongConstant(Operand op) { 4896 /* for long and double constants, always move them to a register, 4897 * therefor, BURS will split it in two registers. 4898 */ 4899 RegisterOperand t = gc.getTemps().makeTemp(op.getType()); 4900 appendInstruction(Move.create(LONG_MOVE, t, op)); 4901 4902 return t.copyD2U(); 4903 } 4904 4905 /** 4906 * special process for long/double constants 4907 * @param op a double constant 4908 * @return a new operand 4909 */ 4910 private Operand _prepareDoubleConstant(Operand op) { 4911 /* for long and double constants, always move them to a register, 4912 * therefor, BURS will split it in two registers. 4913 */ 4914 RegisterOperand t = gc.getTemps().makeTemp(op.getType()); 4915 appendInstruction(Move.create(DOUBLE_MOVE, t, op)); 4916 4917 return t.copyD2U(); 4918 } 4919 4920 /** 4921 * make a temporary register, and create a move instruction 4922 * @param op the local variable. 4923 * @return operand marked as use. 4924 */ 4925 private Operand _loadLocalForOSR(Operand op) { 4926 4927 /* return address is processed specially */ 4928 if (op instanceof ReturnAddressOperand) { 4929 return op; 4930 } 4931 4932 RegisterOperand t = gc.getTemps().makeTemp(op.getType()); 4933 4934 byte tcode = op.getType().getName().parseForTypeCode(); 4935 4936 Operator operator = null; 4937 4938 switch (tcode) { 4939 case ClassTypeCode: 4940 case ArrayTypeCode: 4941 operator = REF_MOVE; 4942 break; 4943 case BooleanTypeCode: 4944 case ByteTypeCode: 4945 case ShortTypeCode: 4946 case CharTypeCode: 4947 case IntTypeCode: 4948 operator = INT_MOVE; 4949 break; 4950 case LongTypeCode: 4951 operator = LONG_MOVE; 4952 break; 4953 case FloatTypeCode: 4954 operator = FLOAT_MOVE; 4955 break; 4956 case DoubleTypeCode: 4957 operator = DOUBLE_MOVE; 4958 break; 4959 case VoidTypeCode: 4960 return null; 4961 } 4962 4963 appendInstruction(Move.create(operator, t, op.copy())); 4964 return t.copyD2U(); 4965 } 4966 4967 /** 4968 * Creates an OSR point instruction with its dependent OsrBarrier 4969 * which provides type and variable information. 4970 * The OsrPoint instruction is going to be refilled immediately 4971 * after BC2IR, before any other optimizations. 4972 * 4973 * @param barrier the OSR barrier instruction 4974 * @param gc context that has information about OSR 4975 * @return the osr point instruction 4976 */ 4977 public static Instruction _osrHelper(Instruction barrier, GenerationContext gc) { 4978 Instruction inst = OsrPoint.create(YIELDPOINT_OSR, null, // currently unknown 4979 0); // currently unknown 4980 gc.saveOSRBarrierForInst(barrier, inst); 4981 return inst; 4982 } 4983 4984 //// LOCAL STATE. 4985 /** 4986 * Gets the specified local variable. This can return an RegisterOperand 4987 * which refers to the given local, or some other kind of operand (if the 4988 * local variable is assumed to contain a particular value.) 4989 * 4990 * @param i local variable number 4991 * @return a copy of the local variable 4992 */ 4993 private Operand getLocal(int i) { 4994 Operand local = _localState[i]; 4995 if (DBG_LOCAL || DBG_SELECTED) db("getting local " + i + " for use: " + local); 4996 return local.copy(); 4997 } 4998 4999 /** 5000 * Gets the specified local variable (long, double). This can return an 5001 * RegisterOperand which refers to the given local, or some other kind 5002 * of operand (if the local variable is assumed to contain a given value.) 5003 * 5004 * @param i local variable number 5005 * @return a copy of the local variable 5006 */ 5007 private Operand getLocalDual(int i) { 5008 if (VM.VerifyAssertions) opt_assert(_localState[i + 1] == DUMMY); 5009 Operand local = _localState[i]; 5010 if (DBG_LOCAL || DBG_SELECTED) db("getting local " + i + " for use: " + local); 5011 return local.copy(); 5012 } 5013 5014 /** 5015 * Set the specified local variable 5016 * 5017 * @param i local variable number 5018 * @param op Operand to store in the local 5019 */ 5020 private void setLocal(int i, Operand op) { 5021 if (DBG_LOCAL || DBG_SELECTED) db("setting local " + i + " with " + op); 5022 _localState[i] = op; 5023 } 5024 5025 /** 5026 * Set the specified local variable 5027 * 5028 * @param i local variable number 5029 * @param op Operand to store in the local 5030 */ 5031 private void setLocalDual(int i, Operand op) { 5032 if (DBG_LOCAL || DBG_SELECTED) db("setting dual local " + i + " with " + op); 5033 _localState[i] = op; 5034 _localState[i + 1] = DUMMY; 5035 } 5036 5037 /** 5038 * Dummy stack slot 5039 * @see BC2IR#DUMMY 5040 */ 5041 private static final class DummyStackSlot extends Operand { 5042 @Override 5043 public Operand copy() { 5044 return this; 5045 } 5046 5047 @Override 5048 public boolean similar(Operand op) { 5049 return (op instanceof DummyStackSlot); 5050 } 5051 5052 @Override 5053 public String toString() { 5054 return "<DUMMY>"; 5055 } 5056 } 5057}