Commit 022aa0ce by Ian Lance Taylor

compiler, runtime: simplify select and channel operations

    
    In preparation for upgrading libgo to the 1.9 release, this
    approximately incorporates https://golang.org/cl/37661 and
    https://golang.org/cl/38351.
    
    CL 37661 changed the gc compiler such that the select statement simply
    returns an integer which is then used as the argument for a switch.
    Since gccgo already worked that way, this just adjusts the switch code
    to look like the gc switch code by removing the explicit case index
    expression and calculating it from the order of calls to selectsend,
    selectrecv, and selectdefault.
    
    CL 38351 simplifies the channel code by not passing the unused channel
    type descriptor pointer.
    
    Reviewed-on: https://go-review.googlesource.com/62730

From-SVN: r252749
parent 0468f67f
0176cbc6dbd2170bfe2eb8904b80ddfe4c946997 199f175f4239d1ca6d7e80d08639955d41c3b09f
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -14463,15 +14463,14 @@ Receive_expression::do_get_backend(Translate_context* context) ...@@ -14463,15 +14463,14 @@ Receive_expression::do_get_backend(Translate_context* context)
go_assert(this->channel_->type()->is_error()); go_assert(this->channel_->type()->is_error());
return context->backend()->error_expression(); return context->backend()->error_expression();
} }
Expression* td = Expression::make_type_descriptor(channel_type, loc);
Expression* recv_ref = Expression* recv_ref =
Expression::make_temporary_reference(this->temp_receiver_, loc); Expression::make_temporary_reference(this->temp_receiver_, loc);
Expression* recv_addr = Expression* recv_addr =
Expression::make_temporary_reference(this->temp_receiver_, loc); Expression::make_temporary_reference(this->temp_receiver_, loc);
recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc); recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc);
Expression* recv = Runtime::make_call(Runtime::CHANRECV1, loc, 3, Expression* recv = Runtime::make_call(Runtime::CHANRECV1, loc, 2,
td, this->channel_, recv_addr); this->channel_, recv_addr);
return Expression::make_compound(recv, recv_ref, loc)->get_backend(context); return Expression::make_compound(recv, recv_ref, loc)->get_backend(context);
} }
......
...@@ -137,39 +137,31 @@ DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(POINTER), R0()) ...@@ -137,39 +137,31 @@ DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(POINTER), R0())
DEF_GO_RUNTIME(MAKECHAN, "runtime.makechan", P2(TYPE, INT64), R1(CHAN)) DEF_GO_RUNTIME(MAKECHAN, "runtime.makechan", P2(TYPE, INT64), R1(CHAN))
// Send a value on a channel. // 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. // 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. // Receive a value from a channel returning whether it is closed.
DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER), DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL))
R1(BOOL))
// Start building a select statement. // Start building a select statement.
DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P3(POINTER, INT64, INT32), R0()) DEF_GO_RUNTIME(NEWSELECT, "runtime.newselect", P3(POINTER, INT64, INT32), R0())
// Add a default clause to a select statement. // Add a default clause to a select statement.
DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", DEF_GO_RUNTIME(SELECTDEFAULT, "runtime.selectdefault", P1(POINTER), R0())
P2(POINTER, INT32), R0())
// Add a send clause to a select statement. // Add a send clause to a select statement.
DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend", DEF_GO_RUNTIME(SELECTSEND, "runtime.selectsend", P3(POINTER, CHAN, POINTER),
P4(POINTER, CHAN, POINTER, INT32), R0()) R0())
// Add a receive clause to a select statement, for a clause which does // Add a receive clause to a select statement.
// not check whether the channel is closed.
DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv", DEF_GO_RUNTIME(SELECTRECV, "runtime.selectrecv",
P4(POINTER, CHAN, POINTER, INT32), R0()) P4(POINTER, CHAN, POINTER, BOOLPTR), 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())
// Run a select, returning the index of the selected clause. // 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. // Panic.
......
...@@ -1517,14 +1517,12 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*, ...@@ -1517,14 +1517,12 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
NULL, loc); NULL, loc);
b->add_statement(closed_temp); b->add_statement(closed_temp);
// closed_temp = chanrecv2(type, channel, &val_temp) // closed_temp = chanrecv2(channel, &val_temp)
Expression* td = Expression::make_type_descriptor(this->channel_->type(),
loc);
Temporary_reference_expression* ref = Temporary_reference_expression* ref =
Expression::make_temporary_reference(val_temp, loc); Expression::make_temporary_reference(val_temp, loc);
Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
Expression* call = Runtime::make_call(Runtime::CHANRECV2, 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 = Expression::make_temporary_reference(closed_temp, loc);
ref->set_is_lvalue(); ref->set_is_lvalue();
Statement* s = Statement::make_assignment(ref, call, loc); Statement* s = Statement::make_assignment(ref, call, loc);
...@@ -4516,9 +4514,6 @@ Send_statement::do_get_backend(Translate_context* context) ...@@ -4516,9 +4514,6 @@ Send_statement::do_get_backend(Translate_context* context)
&& val->temporary_reference_expression() == NULL) && val->temporary_reference_expression() == NULL)
can_take_address = false; can_take_address = false;
Expression* td = Expression::make_type_descriptor(this->channel_->type(),
loc);
Bstatement* btemp = NULL; Bstatement* btemp = NULL;
if (can_take_address) if (can_take_address)
{ {
...@@ -4539,7 +4534,7 @@ Send_statement::do_get_backend(Translate_context* context) ...@@ -4539,7 +4534,7 @@ Send_statement::do_get_backend(Translate_context* context)
btemp = temp->get_backend(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); this->channel_, val);
context->gogo()->lower_expression(context->function(), NULL, &call); context->gogo()->lower_expression(context->function(), NULL, &call);
...@@ -4621,13 +4616,10 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, ...@@ -4621,13 +4616,10 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
Expression* selref = Expression::make_temporary_reference(sel, loc); Expression* selref = Expression::make_temporary_reference(sel, loc);
selref = Expression::make_unary(OPERATOR_AND, selref, loc); selref = Expression::make_unary(OPERATOR_AND, selref, loc);
Expression* index_expr = Expression::make_integer_ul(this->index_, NULL,
loc);
if (this->is_default_) if (this->is_default_)
{ {
go_assert(this->channel_ == NULL && this->val_ == NULL); go_assert(this->channel_ == NULL && this->val_ == NULL);
this->lower_default(b, selref, index_expr); this->lower_default(b, selref);
this->is_lowered_ = true; this->is_lowered_ = true;
return; return;
} }
...@@ -4641,9 +4633,9 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, ...@@ -4641,9 +4633,9 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
loc); loc);
if (this->is_send_) if (this->is_send_)
this->lower_send(b, selref, chanref, index_expr); this->lower_send(b, selref, chanref);
else 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 // Now all references should be handled through the statements, not
// through here. // through here.
...@@ -4654,12 +4646,11 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, ...@@ -4654,12 +4646,11 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function,
// Lower a default clause in a select statement. // Lower a default clause in a select statement.
void void
Select_clauses::Select_clause::lower_default(Block* b, Expression* selref, Select_clauses::Select_clause::lower_default(Block* b, Expression* selref)
Expression* index_expr)
{ {
Location loc = this->location_; Location loc = this->location_;
Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 2, selref, Expression* call = Runtime::make_call(Runtime::SELECTDEFAULT, loc, 1,
index_expr); selref);
b->add_statement(Statement::make_statement(call, true)); b->add_statement(Statement::make_statement(call, true));
} }
...@@ -4667,8 +4658,7 @@ Select_clauses::Select_clause::lower_default(Block* b, Expression* selref, ...@@ -4667,8 +4658,7 @@ Select_clauses::Select_clause::lower_default(Block* b, Expression* selref,
void void
Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
Expression* chanref, Expression* chanref)
Expression* index_expr)
{ {
Location loc = this->location_; Location loc = this->location_;
...@@ -4687,8 +4677,8 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, ...@@ -4687,8 +4677,8 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
Expression* valref = Expression::make_temporary_reference(val, loc); Expression* valref = Expression::make_temporary_reference(val, loc);
Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc); Expression* valaddr = Expression::make_unary(OPERATOR_AND, valref, loc);
Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 4, selref, Expression* call = Runtime::make_call(Runtime::SELECTSEND, loc, 3, selref,
chanref, valaddr, index_expr); chanref, valaddr);
b->add_statement(Statement::make_statement(call, true)); b->add_statement(Statement::make_statement(call, true));
} }
...@@ -4697,8 +4687,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* selref, ...@@ -4697,8 +4687,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* selref,
void void
Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
Block* b, Expression* selref, Block* b, Expression* selref,
Expression* chanref, Expression* chanref)
Expression* index_expr)
{ {
Location loc = this->location_; Location loc = this->location_;
...@@ -4715,10 +4704,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, ...@@ -4715,10 +4704,9 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
Temporary_statement* closed_temp = NULL; Temporary_statement* closed_temp = NULL;
Expression* call; Expression* caddr;
if (this->closed_ == NULL && this->closedvar_ == NULL) if (this->closed_ == NULL && this->closedvar_ == NULL)
call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref, chanref, caddr = Expression::make_nil(loc);
valaddr, index_expr);
else else
{ {
closed_temp = Statement::make_temporary(Type::lookup_bool_type(), NULL, 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, ...@@ -4726,11 +4714,12 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function,
b->add_statement(closed_temp); b->add_statement(closed_temp);
Expression* cref = Expression::make_temporary_reference(closed_temp, Expression* cref = Expression::make_temporary_reference(closed_temp,
loc); loc);
Expression* caddr = Expression::make_unary(OPERATOR_AND, cref, loc); caddr = Expression::make_unary(OPERATOR_AND, cref, loc);
call = Runtime::make_call(Runtime::SELECTRECV2, loc, 5, selref, chanref,
valaddr, caddr, index_expr);
} }
Expression* call = Runtime::make_call(Runtime::SELECTRECV, loc, 4, selref,
chanref, valaddr, caddr);
b->add_statement(Statement::make_statement(call, true)); b->add_statement(Statement::make_statement(call, true));
// If the block of statements is executed, arrange for the received // If the block of statements is executed, arrange for the received
...@@ -4958,15 +4947,14 @@ Select_clauses::get_backend(Translate_context* context, ...@@ -4958,15 +4947,14 @@ Select_clauses::get_backend(Translate_context* context,
std::vector<std::vector<Bexpression*> > cases(count); std::vector<std::vector<Bexpression*> > cases(count);
std::vector<Bstatement*> clauses(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; int i = 0;
for (Clauses::iterator p = this->clauses_.begin(); for (Clauses::iterator p = this->clauses_.begin();
p != this->clauses_.end(); p != this->clauses_.end();
++p, ++i) ++p, ++i)
{ {
int index = p->index(); Expression* index_expr = Expression::make_integer_ul(i, int_type,
Expression* index_expr = Expression::make_integer_ul(index, int32_type,
location); location);
cases[i].push_back(index_expr->get_backend(context)); cases[i].push_back(index_expr->get_backend(context));
......
...@@ -899,10 +899,9 @@ class Select_clauses ...@@ -899,10 +899,9 @@ class Select_clauses
Named_object* var, Named_object* closedvar, bool is_default, Named_object* var, Named_object* closedvar, bool is_default,
Block* statements, Location location) Block* statements, Location location)
{ {
int index = static_cast<int>(this->clauses_.size()); this->clauses_.push_back(Select_clause(is_send, channel, val, closed, var,
this->clauses_.push_back(Select_clause(index, is_send, channel, val, closedvar, is_default, statements,
closed, var, closedvar, is_default, location));
statements, location));
} }
size_t size_t
...@@ -950,21 +949,15 @@ class Select_clauses ...@@ -950,21 +949,15 @@ class Select_clauses
is_default_(false) is_default_(false)
{ } { }
Select_clause(int index, bool is_send, Expression* channel, Select_clause(bool is_send, Expression* channel, Expression* val,
Expression* val, Expression* closed, Named_object* var, Expression* closed, Named_object* var,
Named_object* closedvar, bool is_default, Block* statements, Named_object* closedvar, bool is_default, Block* statements,
Location location) Location location)
: index_(index), channel_(channel), val_(val), closed_(closed), : channel_(channel), val_(val), closed_(closed), var_(var),
var_(var), closedvar_(closedvar), statements_(statements), closedvar_(closedvar), statements_(statements), location_(location),
location_(location), is_send_(is_send), is_default_(is_default), is_send_(is_send), is_default_(is_default), is_lowered_(false)
is_lowered_(false)
{ go_assert(is_default ? channel == NULL : channel != NULL); } { go_assert(is_default ? channel == NULL : channel != NULL); }
// Return the index of this clause.
int
index() const
{ return this->index_; }
// Traverse the select clause. // Traverse the select clause.
int int
traverse(Traverse*); traverse(Traverse*);
...@@ -1025,17 +1018,14 @@ class Select_clauses ...@@ -1025,17 +1018,14 @@ class Select_clauses
private: private:
void void
lower_default(Block*, Expression*, Expression*); lower_default(Block*, Expression*);
void void
lower_send(Block*, Expression*, Expression*, Expression*); lower_send(Block*, Expression*, Expression*);
void void
lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*, lower_recv(Gogo*, Named_object*, Block*, Expression*, Expression*);
Expression*);
// The index of this case in the generated switch statement.
int index_;
// The channel. // The channel.
Expression* channel_; Expression* channel_;
// The value to send or the lvalue to receive into. // The value to send or the lvalue to receive into.
......
...@@ -1160,7 +1160,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) { ...@@ -1160,7 +1160,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
} else { } else {
p = unsafe.Pointer(&val.ptr) p = unsafe.Pointer(&val.ptr)
} }
selected, ok := chanrecv(v.typ, v.pointer(), nb, p) selected, ok := chanrecv(v.pointer(), nb, p)
if !selected { if !selected {
val = Value{} val = Value{}
} }
...@@ -1191,7 +1191,7 @@ func (v Value) send(x Value, nb bool) (selected bool) { ...@@ -1191,7 +1191,7 @@ func (v Value) send(x Value, nb bool) (selected bool) {
} else { } else {
p = unsafe.Pointer(&x.ptr) 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. // Set assigns x to the value v.
...@@ -2327,10 +2327,10 @@ func chanlen(ch unsafe.Pointer) int ...@@ -2327,10 +2327,10 @@ func chanlen(ch unsafe.Pointer) int
// (due to the escapes() call in ValueOf). // (due to the escapes() call in ValueOf).
//go:noescape //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 //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 makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
func makemap(t *rtype) (m unsafe.Pointer) func makemap(t *rtype) (m unsafe.Pointer)
......
...@@ -118,8 +118,8 @@ func chanbuf(c *hchan, i uint) unsafe.Pointer { ...@@ -118,8 +118,8 @@ func chanbuf(c *hchan, i uint) unsafe.Pointer {
// entry point for c <- x from compiled code // entry point for c <- x from compiled code
//go:nosplit //go:nosplit
func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) { func chansend1(c *hchan, elem unsafe.Pointer) {
chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t))) chansend(c, elem, true, getcallerpc(unsafe.Pointer(&c)))
} }
/* /*
...@@ -134,14 +134,7 @@ func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) { ...@@ -134,14 +134,7 @@ func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) {
* been closed. it is easiest to loop and re-run * been closed. it is easiest to loop and re-run
* the operation; we'll see that it's now closed. * the operation; we'll see that it's now closed.
*/ */
func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { func chansend(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)
}
if c == nil { if c == nil {
if !block { if !block {
return false return false
...@@ -400,13 +393,13 @@ func closechan(c *hchan) { ...@@ -400,13 +393,13 @@ func closechan(c *hchan) {
// entry points for <- c from compiled code // entry points for <- c from compiled code
//go:nosplit //go:nosplit
func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) { func chanrecv1(c *hchan, elem unsafe.Pointer) {
chanrecv(t, c, elem, true) chanrecv(c, elem, true)
} }
//go:nosplit //go:nosplit
func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) { func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) {
_, received = chanrecv(t, c, elem, true) _, received = chanrecv(c, elem, true)
return return
} }
...@@ -416,7 +409,7 @@ func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) { ...@@ -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, if c is closed, zeros *ep and returns (true, false).
// Otherwise, fills in *ep with an element and returns (true, true). // 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. // 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 // raceenabled: don't need to check ep, as it is always on the stack
// or is new memory allocated by reflect. // or is new memory allocated by reflect.
...@@ -609,8 +602,8 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) { ...@@ -609,8 +602,8 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
// ... bar // ... bar
// } // }
// //
func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) { func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) {
return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t))) return chansend(c, elem, false, getcallerpc(unsafe.Pointer(&c)))
} }
// compiler implements // compiler implements
...@@ -630,8 +623,8 @@ func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) { ...@@ -630,8 +623,8 @@ func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) {
// ... bar // ... bar
// } // }
// //
func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) { func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected bool) {
selected, _ = chanrecv(t, c, elem, false) selected, _ = chanrecv(c, elem, false)
return return
} }
...@@ -652,20 +645,20 @@ func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) { ...@@ -652,20 +645,20 @@ func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) {
// ... bar // ... 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. // 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 return
} }
//go:linkname reflect_chansend reflect.chansend //go:linkname reflect_chansend reflect.chansend
func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) { func reflect_chansend(c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t))) return chansend(c, elem, !nb, getcallerpc(unsafe.Pointer(&c)))
} }
//go:linkname reflect_chanrecv reflect.chanrecv //go:linkname reflect_chanrecv reflect.chanrecv
func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) { func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
return chanrecv(t, c, elem, !nb) return chanrecv(c, elem, !nb)
} }
//go:linkname reflect_chanlen reflect.chanlen //go:linkname reflect_chanlen reflect.chanlen
......
...@@ -18,14 +18,14 @@ import ( ...@@ -18,14 +18,14 @@ import (
//go:linkname selectdefault runtime.selectdefault //go:linkname selectdefault runtime.selectdefault
//go:linkname selectsend runtime.selectsend //go:linkname selectsend runtime.selectsend
//go:linkname selectrecv runtime.selectrecv //go:linkname selectrecv runtime.selectrecv
//go:linkname selectrecv2 runtime.selectrecv2
//go:linkname selectgo runtime.selectgo //go:linkname selectgo runtime.selectgo
const ( const debugSelect = false
debugSelect = false
const (
// scase.kind // scase.kind
caseRecv = iota caseNil = iota
caseRecv
caseSend caseSend
caseDefault caseDefault
) )
...@@ -47,10 +47,9 @@ type hselect struct { ...@@ -47,10 +47,9 @@ type hselect struct {
type scase struct { type scase struct {
elem unsafe.Pointer // data element elem unsafe.Pointer // data element
c *hchan // chan c *hchan // chan
pc uintptr // return pc pc uintptr // return pc (for race detector / msan)
kind uint16 kind uint16
index uint16 // case index receivedp *bool // pointer to received bool, if any
receivedp *bool // pointer to received bool (recv2)
releasetime int64 releasetime int64
} }
...@@ -88,88 +87,64 @@ func newselect(sel *hselect, selsize int64, size int32) { ...@@ -88,88 +87,64 @@ func newselect(sel *hselect, selsize int64, size int32) {
} }
} }
func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer, index int32) { func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) {
// nil cases do not compete pc := getcallerpc(unsafe.Pointer(&sel))
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) {
i := sel.ncase i := sel.ncase
if i >= sel.tcase { if i >= sel.tcase {
throw("selectsend: too many cases") throw("selectsend: too many cases")
} }
sel.ncase = i + 1 sel.ncase = i + 1
if c == nil {
return
}
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc cas.pc = pc
cas.c = c cas.c = c
cas.index = uint16(index)
cas.kind = caseSend cas.kind = caseSend
cas.elem = elem cas.elem = elem
if debugSelect { if debugSelect {
print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " index=", cas.index, "\n") print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, "\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)
} }
return
} }
func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool, index int32) { func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) {
// nil cases do not compete pc := getcallerpc(unsafe.Pointer(&sel))
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) {
i := sel.ncase i := sel.ncase
if i >= sel.tcase { if i >= sel.tcase {
throw("selectrecv: too many cases") throw("selectrecv: too many cases")
} }
sel.ncase = i + 1 sel.ncase = i + 1
if c == nil {
return
}
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = pc cas.pc = pc
cas.c = c cas.c = c
cas.index = uint16(index)
cas.kind = caseRecv cas.kind = caseRecv
cas.elem = elem cas.elem = elem
cas.receivedp = received cas.receivedp = received
if debugSelect { 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) { func selectdefault(sel *hselect) {
selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), index) pc := getcallerpc(unsafe.Pointer(&sel))
return
}
func selectdefaultImpl(sel *hselect, callerpc uintptr, index int32) {
i := sel.ncase i := sel.ncase
if i >= sel.tcase { if i >= sel.tcase {
throw("selectdefault: too many cases") throw("selectdefault: too many cases")
} }
sel.ncase = i + 1 sel.ncase = i + 1
cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
cas.pc = callerpc cas.pc = pc
cas.c = nil cas.c = nil
cas.index = uint16(index)
cas.kind = caseDefault cas.kind = caseDefault
if debugSelect { 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) { ...@@ -193,14 +168,11 @@ func selunlock(scases []scase, lockorder []uint16) {
// the G that calls select runnable again and schedules it for execution. // 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. // 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. // Now if the first M touches sel, it will access freed memory.
n := len(scases) for i := len(scases) - 1; i >= 0; i-- {
r := 0
// skip the default case
if n > 0 && scases[lockorder[0]].c == nil {
r = 1
}
for i := n - 1; i >= r; i-- {
c := scases[lockorder[i]].c c := scases[lockorder[i]].c
if c == nil {
break
}
if i > 0 && c == scases[lockorder[i-1]].c { if i > 0 && c == scases[lockorder[i-1]].c {
continue // will unlock it on the next iteration continue // will unlock it on the next iteration
} }
...@@ -241,20 +213,15 @@ func block() { ...@@ -241,20 +213,15 @@ func block() {
// *sel is on the current goroutine's stack (regardless of any // *sel is on the current goroutine's stack (regardless of any
// escaping in selectgo). // escaping in selectgo).
// //
// selectgo does not return. Instead, it overwrites its return PC and // selectgo returns the index of the chosen scase, which matches the
// returns directly to the triggered select case. Because of this, it // ordinal position of its respective select{recv,send,default} call.
// cannot appear at the top of a split stack. func selectgo(sel *hselect) int {
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) {
if debugSelect { if debugSelect {
print("select: sel=", sel, "\n") 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)} scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
scases := *(*[]scase)(unsafe.Pointer(&scaseslice)) scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
...@@ -347,13 +314,19 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) { ...@@ -347,13 +314,19 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
loop: loop:
// pass 1 - look for something already waiting // pass 1 - look for something already waiting
var dfli int
var dfl *scase var dfl *scase
var casi int
var cas *scase var cas *scase
for i := 0; i < int(sel.ncase); i++ { for i := 0; i < int(sel.ncase); i++ {
cas = &scases[pollorder[i]] casi = int(pollorder[i])
cas = &scases[casi]
c = cas.c c = cas.c
switch cas.kind { switch cas.kind {
case caseNil:
continue
case caseRecv: case caseRecv:
sg = c.sendq.dequeue() sg = c.sendq.dequeue()
if sg != nil { if sg != nil {
...@@ -382,12 +355,14 @@ loop: ...@@ -382,12 +355,14 @@ loop:
} }
case caseDefault: case caseDefault:
dfli = casi
dfl = cas dfl = cas
} }
} }
if dfl != nil { if dfl != nil {
selunlock(scases, lockorder) selunlock(scases, lockorder)
casi = dfli
cas = dfl cas = dfl
goto retc goto retc
} }
...@@ -400,7 +375,11 @@ loop: ...@@ -400,7 +375,11 @@ loop:
} }
nextp = &gp.waiting nextp = &gp.waiting
for _, casei := range lockorder { for _, casei := range lockorder {
cas = &scases[casei] casi = int(casei)
cas = &scases[casi]
if cas.kind == caseNil {
continue
}
c = cas.c c = cas.c
sg := acquireSudog() sg := acquireSudog()
sg.g = gp sg.g = gp
...@@ -494,6 +473,7 @@ loop: ...@@ -494,6 +473,7 @@ loop:
// otherwise they stack up on quiet channels // otherwise they stack up on quiet channels
// record the successful case, if any. // record the successful case, if any.
// We singly-linked up the SudoGs in lock order. // We singly-linked up the SudoGs in lock order.
casi = -1
cas = nil cas = nil
sglist = gp.waiting sglist = gp.waiting
// Clear all elem before unlinking from gp.waiting. // Clear all elem before unlinking from gp.waiting.
...@@ -506,11 +486,15 @@ loop: ...@@ -506,11 +486,15 @@ loop:
for _, casei := range lockorder { for _, casei := range lockorder {
k = &scases[casei] k = &scases[casei]
if k.kind == caseNil {
continue
}
if sglist.releasetime > 0 { if sglist.releasetime > 0 {
k.releasetime = sglist.releasetime k.releasetime = sglist.releasetime
} }
if sg == sglist { if sg == sglist {
// sg has already been dequeued by the G that woke us up. // sg has already been dequeued by the G that woke us up.
casi = int(casei)
cas = k cas = k
} else { } else {
c = k.c c = k.c
...@@ -659,7 +643,7 @@ retc: ...@@ -659,7 +643,7 @@ retc:
if cas.releasetime > 0 { if cas.releasetime > 0 {
blockevent(cas.releasetime-t0, 2) blockevent(cas.releasetime-t0, 2)
} }
return cas.pc, cas.index return casi
sclose: sclose:
// send on closed channel // send on closed channel
...@@ -703,22 +687,15 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { ...@@ -703,22 +687,15 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
rc := &cases[i] rc := &cases[i]
switch rc.dir { switch rc.dir {
case selectDefault: case selectDefault:
selectdefaultImpl(sel, uintptr(i), 0) selectdefault(sel)
case selectSend: case selectSend:
if rc.ch == nil { selectsend(sel, rc.ch, rc.val)
break
}
selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0)
case selectRecv: case selectRecv:
if rc.ch == nil { selectrecv(sel, rc.ch, rc.val, r)
break
}
selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0)
} }
} }
pc, _ := selectgoImpl(sel) chosen = selectgo(sel)
chosen = int(pc)
recvOK = *r recvOK = *r
return return
} }
......
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