@Override
    public void visitCallSite(NodeTraversal t, Node callNode, FunctionState fs) {
      Preconditions.checkState(fs.hasExistingFunctionDefinition());
      if (fs.canInline()) {
        Reference ref = fs.getReference(callNode);

        // There are two cases ref can be null: if the call site was introduced
        // because it was part of a function that was inlined during this pass
        // or if the call site was trimmed from the list of references because
        // the function couldn't be inlined at this location.
        if (ref != null) {
          if (specializationState != null) {
            Node containingFunction = getContainingFunction(t);
            if (containingFunction != null) {
              // Report that the function was specialized so that
              // {@link SpecializeModule} can fix it up.
              specializationState.reportSpecializedFunction(containingFunction);
            }
          }
          inlineFunction(t, ref, fs);
          // Keep track of references that have been inlined so that
          // we can verify that none have been missed.
          ref.inlined = true;
        }
      }
    }
    private boolean maybeAddReferenceUsingMode(
        NodeTraversal t, FunctionState fs, Node callNode, JSModule module, InliningMode mode) {

      // If many functions are inlined into the same function F in the same
      // inlining round, then the size of F may exceed the max size.
      // This could be avoided if we bail later, during the inlining phase, eg,
      // in Inline#visitCallSite. However, that is not safe, because at that
      // point expression decomposition has already run, and we want to
      // decompose expressions only for the calls that are actually inlined.
      if (enforceMaxSizeAfterInlining && targetSizeAfterInlineExceedsLimit(t, fs)) {
        return false;
      }

      Reference candidate = new Reference(callNode, t.getScope(), module, mode);
      CanInlineResult result =
          injector.canInlineReferenceToFunction(
              candidate,
              fs.getFn().getFunctionNode(),
              fs.getNamesToAlias(),
              fs.getReferencesThis(),
              fs.hasInnerFunctions());
      if (result != CanInlineResult.NO) {
        // Yeah!
        candidate.setRequiresDecomposition(result == CanInlineResult.AFTER_PREPARATION);
        fs.addReference(candidate);
        return true;
      }

      return false;
    }
 if (maybeDecl.isVarDeclaration()) {
   Preconditions.checkState(!maybeDecl.isInitializingDeclaration());
   Reference maybeInit = references.get(index);
   if (maybeInit.isSimpleAssignmentToName()) {
     return true;
   }
 }
예제 #4
0
 /** @return Whether the variable is never assigned a value. */
 boolean isNeverAssigned() {
   int size = references.size();
   for (int i = 0; i < size; i++) {
     Reference ref = references.get(i);
     if (ref.isLvalue() || ref.isInitializingDeclaration()) {
       return false;
     }
   }
   return true;
 }
예제 #5
0
 /**
  * @param index The index into the references array to look for an assigning declaration.
  *     <p>This is either the declaration if a value is assigned (such as "var a = 2", "function
  *     a()...", "... catch (a)...").
  */
 private boolean isInitializingDeclarationAt(int index) {
   Reference maybeInit = references.get(index);
   if (maybeInit.isInitializingDeclaration()) {
     // This is a declaration that represents the initial value.
     // Specifically, var declarations without assignments such as "var a;"
     // are not.
     return true;
   }
   return false;
 }
예제 #6
0
 /**
  * @param index The index into the references array to look for an initialized assignment
  *     reference. That is, an assignment immediately follow a variable declaration that itself
  *     does not initialize the variable.
  */
 private boolean isInitializingAssignmentAt(int index) {
   if (index < references.size() && index > 0) {
     Reference maybeDecl = references.get(index - 1);
     if (maybeDecl.isVarDeclaration()) {
       Preconditions.checkState(!maybeDecl.isInitializingDeclaration());
       Reference maybeInit = references.get(index);
       if (maybeInit.isSimpleAssignmentToName()) {
         return true;
       }
     }
   }
   return false;
 }
예제 #7
0
 /** @return The one and only assignment. Returns if there are 0 or 2+ assignments. */
 private Reference getOneAndOnlyAssignment() {
   Reference assignment = null;
   int size = references.size();
   for (int i = 0; i < size; i++) {
     Reference ref = references.get(i);
     if (ref.isLvalue() || ref.isInitializingDeclaration()) {
       if (assignment == null) {
         assignment = ref;
       } else {
         return null;
       }
     }
   }
   return assignment;
 }
예제 #8
0
    /** @return Whether the variable is only assigned a value once for its lifetime. */
    boolean isAssignedOnceInLifetime() {
      Reference ref = getOneAndOnlyAssignment();
      if (ref == null) {
        return false;
      }

      // Make sure this assignment is not in a loop.
      for (BasicBlock block = ref.getBasicBlock(); block != null; block = block.getParent()) {
        if (block.isFunction) {
          if (ref.getSymbol().getScope() != ref.scope) {
            return false;
          }
          break;
        } else if (block.isLoop) {
          return false;
        }
      }

      return true;
    }
예제 #9
0
    /**
     * Determines if the variable for this reference collection is "well-defined." A variable is
     * well-defined if we can prove at compile-time that it's assigned a value before it's used.
     *
     * <p>Notice that if this function returns false, this doesn't imply that the variable is used
     * before it's assigned. It just means that we don't have enough information to make a
     * definitive judgment.
     */
    protected boolean isWellDefined() {
      int size = references.size();
      if (size == 0) {
        return false;
      }

      // If this is a declaration that does not instantiate the variable,
      // it's not well-defined.
      Reference init = getInitializingReference();
      if (init == null) {
        return false;
      }

      Preconditions.checkState(references.get(0).isDeclaration());
      BasicBlock initBlock = init.getBasicBlock();
      for (int i = 1; i < size; i++) {
        if (!initBlock.provablyExecutesBefore(references.get(i).getBasicBlock())) {
          return false;
        }
      }

      return true;
    }