Example #1
0
  /**
   * Finds set of all defs in function given (defSites). Adds parameters of function to this set:
   * defSites. Finds all variables that are referenced in the function given (alf.names).
   * windowProps are all global properties available. Closures = alf.names - defSites - windowProps
   *
   * @param n root node of the function who's closures are to be found
   * @return set of closure names
   */
  private Set<String> findClosures(Node n) {
    Set<String> closureVars = null;

    SimpleDefinitionFinder defFinder = new SimpleDefinitionFinder(compiler);
    defFinder.process(externs, n.getLastChild());
    Collection<DefinitionSite> defSites = defFinder.getDefinitionSites();
    Set<String> localDefs = new HashSet<String>();

    for (DefinitionSite site : defSites) {
      if (site.node.getType() == Token.GETPROP) continue;
      String def = site.node.getString();
      if (def.length() > 0) {
        localDefs.add(def);
      }
    }

    // adding params to function as defs
    Node origParamNode = n.getChildAtIndex(1);
    for (int i = 0; i < origParamNode.getChildCount(); i++) {
      String temp = origParamNode.getChildAtIndex(i).getString();
      localDefs.add(temp);
    }

    // System.out.println("\nPrinting LOCAL def sites:" + defs);

    /*SimpleDefinitionFinder defFinder1 = new SimpleDefinitionFinder(compiler);
    defFinder1.process(externs, root);
    Collection<DefinitionSite> defSites1 = defFinder1.getDefinitionSites();
    Set<String> defs1 = new HashSet<String>();

    for(DefinitionSite site1: defSites1){
    	if (site1.node.getType() == Token.GETPROP) continue;
    	String def = site1.node.getString();
    	if (def.length() > 0){
    		defs1.add(def);
    	}
    }
    System.out.println("\nPrinting Global def sites:" + defs1);*/

    AllNamesFinder alf = new AllNamesFinder(compiler);
    NodeTraversal.traverse(compiler, n.getLastChild(), alf);

    // System.out.println("all names: " + alf.names);

    closureVars = alf.names;

    closureVars.removeAll(localDefs);
    closureVars.removeAll(Props.windowProps);

    closureVars.remove(
        "this"); // since 'this' is later modified to $$_self we don't need to consider this as
    // closure

    return closureVars;
  }
 @Override
 public void process(Node externs, Node root) {
   if (!passes.isEmpty()) {
     SimpleDefinitionFinder defFinder = new SimpleDefinitionFinder(compiler);
     compiler.setSimpleDefinitionFinder(defFinder);
     defFinder.process(externs, root);
     for (CallGraphCompilerPass pass : passes) {
       pass.process(externs, root, defFinder);
     }
   }
 }
  /**
   * Traverses the root, removing all unused variables. Multiple traversals may occur to ensure all
   * unused variables are removed.
   */
  public void process(Node externs, Node root) {
    Preconditions.checkState(compiler.getLifeCycleStage().isNormalized());
    SimpleDefinitionFinder defFinder = null;

    if (modifyCallSites) {
      // For testing, allow the SimpleDefinitionFinder to be build now.
      defFinder = new SimpleDefinitionFinder(compiler);
      defFinder.process(externs, root);
    }
    process(externs, root, defFinder);
  }
    /**
     * @return Whether the definitionSite represents a function whose call signature can be
     *     modified.
     */
    private boolean canChangeSignature(Node function) {
      Definition definition = getFunctionDefinition(function);
      CodingConvention convention = compiler.getCodingConvention();

      Preconditions.checkState(!definition.isExtern());

      Collection<UseSite> useSites = defFinder.getUseSites(definition);
      for (UseSite site : useSites) {
        Node parent = site.node.getParent();

        // This was a use site removed by something else before we run.
        // 1. By another pass before us which means the definition graph is
        //    no updated properly.
        // 2. By the continuations algorithm above.
        if (parent == null) {
          continue; // Ignore it.
        }

        // Ignore references within goog.inherits calls.
        if (NodeUtil.isCall(parent) && convention.getClassesDefinedByCall(parent) != null) {
          continue;
        }

        // Accessing the property directly prevents rewrite.
        if (!SimpleDefinitionFinder.isCallOrNewSite(site)) {
          if (!(NodeUtil.isGetProp(parent) && NodeUtil.isFunctionObjectCall(parent.getParent()))) {
            return false;
          }
        }

        if (NodeUtil.isFunctionObjectApply(parent)) {
          return false;
        }

        // TODO(johnlenz): support specialization

        // Multiple definitions prevent rewrite.
        // Attempt to validate the state of the simple definition finder.
        Node nameNode = site.node;
        Collection<Definition> singleSiteDefinitions =
            defFinder.getDefinitionsReferencedAt(nameNode);
        Preconditions.checkState(singleSiteDefinitions.size() == 1);
        Preconditions.checkState(singleSiteDefinitions.contains(definition));
      }

      return true;
    }
 /**
  * @param function
  * @return the Definition object for the function.
  */
 private Definition getFunctionDefinition(Node function) {
   DefinitionSite definitionSite = defFinder.getDefinitionForFunction(function);
   Preconditions.checkNotNull(definitionSite);
   Definition definition = definitionSite.definition;
   Preconditions.checkState(!definitionSite.inExterns);
   Preconditions.checkState(definition.getRValue() == function);
   return definition;
 }
    /**
     * @param function
     * @return Whether the callers to this function can be modified in any way.
     */
    boolean canModifyCallers(Node function) {
      if (NodeUtil.isVarArgsFunction(function)) {
        return false;
      }

      DefinitionSite defSite = defFinder.getDefinitionForFunction(function);
      if (defSite == null) {
        return false;
      }

      Definition definition = defSite.definition;

      // Be conservative, don't try to optimize any declaration that isn't as
      // simple function declaration or assignment.
      if (!SimpleDefinitionFinder.isSimpleFunctionDeclaration(function)) {
        return false;
      }

      return defFinder.canModifyDefinition(definition);
    }
 /** Remove all the following parameters without side-effects */
 private void tryRemoveAllFollowingArgs(Node function, final int argIndex) {
   Definition definition = getFunctionDefinition(function);
   for (UseSite site : defFinder.getUseSites(definition)) {
     if (!isModifiableCallSite(site)) {
       continue;
     }
     Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex + 1);
     while (arg != null) {
       if (!NodeUtil.mayHaveSideEffects(arg)) {
         toRemove.add(arg);
       }
       arg = arg.getNext();
     }
   }
 }
    /**
     * Remove all references to a parameter, otherwise simplify the known references.
     *
     * @return Whether all the references were removed.
     */
    private boolean canRemoveArgFromCallSites(Node function, int argIndex) {
      Definition definition = getFunctionDefinition(function);

      // Check all the call sites.
      for (UseSite site : defFinder.getUseSites(definition)) {
        if (isModifiableCallSite(site)) {
          Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
          // TODO(johnlenz): try to remove parameters with side-effects by
          // decomposing the call expression.
          if (arg != null && NodeUtil.mayHaveSideEffects(arg, compiler)) {
            return false;
          }
        } else {
          return false;
        }
      }

      return true;
    }
    /**
     * Remove all references to a parameter if possible otherwise simplify the side-effect free
     * parameters.
     */
    private void tryRemoveArgFromCallSites(Node function, int argIndex, boolean canModifyAllSites) {
      Definition definition = getFunctionDefinition(function);

      for (UseSite site : defFinder.getUseSites(definition)) {
        if (isModifiableCallSite(site)) {
          Node arg = getArgumentForCallOrNewOrDotCall(site, argIndex);
          if (arg != null) {
            Node argParent = arg.getParent();
            // Even if we can't change the signature in general we can always
            // remove an unused value off the end of the parameter list.
            if (canModifyAllSites
                || (arg.getNext() == null && !NodeUtil.mayHaveSideEffects(arg, compiler))) {
              toRemove.add(arg);
            } else {
              // replace the node in the arg with 0
              if (!NodeUtil.mayHaveSideEffects(arg, compiler)
                  && (arg.getType() != Token.NUMBER || arg.getDouble() != 0)) {
                toReplaceWithZero.add(arg);
              }
            }
          }
        }
      }
    }
 /**
  * @param site The site to inspect
  * @return Whether the call site is suitable for modification
  */
 private static boolean isModifiableCallSite(UseSite site) {
   return SimpleDefinitionFinder.isCallOrNewSite(site)
       && !NodeUtil.isFunctionObjectApply(site.node.getParent());
 }