1
2
3
4
5 package walk
6
7 import (
8 "encoding/binary"
9 "go/constant"
10
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/reflectdata"
14 "cmd/compile/internal/ssagen"
15 "cmd/compile/internal/typecheck"
16 "cmd/compile/internal/types"
17 "cmd/internal/sys"
18 )
19
20
21 func walkConv(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
22 n.X = walkExpr(n.X, init)
23 if n.Op() == ir.OCONVNOP && n.Type() == n.X.Type() {
24 return n.X
25 }
26 if n.Op() == ir.OCONVNOP && ir.ShouldCheckPtr(ir.CurFunc, 1) {
27 if n.Type().IsUnsafePtr() && n.X.Type().IsUintptr() {
28 return walkCheckPtrArithmetic(n, init)
29 }
30 }
31 param, result := rtconvfn(n.X.Type(), n.Type())
32 if param == types.Txxx {
33 return n
34 }
35 fn := types.BasicTypeNames[param] + "to" + types.BasicTypeNames[result]
36 return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type())
37 }
38
39
40 func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
41
42 n.X = walkExpr(n.X, init)
43
44 fromType := n.X.Type()
45 toType := n.Type()
46 if !fromType.IsInterface() && !ir.IsBlank(ir.CurFunc.Nname) {
47
48 if fromType.HasShape() {
49
50
51
52
53 } else {
54 reflectdata.MarkTypeUsedInInterface(fromType, ir.CurFunc.LSym)
55 }
56 }
57
58 if !fromType.IsInterface() {
59 typeWord := reflectdata.ConvIfaceTypeWord(base.Pos, n)
60 l := ir.NewBinaryExpr(base.Pos, ir.OMAKEFACE, typeWord, dataWord(n, init))
61 l.SetType(toType)
62 l.SetTypecheck(n.Typecheck())
63 return l
64 }
65 if fromType.IsEmptyInterface() {
66 base.Fatalf("OCONVIFACE can't operate on an empty interface")
67 }
68
69
70 c := typecheck.TempAt(base.Pos, ir.CurFunc, fromType)
71 init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
72
73 if toType.IsEmptyInterface() {
74
75
76
77
78
79
80
81
82
83 itab := ir.NewUnaryExpr(base.Pos, ir.OITAB, c)
84 itab.SetType(types.Types[types.TUINTPTR].PtrTo())
85 itab.SetTypecheck(1)
86 data := ir.NewUnaryExpr(n.Pos(), ir.OIDATA, c)
87 data.SetType(types.Types[types.TUINT8].PtrTo())
88 data.SetTypecheck(1)
89
90 typeWord := typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(types.Types[types.TUINT8]))
91 init.Append(ir.NewAssignStmt(base.Pos, typeWord, typecheck.Conv(typecheck.Conv(itab, types.Types[types.TUNSAFEPTR]), typeWord.Type())))
92 nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, typeWord, typecheck.NodNil())), nil, nil)
93 nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, typeWord, itabType(typeWord))}
94 init.Append(nif)
95
96
97
98 e := ir.NewBinaryExpr(base.Pos, ir.OMAKEFACE, typeWord, data)
99 e.SetType(toType)
100 e.SetTypecheck(1)
101 return e
102 }
103
104
105
106 var rhs ir.Node
107 if n.TypeWord == nil || n.TypeWord.Op() == ir.OADDR && n.TypeWord.(*ir.AddrExpr).X.Op() == ir.OLINKSYMOFFSET {
108
109 ta := ir.NewTypeAssertExpr(base.Pos, c, toType)
110 ta.SetOp(ir.ODOTTYPE2)
111
112 ta.Descriptor = makeTypeAssertDescriptor(toType, true)
113 rhs = ta
114 } else {
115 ta := ir.NewDynamicTypeAssertExpr(base.Pos, ir.ODYNAMICDOTTYPE2, c, n.TypeWord)
116 rhs = ta
117 }
118 rhs.SetType(toType)
119 rhs.SetTypecheck(1)
120
121 res := typecheck.TempAt(base.Pos, ir.CurFunc, toType)
122 as := ir.NewAssignListStmt(base.Pos, ir.OAS2DOTTYPE, []ir.Node{res, ir.BlankNode}, []ir.Node{rhs})
123 init.Append(as)
124 return res
125 }
126
127
128
129 func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
130 pos, n := conv.Pos(), conv.X
131 fromType := n.Type()
132
133
134 if types.IsDirectIface(fromType) {
135 return n
136 }
137
138 isInteger := fromType.IsInteger()
139 isBool := fromType.IsBoolean()
140 if sc := fromType.SoleComponent(); sc != nil {
141 isInteger = sc.IsInteger()
142 isBool = sc.IsBoolean()
143 }
144
145 var value ir.Node
146 switch {
147 case fromType.Size() == 0:
148
149 cheapExpr(n, init)
150 value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR])
151 case isBool || fromType.Size() == 1 && isInteger:
152
153
154 n = cheapExpr(n, init)
155 n = soleComponent(init, n)
156
157 index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(base.Pos, 3))
158 if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian {
159 index = ir.NewBinaryExpr(base.Pos, ir.OADD, index, ir.NewInt(base.Pos, 7))
160 }
161
162
163 staticuint64s := ir.NewLinksymExpr(base.Pos, ir.Syms.Staticuint64s, types.NewArray(types.Types[types.TUINT8], 256*8))
164 xe := ir.NewIndexExpr(base.Pos, staticuint64s, index)
165 xe.SetBounded(true)
166 value = xe
167 case n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PEXTERN && n.(*ir.Name).Readonly():
168
169 value = n
170 case conv.Esc() == ir.EscNone && fromType.Size() <= 1024:
171
172 value = typecheck.TempAt(base.Pos, ir.CurFunc, fromType)
173 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n)))
174 }
175 if value != nil {
176
177 return typecheck.Expr(typecheck.NodAddr(value))
178 }
179
180
181 fnname, argType, needsaddr := dataWordFuncName(fromType)
182 var fn *ir.Name
183
184 var args []ir.Node
185 if needsaddr {
186
187
188
189
190
191
192 if !ir.IsAddressable(n) {
193 n = copyExpr(n, fromType, init)
194 }
195 fn = typecheck.LookupRuntime(fnname, fromType)
196 args = []ir.Node{reflectdata.ConvIfaceSrcRType(base.Pos, conv), typecheck.NodAddr(n)}
197 } else {
198
199
200 fn = typecheck.LookupRuntime(fnname)
201 var arg ir.Node
202 switch {
203 case fromType == argType:
204
205 arg = n
206 case fromType.Kind() == argType.Kind(),
207 fromType.IsPtrShaped() && argType.IsPtrShaped():
208
209
210 arg = ir.NewConvExpr(pos, ir.OCONVNOP, argType, n)
211 case fromType.IsInteger() && argType.IsInteger():
212
213 arg = ir.NewConvExpr(pos, ir.OCONV, argType, n)
214 default:
215
216 arg = copyExpr(n, fromType, init)
217 var addr ir.Node = typecheck.NodAddr(arg)
218 addr = ir.NewConvExpr(pos, ir.OCONVNOP, argType.PtrTo(), addr)
219 arg = ir.NewStarExpr(pos, addr)
220 arg.SetType(argType)
221 }
222 args = []ir.Node{arg}
223 }
224 call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
225 call.Args = args
226 return safeExpr(walkExpr(typecheck.Expr(call), init), init)
227 }
228
229
230 func walkBytesRunesToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
231 a := typecheck.NodNil()
232 if n.Esc() == ir.EscNone {
233
234 a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
235 }
236 if n.Op() == ir.ORUNES2STR {
237
238 return mkcall("slicerunetostring", n.Type(), init, a, n.X)
239 }
240
241 n.X = cheapExpr(n.X, init)
242 ptr, len := backingArrayPtrLen(n.X)
243 return mkcall("slicebytetostring", n.Type(), init, a, ptr, len)
244 }
245
246
247 func walkBytesToStringTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
248 n.X = walkExpr(n.X, init)
249 if !base.Flag.Cfg.Instrumenting {
250
251
252 return n
253 }
254
255 n.X = cheapExpr(n.X, init)
256 ptr, len := backingArrayPtrLen(n.X)
257 return mkcall("slicebytetostringtmp", n.Type(), init, ptr, len)
258 }
259
260
261 func walkRuneToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
262 a := typecheck.NodNil()
263 if n.Esc() == ir.EscNone {
264 a = stackBufAddr(4, types.Types[types.TUINT8])
265 }
266
267 return mkcall("intstring", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TINT64]))
268 }
269
270
271 func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
272 s := n.X
273
274 if expr, ok := s.(*ir.AddStringExpr); ok {
275 return walkAddString(n.Type(), expr, init)
276 }
277
278 if ir.IsConst(s, constant.String) {
279 sc := ir.StringVal(s)
280
281
282 t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
283 var a ir.Node
284 if n.Esc() == ir.EscNone && len(sc) <= int(ir.MaxImplicitStackVarSize) {
285 a = stackBufAddr(t.NumElem(), t.Elem())
286 } else {
287 types.CalcSize(t)
288 a = ir.NewUnaryExpr(base.Pos, ir.ONEW, nil)
289 a.SetType(types.NewPtr(t))
290 a.SetTypecheck(1)
291 a.MarkNonNil()
292 }
293 p := typecheck.TempAt(base.Pos, ir.CurFunc, t.PtrTo())
294 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, p, a)))
295
296
297 if len(sc) > 0 {
298 sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
299 sptr.SetBounded(true)
300 as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(sptr, t.PtrTo())))
301 appendWalkStmt(init, as)
302 }
303
304
305 slice := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p, nil, nil, nil)
306 slice.SetType(n.Type())
307 slice.SetTypecheck(1)
308 return walkExpr(slice, init)
309 }
310
311 a := typecheck.NodNil()
312 if n.Esc() == ir.EscNone {
313
314 a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
315 }
316
317 return mkcall("stringtoslicebyte", n.Type(), init, a, typecheck.Conv(s, types.Types[types.TSTRING]))
318 }
319
320
321 func walkStringToBytesTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
322
323
324
325
326
327
328
329 n.X = walkExpr(n.X, init)
330 return n
331 }
332
333
334 func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
335 a := typecheck.NodNil()
336 if n.Esc() == ir.EscNone {
337
338 a = stackBufAddr(tmpstringbufsize, types.Types[types.TINT32])
339 }
340
341 return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
342 }
343
344
345
346
347
348 func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
349 if from.IsInterface() {
350 base.Fatalf("can only handle non-interfaces")
351 }
352 switch {
353 case from.Size() == 2 && uint8(from.Alignment()) == 2:
354 return "convT16", types.Types[types.TUINT16], false
355 case from.Size() == 4 && uint8(from.Alignment()) == 4 && !from.HasPointers():
356 return "convT32", types.Types[types.TUINT32], false
357 case from.Size() == 8 && uint8(from.Alignment()) == uint8(types.Types[types.TUINT64].Alignment()) && !from.HasPointers():
358 return "convT64", types.Types[types.TUINT64], false
359 }
360 if sc := from.SoleComponent(); sc != nil {
361 switch {
362 case sc.IsString():
363 return "convTstring", types.Types[types.TSTRING], false
364 case sc.IsSlice():
365 return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false
366 }
367 }
368
369 if from.HasPointers() {
370 return "convT", types.Types[types.TUNSAFEPTR], true
371 }
372 return "convTnoptr", types.Types[types.TUNSAFEPTR], true
373 }
374
375
376
377
378
379
380 func rtconvfn(src, dst *types.Type) (param, result types.Kind) {
381 if ssagen.Arch.SoftFloat {
382 return types.Txxx, types.Txxx
383 }
384
385 switch ssagen.Arch.LinkArch.Family {
386 case sys.ARM, sys.MIPS:
387 if src.IsFloat() {
388 switch dst.Kind() {
389 case types.TINT64, types.TUINT64:
390 return types.TFLOAT64, dst.Kind()
391 }
392 }
393 if dst.IsFloat() {
394 switch src.Kind() {
395 case types.TINT64, types.TUINT64:
396 return src.Kind(), dst.Kind()
397 }
398 }
399
400 case sys.I386:
401 if src.IsFloat() {
402 switch dst.Kind() {
403 case types.TINT64, types.TUINT64:
404 return types.TFLOAT64, dst.Kind()
405 case types.TUINT32, types.TUINT, types.TUINTPTR:
406 return types.TFLOAT64, types.TUINT32
407 }
408 }
409 if dst.IsFloat() {
410 switch src.Kind() {
411 case types.TINT64, types.TUINT64:
412 return src.Kind(), dst.Kind()
413 case types.TUINT32, types.TUINT, types.TUINTPTR:
414 return types.TUINT32, types.TFLOAT64
415 }
416 }
417 }
418 return types.Txxx, types.Txxx
419 }
420
421 func soleComponent(init *ir.Nodes, n ir.Node) ir.Node {
422 if n.Type().SoleComponent() == nil {
423 return n
424 }
425
426 for {
427 switch {
428 case n.Type().IsStruct():
429 if n.Type().Field(0).Sym.IsBlank() {
430
431 n = typecheck.TempAt(base.Pos, ir.CurFunc, n.Type().Field(0).Type)
432 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n, nil))
433 continue
434 }
435 n = typecheck.DotField(n.Pos(), n, 0)
436 case n.Type().IsArray():
437 n = typecheck.Expr(ir.NewIndexExpr(n.Pos(), n, ir.NewInt(base.Pos, 0)))
438 default:
439 return n
440 }
441 }
442 }
443
444
445
446
447 func byteindex(n ir.Node) ir.Node {
448
449
450
451
452 if !types.Identical(n.Type(), types.Types[types.TUINT8]) {
453 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
454 n.SetType(types.Types[types.TUINT8])
455 n.SetTypecheck(1)
456 }
457 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
458 n.SetType(types.Types[types.TINT])
459 n.SetTypecheck(1)
460 return n
461 }
462
463 func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
464
465
466
467 if n.CheckPtr() {
468 return n
469 }
470 n.SetCheckPtr(true)
471 defer n.SetCheckPtr(false)
472
473
474
475 switch n.X.Op() {
476 case ir.OCALLMETH:
477 base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
478 case ir.OCALLFUNC, ir.OCALLINTER:
479 return n
480 }
481
482 if n.X.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(n.X) {
483 return n
484 }
485
486
487
488
489
490
491
492 var originals []ir.Node
493 var walk func(n ir.Node)
494 walk = func(n ir.Node) {
495 switch n.Op() {
496 case ir.OADD:
497 n := n.(*ir.BinaryExpr)
498 walk(n.X)
499 walk(n.Y)
500 case ir.OSUB, ir.OANDNOT:
501 n := n.(*ir.BinaryExpr)
502 walk(n.X)
503 case ir.OCONVNOP:
504 n := n.(*ir.ConvExpr)
505 if n.X.Type().IsUnsafePtr() {
506 n.X = cheapExpr(n.X, init)
507 originals = append(originals, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]))
508 }
509 }
510 }
511 walk(n.X)
512
513 cheap := cheapExpr(n, init)
514
515 slice := typecheck.MakeDotArgs(base.Pos, types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
516 slice.SetEsc(ir.EscNone)
517
518 init.Append(mkcall("checkptrArithmetic", nil, init, typecheck.ConvNop(cheap, types.Types[types.TUNSAFEPTR]), slice))
519
520
521
522 return cheap
523 }
524
525
526 func walkSliceToArray(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
527
528 conv := typecheck.Expr(ir.NewConvExpr(base.Pos, ir.OCONV, types.NewPtr(n.Type()), n.X)).(*ir.ConvExpr)
529 deref := typecheck.Expr(ir.NewStarExpr(base.Pos, conv)).(*ir.StarExpr)
530
531
532
533
534
535
536
537
538 deref.SetBounded(true)
539
540 return walkExpr(deref, init)
541 }
542
View as plain text