// checkBasicBlocks traverses the control flow graph starting at a set of given
// block and checks each instruction for allowed operations.
//
// funcFact are the exported facts for the enclosing function for these basic
// blocks.
checkBasicBlocks traverses the control flow graph starting at a set of given
block and checks each instruction for allowed operations.

funcFact are the exported facts for the enclosing function for these basic
blocks.
// checkBasicBlocks traverses the control flow graph starting at a set of given // block and checks each instruction for allowed operations . // // funcFact are the exported facts for the enclosing function for these basic // blocks .
func (pc *passContext) checkBasicBlocks(blocks []*ssa.BasicBlock, recoverBlock *ssa.BasicBlock, fn *ssa.Function, funcFact lockFunctionFacts) {
	if len(blocks) == 0 {
		return
	}
	seen := make(map[*ssa.BasicBlock]*locksHeld)
	var scan func(block *ssa.BasicBlock, parent *locksHeld)
	scan = func(block *ssa.BasicBlock, parent *locksHeld) {
		_, isExempted := pc.exemptions[block.Parent().Object()]
		if oldLocksHeld, ok := seen[block]; ok {
			if oldLocksHeld.Same(parent) {
				return
			}
			pc.maybeFail(block.Instrs[0].Pos(), isExempted, "failure entering a block %+v with different sets of lock held, oldLocks: %+v, parentLocks: %+v", block, oldLocksHeld, parent)
			return
		}
		seen[block] = parent
		var lh = parent.Copy()
		for _, inst := range block.Instrs {
			pc.checkInstruction(inst, isExempted, lh)
		}
		for _, b := range block.Succs {
			scan(b, lh)
		}
	}
	lh := &locksHeld{locks: make(map[ssa.Value]mutexState)}
	for _, fg := range funcFact.GuardedBy {
		log.Debugf("fn: %s, fn.Operands() == %+v", fn, fn.Operands(nil))
		r := fn.Params[fg.ParameterNumber]
		guardObj := findField(r, fg.FieldNumber)
		var fieldFacts lockFieldFacts
		pc.pass.ImportObjectFact(guardObj, &fieldFacts)
		if fieldFacts.IsMutex || fieldFacts.IsRWMutex {
			m, ok := lh.locks[r]
			if !ok {
				m = mutexState{lockedMutexes: make(map[int]struct{})}
				lh.locks[r] = m
			}
			m.lockedMutexes[fieldFacts.FieldNumber] = struct{}{}
		} else {
			panic(fmt.Sprintf("function: %+v has an invalid guard that is not a mutex: %+v", fn, guardObj))
		}
	}
	scan(blocks[0], lh)
	for _, b := range blocks {
		if _, ok := seen[b]; !ok && b != recoverBlock {
			panic(fmt.Sprintf("block %+v was not visited during checkBasicBlocks", b))
		}
	}
}
func ( pc * passContext ) checkBasicBlocks ( blocks [ ] * ssa . BasicBlock , recoverBlock * ssa . BasicBlock , fn * ssa . Function , funcFact lockFunctionFacts ) { if len ( blocks ) == 0 { return } seen := make ( map [ * ssa . BasicBlock ] * locksHeld ) var scan func ( block * ssa . BasicBlock , parent * locksHeld ) scan = func ( block * ssa . BasicBlock , parent * locksHeld ) { _ , isExempted := pc . exemptions [ block . Parent ( ) . Object ( ) ] if oldLocksHeld , ok := seen [ block ] ; ok { if oldLocksHeld . Same ( parent ) { return } pc . maybeFail ( block . Instrs [ 0 ] . Pos ( ) , isExempted , " " , block , oldLocksHeld , parent ) return } seen [ block ] = parent var lh = parent . Copy ( ) for _ , inst := range block . Instrs { pc . checkInstruction ( inst , isExempted , lh ) } for _ , b := range block . Succs { scan ( b , lh ) } } lh := & locksHeld { locks : make ( map [ ssa . Value ] mutexState ) } for _ , fg := range funcFact . GuardedBy { log . Debugf ( " " , fn , fn . Operands ( nil ) ) r := fn . Params [ fg . ParameterNumber ] guardObj := findField ( r , fg . FieldNumber ) var fieldFacts lockFieldFacts pc . pass . ImportObjectFact ( guardObj , & fieldFacts ) if fieldFacts . IsMutex || fieldFacts . IsRWMutex { m , ok := lh . locks [ r ] if ! ok { m = mutexState { lockedMutexes : make ( map [ int ] struct { } ) } lh . locks [ r ] = m } m . lockedMutexes [ fieldFacts . FieldNumber ] = struct { } { } } else { panic ( fmt . Sprintf ( " " , fn , guardObj ) ) } } scan ( blocks [ 0 ] , lh ) for _ , b := range blocks { if _ , ok := seen [ b ] ; ! ok && b != recoverBlock { panic ( fmt . Sprintf ( " " , b ) ) } } }
checkBasicBlocks traverses the control flow graph starting at a set of given
block and checks each instruction for allowed operations.
checkBasicBlocks traverses the control flow graph starting at a set of given block and checks each instruction for allowed operations .
// mutexes is used to track currently locked sync.Mutexes/sync.RWMutexes for a // given *struct identified by ssa.Value. // Initialize lh with any preconditions that require locks to be held for the // method to be invoked. // The first is the method object itself so we skip that when looking // for receiver/function parameters. // Start scanning from the first basic block. // Validate that all blocks were touched.