1
2
3
4
5 package gc
6
7 import (
8 "internal/race"
9 "math/rand"
10 "sort"
11 "sync"
12
13 "cmd/compile/internal/base"
14 "cmd/compile/internal/ir"
15 "cmd/compile/internal/liveness"
16 "cmd/compile/internal/objw"
17 "cmd/compile/internal/pgoir"
18 "cmd/compile/internal/ssagen"
19 "cmd/compile/internal/staticinit"
20 "cmd/compile/internal/types"
21 "cmd/compile/internal/walk"
22 "cmd/internal/obj"
23 )
24
25
26
27 var (
28 compilequeue []*ir.Func
29 )
30
31 func enqueueFunc(fn *ir.Func) {
32 if ir.CurFunc != nil {
33 base.FatalfAt(fn.Pos(), "enqueueFunc %v inside %v", fn, ir.CurFunc)
34 }
35
36 if ir.FuncName(fn) == "_" {
37
38
39 return
40 }
41
42
43 if fn.IsDeadcodeClosure() {
44 return
45 }
46
47 if clo := fn.OClosure; clo != nil && !ir.IsTrivialClosure(clo) {
48 return
49 }
50
51 if ssagen.CreateWasmImportWrapper(fn) {
52 return
53 }
54
55 if len(fn.Body) == 0 {
56
57 ir.InitLSym(fn, false)
58 types.CalcSize(fn.Type())
59 a := ssagen.AbiForBodylessFuncStackMap(fn)
60 abiInfo := a.ABIAnalyzeFuncType(fn.Type())
61 liveness.WriteFuncMap(fn, abiInfo)
62 if fn.ABI == obj.ABI0 {
63 x := ssagen.EmitArgInfo(fn, abiInfo)
64 objw.Global(x, int32(len(x.P)), obj.RODATA|obj.LOCAL)
65 }
66 return
67 }
68
69 errorsBefore := base.Errors()
70
71 todo := []*ir.Func{fn}
72 for len(todo) > 0 {
73 next := todo[len(todo)-1]
74 todo = todo[:len(todo)-1]
75
76 prepareFunc(next)
77 todo = append(todo, next.Closures...)
78 }
79
80 if base.Errors() > errorsBefore {
81 return
82 }
83
84
85
86 compilequeue = append(compilequeue, fn)
87 }
88
89
90
91 func prepareFunc(fn *ir.Func) {
92
93
94
95 ir.InitLSym(fn, true)
96
97
98
99 if staticinit.MapInitToVar != nil {
100 if _, ok := staticinit.MapInitToVar[fn]; ok {
101 ssagen.RegisterMapInitLsym(fn.Linksym())
102 }
103 }
104
105
106 types.CalcSize(fn.Type())
107
108 ir.CurFunc = fn
109 walk.Walk(fn)
110 ir.CurFunc = nil
111 }
112
113
114
115
116 func compileFunctions(profile *pgoir.Profile) {
117 if race.Enabled {
118
119 tmp := make([]*ir.Func, len(compilequeue))
120 perm := rand.Perm(len(compilequeue))
121 for i, v := range perm {
122 tmp[v] = compilequeue[i]
123 }
124 copy(compilequeue, tmp)
125 } else {
126
127
128
129 sort.Slice(compilequeue, func(i, j int) bool {
130 return len(compilequeue[i].Body) > len(compilequeue[j].Body)
131 })
132 }
133
134
135
136 queue := func(work func(int)) {
137 work(0)
138 }
139
140 if nWorkers := base.Flag.LowerC; nWorkers > 1 {
141
142
143
144 workq := make(chan func(int))
145 done := make(chan int)
146 go func() {
147 ids := make([]int, nWorkers)
148 for i := range ids {
149 ids[i] = i
150 }
151 var pending []func(int)
152 for {
153 select {
154 case work := <-workq:
155 pending = append(pending, work)
156 case id := <-done:
157 ids = append(ids, id)
158 }
159 for len(pending) > 0 && len(ids) > 0 {
160 work := pending[len(pending)-1]
161 id := ids[len(ids)-1]
162 pending = pending[:len(pending)-1]
163 ids = ids[:len(ids)-1]
164 go func() {
165 work(id)
166 done <- id
167 }()
168 }
169 }
170 }()
171 queue = func(work func(int)) {
172 workq <- work
173 }
174 }
175
176 var wg sync.WaitGroup
177 var compile func([]*ir.Func)
178 compile = func(fns []*ir.Func) {
179 wg.Add(len(fns))
180 for _, fn := range fns {
181 fn := fn
182 queue(func(worker int) {
183 ssagen.Compile(fn, worker, profile)
184 compile(fn.Closures)
185 wg.Done()
186 })
187 }
188 }
189
190 types.CalcSizeDisabled = true
191 base.Ctxt.InParallel = true
192
193 compile(compilequeue)
194 compilequeue = nil
195 wg.Wait()
196
197 base.Ctxt.InParallel = false
198 types.CalcSizeDisabled = false
199 }
200
View as plain text