iface.go 8.73 KB
Newer Older
1 2 3 4 5 6
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

7 8
import (
	"runtime/internal/atomic"
9
	"runtime/internal/sys"
10 11
	"unsafe"
)
12 13 14 15 16 17

const (
	hashSize = 1009
)

var (
Russ Cox's avatar
Russ Cox committed
18
	ifaceLock mutex // lock for accessing hash
19 20 21
	hash      [hashSize]*itab
)

22 23 24 25 26 27 28 29
func itabhash(inter *interfacetype, typ *_type) uint32 {
	// compiler has provided some good hash codes for us.
	h := inter.typ.hash
	h += 17 * typ.hash
	// TODO(rsc): h += 23 * x.mhash ?
	return h % hashSize
}

30 31
func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
	if len(inter.mhdr) == 0 {
32
		throw("internal error - misuse of itab")
33 34 35
	}

	// easy case
36
	if typ.tflag&tflagUncommon == 0 {
37 38 39
		if canfail {
			return nil
		}
40
		panic(&TypeAssertionError{"", typ._string, inter.typ._string, inter.mhdr[0].name.name()})
41 42
	}

43
	h := itabhash(inter, typ)
44 45 46 47 48 49 50

	// look twice - once without lock, once with.
	// common case will be no lock contention.
	var m *itab
	var locked int
	for locked = 0; locked < 2; locked++ {
		if locked != 0 {
Russ Cox's avatar
Russ Cox committed
51
			lock(&ifaceLock)
52
		}
53
		for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
54 55 56 57 58 59 60 61
			if m.inter == inter && m._type == typ {
				if m.bad != 0 {
					m = nil
					if !canfail {
						// this can only happen if the conversion
						// was already done once using the , ok form
						// and we have a cached negative result.
						// the cached result doesn't record which
62 63 64
						// interface function was missing, so try
						// adding the itab again, which will throw an error.
						additab(m, locked != 0, false)
65 66 67
					}
				}
				if locked != 0 {
Russ Cox's avatar
Russ Cox committed
68
					unlock(&ifaceLock)
69 70 71 72 73 74
				}
				return m
			}
		}
	}

75
	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
76 77
	m.inter = inter
	m._type = typ
78 79 80 81 82 83 84 85 86 87 88 89
	additab(m, true, canfail)
	unlock(&ifaceLock)
	if m.bad != 0 {
		return nil
	}
	return m
}

func additab(m *itab, locked, canfail bool) {
	inter := m.inter
	typ := m._type
	x := typ.uncommon()
90 91 92 93 94 95

	// both inter and typ have method sorted by name,
	// and interface names are unique,
	// so can iterate over both in lock step;
	// the loop is O(ni+nt) not O(ni*nt).
	ni := len(inter.mhdr)
96 97
	nt := int(x.mcount)
	xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt]
98 99
	j := 0
	for k := 0; k < ni; k++ {
100
		i := &inter.mhdr[k]
101
		iname := i.name.name()
102
		itype := i._type
103 104 105 106
		ipkg := i.name.pkgPath()
		if ipkg == nil {
			ipkg = inter.pkgpath
		}
107
		for ; j < nt; j++ {
108 109
			t := &xmhdr[j]
			if typ.typeOff(t.mtyp) == itype && t.name.name() == iname {
110 111 112 113 114 115
				pkgPath := t.name.pkgPath()
				if pkgPath == nil {
					pkgPath = x.pkgpath
				}
				if t.name.isExported() || pkgPath == ipkg {
					if m != nil {
116 117
						ifn := typ.textOff(t.ifn)
						*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn
118 119
					}
					goto nextimethod
120 121 122 123 124
				}
			}
		}
		// didn't find method
		if !canfail {
125
			if locked {
Russ Cox's avatar
Russ Cox committed
126
				unlock(&ifaceLock)
127
			}
128
			panic(&TypeAssertionError{"", typ._string, inter.typ._string, iname})
129 130 131 132 133
		}
		m.bad = 1
		break
	nextimethod:
	}
134
	if !locked {
135
		throw("invalid itab locking")
136
	}
137
	h := itabhash(inter, typ)
