Skip to content

Commit 6fbbef6

Browse files
committed
first draft: function calls
We have implemented function calls in a way which should facilitate closures and interfaces a great deal. rather than the traditional Anderson copy/transfer constraints of arguments to parameters and function results to caller local results, we 1. represent each function in contiguous memory as a sequence (p0, p1, ..., pn, r0, r1, ..., rm) where each pi is a pointer to an object of type of parameter i, and each ri is a pointer to an object of type of return i. 2. upon analyzing a function we take *pi as the starting value of the parameter. 3. Upon calling a function, we set *pi = argi and resi = *ri. Now, given 2 functions f, g of the same signature, we have copy/transfer constraints (fp0, fp1, ..., fpn, fr0, fr1, ..., frm) = (gp0, gp1, ..., gpn, gr0, gr1, ..., grn). then the points-to of each parameter and result are transfered to f from g. In this way, dynamic dispatch should be a cinch: just call the function object associated with the node, it will have all the loads/stores of any function assigned to it. Something similar should work for interfaces: we just keep a struct of function objects defined as above, and on assignment to an interface value, we assign the functions from the concrete type. Likewise, this should facilitate closures by adding a free variables component like the pi,ri components.
1 parent 2d2291b commit 6fbbef6

File tree

4 files changed

+109
-25
lines changed

4 files changed

+109
-25
lines changed

memory/model.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type Model struct {
3232
locs []loc
3333
constraints []Constraint
3434
indexing indexing.T
35+
work []Loc
3536
}
3637

