aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/syscall/js
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-09-06 18:12:46 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-09-06 18:12:46 +0000
commitaa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13 (patch)
tree7e63b06d1eec92beec6997c9d3ab47a5d6a835be /libgo/go/syscall/js
parent920ea3b8ba3164b61ac9490dfdfceb6936eda6dd (diff)
downloadgcc-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.go102
-rw-r--r--libgo/go/syscall/js/js_test.go157
-rw-r--r--libgo/go/syscall/js/typedarray.go104
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")
- }
-}