Commit ccdb5093 authored by Russ Cox's avatar Russ Cox

cmd/gc, runtime: make assertI2T and variants not variadic

A side effect of this change is that when assertI2T writes to the
memory for the T being extracted, it can use typedmemmove
for write barriers.

There are other ways we could have done this, but this one
finishes a TODO in package runtime.

Found with GODEBUG=wbshadow=2 mode.
Eventually that will run automatically, but right now
it still detects other missing write barriers.

Change-Id: Icbc8aabfd8a9b1f00be2e421af0e3b29fa54d01e
Reviewed-on: https://go-review.googlesource.com/2279Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent e5ef6572
...@@ -48,20 +48,18 @@ char *runtimeimport = ...@@ -48,20 +48,18 @@ char *runtimeimport =
"func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" "func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n"
"func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n" "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n"
"func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n" "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n"
"func @\"\".assertE2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" "func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
"func @\"\".assertE2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n" "func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
"func @\"\".assertE2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" "func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
"func @\"\".assertE2I2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n" "func @\"\".assertE2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
"func @\"\".assertE2T (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" "func @\"\".assertE2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
"func @\"\".assertE2T2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n" "func @\"\".assertE2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
"func @\"\".assertI2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" "func @\"\".assertI2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
"func @\"\".assertI2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n" "func @\"\".assertI2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
"func @\"\".assertI2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" "func @\"\".assertI2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
"func @\"\".assertI2I2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n" "func @\"\".assertI2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
"func @\"\".assertI2T (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n" "func @\"\".assertI2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n"
"func @\"\".assertI2T2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n" "func @\"\".assertI2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n"
"func @\"\".assertI2TOK (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ok·1 bool)\n"
"func @\"\".assertE2TOK (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ok·1 bool)\n"
"func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" "func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
"func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" "func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
......
...@@ -497,7 +497,7 @@ orderstmt(Node *n, Order *order) ...@@ -497,7 +497,7 @@ orderstmt(Node *n, Order *order)
int lno; int lno;
NodeList *l, *t, *t1; NodeList *l, *t, *t1;
Node *r, *tmp1, *tmp2, **np; Node *r, *tmp1, *tmp2, **np;
Type *ch; Type *ch, *typ;
if(n == N) if(n == N)
return; return;
...@@ -516,7 +516,6 @@ orderstmt(Node *n, Order *order) ...@@ -516,7 +516,6 @@ orderstmt(Node *n, Order *order)
case OAS: case OAS:
case OAS2: case OAS2:
case OAS2DOTTYPE:
case OCLOSE: case OCLOSE:
case OCOPY: case OCOPY:
case OPRINT: case OPRINT:
...@@ -588,9 +587,29 @@ orderstmt(Node *n, Order *order) ...@@ -588,9 +587,29 @@ orderstmt(Node *n, Order *order)
cleantemp(t, order); cleantemp(t, order);
break; break;
case OAS2DOTTYPE:
// Special: use temporary variables to hold result,
// so that assertI2Tetc can take address of temporary.
// No temporary for blank assignment.
t = marktemp(order);
orderexprlist(n->list, order);
orderexpr(&n->rlist->n->left, order); // i in i.(T)
if(isblank(n->list->n))
order->out = list(order->out, n);
else {
typ = n->rlist->n->type;
tmp1 = ordertemp(typ, order, haspointers(typ));
order->out = list(order->out, n);
r = nod(OAS, n->list->n, tmp1);
typecheck(&r, Etop);
ordermapassign(r, order);
n->list = list(list1(tmp1), n->list->next->n);
}
cleantemp(t, order);
break;
case OAS2RECV: case OAS2RECV:
// Special: avoid copy of receive. // Special: use temporary variables to hold result,
// Use temporary variables to hold result,
// so that chanrecv can take address of temporary. // so that chanrecv can take address of temporary.
t = marktemp(order); t = marktemp(order);
orderexprlist(n->list, order); orderexprlist(n->list, order);
...@@ -1077,6 +1096,7 @@ orderexpr(Node **np, Order *order) ...@@ -1077,6 +1096,7 @@ orderexpr(Node **np, Order *order)
break; break;
case ORECV: case ORECV:
case ODOTTYPE:
orderexpr(&n->left, order); orderexpr(&n->left, order);
n = ordercopyexpr(n, n->type, order, 1); n = ordercopyexpr(n, n->type, order, 1);
break; break;
......
...@@ -66,20 +66,18 @@ func convT2E(typ *byte, elem *any) (ret any) ...@@ -66,20 +66,18 @@ func convT2E(typ *byte, elem *any) (ret any)
func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any) func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any)
// interface type assertions x.(T) // interface type assertions x.(T)
func assertE2E(typ *byte, iface any) (ret any) func assertE2E(typ *byte, iface any, ret *any)
func assertE2E2(typ *byte, iface any) (ret any, ok bool) func assertE2E2(typ *byte, iface any, ret *any) bool
func assertE2I(typ *byte, iface any) (ret any) func assertE2I(typ *byte, iface any, ret *any)
func assertE2I2(typ *byte, iface any) (ret any, ok bool) func assertE2I2(typ *byte, iface any, ret *any) bool
func assertE2T(typ *byte, iface any) (ret any) func assertE2T(typ *byte, iface any, ret *any)
func assertE2T2(typ *byte, iface any) (ret any, ok bool) func assertE2T2(typ *byte, iface any, ret *any) bool
func assertI2E(typ *byte, iface any) (ret any) func assertI2E(typ *byte, iface any, ret *any)
func assertI2E2(typ *byte, iface any) (ret any, ok bool) func assertI2E2(typ *byte, iface any, ret *any) bool
func assertI2I(typ *byte, iface any) (ret any) func assertI2I(typ *byte, iface any, ret *any)
func assertI2I2(typ *byte, iface any) (ret any, ok bool) func assertI2I2(typ *byte, iface any, ret *any) bool
func assertI2T(typ *byte, iface any) (ret any) func assertI2T(typ *byte, iface any, ret *any)
func assertI2T2(typ *byte, iface any) (ret any, ok bool) func assertI2T2(typ *byte, iface any, ret *any) bool
func assertI2TOK(typ *byte, iface any) (ok bool)
func assertE2TOK(typ *byte, iface any) (ok bool)
func ifaceeq(i1 any, i2 any) (ret bool) func ifaceeq(i1 any, i2 any) (ret bool)
func efaceeq(i1 any, i2 any) (ret bool) func efaceeq(i1 any, i2 any) (ret bool)
......
...@@ -408,7 +408,7 @@ walkexprlistcheap(NodeList *l, NodeList **init) ...@@ -408,7 +408,7 @@ walkexprlistcheap(NodeList *l, NodeList **init)
void void
walkexpr(Node **np, NodeList **init) walkexpr(Node **np, NodeList **init)
{ {
Node *r, *l, *var, *a; Node *r, *l, *var, *a, *ok;
Node *map, *key; Node *map, *key;
NodeList *ll, *lr; NodeList *ll, *lr;
Type *t; Type *t;
...@@ -665,6 +665,29 @@ walkexpr(Node **np, NodeList **init) ...@@ -665,6 +665,29 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->right, init); walkexpr(&n->right, init);
break; break;
case ODOTTYPE:
// x = i.(T); n->left is x, n->right->left is i.
// orderstmt made sure x is addressable.
walkexpr(&n->right->left, init);
n1 = nod(OADDR, n->left, N);
r = n->right; // i.(T)
strcpy(buf, "assertI2T");
if(isnilinter(r->left->type))
buf[6] = 'E';
if(isnilinter(r->type))
buf[8] = 'E';
else if(isinter(r->type))
buf[8] = 'I';
fn = syslook(buf, 1);
argtype(fn, r->left->type);
argtype(fn, r->type);
n = mkcall1(fn, T, init, typename(r->type), r->left, n1);
walkexpr(&n, init);
goto ret;
case ORECV: case ORECV:
// x = <-c; n->left is x, n->right->left is c. // x = <-c; n->left is x, n->right->left is c.
// orderstmt made sure x is addressable. // orderstmt made sure x is addressable.
...@@ -810,77 +833,42 @@ walkexpr(Node **np, NodeList **init) ...@@ -810,77 +833,42 @@ walkexpr(Node **np, NodeList **init)
case OAS2DOTTYPE: case OAS2DOTTYPE:
// a,b = i.(T) // a,b = i.(T)
// orderstmt made sure a is addressable.
*init = concat(*init, n->ninit); *init = concat(*init, n->ninit);
n->ninit = nil; n->ninit = nil;
r = n->rlist->n; r = n->rlist->n;
walkexprlistsafe(n->list, init); walkexprlistsafe(n->list, init);
if(isblank(n->list->n) && !isinter(r->type)) { walkexpr(&r->left, init);
strcpy(buf, "assert"); if(isblank(n->list->n))
p = buf+strlen(buf); n1 = nodnil();
if(isnilinter(r->left->type))
*p++ = 'E';
else else
*p++ = 'I'; n1 = nod(OADDR, n->list->n, N);
*p++ = '2'; n1->etype = 1; // addr does not escape
*p++ = 'T';
*p++ = 'O';
*p++ = 'K';
*p = '\0';
fn = syslook(buf, 1); strcpy(buf, "assertI2T2");
if(isnilinter(r->left->type))
buf[6] = 'E';
if(isnilinter(r->type))
buf[8] = 'E';
else if(isinter(r->type))
buf[8] = 'I';
// runtime.assert(E|I)2TOK returns a typed bool, but due fn = syslook(buf, 1);
// to spec changes, the boolean result of i.(T) is now untyped
// so we make it the same type as the variable on the lhs.
if(!isblank(n->list->next->n))
fn->type->type->down->type->type = n->list->next->n->type;
ll = list1(typename(r->type));
ll = list(ll, r->left);
argtype(fn, r->left->type); argtype(fn, r->left->type);
n1 = nod(OCALL, fn, N); argtype(fn, r->type);
n1->list = ll;
n = nod(OAS, n->list->next->n, n1); t = types[TBOOL];
ok = n->list->next->n;
if(!isblank(ok))
t = ok->type;
r = mkcall1(fn, t, init, typename(r->type), r->left, n1);
n = nod(OAS, ok, r);
typecheck(&n, Etop); typecheck(&n, Etop);
walkexpr(&n, init);
goto ret;
}
r->op = ODOTTYPE2;
walkexpr(&r, init);
ll = ascompatet(n->op, n->list, &r->type, 0, init);
n = liststmt(concat(list1(r), ll));
goto ret; goto ret;
case ODOTTYPE: case ODOTTYPE:
case ODOTTYPE2: case ODOTTYPE2:
// Build name of function: assertI2E2 etc. fatal("walkexpr ODOTTYPE"); // should see inside OAS or OAS2 only
strcpy(buf, "assert");
p = buf+strlen(buf);
if(isnilinter(n->left->type))
*p++ = 'E';
else
*p++ = 'I';
*p++ = '2';
if(isnilinter(n->type))
*p++ = 'E';
else if(isinter(n->type))
*p++ = 'I';
else
*p++ = 'T';
if(n->op == ODOTTYPE2)
*p++ = '2';
*p = '\0';
fn = syslook(buf, 1);
ll = list1(typename(n->type));
ll = list(ll, n->left);
argtype(fn, n->left->type);
argtype(fn, n->type);
n = nod(OCALL, fn, N);
n->list = ll;
typecheck(&n, Erv | Efnstruct);
walkexpr(&n, init);
goto ret;
case OCONVIFACE: case OCONVIFACE:
walkexpr(&n->left, init); walkexpr(&n->left, init);
......
...@@ -166,10 +166,7 @@ func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) ...@@ -166,10 +166,7 @@ func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer)
return return
} }
// TODO: give these routines a pointer to the result area instead of writing func assertI2T(t *_type, i fInterface, r unsafe.Pointer) {
// extra data in the outargs section. Then we can get rid of go:nosplit.
//go:nosplit
func assertI2T(t *_type, i fInterface) (r struct{}) {
ip := (*iface)(unsafe.Pointer(&i)) ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab tab := ip.tab
if tab == nil { if tab == nil {
...@@ -178,51 +175,35 @@ func assertI2T(t *_type, i fInterface) (r struct{}) { ...@@ -178,51 +175,35 @@ func assertI2T(t *_type, i fInterface) (r struct{}) {
if tab._type != t { if tab._type != t {
panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""}) panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
} }
// NOTE(rsc): If this changes to take a pointer argument if r != nil {
// instead of using &r, these calls need to change to be
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), uintptr(t.size)) writebarrierptr((*uintptr)(r), uintptr(ip.data))
} else { } else {
memmove(unsafe.Pointer(&r), ip.data, uintptr(t.size)) typedmemmove(t, r, ip.data)
}
} }
return
} }
//go:nosplit func assertI2T2(t *_type, i fInterface, r unsafe.Pointer) bool {
func assertI2T2(t *_type, i fInterface) (r byte) {
ip := (*iface)(unsafe.Pointer(&i)) ip := (*iface)(unsafe.Pointer(&i))
ok := (*bool)(add(unsafe.Pointer(&r), uintptr(t.size)))
tab := ip.tab tab := ip.tab
if tab == nil || tab._type != t { if tab == nil || tab._type != t {
*ok = false if r != nil {
memclr(unsafe.Pointer(&r), uintptr(t.size)) memclr(r, uintptr(t.size))
return }
return false
} }
*ok = true if r != nil {
// NOTE(rsc): If this changes to take a pointer argument
// instead of using &r, these calls need to change to be
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), uintptr(t.size)) writebarrierptr((*uintptr)(r), uintptr(ip.data))
} else { } else {
memmove(unsafe.Pointer(&r), ip.data, uintptr(t.size)) typedmemmove(t, r, ip.data)
} }
return }
} return true
func assertI2TOK(t *_type, i fInterface) bool {
ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab
return tab != nil && tab._type == t
} }
//go:nosplit func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
func assertE2T(t *_type, e interface{}) (r struct{}) {
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
if ep._type == nil { if ep._type == nil {
panic(&TypeAssertionError{"", "", *t._string, ""}) panic(&TypeAssertionError{"", "", *t._string, ""})
...@@ -230,46 +211,31 @@ func assertE2T(t *_type, e interface{}) (r struct{}) { ...@@ -230,46 +211,31 @@ func assertE2T(t *_type, e interface{}) (r struct{}) {
if ep._type != t { if ep._type != t {
panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""}) panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
} }
// NOTE(rsc): If this changes to take a pointer argument if r != nil {
// instead of using &r, these calls need to change to be
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), uintptr(t.size)) writebarrierptr((*uintptr)(r), uintptr(ep.data))
} else { } else {
memmove(unsafe.Pointer(&r), ep.data, uintptr(t.size)) typedmemmove(t, r, ep.data)
}
} }
return
} }
//go:nosplit func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
func assertE2T2(t *_type, e interface{}) (r byte) {
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
size := uintptr(t.size)
ok := (*bool)(add(unsafe.Pointer(&r), size))
if ep._type != t { if ep._type != t {
*ok = false if r != nil {
memclr(unsafe.Pointer(&r), size) memclr(r, uintptr(t.size))
return
} }
*ok = true return false
// NOTE(rsc): If this changes to take a pointer argument }
// instead of using &r, these calls need to change to be if r != nil {
// typedmemmove (the first can be just writebarrierptr).
// Until then, it is very important that no blocking operation
// happens between the memmove and the return.
if isDirectIface(t) { if isDirectIface(t) {
memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size) writebarrierptr((*uintptr)(r), uintptr(ep.data))
} else { } else {
memmove(unsafe.Pointer(&r), ep.data, size) typedmemmove(t, r, ep.data)
} }
return }
} return true
func assertE2TOK(t *_type, e interface{}) bool {
ep := (*eface)(unsafe.Pointer(&e))
return t == ep._type
} }
func convI2E(i fInterface) (r interface{}) { func convI2E(i fInterface) (r interface{}) {
...@@ -284,30 +250,31 @@ func convI2E(i fInterface) (r interface{}) { ...@@ -284,30 +250,31 @@ func convI2E(i fInterface) (r interface{}) {
return return
} }
func assertI2E(inter *interfacetype, i fInterface) (r interface{}) { func assertI2E(inter *interfacetype, i fInterface, r *interface{}) {
ip := (*iface)(unsafe.Pointer(&i)) ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab tab := ip.tab
if tab == nil { if tab == nil {
// explicit conversions require non-nil interface value. // explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
} }
rp := (*eface)(unsafe.Pointer(&r)) rp := (*eface)(unsafe.Pointer(r))
rp._type = tab._type rp._type = tab._type
rp.data = ip.data rp.data = ip.data
return return
} }
func assertI2E2(inter *interfacetype, i fInterface) (r interface{}, ok bool) { func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
ip := (*iface)(unsafe.Pointer(&i)) ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab tab := ip.tab
if tab == nil { if tab == nil {
return return false
} }
rp := (*eface)(unsafe.Pointer(&r)) if r != nil {
rp := (*eface)(unsafe.Pointer(r))
rp._type = tab._type rp._type = tab._type
rp.data = ip.data rp.data = ip.data
ok = true }
return return true
} }
func convI2I(inter *interfacetype, i fInterface) (r fInterface) { func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
...@@ -327,14 +294,14 @@ func convI2I(inter *interfacetype, i fInterface) (r fInterface) { ...@@ -327,14 +294,14 @@ func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
return return
} }
func assertI2I(inter *interfacetype, i fInterface) (r fInterface) { func assertI2I(inter *interfacetype, i fInterface, r *fInterface) {
ip := (*iface)(unsafe.Pointer(&i)) ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab tab := ip.tab
if tab == nil { if tab == nil {
// explicit conversions require non-nil interface value. // explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
} }
rp := (*iface)(unsafe.Pointer(&r)) rp := (*iface)(unsafe.Pointer(r))
if tab.inter == inter { if tab.inter == inter {
rp.tab = tab rp.tab = tab
rp.data = ip.data rp.data = ip.data
...@@ -342,85 +309,96 @@ func assertI2I(inter *interfacetype, i fInterface) (r fInterface) { ...@@ -342,85 +309,96 @@ func assertI2I(inter *interfacetype, i fInterface) (r fInterface) {
} }
rp.tab = getitab(inter, tab._type, false) rp.tab = getitab(inter, tab._type, false)
rp.data = ip.data rp.data = ip.data
return
} }
func assertI2I2(inter *interfacetype, i fInterface) (r fInterface, ok bool) { func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool {
ip := (*iface)(unsafe.Pointer(&i)) ip := (*iface)(unsafe.Pointer(&i))
tab := ip.tab tab := ip.tab
if tab == nil { if tab == nil {
return if r != nil {
*r = nil
} }
rp := (*iface)(unsafe.Pointer(&r)) return false
if tab.inter == inter {
rp.tab = tab
rp.data = ip.data
ok = true
return
} }
if tab.inter != inter {
tab = getitab(inter, tab._type, true) tab = getitab(inter, tab._type, true)
if tab == nil { if tab == nil {
rp.data = nil if r != nil {
rp.tab = nil *r = nil
ok = false
return
} }
return false
}
}
if r != nil {
rp := (*iface)(unsafe.Pointer(r))
rp.tab = tab rp.tab = tab
rp.data = ip.data rp.data = ip.data
ok = true }
return return true
} }
func assertE2I(inter *interfacetype, e interface{}) (r fInterface) { func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
t := ep._type t := ep._type
if t == nil { if t == nil {
// explicit conversions require non-nil interface value. // explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
} }
rp := (*iface)(unsafe.Pointer(&r)) rp := (*iface)(unsafe.Pointer(r))
rp.tab = getitab(inter, t, false) rp.tab = getitab(inter, t, false)
rp.data = ep.data rp.data = ep.data
return
} }
func assertE2I2(inter *interfacetype, e interface{}) (r fInterface, ok bool) { func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
t := ep._type t := ep._type
if t == nil { if t == nil {
return if r != nil {
*r = nil
}
return false
} }
tab := getitab(inter, t, true) tab := getitab(inter, t, true)
if tab == nil { if tab == nil {
return if r != nil {
*r = nil
} }
rp := (*iface)(unsafe.Pointer(&r)) return false
}
if r != nil {
rp := (*iface)(unsafe.Pointer(r))
rp.tab = tab rp.tab = tab
rp.data = ep.data rp.data = ep.data
ok = true }
return return true
} }
//go:linkname reflect_ifaceE2I reflect.ifaceE2I //go:linkname reflect_ifaceE2I reflect.ifaceE2I
func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) { func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) {
*dst = assertE2I(inter, e) assertE2I(inter, e, dst)
} }
func assertE2E(inter *interfacetype, e interface{}) interface{} { func assertE2E(inter *interfacetype, e interface{}, r *interface{}) {
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
if ep._type == nil { if ep._type == nil {
// explicit conversions require non-nil interface value. // explicit conversions require non-nil interface value.
panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
} }
return e *r = e
} }
func assertE2E2(inter *interfacetype, e interface{}) (interface{}, bool) { func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
ep := (*eface)(unsafe.Pointer(&e)) ep := (*eface)(unsafe.Pointer(&e))
if ep._type == nil { if ep._type == nil {
return nil, false if r != nil {
*r = nil
}
return false
}
if r != nil {
*r = e
} }
return e, true return true
} }
func ifacethash(i fInterface) uint32 { func ifacethash(i fInterface) uint32 {
...@@ -448,8 +426,3 @@ func iterate_itabs(fn func(*itab)) { ...@@ -448,8 +426,3 @@ func iterate_itabs(fn func(*itab)) {
} }
} }
} }
func ifaceE2I2(inter *interfacetype, e interface{}, r *fInterface) (ok bool) {
*r, ok = assertE2I2(inter, e)
return
}
...@@ -807,7 +807,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { ...@@ -807,7 +807,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
// ok - satisfies empty interface // ok - satisfies empty interface
goto okarg goto okarg
} }
if _, ok := assertE2I2(ityp, obj); ok { if assertE2I2(ityp, obj, nil) {
goto okarg goto okarg
} }
} }
...@@ -937,7 +937,7 @@ func runfinq() { ...@@ -937,7 +937,7 @@ func runfinq() {
if len(ityp.mhdr) != 0 { if len(ityp.mhdr) != 0 {
// convert to interface with methods // convert to interface with methods
// this conversion is guaranteed to succeed - we checked in SetFinalizer // this conversion is guaranteed to succeed - we checked in SetFinalizer
*(*fInterface)(frame) = assertE2I(ityp, *(*interface{})(frame)) assertE2I(ityp, *(*interface{})(frame), (*fInterface)(frame))
} }
default: default:
throw("bad kind in runfinq") throw("bad kind in runfinq")
......
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