iface.c 15.7 KB
Newer Older
Ken Thompson's avatar
Ken Thompson committed
1 2 3 4 5
// Copyright 2009 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.

#include "runtime.h"
Dmitriy Vyukov's avatar
Dmitriy Vyukov committed
6
#include "arch.h"
7
#include "type.h"
8
#include "malloc.h"
Ken Thompson's avatar
Ken Thompson committed
9

10 11 12 13 14 15 16 17
enum 
{
	// If an empty interface has these bits set in its type
	// pointer, it was copied from a reflect.Value and is
	// not a valid empty interface.
	reflectFlags = 3,
};

18 19
void
runtime·printiface(Iface i)
20
{
21
	runtime·printf("(%p,%p)", i.tab, i.data);
22
}
Ken Thompson's avatar
Ken Thompson committed
23

24 25
void
runtime·printeface(Eface e)
26
{
27
	runtime·printf("(%p,%p)", e.type, e.data);
28
}
Ken Thompson's avatar
Ken Thompson committed
29

Russ Cox's avatar
Russ Cox committed
30
/*
31
 * layout of Itab known to compilers
Russ Cox's avatar
Russ Cox committed
32
 */
33
struct Itab
Ken Thompson's avatar
Ken Thompson committed
34
{
35 36 37
	InterfaceType*	inter;
	Type*	type;
	Itab*	link;
Ken Thompson's avatar
Ken Thompson committed
38 39 40 41 42
	int32	bad;
	int32	unused;
	void	(*fun[])(void);
};

43
static	Itab*	hash[1009];
Russ Cox's avatar
Russ Cox committed
44
static	Lock	ifacelock;
Ken Thompson's avatar
Ken Thompson committed
45

46 47
static Itab*
itab(InterfaceType *inter, Type *type, int32 canfail)
Ken Thompson's avatar
Ken Thompson committed
48
{
Russ Cox's avatar
Russ Cox committed
49
	int32 locked;
50 51 52
	int32 ni;
	Method *t, *et;
	IMethod *i, *ei;
53
	uint32 h;
54
	String *iname, *ipkgPath;
55 56
	Itab *m;
	UncommonType *x;
57
	Type *itype;
58
	Eface err;
Ken Thompson's avatar
Ken Thompson committed
59

60
	if(inter->mhdr.len == 0)
61
		runtime·throw("internal error - misuse of itab");
62

63 64
	locked = 0;

65
	// easy case
66 67
	x = type->x;
	if(x == nil) {
68 69
		if(canfail)
			return nil;
70 71
		iname = inter->m[0].name;
		goto throw;
72 73
	}

Russ Cox's avatar
Russ Cox committed
74
	// compiler has provided some good hash codes for us.
75 76 77
	h = inter->hash;
	h += 17 * type->hash;
	// TODO(rsc): h += 23 * x->mhash ?
Russ Cox's avatar
Russ Cox committed
78 79 80 81 82 83
	h %= nelem(hash);

	// look twice - once without lock, once with.
	// common case will be no lock contention.
	for(locked=0; locked<2; locked++) {
		if(locked)
84
			runtime·lock(&ifacelock);
85
		for(m=runtime·atomicloadp(&hash[h]); m!=nil; m=m->link) {
86
			if(m->inter == inter && m->type == type) {
Russ Cox's avatar
Russ Cox committed
87 88 89 90 91 92 93 94 95
				if(m->bad) {
					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
						// interface function was missing, so jump
						// down to the interface check, which will
96 97
						// do more work but give a better error.
						goto search;
Russ Cox's avatar
Russ Cox committed
98
					}
Russ Cox's avatar
Russ Cox committed
99
				}
Russ Cox's avatar
Russ Cox committed
100
				if(locked)
101
					runtime·unlock(&ifacelock);
Russ Cox's avatar
Russ Cox committed
102
				return m;
Ken Thompson's avatar
Ken Thompson committed
103 104 105
			}
		}
	}
Russ Cox's avatar
Russ Cox committed
106

