type blockEffects … type liveness … type Map … func (m *Map) reset() { … } func (m *Map) set(v *ssa.Value, i objw.StackMapIndex) { … } func (m *Map) setUnsafeVal(v *ssa.Value) { … } func (m *Map) setUnsafeBlock(b *ssa.Block) { … } func (m Map) Get(v *ssa.Value) objw.StackMapIndex { … } func (m Map) GetUnsafe(v *ssa.Value) bool { … } func (m Map) GetUnsafeBlock(b *ssa.Block) bool { … } type progeffectscache … // shouldTrack reports whether the liveness analysis // should track the variable n. // We don't care about variables that have no pointers, // nor do we care about non-local variables, // nor do we care about empty structs (handled by the pointer check), // nor do we care about the fake PAUTOHEAP variables. func shouldTrack(n *ir.Name) bool { … } // getvariables returns the list of on-stack variables that we need to track // and a map for looking up indices by *Node. func getvariables(fn *ir.Func) ([]*ir.Name, map[*ir.Name]int32) { … } func (lv *liveness) initcache() { … } type liveEffect … const uevar … const varkill … // valueEffects returns the index of a variable in lv.vars and the // liveness effects v has on that variable. // If v does not affect any tracked variables, it returns -1, 0. func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) { … } // affectedVar returns the *ir.Name node affected by v. func affectedVar(v *ssa.Value) (*ir.Name, ssa.SymEffect) { … } type livenessFuncCache … // Constructs a new liveness structure used to hold the global state of the // liveness computation. The cfg argument is a slice of *BasicBlocks and the // vars argument is a slice of *Nodes. func newliveness(fn *ir.Func, f *ssa.Func, vars []*ir.Name, idx map[*ir.Name]int32, stkptrsize int64) *liveness { … } func (lv *liveness) blockEffects(b *ssa.Block) *blockEffects { … } // Generates live pointer value maps for arguments and local variables. The // this argument and the in arguments are always assumed live. The vars // argument is a slice of *Nodes. func (lv *liveness) pointerMap(liveout bitvec.BitVec, vars []*ir.Name, args, locals bitvec.BitVec) { … } // IsUnsafe indicates that all points in this function are // unsafe-points. func IsUnsafe(f *ssa.Func) bool { … } // markUnsafePoints finds unsafe points and computes lv.unsafePoints. func (lv *liveness) markUnsafePoints() { … } // Returns true for instructions that must have a stack map. // // This does not necessarily mean the instruction is a safe-point. In // particular, call Values can have a stack map in case the callee // grows the stack, but not themselves be a safe-point. func (lv *liveness) hasStackMap(v *ssa.Value) bool { … } // Initializes the sets for solving the live variables. Visits all the // instructions in each basic block to summarizes the information at each basic // block func (lv *liveness) prologue() { … } // Solve the liveness dataflow equations. func (lv *liveness) solve() { … } // Visits all instructions in a basic block and computes a bit vector of live // variables at each safe point locations. func (lv *liveness) epilogue() { … } // Compact coalesces identical bitmaps from lv.livevars into the sets // lv.stackMapSet. // // Compact clears lv.livevars. // // There are actually two lists of bitmaps, one list for the local variables and one // list for the function arguments. Both lists are indexed by the same PCDATA // index, so the corresponding pairs must be considered together when // merging duplicates. The argument bitmaps change much less often during // function execution than the local variable bitmaps, so it is possible that // we could introduce a separate PCDATA index for arguments vs locals and // then compact the set of argument bitmaps separately from the set of // local variable bitmaps. As of 2014-04-02, doing this to the godoc binary // is actually a net loss: we save about 50k of argument bitmaps but the new // PCDATA tables cost about 100k. So for now we keep using a single index for // both bitmap lists. func (lv *liveness) compact(b *ssa.Block) { … } func (lv *liveness) enableClobber() { … } // Inserts code to clobber pointer slots in all the dead variables (locals and args) // at every synchronous safepoint in b. func (lv *liveness) clobber(b *ssa.Block) { … } // clobber generates code to clobber pointer slots in all dead variables // (those not marked in live). Clobbering instructions are added to the end // of b.Values. func clobber(lv *liveness, b *ssa.Block, live bitvec.BitVec) { … } // clobberVar generates code to trash the pointers in v. // Clobbering instructions are added to the end of b.Values. func clobberVar(b *ssa.Block, v *ir.Name) { … } // b = block to which we append instructions // v = variable // offset = offset of (sub-portion of) variable to clobber (in bytes) // t = type of sub-portion of v. func clobberWalk(b *ssa.Block, v *ir.Name, offset int64, t *types.Type) { … } // clobberPtr generates a clobber of the pointer at offset offset in v. // The clobber instruction is added at the end of b. func clobberPtr(b *ssa.Block, v *ir.Name, offset int64) { … } func (lv *liveness) showlive(v *ssa.Value, live bitvec.BitVec) { … } func (lv *liveness) printbvec(printed bool, name string, live bitvec.BitVec) bool { … } // printeffect is like printbvec, but for valueEffects. func (lv *liveness) printeffect(printed bool, name string, pos int32, x bool) bool { … } // Prints the computed liveness information and inputs, for debugging. // This format synthesizes the information used during the multiple passes // into a single presentation. func (lv *liveness) printDebug() { … } // Dumps a slice of bitmaps to a symbol as a sequence of uint32 values. The // first word dumped is the total number of bitmaps. The second word is the // length of the bitmaps. All bitmaps are assumed to be of equal length. The // remaining bytes are the raw bitmaps. func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) { … } // Entry pointer for Compute analysis. Solves for the Compute of // pointer variables in the function and emits a runtime data // structure read by the garbage collector. // Returns a map from GC safe points to their corresponding stack map index, // and a map that contains all input parameters that may be partially live. func Compute(curfn *ir.Func, f *ssa.Func, stkptrsize int64, pp *objw.Progs) (Map, map[*ir.Name]bool) { … } func (lv *liveness) emitStackObjects() *obj.LSym { … } // isfat reports whether a variable of type t needs multiple assignments to initialize. // For example: // // type T struct { x, y int } // x := T{x: 0, y: 1} // // Then we need: // // var t T // t.x = 0 // t.y = 1 // // to fully initialize t. func isfat(t *types.Type) bool { … } // WriteFuncMap writes the pointer bitmaps for bodyless function fn's // inputs and outputs as the value of symbol <fn>.args_stackmap. // If fn has outputs, two bitmaps are written, otherwise just one. func WriteFuncMap(fn *ir.Func, abiInfo *abi.ABIParamResultInfo) { … }