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
119
120
121
122 func compileFunctions(profile *pgoir.Profile) {
123 if race.Enabled {
124
125 tmp := make([]*ir.Func, len(compilequeue))
126 perm := rand.Perm(len(compilequeue))
127 for i, v := range perm {
128 tmp[v] = compilequeue[i]
129 }
130 copy(compilequeue, tmp)
131 } else {
132
133
134
135 slices.SortFunc(compilequeue, func(a, b *ir.Func) int {
136 return cmp.Compare(len(b.Body), len(a.Body))
137 })
138 }
139
140
141
142 queue := func(work func(int)) {
143 work(0)
144 }
145
146 if nWorkers := base.Flag.LowerC; nWorkers > 1 {
147
148
149
150 workq := make(chan func(int))
151 done := make(chan int)
152 go func() {
153 ids := make([]int, nWorkers)
154 for i := range ids {
155 ids[i] = i
156 }
157 var pending []func(int)
158 for {
159 select {
160 case work := <-workq:
161 pending = append(pending, work)
162 case id := <-done:
163 ids = append(ids, id)
164 }
165 for len(pending) > 0 && len(ids) > 0 {
166 work := pending[len(pending)-1]
167 id := ids[len(ids)-1]
168 pending = pending[:len(pending)-1]
169 ids = ids[:len(ids)-1]
170 go func() {
171 work(id)
172 done <- id
173 }()
174 }
175 }
176 }()
177 queue = func(work func(int)) {
178 workq <- work
179 }
180 }
181
182 var wg sync.WaitGroup
183 var compile func([]*ir.Func)
184 compile = func(fns []*ir.Func) {
185 wg.Add(len(fns))
186 for _, fn := range fns {
187 fn := fn
188 queue(func(worker int) {
189 ssagen.Compile(fn, worker, profile)
190 compile(fn.Closures)
191 wg.Done()
192 })
193 }
194 }
195
196 types.CalcSizeDisabled = true
197 base.Ctxt.InParallel = true
198
199 compile(compilequeue)
200 compilequeue = nil
201 wg.Wait()
202
203 base.Ctxt.InParallel = false
204 types.CalcSizeDisabled = false
205 }
206
View as plain text