private boolean targetSizeAfterInlineExceedsLimit(NodeTraversal t, FunctionState fs) {
   Node containingFunction = getContainingFunction(t);
   // Always inline at the top level,
   // unless maybeAddFunction has marked fs as not inlinable.
   if (containingFunction == null) {
     return false;
   }
   Node inlinedFun = fs.getFn().getFunctionNode();
   if (isAlwaysInlinable(inlinedFun)) {
     return false;
   }
   int inlinedFunSize =
       NodeUtil.countAstSizeUpToLimit(NodeUtil.getFunctionBody(inlinedFun), maxSizeAfterInlining);
   int targetFunSize = NodeUtil.countAstSizeUpToLimit(containingFunction, maxSizeAfterInlining);
   return inlinedFunSize + targetFunSize > maxSizeAfterInlining;
 }
  /**
   * Updates the FunctionState object for the given function. Checks if the given function matches
   * the criteria for an inlinable function.
   */
  private void maybeAddFunction(Function fn, JSModule module) {
    String name = fn.getName();
    FunctionState fs = getOrCreateFunctionState(name);

    // TODO(johnlenz): Maybe "smarten" FunctionState by adding this logic
    // to it?

    // If the function has multiple definitions, don't inline it.
    if (fs.hasExistingFunctionDefinition()) {
      fs.setInline(false);
      return;
    }
    Node fnNode = fn.getFunctionNode();
    if (enforceMaxSizeAfterInlining
        && !isAlwaysInlinable(fnNode)
        && maxSizeAfterInlining <= NodeUtil.countAstSizeUpToLimit(fnNode, maxSizeAfterInlining)) {
      fs.setInline(false);
      return;
    }
    // verify the function hasn't already been marked as "don't inline"
    if (fs.canInline()) {
      // store it for use when inlining.
      fs.setFn(fn);
      if (FunctionInjector.isDirectCallNodeReplacementPossible(fn.getFunctionNode())) {
        fs.inlineDirectly(true);
      }

      // verify the function meets all the requirements.
      // TODO(johnlenz): Minimum requirement checks are about 5% of the
      // run-time cost of this pass.
      if (!isCandidateFunction(fn)) {
        // It doesn't meet the requirements.
        fs.setInline(false);
      }

      // Set the module and gather names that need temporaries.
      if (fs.canInline()) {
        fs.setModule(module);

        Set<String> namesToAlias = FunctionArgumentInjector.findModifiedParameters(fnNode);
        if (!namesToAlias.isEmpty()) {
          fs.inlineDirectly(false);
          fs.setNamesToAlias(namesToAlias);
        }

        Node block = NodeUtil.getFunctionBody(fnNode);
        if (NodeUtil.referencesThis(block)) {
          fs.setReferencesThis(true);
        }

        if (NodeUtil.containsFunction(block)) {
          fs.setHasInnerFunctions(true);
          // If there are inner functions, we can inline into global scope
          // if there are no local vars or named functions.
          // TODO(johnlenz): this can be improved by looking at the possible
          // values for locals.  If there are simple values, or constants
          // we could still inline.
          if (!assumeMinimumCapture && hasLocalNames(fnNode)) {
            fs.setInline(false);
          }
        }
      }

      // Check if block inlining is allowed.
      if (fs.canInline() && !fs.canInlineDirectly()) {
        if (!blockFunctionInliningEnabled) {
          fs.setInline(false);
        }
      }
    }
  }