138
	m.link = hash[h]
139
	atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
140 141 142 143 144 145 146 147
}

func itabsinit() {
	lock(&ifaceLock)
	for m := &firstmoduledata; m != nil; m = m.next {
		for _, i := range m.itablinks {
			additab(i, true, false)
		}
148
	}
149
	unlock(&ifaceLock)
150 151
}

152
func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
153 154 155
	if raceenabled {
		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
	}
156 157 158
	if msanenabled {
		msanread(elem, t.size)
	}
159
	if isDirectIface(t) {
160 161
		e._type = t
		typedmemmove(t, unsafe.Pointer(&e.data), elem)
162
	} else {
163 164 165
		if x == nil {
			x = newobject(t)
		}
166
		// TODO: We allocate a zeroed object only to overwrite it with
167
		// actual data. Figure out how to avoid zeroing. Also below in convT2I.
168
		typedmemmove(t, x, elem)
169 170
		e._type = t
		e.data = x
171 172 173 174
	}
	return
}

175 176
func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
	t := tab._type
177
	if raceenabled {
178
		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I))
179
	}
180 181 182
	if msanenabled {
		msanread(elem, t.size)
	}
183
	if isDirectIface(t) {
184 185
		i.tab = tab
		typedmemmove(t, unsafe.Pointer(&i.data), elem)
186
	} else {
187 188 189
		if x == nil {
			x = newobject(t)
		}
190
		typedmemmove(t, x, elem)
191 192
		i.tab = tab
		i.data = x
193 194 195 196
	}
	return
}

197 198 199
func panicdottype(have, want, iface *_type) {
	haveString := ""
	if have != nil {
200
		haveString = have._string
201
	}
202
	panic(&TypeAssertionError{iface._string, haveString, want._string, ""})
203 204
}

205 206
func assertI2T(t *_type, i iface, r unsafe.Pointer) {
	tab := i.tab
207
	if tab == nil {
208
		panic(&TypeAssertionError{"", "", t._string, ""})
209 210
	}
	if tab._type != t {
211
		panic(&TypeAssertionError{tab.inter.typ._string, tab._type._string, t._string, ""})
212
	}
213 214
	if r != nil {
		if isDirectIface(t) {
215
			writebarrierptr((*uintptr)(r), uintptr(i.data))
216
		} else {
217
			typedmemmove(t, r, i.data)
218
		}
219 220 221
	}
}

222 223
func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
	tab := i.tab
224
	if tab == nil || tab._type != t {
225
		if r != nil {
226
			memclr(r, t.size)
227 228
		}
		return false
229
	}
230 231
	if r != nil {
		if isDirectIface(t) {
232
			writebarrierptr((*uintptr)(r), uintptr(i.data))
233
		} else {
234
			typedmemmove(t, r, i.data)
235
		}
236
	}
237
	return true
238 239
}

240 241
func assertE2T(t *_type, e eface, r unsafe.Pointer) {
	if e._type == nil {
242
		panic(&TypeAssertionError{"", "", t._string, ""})
243
	}
244
	if e._type != t {
245
		panic(&TypeAssertionError{"", e._type._string, t._string, ""})
246
	}
247 248
	if r != nil {
		if isDirectIface(t) {
249
			writebarrierptr((*uintptr)(r), uintptr(e.data))
250
		} else {
251
			typedmemmove(t, r, e.data)
252
		}
253 254 255
	}
}

256 257
var testingAssertE2T2GC bool

258
// The compiler ensures that r is non-nil.
259
func assertE2T2(t *_type, e eface, r unsafe.Pointer) bool {
260 261 262
	if testingAssertE2T2GC {
		GC()
	}
263
	if e._type != t {
264
		memclr(r, t.size)
265
		return false
266
	}
267
	if isDirectIface(t) {
268
		writebarrierptr((*uintptr)(r), uintptr(e.data))
269
	} else {
270
		typedmemmove(t, r, e.data)
271
	}
272
	return true
273 274
}

275 276
func convI2E(i iface) (r eface) {
	tab := i.tab
277 278 279
	if tab == nil {
		return
	}
280 281
	r._type = tab._type
	r.data = i.data
282 283 284
	return
}

