synchronized(VM_Class.OptCLDepManager) {
synchronized(VM_Class.classLoadListener) {
  public OPT_InlineDecision shouldInline (final OPT_CompilationState state) {    final OPT_Options opts = state.getOptions();    final boolean verbose = opts.PRINT_DETAILED_INLINE_REPORT;    if (!opts.INLINE) {      return OPT_InlineDecision.NO("inlining not enabled");    }    final VM_Method staticCallee = state.obtainTarget();    final VM_NormalMethod rootMethod = state.getRootMethod();    final VM_Method caller = state.getMethod();    final int bcIndex = state.getBytecodeIndex();    if (verbose) VM.sysWriteln("Begin inline decision for "+"<"+caller+","+bcIndex+","+staticCallee+">");        // Stage 1: At all optimization levels we should attempt to inline    //          trivial methods. Even if the inline code is never executed,    //          inlining a trivial method is a no cost operation as the impact    //          on code size should be negligible and compile time usually is    //          reduced since we expect to eliminate the call instruction (or    //          at worse replace one call instruction with another one).    if (!state.isInvokeInterface()) {      if (staticCallee.isNative()) {        if (verbose) VM.sysWriteln("\tNO: native method\n");        return OPT_InlineDecision.NO("native method");      }      if (hasNoInlinePragma(staticCallee, state)) {        if (verbose) VM.sysWriteln("\tNO: pragmaNoInline\n");        return OPT_InlineDecision.NO("pragmaNoInline");      }      if (!staticCallee.isAbstract()) {        int inlinedSizeEstimate = inlinedSizeEstimate((VM_NormalMethod)staticCallee, state);        boolean guardless = state.getHasPreciseTarget() || !needsGuard(staticCallee);        if (inlinedSizeEstimate < opts.IC_MAX_ALWAYS_INLINE_TARGET_SIZE &&             guardless &&            !state.getSequence().containsMethod(staticCallee)) {          if (verbose) VM.sysWriteln("\tYES: trivial guardless inline\n");          return OPT_InlineDecision.YES(staticCallee, "trivial inline");        }      }    }    if (opts.getOptLevel() == 0) {      // at opt level 0, trivial unguarded inlines are the only kind we consider      if (verbose) VM.sysWriteln("\tNO: only do trivial inlines at O0\n");      return OPT_InlineDecision.NO("Only do trivial inlines at O0");    }    if (rootMethod.inlinedSizeEstimate() > opts.IC_MASSIVE_METHOD_SIZE) {      // In massive methods, we do not do any additional inlining to      // avoid completely blowing out compile time by making a bad situation worse      if (verbose) VM.sysWriteln("\tNO: only do trivial inlines into massive methods\n");      return OPT_InlineDecision.NO("Root method is massive; no non-trivial inlines");    }    // Stage 2: Determine based on profile data and static information    //          what are the possible targets of this call.    //    VM_WeightedCallTargets targets = null;    boolean purelyStatic = true;    if (VM_Controller.dcg != null && VM_Controller.options.ADAPTIVE_INLINING) {      targets = VM_Controller.dcg.getCallTargets(caller, bcIndex);      if (targets != null) {        if (verbose) VM.sysWriteln("\tFound profile data");        purelyStatic = false;        if (state.getHasPreciseTarget()) {          // static analysis tells us that there is only one possible target.          // Filter the profile information accordingly.          targets = targets.filter(staticCallee);          if (verbose) VM.sysWriteln("\tFiltered to match precise target");          if (targets == null) {            if (verbose) VM.sysWriteln("\tNow no profile data...");            // After filtering, no matching profile data, fall back to            // static information to avoid degradations            targets = VM_WeightedCallTargets.create(staticCallee, 0);            purelyStatic = true;          }        }      }    }    // Critical section: must prevent class hierarchy from changing while    // we are inspecting it to determine how/whether to do the inline guard.    synchronized(VM_Class.OptCLDepManager) {      boolean guardOverrideOnStaticCallee = false;      if (targets == null) {        if (verbose) VM.sysWriteln("\tNo profile data");        // No profile information.        // Fake up "profile data" based on static information to        // be able to share all the decision making logic.        if (state.isInvokeInterface()) {          if (opts.GUARDED_INLINE_INTERFACE) {            VM_Method singleImpl = OPT_InterfaceHierarchy.getUniqueImplementation(staticCallee);            if (singleImpl != null && hasBody(singleImpl)) {              if (verbose) VM.sysWriteln("\tFound a single implementation "+singleImpl+" of an interface method "+staticCallee);              targets = VM_WeightedCallTargets.create(singleImpl, 0);              guardOverrideOnStaticCallee = true;            }          }        } else {          // invokestatic, invokevirtual, invokespecial          if (staticCallee.isAbstract()) {            // look for single non-abstract implementation of the abstract method            VM_Class klass = staticCallee.getDeclaringClass();            while (true) {              VM_Class[] subClasses = klass.getSubClasses();              if (subClasses.length != 1) break; // multiple subclasses => multiple targets              VM_Method singleImpl = subClasses[0].findDeclaredMethod(staticCallee.getName(),                                                                      staticCallee.getDescriptor());              if (singleImpl != null && !singleImpl.isAbstract()) {                // found something                if (verbose) VM.sysWriteln("\tsingle impl of abstract method");                targets = VM_WeightedCallTargets.create(singleImpl, 0);                guardOverrideOnStaticCallee = true;                break;              }              klass = subClasses[0]; // keep crawling down the hierarchy            }          } else {            targets = VM_WeightedCallTargets.create(staticCallee, 0);          }        }      }            // At this point targets is either null, or accurately represents what we      // think are the likely target(s) of the call site.      // This information may be either derived from profile information or      // from static heuristics. To the first approximation, we don't care which.      // If there is a precise target, then targets contains exactly that target method.      if (targets == null) return OPT_InlineDecision.NO("No potential targets identified");            // Stage 3: We have one or more targets.  Determine what if anything should be done with them.      final ArrayList<VM_Method> methodsToInline = new ArrayList<VM_Method>();       final ArrayList<Boolean> methodsNeedGuard = new ArrayList<Boolean>();      final double callSiteWeight = targets.totalWeight();      final boolean goosc = guardOverrideOnStaticCallee; // real closures anyone?      final boolean ps = purelyStatic;                   // real closures anyone?      targets.visitTargets(new VM_WeightedCallTargets.Visitor() {          public void visit(VM_Method callee, double weight) {            if (hasBody(callee)) {              if (verbose) {                VM.sysWriteln("\tEvaluating target "+callee+" with "+weight+                              " samples ("+(100*VM_AdaptiveInlining.adjustedWeight(weight))+"%)");              }              // Don't inline recursively and respect no inline pragmas              OPT_InlineSequence seq = state.getSequence();              if (seq.containsMethod(callee)) {                if (verbose) VM.sysWriteln("\t\tReject: recursive");                return;              }              if (hasNoInlinePragma(callee, state)) {                if (verbose) VM.sysWriteln("\t\tReject: noinline pragma");                return;              }              // more or less figure out the guard situation early -- impacts size estimate.              boolean needsGuard = !state.getHasPreciseTarget() && (staticCallee != callee || needsGuard(staticCallee));              if (needsGuard && isForbiddenSpeculation(state.getRootMethod(), callee)) {                if (verbose) VM.sysWriteln("\t\tReject: forbidden speculation");                return;              }              boolean currentlyFinal =                (goosc || (staticCallee == callee)) && isCurrentlyFinal(callee,                                                                        !opts.guardWithClassTest());              boolean preEx = needsGuard && state.getIsExtant() && opts.PREEX_INLINE && currentlyFinal;              if (needsGuard && !preEx) {                if (!opts.GUARDED_INLINE) {                  if (verbose) VM.sysWriteln("\t\tReject: guarded inlining disabled");                  return;                }                if (!currentlyFinal && ps) {                  if (verbose) VM.sysWriteln("\t\tReject: multiple targets and no profile data");                  return;                }              }                            // Estimate cost of performing this inlining action.              // Includes cost of guard & off-branch call if they are going to be generated.              boolean decideYes = false;              if (hasInlinePragma(callee, state)) {                if (verbose) VM.sysWriteln("\t\tSelect: pragma inline");                decideYes = true;              } else {                // Preserve previous inlining decisions                // Not the best thing in the world due to phase shifts, but                // it does buy some degree of stability. So, it is probably the lesser                // of two evils.                VM_CompiledMethod prev = state.getRootMethod().getCurrentCompiledMethod();                if (prev != null && prev.getCompilerType() == VM_CompiledMethod.OPT) {                  if (((VM_OptCompiledMethod)prev).getMCMap().hasInlinedEdge(caller, bcIndex, callee)) {                    if (verbose) VM.sysWriteln("\t\tSelect: Previously inlined");                    decideYes = true;                  }                }                if (!decideYes) {                  int inlinedSizeEstimate = inlinedSizeEstimate((VM_NormalMethod)callee, state);                  int cost = inliningActionCost(inlinedSizeEstimate, needsGuard, preEx, opts);                  int maxCost = opts.IC_MAX_TARGET_SIZE;                  if (callSiteWeight > VM_Controller.options.AI_SEED_MULTIPLIER) {                    // real profile data with enough samples for us to trust it.                    // Use weight and shape of call site distrubution to compute                    // a higher maxCost.                    double fractionOfSample = weight/callSiteWeight;                    if (needsGuard && fractionOfSample < opts.AI_MIN_CALLSITE_FRACTION) {                      // This call accounts for less than AI_MIN_CALLSITE_FRACTION                      // of the profiled targets at this call site.                      // It is highly unlikely to be profitable to inline it.                      if (verbose) VM.sysWriteln("\t\tReject: less than AI_MIN_CALLSITE_FRACTION of distribution");                      maxCost = 0;                    } else {                      if (cost > maxCost) {                        // adjust up based on weight of callsite                        double adjustedWeight = VM_AdaptiveInlining.adjustedWeight(weight);                        if (adjustedWeight > VM_Controller.options.AI_CONTROL_POINT) {                          maxCost = opts.AI_MAX_TARGET_SIZE;                        } else {                          int range = opts.AI_MAX_TARGET_SIZE - opts.IC_MAX_TARGET_SIZE;                          double slope = ((double)range) / VM_Controller.options.AI_CONTROL_POINT;                          int sizeAdj = (int) (slope * adjustedWeight);                          maxCost += sizeAdj;                        }                      }                    }                  }                  // Somewhat bogus, but if we get really deeply inlined we start backing off.                  int curDepth = state.getInlineDepth();                  if (curDepth > opts.IC_MAX_INLINE_DEPTH) {                    maxCost /= (curDepth - opts.IC_MAX_INLINE_DEPTH + 1);                  }                                    decideYes = cost <= maxCost;                  if (verbose) {                    if (decideYes) {                      VM.sysWriteln("\t\tAccept: cost of "+cost+" was below threshold "+maxCost);                    } else {                      VM.sysWriteln("\t\tReject: cost of "+cost+" was above threshold "+maxCost);                    }                  }                }              }              if (decideYes) {                // Ok, we're going to inline it.                // Record that and also whether or not we think it needs a guard.                methodsToInline.add(callee);                if (preEx) {                  if (OPT_ClassLoadingDependencyManager.TRACE ||                       OPT_ClassLoadingDependencyManager.DEBUG) {                    VM_Class.OptCLDepManager.report("PREEX_INLINE: Inlined "                                                    + callee + " into " + caller + "\n");                  }                  VM_Class.OptCLDepManager.addNotOverriddenDependency(callee, state.getCompiledMethod());                  if (goosc) {                    VM_Class.OptCLDepManager.addNotOverriddenDependency(staticCallee, state.getCompiledMethod());                  }                  methodsNeedGuard.add(Boolean.FALSE);                } else {                  methodsNeedGuard.add(Boolean.valueOf(needsGuard));                }              }            }          }        });      // Stage 4: Choose guards and package up the results in an InlineDecision object      if (methodsToInline.size() == 0) {        OPT_InlineDecision d = OPT_InlineDecision.NO("No desirable targets");        if (verbose) VM.sysWriteln("\tDecide: "+d);        return d;      } else if (methodsToInline.size() == 1) {        VM_Method target = (VM_Method)methodsToInline.get(0);        boolean needsGuard = ((Boolean)methodsNeedGuard.get(0)).booleanValue();        if (needsGuard) {          if ((guardOverrideOnStaticCallee || target == staticCallee) &&              isCurrentlyFinal(target, !opts.guardWithClassTest())) {            OPT_InlineDecision d = OPT_InlineDecision.guardedYES(target,                                                                  chooseGuard(caller, target, staticCallee, state, true),                                                                  "Guarded inline of single static target");            if (opts.OSR_GUARDED_INLINING &&                 OPT_Compiler.getAppStarted() &&                VM_Controller.options.ENABLE_RECOMPILATION) {              // note that we will OSR the failed case.              d.setOSRTestFailed();            }            if (verbose) VM.sysWriteln("\tDecide: "+d);            return d;          } else {            OPT_InlineDecision d = OPT_InlineDecision.guardedYES(target,                                                                 chooseGuard(caller, target, staticCallee, state, false),                                                                  "Guarded inlining of one potential target");            if (verbose) VM.sysWriteln("\tDecide: "+d);            return d;          }        } else {          OPT_InlineDecision d = OPT_InlineDecision.YES(target, "Unique and desirable target");          if (verbose) VM.sysWriteln("\tDecide: "+d);          return d;        }              } else {        VM_Method[] methods = new VM_Method[methodsNeedGuard.size()];        byte[] guards = new byte[methods.length];        int idx = 0;        for (Iterator methodIterator = methodsToInline.iterator(), guardIterator = methodsNeedGuard.iterator();             methodIterator.hasNext();) {          VM_Method target = (VM_Method)methodIterator.next();          boolean needsGuard = ((Boolean)guardIterator.next()).booleanValue();          if (VM.VerifyAssertions) VM._assert(needsGuard);          methods[idx] = target;          guards[idx] = chooseGuard(caller, target, staticCallee, state, false);          idx++;        }         OPT_InlineDecision d = OPT_InlineDecision.guardedYES(methods, guards, "Inline multiple targets");        if (verbose) VM.sysWriteln("\tDecide: "+d);        return d;      }    }  }