type orderState … // order rewrites fn.Nbody to apply the ordering constraints // described in the comment at the top of the file. func order(fn *ir.Func) { … } // append typechecks stmt and appends it to out. func (o *orderState) append(stmt ir.Node) { … } // newTemp allocates a new temporary with the given type, // pushes it onto the temp stack, and returns it. // If clear is true, newTemp emits code to zero the temporary. func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name { … } // copyExpr behaves like newTemp but also emits // code to initialize the temporary to the value n. func (o *orderState) copyExpr(n ir.Node) *ir.Name { … } // copyExprClear is like copyExpr but clears the temp before assignment. // It is provided for use when the evaluation of tmp = n turns into // a function call that is passed a pointer to the temporary as the output space. // If the call blocks before tmp has been written, // the garbage collector will still treat the temporary as live, // so we must zero it before entering that call. // Today, this only happens for channel receive operations. // (The other candidate would be map access, but map access // returns a pointer to the result data instead of taking a pointer // to be filled in.) func (o *orderState) copyExprClear(n ir.Node) *ir.Name { … } func (o *orderState) copyExpr1(n ir.Node, clear bool) *ir.Name { … } // cheapExpr returns a cheap version of n. // The definition of cheap is that n is a variable or constant. // If not, cheapExpr allocates a new tmp, emits tmp = n, // and then returns tmp. func (o *orderState) cheapExpr(n ir.Node) ir.Node { … } // safeExpr returns a safe version of n. // The definition of safe is that n can appear multiple times // without violating the semantics of the original program, // and that assigning to the safe version has the same effect // as assigning to the original n. // // The intended use is to apply to x when rewriting x += y into x = x + y. func (o *orderState) safeExpr(n ir.Node) ir.Node { … } // addrTemp ensures that n is okay to pass by address to runtime routines. // If the original argument n is not okay, addrTemp creates a tmp, emits // tmp = n, and then returns tmp. // The result of addrTemp MUST be assigned back to n, e.g. // // n.Left = o.addrTemp(n.Left) func (o *orderState) addrTemp(n ir.Node) ir.Node { … } // mapKeyTemp prepares n to be a key in a map runtime call and returns n. // The first parameter is the position of n's containing node, for use in case // that n's position is not unique (e.g., if n is an ONAME). func (o *orderState) mapKeyTemp(outerPos src.XPos, t *types.Type, n ir.Node) ir.Node { … } // mapKeyReplaceStrConv replaces OBYTES2STR by OBYTES2STRTMP // in n to avoid string allocations for keys in map lookups. // Returns a bool that signals if a modification was made. // // For: // // x = m[string(k)] // x = m[T1{... Tn{..., string(k), ...}}] // // where k is []byte, T1 to Tn is a nesting of struct and array literals, // the allocation of backing bytes for the string can be avoided // by reusing the []byte backing array. These are special cases // for avoiding allocations when converting byte slices to strings. // It would be nice to handle these generally, but because // []byte keys are not allowed in maps, the use of string(k) // comes up in important cases in practice. See issue 3512. func mapKeyReplaceStrConv(n ir.Node) bool { … } type ordermarker … // markTemp returns the top of the temporary variable stack. func (o *orderState) markTemp() ordermarker { … } // popTemp pops temporaries off the stack until reaching the mark, // which must have been returned by markTemp. func (o *orderState) popTemp(mark ordermarker) { … } // stmtList orders each of the statements in the list. func (o *orderState) stmtList(l ir.Nodes) { … } // orderMakeSliceCopy matches the pattern: // // m = OMAKESLICE([]T, x); OCOPY(m, s) // // and rewrites it to: // // m = OMAKESLICECOPY([]T, x, s); nil func orderMakeSliceCopy(s []ir.Node) { … } // edge inserts coverage instrumentation for libfuzzer. func (o *orderState) edge() { … } // orderBlock orders the block of statements in n into a new slice, // and then replaces the old slice in n with the new slice. // free is a map that can be used to obtain temporary variables by type. func orderBlock(n *ir.Nodes, free map[string][]*ir.Name) { … } // exprInPlace orders the side effects in *np and // leaves them as the init list of the final *np. // The result of exprInPlace MUST be assigned back to n, e.g. // // n.Left = o.exprInPlace(n.Left) func (o *orderState) exprInPlace(n ir.Node) ir.Node { … } // orderStmtInPlace orders the side effects of the single statement *np // and replaces it with the resulting statement list. // The result of orderStmtInPlace MUST be assigned back to n, e.g. // // n.Left = orderStmtInPlace(n.Left) // // free is a map that can be used to obtain temporary variables by type. func orderStmtInPlace(n ir.Node, free map[string][]*ir.Name) ir.Node { … } // init moves n's init list to o.out. func (o *orderState) init(n ir.Node) { … } // call orders the call expression n. // n.Op is OCALLFUNC/OCALLINTER or a builtin like OCOPY. func (o *orderState) call(nn ir.Node) { … } // mapAssign appends n to o.out. func (o *orderState) mapAssign(n ir.Node) { … } func (o *orderState) safeMapRHS(r ir.Node) ir.Node { … } // stmt orders the statement n, appending to o.out. func (o *orderState) stmt(n ir.Node) { … } func hasDefaultCase(n *ir.SwitchStmt) bool { … } // exprList orders the expression list l into o. func (o *orderState) exprList(l ir.Nodes) { … } // exprListInPlace orders the expression list l but saves // the side effects on the individual expression ninit lists. func (o *orderState) exprListInPlace(l ir.Nodes) { … } func (o *orderState) exprNoLHS(n ir.Node) ir.Node { … } // expr orders a single expression, appending side // effects to o.out as needed. // If this is part of an assignment lhs = *np, lhs is given. // Otherwise lhs == nil. (When lhs != nil it may be possible // to avoid copying the result of the expression to a temporary.) // The result of expr MUST be assigned back to n, e.g. // // n.Left = o.expr(n.Left, lhs) func (o *orderState) expr(n, lhs ir.Node) ir.Node { … } func (o *orderState) expr1(n, lhs ir.Node) ir.Node { … } // as2func orders OAS2FUNC nodes. It creates temporaries to ensure left-to-right assignment. // The caller should order the right-hand side of the assignment before calling order.as2func. // It rewrites, // // a, b, a = ... // // as // // tmp1, tmp2, tmp3 = ... // a, b, a = tmp1, tmp2, tmp3 // // This is necessary to ensure left to right assignment order. func (o *orderState) as2func(n *ir.AssignListStmt) { … } // as2ok orders OAS2XXX with ok. // Just like as2func, this also adds temporaries to ensure left-to-right assignment. func (o *orderState) as2ok(n *ir.AssignListStmt) { … }