1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package walk
6
7import (
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// walkConv walks an OCONV or OCONVNOP (but not OCONVIFACE) node.
21func 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() { // uintptr to unsafe.Pointer
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// walkConvInterface walks an OCONVIFACE node.
40func 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		// skip unnamed functions (func _())
48		if fromType.HasShape() {
49			// Unified IR uses OCONVIFACE for converting all derived types
50			// to interface type. Avoid assertion failure in
51			// MarkTypeUsedInInterface, because we've marked used types
52			// separately anyway.
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	// Evaluate the input interface.
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		// Implement interface to empty interface conversion:
75		//
76		// var res *uint8
77		// res = (*uint8)(unsafe.Pointer(itab))
78		// if res != nil {
79		//    res = res.type
80		// }
81
82		// Grab its parts.
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()) // Type is generic pointer - we're just passing it through.
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		// Build the result.
97		// e = iface{typeWord, data}
98		e := ir.NewBinaryExpr(base.Pos, ir.OMAKEFACE, typeWord, data)
99		e.SetType(toType) // assign type manually, typecheck doesn't understand OEFACE.
100		e.SetTypecheck(1)
101		return e
102	}
103
104	// Must be converting I2I (more specific to less specific interface).
105	// Use the same code as e, _ = c.(T).
106	var rhs ir.Node
107	if n.TypeWord == nil || n.TypeWord.Op() == ir.OADDR && n.TypeWord.(*ir.AddrExpr).X.Op() == ir.OLINKSYMOFFSET {
108		// Fixed (not loaded from a dictionary) type.
109		ta := ir.NewTypeAssertExpr(base.Pos, c, toType)
110		ta.SetOp(ir.ODOTTYPE2)
111		// Allocate a descriptor for this conversion to pass to the runtime.
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// Returns the data word (the second word) used to represent conv.X in
128// an interface.
129func dataWord(conv *ir.ConvExpr, init *ir.Nodes) ir.Node {
130	pos, n := conv.Pos(), conv.X
131	fromType := n.Type()
132
133	// If it's a pointer, it is its own representation.
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	// Try a bunch of cases to avoid an allocation.
145	var value ir.Node
146	switch {
147	case fromType.Size() == 0:
148		// n is zero-sized. Use zerobase.
149		cheapExpr(n, init) // Evaluate n for side-effects. See issue 19246.
150		value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR])
151	case isBool || fromType.Size() == 1 && isInteger:
152		// n is a bool/byte. Use staticuint64s[n * 8] on little-endian
153		// and staticuint64s[n * 8 + 7] on big-endian.
154		n = cheapExpr(n, init)
155		n = soleComponent(init, n)
156		// byteindex widens n so that the multiplication doesn't overflow.
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		// The actual type is [256]uint64, but we use [256*8]uint8 so we can address
162		// individual bytes.
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		// n is a readonly global; use it directly.
169		value = n
170	case conv.Esc() == ir.EscNone && fromType.Size() <= 1024:
171		// n does not escape. Use a stack temporary initialized to n.
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		// The interface data word is &value.
177		return typecheck.Expr(typecheck.NodAddr(value))
178	}
179
180	// Time to do an allocation. We'll call into the runtime for that.
181	fnname, argType, needsaddr := dataWordFuncName(fromType)
182	var fn *ir.Name
183
184	var args []ir.Node
185	if needsaddr {
186		// Types of large or unknown size are passed by reference.
187		// Orderexpr arranged for n to be a temporary for all
188		// the conversions it could see. Comparison of an interface
189		// with a non-interface, especially in a switch on interface value
190		// with non-interface cases, is not visible to order.stmt, so we
191		// have to fall back on allocating a temp here.
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		// Use a specialized conversion routine that takes the type being
199		// converted by value, not by pointer.
200		fn = typecheck.LookupRuntime(fnname)
201		var arg ir.Node
202		switch {
203		case fromType == argType:
204			// already in the right type, nothing to do
205			arg = n
206		case fromType.Kind() == argType.Kind(),
207			fromType.IsPtrShaped() && argType.IsPtrShaped():
208			// can directly convert (e.g. named type to underlying type, or one pointer to another)
209			// TODO: never happens because pointers are directIface?
210			arg = ir.NewConvExpr(pos, ir.OCONVNOP, argType, n)
211		case fromType.IsInteger() && argType.IsInteger():
212			// can directly convert (e.g. int32 to uint32)
213			arg = ir.NewConvExpr(pos, ir.OCONV, argType, n)
214		default:
215			// unsafe cast through memory
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// walkBytesRunesToString walks an OBYTES2STR or ORUNES2STR node.
230func walkBytesRunesToString(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
231	a := typecheck.NodNil()
232	if n.Esc() == ir.EscNone {
233		// Create temporary buffer for string on stack.
234		a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
235	}
236	if n.Op() == ir.ORUNES2STR {
237		// slicerunetostring(*[32]byte, []rune) string
238		return mkcall("slicerunetostring", n.Type(), init, a, n.X)
239	}
240	// slicebytetostring(*[32]byte, ptr *byte, n int) string
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// walkBytesToStringTemp walks an OBYTES2STRTMP node.
247func walkBytesToStringTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
248	n.X = walkExpr(n.X, init)
249	if !base.Flag.Cfg.Instrumenting {
250		// Let the backend handle OBYTES2STRTMP directly
251		// to avoid a function call to slicebytetostringtmp.
252		return n
253	}
254	// slicebytetostringtmp(ptr *byte, n int) string
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// walkRuneToString walks an ORUNESTR node.
261func 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	// intstring(*[4]byte, rune)
267	return mkcall("intstring", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TINT64]))
268}
269
270// walkStringToBytes walks an OSTR2BYTES node.
271func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
272	s := n.X
273	if ir.IsConst(s, constant.String) {
274		sc := ir.StringVal(s)
275
276		// Allocate a [n]byte of the right size.
277		t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
278		var a ir.Node
279		if n.Esc() == ir.EscNone && len(sc) <= int(ir.MaxImplicitStackVarSize) {
280			a = stackBufAddr(t.NumElem(), t.Elem())
281		} else {
282			types.CalcSize(t)
283			a = ir.NewUnaryExpr(base.Pos, ir.ONEW, nil)
284			a.SetType(types.NewPtr(t))
285			a.SetTypecheck(1)
286			a.MarkNonNil()
287		}
288		p := typecheck.TempAt(base.Pos, ir.CurFunc, t.PtrTo()) // *[n]byte
289		init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, p, a)))
290
291		// Copy from the static string data to the [n]byte.
292		if len(sc) > 0 {
293			sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
294			sptr.SetBounded(true)
295			as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(sptr, t.PtrTo())))
296			appendWalkStmt(init, as)
297		}
298
299		// Slice the [n]byte to a []byte.
300		slice := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p, nil, nil, nil)
301		slice.SetType(n.Type())
302		slice.SetTypecheck(1)
303		return walkExpr(slice, init)
304	}
305
306	a := typecheck.NodNil()
307	if n.Esc() == ir.EscNone {
308		// Create temporary buffer for slice on stack.
309		a = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
310	}
311	// stringtoslicebyte(*32[byte], string) []byte
312	return mkcall("stringtoslicebyte", n.Type(), init, a, typecheck.Conv(s, types.Types[types.TSTRING]))
313}
314
315// walkStringToBytesTemp walks an OSTR2BYTESTMP node.
316func walkStringToBytesTemp(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
317	// []byte(string) conversion that creates a slice
318	// referring to the actual string bytes.
319	// This conversion is handled later by the backend and
320	// is only for use by internal compiler optimizations
321	// that know that the slice won't be mutated.
322	// The only such case today is:
323	// for i, c := range []byte(string)
324	n.X = walkExpr(n.X, init)
325	return n
326}
327
328// walkStringToRunes walks an OSTR2RUNES node.
329func walkStringToRunes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
330	a := typecheck.NodNil()
331	if n.Esc() == ir.EscNone {
332		// Create temporary buffer for slice on stack.
333		a = stackBufAddr(tmpstringbufsize, types.Types[types.TINT32])
334	}
335	// stringtoslicerune(*[32]rune, string) []rune
336	return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
337}
338
339// dataWordFuncName returns the name of the function used to convert a value of type "from"
340// to the data word of an interface.
341// argType is the type the argument needs to be coerced to.
342// needsaddr reports whether the value should be passed (needaddr==false) or its address (needsaddr==true).
343func dataWordFuncName(from *types.Type) (fnname string, argType *types.Type, needsaddr bool) {
344	if from.IsInterface() {
345		base.Fatalf("can only handle non-interfaces")
346	}
347	switch {
348	case from.Size() == 2 && uint8(from.Alignment()) == 2:
349		return "convT16", types.Types[types.TUINT16], false
350	case from.Size() == 4 && uint8(from.Alignment()) == 4 && !from.HasPointers():
351		return "convT32", types.Types[types.TUINT32], false
352	case from.Size() == 8 && uint8(from.Alignment()) == uint8(types.Types[types.TUINT64].Alignment()) && !from.HasPointers():
353		return "convT64", types.Types[types.TUINT64], false
354	}
355	if sc := from.SoleComponent(); sc != nil {
356		switch {
357		case sc.IsString():
358			return "convTstring", types.Types[types.TSTRING], false
359		case sc.IsSlice():
360			return "convTslice", types.NewSlice(types.Types[types.TUINT8]), false // the element type doesn't matter
361		}
362	}
363
364	if from.HasPointers() {
365		return "convT", types.Types[types.TUNSAFEPTR], true
366	}
367	return "convTnoptr", types.Types[types.TUNSAFEPTR], true
368}
369
370// rtconvfn returns the parameter and result types that will be used by a
371// runtime function to convert from type src to type dst. The runtime function
372// name can be derived from the names of the returned types.
373//
374// If no such function is necessary, it returns (Txxx, Txxx).
375func rtconvfn(src, dst *types.Type) (param, result types.Kind) {
376	if ssagen.Arch.SoftFloat {
377		return types.Txxx, types.Txxx
378	}
379
380	switch ssagen.Arch.LinkArch.Family {
381	case sys.ARM, sys.MIPS:
382		if src.IsFloat() {
383			switch dst.Kind() {
384			case types.TINT64, types.TUINT64:
385				return types.TFLOAT64, dst.Kind()
386			}
387		}
388		if dst.IsFloat() {
389			switch src.Kind() {
390			case types.TINT64, types.TUINT64:
391				return src.Kind(), dst.Kind()
392			}
393		}
394
395	case sys.I386:
396		if src.IsFloat() {
397			switch dst.Kind() {
398			case types.TINT64, types.TUINT64:
399				return types.TFLOAT64, dst.Kind()
400			case types.TUINT32, types.TUINT, types.TUINTPTR:
401				return types.TFLOAT64, types.TUINT32
402			}
403		}
404		if dst.IsFloat() {
405			switch src.Kind() {
406			case types.TINT64, types.TUINT64:
407				return src.Kind(), dst.Kind()
408			case types.TUINT32, types.TUINT, types.TUINTPTR:
409				return types.TUINT32, types.TFLOAT64
410			}
411		}
412	}
413	return types.Txxx, types.Txxx
414}
415
416func soleComponent(init *ir.Nodes, n ir.Node) ir.Node {
417	if n.Type().SoleComponent() == nil {
418		return n
419	}
420	// Keep in sync with cmd/compile/internal/types/type.go:Type.SoleComponent.
421	for {
422		switch {
423		case n.Type().IsStruct():
424			if n.Type().Field(0).Sym.IsBlank() {
425				// Treat blank fields as the zero value as the Go language requires.
426				n = typecheck.TempAt(base.Pos, ir.CurFunc, n.Type().Field(0).Type)
427				appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n, nil))
428				continue
429			}
430			n = typecheck.DotField(n.Pos(), n, 0)
431		case n.Type().IsArray():
432			n = typecheck.Expr(ir.NewIndexExpr(n.Pos(), n, ir.NewInt(base.Pos, 0)))
433		default:
434			return n
435		}
436	}
437}
438
439// byteindex converts n, which is byte-sized, to an int used to index into an array.
440// We cannot use conv, because we allow converting bool to int here,
441// which is forbidden in user code.
442func byteindex(n ir.Node) ir.Node {
443	// We cannot convert from bool to int directly.
444	// While converting from int8 to int is possible, it would yield
445	// the wrong result for negative values.
446	// Reinterpreting the value as an unsigned byte solves both cases.
447	if !types.Identical(n.Type(), types.Types[types.TUINT8]) {
448		n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
449		n.SetType(types.Types[types.TUINT8])
450		n.SetTypecheck(1)
451	}
452	n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
453	n.SetType(types.Types[types.TINT])
454	n.SetTypecheck(1)
455	return n
456}
457
458func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
459	// Calling cheapExpr(n, init) below leads to a recursive call to
460	// walkExpr, which leads us back here again. Use n.Checkptr to
461	// prevent infinite loops.
462	if n.CheckPtr() {
463		return n
464	}
465	n.SetCheckPtr(true)
466	defer n.SetCheckPtr(false)
467
468	// TODO(mdempsky): Make stricter. We only need to exempt
469	// reflect.Value.Pointer and reflect.Value.UnsafeAddr.
470	switch n.X.Op() {
471	case ir.OCALLMETH:
472		base.FatalfAt(n.X.Pos(), "OCALLMETH missed by typecheck")
473	case ir.OCALLFUNC, ir.OCALLINTER:
474		return n
475	}
476
477	if n.X.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(n.X) {
478		return n
479	}
480
481	// Find original unsafe.Pointer operands involved in this
482	// arithmetic expression.
483	//
484	// "It is valid both to add and to subtract offsets from a
485	// pointer in this way. It is also valid to use &^ to round
486	// pointers, usually for alignment."
487	var originals []ir.Node
488	var walk func(n ir.Node)
489	walk = func(n ir.Node) {
490		switch n.Op() {
491		case ir.OADD:
492			n := n.(*ir.BinaryExpr)
493			walk(n.X)
494			walk(n.Y)
495		case ir.OSUB, ir.OANDNOT:
496			n := n.(*ir.BinaryExpr)
497			walk(n.X)
498		case ir.OCONVNOP:
499			n := n.(*ir.ConvExpr)
500			if n.X.Type().IsUnsafePtr() {
501				n.X = cheapExpr(n.X, init)
502				originals = append(originals, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]))
503			}
504		}
505	}
506	walk(n.X)
507
508	cheap := cheapExpr(n, init)
509
510	slice := typecheck.MakeDotArgs(base.Pos, types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
511	slice.SetEsc(ir.EscNone)
512
513	init.Append(mkcall("checkptrArithmetic", nil, init, typecheck.ConvNop(cheap, types.Types[types.TUNSAFEPTR]), slice))
514	// TODO(khr): Mark backing store of slice as dead. This will allow us to reuse
515	// the backing store for multiple calls to checkptrArithmetic.
516
517	return cheap
518}
519
520// walkSliceToArray walks an OSLICE2ARR expression.
521func walkSliceToArray(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
522	// Replace T(x) with *(*T)(x).
523	conv := typecheck.Expr(ir.NewConvExpr(base.Pos, ir.OCONV, types.NewPtr(n.Type()), n.X)).(*ir.ConvExpr)
524	deref := typecheck.Expr(ir.NewStarExpr(base.Pos, conv)).(*ir.StarExpr)
525
526	// The OSLICE2ARRPTR conversion handles checking the slice length,
527	// so the dereference can't fail.
528	//
529	// However, this is more than just an optimization: if T is a
530	// zero-length array, then x (and thus (*T)(x)) can be nil, but T(x)
531	// should *not* panic. So suppressing the nil check here is
532	// necessary for correctness in that case.
533	deref.SetBounded(true)
534
535	return walkExpr(deref, init)
536}
537