void maybeAddFunction ( Function fn , JSModule module ) { String name = fn . getName ( ) ; FunctionState functionState = getOrCreateFunctionState ( name ) ; // TODO(johnlenz): Maybe "smarten" FunctionState by adding this logic to it? // If the function has multiple definitions, don't inline it. if ( functionState . hasExistingFunctionDefinition ( ) ) { functionState . disallowInlining ( ) ; return ; } Node fnNode = fn . getFunctionNode ( ) ; if ( hasNoInlineAnnotation ( fnNode ) ) { functionState . disallowInlining ( ) ; return ; } if ( enforceMaxSizeAfterInlining && ! isAlwaysInlinable ( fnNode ) && maxSizeAfterInlining <= NodeUtil . countAstSizeUpToLimit ( fnNode , maxSizeAfterInlining ) ) { functionState . disallowInlining ( ) ; return ; } // verify the function hasn't already been marked as "don't inline" if ( functionState . canInline ( ) ) { // store it for use when inlining. functionState . setFn ( fn ) ; if ( FunctionInjector . isDirectCallNodeReplacementPossible ( fn . getFunctionNode ( ) ) ) { functionState . inlineDirectly ( true ) ; } if ( hasNonInlinableParam ( NodeUtil . getFunctionParameters ( fnNode ) ) ) { functionState . disallowInlining ( ) ; } // 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. functionState . disallowInlining ( ) ; } // Set the module and gather names that need temporaries. if ( functionState . canInline ( ) ) { functionState . setModule ( module ) ; Set < String > namesToAlias = FunctionArgumentInjector . findModifiedParameters ( fnNode ) ; if ( ! namesToAlias . isEmpty ( ) ) { functionState . inlineDirectly ( false ) ; functionState . setNamesToAlias ( namesToAlias ) ; } Node block = NodeUtil . getFunctionBody ( fnNode ) ; if ( NodeUtil . referencesThis ( block ) ) { functionState . setReferencesThis ( true ) ; } if ( NodeUtil . containsFunction ( block ) ) { functionState . 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 ) ) { functionState . disallowInlining ( ) ; } } } if ( fnNode . getGrandparent ( ) . isVar ( ) ) { Node block = functionState . getFn ( ) . getDeclaringBlock ( ) ; if ( block . isBlock ( ) && ! block . getParent ( ) . isFunction ( ) && ( NodeUtil . containsType ( block , Token . LET ) || NodeUtil . containsType ( block , Token . CONST ) ) ) { // The function might capture a variable that's not in scope at the call site, // so don't inline. functionState . disallowInlining ( ) ; } } if ( fnNode . isGeneratorFunction ( ) ) { functionState . disallowInlining ( ) ; } if ( fnNode . isAsyncFunction ( ) ) { functionState . disallowInlining ( ) ; } } }
Updates the FunctionState object for the given function . Checks if the given function matches the criteria for an inlinable function .