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