// genStaticCall generates constraints for a statically dispatched function call. func (a *analysis) genStaticCall(caller *cgnode, site *callsite, call *ssa.CallCommon, result nodeid) { fn := call.StaticCallee() // Special cases for inlined intrinsics. switch fn { case a.runtimeSetFinalizer: // Inline SetFinalizer so the call appears direct. site.targets = a.addOneNode(tInvalid, "SetFinalizer.targets", nil) a.addConstraint(&runtimeSetFinalizerConstraint{ targets: site.targets, x: a.valueNode(call.Args[0]), f: a.valueNode(call.Args[1]), }) return case a.reflectValueCall: // Inline (reflect.Value).Call so the call appears direct. dotdotdot := false ret := reflectCallImpl(a, caller, site, a.valueNode(call.Args[0]), a.valueNode(call.Args[1]), dotdotdot) if result != 0 { a.addressOf(fn.Signature.Results().At(0).Type(), result, ret) } return } // Ascertain the context (contour/cgnode) for a particular call. var obj nodeid if a.shouldUseContext(fn) { obj = a.makeFunctionObject(fn, site) // new contour } else { obj = a.objectNode(nil, fn) // shared contour } a.callEdge(caller, site, obj) sig := call.Signature() // Copy receiver, if any. params := a.funcParams(obj) args := call.Args if sig.Recv() != nil { sz := a.sizeof(sig.Recv().Type()) a.copy(params, a.valueNode(args[0]), sz) params += nodeid(sz) args = args[1:] } // Copy actual parameters into formal params block. // Must loop, since the actuals aren't contiguous. for i, arg := range args { sz := a.sizeof(sig.Params().At(i).Type()) a.copy(params, a.valueNode(arg), sz) params += nodeid(sz) } // Copy formal results block to actual result. if result != 0 { a.copy(result, a.funcResults(obj), a.sizeof(sig.Results())) } }
func (caller *Function) callClosure(common *ssa.CallCommon, closure *ssa.MakeClosure, infer *TypeInfer, b *Block, l *Loop) { callee := caller.prepareCallFn(common, closure.Fn.(*ssa.Function), nil) for _, b := range closure.Bindings { if inst, ok := caller.locals[b]; ok { callee.locals[b] = inst } } callee.call(common, common.StaticCallee(), nil, infer, b, l) }
func call(i ssa.Instruction, out *bytes.Buffer) { var callCom ssa.CallCommon switch i := i.(type) { case *ssa.Call: callCom = i.Call case *ssa.Go: callCom = i.Call case *ssa.Defer: callCom = i.Call default: return } // invoked call out.WriteString(" call is invoked") if callCom.IsInvoke() { out.WriteString(" true\n") } else { out.WriteString(" false\n") } // method if callCom.Method == nil { out.WriteString(" value is a *Builtin ") if _, ok := callCom.Value.(*ssa.Builtin); ok { out.WriteString(" true\n") } else { out.WriteString(" false\n") } } // signatue if callCom.Value != nil { out.WriteString(" signature(Value):" + callCom.Value.Name() + " " + callCom.Signature().String() + "\n") } if callCom.StaticCallee() != nil { out.WriteString(" signature:" + callCom.StaticCallee().Signature.String() + "\n") } // arguments for i, arg := range callCom.Args { if i == 1 { out.WriteString(" args:") } out.WriteString(arg.String() + "|") } out.WriteString("\n") }
// Emit the code for a call to a function or builtin, which could be deferred. func emitCall(isBuiltin, isGo, isDefer, usesGr bool, register string, callInfo ssa.CallCommon, errorInfo, comment string) { // usesGr gives the default position l := TargetLang fnToCall := "" if isBuiltin { fnToCall = callInfo.Value.(*ssa.Builtin).Name() usesGr = false } else if callInfo.StaticCallee() != nil { pName, _ := FuncPathName(callInfo.StaticCallee()) //fmt.Sprintf("fn%d", callInfo.StaticCallee().Pos()) if callInfo.Signature().Recv() != nil { pName = callInfo.Signature().Recv().Pkg().Name() + ":" + callInfo.Signature().Recv().Type().String() // no use of Underlying() here } else { pkg := callInfo.StaticCallee().Package() if pkg != nil { pName = pkg.Object.Path() // was .Name() } } fnToCall = LanguageList[l].LangName(pName, callInfo.StaticCallee().Name()) usesGr = grMap[callInfo.StaticCallee()] } else { // Dynamic call (take the default on usesGr) fnToCall = LanguageList[l].Value(callInfo.Value, errorInfo) } if isBuiltin { switch fnToCall { case "len", "cap", "append", "real", "imag", "complex": // "copy" may have the results unused if register == "" { LogError(errorInfo, "pogo", fmt.Errorf("the result from a built-in function is not used")) } default: } } else { if callInfo.Signature().Results().Len() > 0 { if register == "" { LogWarning(errorInfo, "pogo", fmt.Errorf("the result from a function call is not used")) //TODO is this needed? } } } // target language code must do builtin emulation text := LanguageList[l].Call(register, callInfo, callInfo.Args, isBuiltin, isGo, isDefer, usesGr, fnToCall, errorInfo) fmt.Fprintln(&LanguageList[l].buffer, text+LanguageList[l].Comment(comment)) }
func (caller *Function) callFn(common *ssa.CallCommon, infer *TypeInfer, b *Block, l *Loop) *Function { return caller.call(common, common.StaticCallee(), nil, infer, b, l) }
func (caller *frame) callCommon(call *ssa.Call, common *ssa.CallCommon) { switch fn := common.Value.(type) { case *ssa.Builtin: caller.callBuiltin(common) case *ssa.MakeClosure: // TODO(nickng) Handle calling closure fmt.Fprintf(os.Stderr, " # TODO (handle closure) %s\n", fn.String()) case *ssa.Function: if common.StaticCallee() == nil { panic("Call with nil CallCommon!") } 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: caller.gortn, // Use the same role as caller } fmt.Fprintf(os.Stderr, "++ call %s(", orange(common.StaticCallee().String())) callee.translate(common) fmt.Fprintf(os.Stderr, ")\n") if callee.isRecursive() { fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(common.StaticCallee().String())) callee.printCallStack() } else { if hasCode := visitFunc(callee.fn, callee); hasCode { caller.handleRetvals(call.Value(), callee) } else { caller.handleExtRetvals(call.Value(), callee) } fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(common.StaticCallee().String()), len(callee.retvals)) } default: if !common.IsInvoke() { fmt.Fprintf(os.Stderr, "Unknown call type %v\n", common) return } switch vd, kind := caller.get(common.Value); kind { case Struct, LocalStruct: fmt.Fprintf(os.Stderr, "++ invoke %s.%s, type=%s\n", reg(common.Value), common.Method.String(), vd.Var.Type().String()) // If dealing with interfaces, check that the method is invokable if iface, ok := common.Value.Type().Underlying().(*types.Interface); ok { if meth, _ := types.MissingMethod(vd.Var.Type(), iface, true); meth != nil { fmt.Fprintf(os.Stderr, " ^ interface not fully implemented\n") } else { fn := findMethod(common.Value.Parent().Prog, common.Method, vd.Var.Type()) if fn != nil { fmt.Fprintf(os.Stderr, " ^ found function %s\n", fn.String()) callee := &frame{ fn: fn, 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: caller.gortn, // Use the same role as caller } common.Args = append([]ssa.Value{common.Value}, common.Args...) fmt.Fprintf(os.Stderr, "++ call %s(", orange(fn.String())) callee.translate(common) fmt.Fprintf(os.Stderr, ")\n") if callee.isRecursive() { fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(fn.String())) callee.printCallStack() } else { if hasCode := visitFunc(callee.fn, callee); hasCode { caller.handleRetvals(call.Value(), callee) } else { caller.handleExtRetvals(call.Value(), callee) } fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(fn.String()), len(callee.retvals)) } } else { panic(fmt.Sprintf("Cannot call function: %s.%s is abstract (program not well-formed)", common.Value, common.Method.String())) } } } else { fmt.Fprintf(os.Stderr, " ^ method %s.%s does not exist\n", reg(common.Value), common.Method.String()) } default: fmt.Fprintf(os.Stderr, "++ invoke %s.%s\n", reg(common.Value), common.Method.String()) } } }