// Go handles Go statements. func (caller *Function) Go(instr *ssa.Go, infer *TypeInfer) { common := instr.Common() callee := caller.prepareCallFn(common, common.StaticCallee(), nil) spawnStmt := &migo.SpawnStatement{Name: callee.Fn.String(), Params: []*migo.Parameter{}} for i, c := range common.Args { if _, ok := c.Type().(*types.Chan); ok { ch := getChan(c, infer) spawnStmt.AddParams(&migo.Parameter{Caller: ch, Callee: callee.Fn.Params[i]}) } } if inst, ok := caller.locals[common.Value]; ok { if bindings, ok := caller.Prog.closures[inst]; ok { for _, b := range bindings { if v, ok := b.(*Value); ok { if _, ok := derefType(v.Type()).(*types.Chan); ok { spawnStmt.AddParams(&migo.Parameter{Caller: v, Callee: v}) } } } } } caller.FuncDef.AddStmts(spawnStmt) // Don't actually call/visit the function but enqueue it. infer.GQueue = append(infer.GQueue, callee) }
func (caller *frame) callGo(g *ssa.Go) { common := g.Common() goname := fmt.Sprintf("%s_%d", common.Value.Name(), int(g.Pos())) gorole := caller.env.session.GetRole(goname) callee := &frame{ fn: common.StaticCallee(), locals: make(map[ssa.Value]*utils.Definition), arrays: make(map[*utils.Definition]Elems), structs: make(map[*utils.Definition]Fields), tuples: make(map[ssa.Value]Tuples), phi: make(map[ssa.Value][]ssa.Value), recvok: make(map[ssa.Value]*sesstype.Chan), retvals: make(Tuples, common.Signature().Results().Len()), defers: make([]*ssa.Defer, 0), caller: caller, env: caller.env, // Use the same env as caller gortn: &goroutine{ role: gorole, root: sesstype.NewLabelNode(goname), leaf: nil, visited: make(map[*ssa.BasicBlock]sesstype.Node), }, } callee.gortn.leaf = &callee.gortn.root fmt.Fprintf(os.Stderr, "@@ queue go %s(", common.StaticCallee().String()) callee.translate(common) fmt.Fprintf(os.Stderr, ")\n") // TODO(nickng) Does not stop at recursive call. caller.env.extract.goQueue = append(caller.env.extract.goQueue, callee) }