107
	ni = inter->mhdr.len;
108
	m = runtime·malloc(sizeof(*m) + ni*sizeof m->fun[0]);
109 110 111 112
	m->inter = inter;
	m->type = type;

search:
113 114
	// both inter and type have method sorted by name,
	// and interface names are unique,
115 116 117
	// so can iterate over both in lock step;
	// the loop is O(ni+nt) not O(ni*nt).
	i = inter->m;
118
	ei = i + inter->mhdr.len;
119
	t = x->m;
120
	et = t + x->mhdr.len;
121
	for(; i < ei; i++) {
122
		itype = i->type;
123
		iname = i->name;
124
		ipkgPath = i->pkgPath;
125 126
		for(;; t++) {
			if(t >= et) {
Russ Cox's avatar
Russ Cox committed
127
				if(!canfail) {
128 129
				throw:
					// didn't find method
130
					runtime·newTypeAssertionError(nil, type, inter,
131 132 133
						nil, type->string, inter->string,
						iname, &err);
					if(locked)
134 135
						runtime·unlock(&ifacelock);
					runtime·panic(err);
136
					return nil;	// not reached
Russ Cox's avatar
Russ Cox committed
137
				}
Russ Cox's avatar
Russ Cox committed
138
				m->bad = 1;
139
				goto out;
Russ Cox's avatar
Russ Cox committed
140
			}
141
			if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
Russ Cox's avatar
Russ Cox committed
142 143
				break;
		}
144
		if(m)
145
			m->fun[i - inter->m] = t->ifn;
Ken Thompson's avatar
Ken Thompson committed
146
	}
147 148

out:
149 150
	if(!locked)
		runtime·panicstring("invalid itab locking");
Russ Cox's avatar
Russ Cox committed
151
	m->link = hash[h];
152 153
	runtime·atomicstorep(&hash[h], m);
	runtime·unlock(&ifacelock);
154 155
	if(m->bad)
		return nil;
Russ Cox's avatar
Russ Cox committed
156
	return m;
Ken Thompson's avatar
Ken Thompson committed
157 158
}

159
static void
160
copyin(Type *t, void *src, void **dst)
161 162 163 164
{
	int32 wid, alg;
	void *p;

165 166
	wid = t->size;
	alg = t->alg;
167 168

	if(wid <= sizeof(*dst))
169
		runtime·algarray[alg].copy(wid, dst, src);
170
	else {
171 172
		p = runtime·mal(wid);
		runtime·algarray[alg].copy(wid, p, src);
173 174 175 176 177
		*dst = p;
	}
}

static void
178
copyout(Type *t, void **src, void *dst)
179 180 181
{
	int32 wid, alg;

182 183
	wid = t->size;
	alg = t->alg;
184 185

	if(wid <= sizeof(*src))
186
		runtime·algarray[alg].copy(wid, dst, src);
187
	else
188
		runtime·algarray[alg].copy(wid, dst, *src);
189 190
}

Russ Cox's avatar
Russ Cox committed
191
// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
192
#pragma textflag 7
Ken Thompson's avatar
Ken Thompson committed
193
void
194
runtime·convT2I(Type *t, InterfaceType *inter, ...)
Ken Thompson's avatar
Ken Thompson committed
195
{
Russ Cox's avatar
Russ Cox committed
196 197
	byte *elem;
	Iface *ret;
198
	int32 wid;
Russ Cox's avatar
Russ Cox committed
199

Russ Cox's avatar
Russ Cox committed
200
	elem = (byte*)(&inter+1);
201
	wid = t->size;
202
	ret = (Iface*)(elem + runtime·rnd(wid, Structrnd));
203 204
	ret->tab = itab(inter, t, 0);
	copyin(t, elem, &ret->data);
205
}
206

