From patchwork Thu Sep 14 03:57:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 813704 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-462103-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="I4SlLgyk"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xt4Vt2FMXz9sBZ for ; Thu, 14 Sep 2017 13:57:41 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=vIE8sSuugNOIM5epSJlf9D5qWztif7BQ9f3U1+aJ2ZFrpp 8nkttXHResItqI+m6OBlHFoSLkZLMsCUS6beyMmGfx+pHr6JdkZR0sJGWLoPWoUs ILN1dDtvi+3tGlZu3gTgzXwTUx8DbLdd0E/5BKR0Gd6js+ma5Tq/QozFK1kXI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=svJojSMd4qtJBQfrD0ZrolemFpY=; b=I4SlLgykoTGuRwtScHl9 ZJMGY2rOYql3HwwGjS/rL/Z64ODVjpUAkwOMyUwfZd7v1tHwEK6PhPn4SmQ4AOjZ DrtTyt/aIRMAhf5qrx+hKqqiFb20xjopKmJkc9p2Zco9C/DHhvk0uPXdmP7G0i5l nR+UqQZssybW5SQHOMAcuOc= Received: (qmail 7020 invoked by alias); 14 Sep 2017 03:57:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 3917 invoked by uid 89); 14 Sep 2017 03:57:27 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-15.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=8888, kc, Statement, compete X-HELO: mail-pg0-f53.google.com Received: from mail-pg0-f53.google.com (HELO mail-pg0-f53.google.com) (74.125.83.53) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 14 Sep 2017 03:57:22 +0000 Received: by mail-pg0-f53.google.com with SMTP id i130so4199175pgc.3 for ; Wed, 13 Sep 2017 20:57:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=OA5Hrs1OALvHLLUclamtzABvKLx3cTAkuhW/i8zIOmg=; b=ec1YFl5YggR5V3xJIp2JmczWG5HzOtxlYwnwgJMWWvq2Vbw09yI/taT0vz6dm75Oky o/0j7dJ5A1ppATPNgMGPCxA6/2aHWFuS3HuyTQf2/nAxmAeM7dtk4lelFB38kWy5cITz Fg5skeldgXxy0r7ZfNPFRIEVYLp/dCSelS+WWn0fQ5EUB7EL/hgjQGw8drrLs368sNaj pmxxkkj8TSnWYqY7pAqAI5m3iQhBnZv4Vto90e8m2nILJhMUB87IzPAhWSQBcNa1Nm4o 4vWrKe4sc8VP3srLHx/IbulsOeWJB6DVOm4hQw5p0DZs6aBON9PN/z//Pzk8tOC6JIRz aQ6A== X-Gm-Message-State: AHPjjUh3APZGAdxH08n0/df8dEjygHNR54lfuCWtLi8brMGjwgL3ErJa YrrTdKWu2ngCoTOZKxQLZ1V3mQXKQ0m3ex7T1aMB5Mtr X-Google-Smtp-Source: ADKCNb7I1ZRKupFQbiuAEUH91DbHFOypiwXsFFunBFK6DeYnjHkaf5NzytnqDzkJnFc0LyuNypolX0Gab1kIN/2fkug= X-Received: by 10.101.71.135 with SMTP id e7mr20279949pgs.112.1505361440926; Wed, 13 Sep 2017 20:57:20 -0700 (PDT) MIME-Version: 1.0 Received: by 10.100.182.173 with HTTP; Wed, 13 Sep 2017 20:57:20 -0700 (PDT) From: Ian Lance Taylor Date: Wed, 13 Sep 2017 20:57:20 -0700 Message-ID: Subject: Go patch committed: simplify select and channel operations To: gcc-patches , "gofrontend-dev@googlegroups.com" In preparation for upgrading libgo to the 1.9 release, this patch to the Go frontend approximately incorporates https://golang.org/cl/37661 and https://golang.org/cl/38351 from the gc toolchain. 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. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 252748) +++ gcc/go/gofrontend/MERGE (working copy) @@ -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. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 252748) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -14463,15 +14463,14 @@ Receive_expression::do_get_backend(Trans 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); } Index: gcc/go/gofrontend/runtime.def =================================================================== --- gcc/go/gofrontend/runtime.def (revision 251948) +++ gcc/go/gofrontend/runtime.def (working copy) @@ -137,39 +137,31 @@ DEF_GO_RUNTIME(MAPITERNEXT, "runtime.map 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. Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 251948) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -1517,14 +1517,12 @@ Tuple_receive_assignment_statement::do_l 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 && 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 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(Gog 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(Gog 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(Gog // 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_def 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_sen 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_sen 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_rec 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_rec 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_co std::vector > cases(count); std::vector 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)); Index: gcc/go/gofrontend/statements.h =================================================================== --- gcc/go/gofrontend/statements.h (revision 251948) +++ gcc/go/gofrontend/statements.h (working copy) @@ -899,10 +899,9 @@ class Select_clauses Named_object* var, Named_object* closedvar, bool is_default, Block* statements, Location location) { - int index = static_cast(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. Index: libgo/go/reflect/value.go =================================================================== --- libgo/go/reflect/value.go (revision 252746) +++ libgo/go/reflect/value.go (working copy) @@ -1160,7 +1160,7 @@ func (v Value) recv(nb bool) (val Value, } 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) (s } 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) Index: libgo/go/runtime/chan.go =================================================================== --- libgo/go/runtime/chan.go (revision 251948) +++ libgo/go/runtime/chan.go (working copy) @@ -118,8 +118,8 @@ func chanbuf(c *hchan, i uint) unsafe.Po // 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, el * 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, el // 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 // ... 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, // ... 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 unsa // ... 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 Index: libgo/go/runtime/select.go =================================================================== --- libgo/go/runtime/select.go (revision 251948) +++ libgo/go/runtime/select.go (working copy) @@ -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 int } } -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") + 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) { - // 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 // 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 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 []runtimeSele 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 }