From afe402d20af0d54d4e0baeb9e70e668e2a26f188 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 5 May 2018 10:25:45 +0200 Subject: prog: make c.Ret optional No reason to allocate return value if there is no return type. c.Ret == nil is the reasonable indication that this is a "void" call. --- prog/clone.go | 4 +++- prog/encoding.go | 4 ++-- prog/encodingexec.go | 2 +- prog/prog.go | 10 +++++++--- prog/validation.go | 32 +++++++++++++++++++------------- 5 files changed, 32 insertions(+), 20 deletions(-) (limited to 'prog') diff --git a/prog/clone.go b/prog/clone.go index 51d801e28..3b6ba0fbc 100644 --- a/prog/clone.go +++ b/prog/clone.go @@ -12,7 +12,9 @@ func (p *Prog) Clone() *Prog { for ci, c := range p.Calls { c1 := new(Call) c1.Meta = c.Meta - c1.Ret = clone(c.Ret, newargs).(*ResultArg) + if c.Ret != nil { + c1.Ret = clone(c.Ret, newargs).(*ResultArg) + } c1.Args = make([]Arg, len(c.Args)) for ai, arg := range c.Args { c1.Args[ai] = clone(arg, newargs) diff --git a/prog/encoding.go b/prog/encoding.go index 86577cd12..f0d96da95 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -33,7 +33,7 @@ func (p *Prog) Serialize() []byte { vars := make(map[*ResultArg]int) varSeq := 0 for _, c := range p.Calls { - if len(c.Ret.uses) != 0 { + if c.Ret != nil && len(c.Ret.uses) != 0 { fmt.Fprintf(buf, "r%v = ", varSeq) vars[c.Ret] = varSeq varSeq++ @@ -206,7 +206,7 @@ func (target *Target) Deserialize(data []byte) (prog *Prog, err error) { if len(c.Args) != len(meta.Args) { return nil, fmt.Errorf("wrong call arg count: %v, want %v", len(c.Args), len(meta.Args)) } - if r != "" { + if r != "" && c.Ret != nil { vars[r] = c.Ret } } diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 9d918b155..a162a7126 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -152,7 +152,7 @@ func (p *Prog) SerializeForExec(buffer []byte) (int, error) { } // Generate the call itself. w.write(uint64(c.Meta.ID)) - if len(c.Ret.uses) != 0 { + if c.Ret != nil && len(c.Ret.uses) != 0 { if _, ok := w.args[c.Ret]; ok { panic("argInfo is already created for return value") } diff --git a/prog/prog.go b/prog/prog.go index ef09d46a9..19f5e319f 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -261,8 +261,10 @@ func MakeResultArg(t Type, r *ResultArg, v uint64) *ResultArg { } func MakeReturnArg(t Type) *ResultArg { - // TODO(dvyukov): we should not create return arg at all if t is nil. - if t != nil && t.Dir() != DirOut { + if t == nil { + return nil + } + if t.Dir() != DirOut { panic("return arg is not out") } return &ResultArg{ArgCommon: ArgCommon{typ: t}} @@ -491,7 +493,9 @@ func (p *Prog) removeCall(idx int) { for _, arg := range c.Args { removeArg(arg) } - removeArg(c.Ret) + if c.Ret != nil { + removeArg(c.Ret) + } copy(p.Calls[idx:], p.Calls[idx+1:]) p.Calls = p.Calls[:len(p.Calls)-1] } diff --git a/prog/validation.go b/prog/validation.go index f6e0780fd..ac7faeee2 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -47,26 +47,31 @@ func (p *Prog) validateCall(ctx *validCtx, c *Call) error { return err } } - if c.Ret == nil { - return fmt.Errorf("syscall %v: return value is absent", c.Meta.Name) - } - if c.Ret.Type() != nil && c.Ret.Type().Dir() != DirOut { - return fmt.Errorf("syscall %v: return value %v is not output", c.Meta.Name, c.Ret) - } else if c.Ret.Res != nil || c.Ret.Val != 0 || c.Ret.OpDiv != 0 || c.Ret.OpAdd != 0 { - return fmt.Errorf("syscall %v: return value %v is not empty", c.Meta.Name, c.Ret) - } - if c.Meta.Ret != nil { + if c.Meta.Ret == nil { + if c.Ret != nil { + return fmt.Errorf("syscall %v: return value without type", c.Meta.Name) + } + } else { + if c.Ret == nil { + return fmt.Errorf("syscall %v: return value is absent", c.Meta.Name) + } + if c.Ret.Type() != c.Meta.Ret { + return fmt.Errorf("syscall %v: wrong return type", c.Meta.Name) + } + if c.Ret.Type().Dir() != DirOut { + return fmt.Errorf("syscall %v: return value %v is not output", c.Meta.Name, c.Ret) + } + if c.Ret.Res != nil || c.Ret.Val != 0 || c.Ret.OpDiv != 0 || c.Ret.OpAdd != 0 { + return fmt.Errorf("syscall %v: return value %v is not empty", c.Meta.Name, c.Ret) + } if err := validateArg(ctx, c, c.Ret); err != nil { return err } - } else if c.Ret.Type() != nil { - return fmt.Errorf("syscall %v: return value has spurious type: %+v", - c.Meta.Name, c.Ret.Type()) } return nil } -// nolint +// nolint: gocyclo func validateArg(ctx *validCtx, c *Call, arg Arg) error { if arg == nil { return fmt.Errorf("syscall %v: nil arg", c.Meta.Name) @@ -76,6 +81,7 @@ func validateArg(ctx *validCtx, c *Call, arg Arg) error { c.Meta.Name, arg) } ctx.args[arg] = true + // TODO(dvyukov): move this to ResultArg verification. if used, ok := arg.(*ResultArg); ok { for u := range used.uses { if u == nil { -- cgit mrf-deployment