Russ Cox's avatar
Russ Cox committed
207
// func convT2E(typ *byte, elem any) (ret any)
208 209
#pragma textflag 7
void
210
runtime·convT2E(Type *t, ...)
211 212 213 214
{
	byte *elem;
	Eface *ret;
	int32 wid;
Ken Thompson's avatar
Ken Thompson committed
215

216 217
	elem = (byte*)(&t+1);
	wid = t->size;
218
	ret = (Eface*)(elem + runtime·rnd(wid, Structrnd));
219 220
	ret->type = t;
	copyin(t, elem, &ret->data);
Ken Thompson's avatar
Ken Thompson committed
221 222
}

223 224
static void assertI2Tret(Type *t, Iface i, byte *ret);

Russ Cox's avatar
Russ Cox committed
225
// func ifaceI2T(typ *byte, iface any) (ret any)
226
#pragma textflag 7
Ken Thompson's avatar
Ken Thompson committed
227
void
228
runtime·assertI2T(Type *t, Iface i, ...)
Ken Thompson's avatar
Ken Thompson committed
229
{
Russ Cox's avatar
Russ Cox committed
230 231 232
	byte *ret;

	ret = (byte*)(&i+1);
233 234 235 236 237 238 239 240 241
	assertI2Tret(t, i, ret);
}

static void
assertI2Tret(Type *t, Iface i, byte *ret)
{
	Itab *tab;
	Eface err;

242 243
	tab = i.tab;
	if(tab == nil) {
244
		runtime·newTypeAssertionError(nil, nil, t,
245 246
			nil, nil, t->string,
			nil, &err);
247
		runtime·panic(err);
Russ Cox's avatar
Russ Cox committed
248
	}
249
	if(tab->type != t) {
250
		runtime·newTypeAssertionError(tab->inter, tab->type, t,
251 252
			tab->inter->string, tab->type->string, t->string,
			nil, &err);
253
		runtime·panic(err);
Russ Cox's avatar
Russ Cox committed
254
	}
255
	copyout(t, &i.data, ret);
Russ Cox's avatar
Russ Cox committed
256 257
}

Russ Cox's avatar
Russ Cox committed
258
// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
259
#pragma textflag 7
Russ Cox's avatar
Russ Cox committed
260
void
261
runtime·assertI2T2(Type *t, Iface i, ...)
Russ Cox's avatar
Russ Cox committed
262
{
Russ Cox's avatar
Russ Cox committed
263 264
	byte *ret;
	bool *ok;
265
	int32 wid;
Ken Thompson's avatar
Ken Thompson committed
266

267
	ret = (byte*)(&i+1);
268
	wid = t->size;
269
	ok = (bool*)(ret + wid);
270

271
	if(i.tab == nil || i.tab->type != t) {
Russ Cox's avatar
Russ Cox committed
272
		*ok = false;
273
		runtime·memclr(ret, wid);
274 275 276 277
		return;
	}

	*ok = true;
278
	copyout(t, &i.data, ret);
279 280
}

281 282
static void assertE2Tret(Type *t, Eface e, byte *ret);

Russ Cox's avatar
Russ Cox committed
283
// func ifaceE2T(typ *byte, iface any) (ret any)
284 285
#pragma textflag 7
void
286
runtime·assertE2T(Type *t, Eface e, ...)
287 288 289
{
	byte *ret;

290 291
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
292
	ret = (byte*)(&e+1);
293 294 295 296 297 298 299
	assertE2Tret(t, e, ret);
}

static void
assertE2Tret(Type *t, Eface e, byte *ret)
{
	Eface err;
300

301 302
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
303
	if(e.type == nil) {
304
		runtime·newTypeAssertionError(nil, nil, t,
305 306
			nil, nil, t->string,
			nil, &err);
307
		runtime·panic(err);
308
	}
309
	if(e.type != t) {
310
		runtime·newTypeAssertionError(nil, e.type, t,
311 312
			nil, e.type->string, t->string,
			nil, &err);
313
		runtime·panic(err);
Russ Cox's avatar
Russ Cox committed
314
	}
315
	copyout(t, &e.data, ret);
316 317
}

Russ Cox's avatar
Russ Cox committed
318
// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
319 320
#pragma textflag 7
void
321
runtime·assertE2T2(Type *t, Eface e, ...)
322 323 324 325 326
{
	byte *ret;
	bool *ok;
	int32 wid;

327 328
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
329
	ret = (byte*)(&e+1);
330
	wid = t->size;
331
	ok = (bool*)(ret + wid);
332

333
	if(t != e.type) {
334
		*ok = false;
335
		runtime·memclr(ret, wid);
336
		return;
Russ Cox's avatar
Russ Cox committed
337
	}
338 339

	*ok = true;
340
	copyout(t, &e.data, ret);
341 342
}

Russ Cox's avatar
Russ Cox committed
343
// func convI2E(elem any) (ret any)
344
void
345
runtime·convI2E(Iface i, Eface ret)
346
{
347
	Itab *tab;
348 349

	ret.data = i.data;
Russ Cox's avatar
Russ Cox committed
350
	if((tab = i.tab) == nil)
351 352
		ret.type = nil;
	else
353
		ret.type = tab->type;
354
	FLUSH(&ret);
Ken Thompson's avatar
Ken Thompson committed
355 356
}

Russ Cox's avatar
Russ Cox committed
357
// func ifaceI2E(typ *byte, iface any) (ret any)
Ken Thompson's avatar
Ken Thompson committed
358
void
359
runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
Ken Thompson's avatar
Ken Thompson committed
360
{
361
	Itab *tab;
Russ Cox's avatar
Russ Cox committed
362
	Eface err;
Russ Cox's avatar
Russ Cox committed
363

364 365
	tab = i.tab;
	if(tab == nil) {
Russ Cox's avatar
Russ Cox committed
366
		// explicit conversions require non-nil interface value.
367
		runtime·newTypeAssertionError(nil, nil, inter,
Russ Cox's avatar
Russ Cox committed
368 369
			nil, nil, inter->string,
			nil, &err);
370
		runtime·panic(err);
Russ Cox's avatar
Russ Cox committed
371 372 373 374 375 376 377 378
	}
	ret.data = i.data;
	ret.type = tab->type;
	FLUSH(&ret);
}

// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
void
379
runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
Russ Cox's avatar
Russ Cox committed
380 381 382 383 384 385 386 387
{
	Itab *tab;

	USED(inter);
	tab = i.tab;
	if(tab == nil) {
		ret.type = nil;
		ok = 0;
388
	} else {
Russ Cox's avatar
Russ Cox committed
389 390
		ret.type = tab->type;
		ok = 1;
Ken Thompson's avatar
Ken Thompson committed
391
	}
Russ Cox's avatar
Russ Cox committed
392 393 394 395
	ret.data = i.data;
	FLUSH(&ret);
	FLUSH(&ok);
}
Ken Thompson's avatar
Ken Thompson committed
396

Russ Cox's avatar
Russ Cox committed
397 398
// func convI2I(typ *byte, elem any) (ret any)
void
399
runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
Russ Cox's avatar
Russ Cox committed
400 401 402 403 404 405 406 407 408 409
{
	Itab *tab;
	
	ret.data = i.data;
	if((tab = i.tab) == nil)
		ret.tab = nil;
	else if(tab->inter == inter)
		ret.tab = tab;
	else
		ret.tab = itab(inter, tab->type, 0);
Russ Cox's avatar
Russ Cox committed
410
	FLUSH(&ret);
Ken Thompson's avatar
Ken Thompson committed
411
}
Ken Thompson's avatar
Ken Thompson committed
412

413
void
414
runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
415
{
416
	Itab *tab;
417
	Eface err;
418

419 420
	tab = i.tab;
	if(tab == nil) {
421
		// explicit conversions require non-nil interface value.
422
		runtime·newTypeAssertionError(nil, nil, inter,
423 424
			nil, nil, inter->string,
			nil, &err);
425
		runtime·panic(err);
426
	}
Russ Cox's avatar
Russ Cox committed
427 428 429
	ret->data = i.data;
	ret->tab = itab(inter, tab->type, 0);
}
430

