func (f *Function) Len(call *ssa.Call) (string, *Error) { asm := fmt.Sprintf("// BEGIN Builtin.Len: %v\n", call) callcommon := call.Common() arg := callcommon.Args[0] ctx := context{f, call} if callcommon.IsInvoke() { panic(ice("len is a function, not a method")) } if len(callcommon.Args) != 1 { panic(ice(fmt.Sprintf("too many args (%v) for len", len(callcommon.Args)))) } ident := f.Ident(call.Value()) if reflectType(ident.typ).Name() != "int" { panic(ice(fmt.Sprintf("len returns int not (%v)", reflectType(ident.typ).Name()))) } if isArray(arg.Type()) { length := reflectType(arg.Type()).Len() if length >= math.MaxInt32 { panic(ice(fmt.Sprintf("array too large (%v), maximum (%v)", length, math.MaxInt32))) } a, reg := f.allocIdentReg(call, ident, sizeof(ident.typ)) asm += a asm += MovImm32Reg(ctx, int32(length), reg, false) a, err := f.StoreValue(call, ident, reg) asm += a if err != nil { return asm, err } } else if isSlice(arg.Type()) { a, err := f.SliceLen(call, arg, ident) asm += a if err != nil { return asm, err } } else { panic(ice(fmt.Sprintf("bad type (%v) passed to len", arg.Type()))) } asm += fmt.Sprintf("// END Builtin.Len: %v\n", call) return asm, nil }
// Call performs call on a given unprepared call context. func (caller *Function) Call(call *ssa.Call, infer *TypeInfer, b *Block, l *Loop) { if call == nil { infer.Logger.Fatal("Call is nil") return } common := call.Common() switch fn := common.Value.(type) { case *ssa.Builtin: switch fn.Name() { case "close": ch, ok := caller.locals[common.Args[0]] if !ok { infer.Logger.Fatalf("call close: %s: %s", common.Args[0].Name(), ErrUnknownValue) return } if paramName, ok := caller.revlookup[ch.String()]; ok { caller.FuncDef.AddStmts(&migo.CloseStatement{Chan: paramName}) } else { if _, ok := common.Args[0].(*ssa.Phi); ok { caller.FuncDef.AddStmts(&migo.CloseStatement{Chan: common.Args[0].Name()}) } else { caller.FuncDef.AddStmts(&migo.CloseStatement{Chan: ch.(*Value).Name()}) } } infer.Logger.Print(caller.Sprintf("close %s", common.Args[0])) return case "len": if l.State == Enter { len, err := caller.callLen(common, infer) if err == ErrRuntimeLen { l.Bound = Dynamic return } l.Bound, l.End = Static, len return } caller.locals[call] = &Value{call, caller.InstanceID(), l.Index} infer.Logger.Printf(caller.Sprintf(" builtin.%s", common.String())) default: infer.Logger.Printf(caller.Sprintf(" builtin.%s", common.String())) } case *ssa.MakeClosure: infer.Logger.Printf(caller.Sprintf(SkipSymbol+" make closure %s", fn.String())) caller.callClosure(common, fn, infer, b, l) case *ssa.Function: if common.StaticCallee() == nil { infer.Logger.Fatal("Call with nil CallCommon") } callee := caller.callFn(common, infer, b, l) if callee != nil { caller.storeRetvals(infer, call.Value(), callee) } default: if !common.IsInvoke() { infer.Logger.Print("Unknown call type", common.String(), common.Description()) return } callee := caller.invoke(common, infer, b, l) if callee != nil { caller.storeRetvals(infer, call.Value(), callee) } else { // Mock out the return values. switch common.Signature().Results().Len() { case 0: case 1: caller.locals[call.Value()] = &External{ parent: caller.Fn, typ: call.Value().Type().Underlying(), } case 2: caller.locals[call.Value()] = &External{typ: call.Value().Type().Underlying()} caller.tuples[caller.locals[call.Value()]] = make(Tuples, common.Signature().Results().Len()) } } } }
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()) } } }