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) {
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
53 ir.InitLSym(fn, false)
54 types.CalcSize(fn.Type())
55 a := ssagen.AbiForBodylessFuncStackMap(fn)
56 abiInfo := a.ABIAnalyzeFuncType(fn.Type())
57 if fn.ABI == obj.ABI0 {
58
59
60
61
62 liveness.WriteFuncMap(fn, abiInfo)
63
64 x := ssagen.EmitArgInfo(fn, abiInfo)
65 objw.Global(x, int32(len(x.P)), obj.RODATA|obj.LOCAL)
66 }
67 return
68 }
69
70 errorsBefore := base.Errors()
71
72 todo := []*ir.Func{fn}
73 for len(todo) > 0 {
74 next := todo[len(todo)-1]
75 todo = todo[:len(todo)-1]
76
77 prepareFunc(next)
78 todo = append(todo, next.Closures...)
79 }
80
81 if base.Errors() > errorsBefore {
82 return
83 }
84
85
86
87 compilequeue = append(compilequeue, fn)
88 }
89
90
91
92 func prepareFunc(fn *ir.Func) {
93
94
95
96 ir.InitLSym(fn, true)
97
98
99
100 if staticinit.MapInitToVar != nil {
101 if _, ok := staticinit.MapInitToVar[fn]; ok {
102 ssagen.RegisterMapInitLsym(fn.Linksym())
103 }
104 }
105
106
107 types.CalcSize(fn.Type())
108
109
110
111
112 ssagen.GenWasmExportWrapper(fn)
113
114 ir.CurFunc = fn
115 walk.Walk(fn)
116 ir.CurFunc = nil
117
118 base.Ctxt.DwTextCount++
119 }
120
121
122
123
124 func compileFunctions(profile *pgoir.Profile) {
125 if race.Enabled {
126
127 tmp := make([]*ir.Func, len(compilequeue))
128 perm := rand.Perm(len(compilequeue))
129 for i, v := range perm {
130 tmp[v] = compilequeue[i]
131 }
132 copy(compilequeue, tmp)
133 } else {
134
135
136
137 slices.SortFunc(compilequeue, func(a, b *ir.Func) int {
138 return cmp.Compare(len(b.Body), len(a.Body))
139 })
140 }
141
142
143
144 queue := func(work func(int)) {
145 work(0)
146 }
147
148 if nWorkers := base.Flag.LowerC; nWorkers > 1 {
149
150
151
152 workq := make(chan func(int))
153 done := make(chan int)
154 go func() {
155 ids := make([]int, nWorkers)
156 for i := range ids {
157 ids[i] = i
158 }
159 var pending []func(int)
160 for {
161 select {
162 case work := <-workq:
163 pending = append(pending, work)
164 case id := <-done:
165 ids = append(ids, id)
166 }
167 for len(pending) > 0 && len(ids) > 0 {
168 work := pending[len(pending)-1]
169 id := ids[len(ids)-1]
170 pending = pending[:len(pending)-1]
171 ids = ids[:len(ids)-1]
172 go func() {
173 work(id)
174 done <- id
175 }()
176 }
177 }
178 }()
179 queue = func(work func(int)) {
180 workq <- work
181 }
182 }
183
184 var wg sync.WaitGroup
185 var compile func([]*ir.Func)
186 compile = func(fns []*ir.Func) {
187 wg.Add(len(fns))
188 for _, fn := range fns {
189 fn := fn
190 queue(func(worker int) {
191 ssagen.Compile(fn, worker, profile)
192 compile(fn.Closures)
193 wg.Done()
194 })
195 }
196 }
197
198 types.CalcSizeDisabled = true
199 base.Ctxt.InParallel = true
200
201 compile(compilequeue)
202 compilequeue = nil
203 wg.Wait()
204
205 base.Ctxt.InParallel = false
206 types.CalcSizeDisabled = false
207 }
208
View as plain text