Russ Cox's avatar
Russ Cox committed
431 432
// func ifaceI2I(sigi *byte, iface any) (ret any)
void
433
runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
Russ Cox's avatar
Russ Cox committed
434
{
435
	runtime·ifaceI2I(inter, i, &ret);
436 437
}

Russ Cox's avatar
Russ Cox committed
438
// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
Russ Cox's avatar
Russ Cox committed
439
void
440
runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
Russ Cox's avatar
Russ Cox committed
441
{
442
	Itab *tab;
Russ Cox's avatar
Russ Cox committed
443

444
	tab = i.tab;
Russ Cox's avatar
Russ Cox committed
445 446 447 448
	if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) {
		ret.data = i.data;
		ret.tab = tab;
		ok = 1;
Russ Cox's avatar
Russ Cox committed
449
	} else {
Russ Cox's avatar
Russ Cox committed
450 451 452
		ret.data = 0;
		ret.tab = 0;
		ok = 0;
Russ Cox's avatar
Russ Cox committed
453
	}
454 455 456 457 458
	FLUSH(&ret);
	FLUSH(&ok);
}

void
459
runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
460
{
461
	Type *t;
462
	Eface err;
463

464 465
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
466 467
	t = e.type;
	if(t == nil) {
468
		// explicit conversions require non-nil interface value.
469
		runtime·newTypeAssertionError(nil, nil, inter,
470 471
			nil, nil, inter->string,
			nil, &err);
472
		runtime·panic(err);
Russ Cox's avatar
Russ Cox committed
473
	}
Russ Cox's avatar
Russ Cox committed
474 475
	ret->data = e.data;
	ret->tab = itab(inter, t, 0);
Russ Cox's avatar
Russ Cox committed
476 477
}

478 479 480 481 482 483 484 485
// For reflect
//	func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
void
reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
{
	runtime·ifaceE2I(inter, e, dst);
}

Russ Cox's avatar
Russ Cox committed
486
// func ifaceE2I(sigi *byte, iface any) (ret any)
Russ Cox's avatar
Russ Cox committed
487
void
488
runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
Russ Cox's avatar
Russ Cox committed
489
{
490
	runtime·ifaceE2I(inter, e, &ret);
491 492
}

Russ Cox's avatar
Russ Cox committed
493
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
494
void
495
runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
496
{
497 498
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
Russ Cox's avatar
Russ Cox committed
499 500
	if(e.type == nil) {
		ok = 0;
501 502
		ret.data = nil;
		ret.tab = nil;
Russ Cox's avatar
Russ Cox committed
503 504 505
	} else if((ret.tab = itab(inter, e.type, 1)) == nil) {
		ok = 0;
		ret.data = nil;
506
	} else {
Russ Cox's avatar
Russ Cox committed
507
		ok = 1;
508 509
		ret.data = e.data;
	}
Russ Cox's avatar
Russ Cox committed
510
	FLUSH(&ret);
Russ Cox's avatar
Russ Cox committed
511 512 513
	FLUSH(&ok);
}

Russ Cox's avatar
Russ Cox committed
514 515
// func ifaceE2E(typ *byte, iface any) (ret any)
void
516
runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
Russ Cox's avatar
Russ Cox committed
517 518 519 520
{
	Type *t;
	Eface err;

521 522
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
Russ Cox's avatar
Russ Cox committed
523 524 525
	t = e.type;
	if(t == nil) {
		// explicit conversions require non-nil interface value.
526
		runtime·newTypeAssertionError(nil, nil, inter,
Russ Cox's avatar
Russ Cox committed
527 528
			nil, nil, inter->string,
			nil, &err);
529
		runtime·panic(err);
Russ Cox's avatar
Russ Cox committed
530 531 532 533 534 535 536
	}
	ret = e;
	FLUSH(&ret);
}

// func ifaceE2E2(iface any) (ret any, ok bool)
void
537
runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
Russ Cox's avatar
Russ Cox committed
538
{
539 540
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
Russ Cox's avatar
Russ Cox committed
541 542 543 544 545 546 547
	USED(inter);
	ret = e;
	ok = e.type != nil;
	FLUSH(&ret);
	FLUSH(&ok);
}

