The Go Programming Language

Text file src/pkg/runtime/iface.c

     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	
     5	#include "runtime.h"
     6	#include "type.h"
     7	#include "malloc.h"
     8	
     9	enum 
    10	{
    11		// If an empty interface has these bits set in its type
    12		// pointer, it was copied from a reflect.Value and is
    13		// not a valid empty interface.
    14		reflectFlags = 3,
    15	};
    16	
    17	void
    18	runtime·printiface(Iface i)
    19	{
    20		runtime·printf("(%p,%p)", i.tab, i.data);
    21	}
    22	
    23	void
    24	runtime·printeface(Eface e)
    25	{
    26		runtime·printf("(%p,%p)", e.type, e.data);
    27	}
    28	
    29	/*
    30	 * layout of Itab known to compilers
    31	 */
    32	struct Itab
    33	{
    34		InterfaceType*	inter;
    35		Type*	type;
    36		Itab*	link;
    37		int32	bad;
    38		int32	unused;
    39		void	(*fun[])(void);
    40	};
    41	
    42	static	Itab*	hash[1009];
    43	static	Lock	ifacelock;
    44	
    45	static Itab*
    46	itab(InterfaceType *inter, Type *type, int32 canfail)
    47	{
    48		int32 locked;
    49		int32 ni;
    50		Method *t, *et;
    51		IMethod *i, *ei;
    52		uint32 h;
    53		String *iname, *ipkgPath;
    54		Itab *m;
    55		UncommonType *x;
    56		Type *itype;
    57		Eface err;
    58	
    59		if(inter->mhdr.len == 0)
    60			runtime·throw("internal error - misuse of itab");
    61	
    62		locked = 0;
    63	
    64		// easy case
    65		x = type->x;
    66		if(x == nil) {
    67			if(canfail)
    68				return nil;
    69			iname = inter->m[0].name;
    70			goto throw;
    71		}
    72	
    73		// compiler has provided some good hash codes for us.
    74		h = inter->hash;
    75		h += 17 * type->hash;
    76		// TODO(rsc): h += 23 * x->mhash ?
    77		h %= nelem(hash);
    78	
    79		// look twice - once without lock, once with.
    80		// common case will be no lock contention.
    81		for(locked=0; locked<2; locked++) {
    82			if(locked)
    83				runtime·lock(&ifacelock);
    84			for(m=runtime·atomicloadp(&hash[h]); m!=nil; m=m->link) {
    85				if(m->inter == inter && m->type == type) {
    86					if(m->bad) {
    87						m = nil;
    88						if(!canfail) {
    89							// this can only happen if the conversion
    90							// was already done once using the , ok form
    91							// and we have a cached negative result.
    92							// the cached result doesn't record which
    93							// interface function was missing, so jump
    94							// down to the interface check, which will
    95							// do more work but give a better error.
    96							goto search;
    97						}
    98					}
    99					if(locked)
   100						runtime·unlock(&ifacelock);
   101					return m;
   102				}
   103			}
   104		}
   105	
   106		ni = inter->mhdr.len;
   107		m = runtime·malloc(sizeof(*m) + ni*sizeof m->fun[0]);
   108		m->inter = inter;
   109		m->type = type;
   110	
   111	search:
   112		// both inter and type have method sorted by name,
   113		// and interface names are unique,
   114		// so can iterate over both in lock step;
   115		// the loop is O(ni+nt) not O(ni*nt).
   116		i = inter->m;
   117		ei = i + inter->mhdr.len;
   118		t = x->m;
   119		et = t + x->mhdr.len;
   120		for(; i < ei; i++) {
   121			itype = i->type;
   122			iname = i->name;
   123			ipkgPath = i->pkgPath;
   124			for(;; t++) {
   125				if(t >= et) {
   126					if(!canfail) {
   127					throw:
   128						// didn't find method
   129						runtime·newTypeAssertionError(nil, type, inter,
   130							nil, type->string, inter->string,
   131							iname, &err);
   132						if(locked)
   133							runtime·unlock(&ifacelock);
   134						runtime·panic(err);
   135						return nil;	// not reached
   136					}
   137					m->bad = 1;
   138					goto out;
   139				}
   140				if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
   141					break;
   142			}
   143			if(m)
   144				m->fun[i - inter->m] = t->ifn;
   145		}
   146	
   147	out:
   148		if(!locked)
   149			runtime·panicstring("invalid itab locking");
   150		m->link = hash[h];
   151		runtime·atomicstorep(&hash[h], m);
   152		runtime·unlock(&ifacelock);
   153		if(m->bad)
   154			return nil;
   155		return m;
   156	}
   157	
   158	static void
   159	copyin(Type *t, void *src, void **dst)
   160	{
   161		int32 wid, alg;
   162		void *p;
   163	
   164		wid = t->size;
   165		alg = t->alg;
   166	
   167		if(wid <= sizeof(*dst))
   168			runtime·algarray[alg].copy(wid, dst, src);
   169		else {
   170			p = runtime·mal(wid);
   171			runtime·algarray[alg].copy(wid, p, src);
   172			*dst = p;
   173		}
   174	}
   175	
   176	static void
   177	copyout(Type *t, void **src, void *dst)
   178	{
   179		int32 wid, alg;
   180	
   181		wid = t->size;
   182		alg = t->alg;
   183	
   184		if(wid <= sizeof(*src))
   185			runtime·algarray[alg].copy(wid, dst, src);
   186		else
   187			runtime·algarray[alg].copy(wid, dst, *src);
   188	}
   189	
   190	// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
   191	#pragma textflag 7
   192	void
   193	runtime·convT2I(Type *t, InterfaceType *inter, ...)
   194	{
   195		byte *elem;
   196		Iface *ret;
   197		int32 wid;
   198	
   199		elem = (byte*)(&inter+1);
   200		wid = t->size;
   201		ret = (Iface*)(elem + runtime·rnd(wid, Structrnd));
   202		ret->tab = itab(inter, t, 0);
   203		copyin(t, elem, &ret->data);
   204	}
   205	
   206	// func convT2E(typ *byte, elem any) (ret any)
   207	#pragma textflag 7
   208	void
   209	runtime·convT2E(Type *t, ...)
   210	{
   211		byte *elem;
   212		Eface *ret;
   213		int32 wid;
   214	
   215		elem = (byte*)(&t+1);
   216		wid = t->size;
   217		ret = (Eface*)(elem + runtime·rnd(wid, Structrnd));
   218		ret->type = t;
   219		copyin(t, elem, &ret->data);
   220	}
   221	
   222	static void assertI2Tret(Type *t, Iface i, byte *ret);
   223	
   224	// func ifaceI2T(typ *byte, iface any) (ret any)
   225	#pragma textflag 7
   226	void
   227	runtime·assertI2T(Type *t, Iface i, ...)
   228	{
   229		byte *ret;
   230	
   231		ret = (byte*)(&i+1);
   232		assertI2Tret(t, i, ret);
   233	}
   234	
   235	static void
   236	assertI2Tret(Type *t, Iface i, byte *ret)
   237	{
   238		Itab *tab;
   239		Eface err;
   240	
   241		tab = i.tab;
   242		if(tab == nil) {
   243			runtime·newTypeAssertionError(nil, nil, t,
   244				nil, nil, t->string,
   245				nil, &err);
   246			runtime·panic(err);
   247		}
   248		if(tab->type != t) {
   249			runtime·newTypeAssertionError(tab->inter, tab->type, t,
   250				tab->inter->string, tab->type->string, t->string,
   251				nil, &err);
   252			runtime·panic(err);
   253		}
   254		copyout(t, &i.data, ret);
   255	}
   256	
   257	// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
   258	#pragma textflag 7
   259	void
   260	runtime·assertI2T2(Type *t, Iface i, ...)
   261	{
   262		byte *ret;
   263		bool *ok;
   264		int32 wid;
   265	
   266		ret = (byte*)(&i+1);
   267		wid = t->size;
   268		ok = (bool*)(ret + wid);
   269	
   270		if(i.tab == nil || i.tab->type != t) {
   271			*ok = false;
   272			runtime·memclr(ret, wid);
   273			return;
   274		}
   275	
   276		*ok = true;
   277		copyout(t, &i.data, ret);
   278	}
   279	
   280	static void assertE2Tret(Type *t, Eface e, byte *ret);
   281	
   282	// func ifaceE2T(typ *byte, iface any) (ret any)
   283	#pragma textflag 7
   284	void
   285	runtime·assertE2T(Type *t, Eface e, ...)
   286	{
   287		byte *ret;
   288	
   289		if(((uintptr)e.type&reflectFlags) != 0)
   290			runtime·throw("invalid interface value");
   291		ret = (byte*)(&e+1);
   292		assertE2Tret(t, e, ret);
   293	}
   294	
   295	static void
   296	assertE2Tret(Type *t, Eface e, byte *ret)
   297	{
   298		Eface err;
   299	
   300		if(((uintptr)e.type&reflectFlags) != 0)
   301			runtime·throw("invalid interface value");
   302		if(e.type == nil) {
   303			runtime·newTypeAssertionError(nil, nil, t,
   304				nil, nil, t->string,
   305				nil, &err);
   306			runtime·panic(err);
   307		}
   308		if(e.type != t) {
   309			runtime·newTypeAssertionError(nil, e.type, t,
   310				nil, e.type->string, t->string,
   311				nil, &err);
   312			runtime·panic(err);
   313		}
   314		copyout(t, &e.data, ret);
   315	}
   316	
   317	// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
   318	#pragma textflag 7
   319	void
   320	runtime·assertE2T2(Type *t, Eface e, ...)
   321	{
   322		byte *ret;
   323		bool *ok;
   324		int32 wid;
   325	
   326		if(((uintptr)e.type&reflectFlags) != 0)
   327			runtime·throw("invalid interface value");
   328		ret = (byte*)(&e+1);
   329		wid = t->size;
   330		ok = (bool*)(ret + wid);
   331	
   332		if(t != e.type) {
   333			*ok = false;
   334			runtime·memclr(ret, wid);
   335			return;
   336		}
   337	
   338		*ok = true;
   339		copyout(t, &e.data, ret);
   340	}
   341	
   342	// func convI2E(elem any) (ret any)
   343	void
   344	runtime·convI2E(Iface i, Eface ret)
   345	{
   346		Itab *tab;
   347	
   348		ret.data = i.data;
   349		if((tab = i.tab) == nil)
   350			ret.type = nil;
   351		else
   352			ret.type = tab->type;
   353		FLUSH(&ret);
   354	}
   355	
   356	// func ifaceI2E(typ *byte, iface any) (ret any)
   357	void
   358	runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
   359	{
   360		Itab *tab;
   361		Eface err;
   362	
   363		tab = i.tab;
   364		if(tab == nil) {
   365			// explicit conversions require non-nil interface value.
   366			runtime·newTypeAssertionError(nil, nil, inter,
   367				nil, nil, inter->string,
   368				nil, &err);
   369			runtime·panic(err);
   370		}
   371		ret.data = i.data;
   372		ret.type = tab->type;
   373		FLUSH(&ret);
   374	}
   375	
   376	// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
   377	void
   378	runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
   379	{
   380		Itab *tab;
   381	
   382		USED(inter);
   383		tab = i.tab;
   384		if(tab == nil) {
   385			ret.type = nil;
   386			ok = 0;
   387		} else {
   388			ret.type = tab->type;
   389			ok = 1;
   390		}
   391		ret.data = i.data;
   392		FLUSH(&ret);
   393		FLUSH(&ok);
   394	}
   395	
   396	// func convI2I(typ *byte, elem any) (ret any)
   397	void
   398	runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
   399	{
   400		Itab *tab;
   401		
   402		ret.data = i.data;
   403		if((tab = i.tab) == nil)
   404			ret.tab = nil;
   405		else if(tab->inter == inter)
   406			ret.tab = tab;
   407		else
   408			ret.tab = itab(inter, tab->type, 0);
   409		FLUSH(&ret);
   410	}
   411	
   412	void
   413	runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
   414	{
   415		Itab *tab;
   416		Eface err;
   417	
   418		tab = i.tab;
   419		if(tab == nil) {
   420			// explicit conversions require non-nil interface value.
   421			runtime·newTypeAssertionError(nil, nil, inter,
   422				nil, nil, inter->string,
   423				nil, &err);
   424			runtime·panic(err);
   425		}
   426		ret->data = i.data;
   427		ret->tab = itab(inter, tab->type, 0);
   428	}
   429	
   430	// func ifaceI2I(sigi *byte, iface any) (ret any)
   431	void
   432	runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
   433	{
   434		runtime·ifaceI2I(inter, i, &ret);
   435	}
   436	
   437	// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
   438	void
   439	runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
   440	{
   441		Itab *tab;
   442	
   443		tab = i.tab;
   444		if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) {
   445			ret.data = i.data;
   446			ret.tab = tab;
   447			ok = 1;
   448		} else {
   449			ret.data = 0;
   450			ret.tab = 0;
   451			ok = 0;
   452		}
   453		FLUSH(&ret);
   454		FLUSH(&ok);
   455	}
   456	
   457	void
   458	runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
   459	{
   460		Type *t;
   461		Eface err;
   462	
   463		if(((uintptr)e.type&reflectFlags) != 0)
   464			runtime·throw("invalid interface value");
   465		t = e.type;
   466		if(t == nil) {
   467			// explicit conversions require non-nil interface value.
   468			runtime·newTypeAssertionError(nil, nil, inter,
   469				nil, nil, inter->string,
   470				nil, &err);
   471			runtime·panic(err);
   472		}
   473		ret->data = e.data;
   474		ret->tab = itab(inter, t, 0);
   475	}
   476	
   477	// For reflect
   478	//	func ifaceE2I(t *InterfaceType, e interface{}, dst *Iface)
   479	void
   480	reflect·ifaceE2I(InterfaceType *inter, Eface e, Iface *dst)
   481	{
   482		runtime·ifaceE2I(inter, e, dst);
   483	}
   484	
   485	// func ifaceE2I(sigi *byte, iface any) (ret any)
   486	void
   487	runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
   488	{
   489		runtime·ifaceE2I(inter, e, &ret);
   490	}
   491	
   492	// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
   493	void
   494	runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
   495	{
   496		if(((uintptr)e.type&reflectFlags) != 0)
   497			runtime·throw("invalid interface value");
   498		if(e.type == nil) {
   499			ok = 0;
   500			ret.data = nil;
   501			ret.tab = nil;
   502		} else if((ret.tab = itab(inter, e.type, 1)) == nil) {
   503			ok = 0;
   504			ret.data = nil;
   505		} else {
   506			ok = 1;
   507			ret.data = e.data;
   508		}
   509		FLUSH(&ret);
   510		FLUSH(&ok);
   511	}
   512	
   513	// func ifaceE2E(typ *byte, iface any) (ret any)
   514	void
   515	runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
   516	{
   517		Type *t;
   518		Eface err;
   519	
   520		if(((uintptr)e.type&reflectFlags) != 0)
   521			runtime·throw("invalid interface value");
   522		t = e.type;
   523		if(t == nil) {
   524			// explicit conversions require non-nil interface value.
   525			runtime·newTypeAssertionError(nil, nil, inter,
   526				nil, nil, inter->string,
   527				nil, &err);
   528			runtime·panic(err);
   529		}
   530		ret = e;
   531		FLUSH(&ret);
   532	}
   533	
   534	// func ifaceE2E2(iface any) (ret any, ok bool)
   535	void
   536	runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
   537	{
   538		if(((uintptr)e.type&reflectFlags) != 0)
   539			runtime·throw("invalid interface value");
   540		USED(inter);
   541		ret = e;
   542		ok = e.type != nil;
   543		FLUSH(&ret);
   544		FLUSH(&ok);
   545	}
   546	
   547	static uintptr
   548	ifacehash1(void *data, Type *t)
   549	{
   550		int32 alg, wid;
   551		Eface err;
   552	
   553		if(t == nil)
   554			return 0;
   555	
   556		alg = t->alg;
   557		wid = t->size;
   558		if(runtime·algarray[alg].hash == runtime·nohash) {
   559			// calling nohash will panic too,
   560			// but we can print a better error.
   561			runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
   562			runtime·panic(err);
   563		}
   564		if(wid <= sizeof(data))
   565			return runtime·algarray[alg].hash(wid, &data);
   566		return runtime·algarray[alg].hash(wid, data);
   567	}
   568	
   569	uintptr
   570	runtime·ifacehash(Iface a)
   571	{
   572		if(a.tab == nil)
   573			return 0;
   574		return ifacehash1(a.data, a.tab->type);
   575	}
   576	
   577	uintptr
   578	runtime·efacehash(Eface a)
   579	{
   580		return ifacehash1(a.data, a.type);
   581	}
   582	
   583	static bool
   584	ifaceeq1(void *data1, void *data2, Type *t)
   585	{
   586		int32 alg, wid;
   587		Eface err;
   588	
   589		alg = t->alg;
   590		wid = t->size;
   591	
   592		if(runtime·algarray[alg].equal == runtime·noequal) {
   593			// calling noequal will panic too,
   594			// but we can print a better error.
   595			runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
   596			runtime·panic(err);
   597		}
   598	
   599		if(wid <= sizeof(data1))
   600			return runtime·algarray[alg].equal(wid, &data1, &data2);
   601		return runtime·algarray[alg].equal(wid, data1, data2);
   602	}
   603	
   604	bool
   605	runtime·ifaceeq_c(Iface i1, Iface i2)
   606	{
   607		if(i1.tab != i2.tab)
   608			return false;
   609		if(i1.tab == nil)
   610			return true;
   611		return ifaceeq1(i1.data, i2.data, i1.tab->type);
   612	}
   613	
   614	bool
   615	runtime·efaceeq_c(Eface e1, Eface e2)
   616	{
   617		if(((uintptr)e1.type&reflectFlags) != 0)
   618			runtime·throw("invalid interface value");
   619		if(((uintptr)e2.type&reflectFlags) != 0)
   620			runtime·throw("invalid interface value");
   621		if(e1.type != e2.type)
   622			return false;
   623		if(e1.type == nil)
   624			return true;
   625		return ifaceeq1(e1.data, e2.data, e1.type);
   626	}
   627	
   628	// ifaceeq(i1 any, i2 any) (ret bool);
   629	void
   630	runtime·ifaceeq(Iface i1, Iface i2, bool ret)
   631	{
   632		ret = runtime·ifaceeq_c(i1, i2);
   633		FLUSH(&ret);
   634	}
   635	
   636	// efaceeq(i1 any, i2 any) (ret bool)
   637	void
   638	runtime·efaceeq(Eface e1, Eface e2, bool ret)
   639	{
   640		ret = runtime·efaceeq_c(e1, e2);
   641		FLUSH(&ret);
   642	}
   643	
   644	// ifacethash(i1 any) (ret uint32);
   645	void
   646	runtime·ifacethash(Iface i1, uint32 ret)
   647	{
   648		Itab *tab;
   649	
   650		ret = 0;
   651		tab = i1.tab;
   652		if(tab != nil)
   653			ret = tab->type->hash;
   654		FLUSH(&ret);
   655	}
   656	
   657	// efacethash(e1 any) (ret uint32)
   658	void
   659	runtime·efacethash(Eface e1, uint32 ret)
   660	{
   661		Type *t;
   662	
   663		if(((uintptr)e1.type&reflectFlags) != 0)
   664			runtime·throw("invalid interface value");
   665		ret = 0;
   666		t = e1.type;
   667		if(t != nil)
   668			ret = t->hash;
   669		FLUSH(&ret);
   670	}
   671	
   672	void
   673	unsafe·Typeof(Eface e, Eface ret)
   674	{
   675		if(((uintptr)e.type&reflectFlags) != 0)
   676			runtime·throw("invalid interface value");
   677		if(e.type == nil) {
   678			ret.type = nil;
   679			ret.data = nil;
   680		} else {
   681			ret = *(Eface*)(e.type);
   682		}
   683		FLUSH(&ret);
   684	}
   685	
   686	void
   687	unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
   688	{
   689		uintptr *p;
   690		uintptr x;
   691	
   692		if(((uintptr)e.type&reflectFlags) != 0)
   693			runtime·throw("invalid interface value");
   694		if(e.type == nil) {
   695			rettype.type = nil;
   696			rettype.data = nil;
   697			retaddr = 0;
   698		} else {
   699			rettype = *(Eface*)e.type;
   700			if(e.type->size <= sizeof(uintptr)) {
   701				// Copy data into x ...
   702				x = 0;
   703				runtime·algarray[e.type->alg].copy(e.type->size, &x, &e.data);
   704	
   705				// but then build pointer to x so that Reflect
   706				// always returns pointer to data.
   707				p = runtime·mal(sizeof(uintptr));
   708				*p = x;
   709			} else {
   710				// Already a pointer, but still make a copy,
   711				// to preserve value semantics for interface data.
   712				p = runtime·mal(e.type->size);
   713				runtime·algarray[e.type->alg].copy(e.type->size, p, e.data);
   714			}
   715			retaddr = p;
   716		}
   717		FLUSH(&rettype);
   718		FLUSH(&retaddr);
   719	}
   720	
   721	void
   722	unsafe·Unreflect(Eface typ, void *addr, Eface e)
   723	{
   724		if(((uintptr)typ.type&reflectFlags) != 0)
   725			runtime·throw("invalid interface value");
   726	
   727		// Reflect library has reinterpreted typ
   728		// as its own kind of type structure.
   729		// We know that the pointer to the original
   730		// type structure sits before the data pointer.
   731		e.type = (Type*)((Eface*)typ.data-1);
   732	
   733		// Interface holds either pointer to data
   734		// or copy of original data.
   735		if(e.type->size <= sizeof(uintptr))
   736			runtime·algarray[e.type->alg].copy(e.type->size, &e.data, addr);
   737		else {
   738			// Easier: already a pointer to data.
   739			// TODO(rsc): Should this make a copy?
   740			e.data = addr;
   741		}
   742	
   743		FLUSH(&e);
   744	}
   745	
   746	void
   747	unsafe·New(Eface typ, void *ret)
   748	{
   749		Type *t;
   750	
   751		if(((uintptr)typ.type&reflectFlags) != 0)
   752			runtime·throw("invalid interface value");
   753	
   754		// Reflect library has reinterpreted typ
   755		// as its own kind of type structure.
   756		// We know that the pointer to the original
   757		// type structure sits before the data pointer.
   758		t = (Type*)((Eface*)typ.data-1);
   759	
   760		if(t->kind&KindNoPointers)
   761			ret = runtime·mallocgc(t->size, FlagNoPointers, 1, 1);
   762		else
   763			ret = runtime·mal(t->size);
   764		FLUSH(&ret);
   765	}
   766	
   767	void
   768	unsafe·NewArray(Eface typ, uint32 n, void *ret)
   769	{
   770		uint64 size;
   771		Type *t;
   772	
   773		if(((uintptr)typ.type&reflectFlags) != 0)
   774			runtime·throw("invalid interface value");
   775	
   776		// Reflect library has reinterpreted typ
   777		// as its own kind of type structure.
   778		// We know that the pointer to the original
   779		// type structure sits before the data pointer.
   780		t = (Type*)((Eface*)typ.data-1);
   781		
   782		size = n*t->size;
   783		if(t->kind&KindNoPointers)
   784			ret = runtime·mallocgc(size, FlagNoPointers, 1, 1);
   785		else
   786			ret = runtime·mal(size);
   787		FLUSH(&ret);
   788	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.