Commit b53b47f5 authored by Russ Cox's avatar Russ Cox

runtime: finish converting iface.goc to iface.go

LGTM=bradfitz, dvyukov
R=golang-codereviews, bradfitz, dvyukov
CC=golang-codereviews, iant, khr
https://golang.org/cl/131510043
parent 98e5a44a
...@@ -584,7 +584,10 @@ itab_callback(Itab *tab) ...@@ -584,7 +584,10 @@ itab_callback(Itab *tab)
static void static void
dumpitabs(void) dumpitabs(void)
{ {
runtime·iterate_itabs(itab_callback); void (*fn)(Itab*);
fn = itab_callback;
runtime·iterate_itabs(&fn);
} }
static void static void
......
...@@ -425,3 +425,16 @@ func efacethash(e interface{}) uint32 { ...@@ -425,3 +425,16 @@ func efacethash(e interface{}) uint32 {
} }
return t.hash return t.hash
} }
func iterate_itabs(fn func(*itab)) {
for _, h := range hash {
for ; h != nil; h = h.link {
fn(h)
}
}
}
func ifaceE2I2(inter *interfacetype, e interface{}, r *fInterface) (ok bool) {
*r, ok = assertE2I2(inter, e)
return
}
// 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.
package runtime
#include "runtime.h"
#include "arch_GOARCH.h"
#include "type.h"
#include "typekind.h"
#include "malloc.h"
#include "../../cmd/ld/textflag.h"
extern Itab* runtime·hash[1009];
extern Mutex runtime·ifaceLock;
// TODO: delete this when no longer used (ifaceE2I2 is all that's left)
static Itab*
itab(InterfaceType *inter, Type *type, int32 canfail)
{
int32 locked;
int32 ni;
Method *t, *et;
IMethod *i, *ei;
uint32 h;
String *iname, *ipkgPath;
Itab *m;
UncommonType *x;
Type *itype;
Eface err;
if(inter->mhdr.len == 0)
runtime·throw("internal error - misuse of itab");
locked = 0;
// easy case
x = type->x;
if(x == nil) {
if(canfail)
return nil;
iname = inter->m[0].name;
goto throw;
}
// compiler has provided some good hash codes for us.
h = inter->typ.hash;
h += 17 * type->hash;
// TODO(rsc): h += 23 * x->mhash ?
h %= nelem(runtime·hash);
// look twice - once without lock, once with.
// common case will be no lock contention.
for(locked=0; locked<2; locked++) {
if(locked)
runtime·lock(&runtime·ifaceLock);
for(m=runtime·atomicloadp(&runtime·hash[h]); m!=nil; m=m->link) {
if(m->inter == inter && m->type == type) {
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
// do more work but give a better error.
goto search;
}
}
if(locked)
runtime·unlock(&runtime·ifaceLock);
return m;
}
}
}
ni = inter->mhdr.len;
m = runtime·persistentalloc(sizeof(*m) + ni*sizeof m->fun[0], 0, &mstats.other_sys);
m->inter = inter;
m->type = type;
search:
// both inter and type 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).
i = inter->m;
ei = i + inter->mhdr.len;
t = x->m;
et = t + x->mhdr.len;
for(; i < ei; i++) {
itype = i->type;
iname = i->name;
ipkgPath = i->pkgPath;
for(;; t++) {
if(t >= et) {
if(!canfail) {
throw:
// didn't find method
runtime·newTypeAssertionError(
nil, type->string, inter->typ.string,
iname, &err);
if(locked)
runtime·unlock(&runtime·ifaceLock);
runtime·panic(err);
return nil; // not reached
}
m->bad = 1;
goto out;
}
if(t->mtyp == itype && t->name == iname && t->pkgPath == ipkgPath)
break;
}
if(m)
m->fun[i - inter->m] = t->ifn;
}
out:
if(!locked)
runtime·panicstring("invalid itab locking");
m->link = runtime·hash[h];
runtime·atomicstorep(&runtime·hash[h], m);
runtime·unlock(&runtime·ifaceLock);
if(m->bad)
return nil;
return m;
}
// call the callback for every itab that is currently allocated.
void
runtime·iterate_itabs(void (*callback)(Itab*))
{
int32 i;
Itab *tab;
for(i = 0; i < nelem(runtime·hash); i++) {
for(tab = runtime·hash[i]; tab != nil; tab = tab->link) {
callback(tab);
}
}
}
// Still in C because it is called from C for finalizers. This will
// get converted to Go in a separate CL. This is the last user of
// the C version of itab().
bool
runtime·ifaceE2I2(InterfaceType *inter, Eface e, Iface *ret)
{
ret->tab = itab(inter, e.type, 1);
if(ret->tab == nil)
return false;
ret->data = e.data;
return true;
}
...@@ -959,7 +959,7 @@ void _rt0_go(void); ...@@ -959,7 +959,7 @@ void _rt0_go(void);
void* runtime·funcdata(Func*, int32); void* runtime·funcdata(Func*, int32);
void runtime·setmaxthreads_m(void); void runtime·setmaxthreads_m(void);
G* runtime·timejump(void); G* runtime·timejump(void);
void runtime·iterate_itabs(void (*callback)(Itab*)); void runtime·iterate_itabs(void (**callback)(Itab*));
void runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*)); void runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*));
#pragma varargck argpos runtime·printf 1 #pragma varargck argpos runtime·printf 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment