001/* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013package org.jikesrvm.compilers.opt.escape; 014 015import static org.jikesrvm.compilers.opt.ir.Operators.*; 016import static org.jikesrvm.compilers.opt.ir.ia32.ArchOperators.PREFETCH_opcode; 017import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBST_opcode; 018import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBTST_opcode; 019import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBT_opcode; 020import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBZL_opcode; 021import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.DCBZ_opcode; 022import static org.jikesrvm.compilers.opt.ir.ppc.ArchOperators.ICBI_opcode; 023 024import java.util.ArrayList; 025import java.util.Enumeration; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.Set; 029 030import org.jikesrvm.VM; 031import org.jikesrvm.classloader.NormalMethod; 032import org.jikesrvm.classloader.RVMMethod; 033import org.jikesrvm.compilers.opt.DefUse; 034import org.jikesrvm.compilers.opt.MagicNotImplementedException; 035import org.jikesrvm.compilers.opt.OptOptions; 036import org.jikesrvm.compilers.opt.OptimizingCompilerException; 037import org.jikesrvm.compilers.opt.Simple; 038import org.jikesrvm.compilers.opt.bc2ir.ConvertBCtoHIR; 039import org.jikesrvm.compilers.opt.driver.CompilationPlan; 040import org.jikesrvm.compilers.opt.driver.CompilerPhase; 041import org.jikesrvm.compilers.opt.driver.OptimizationPlanCompositeElement; 042import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement; 043import org.jikesrvm.compilers.opt.driver.OptimizingCompiler; 044import org.jikesrvm.compilers.opt.ir.AStore; 045import org.jikesrvm.compilers.opt.ir.Call; 046import org.jikesrvm.compilers.opt.ir.IR; 047import org.jikesrvm.compilers.opt.ir.Instruction; 048import org.jikesrvm.compilers.opt.ir.PutField; 049import org.jikesrvm.compilers.opt.ir.PutStatic; 050import org.jikesrvm.compilers.opt.ir.Register; 051import org.jikesrvm.compilers.opt.ir.ResultCarrier; 052import org.jikesrvm.compilers.opt.ir.Return; 053import org.jikesrvm.compilers.opt.ir.Store; 054import org.jikesrvm.compilers.opt.ir.operand.MethodOperand; 055import org.jikesrvm.compilers.opt.ir.operand.Operand; 056import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand; 057 058/** 059 * Simple flow-insensitive intra-procedural escape analysis. Information 060 * about other procedures is only used when examining call instructions. 061 * <p> 062 * NOTE: The analysis is tailored to the optimizations that currently make 063 * use of it and <em>NOT</em> suited for general tasks that rely on escape 064 * analysis. In particular, the analysis may incorrectly classify uses as 065 * thread-local or method-local. This does not cause problems for the implemented 066 * optimizations because those will only be performed when the definition of 067 * the object in question is contained in the method that's being compiled. 068 * <p> 069 * TODO list: 070 * <ul> 071 * <li>This would be more effective if formulated as a data-flow problem, 072 * and solved with iteration.</li> 073 * <li>Implement a more powerful analysis that it suitable for general use and 074 * add suitable references</li> 075 * <li>Write a testsuite that demonstrates the capabilities of the analysis</li> 076 * </ul> 077 * 078 */ 079class SimpleEscape extends CompilerPhase { 080 /** 081 * Return this instance of this phase. This phase contains no 082 * per-compilation instance fields. 083 * @param ir not used 084 * @return this 085 */ 086 @Override 087 public CompilerPhase newExecution(IR ir) { 088 return this; 089 } 090 091 @Override 092 public final boolean shouldPerform(OptOptions options) { 093 return options.ESCAPE_SIMPLE_IPA; 094 } 095 096 @Override 097 public final String getName() { 098 return "Simple Escape Analysis"; 099 } 100 101 @Override 102 public final boolean printingEnabled(OptOptions options, boolean before) { 103 return false; 104 } 105 106 @Override 107 public void perform(IR ir) { 108 SimpleEscape analyzer = new SimpleEscape(); 109 analyzer.simpleEscapeAnalysis(ir); 110 } 111 112 /** 113 * Performs the escape analysis for a method. 114 * 115 * <p> Side effect: updates method summary database to hold 116 * escape analysis result for parameters 117 * 118 * @param ir IR for the target method 119 * @return an object holding the result of the analysis 120 */ 121 public FI_EscapeSummary simpleEscapeAnalysis(IR ir) { 122 final boolean DEBUG = false; 123 if (DEBUG) { 124 VM.sysWrite("ENTER Simple Escape Analysis " + ir.method + "\n"); 125 } 126 if (DEBUG) { 127 ir.printInstructions(); 128 } 129 // create a method summary object for this method 130 RVMMethod m = ir.method; 131 MethodSummary summ = SummaryDatabase.findOrCreateMethodSummary(m); 132 summ.setInProgress(true); 133 FI_EscapeSummary result = new FI_EscapeSummary(); 134 // set up register lists, SSA flags 135 DefUse.computeDU(ir); 136 DefUse.recomputeSSA(ir); 137 // pass through registers, and mark escape information 138 for (Register reg = ir.regpool.getFirstSymbolicRegister(); reg != null; reg = reg.getNext()) { 139 // skip the following types of registers: 140 if (reg.isFloatingPoint()) { 141 continue; 142 } 143 if (reg.isInteger()) { 144 continue; 145 } 146 if (reg.isLong()) { 147 continue; 148 } 149 if (reg.isCondition()) { 150 continue; 151 } 152 if (reg.isValidation()) { 153 continue; 154 } 155 if (reg.isPhysical()) { 156 continue; 157 } 158 if (!reg.isSSA()) { 159 continue; 160 } 161 AnalysisResult escapes = checkAllAppearances(reg, ir); 162 if (escapes.threadLocal) { 163 result.setThreadLocal(reg, true); 164 } 165 if (escapes.methodLocal) { 166 result.setMethodLocal(reg, true); 167 } 168 } 169 // update the method summary database to note whether 170 // parameters may escape 171 int numParam = 0; 172 for (Enumeration<Operand> e = ir.getParameters(); e.hasMoreElements(); numParam++) { 173 Register p = ((RegisterOperand) e.nextElement()).getRegister(); 174 if (result.isThreadLocal(p)) { 175 summ.setParameterMayEscapeThread(numParam, false); 176 } else { 177 summ.setParameterMayEscapeThread(numParam, true); 178 } 179 } 180 181 // update the method summary to note whether the return value 182 // may escape 183 boolean foundEscapingReturn = false; 184 for (Iterator<Operand> itr = iterateReturnValues(ir); itr.hasNext();) { 185 Operand op = itr.next(); 186 if (op == null) { 187 continue; 188 } 189 if (op.isRegister()) { 190 Register r = op.asRegister().getRegister(); 191 if (!result.isThreadLocal(r)) { 192 foundEscapingReturn = true; 193 } 194 } 195 } 196 if (!foundEscapingReturn) { 197 summ.setResultMayEscapeThread(false); 198 } 199 // record that we're done with analysis 200 summ.setInProgress(false); 201 if (DEBUG) { 202 VM.sysWrite("LEAVE Simple Escape Analysis " + ir.method + "\n"); 203 } 204 return result; 205 } 206 207 /** 208 * This member represents the directions to the optimizing compiler to 209 * perform escape analysis on a method, but do <em> not </em> generate 210 * code. 211 */ 212 private static final OptimizationPlanElement escapePlan = initEscapePlan(); 213 214 /** 215 * Checks all appearances of a register, to see if any instruction in 216 * this method causes the object pointed to by the register to escape 217 * this thread and/or method. 218 * 219 * @param reg the register to check 220 * @param ir the governing IR 221 * @return {@code true} if it may escape this thread, 222 * {@code false} otherwise 223 */ 224 private static AnalysisResult checkAllAppearances(Register reg, IR ir) { 225 return new AnalysisResult(!checkIfUseEscapesThread(reg, ir, null), 226 !checkIfUseEscapesMethod(reg, ir, null)); 227 } 228 private static boolean checkIfUseEscapesThread(Register reg, IR ir, Set<Register> visited) { 229 for (RegisterOperand use = reg.useList; use != null; use = use.getNext()) { 230 231 assertThatTypeIsNotNull(ir, use); 232 233 // if the type is primitive, just say it escapes 234 // TODO: handle this more cleanly 235 if (use.getType().isPrimitiveType()) { 236 return true; 237 } 238 if (checkEscapesThread(use, ir, visited)) { 239 return true; 240 } 241 } 242 for (RegisterOperand def = reg.defList; def != null; def = def.getNext()) { 243 244 assertThatTypeIsNotNull(ir, def); 245 246 // if the type is primitive, just say it escapes 247 // TODO: handle this more cleanly 248 if (def.getType() == null || def.getType().isPrimitiveType()) { 249 return true; 250 } 251 if (checkEscapesThread(def, ir, visited)) { 252 return true; 253 } 254 } 255 return false; 256 } 257 private static boolean checkIfUseEscapesMethod(Register reg, IR ir, Set<Register> visited) { 258 for (RegisterOperand use = reg.useList; use != null; use = use.getNext()) { 259 assertThatTypeIsNotNull(ir, use); 260 261 // if the type is primitive, just say it escapes 262 // TODO: handle this more cleanly 263 if (use.getType().isPrimitiveType()) { 264 return true; 265 } 266 if (checkEscapesMethod(use, ir, visited)) { 267 return true; 268 } 269 } 270 for (RegisterOperand def = reg.defList; def != null; def = def.getNext()) { 271 assertThatTypeIsNotNull(ir, def); 272 273 // if the type is primitive, just say it escapes 274 // TODO: handle this more cleanly 275 if (def.getType() == null || def.getType().isPrimitiveType()) { 276 return true; 277 } 278 if (checkEscapesMethod(def, ir, visited)) { 279 return true; 280 } 281 } 282 return false; 283 } 284 285 private static void assertThatTypeIsNotNull(IR ir, RegisterOperand useOrDef) { 286 if (VM.VerifyAssertions && useOrDef.getType() == null) { 287 ir.printInstructions(); 288 String msg = "type of " + useOrDef + " is null"; 289 VM._assert(VM.NOT_REACHED, msg); 290 } 291 } 292 293 /** 294 * Checks a single use, to see if this use may cause the object 295 * referenced to escape from this thread. 296 * 297 * @param use the use to check 298 * @param ir the governing IR 299 * @param visited visited registers 300 * @return {@code true} if it may escape, {@code false} otherwise 301 */ 302 private static boolean checkEscapesThread(RegisterOperand use, IR ir, Set<Register> visited) { 303 Instruction inst = use.instruction; 304 switch (inst.getOpcode()) { 305 case INT_ASTORE_opcode: 306 case LONG_ASTORE_opcode: 307 case FLOAT_ASTORE_opcode: 308 case DOUBLE_ASTORE_opcode: 309 case BYTE_ASTORE_opcode: 310 case SHORT_ASTORE_opcode: 311 case REF_ASTORE_opcode: 312 // as long as we don't store this operand elsewhere, all 313 // is OK 314 Operand value = AStore.getValue(inst); 315 return value == use; 316 case GETFIELD_opcode: 317 case GETSTATIC_opcode: 318 case INT_ALOAD_opcode: 319 case LONG_ALOAD_opcode: 320 case FLOAT_ALOAD_opcode: 321 case DOUBLE_ALOAD_opcode: 322 case BYTE_ALOAD_opcode: 323 case UBYTE_ALOAD_opcode: 324 case BYTE_LOAD_opcode: 325 case UBYTE_LOAD_opcode: 326 case SHORT_ALOAD_opcode: 327 case USHORT_ALOAD_opcode: 328 case SHORT_LOAD_opcode: 329 case USHORT_LOAD_opcode: 330 case REF_ALOAD_opcode: 331 case INT_LOAD_opcode: 332 case LONG_LOAD_opcode: 333 case FLOAT_LOAD_opcode: 334 case DOUBLE_LOAD_opcode: 335 case REF_LOAD_opcode: 336 // all is OK, unless we load this register from memory 337 Operand result = ResultCarrier.getResult(inst); 338 return result == use; 339 case PUTFIELD_opcode: 340 // as long as we don't store this operand elsewhere, all 341 // is OK. TODO: add more smarts. 342 value = PutField.getValue(inst); 343 return value == use; 344 case PUTSTATIC_opcode: 345 // as long as we don't store this operand elsewhere, all 346 // is OK. TODO: add more smarts. 347 value = PutStatic.getValue(inst); 348 return value == use; 349 case BYTE_STORE_opcode: 350 case SHORT_STORE_opcode: 351 case REF_STORE_opcode: 352 case INT_STORE_opcode: 353 case LONG_STORE_opcode: 354 case FLOAT_STORE_opcode: 355 case DOUBLE_STORE_opcode: 356 // as long as we don't store this operand elsewhere, all 357 // is OK. TODO: add more smarts. 358 value = Store.getValue(inst); 359 return value == use; 360 // the following instructions never cause an object to 361 // escape 362 case BOUNDS_CHECK_opcode: 363 case MONITORENTER_opcode: 364 case MONITOREXIT_opcode: 365 case NULL_CHECK_opcode: 366 case ARRAYLENGTH_opcode: 367 case REF_IFCMP_opcode: 368 case INT_IFCMP_opcode: 369 case IG_PATCH_POINT_opcode: 370 case IG_CLASS_TEST_opcode: 371 case IG_METHOD_TEST_opcode: 372 case BOOLEAN_CMP_INT_opcode: 373 case BOOLEAN_CMP_ADDR_opcode: 374 case OBJARRAY_STORE_CHECK_opcode: 375 case OBJARRAY_STORE_CHECK_NOTNULL_opcode: 376 case GET_OBJ_TIB_opcode: 377 case GET_TYPE_FROM_TIB_opcode: 378 case NEW_opcode: 379 case NEWARRAY_opcode: 380 case NEWOBJMULTIARRAY_opcode: 381 case NEW_UNRESOLVED_opcode: 382 case NEWARRAY_UNRESOLVED_opcode: 383 case INSTANCEOF_opcode: 384 case INSTANCEOF_NOTNULL_opcode: 385 case INSTANCEOF_UNRESOLVED_opcode: 386 case MUST_IMPLEMENT_INTERFACE_opcode: 387 case GET_CAUGHT_EXCEPTION_opcode: 388 case IR_PROLOGUE_opcode: 389 return false; 390 case RETURN_opcode: 391 // a return instruction might cause an object to escape, 392 // but not a parameter (whose escape properties are determined 393 // by caller) 394 return !ir.isParameter(use); 395 case CALL_opcode: 396 MethodOperand mop = Call.getMethod(inst); 397 if (mop == null) { 398 return true; 399 } 400 if (!mop.hasPreciseTarget()) { 401 // if we're not sure of the dynamic target, give up 402 return true; 403 } 404 // pure methods don't let object escape 405 if (mop.getTarget().isPure()) { 406 return false; 407 } 408 // Assume non-annotated native methods let object escape 409 if (mop.getTarget().isNative()) { 410 return true; 411 } 412 // try to get a method summary for the called method 413 MethodSummary summ = getMethodSummaryIfAvailable(mop.getTarget(), ir.options); 414 if (summ == null) { 415 // couldn't get one. assume the object escapes 416 return true; 417 } 418 // if use is result of the call... 419 if (use == Call.getResult(inst)) { 420 return summ.resultMayEscapeThread(); 421 } 422 // use is a parameter to the call. Find out which one. 423 int p = getParameterIndex(use, inst); 424 return summ.parameterMayEscapeThread(p); 425 case CHECKCAST_opcode: 426 case CHECKCAST_NOTNULL_opcode: 427 case CHECKCAST_UNRESOLVED_opcode: 428 case REF_MOVE_opcode: { 429 Register copy = ResultCarrier.getResult(inst).getRegister(); 430 if (!copy.isSSA()) { 431 return true; 432 } else { 433 if (visited == null) { 434 visited = new HashSet<Register>(); 435 } 436 visited.add(use.getRegister()); 437 if (visited.contains(copy)) { 438 return false; 439 } else { 440 return checkIfUseEscapesThread(copy, ir, visited); 441 } 442 } 443 } 444 case ATHROW_opcode: 445 case PREPARE_INT_opcode: 446 case PREPARE_ADDR_opcode: 447 case PREPARE_LONG_opcode: 448 case ATTEMPT_LONG_opcode: 449 case ATTEMPT_INT_opcode: 450 case ATTEMPT_ADDR_opcode: 451 case INT_MOVE_opcode: 452 case INT_ADD_opcode: 453 case REF_ADD_opcode: 454 case INT_MUL_opcode: 455 case INT_DIV_opcode: 456 case INT_REM_opcode: 457 case INT_NEG_opcode: 458 case INT_ZERO_CHECK_opcode: 459 case INT_OR_opcode: 460 case INT_AND_opcode: 461 case INT_XOR_opcode: 462 case REF_OR_opcode: 463 case REF_AND_opcode: 464 case REF_XOR_opcode: 465 case INT_SUB_opcode: 466 case REF_SUB_opcode: 467 case INT_SHL_opcode: 468 case INT_SHR_opcode: 469 case INT_USHR_opcode: 470 case SYSCALL_opcode: 471 case REF_SHL_opcode: 472 case REF_SHR_opcode: 473 case REF_USHR_opcode: 474 case SET_CAUGHT_EXCEPTION_opcode: 475 case PHI_opcode: 476 case INT_2LONG_opcode: 477 case REF_COND_MOVE_opcode: 478 case INT_COND_MOVE_opcode: 479 case INT_2ADDRSigExt_opcode: 480 case INT_2ADDRZerExt_opcode: 481 case ADDR_2INT_opcode: 482 case ADDR_2LONG_opcode: 483 case LONG_OR_opcode: 484 case LONG_AND_opcode: 485 case LONG_XOR_opcode: 486 case LONG_SUB_opcode: 487 case LONG_SHL_opcode: 488 case LONG_ADD_opcode: 489 case LONG_SHR_opcode: 490 case LONG_USHR_opcode: 491 case LONG_NEG_opcode: 492 case LONG_MOVE_opcode: 493 case LONG_2ADDR_opcode: 494 // we don't currently analyze these instructions, 495 // so conservatively assume everything escapes 496 // TODO: add more smarts 497 case YIELDPOINT_OSR_opcode: 498 // on stack replacement really a part of the current method, but 499 // we do not know exactly, so be conservative 500 return true; 501 default: 502 if (VM.BuildForPowerPC) { 503 switch (inst.getOpcode()) { 504 case DCBST_opcode: 505 case DCBT_opcode: 506 case DCBTST_opcode: 507 case DCBZ_opcode: 508 case DCBZL_opcode: 509 case ICBI_opcode: 510 return false; 511 } 512 } else { 513 switch (inst.getOpcode()) { 514 case PREFETCH_opcode: 515 return false; 516 } 517 } 518 throw new OptimizingCompilerException("SimpleEscapge: Unexpected " + inst); 519 } 520 } 521 522 /** 523 * Checks a single use, to see if this use may cause the object 524 * referenced to escape from this method. 525 * 526 * @param use the use to check 527 * @param ir the governing IR 528 * @param visited visited registers 529 * @return {@code true} if it may escape, {@code false} otherwise 530 */ 531 private static boolean checkEscapesMethod(RegisterOperand use, IR ir, Set<Register> visited) { 532 Instruction inst = use.instruction; 533 try { 534 switch (inst.getOpcode()) { 535 case INT_ASTORE_opcode: 536 case LONG_ASTORE_opcode: 537 case FLOAT_ASTORE_opcode: 538 case DOUBLE_ASTORE_opcode: 539 case BYTE_ASTORE_opcode: 540 case SHORT_ASTORE_opcode: 541 case REF_ASTORE_opcode: 542 // as long as we don't store this operand elsewhere, all 543 // is OK 544 Operand value = AStore.getValue(inst); 545 return value == use; 546 case GETFIELD_opcode: 547 case GETSTATIC_opcode: 548 case INT_ALOAD_opcode: 549 case LONG_ALOAD_opcode: 550 case FLOAT_ALOAD_opcode: 551 case DOUBLE_ALOAD_opcode: 552 case BYTE_ALOAD_opcode: 553 case UBYTE_ALOAD_opcode: 554 case BYTE_LOAD_opcode: 555 case UBYTE_LOAD_opcode: 556 case USHORT_ALOAD_opcode: 557 case SHORT_ALOAD_opcode: 558 case USHORT_LOAD_opcode: 559 case SHORT_LOAD_opcode: 560 case REF_ALOAD_opcode: 561 case INT_LOAD_opcode: 562 case LONG_LOAD_opcode: 563 case FLOAT_LOAD_opcode: 564 case DOUBLE_LOAD_opcode: 565 case REF_LOAD_opcode: 566 // all is OK, unless we load this register from memory 567 Operand result = ResultCarrier.getResult(inst); 568 return result == use; 569 case PUTFIELD_opcode: 570 // as long as we don't store this operand elsewhere, all 571 // is OK. TODO: add more smarts. 572 value = PutField.getValue(inst); 573 return value == use; 574 case PUTSTATIC_opcode: 575 // as long as we don't store this operand elsewhere, all 576 // is OK. TODO: add more smarts. 577 value = PutStatic.getValue(inst); 578 return value == use; 579 case BYTE_STORE_opcode: 580 case SHORT_STORE_opcode: 581 case REF_STORE_opcode: 582 case INT_STORE_opcode: 583 case LONG_STORE_opcode: 584 case FLOAT_STORE_opcode: 585 case DOUBLE_STORE_opcode: 586 // as long as we don't store this operand elsewhere, all 587 // is OK. TODO: add more smarts. 588 value = Store.getValue(inst); 589 return value == use; 590 // the following instructions never cause an object to 591 // escape 592 case BOUNDS_CHECK_opcode: 593 case MONITORENTER_opcode: 594 case MONITOREXIT_opcode: 595 case NULL_CHECK_opcode: 596 case ARRAYLENGTH_opcode: 597 case REF_IFCMP_opcode: 598 case INT_IFCMP_opcode: 599 case IG_PATCH_POINT_opcode: 600 case IG_CLASS_TEST_opcode: 601 case IG_METHOD_TEST_opcode: 602 case BOOLEAN_CMP_INT_opcode: 603 case BOOLEAN_CMP_ADDR_opcode: 604 case OBJARRAY_STORE_CHECK_opcode: 605 case OBJARRAY_STORE_CHECK_NOTNULL_opcode: 606 case GET_OBJ_TIB_opcode: 607 case GET_TYPE_FROM_TIB_opcode: 608 case NEW_opcode: 609 case NEWARRAY_opcode: 610 case NEWOBJMULTIARRAY_opcode: 611 case NEW_UNRESOLVED_opcode: 612 case NEWARRAY_UNRESOLVED_opcode: 613 case INSTANCEOF_opcode: 614 case INSTANCEOF_NOTNULL_opcode: 615 case INSTANCEOF_UNRESOLVED_opcode: 616 case MUST_IMPLEMENT_INTERFACE_opcode: 617 case GET_CAUGHT_EXCEPTION_opcode: 618 case IR_PROLOGUE_opcode: 619 return false; 620 case RETURN_opcode: 621 // a return instruction causes an object to escape this method. 622 return true; 623 case CALL_opcode: { 624 // A call instruction causes an object to escape this method 625 // except when the target is to Throwable.<init> (which we never inline) 626 MethodOperand mop = Call.getMethod(inst); 627 if (mop != null && mop.hasPreciseTarget()) { 628 RVMMethod target = mop.getTarget(); 629 if (target.hasNoEscapesAnnotation()) { 630 return false; 631 } 632 } 633 return true; 634 } 635 case CHECKCAST_opcode: 636 case CHECKCAST_NOTNULL_opcode: 637 case CHECKCAST_UNRESOLVED_opcode: 638 case REF_MOVE_opcode: { 639 if (visited == null) { 640 visited = new HashSet<Register>(); 641 } 642 Register copy = ResultCarrier.getResult(inst).getRegister(); 643 if (!copy.isSSA()) { 644 return true; 645 } else { 646 visited.add(use.getRegister()); 647 if (visited.contains(copy)) { 648 return false; 649 } else { 650 boolean result2 = checkIfUseEscapesMethod(copy, ir, visited); 651 return result2; 652 } 653 } 654 } 655 case ATHROW_opcode: 656 case PREPARE_INT_opcode: 657 case PREPARE_ADDR_opcode: 658 case ATTEMPT_INT_opcode: 659 case ATTEMPT_ADDR_opcode: 660 case PREPARE_LONG_opcode: 661 case ATTEMPT_LONG_opcode: 662 case INT_MOVE_opcode: 663 case INT_ADD_opcode: 664 case REF_ADD_opcode: 665 case INT_MUL_opcode: 666 case INT_DIV_opcode: 667 case INT_REM_opcode: 668 case INT_NEG_opcode: 669 case INT_ZERO_CHECK_opcode: 670 case INT_OR_opcode: 671 case INT_AND_opcode: 672 case INT_XOR_opcode: 673 case REF_OR_opcode: 674 case REF_AND_opcode: 675 case REF_XOR_opcode: 676 case INT_SUB_opcode: 677 case REF_SUB_opcode: 678 case INT_SHL_opcode: 679 case INT_SHR_opcode: 680 case INT_USHR_opcode: 681 case SYSCALL_opcode: 682 case REF_SHL_opcode: 683 case REF_SHR_opcode: 684 case REF_USHR_opcode: 685 case SET_CAUGHT_EXCEPTION_opcode: 686 case PHI_opcode: 687 case INT_2LONG_opcode: 688 case REF_COND_MOVE_opcode: 689 case INT_COND_MOVE_opcode: 690 case INT_2ADDRSigExt_opcode: 691 case INT_2ADDRZerExt_opcode: 692 case ADDR_2INT_opcode: 693 case ADDR_2LONG_opcode: 694 case LONG_OR_opcode: 695 case LONG_AND_opcode: 696 case LONG_XOR_opcode: 697 case LONG_SUB_opcode: 698 case LONG_SHL_opcode: 699 case LONG_ADD_opcode: 700 case LONG_SHR_opcode: 701 case LONG_USHR_opcode: 702 case LONG_NEG_opcode: 703 case LONG_MOVE_opcode: 704 case LONG_2ADDR_opcode: 705 case YIELDPOINT_OSR_opcode: 706 // we don't currently analyze these instructions, 707 // so conservatively assume everything escapes 708 // TODO: add more smarts 709 return true; 710 default: 711 if (VM.BuildForPowerPC) { 712 switch(inst.getOpcode()) { 713 case DCBST_opcode: 714 case DCBT_opcode: 715 case DCBTST_opcode: 716 case DCBZ_opcode: 717 case DCBZL_opcode: 718 case ICBI_opcode: 719 return false; 720 } 721 } else { 722 switch(inst.getOpcode()) { 723 case PREFETCH_opcode: 724 return false; 725 } 726 } 727 throw new OptimizingCompilerException("SimpleEscapge: Unexpected " + inst); 728 } 729 } catch (Exception e) { 730 OptimizingCompilerException oe = new OptimizingCompilerException("Error handling use (" + use + ") of: " + inst); 731 oe.initCause(e); 732 throw oe; 733 } 734 } 735 736 /** 737 * Which parameter to a call instruction corresponds to op? 738 * <p> PRECONDITION: Call.conforms(s) 739 * 740 * @param op the operand whose parameter is sought 741 * @param s the call instruction 742 * @return the index in the instruction for the parameter that matches 743 * the operand 744 */ 745 private static int getParameterIndex(Operand op, Instruction s) { 746 for (int i = 0; i < Call.getNumberOfParams(s); i++) { 747 Operand p = Call.getParam(s, i); 748 if (p == op) { 749 return i; 750 } 751 } 752 throw new OptimizingCompilerException("Parameter not found" + op + s); 753 } 754 755 /** 756 * Returns a method summary if present. 757 * <p> 758 * In the special case of enabled eager method summary computation, 759 * this method will perform escape analysis for the requested method, 760 * which will create the method summary as a side effect. 761 * 762 * @param m the method whose summary is sought 763 * @param options options to determine whether to create a summary 764 * if it does not exist 765 * @return a method summary or {@code null}. 766 */ 767 private static MethodSummary getMethodSummaryIfAvailable(RVMMethod m, OptOptions options) { 768 MethodSummary summ = SummaryDatabase.findMethodSummary(m); 769 if (summ == null) { 770 if (options.ESCAPE_SIMPLE_IPA) { 771 performSimpleEscapeAnalysis(m, options); 772 summ = SummaryDatabase.findMethodSummary(m); 773 } 774 return summ; 775 } else { 776 return summ; 777 } 778 } 779 780 private static void performSimpleEscapeAnalysis(RVMMethod m, OptOptions options) { 781 if (!options.ESCAPE_SIMPLE_IPA) { 782 return; 783 } 784 // do not perform for unloaded methods 785 MethodSummary summ = SummaryDatabase.findMethodSummary(m); 786 if (summ != null) { 787 // do not attempt to perform escape analysis recursively 788 if (summ.inProgress()) { 789 return; 790 } 791 } 792 CompilationPlan plan = new CompilationPlan((NormalMethod) m, escapePlan, null, options); 793 plan.analyzeOnly = true; 794 try { 795 OptimizingCompiler.compile(plan); 796 } catch (MagicNotImplementedException e) { 797 summ.setInProgress(false); // summary stays at bottom 798 } 799 } 800 801 private static OptimizationPlanElement initEscapePlan() { 802 return OptimizationPlanCompositeElement.compose("Escape Analysis", 803 new Object[]{new ConvertBCtoHIR(), 804 new Simple(1, true, true, false, false), 805 new SimpleEscape()}); 806 } 807 808 /** 809 * TODO: Move this utility elsewhere 810 * 811 * @param ir the IR to search for the return values 812 * @return an iterator over the operands that serve as return values 813 * in an IR 814 */ 815 private static Iterator<Operand> iterateReturnValues(IR ir) { 816 ArrayList<Operand> returnValues = new ArrayList<Operand>(); 817 for (Enumeration<Instruction> e = ir.forwardInstrEnumerator(); e.hasMoreElements();) { 818 Instruction s = e.nextElement(); 819 if (Return.conforms(s)) { 820 returnValues.add(Return.getVal(s)); 821 } 822 } 823 return returnValues.iterator(); 824 } 825 826 /** 827 * Utility class used to hold the result of the escape analysis. 828 */ 829 private static final class AnalysisResult { 830 /** 831 * Was the result "the register must point to thread-local objects"? 832 */ 833 final boolean threadLocal; 834 /** 835 * Was the result "the register must point to method-local objects"? 836 */ 837 final boolean methodLocal; 838 839 AnalysisResult(boolean tl, boolean ml) { 840 threadLocal = tl; 841 methodLocal = ml; 842 } 843 } 844}