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}