type resultPropAndCS … type resultUseAnalyzer … // rescoreBasedOnCallResultUses examines how call results are used, // and tries to update the scores of calls based on how their results // are used in the function. func (csa *callSiteAnalyzer) rescoreBasedOnCallResultUses(fn *ir.Func, resultNameTab map[*ir.Name]resultPropAndCS, cstab CallSiteTab) { … } func (csa *callSiteAnalyzer) examineCallResults(cs *CallSite, resultNameTab map[*ir.Name]resultPropAndCS) map[*ir.Name]resultPropAndCS { … } // namesDefined returns a list of ir.Name's corresponding to locals // that receive the results from the call at site 'cs', plus the // properties object for the called function. If a given result // isn't cleanly assigned to a newly defined local, the // slot for that result in the returned list will be nil. Example: // // call returned name list // // x := foo() [ x ] // z, y := bar() [ nil, nil ] // _, q := baz() [ nil, q ] // // In the case of a multi-return call, such as "x, y := foo()", // the pattern we see from the front end will be a call op // assigning to auto-temps, and then an assignment of the auto-temps // to the user-level variables. In such cases we return // first the user-level variable (in the first func result) // and then the auto-temp name in the second result. func namesDefined(cs *CallSite) ([]*ir.Name, []*ir.Name, *FuncProps) { … } func (rua *resultUseAnalyzer) nodeVisitPost(n ir.Node) { … } func (rua *resultUseAnalyzer) nodeVisitPre(n ir.Node) { … } // callTargetCheckResults examines a given call to see whether the // callee expression is potentially an inlinable function returned // from a potentially inlinable call. Examples: // // Scenario 1: named intermediate // // fn1 := foo() conc := bar() // fn1("blah") conc.MyMethod() // // Scenario 2: returned func or concrete object feeds directly to call // // foo()("blah") bar().MyMethod() // // In the second case although at the source level the result of the // direct call feeds right into the method call or indirect call, // we're relying on the front end having inserted an auto-temp to // capture the value. func (rua *resultUseAnalyzer) callTargetCheckResults(call ir.Node) { … } // foldCheckResults examines the specified if/switch condition 'cond' // to see if it refers to locals defined by a (potentially inlinable) // function call at call site C, and if so, whether 'cond' contains // only combinations of simple references to all of the names in // 'names' with selected constants + operators. If these criteria are // met, then we adjust the score for call site C to reflect the // fact that inlining will enable deadcode and/or constant propagation. // Note: for this heuristic to kick in, the names in question have to // be all from the same callsite. Examples: // // q, r := baz() x, y := foo() // switch q+r { a, b, c := bar() // ... if x && y && a && b && c { // } ... // } // // For the call to "baz" above we apply a score adjustment, but not // for the calls to "foo" or "bar". func (rua *resultUseAnalyzer) foldCheckResults(cond ir.Node) { … } func collectNamesUsed(expr ir.Node) []*ir.Name { … } func (rua *resultUseAnalyzer) returnHasProp(name *ir.Name, prop ResultPropBits) *CallSite { … } func (rua *resultUseAnalyzer) getCallResultName(ce *ir.CallExpr) *ir.Name { … }