Russ Cox's avatar
Russ Cox committed
548
static uintptr
549
ifacehash1(void *data, Type *t)
550 551
{
	int32 alg, wid;
552
	Eface err;
Russ Cox's avatar
Russ Cox committed
553

554
	if(t == nil)
555
		return 0;
556

557 558
	alg = t->alg;
	wid = t->size;
559
	if(runtime·algarray[alg].hash == runtime·nohash) {
560
		// calling nohash will panic too,
561
		// but we can print a better error.
562 563
		runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
		runtime·panic(err);
564
	}
565
	if(wid <= sizeof(data))
566 567
		return runtime·algarray[alg].hash(wid, &data);
	return runtime·algarray[alg].hash(wid, data);
568 569
}

Russ Cox's avatar
Russ Cox committed
570
uintptr
571
runtime·ifacehash(Iface a)
Ken Thompson's avatar
Ken Thompson committed
572
{
573
	if(a.tab == nil)
574
		return 0;
575
	return ifacehash1(a.data, a.tab->type);
576
}
Ken Thompson's avatar
Ken Thompson committed
577

Russ Cox's avatar
Russ Cox committed
578
uintptr
579
runtime·efacehash(Eface a)
580 581 582
{
	return ifacehash1(a.data, a.type);
}
Ken Thompson's avatar
Ken Thompson committed
583

584
static bool
585
ifaceeq1(void *data1, void *data2, Type *t)
586 587
{
	int32 alg, wid;
588
	Eface err;
Ken Thompson's avatar
Ken Thompson committed
589

590 591
	alg = t->alg;
	wid = t->size;
Ken Thompson's avatar
Ken Thompson committed
592

593
	if(runtime·algarray[alg].equal == runtime·noequal) {
594
		// calling noequal will panic too,
595
		// but we can print a better error.
596 597
		runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
		runtime·panic(err);
598 599
	}

600
	if(wid <= sizeof(data1))
601 602
		return runtime·algarray[alg].equal(wid, &data1, &data2);
	return runtime·algarray[alg].equal(wid, data1, data2);
603
}
Ken Thompson's avatar
Ken Thompson committed
604

605
bool
606
runtime·ifaceeq_c(Iface i1, Iface i2)
607
{
608
	if(i1.tab != i2.tab)
609
		return false;
610
	if(i1.tab == nil)
611
		return true;
612
	return ifaceeq1(i1.data, i2.data, i1.tab->type);
613 614 615
}

