aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-05-05 10:25:45 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-05-05 10:25:45 +0200
commitafe402d20af0d54d4e0baeb9e70e668e2a26f188 (patch)
tree58f79c51ee9c8a48939059a23c47d68751d55701
parent9dfb5efa91fc0f051a1ddc88ace2867bb6b32275 (diff)
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.
-rw-r--r--prog/clone.go4
-rw-r--r--prog/encoding.go4
-rw-r--r--prog/encodingexec.go2
-rw-r--r--prog/prog.go10
-rw-r--r--prog/validation.go32
5 files changed, 32 insertions, 20 deletions
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 {