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