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