285 286
func assertI2E(inter *interfacetype, i iface, r *eface) {
	tab := i.tab
287 288
	if tab == nil {
		// explicit conversions require non-nil interface value.
289
		panic(&TypeAssertionError{"", "", inter.typ._string, ""})
290
	}
291 292
	r._type = tab._type
	r.data = i.data
293 294 295
	return
}

296
// The compiler ensures that r is non-nil.
297 298
func assertI2E2(inter *interfacetype, i iface, r *eface) bool {
	tab := i.tab
299
	if tab == nil {
300
		return false
301
	}
302 303
	r._type = tab._type
	r.data = i.data
304
	return true
305 306
}

307 308
func convI2I(inter *interfacetype, i iface) (r iface) {
	tab := i.tab
309 310 311 312
	if tab == nil {
		return
	}
	if tab.inter == inter {
313 314
		r.tab = tab
		r.data = i.data
315 316
		return
	}
317 318
	r.tab = getitab(inter, tab._type, false)
	r.data = i.data
319 320 321
	return
}

322 323
func assertI2I(inter *interfacetype, i iface, r *iface) {
	tab := i.tab
324 325
	if tab == nil {
		// explicit conversions require non-nil interface value.
326
		panic(&TypeAssertionError{"", "", inter.typ._string, ""})
327 328
	}
	if tab.inter == inter {
329 330
		r.tab = tab
		r.data = i.data
331 332
		return
	}
333 334
	r.tab = getitab(inter, tab._type, false)
	r.data = i.data
335 336
}

337 338
func assertI2I2(inter *interfacetype, i iface, r *iface) bool {
	tab := i.tab
339
	if tab == nil {
340
		if r != nil {
341
			*r = iface{}
342 343
		}
		return false
344
	}
345 346 347 348
	if tab.inter != inter {
		tab = getitab(inter, tab._type, true)
		if tab == nil {
			if r != nil {
349
				*r = iface{}
350 351 352 353 354
			}
			return false
		}
	}
	if r != nil {
355 356
		r.tab = tab
		r.data = i.data
357
	}
358
	return true
359 360
}

361 362
func assertE2I(inter *interfacetype, e eface, r *iface) {
	t := e._type
363 364
	if t == nil {
		// explicit conversions require non-nil interface value.
365
		panic(&TypeAssertionError{"", "", inter.typ._string, ""})
366
	}
367 368
	r.tab = getitab(inter, t, false)
	r.data = e.data
369 370
}

371 372
var testingAssertE2I2GC bool

373
func assertE2I2(inter *interfacetype, e eface, r *iface) bool {
374 375 376
	if testingAssertE2I2GC {
		GC()
	}
377
	t := e._type
378
	if t == nil {
379
		if r != nil {
380
			*r = iface{}
381 382
		}
		return false
383 384 385
	}
	tab := getitab(inter, t, true)
	if tab == nil {
386
		if r != nil {
387
			*r = iface{}
388 389
		}
		return false
390
	}
391
	if r != nil {
392 393
		r.tab = tab
		r.data = e.data
394 395
	}
	return true
396 397
}

Russ Cox's avatar
Russ Cox committed
398
//go:linkname reflect_ifaceE2I reflect.ifaceE2I
399
func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
400
	assertE2I(inter, e, dst)
401 402
}

403 404
func assertE2E(inter *interfacetype, e eface, r *eface) {
	if e._type == nil {
405
		// explicit conversions require non-nil interface value.
406
		panic(&TypeAssertionError{"", "", inter.typ._string, ""})
407
	}
408
	*r = e
409 410
}

411
// The compiler ensures that r is non-nil.
412 413 414
func assertE2E2(inter *interfacetype, e eface, r *eface) bool {
	if e._type == nil {
		*r = eface{}
415
		return false
416
	}
417
	*r = e
418
	return true
419 420
}

421
func iterate_itabs(fn func(*itab)) {
Russ Cox's avatar
Russ Cox committed
422
	for _, h := range &hash {
423 424 425 426 427
		for ; h != nil; h = h.link {
			fn(h)
		}
	}
}