1// Copyright 2014 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 runtime
6
7import (
8	"unsafe"
9)
10
11// For gccgo, use go:linkname to rename compiler-called functions to
12// themselves, so that the compiler will export them.
13//
14//go:linkname requireitab runtime.requireitab
15//go:linkname assertitab runtime.assertitab
16//go:linkname assertI2T runtime.assertI2T
17//go:linkname ifacetypeeq runtime.ifacetypeeq
18//go:linkname efacetype runtime.efacetype
19//go:linkname ifacetype runtime.ifacetype
20//go:linkname ifaceE2E2 runtime.ifaceE2E2
21//go:linkname ifaceI2E2 runtime.ifaceI2E2
22//go:linkname ifaceE2I2 runtime.ifaceE2I2
23//go:linkname ifaceI2I2 runtime.ifaceI2I2
24//go:linkname ifaceE2T2P runtime.ifaceE2T2P
25//go:linkname ifaceI2T2P runtime.ifaceI2T2P
26//go:linkname ifaceE2T2 runtime.ifaceE2T2
27//go:linkname ifaceI2T2 runtime.ifaceI2T2
28//go:linkname ifaceT2Ip runtime.ifaceT2Ip
29// Temporary for C code to call:
30//go:linkname getitab runtime.getitab
31
32// The gccgo itab structure is different than the gc one.
33//
34// Both gccgo and gc represent empty interfaces the same way:
35// a two field struct, where the first field points to a type descriptor
36// (a *_type) and the second field is the data pointer.
37//
38// Non-empty interfaces are also two-field structs, and the second
39// field is the data pointer. However, for gccgo, the first field, the
40// itab field, is different. The itab field points to the interface
41// method table, which is the implemention of a specific interface
42// type for a specific dynamic non-interface type.  An interface
43// method table is a list of pointer values. The first pointer is the
44// type descriptor (a *_type) for the dynamic type. The subsequent
45// pointers are pointers to function code, which implement the methods
46// required by the interface. The pointers are sorted by name.
47//
48// The method pointers in the itab are C function pointers, not Go
49// function pointers; they may be called directly, and they have no
50// closures. The receiver is always passed as a pointer, and it is
51// always the same pointer stored in the interface value. A value
52// method starts by copying the receiver value out of the pointer into
53// a local variable.
54//
55// A method call on an interface value is by definition calling a
56// method at a known index m in the list of methods. Given a non-empty
57// interface value i, the call i.m(args) looks like
58//     i.itab[m+1](i.iface, args)
59
60// Both an empty interface and a non-empty interface have a data
61// pointer field. The meaning of this field is determined by the
62// kindDirectIface bit in the `kind` field of the type descriptor of
63// the value stored in the interface. If kindDirectIface is set, then
64// the data pointer field in the interface value is exactly the value
65// stored in the interface. Otherwise, the data pointer field is a
66// pointer to memory that holds the value. It follows from this that
67// kindDirectIface can only be set for a type whose representation is
68// simply a pointer. In the current gccgo implementation, this is set
69// only for pointer types (including unsafe.Pointer). In the future it
70// could also be set for other types: channels, maps, functions,
71// single-field structs and single-element arrays whose single field
72// is simply a pointer.
73
74// For a nil interface value both fields in the interface struct are nil.
75
76// Return the interface method table for a value of type rhs converted
77// to an interface of type lhs.
78func getitab(lhs, rhs *_type, canfail bool) unsafe.Pointer {
79	if rhs == nil {
80		return nil
81	}
82
83	if lhs.kind&kindMask != kindInterface {
84		throw("getitab called for non-interface type")
85	}
86
87	lhsi := (*interfacetype)(unsafe.Pointer(lhs))
88
89	if len(lhsi.methods) == 0 {
90		throw("getitab called for empty interface type")
91	}
92
93	if rhs.uncommontype == nil || len(rhs.methods) == 0 {
94		if canfail {
95			return nil
96		}
97		panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsi.methods[0].name})
98	}
99
100	methods := make([]unsafe.Pointer, len(lhsi.methods)+1)
101	methods[0] = unsafe.Pointer(rhs)
102
103	ri := 0
104	for li := range lhsi.methods {
105		lhsMethod := &lhsi.methods[li]
106		var rhsMethod *method
107
108		for {
109			if ri >= len(rhs.methods) {
110				if canfail {
111					return nil
112				}
113				panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsMethod.name})
114			}
115
116			rhsMethod = &rhs.methods[ri]
117			if (lhsMethod.name == rhsMethod.name || *lhsMethod.name == *rhsMethod.name) &&
118				(lhsMethod.pkgPath == rhsMethod.pkgPath || *lhsMethod.pkgPath == *rhsMethod.pkgPath) {
119				break
120			}
121
122			ri++
123		}
124
125		if !eqtype(lhsMethod.typ, rhsMethod.mtyp) {
126			if canfail {
127				return nil
128			}
129			panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsMethod.name})
130		}
131
132		methods[li+1] = unsafe.Pointer(rhsMethod.tfn)
133		ri++
134	}
135
136	return unsafe.Pointer(&methods[0])
137}
138
139// Return the interface method table for a value of type rhs converted
140// to an interface of type lhs.  Panics if the conversion is impossible.
141func requireitab(lhs, rhs *_type) unsafe.Pointer {
142	return getitab(lhs, rhs, false)
143}
144
145// Return the interface method table for a value of type rhs converted
146// to an interface of type lhs.  Panics if the conversion is
147// impossible or if the rhs type is nil.
148func assertitab(lhs, rhs *_type) unsafe.Pointer {
149	if rhs == nil {
150		panic(&TypeAssertionError{"", "", *lhs.string, ""})
151	}
152
153	if lhs.kind&kindMask != kindInterface {
154		throw("assertitab called for non-interface type")
155	}
156
157	lhsi := (*interfacetype)(unsafe.Pointer(lhs))
158
159	if len(lhsi.methods) == 0 {
160		return unsafe.Pointer(rhs)
161	}
162
163	return getitab(lhs, rhs, false)
164}
165
166// Check whether an interface type may be converted to a non-interface
167// type, panicing if not.
168func assertI2T(lhs, rhs, inter *_type) {
169	if rhs == nil {
170		panic(&TypeAssertionError{"", "", *lhs.string, ""})
171	}
172	if !eqtype(lhs, rhs) {
173		panic(&TypeAssertionError{*inter.string, *rhs.string, *lhs.string, ""})
174	}
175}
176
177// Compare two type descriptors for equality.
178func ifacetypeeq(a, b *_type) bool {
179	return eqtype(a, b)
180}
181
182// Return the type descriptor of an empty interface.
183// FIXME: This should be inlined by the compiler.
184func efacetype(e eface) *_type {
185	return e._type
186}
187
188// Return the type descriptor of a non-empty interface.
189// FIXME: This should be inlined by the compiler.
190func ifacetype(i iface) *_type {
191	if i.tab == nil {
192		return nil
193	}
194	return *(**_type)(i.tab)
195}
196
197// Convert an empty interface to an empty interface, for a comma-ok
198// type assertion.
199func ifaceE2E2(e eface) (eface, bool) {
200	return e, e._type != nil
201}
202
203// Convert a non-empty interface to an empty interface, for a comma-ok
204// type assertion.
205func ifaceI2E2(i iface) (eface, bool) {
206	if i.tab == nil {
207		return eface{nil, nil}, false
208	} else {
209		return eface{*(**_type)(i.tab), i.data}, true
210	}
211}
212
213// Convert an empty interface to a non-empty interface, for a comma-ok
214// type assertion.
215func ifaceE2I2(inter *_type, e eface) (iface, bool) {
216	if e._type == nil {
217		return iface{nil, nil}, false
218	} else {
219		itab := getitab(inter, e._type, true)
220		if itab == nil {
221			return iface{nil, nil}, false
222		} else {
223			return iface{itab, e.data}, true
224		}
225	}
226}
227
228// Convert a non-empty interface to a non-empty interface, for a
229// comma-ok type assertion.
230func ifaceI2I2(inter *_type, i iface) (iface, bool) {
231	if i.tab == nil {
232		return iface{nil, nil}, false
233	} else {
234		itab := getitab(inter, *(**_type)(i.tab), true)
235		if itab == nil {
236			return iface{nil, nil}, false
237		} else {
238			return iface{itab, i.data}, true
239		}
240	}
241}
242
243// Convert an empty interface to a pointer non-interface type.
244func ifaceE2T2P(t *_type, e eface) (unsafe.Pointer, bool) {
245	if !eqtype(t, e._type) {
246		return nil, false
247	} else {
248		return e.data, true
249	}
250}
251
252// Convert a non-empty interface to a pointer non-interface type.
253func ifaceI2T2P(t *_type, i iface) (unsafe.Pointer, bool) {
254	if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) {
255		return nil, false
256	} else {
257		return i.data, true
258	}
259}
260
261// Convert an empty interface to a non-pointer non-interface type.
262func ifaceE2T2(t *_type, e eface, ret unsafe.Pointer) bool {
263	if !eqtype(t, e._type) {
264		typedmemclr(t, ret)
265		return false
266	} else {
267		typedmemmove(t, ret, e.data)
268		return true
269	}
270}
271
272// Convert a non-empty interface to a non-pointer non-interface type.
273func ifaceI2T2(t *_type, i iface, ret unsafe.Pointer) bool {
274	if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) {
275		typedmemclr(t, ret)
276		return false
277	} else {
278		typedmemmove(t, ret, i.data)
279		return true
280	}
281}
282
283// Return whether we can convert a type to an interface type.
284func ifaceT2Ip(to, from *_type) bool {
285	if from == nil {
286		return false
287	}
288
289	if to.kind&kindMask != kindInterface {
290		throw("ifaceT2Ip called with non-interface type")
291	}
292	toi := (*interfacetype)(unsafe.Pointer(to))
293
294	if from.uncommontype == nil || len(from.methods) == 0 {
295		return len(toi.methods) == 0
296	}
297
298	ri := 0
299	for li := range toi.methods {
300		toMethod := &toi.methods[li]
301		var fromMethod *method
302		for {
303			if ri >= len(from.methods) {
304				return false
305			}
306
307			fromMethod = &from.methods[ri]
308			if (toMethod.name == fromMethod.name || *toMethod.name == *fromMethod.name) &&
309				(toMethod.pkgPath == fromMethod.pkgPath || *toMethod.pkgPath == *fromMethod.pkgPath) {
310				break
311			}
312
313			ri++
314		}
315
316		if !eqtype(fromMethod.mtyp, toMethod.typ) {
317			return false
318		}
319
320		ri++
321	}
322
323	return true
324}
325
326//go:linkname reflect_ifaceE2I reflect.ifaceE2I
327func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
328	t := e._type
329	if t == nil {
330		panic(TypeAssertionError{"", "", *inter.typ.string, ""})
331	}
332	dst.tab = requireitab((*_type)(unsafe.Pointer(inter)), t)
333	dst.data = e.data
334}
335