1
2
3
4
5 package ssa
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import (
23 "fmt"
24
25 "go/token"
26 "go/types"
27 )
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 func makeWrapper(prog *Program, sel *selection, cr *creator) *Function {
46 obj := sel.obj.(*types.Func)
47 sig := sel.typ.(*types.Signature)
48
49 var recv *types.Var
50 name := obj.Name()
51 var description string
52 var start int
53 if sel.kind == types.MethodExpr {
54 name += "$thunk"
55 description = "thunk"
56 recv = sig.Params().At(0)
57 start = 1
58 } else {
59 description = "wrapper"
60 recv = sig.Recv()
61 }
62
63 description = fmt.Sprintf("%s for %s", description, sel.obj)
64 if prog.mode&LogSource != 0 {
65 defer logStack("make %s to (%s)", description, recv.Type())()
66 }
67 fn := &Function{
68 name: name,
69 method: sel,
70 object: obj,
71 Signature: sig,
72 Synthetic: description,
73 Prog: prog,
74 pos: obj.Pos(),
75 info: nil,
76 }
77 cr.Add(fn)
78 fn.startBody()
79 fn.addSpilledParam(recv)
80 createParams(fn, start)
81
82 indices := sel.index
83
84 var v Value = fn.Locals[0]
85 if isPointer(sel.recv) {
86 v = emitLoad(fn, v)
87
88
89
90 if len(indices) == 1 && !isPointer(recvType(obj)) {
91 var c Call
92 c.Call.Value = &Builtin{
93 name: "ssa:wrapnilchk",
94 sig: types.NewSignature(nil,
95 types.NewTuple(anonVar(sel.recv), anonVar(tString), anonVar(tString)),
96 types.NewTuple(anonVar(sel.recv)), false),
97 }
98 c.Call.Args = []Value{
99 v,
100 stringConst(deref(sel.recv).String()),
101 stringConst(sel.obj.Name()),
102 }
103 c.setType(v.Type())
104 v = fn.emit(&c)
105 }
106 }
107
108
109
110
111
112
113
114
115
116 v = emitImplicitSelections(fn, v, indices[:len(indices)-1], token.NoPos)
117
118
119
120
121
122 var c Call
123 if r := recvType(obj); !types.IsInterface(r) {
124 if !isPointer(r) {
125 v = emitLoad(fn, v)
126 }
127 callee := prog.originFunc(obj)
128 if callee.typeparams.Len() > 0 {
129 callee = prog.lookupOrCreateInstance(callee, receiverTypeArgs(obj), cr)
130 }
131 c.Call.Value = callee
132 c.Call.Args = append(c.Call.Args, v)
133 } else {
134 c.Call.Method = obj
135 c.Call.Value = emitLoad(fn, v)
136 }
137 for _, arg := range fn.Params[1:] {
138 c.Call.Args = append(c.Call.Args, arg)
139 }
140 emitTailCall(fn, &c)
141 fn.finishBody()
142 fn.done()
143 return fn
144 }
145
146
147
148
149 func createParams(fn *Function, start int) {
150 tparams := fn.Signature.Params()
151 for i, n := start, tparams.Len(); i < n; i++ {
152 fn.addParamObj(tparams.At(i))
153 }
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 func makeBound(prog *Program, obj *types.Func, cr *creator) *Function {
183 targs := receiverTypeArgs(obj)
184 key := boundsKey{obj, prog.canon.List(targs)}
185
186 prog.methodsMu.Lock()
187 defer prog.methodsMu.Unlock()
188 fn, ok := prog.bounds[key]
189 if !ok {
190 description := fmt.Sprintf("bound method wrapper for %s", obj)
191 if prog.mode&LogSource != 0 {
192 defer logStack("%s", description)()
193 }
194 fn = &Function{
195 name: obj.Name() + "$bound",
196 object: obj,
197 Signature: changeRecv(obj.Type().(*types.Signature), nil),
198 Synthetic: description,
199 Prog: prog,
200 pos: obj.Pos(),
201 info: nil,
202 }
203 cr.Add(fn)
204
205 fv := &FreeVar{name: "recv", typ: recvType(obj), parent: fn}
206 fn.FreeVars = []*FreeVar{fv}
207 fn.startBody()
208 createParams(fn, 0)
209 var c Call
210
211 if !types.IsInterface(recvType(obj)) {
212 callee := prog.originFunc(obj)
213 if callee.typeparams.Len() > 0 {
214 callee = prog.lookupOrCreateInstance(callee, targs, cr)
215 }
216 c.Call.Value = callee
217 c.Call.Args = []Value{fv}
218 } else {
219 c.Call.Method = obj
220 c.Call.Value = fv
221 }
222 for _, arg := range fn.Params {
223 c.Call.Args = append(c.Call.Args, arg)
224 }
225 emitTailCall(fn, &c)
226 fn.finishBody()
227 fn.done()
228
229 prog.bounds[key] = fn
230 }
231 return fn
232 }
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258 func makeThunk(prog *Program, sel *selection, cr *creator) *Function {
259 if sel.kind != types.MethodExpr {
260 panic(sel)
261 }
262
263
264 canonRecv := prog.canon.Type(sel.recv)
265 key := selectionKey{
266 kind: sel.kind,
267 recv: canonRecv,
268 obj: sel.obj,
269 index: fmt.Sprint(sel.index),
270 indirect: sel.indirect,
271 }
272
273 prog.methodsMu.Lock()
274 defer prog.methodsMu.Unlock()
275
276 fn, ok := prog.thunks[key]
277 if !ok {
278 fn = makeWrapper(prog, sel, cr)
279 if fn.Signature.Recv() != nil {
280 panic(fn)
281 }
282 prog.thunks[key] = fn
283 }
284 return fn
285 }
286
287 func changeRecv(s *types.Signature, recv *types.Var) *types.Signature {
288 return types.NewSignature(recv, s.Params(), s.Results(), s.Variadic())
289 }
290
291
292 type selectionKey struct {
293 kind types.SelectionKind
294 recv types.Type
295 obj types.Object
296 index string
297 indirect bool
298 }
299
300
301 type boundsKey struct {
302 obj types.Object
303 inst *typeList
304 }
305
306
307
308 type selection struct {
309 kind types.SelectionKind
310 recv types.Type
311 typ types.Type
312 obj types.Object
313 index []int
314 indirect bool
315 }
316
317 func toSelection(sel *types.Selection) *selection {
318 return &selection{
319 kind: sel.Kind(),
320 recv: sel.Recv(),
321 typ: sel.Type(),
322 obj: sel.Obj(),
323 index: sel.Index(),
324 indirect: sel.Indirect(),
325 }
326 }
327
328
329
330
331
332
333 func buildInstantiationWrapper(fn *Function) {
334 orig := fn.topLevelOrigin
335 sig := fn.Signature
336
337 fn.startBody()
338 if sig.Recv() != nil {
339 fn.addParamObj(sig.Recv())
340 }
341 createParams(fn, 0)
342
343
344
345
346 var c Call
347 c.Call.Value = orig
348 if res := orig.Signature.Results(); res.Len() == 1 {
349 c.typ = res.At(0).Type()
350 } else {
351 c.typ = res
352 }
353
354
355
356 argOffset := 0
357 for i, arg := range fn.Params {
358 var typ types.Type
359 if i == 0 && sig.Recv() != nil {
360 typ = orig.Signature.Recv().Type()
361 argOffset = 1
362 } else {
363 typ = orig.Signature.Params().At(i - argOffset).Type()
364 }
365 c.Call.Args = append(c.Call.Args, emitTypeCoercion(fn, arg, typ))
366 }
367
368 results := fn.emit(&c)
369 var ret Return
370 switch res := sig.Results(); res.Len() {
371 case 0:
372
373 case 1:
374 ret.Results = []Value{emitTypeCoercion(fn, results, res.At(0).Type())}
375 default:
376 for i := 0; i < sig.Results().Len(); i++ {
377 v := emitExtract(fn, results, i)
378 ret.Results = append(ret.Results, emitTypeCoercion(fn, v, res.At(i).Type()))
379 }
380 }
381
382 fn.emit(&ret)
383 fn.currentBlock = nil
384
385 fn.finishBody()
386 }
387
View as plain text