Skip to content

[go1.20] Some more native overrides for go1.20 #1306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions compiler/natives/src/encoding/gob/gob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:build js
// +build js

package gob

import (
"reflect"
"sync"
)

type typeInfo struct {
id typeId
encInit sync.Mutex

// temporarily replacement of atomic.Pointer[encEngine] for go1.20 without generics.
encoder atomicEncEnginePointer
wire *wireType
}

type atomicEncEnginePointer struct {
v *encEngine
}

func (x *atomicEncEnginePointer) Load() *encEngine { return x.v }
func (x *atomicEncEnginePointer) Store(val *encEngine) { x.v = val }

// temporarily replacement of growSlice[E any] for go1.20 without generics.
func growSlice(v reflect.Value, ps any, length int) {
vps := reflect.ValueOf(ps)
vs := vps.Elem()
zero := reflect.Zero(vs.Elem().Type())
vs.Set(reflect.Append(vs, zero))
cp := vs.Cap()
if cp > length {
cp = length
}
vs.Set(vs.Slice(0, cp))
v.Set(vs)
vps.Set(vs.Addr())
}
8 changes: 8 additions & 0 deletions compiler/natives/src/go/token/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ type atomicFilePointer struct {

func (x *atomicFilePointer) Load() *File { return x.v }
func (x *atomicFilePointer) Store(val *File) { x.v = val }

func (x *atomicFilePointer) CompareAndSwap(old, new *File) bool {
if x.v == old {
x.v = new
return true
}
return false
}
12 changes: 12 additions & 0 deletions compiler/natives/src/internal/coverage/slicereader/slicereader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//go:build js
// +build js

package slicereader

func toString(b []byte) string {
if len(b) == 0 {
return ``
}
// Overwritten to avoid `unsafe.String`
return string(b)
}
95 changes: 95 additions & 0 deletions compiler/natives/src/internal/godebug/godebug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//go:build js
// +build js

package godebug

import (
"sync"
)

type Setting struct {
name string
once sync.Once

// temporarily replacement of atomic.Pointer[string] for go1.20 without generics.
value *atomicStringPointer
}

type atomicStringPointer struct {
v *string
}

func (x *atomicStringPointer) Load() *string { return x.v }
func (x *atomicStringPointer) Store(val *string) { x.v = val }

func (s *Setting) Value() string {
s.once.Do(func() {
v, ok := cache.Load(s.name)
if !ok {
// temporarily replacement of atomic.Pointer[string] for go1.20 without generics.
p := new(atomicStringPointer)
p.Store(&empty)
v, _ = cache.LoadOrStore(s.name, p)
}
// temporarily replacement of atomic.Pointer[string] for go1.20 without generics.
s.value = v.(*atomicStringPointer)
})
return *s.value.Load()
}

// setUpdate is provided by package runtime.
// It calls update(def, env), where def is the default GODEBUG setting
// and env is the current value of the $GODEBUG environment variable.
// After that first call, the runtime calls update(def, env)
// again each time the environment variable changes
// (due to use of os.Setenv, for example).
//
// GOPHERJS: Currently we don't inject a proxy into process.env to watch
// for changes via syscall.runtimeSetenv and syscall.runtimeUnsetenv.
// We may want to look into this in the future.
func setUpdate(update func(string, string)) {}

func update(def, env string) {
updateMu.Lock()
defer updateMu.Unlock()

did := make(map[string]bool)
parse(did, env)
parse(did, def)

cache.Range(func(name, v any) bool {
if !did[name.(string)] {
// temporarily replacement of atomic.Pointer[string] for go1.20 without generics.
v.(*atomicStringPointer).Store(&empty)
}
return true
})
}

func parse(did map[string]bool, s string) {
end := len(s)
eq := -1
for i := end - 1; i >= -1; i-- {
if i == -1 || s[i] == ',' {
if eq >= 0 {
name, value := s[i+1:eq], s[eq+1:end]
if !did[name] {
did[name] = true
v, ok := cache.Load(name)
if !ok {
// temporarily replacement of atomic.Pointer[string] for go1.20 without generics.
p := new(atomicStringPointer)
p.Store(&empty)
v, _ = cache.LoadOrStore(name, p)
}
// temporarily replacement of atomic.Pointer[string] for go1.20 without generics.
v.(*atomicStringPointer).Store(&value)
}
}
eq = -1
end = i
} else if s[i] == '=' {
eq = i
}
}
}
9 changes: 9 additions & 0 deletions compiler/natives/src/math/rand/rand.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build js
// +build js

package rand

import _ "unsafe"

//go:linkname fastrand64 runtime.fastrand64
func fastrand64() uint64
4 changes: 2 additions & 2 deletions compiler/natives/src/net/http/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import (
"testing"
)

func testClientTimeout(t *testing.T, h2 bool) {
func testClientTimeout(t *testing.T, mode testMode) {
// The original test expects Client.Timeout error to be returned, but under
// GopherJS an "i/o timeout" error is frequently returned. Otherwise the test
// seems to be working correctly.
t.Skip("Flaky test under GopherJS.")
}

func testClientTimeout_Headers(t *testing.T, h2 bool) {
func testClientTimeout_Headers(t *testing.T, mode testMode) {
// The original test expects Client.Timeout error to be returned, but under
// GopherJS an "i/o timeout" error is frequently returned. Otherwise the test
// seems to be working correctly.
Expand Down
4 changes: 2 additions & 2 deletions compiler/natives/src/net/http/clientserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"testing"
)

func testTransportGCRequest(t *testing.T, h2, body bool) {
func testTransportGCRequest(t *testing.T, mode testMode, body bool) {
t.Skip("The test relies on runtime.SetFinalizer(), which is not supported by GopherJS.")
}

func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) {
func testWriteHeaderAfterWrite(t *testing.T, mode testMode, hijack bool) {
t.Skip("GopherJS source maps don't preserve original function names in stack traces, which this test relied on.")
}
32 changes: 32 additions & 0 deletions compiler/natives/src/net/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ package http
import (
"bufio"
"bytes"
"context"
"crypto/tls"
"errors"
"io"
"net"
"net/textproto"
"strconv"
"sync"
"sync/atomic"

"github.com/gopherjs/gopherjs/js"
)
Expand Down Expand Up @@ -113,3 +118,30 @@ func (t *XHRTransport) CancelRequest(req *Request) {
xhr.Call("abort")
}
}

type conn struct {
server *Server
cancelCtx context.CancelFunc
rwc net.Conn
remoteAddr string
tlsState *tls.ConnectionState
werr error
r *connReader
bufr *bufio.Reader
bufw *bufio.Writer
lastMethod string

// temporarily replacement of `atomic.Pointer[response]` for go1.20 without generics.
curReq atomicResponsePointer

curState atomic.Uint64
mu sync.Mutex
hijackedv bool
}

type atomicResponsePointer struct {
v *response
}

func (x *atomicResponsePointer) Load() *response { return x.v }
func (x *atomicResponsePointer) Store(val *response) { x.v = val }
6 changes: 5 additions & 1 deletion compiler/natives/src/strings/strings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ func TestCompareStrings(t *testing.T) {
}

func TestClone(t *testing.T) {
t.Skip("conversion to reflect.StringHeader is not supported in GopherJS")
t.Skip("conversion to unsafe.StringData is not supported in GopherJS")
}

func TestMap(t *testing.T) {
t.Skip("identity test uses unsafe.StringData is not supported in GopherJS")
}
16 changes: 15 additions & 1 deletion compiler/natives/src/sync/atomic/atomic.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,5 +221,19 @@ func sameType(x, y interface{}) bool {
return js.InternalObject(x).Get("constructor") == js.InternalObject(y).Get("constructor")
}

//gopherjs:purge for go1.19 without generics
// Override pointer so that the type check in the source code is satisfied
// but remove the fields and methods for go1.20 without generics.
// See https://cs.opensource.google/go/go/+/refs/tags/go1.20.14:src/sync/atomic/type.go;l=40
type Pointer[T any] struct{}

//gopherjs:purge for go1.20 without generics
func (x *Pointer[T]) Load() *T

//gopherjs:purge for go1.20 without generics
func (x *Pointer[T]) Store(val *T)

//gopherjs:purge for go1.20 without generics
func (x *Pointer[T]) Swap(new *T) (old *T)

//gopherjs:purge for go1.20 without generics
func (x *Pointer[T]) CompareAndSwap(old, new *T) (swapped bool)
8 changes: 8 additions & 0 deletions compiler/natives/src/syscall/syscall_js_wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ func runtime_envs() []string {
return envs
}

func runtimeSetenv(k, v string) {
setenv_c(k, v)
}

func runtimeUnsetenv(k string) {
unsetenv_c(k)
}

func setenv_c(k, v string) {
process := js.Global().Get("process")
if process.IsUndefined() {
Expand Down
7 changes: 7 additions & 0 deletions compiler/natives/src/time/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build js
// +build js

package time

// replaced for go1.20 temporarily without generics.
var ParseRFC3339 = parseRFC3339
Loading