-0176cbc6dbd2170bfe2eb8904b80ddfe4c946997
+199f175f4239d1ca6d7e80d08639955d41c3b09f
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
go_assert(this->channel_->type()->is_error());
return context->backend()->error_expression();
}
- Expression* td = Expression::make_type_descriptor(channel_type, loc);
Expression* recv_ref =
Expression::make_temporary_reference(this->temp_receiver_, loc);
Expression* recv_addr =
Expression::make_temporary_reference(this->temp_receiver_, loc);
recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc);
- Expression* recv = Runtime::make_call(Runtime::CHANRECV1, loc, 3,
- td, this->channel_, recv_addr);
+ Expression* recv = Runtime::make_call(Runtime::CHANRECV1, loc, 2,
+ this->channel_, recv_addr);
return Expression::make_compound(recv, recv_ref, loc)->get_backend(context);
}
DEF_GO_RUNTIME(MAKECHAN, "runtime.makechan", P2(TYPE, INT64), R1(CHAN))
// Send a value on a channel.
-DEF_GO_RUNTIME(CHANSEND, "runtime.chansend1", P3(TYPE, CHAN, POINTER), R0())
+DEF_GO_RUNTIME(CHANSEND, "runtime.chansend1", P2(CHAN, POINTER), R0())
// Receive a value from a channel.
-DEF_GO_RUNTIME(CHANRECV1, "runtime.chanrecv1", P3(TYPE, CHAN, POINTER), R0())
+DEF_GO_RUNTIME(CHANRECV1, "runtime.chanrecv1", P2(CHAN, POINTER), R0())
// Receive a value from a channel returning whether it is closed.
-DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER),
- R1(BOOL))
+DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL))
// Start building a select statement.
DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P3(POINTER, INT64, INT32), R0())
// Add a default clause to a select statement.
-DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault",
- P2(POINTER, INT32), R0())
+DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", P1(POINTER), R0())
// Add a send clause to a select statement.
-DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend",
- P4(POINTER, CHAN, POINTER, INT32), R0())
+DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend", P3(POINTER, CHAN, POINTER),
+ R0())
-// Add a receive clause to a select statement, for a clause which does
-// not check whether the channel is closed.
+// Add a receive clause to a select statement.
DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv",
- P4(POINTER, CHAN, POINTER, INT32), R0())
-
-// Add a receive clause to a select statement, for a clause which does
-// check whether the channel is closed.
-DEF_GO_RUNTIME(SELECTRECV2, "runtime.selectrecv2",
- P5(POINTER, CHAN, POINTER, BOOLPTR, INT32), R0())
+ P4(POINTER, CHAN, POINTER, BOOLPTR), R0())
// Run a select, returning the index of the selected clause.
-DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT32))
+DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P1(POINTER), R1(INT))
// Panic.
NULL, loc);
b->add_statement(closed_temp);
- // closed_temp = chanrecv2(type, channel, &val_temp)
- Expression* td = Expression::make_type_descriptor(this->channel_->type(),
- loc);
+ // closed_temp = chanrecv2(channel, &val_temp)
Temporary_reference_expression* ref =
Expression::make_temporary_reference(val_temp, loc);
Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
Expression* call = Runtime::make_call(Runtime::CHANRECV2,
- loc, 3, td, this->channel_, p2);
+ loc, 2, this->channel_, p2);
ref = Expression::make_temporary_reference(closed_temp, loc);
ref->set_is_lvalue();
Statement* s = Statement::make_assignment(ref, call, loc);
&& val->temporary_reference_expression() == NULL)
can_take_address = false;
- Expression* td = Expression::make_type_descriptor(this->channel_->type(),
- loc);
-
Bstatement* btemp = NULL;
if (can_take_address)
{
btemp = temp->get_backend(context);
}
- Expression* call = Runtime::make_call(Runtime::CHANSEND, loc, 3, td,
+ Expression* call = Runtime::make_call(Runtime::CHANSEND, loc, 2,
this->channel_, val);
context->gogo()->lower_expression(context->function(), NULL, &call);
Expression* selref = Expression::make_temporary_reference(sel, loc);
selref = Expression::make_unary(OPERATOR_AND, selref, loc);
- Expression* index_expr = Expression::make_integer_ul(this->index_, NULL,
- loc);
-
if (this->is_default_)
{
go_assert(this->channel_ == NULL && this->val_ == NULL);
- this->lower_default(b, selref, index_expr);
+ this->lower_default(b, selref);
this->is_lowered_ = true;
return;
}
loc);
if (this->is_send_)
- this->lower_send(b, selref, chanref, index_expr);
+ this->lower_send(b, selref, chanref);
else
- this->lower_recv(gogo, function, b, selref, chanref, index_expr);
+ this->lower_recv(gogo, function, b, selref, chanref);
// Now all references should be handled through the statements, not
// through here.
// Lower a default clause in a select statement.
void
-Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
- Expression* index_expr)
+Select_clauses::Select_clause::lower_default(Block* b, Expression* selref)
{
Location loc = this->location_;
- Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref,
- index_expr);
+ Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 1,
+ selref);
b->add_statement(Statement::make_statement(call, true));
}
void
Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
- Expression* chanref,
- Expression* index_expr)
+ Expression* chanref)
{
Location loc = this->location_;
Expression* valref = Expression::make_temporary_reference(val, loc);
Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
- Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref,
- chanref, valaddr, index_expr);
+ Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 3, selref,
+ chanref, valaddr);
b->add_statement(Statement::make_statement(call, true));
}
void
Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
Block* b, Expression* selref,
- Expression* chanref,
- Expression* index_expr)
+ Expression* chanref)
{
Location loc = this->location_;
Temporary_statement* closed_temp = NULL;
- Expression* call;
+ Expression* caddr;
if (this->closed_ == NULL && this->closedvar_ == NULL)
- call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref,
- valaddr, index_expr);
+ caddr = Expression::make_nil(loc);
else
{
closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL,
b->add_statement(closed_temp);
Expression* cref = Expression::make_temporary_reference(closed_temp,
loc);
- Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
- call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
- valaddr, caddr, index_expr);
+ caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
}
+ Expression* call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref,
+ chanref, valaddr, caddr);
+
b->add_statement(Statement::make_statement(call, true));
// If the block of statements is executed, arrange for the received
std::vector<std::vector<Bexpression*> > cases(count);
std::vector<Bstatement*> clauses(count);
- Type* int32_type = Type::lookup_integer_type("int32");
+ Type* int_type = Type::lookup_integer_type("int");
int i = 0;
for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end();
++p, ++i)
{
- int index = p->index();
- Expression* index_expr = Expression::make_integer_ul(index, int32_type,
+ Expression* index_expr = Expression::make_integer_ul(i, int_type,
location);
cases[i].push_back(index_expr->get_backend(context));
Named_object* var, Named_object* closedvar, bool is_default,
Block* statements, Location location)
{
- int index = static_cast<int>(this->clauses_.size());
- this->clauses_.push_back(Select_clause(index, is_send, channel, val,
- closed, var, closedvar, is_default,
- statements, location));
+ this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var,
+ closedvar, is_default, statements,
+ location));
}
size_t
is_default_(false)
{ }
- Select_clause(int index, bool is_send, Expression* channel,
- Expression* val, Expression* closed, Named_object* var,
+ Select_clause(bool is_send, Expression* channel, Expression* val,
+ Expression* closed, Named_object* var,
Named_object* closedvar, bool is_default, Block* statements,
Location location)
- : index_(index), channel_(channel), val_(val), closed_(closed),
- var_(var), closedvar_(closedvar), statements_(statements),
- location_(location), is_send_(is_send), is_default_(is_default),
- is_lowered_(false)
+ : channel_(channel), val_(val), closed_(closed), var_(var),
+ closedvar_(closedvar), statements_(statements), location_(location),
+ is_send_(is_send), is_default_(is_default), is_lowered_(false)
{ go_assert(is_default ? channel == NULL : channel != NULL); }
- // Return the index of this clause.
- int
- index() const
- { return this->index_; }
-
// Traverse the select clause.
int
traverse(Traverse*);
private:
void
- lower_default(Block*, Expression*, Expression*);
+ lower_default(Block*, Expression*);
void
- lower_send(Block*, Expression*, Expression*, Expression*);
+ lower_send(Block*, Expression*, Expression*);
void
- lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*,
- Expression*);
+ lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*);
- // The index of this case in the generated switch statement.
- int index_;
// The channel.
Expression* channel_;
// The value to send or the lvalue to receive into.
} else {
p = unsafe.Pointer(&val.ptr)
}
- selected, ok := chanrecv(v.typ, v.pointer(), nb, p)
+ selected, ok := chanrecv(v.pointer(), nb, p)
if !selected {
val = Value{}
}
} else {
p = unsafe.Pointer(&x.ptr)
}
- return chansend(v.typ, v.pointer(), p, nb)
+ return chansend(v.pointer(), p, nb)
}
// Set assigns x to the value v.
// (due to the escapes() call in ValueOf).
//go:noescape
-func chanrecv(t *rtype, ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
+func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, received bool)
//go:noescape
-func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
+func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
func makemap(t *rtype) (m unsafe.Pointer)
// entry point for c <- x from compiled code
//go:nosplit
-func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
- chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t)))
+func chansend1(c *hchan, elem unsafe.Pointer) {
+ chansend(c, elem, true, getcallerpc(unsafe.Pointer(&c)))
}
/*
* been closed. it is easiest to loop and re-run
* the operation; we'll see that it's now closed.
*/
-func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
- if raceenabled {
- raceReadObjectPC(t.elem, ep, callerpc, funcPC(chansend))
- }
- if msanenabled {
- msanread(ep, t.elem.size)
- }
-
+func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {
if c == nil {
if !block {
return false
// entry points for <- c from compiled code
//go:nosplit
-func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) {
- chanrecv(t, c, elem, true)
+func chanrecv1(c *hchan, elem unsafe.Pointer) {
+ chanrecv(c, elem, true)
}
//go:nosplit
-func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
- _, received = chanrecv(t, c, elem, true)
+func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) {
+ _, received = chanrecv(c, elem, true)
return
}
// Otherwise, if c is closed, zeros *ep and returns (true, false).
// Otherwise, fills in *ep with an element and returns (true, true).
// A non-nil ep must point to the heap or the caller's stack.
-func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
+func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
// raceenabled: don't need to check ep, as it is always on the stack
// or is new memory allocated by reflect.
// ... bar
// }
//
-func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
- return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t)))
+func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) {
+ return chansend(c, elem, false, getcallerpc(unsafe.Pointer(&c)))
}
// compiler implements
// ... bar
// }
//
-func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
- selected, _ = chanrecv(t, c, elem, false)
+func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected bool) {
+ selected, _ = chanrecv(c, elem, false)
return
}
// ... bar
// }
//
-func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
+func selectnbrecv2(elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
// TODO(khr): just return 2 values from this function, now that it is in Go.
- selected, *received = chanrecv(t, c, elem, false)
+ selected, *received = chanrecv(c, elem, false)
return
}
//go:linkname reflect_chansend reflect.chansend
-func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
- return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t)))
+func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
+ return chansend(c, elem, !nb, getcallerpc(unsafe.Pointer(&c)))
}
//go:linkname reflect_chanrecv reflect.chanrecv
-func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
- return chanrecv(t, c, elem, !nb)
+func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
+ return chanrecv(c, elem, !nb)
}
//go:linkname reflect_chanlen reflect.chanlen
//go:linkname selectdefault runtime.selectdefault
//go:linkname selectsend runtime.selectsend
//go:linkname selectrecv runtime.selectrecv
-//go:linkname selectrecv2 runtime.selectrecv2
//go:linkname selectgo runtime.selectgo
-const (
- debugSelect = false
+const debugSelect = false
+const (
// scase.kind
- caseRecv = iota
+ caseNil = iota
+ caseRecv
caseSend
caseDefault
)
type scase struct {
elem unsafe.Pointer // data element
c *hchan // chan
- pc uintptr // return pc
+ pc uintptr // return pc (for race detector / msan)
kind uint16
- index uint16 // case index
- receivedp *bool // pointer to received bool (recv2)
+ receivedp *bool // pointer to received bool, if any
releasetime int64
}
}
}
-func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer, index int32) {
- // nil cases do not compete
- if c != nil {
- selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, index)
- }
- return
-}
-
-// cut in half to give stack a chance to split
-func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, index int32) {
+func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) {
+ pc := getcallerpc(unsafe.Pointer(&sel))
i := sel.ncase
if i >= sel.tcase {
throw("selectsend: too many cases")
}
sel.ncase = i + 1
+ if c == nil {
+ return
+ }
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc
cas.c = c
- cas.index = uint16(index)
cas.kind = caseSend
cas.elem = elem
if debugSelect {
- print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " index=", cas.index, "\n")
- }
-}
-
-func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, index int32) {
- // nil cases do not compete
- if c != nil {
- selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, index)
+ print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
}
- return
}
-func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool, index int32) {
- // nil cases do not compete
- if c != nil {
- selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, index)
- }
- return
-}
-
-func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, index int32) {
+func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) {
+ pc := getcallerpc(unsafe.Pointer(&sel))
i := sel.ncase
if i >= sel.tcase {
throw("selectrecv: too many cases")
}
sel.ncase = i + 1
+ if c == nil {
+ return
+ }
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc
cas.c = c
- cas.index = uint16(index)
cas.kind = caseRecv
cas.elem = elem
cas.receivedp = received
if debugSelect {
- print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " index=", cas.index, "\n")
+ print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\n")
}
}
-func selectdefault(sel *hselect, index int32) {
- selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), index)
- return
-}
-
-func selectdefaultImpl(sel *hselect, callerpc uintptr, index int32) {
+func selectdefault(sel *hselect) {
+ pc := getcallerpc(unsafe.Pointer(&sel))
i := sel.ncase
if i >= sel.tcase {
throw("selectdefault: too many cases")
}
sel.ncase = i + 1
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
- cas.pc = callerpc
+ cas.pc = pc
cas.c = nil
- cas.index = uint16(index)
cas.kind = caseDefault
if debugSelect {
- print("selectdefault s=", sel, " pc=", hex(cas.pc), " index=", cas.index, "\n")
+ print("selectdefault s=", sel, " pc=", hex(cas.pc), "\n")
}
}
// the G that calls select runnable again and schedules it for execution.
// When the G runs on another M, it locks all the locks and frees sel.
// Now if the first M touches sel, it will access freed memory.
- n := len(scases)
- r := 0
- // skip the default case
- if n > 0 && scases[lockorder[0]].c == nil {
- r = 1
- }
- for i := n - 1; i >= r; i-- {
+ for i := len(scases) - 1; i >= 0; i-- {
c := scases[lockorder[i]].c
+ if c == nil {
+ break
+ }
if i > 0 && c == scases[lockorder[i-1]].c {
continue // will unlock it on the next iteration
}
// *sel is on the current goroutine's stack (regardless of any
// escaping in selectgo).
//
-// selectgo does not return. Instead, it overwrites its return PC and
-// returns directly to the triggered select case. Because of this, it
-// cannot appear at the top of a split stack.
-func selectgo(sel *hselect) int32 {
- _, index := selectgoImpl(sel)
- return int32(index)
-}
-
-// selectgoImpl returns scase.pc and scase.so for the select
-// case which fired.
-func selectgoImpl(sel *hselect) (uintptr, uint16) {
+// selectgo returns the index of the chosen scase, which matches the
+// ordinal position of its respective select{recv,send,default} call.
+func selectgo(sel *hselect) int {
if debugSelect {
print("select: sel=", sel, "\n")
}
+ if sel.ncase != sel.tcase {
+ throw("selectgo: case count mismatch")
+ }
scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
loop:
// pass 1 - look for something already waiting
+ var dfli int
var dfl *scase
+ var casi int
var cas *scase
for i := 0; i < int(sel.ncase); i++ {
- cas = &scases[pollorder[i]]
+ casi = int(pollorder[i])
+ cas = &scases[casi]
c = cas.c
switch cas.kind {
+ case caseNil:
+ continue
+
case caseRecv:
sg = c.sendq.dequeue()
if sg != nil {
}
case caseDefault:
+ dfli = casi
dfl = cas
}
}
if dfl != nil {
selunlock(scases, lockorder)
+ casi = dfli
cas = dfl
goto retc
}
}
nextp = &gp.waiting
for _, casei := range lockorder {
- cas = &scases[casei]
+ casi = int(casei)
+ cas = &scases[casi]
+ if cas.kind == caseNil {
+ continue
+ }
c = cas.c
sg := acquireSudog()
sg.g = gp
// otherwise they stack up on quiet channels
// record the successful case, if any.
// We singly-linked up the SudoGs in lock order.
+ casi = -1
cas = nil
sglist = gp.waiting
// Clear all elem before unlinking from gp.waiting.
for _, casei := range lockorder {
k = &scases[casei]
+ if k.kind == caseNil {
+ continue
+ }
if sglist.releasetime > 0 {
k.releasetime = sglist.releasetime
}
if sg == sglist {
// sg has already been dequeued by the G that woke us up.
+ casi = int(casei)
cas = k
} else {
c = k.c
if cas.releasetime > 0 {
blockevent(cas.releasetime-t0, 2)
}
- return cas.pc, cas.index
+ return casi
sclose:
// send on closed channel
rc := &cases[i]
switch rc.dir {
case selectDefault:
- selectdefaultImpl(sel, uintptr(i), 0)
+ selectdefault(sel)
case selectSend:
- if rc.ch == nil {
- break
- }
- selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0)
+ selectsend(sel, rc.ch, rc.val)
case selectRecv:
- if rc.ch == nil {
- break
- }
- selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0)
+ selectrecv(sel, rc.ch, rc.val, r)
}
}
- pc, _ := selectgoImpl(sel)
- chosen = int(pc)
+ chosen = selectgo(sel)
recvOK = *r
return
}