3738
// NewModel generates a new memory model for a package.
@@ -145,7 +146,17 @@ func (mod *Model) Type(m Loc) typeset.Type {
145146
func (mod *Model) Gen(gp *GenParams) Loc {
146147
var sum int
147148
p := Loc(uint32(len(mod.locs)))
148-
return mod.p_add(gp, p, p, &sum)
149+
result := mod.add(gp, p, p, &sum)
150+
for _, ptr := range mod.work {
151+
gp.typ = gp.ts.Elem(mod.Type(ptr))
152+
sum := 0
153+
p = Loc(uint32(len(mod.locs)))
154+
obj := mod.add(gp, p, p, &sum)
155+
mod.locs[ptr].obj = obj
156+
mod.AddAddressOf(ptr, obj)
157+
}
158+
mod.work = mod.work[:0]
159+
return result
149160
}
150161

151162
func (mod *Model) WithPointer(gp *GenParams) (obj, ptr Loc) {
@@ -180,12 +191,12 @@ func (mod *Model) Cap(c int) {
180191
mod.locs = mod.locs[:c]
181192
}
182193

183-
// p_add adds a root recursively according to ty.
194+
// add adds a root recursively according to ty.
184195
//
185196
// add is responsible for setting the size, parent, class, attrs, typ, and root
186197
// of all added nodes.
187198
//
188-
func (mod *Model) p_add(gp *GenParams, p, r Loc, sum *int) Loc {
199+
func (mod *Model) add(gp *GenParams, p, r Loc, sum *int) Loc {
189200
n := Loc(uint32(len(mod.locs)))
190201
l := loc{
191202
parent: p,
@@ -214,7 +225,7 @@ func (mod *Model) p_add(gp *GenParams, p, r Loc, sum *int) Loc {
214225
elemTy := gp.ts.Elem(gp.typ)
215226
for i := 0; i < m; i++ {
216227
gp.typ = elemTy
217-
mod.p_add(gp, n, r, sum)
228+
mod.add(gp, n, r, sum)
218229
}
219230
case typeset.Struct:
220231
mod.locs = append(mod.locs, l)
@@ -223,7 +234,7 @@ func (mod *Model) p_add(gp *GenParams, p, r Loc, sum *int) Loc {
223234
styp := gp.typ
224235
for i := 0; i < nf; i++ {
225236
_, gp.typ, _ = gp.ts.Field(styp, i)
226-
mod.p_add(gp, n, r, sum)
237+
mod.add(gp, n, r, sum)
227238
}
228239

229240
case typeset.Tuple:
@@ -233,31 +244,34 @@ func (mod *Model) p_add(gp *GenParams, p, r Loc, sum *int) Loc {
233244
ttyp := gp.typ
234245
for i := 0; i < tn; i++ {
235246
_, gp.typ, _ = gp.ts.Field(ttyp, i)
236-
mod.p_add(gp, n, r, sum)
247+
mod.add(gp, n, r, sum)
237248
}
238249
case typeset.Named:
239250
gp.typ = gp.ts.Underlying(gp.typ)
240-
mod.p_add(gp, p, r, sum)
251+
mod.add(gp, p, r, sum)
241252
added = false
242253
case typeset.Func:
243254
mod.locs = append(mod.locs, l)
244255
*sum++
245256
fty := gp.typ
246257
rcvty := gp.ts.Recv(fty)
247258
if rcvty != typeset.NoType {
248-
gp.typ = rcvty
249-
mod.p_add(gp, n, r, sum)
259+
gp.typ = gp.ts.PointerTo(rcvty)
260+
mod.work = append(mod.work, mod.add(gp, n, r, sum))
250261
}
262+
// TBD FreeVars
251263

252264
np := gp.ts.NumParams(fty)
253265
for i := 0; i < np; i++ {
254266
_, gp.typ = gp.ts.Param(fty, i)
255-
mod.p_add(gp, n, r, sum)
267+
gp.typ = gp.ts.PointerTo(gp.typ)
268+
mod.work = append(mod.work, mod.add(gp, n, r, sum))
256269
}
257270
nr := gp.ts.NumResults(fty)
258271
for i := 0; i < nr; i++ {
259272
_, gp.typ = gp.ts.Result(fty, i)
260-
mod.p_add(gp, n, r, sum)
273+
gp.typ = gp.ts.PointerTo(gp.typ)
274+
mod.work = append(mod.work, mod.add(gp, n, r, sum))
261275
}
262276

263277
default:

objects/builder_call.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2021 The pal authors (see AUTHORS)
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package objects
16+
17+
import (
18+
"fmt"
19+
20+
"github.com/go-air/pal/memory"
21+
)
22+
23+
// dst is the memory loc of the result.
24+
// - if f returns a single value, then that
25+
// - otherwise it is a tuple.
26+
//
27+
// args indicate the arguments at the call site.
28+
func (b *Builder) Call(f *Func, dst memory.Loc, args []memory.Loc) {
29+
fmt.Printf("n args %d n params %d\n", len(args), len(f.params))
30+
start := 0
31+
if f.recv != memory.NoLoc {
32+
start = 1
33+
b.AddStore(f.recv, args[0])
34+
}
35+
for i, arg := range args[start:] {
36+
b.AddStore(f.params[i], arg)
37+
}
38+
if dst == memory.NoLoc {
39+
return
40+
}
41+
switch len(f.results) {
42+
case 0:
43+
case 1:
44+
b.AddLoad(dst, f.results[0])
45+
default:
46+
dstTuple := b.omap[dst].(*Tuple)
47+
for i, ret := range f.results {
48+
b.AddLoad(dstTuple.At(i), ret)
49+
}
50+
}
51+
}

ssa2pal/debug.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const (
1919
traceFunc = true
2020
traceParam = false
2121

22-
debugLogModel = true
22+
debugLogModel = false
2323
traceGenValueLoc = false
2424
traceGenExtract = false
2525
traceGenNext = false

ssa2pal/t.go

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626
"sort"
2727

2828
"github.com/go-air/pal/indexing"
29-
"github.com/go-air/pal/internal/plain"
3029
"github.com/go-air/pal/memory"
3130
"github.com/go-air/pal/objects"
3231
"github.com/go-air/pal/results"
@@ -159,13 +158,13 @@ func (p *T) addFuncDecl(name string, fn *ssa.Function) error {
159158
memFn := p.buildr.Func(fn.Signature, name, opaque)
160159

161160
p.vmap[fn] = memFn.Loc()
161+
fmt.Printf("built func %s at %d\n", name, memFn.Loc())
162162

163163
for i, param := range fn.Params {
164+
p.vmap[param] = p.buildr.Memory().Obj(memFn.ParamLoc(i))
164165
if traceParam {
165-
fmt.Printf("setting param %s to %s\n", param, plain.String(memFn.ParamLoc(i)))
166-
166+
fmt.Printf("setting param %s to %s\n", param, p.vmap[param])
167167
}
168-
p.vmap[param] = memFn.ParamLoc(i)
169168
}
170169
// free vars not needed here -- top level func def
171170

@@ -335,6 +334,7 @@ func (p *T) genValueLoc(v ssa.Value) memory.Loc {
335334
rxloc := p.vmap[iter.X]
336335
if rxloc == memory.NoLoc {
337336
rxloc = p.genValueLoc(iter.X)
337+
fmt.Printf("gen value for %s iter.X of next\n", rxloc)
338338
p.buildr.Pos(v.Pos()).Class(memory.Local).Attrs(memory.NoAttrs)
339339
}
340340
mgoty := iter.X.Type().Underlying().(*types.Map)
@@ -408,13 +408,13 @@ func (p *T) genI9nConstraints(fnName string, i9n ssa.Instruction) error {
408408

409409
}
410410
case *ssa.Call:
411-
p.call(i9n.Call)
411+
p.call(i9n.Call, p.vmap[i9n])
412412
case *ssa.ChangeInterface:
413413
case *ssa.ChangeType:
414414
case *ssa.Convert:
415415
case *ssa.DebugRef:
416416
case *ssa.Defer:
417-
p.call(i9n.Call)
417+
p.call(i9n.Call, memory.NoLoc)
418418
case *ssa.Extract: // done in gen locs
419419
case *ssa.Field: // done in gen locs
420420

@@ -439,7 +439,7 @@ func (p *T) genI9nConstraints(fnName string, i9n ssa.Instruction) error {
439439

440440
case *ssa.Go:
441441
// for now, treat as call
442-
p.call(i9n.Call)
442+
p.call(i9n.Call, memory.NoLoc)
443443
case *ssa.If:
444444
case *ssa.Index: // constraints done in gen locs
445445
case *ssa.IndexAddr:
@@ -503,9 +503,10 @@ func (p *T) genI9nConstraints(fnName string, i9n ssa.Instruction) error {
503503
palFn = p.funcs[ssaFn]
504504
// copy results to palFn results...
505505
for i, res := range i9n.Results {
506-
resLoc := palFn.ResultLoc(i)
506+
resptr := palFn.ResultLoc(i)
507+
resobj := p.buildr.Memory().Obj(resptr)
507508
vloc := p.vmap[res]
508-
p.buildr.AddTransfer(resLoc, vloc)
509+
p.buildr.AddTransfer(resobj, vloc)
509510
}
510511

511512
case *ssa.UnOp:
@@ -517,9 +518,10 @@ func (p *T) genI9nConstraints(fnName string, i9n ssa.Instruction) error {
517518
c := p.buildr.Object(p.vmap[i9n.X]).(*objects.Chan)
518519
dst := p.vmap[i9n]
519520
if dst == memory.NoLoc {
520-
panic("no loc for <-")
521+
//panic(fmt.Sprintf("no loc for <- %#v\n", i9n))
522+
} else {
523+
c.Recv(dst, p.buildr.Memory())
521524
}
522-
c.Recv(dst, p.buildr.Memory())
523525

524526
default: // indexing
525527
}
@@ -542,7 +544,7 @@ func (p *T) PkgPath() string {
542544
return p.pass.Pkg.Path()
543545
}
544546

545-
func (p *T) call(c ssa.CallCommon) {
547+
func (p *T) call(c ssa.CallCommon, dst memory.Loc) {
546548
if c.IsInvoke() {
547549
p.invoke(c)
548550
return
@@ -551,7 +553,24 @@ func (p *T) call(c ssa.CallCommon) {
551553
if callee == nil {
552554
return
553555
}
554-
556+
switch fssa := c.Value.(type) {
557+
case *ssa.Function:
558+
floc := p.vmap[fssa]
559+
if floc == memory.NoLoc {
560+
panic("wilma!")
561+
}
562+
fn := p.buildr.Object(floc).(*objects.Func)
563+
fmt.Printf("calling '%s' loc %d\n", fssa.Name(), floc)
564+
args := make([]memory.Loc, len(c.Args))
565+
for i, argVal := range c.Args {
566+
args[i] = p.vmap[argVal]
567+
}
568+
p.buildr.Call(fn, dst, args)
569+
case *ssa.Builtin:
570+
case *ssa.MakeClosure:
571+
default:
572+
// dynamic dispatch
573+
}
555574
}
556575

557576
func (p *T) invoke(c ssa.CallCommon) {

0 commit comments

Comments
 (0)