diff options
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 5 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 26 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 54 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 32 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 8 | ||||
-rw-r--r-- | libgo/go/runtime/chan.go | 43 | ||||
-rw-r--r-- | libgo/go/runtime/select.go | 135 |
8 files changed, 122 insertions, 183 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 7c78efc..b07bce8 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -0176cbc6dbd2170bfe2eb8904b80ddfe4c946997 +199f175f4239d1ca6d7e80d08639955d41c3b09f The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 82de4d8..8816232 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -14463,15 +14463,14 @@ Receive_expression::do_get_backend(Translate_context* context) 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); } diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 635b7fe..6df5349 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -137,39 +137,31 @@ DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(POINTER), R0()) 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. diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index e592176..eb370f8 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -1517,14 +1517,12 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*, 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); @@ -4516,9 +4514,6 @@ Send_statement::do_get_backend(Translate_context* context) && 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) { @@ -4539,7 +4534,7 @@ Send_statement::do_get_backend(Translate_context* context) 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); @@ -4621,13 +4616,10 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, 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; } @@ -4641,9 +4633,9 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, 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. @@ -4654,12 +4646,11 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, // 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)); } @@ -4667,8 +4658,7 @@ Select_clauses::Select_clause::lower_default(Block* b, Expression* selref, void Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, - Expression* chanref, - Expression* index_expr) + Expression* chanref) { Location loc = this->location_; @@ -4687,8 +4677,8 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, 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)); } @@ -4697,8 +4687,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, 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_; @@ -4715,10 +4704,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, 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, @@ -4726,11 +4714,12 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, 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 @@ -4958,15 +4947,14 @@ Select_clauses::get_backend(Translate_context* context, 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)); diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index dac99de..852ab43 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -899,10 +899,9 @@ class Select_clauses 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 @@ -950,21 +949,15 @@ class Select_clauses 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*); @@ -1025,17 +1018,14 @@ class Select_clauses 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. diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 208bb2f..8f6a93b 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -1160,7 +1160,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) { } 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{} } @@ -1191,7 +1191,7 @@ func (v Value) send(x Value, nb bool) (selected bool) { } 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. @@ -2327,10 +2327,10 @@ func chanlen(ch unsafe.Pointer) int // (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) diff --git a/libgo/go/runtime/chan.go b/libgo/go/runtime/chan.go index a9574dd..d2470bd 100644 --- a/libgo/go/runtime/chan.go +++ b/libgo/go/runtime/chan.go @@ -118,8 +118,8 @@ func chanbuf(c *hchan, i uint) 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))) } /* @@ -134,14 +134,7 @@ func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) { * 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 @@ -400,13 +393,13 @@ func closechan(c *hchan) { // 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 } @@ -416,7 +409,7 @@ func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) { // 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. @@ -609,8 +602,8 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) { // ... 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 @@ -630,8 +623,8 @@ func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) { // ... 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 } @@ -652,20 +645,20 @@ func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) { // ... 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 diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go index 62c4049..f0cad1b 100644 --- a/libgo/go/runtime/select.go +++ b/libgo/go/runtime/select.go @@ -18,14 +18,14 @@ import ( //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 ) @@ -47,10 +47,9 @@ type hselect struct { 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 } @@ -88,88 +87,64 @@ func newselect(sel *hselect, selsize int64, size int32) { } } -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") } } @@ -193,14 +168,11 @@ func selunlock(scases []scase, lockorder []uint16) { // 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 } @@ -241,20 +213,15 @@ func block() { // *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)) @@ -347,13 +314,19 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) { 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 { @@ -382,12 +355,14 @@ loop: } case caseDefault: + dfli = casi dfl = cas } } if dfl != nil { selunlock(scases, lockorder) + casi = dfli cas = dfl goto retc } @@ -400,7 +375,11 @@ loop: } 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 @@ -494,6 +473,7 @@ loop: // 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. @@ -506,11 +486,15 @@ loop: 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 @@ -659,7 +643,7 @@ retc: if cas.releasetime > 0 { blockevent(cas.releasetime-t0, 2) } - return cas.pc, cas.index + return casi sclose: // send on closed channel @@ -703,22 +687,15 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { 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 } |