diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-09-06 18:12:46 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-09-06 18:12:46 +0000 |
commit | aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13 (patch) | |
tree | 7e63b06d1eec92beec6997c9d3ab47a5d6a835be /libgo/go/syscall/js | |
parent | 920ea3b8ba3164b61ac9490dfdfceb6936eda6dd (diff) | |
download | gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.zip gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.gz gcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.bz2 |
libgo: update to Go 1.13beta1 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/193497
From-SVN: r275473
Diffstat (limited to 'libgo/go/syscall/js')
-rw-r--r-- | libgo/go/syscall/js/js.go | 102 | ||||
-rw-r--r-- | libgo/go/syscall/js/js_test.go | 157 | ||||
-rw-r--r-- | libgo/go/syscall/js/typedarray.go | 104 |
3 files changed, 222 insertions, 141 deletions
diff --git a/libgo/go/syscall/js/js.go b/libgo/go/syscall/js/js.go index 0893db0..7300d2c 100644 --- a/libgo/go/syscall/js/js.go +++ b/libgo/go/syscall/js/js.go @@ -79,8 +79,7 @@ var ( valueTrue = predefValue(3) valueFalse = predefValue(4) valueGlobal = predefValue(5) - memory = predefValue(6) // WebAssembly linear memory - jsGo = predefValue(7) // instance of the Go class in JavaScript + jsGo = predefValue(6) // instance of the Go class in JavaScript objectConstructor = valueGlobal.Get("Object") arrayConstructor = valueGlobal.Get("Array") @@ -106,7 +105,6 @@ func Global() Value { // | Go | JavaScript | // | ---------------------- | ---------------------- | // | js.Value | [its value] | -// | js.TypedArray | typed array | // | js.Func | function | // | nil | null | // | bool | boolean | @@ -216,6 +214,10 @@ func (t Type) String() string { } } +func (t Type) isObject() bool { + return t == TypeObject || t == TypeFunction +} + // Type returns the JavaScript type of the value v. It is similar to JavaScript's typeof operator, // except that it returns TypeNull instead of TypeObject for null. func (v Value) Type() Type { @@ -244,28 +246,44 @@ func (v Value) Type() Type { } // Get returns the JavaScript property p of value v. +// It panics if v is not a JavaScript object. func (v Value) Get(p string) Value { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.Get", vType}) + } return makeValue(valueGet(v.ref, p)) } func valueGet(v ref, p string) ref // Set sets the JavaScript property p of value v to ValueOf(x). +// It panics if v is not a JavaScript object. func (v Value) Set(p string, x interface{}) { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.Set", vType}) + } valueSet(v.ref, p, ValueOf(x).ref) } func valueSet(v ref, p string, x ref) // Index returns JavaScript index i of value v. +// It panics if v is not a JavaScript object. func (v Value) Index(i int) Value { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.Index", vType}) + } return makeValue(valueIndex(v.ref, i)) } func valueIndex(v ref, i int) ref // SetIndex sets the JavaScript index i of value v to ValueOf(x). +// It panics if v is not a JavaScript object. func (v Value) SetIndex(i int, x interface{}) { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.SetIndex", vType}) + } valueSetIndex(v.ref, i, ValueOf(x).ref) } @@ -280,7 +298,11 @@ func makeArgs(args []interface{}) []ref { } // Length returns the JavaScript property "length" of v. +// It panics if v is not a JavaScript object. func (v Value) Length() int { + if vType := v.Type(); !vType.isObject() { + panic(&ValueError{"Value.SetIndex", vType}) + } return valueLength(v.ref) } @@ -292,7 +314,7 @@ func valueLength(v ref) int func (v Value) Call(m string, args ...interface{}) Value { res, ok := valueCall(v.ref, m, makeArgs(args)) if !ok { - if vType := v.Type(); vType != TypeObject && vType != TypeFunction { // check here to avoid overhead in success case + if vType := v.Type(); !vType.isObject() { // check here to avoid overhead in success case panic(&ValueError{"Value.Call", vType}) } if propType := v.Get(m).Type(); propType != TypeFunction { @@ -306,7 +328,7 @@ func (v Value) Call(m string, args ...interface{}) Value { func valueCall(v ref, m string, args []ref) (ref, bool) // Invoke does a JavaScript call of the value v with the given arguments. -// It panics if v is not a function. +// It panics if v is not a JavaScript function. // The arguments get mapped to JavaScript values according to the ValueOf function. func (v Value) Invoke(args ...interface{}) Value { res, ok := valueInvoke(v.ref, makeArgs(args)) @@ -322,11 +344,14 @@ func (v Value) Invoke(args ...interface{}) Value { func valueInvoke(v ref, args []ref) (ref, bool) // New uses JavaScript's "new" operator with value v as constructor and the given arguments. -// It panics if v is not a function. +// It panics if v is not a JavaScript function. // The arguments get mapped to JavaScript values according to the ValueOf function. func (v Value) New(args ...interface{}) Value { res, ok := valueNew(v.ref, makeArgs(args)) if !ok { + if vType := v.Type(); vType != TypeFunction { // check here to avoid overhead in success case + panic(&ValueError{"Value.Invoke", vType}) + } panic(Error{makeValue(res)}) } return makeValue(res) @@ -350,17 +375,20 @@ func (v Value) float(method string) float64 { return *(*float64)(unsafe.Pointer(&v.ref)) } -// Float returns the value v as a float64. It panics if v is not a JavaScript number. +// Float returns the value v as a float64. +// It panics if v is not a JavaScript number. func (v Value) Float() float64 { return v.float("Value.Float") } -// Int returns the value v truncated to an int. It panics if v is not a JavaScript number. +// Int returns the value v truncated to an int. +// It panics if v is not a JavaScript number. func (v Value) Int() int { return int(v.float("Value.Int")) } -// Bool returns the value v as a bool. It panics if v is not a JavaScript boolean. +// Bool returns the value v as a bool. +// It panics if v is not a JavaScript boolean. func (v Value) Bool() bool { switch v.ref { case valueTrue.ref: @@ -392,9 +420,35 @@ func (v Value) Truthy() bool { } } -// String returns the value v converted to string according to JavaScript type conversions. +// String returns the value v as a string. +// String is a special case because of Go's String method convention. Unlike the other getters, +// it does not panic if v's Type is not TypeString. Instead, it returns a string of the form "<T>" +// or "<T: V>" where T is v's type and V is a string representation of v's value. func (v Value) String() string { - str, length := valuePrepareString(v.ref) + switch v.Type() { + case TypeString: + return jsString(v.ref) + case TypeUndefined: + return "<undefined>" + case TypeNull: + return "<null>" + case TypeBoolean: + return "<boolean: " + jsString(v.ref) + ">" + case TypeNumber: + return "<number: " + jsString(v.ref) + ">" + case TypeSymbol: + return "<symbol>" + case TypeObject: + return "<object>" + case TypeFunction: + return "<function>" + default: + panic("bad type") + } +} + +func jsString(v ref) string { + str, length := valuePrepareString(v) b := make([]byte, length) valueLoadString(str, b) return string(b) @@ -422,3 +476,29 @@ type ValueError struct { func (e *ValueError) Error() string { return "syscall/js: call of " + e.Method + " on " + e.Type.String() } + +// CopyBytesToGo copies bytes from the Uint8Array src to dst. +// It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. +// CopyBytesToGo panics if src is not an Uint8Array. +func CopyBytesToGo(dst []byte, src Value) int { + n, ok := copyBytesToGo(dst, src.ref) + if !ok { + panic("syscall/js: CopyBytesToGo: expected src to be an Uint8Array") + } + return n +} + +func copyBytesToGo(dst []byte, src ref) (int, bool) + +// CopyBytesToJS copies bytes from src to the Uint8Array dst. +// It returns the number of bytes copied, which will be the minimum of the lengths of src and dst. +// CopyBytesToJS panics if dst is not an Uint8Array. +func CopyBytesToJS(dst Value, src []byte) int { + n, ok := copyBytesToJS(dst.ref, src) + if !ok { + panic("syscall/js: CopyBytesToJS: expected dst to be an Uint8Array") + } + return n +} + +func copyBytesToJS(dst ref, src []byte) (int, bool) diff --git a/libgo/go/syscall/js/js_test.go b/libgo/go/syscall/js/js_test.go index c14d2cc..7a1e346 100644 --- a/libgo/go/syscall/js/js_test.go +++ b/libgo/go/syscall/js/js_test.go @@ -72,10 +72,26 @@ func TestString(t *testing.T) { t.Errorf("same value not equal") } - wantInt := "42" - o = dummys.Get("someInt") - if got := o.String(); got != wantInt { - t.Errorf("got %#v, want %#v", got, wantInt) + if got, want := js.Undefined().String(), "<undefined>"; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Null().String(), "<null>"; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.ValueOf(true).String(), "<boolean: true>"; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.ValueOf(42.5).String(), "<number: 42.5>"; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Global().Call("Symbol").String(), "<symbol>"; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Global().String(), "<object>"; got != want { + t.Errorf("got %#v, want %#v", got, want) + } + if got, want := js.Global().Get("setTimeout").String(), "<function>"; got != want { + t.Errorf("got %#v, want %#v", got, want) } } @@ -151,28 +167,6 @@ func TestFrozenObject(t *testing.T) { } } -func TestTypedArrayOf(t *testing.T) { - testTypedArrayOf(t, "[]int8", []int8{0, -42, 0}, -42) - testTypedArrayOf(t, "[]int16", []int16{0, -42, 0}, -42) - testTypedArrayOf(t, "[]int32", []int32{0, -42, 0}, -42) - testTypedArrayOf(t, "[]uint8", []uint8{0, 42, 0}, 42) - testTypedArrayOf(t, "[]uint16", []uint16{0, 42, 0}, 42) - testTypedArrayOf(t, "[]uint32", []uint32{0, 42, 0}, 42) - testTypedArrayOf(t, "[]float32", []float32{0, -42.5, 0}, -42.5) - testTypedArrayOf(t, "[]float64", []float64{0, -42.5, 0}, -42.5) -} - -func testTypedArrayOf(t *testing.T, name string, slice interface{}, want float64) { - t.Run(name, func(t *testing.T) { - a := js.TypedArrayOf(slice) - got := a.Index(1).Float() - a.Release() - if got != want { - t.Errorf("got %#v, want %#v", got, want) - } - }) -} - func TestNaN(t *testing.T) { want := js.ValueOf(math.NaN()) got := dummys.Get("NaN") @@ -202,10 +196,30 @@ func TestLength(t *testing.T) { } } +func TestGet(t *testing.T) { + // positive cases get tested per type + + expectValueError(t, func() { + dummys.Get("zero").Get("badField") + }) +} + +func TestSet(t *testing.T) { + // positive cases get tested per type + + expectValueError(t, func() { + dummys.Get("zero").Set("badField", 42) + }) +} + func TestIndex(t *testing.T) { if got := dummys.Get("someArray").Index(1).Int(); got != 42 { t.Errorf("got %#v, want %#v", got, 42) } + + expectValueError(t, func() { + dummys.Get("zero").Index(1) + }) } func TestSetIndex(t *testing.T) { @@ -213,6 +227,10 @@ func TestSetIndex(t *testing.T) { if got := dummys.Get("someArray").Index(2).Int(); got != 99 { t.Errorf("got %#v, want %#v", got, 99) } + + expectValueError(t, func() { + dummys.Get("zero").SetIndex(2, 99) + }) } func TestCall(t *testing.T) { @@ -223,6 +241,13 @@ func TestCall(t *testing.T) { if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 { t.Errorf("got %#v, want %#v", got, 42) } + + expectPanic(t, func() { + dummys.Call("zero") + }) + expectValueError(t, func() { + dummys.Get("zero").Call("badMethod") + }) } func TestInvoke(t *testing.T) { @@ -230,12 +255,20 @@ func TestInvoke(t *testing.T) { if got := dummys.Get("add").Invoke(i, 2).Int(); got != 42 { t.Errorf("got %#v, want %#v", got, 42) } + + expectValueError(t, func() { + dummys.Get("zero").Invoke() + }) } func TestNew(t *testing.T) { if got := js.Global().Get("Array").New(42).Length(); got != 42 { t.Errorf("got %#v, want %#v", got, 42) } + + expectValueError(t, func() { + dummys.Get("zero").New() + }) } func TestInstanceOf(t *testing.T) { @@ -379,3 +412,75 @@ func TestTruthy(t *testing.T) { t.Errorf("got %#v, want %#v", got, want) } } + +func expectValueError(t *testing.T, fn func()) { + defer func() { + err := recover() + if _, ok := err.(*js.ValueError); !ok { + t.Errorf("expected *js.ValueError, got %T", err) + } + }() + fn() +} + +func expectPanic(t *testing.T, fn func()) { + defer func() { + err := recover() + if err == nil { + t.Errorf("expected panic") + } + }() + fn() +} + +var copyTests = []struct { + srcLen int + dstLen int + copyLen int +}{ + {5, 3, 3}, + {3, 5, 3}, + {0, 0, 0}, +} + +func TestCopyBytesToGo(t *testing.T) { + for _, tt := range copyTests { + t.Run(fmt.Sprintf("%d-to-%d", tt.srcLen, tt.dstLen), func(t *testing.T) { + src := js.Global().Get("Uint8Array").New(tt.srcLen) + if tt.srcLen >= 2 { + src.SetIndex(1, 42) + } + dst := make([]byte, tt.dstLen) + + if got, want := js.CopyBytesToGo(dst, src), tt.copyLen; got != want { + t.Errorf("copied %d, want %d", got, want) + } + if tt.dstLen >= 2 { + if got, want := int(dst[1]), 42; got != want { + t.Errorf("got %d, want %d", got, want) + } + } + }) + } +} + +func TestCopyBytesToJS(t *testing.T) { + for _, tt := range copyTests { + t.Run(fmt.Sprintf("%d-to-%d", tt.srcLen, tt.dstLen), func(t *testing.T) { + src := make([]byte, tt.srcLen) + if tt.srcLen >= 2 { + src[1] = 42 + } + dst := js.Global().Get("Uint8Array").New(tt.dstLen) + + if got, want := js.CopyBytesToJS(dst, src), tt.copyLen; got != want { + t.Errorf("copied %d, want %d", got, want) + } + if tt.dstLen >= 2 { + if got, want := dst.Index(1).Int(), 42; got != want { + t.Errorf("got %d, want %d", got, want) + } + } + }) + } +} diff --git a/libgo/go/syscall/js/typedarray.go b/libgo/go/syscall/js/typedarray.go deleted file mode 100644 index aa56cf6..0000000 --- a/libgo/go/syscall/js/typedarray.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build js,wasm - -package js - -import ( - "sync" - "unsafe" -) - -var ( - int8Array = Global().Get("Int8Array") - int16Array = Global().Get("Int16Array") - int32Array = Global().Get("Int32Array") - uint8Array = Global().Get("Uint8Array") - uint16Array = Global().Get("Uint16Array") - uint32Array = Global().Get("Uint32Array") - float32Array = Global().Get("Float32Array") - float64Array = Global().Get("Float64Array") -) - -var _ Wrapper = TypedArray{} // TypedArray must implement Wrapper - -// TypedArray represents a JavaScript typed array. -type TypedArray struct { - Value -} - -// Release frees up resources allocated for the typed array. -// The typed array and its buffer must not be accessed after calling Release. -func (a TypedArray) Release() { - openTypedArraysMutex.Lock() - delete(openTypedArrays, a) - openTypedArraysMutex.Unlock() -} - -var ( - openTypedArraysMutex sync.Mutex - openTypedArrays = make(map[TypedArray]interface{}) -) - -// TypedArrayOf returns a JavaScript typed array backed by the slice's underlying array. -// -// The supported types are []int8, []int16, []int32, []uint8, []uint16, []uint32, []float32 and []float64. -// Passing an unsupported value causes a panic. -// -// TypedArray.Release must be called to free up resources when the typed array will not be used any more. -func TypedArrayOf(slice interface{}) TypedArray { - a := TypedArray{typedArrayOf(slice)} - openTypedArraysMutex.Lock() - openTypedArrays[a] = slice - openTypedArraysMutex.Unlock() - return a -} - -func typedArrayOf(slice interface{}) Value { - switch slice := slice.(type) { - case []int8: - if len(slice) == 0 { - return int8Array.New(memory.Get("buffer"), 0, 0) - } - return int8Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - case []int16: - if len(slice) == 0 { - return int16Array.New(memory.Get("buffer"), 0, 0) - } - return int16Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - case []int32: - if len(slice) == 0 { - return int32Array.New(memory.Get("buffer"), 0, 0) - } - return int32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - case []uint8: - if len(slice) == 0 { - return uint8Array.New(memory.Get("buffer"), 0, 0) - } - return uint8Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - case []uint16: - if len(slice) == 0 { - return uint16Array.New(memory.Get("buffer"), 0, 0) - } - return uint16Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - case []uint32: - if len(slice) == 0 { - return uint32Array.New(memory.Get("buffer"), 0, 0) - } - return uint32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - case []float32: - if len(slice) == 0 { - return float32Array.New(memory.Get("buffer"), 0, 0) - } - return float32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - case []float64: - if len(slice) == 0 { - return float64Array.New(memory.Get("buffer"), 0, 0) - } - return float64Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice)) - default: - panic("TypedArrayOf: not a supported slice") - } -} |