From fa09322c0e0616a1ce5d56d0aabbbf6fb632f2a0 Mon Sep 17 00:00:00 2001 From: Nevkontakte Date: Sun, 20 Feb 2022 21:21:53 +0000 Subject: [PATCH] Prevent non-blocking select from making function appear blocking. In almost every place compiler checks whether a function is blocking by checking `len(c.Blocking) > 0`, so assigning false to the map confuses the check, causing unnecessary checkpointing prologue and epilogue to be added to the function. Fixes https://github.com/gopherjs/gopherjs/issues/1106. --- compiler/statements.go | 4 +++- tests/goroutine_test.go | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/compiler/statements.go b/compiler/statements.go index 25e5e51be..d845792ee 100644 --- a/compiler/statements.go +++ b/compiler/statements.go @@ -520,7 +520,9 @@ func (fc *funcContext) translateStmt(stmt ast.Stmt, label *types.Label) { Fun: fc.newIdent("$select", types.NewSignature(nil, types.NewTuple(types.NewVar(0, nil, "", types.NewInterface(nil, nil))), types.NewTuple(types.NewVar(0, nil, "", types.Typ[types.Int])), false)), Args: []ast.Expr{fc.newIdent(fmt.Sprintf("[%s]", strings.Join(channels, ", ")), types.NewInterface(nil, nil))}, }, types.Typ[types.Int]) - fc.Blocking[selectCall] = !hasDefault + if !hasDefault { + fc.Blocking[selectCall] = true + } fc.Printf("%s = %s;", selectionVar, fc.translateExpr(selectCall)) if len(caseClauses) != 0 { diff --git a/tests/goroutine_test.go b/tests/goroutine_test.go index a4b5606c0..011e3e8af 100644 --- a/tests/goroutine_test.go +++ b/tests/goroutine_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "runtime" + "sync/atomic" "testing" "time" @@ -289,3 +290,25 @@ func TestGoroutineJsObject(t *testing.T) { runtime.Gosched() } } + +func issue1106() { + select { + default: + } +} + +func TestIssue1106(t *testing.T) { + // https://github.com/gopherjs/gopherjs/issues/1106#issuecomment-1046323374 + var done int32 = 0 + go func() { + f := issue1106 + f() + atomic.AddInt32(&done, 1) + }() + + // Will get stuck here if #1106 is not fixed. + for !atomic.CompareAndSwapInt32(&done, 1, 1) { + // Maintain one active goroutine to prevent Node from exiting. + runtime.Gosched() + } +}