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