Skip to content

Commit

Permalink
In progress with an update to DCE
Browse files Browse the repository at this point in the history
  • Loading branch information
grantnelson-wf committed Aug 9, 2024
1 parent 75705a6 commit bb30788
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 115 deletions.
2 changes: 1 addition & 1 deletion compiler/decls.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func (fc *funcContext) newFuncDecl(fun *ast.FuncDecl, inst typeparams.Instance)
}

fc.pkgCtx.CollectDCEDeps(d, func() {
d.DeclCode = fc.translateTopLevelFunction(fun, inst)
d.DeclCode = fc.namedFuncContext(inst).translateTopLevelFunction(fun)
})
return d
}
Expand Down
14 changes: 6 additions & 8 deletions compiler/internal/dce/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type Decl interface {
// Collector is a tool to collect dependencies for a declaration
// that'll be used in dead-code elimination (DCE).
type Collector struct {
dependencies map[types.Object]struct{}
dce *Info
}

// CollectDCEDeps captures a list of Go objects (types, functions, etc.)
Expand All @@ -24,23 +24,21 @@ type Collector struct {
// Only one CollectDCEDeps call can be active at a time.
// This will overwrite any previous dependencies collected for the given DCE.
func (c *Collector) CollectDCEDeps(decl Decl, f func()) {
if c.dependencies != nil {
if c.dce != nil {
panic(errors.New(`called CollectDCEDeps inside another CollectDCEDeps call`))
}

c.dependencies = make(map[types.Object]struct{})
defer func() { c.dependencies = nil }()
c.dce = decl.Dce()
defer func() { c.dce = nil }()

f()

decl.Dce().setDeps(c.dependencies)
}

// DeclareDCEDep records that the code that is currently being transpiled
// depends on a given Go object.
func (c *Collector) DeclareDCEDep(o types.Object) {
if c.dependencies == nil {
if c.dce == nil {
return // Dependencies are not being collected.
}
c.dependencies[o] = struct{}{}
c.dce.addDep(o)
}
109 changes: 38 additions & 71 deletions compiler/internal/dce/dce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,43 +75,35 @@ func Test_Collector_Collecting(t *testing.T) {

func Test_Info_SetNameAndDep(t *testing.T) {
tests := []struct {
name string
obj types.Object
want Info // expected Info after SetName
wantDep string // expected dep after addDep
name string
obj types.Object
wantObjFilter string // expected Info after SetName
wantMetFilter string // expected Info after SetName
wantDep string // expected dep after addDep
}{
{
name: `package`,
obj: parseObject(t, `Sarah`,
`package jim
import Sarah "fmt"`),
want: Info{
importPath: `jim`,
objectFilter: `Sarah`,
},
wantDep: `jim.Sarah`,
wantObjFilter: `jim.Sarah`,
wantDep: `jim.Sarah`,
},
{
name: `exposed var`,
obj: parseObject(t, `Toby`,
`package jim
var Toby float64`),
want: Info{
importPath: `jim`,
objectFilter: `Toby`,
},
wantDep: `jim.Toby`,
wantObjFilter: `jim.Toby`,
wantDep: `jim.Toby`,
},
{
name: `exposed const`,
obj: parseObject(t, `Ludo`,
`package jim
const Ludo int = 42`),
want: Info{
importPath: `jim`,
objectFilter: `Ludo`,
},
wantDep: `jim.Ludo`,
wantObjFilter: `jim.Ludo`,
wantDep: `jim.Ludo`,
},
{
name: `label`,
Expand All @@ -125,92 +117,68 @@ func Test_Info_SetNameAndDep(t *testing.T) {
goto Gobo
}
}`),
want: Info{
importPath: `jim`,
objectFilter: `Gobo`,
},
wantDep: `jim.Gobo`,
wantObjFilter: `jim.Gobo`,
wantDep: `jim.Gobo`,
},
{
name: `exposed specific type`,
obj: parseObject(t, `Jen`,
`package jim
type Jen struct{}`),
want: Info{
importPath: `jim`,
objectFilter: `Jen`,
},
wantDep: `jim.Jen`,
wantObjFilter: `jim.Jen`,
wantDep: `jim.Jen`,
},
{
name: `exposed generic type`,
obj: parseObject(t, `Henson`,
`package jim
type Henson[T comparable] struct{}`),
want: Info{
importPath: `jim`,
objectFilter: `Henson`,
},
wantDep: `jim.Henson`,
wantObjFilter: `jim.Henson`,
wantDep: `jim.Henson`,
},
{
name: `exposed specific function`,
obj: parseObject(t, `Jareth`,
`package jim
func Jareth() {}`),
want: Info{
importPath: `jim`,
objectFilter: `Jareth`,
},
wantDep: `jim.Jareth`,
wantObjFilter: `jim.Jareth`,
wantDep: `jim.Jareth`,
},
{
name: `exposed generic function`,
obj: parseObject(t, `Didymus`,
`package jim
func Didymus[T comparable]() {}`),
want: Info{
importPath: `jim`,
objectFilter: `Didymus`,
},
wantDep: `jim.Didymus`,
wantObjFilter: `jim.Didymus`,
wantDep: `jim.Didymus`,
},
{
name: `exposed specific method`,
obj: parseObject(t, `Kira`,
`package jim
type Fizzgig string
func (f Fizzgig) Kira() {}`),
want: Info{
importPath: `jim`,
objectFilter: `Fizzgig`,
},
wantDep: `jim.Kira~`,
wantObjFilter: `jim.Fizzgig`,
wantDep: `jim.Kira~`,
},
{
name: `unexposed specific method`,
obj: parseObject(t, `frank`,
`package jim
type Aughra int
func (a Aughra) frank() {}`),
want: Info{
importPath: `jim`,
objectFilter: `Aughra`,
methodFilter: `frank~`,
},
wantDep: `jim.frank~`,
wantObjFilter: `jim.Aughra`,
wantMetFilter: `jim.frank~`,
wantDep: `jim.frank~`,
},
{
name: `specific method on unexposed type`,
obj: parseObject(t, `Red`,
`package jim
type wembley struct{}
func (w wembley) Red() {}`),
want: Info{
importPath: `jim`,
objectFilter: `wembley`,
},
wantDep: `jim.Red~`,
wantObjFilter: `jim.wembley`,
wantDep: `jim.Red~`,
},
}

Expand All @@ -223,26 +191,25 @@ func Test_Info_SetNameAndDep(t *testing.T) {
t.Log(`object:`, types.ObjectString(tt.obj, nil))

d.Dce().SetName(tt.obj)
equal(t, d.Dce().unnamed(), tt.want.unnamed())
equal(t, d.Dce().importPath, tt.want.importPath)
equal(t, d.Dce().objectFilter, tt.want.objectFilter)
equal(t, d.Dce().methodFilter, tt.want.methodFilter)
equal(t, d.Dce().String(), tt.want.String())
equal(t, d.Dce().unnamed(), false)
objectFilter, methodFilter := d.Dce().getInfoNames()
equal(t, objectFilter, tt.wantObjFilter)
equal(t, methodFilter, tt.wantMetFilter)
})
}
})

t.Run(`addDep`, func(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
d := &testDecl{}
d1 := &testDecl{}
t.Log(`object:`, types.ObjectString(tt.obj, nil))

d.Dce().setDeps(map[types.Object]struct{}{
tt.obj: {},
})
equal(t, len(d.Dce().deps), 1)
equal(t, d.Dce().deps[0], tt.wantDep)
d1.Dce().addDep(tt.obj)
equal(t, len(d1.Dce().deps), 1)
depNames := d1.Dce().getDepNames()
equal(t, len(depNames), 1)
equal(t, depNames[0], tt.wantDep)
})
}
})
Expand Down
56 changes: 25 additions & 31 deletions compiler/internal/dce/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,8 @@ type Info struct {
// obj is the Go object the declaration this DCE is for.
obj types.Object

// importPath is the package path of the package the declaration is in.
importPath string

// Symbol's identifier used by the dead-code elimination logic, not including
// package path. If empty, the symbol is assumed to be alive and will not be
// eliminated. For methods it is the same as its receiver type identifier.
objectFilter string

// The second part of the identified used by dead-code elimination for methods.
// Empty for other types of symbols.
methodFilter string

// deps is the set of DCE info objects that this DCE depends on.
deps map[*Info]struct{}
// deps is the set of Go objects that this DCE depends on.
deps map[types.Object]struct{}
}

// String gets a human-readable representation of the DCE info.
Expand All @@ -45,17 +33,19 @@ func (d *Info) String() string {
if d.unnamed() {
tags += `[unnamed] `
}
fullName := d.importPath + `.` + d.objectFilter
if len(d.methodFilter) > 0 {
fullName += `.` + d.methodFilter
objectName, methodName := d.getInfoNames()
fullName := objectName
if len(methodName) > 0 {
objectName += ` &` + methodName
}
return tags + fullName + ` -> [` + strings.Join(d.deps, `, `) + `]`
depNames := `[` + strings.Join(d.getDepNames(), `, `) + `]`
return tags + fullName + ` -> ` + depNames
}

// unnamed returns true if SetName has not been called for this declaration.
// This indicates that the DCE is not initialized.
func (d *Info) unnamed() bool {
return d.objectFilter == `` && d.methodFilter == ``
return d.obj == nil
}

// isAlive returns true if the declaration is marked as alive.
Expand All @@ -80,23 +70,33 @@ func (d *Info) SetName(o types.Object) {
if !d.unnamed() {
panic(fmt.Errorf(`may only set the name once for %s`, d.String()))
}
d.obj = o
}

// addDep adds a declaration dependency for the declaration this
// DCE info is attached to.
func (d *Info) addDep(dep types.Object) {
d.deps[dep] = struct{}{}
}

d.importPath = o.Pkg().Path()
func (d *Info) getInfoNames() (objectFilter, methodFilter string) {
o := d.obj
importPath := o.Pkg().Path()
if typesutil.IsMethod(o) {
recv := typesutil.RecvType(o.Type().(*types.Signature)).Obj()
d.objectFilter = recv.Name()
objectFilter = importPath + `.` + recv.Name()
if !o.Exported() {
d.methodFilter = o.Name() + `~`
methodFilter = importPath + `.` + o.Name() + `~`
}
} else {
d.objectFilter = o.Name()
objectFilter = importPath + `.` + o.Name()
}
return
}

func (d *Info) getDepNames() []string {
depNames := make([]string, 0, len(d.deps))
for dep := range d.deps {
o := dep.obj
for o := range d.deps {
qualifiedName := o.Pkg().Path() + "." + o.Name()
if typesutil.IsMethod(o) {
qualifiedName += "~"
Expand All @@ -106,9 +106,3 @@ func (d *Info) getDepNames() []string {
sort.Strings(depNames)
return depNames
}

// addDep adds a declaration dependency for the declaration this
// DCE info is attached to.
func (d *Info) addDep(dep *Info) {
d.deps[dep] = struct{}{}
}
9 changes: 5 additions & 4 deletions compiler/internal/dce/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ func (s *Selector[D]) Include(decl D, implementsLink bool) {

info := &declInfo[D]{decl: decl}

if dce.objectFilter != `` {
info.objectFilter = dce.importPath + `.` + dce.objectFilter
objectFilter, methodFilter := dce.getInfoNames()
if objectFilter != `` {
info.objectFilter = objectFilter
s.byFilter[info.objectFilter] = append(s.byFilter[info.objectFilter], info)
}

if dce.methodFilter != `` {
info.methodFilter = dce.importPath + `.` + dce.methodFilter
if methodFilter != `` {
info.methodFilter = methodFilter
s.byFilter[info.methodFilter] = append(s.byFilter[info.methodFilter], info)
}
}
Expand Down

0 comments on commit bb30788

Please sign in to comment.