bool
616
runtime·efaceeq_c(Eface e1, Eface e2)
617
{
618 619 620 621
	if(((uintptr)e1.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
	if(((uintptr)e2.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
622 623 624 625 626
	if(e1.type != e2.type)
		return false;
	if(e1.type == nil)
		return true;
	return ifaceeq1(e1.data, e2.data, e1.type);
627 628 629 630
}

// ifaceeq(i1 any, i2 any) (ret bool);
void
631
runtime·ifaceeq(Iface i1, Iface i2, bool ret)
632
{
633
	ret = runtime·ifaceeq_c(i1, i2);
Ken Thompson's avatar
Ken Thompson committed
634 635 636
	FLUSH(&ret);
}

637 638
// efaceeq(i1 any, i2 any) (ret bool)
void
639
runtime·efaceeq(Eface e1, Eface e2, bool ret)
640
{
641
	ret = runtime·efaceeq_c(e1, e2);
642 643 644
	FLUSH(&ret);
}

645 646
// ifacethash(i1 any) (ret uint32);
void
647
runtime·ifacethash(Iface i1, uint32 ret)
648
{
649
	Itab *tab;
650 651

	ret = 0;
652 653 654
	tab = i1.tab;
	if(tab != nil)
		ret = tab->type->hash;
655 656 657
	FLUSH(&ret);
}

658 659
// efacethash(e1 any) (ret uint32)
void
660
runtime·efacethash(Eface e1, uint32 ret)
661
{
662
	Type *t;
663

664 665
	if(((uintptr)e1.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
666
	ret = 0;
667 668 669
	t = e1.type;
	if(t != nil)
		ret = t->hash;
670 671 672 673
	FLUSH(&ret);
}

void
674
unsafe·Typeof(Eface e, Eface ret)
675
{
676 677
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
678 679 680
	if(e.type == nil) {
		ret.type = nil;
		ret.data = nil;
681 682 683
	} else {
		ret = *(Eface*)(e.type);
	}
684
	FLUSH(&ret);
685 686
}

687 688
void
unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
689
{
690 691
	uintptr *p;
	uintptr x;
Russ Cox's avatar
Russ Cox committed
692

693 694
	if(((uintptr)e.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");
695 696 697 698 699 700 701 702 703
	if(e.type == nil) {
		rettype.type = nil;
		rettype.data = nil;
		retaddr = 0;
	} else {
		rettype = *(Eface*)e.type;
		if(e.type->size <= sizeof(uintptr)) {
			// Copy data into x ...
			x = 0;
704
			runtime·algarray[e.type->alg].copy(e.type->size, &x, &e.data);
705 706 707

			// but then build pointer to x so that Reflect
			// always returns pointer to data.
708
			p = runtime·mal(sizeof(uintptr));
709 710 711 712
			*p = x;
		} else {
			// Already a pointer, but still make a copy,
			// to preserve value semantics for interface data.
713 714
			p = runtime·mal(e.type->size);
			runtime·algarray[e.type->alg].copy(e.type->size, p, e.data);
715 716
		}
		retaddr = p;
Russ Cox's avatar
Russ Cox committed
717
	}
718 719
	FLUSH(&rettype);
	FLUSH(&retaddr);
720 721 722
}

void
723
unsafe·Unreflect(Eface typ, void *addr, Eface e)
724
{
725 726 727
	if(((uintptr)typ.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");

728 729 730 731 732 733 734 735 736
	// Reflect library has reinterpreted typ
	// as its own kind of type structure.
	// We know that the pointer to the original
	// type structure sits before the data pointer.
	e.type = (Type*)((Eface*)typ.data-1);

	// Interface holds either pointer to data
	// or copy of original data.
	if(e.type->size <= sizeof(uintptr))
737
		runtime·algarray[e.type->alg].copy(e.type->size, &e.data, addr);
738 739 740 741
	else {
		// Easier: already a pointer to data.
		// TODO(rsc): Should this make a copy?
		e.data = addr;
742 743
	}

744
	FLUSH(&e);
745
}
746 747 748 749 750 751

void
unsafe·New(Eface typ, void *ret)
{
	Type *t;

752 753 754
	if(((uintptr)typ.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");

755 756 757 758 759 760 761
	// Reflect library has reinterpreted typ
	// as its own kind of type structure.
	// We know that the pointer to the original
	// type structure sits before the data pointer.
	t = (Type*)((Eface*)typ.data-1);

	if(t->kind&KindNoPointers)
762
		ret = runtime·mallocgc(t->size, FlagNoPointers, 1, 1);
763
	else
764
		ret = runtime·mal(t->size);
765 766 767 768 769 770 771 772 773
	FLUSH(&ret);
}

void
unsafe·NewArray(Eface typ, uint32 n, void *ret)
{
	uint64 size;
	Type *t;

774 775 776
	if(((uintptr)typ.type&reflectFlags) != 0)
		runtime·throw("invalid interface value");

777 778 779 780 781 782 783 784
	// Reflect library has reinterpreted typ
	// as its own kind of type structure.
	// We know that the pointer to the original
	// type structure sits before the data pointer.
	t = (Type*)((Eface*)typ.data-1);
	
	size = n*t->size;
	if(t->kind&KindNoPointers)
785
		ret = runtime·mallocgc(size, FlagNoPointers, 1, 1);
786
	else
787
		ret = runtime·mal(size);
788 789
	FLUSH(&ret);
}