Skip to content

Commit dbd4b2c

Browse files
authored
ruleguard/quasigo: pass args via ValueStack (#377)
It makes it easier to implement quasigo funcs call later on, so Go->quasigo and quasigo->quasigo can use the same calling convention. Note that args can be bound once (until env.Stack.Reset), which is useful in plugins-like context when you pass the same argument list to all user functions.
1 parent 6aa060f commit dbd4b2c

10 files changed

+160
-77
lines changed

ruleguard/filters.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func makeCustomVarFilter(src, varname string, fn *quasigo.Func) filterFunc {
186186
// We should probably catch the panic here, print trace and return "false"
187187
// from the filter (or even propagate that panic to let it crash).
188188
params.varname = varname
189-
result := quasigo.Call(params.env, fn, params)
189+
result := quasigo.Call(params.env, fn)
190190
if result.Value().(bool) {
191191
return filterSuccess
192192
}

ruleguard/quasigo/compile.go

+36-9
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ type compiler struct {
5454
locals map[string]int
5555
constantsPool map[interface{}]int
5656
intConstantsPool map[int]int
57-
params map[string]int
57+
58+
params map[string]int
59+
intParams map[string]int
5860

5961
code []byte
6062
constants []interface{}
@@ -89,20 +91,31 @@ func (cl *compiler) compileFunc(fn *ast.FuncDecl) *Func {
8991
panic(cl.errorUnsupportedType(fn.Name, cl.retType, "function result"))
9092
}
9193

92-
dbg := funcDebugInfo{
93-
paramNames: make([]string, cl.fnType.Params().Len()),
94-
}
95-
9694
cl.params = make(map[string]int, cl.fnType.Params().Len())
95+
cl.intParams = make(map[string]int, cl.fnType.Params().Len())
9796
for i := 0; i < cl.fnType.Params().Len(); i++ {
9897
p := cl.fnType.Params().At(i)
9998
paramName := p.Name()
10099
paramType := p.Type()
101-
cl.params[paramName] = i
102-
dbg.paramNames[i] = paramName
103100
if !cl.isSupportedType(paramType) {
104101
panic(cl.errorUnsupportedType(fn.Name, paramType, paramName+" param"))
105102
}
103+
if typeIsInt(paramType) {
104+
cl.intParams[paramName] = len(cl.intParams)
105+
} else {
106+
cl.params[paramName] = len(cl.params)
107+
}
108+
}
109+
110+
dbg := funcDebugInfo{
111+
paramNames: make([]string, len(cl.params)),
112+
intParamNames: make([]string, len(cl.intParams)),
113+
}
114+
for paramName, i := range cl.params {
115+
dbg.paramNames[i] = paramName
116+
}
117+
for paramName, i := range cl.intParams {
118+
dbg.intParamNames[i] = paramName
106119
}
107120

108121
cl.compileStmt(fn.Body)
@@ -298,10 +311,20 @@ func (cl *compiler) compileAssignStmt(assign *ast.AssignStmt) {
298311
}
299312
}
300313

314+
func (cl *compiler) isParamName(varname string) bool {
315+
if _, ok := cl.params[varname]; ok {
316+
return true
317+
}
318+
if _, ok := cl.intParams[varname]; ok {
319+
return true
320+
}
321+
return false
322+
}
323+
301324
func (cl *compiler) getLocal(v ast.Expr, varname string) int {
302325
id, ok := cl.locals[varname]
303326
if !ok {
304-
if _, ok := cl.params[varname]; ok {
327+
if cl.isParamName(varname) {
305328
panic(cl.errorf(v, "can't assign to %s, params are readonly", varname))
306329
}
307330
panic(cl.errorf(v, "%s is not a writeable local variable", varname))
@@ -645,7 +668,11 @@ func (cl *compiler) compileIdent(ident *ast.Ident) {
645668
return
646669
}
647670
if paramIndex, ok := cl.params[ident.String()]; ok {
648-
cl.emit8(pickOp(typeIsInt(tv.Type), opPushIntParam, opPushParam), paramIndex)
671+
cl.emit8(opPushParam, paramIndex)
672+
return
673+
}
674+
if paramIndex, ok := cl.intParams[ident.String()]; ok {
675+
cl.emit8(opPushIntParam, paramIndex)
649676
return
650677
}
651678
if localIndex, ok := cl.locals[ident.String()]; ok {

ruleguard/quasigo/compile_test.go

+15-15
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func TestCompile(t *testing.T) {
2525
},
2626

2727
`return b`: {
28-
` PushParam 2 # b`,
28+
` PushParam 1 # b`,
2929
` ReturnTop`,
3030
},
3131

@@ -55,7 +55,7 @@ func TestCompile(t *testing.T) {
5555
` EqInt`,
5656
` Dup`,
5757
` JumpFalse 8 # L0`,
58-
` PushParam 1 # s`,
58+
` PushParam 0 # s`,
5959
` PushConst 0 # value="foo"`,
6060
` EqString`,
6161
`L0:`,
@@ -81,7 +81,7 @@ func TestCompile(t *testing.T) {
8181
},
8282

8383
`if b { return 1 }; return 0`: {
84-
` PushParam 2 # b`,
84+
` PushParam 1 # b`,
8585
` JumpFalse 6 # L0`,
8686
` PushIntConst 0 # value=1`,
8787
` ReturnIntTop`,
@@ -91,7 +91,7 @@ func TestCompile(t *testing.T) {
9191
},
9292

9393
`if b { return 1 } else { return 0 }`: {
94-
` PushParam 2 # b`,
94+
` PushParam 1 # b`,
9595
` JumpFalse 6 # L0`,
9696
` PushIntConst 0 # value=1`,
9797
` ReturnIntTop`,
@@ -103,7 +103,7 @@ func TestCompile(t *testing.T) {
103103
`x := 0; if b { x = 5 } else { x = 50 }; return x`: {
104104
` PushIntConst 0 # value=0`,
105105
` SetIntLocal 0 # x`,
106-
` PushParam 2 # b`,
106+
` PushParam 1 # b`,
107107
` JumpFalse 10 # L0`,
108108
` PushIntConst 1 # value=5`,
109109
` SetIntLocal 0 # x`,
@@ -124,7 +124,7 @@ func TestCompile(t *testing.T) {
124124
` PushConst 0 # value="a"`,
125125
` ReturnTop`,
126126
`L0:`,
127-
` PushParam 2 # b`,
127+
` PushParam 1 # b`,
128128
` JumpFalse 6 # L1`,
129129
` PushConst 1 # value="b"`,
130130
` ReturnTop`,
@@ -134,58 +134,58 @@ func TestCompile(t *testing.T) {
134134
},
135135

136136
`return eface == nil`: {
137-
` PushParam 3 # eface`,
137+
` PushParam 2 # eface`,
138138
` IsNil`,
139139
` ReturnTop`,
140140
},
141141

142142
`return nil == eface`: {
143-
` PushParam 3 # eface`,
143+
` PushParam 2 # eface`,
144144
` IsNil`,
145145
` ReturnTop`,
146146
},
147147

148148
`return eface != nil`: {
149-
` PushParam 3 # eface`,
149+
` PushParam 2 # eface`,
150150
` IsNotNil`,
151151
` ReturnTop`,
152152
},
153153

154154
`return nil != eface`: {
155-
` PushParam 3 # eface`,
155+
` PushParam 2 # eface`,
156156
` IsNotNil`,
157157
` ReturnTop`,
158158
},
159159

160160
`return s[:]`: {
161-
` PushParam 1 # s`,
161+
` PushParam 0 # s`,
162162
` ReturnTop`,
163163
},
164164

165165
`return s[1:]`: {
166-
` PushParam 1 # s`,
166+
` PushParam 0 # s`,
167167
` PushIntConst 0 # value=1`,
168168
` StringSliceFrom`,
169169
` ReturnTop`,
170170
},
171171

172172
`return s[:1]`: {
173-
` PushParam 1 # s`,
173+
` PushParam 0 # s`,
174174
` PushIntConst 0 # value=1`,
175175
` StringSliceTo`,
176176
` ReturnTop`,
177177
},
178178

179179
`return s[1:2]`: {
180-
` PushParam 1 # s`,
180+
` PushParam 0 # s`,
181181
` PushIntConst 0 # value=1`,
182182
` PushIntConst 1 # value=2`,
183183
` StringSlice`,
184184
` ReturnTop`,
185185
},
186186

187187
`return len(s) >= 0`: {
188-
` PushParam 1 # s`,
188+
` PushParam 0 # s`,
189189
` StringLen`,
190190
` PushIntConst 0 # value=0`,
191191
` GtEqInt`,

ruleguard/quasigo/debug_info.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ type debugInfo struct {
55
}
66

77
type funcDebugInfo struct {
8-
paramNames []string
9-
localNames []string
8+
paramNames []string
9+
intParamNames []string
10+
localNames []string
1011
}
1112

1213
func newDebugInfo() *debugInfo {

ruleguard/quasigo/disasm.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,14 @@ func disasm(env *Env, fn *Func) string {
3939
id := decode16(code, pc+1)
4040
arg = id
4141
comment = env.nativeFuncs[id].name
42-
case opPushParam, opPushIntParam:
42+
case opPushParam:
4343
index := int(code[pc+1])
4444
arg = index
4545
comment = dbg.paramNames[index]
46+
case opPushIntParam:
47+
index := int(code[pc+1])
48+
arg = index
49+
comment = dbg.intParamNames[index]
4650
case opSetLocal, opSetIntLocal, opPushLocal, opPushIntLocal, opIncLocal, opDecLocal:
4751
index := int(code[pc+1])
4852
arg = index

ruleguard/quasigo/eval.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,22 @@ func (s *ValueStack) dup() { s.objects = append(s.objects, s.objects[len(s.objec
3838
// Identical to s.Pop() without using the result.
3939
func (s *ValueStack) discard() { s.objects = s.objects[:len(s.objects)-1] }
4040

41-
func eval(env *EvalEnv, fn *Func, args []interface{}) CallResult {
41+
func eval(env *EvalEnv, fn *Func, top, intTop int) CallResult {
4242
pc := 0
4343
code := fn.code
44-
stack := env.stack
44+
stack := &env.Stack
4545
var locals [maxFuncLocals]interface{}
4646
var intLocals [maxFuncLocals]int
4747

4848
for {
4949
switch op := opcode(code[pc]); op {
5050
case opPushParam:
51-
index := code[pc+1]
52-
stack.Push(args[index])
51+
index := int(code[pc+1])
52+
stack.Push(stack.objects[top+index])
5353
pc += 2
5454
case opPushIntParam:
55-
index := code[pc+1]
56-
stack.PushInt(args[index].(int))
55+
index := int(code[pc+1])
56+
stack.PushInt(stack.ints[intTop+index])
5757
pc += 2
5858

5959
case opPushLocal:

0 commit comments

Comments
 (0)