Browse Source

Standard compliance and other fixes for ArrayBuffer

Dmitry Panov 5 years ago
parent
commit
1edec8603b
2 changed files with 36 additions and 15 deletions
  1. 26 15
      builtin_typedarrays.go
  2. 10 0
      tc39_test.go

+ 26 - 15
builtin_typedarrays.go

@@ -1,6 +1,7 @@
 package goja
 package goja
 
 
 import (
 import (
+	"fmt"
 	"math"
 	"math"
 	"sort"
 	"sort"
 	"strings"
 	"strings"
@@ -61,13 +62,26 @@ func (ctx *typedArraySortCtx) Swap(i, j int) {
 	ctx.ta.typedArray.swap(offset+i, offset+j)
 	ctx.ta.typedArray.swap(offset+i, offset+j)
 }
 }
 
 
+func allocByteSlice(size int) (b []byte) {
+	defer func() {
+		if x := recover(); x != nil {
+			panic(rangeError(fmt.Sprintf("Buffer size is too large: %d", size)))
+		}
+	}()
+	if size < 0 {
+		panic(rangeError(fmt.Sprintf("Invalid buffer size: %d", size)))
+	}
+	b = make([]byte, size)
+	return
+}
+
 func (r *Runtime) builtin_newArrayBuffer(args []Value, newTarget *Object) *Object {
 func (r *Runtime) builtin_newArrayBuffer(args []Value, newTarget *Object) *Object {
 	if newTarget == nil {
 	if newTarget == nil {
 		panic(r.needNew("ArrayBuffer"))
 		panic(r.needNew("ArrayBuffer"))
 	}
 	}
 	b := r._newArrayBuffer(r.getPrototypeFromCtor(newTarget, r.global.ArrayBuffer, r.global.ArrayBufferPrototype), nil)
 	b := r._newArrayBuffer(r.getPrototypeFromCtor(newTarget, r.global.ArrayBuffer, r.global.ArrayBufferPrototype), nil)
 	if len(args) > 0 {
 	if len(args) > 0 {
-		b.data = make([]byte, toLength(args[0]))
+		b.data = allocByteSlice(r.toIndex(args[0]))
 	}
 	}
 	return b.val
 	return b.val
 }
 }
@@ -75,9 +89,7 @@ func (r *Runtime) builtin_newArrayBuffer(args []Value, newTarget *Object) *Objec
 func (r *Runtime) arrayBufferProto_getByteLength(call FunctionCall) Value {
 func (r *Runtime) arrayBufferProto_getByteLength(call FunctionCall) Value {
 	o := r.toObject(call.This)
 	o := r.toObject(call.This)
 	if b, ok := o.self.(*arrayBufferObject); ok {
 	if b, ok := o.self.(*arrayBufferObject); ok {
-		if b.data == nil {
-			panic(r.NewTypeError("ArrayBuffer is detached"))
-		}
+		b.ensureNotDetached()
 		return intToValue(int64(len(b.data)))
 		return intToValue(int64(len(b.data)))
 	}
 	}
 	panic(r.NewTypeError("Object is not ArrayBuffer: %s", o))
 	panic(r.NewTypeError("Object is not ArrayBuffer: %s", o))
@@ -87,10 +99,10 @@ func (r *Runtime) arrayBufferProto_slice(call FunctionCall) Value {
 	o := r.toObject(call.This)
 	o := r.toObject(call.This)
 	if b, ok := o.self.(*arrayBufferObject); ok {
 	if b, ok := o.self.(*arrayBufferObject); ok {
 		l := int64(len(b.data))
 		l := int64(len(b.data))
-		start := relToIdx(toLength(call.Argument(0)), l)
+		start := relToIdx(call.Argument(0).ToInteger(), l)
 		var stop int64
 		var stop int64
 		if arg := call.Argument(1); arg != _undefined {
 		if arg := call.Argument(1); arg != _undefined {
-			stop = toLength(arg)
+			stop = arg.ToInteger()
 		} else {
 		} else {
 			stop = l
 			stop = l
 		}
 		}
@@ -98,18 +110,14 @@ func (r *Runtime) arrayBufferProto_slice(call FunctionCall) Value {
 		newLen := max(stop-start, 0)
 		newLen := max(stop-start, 0)
 		ret := r.speciesConstructor(o, r.global.ArrayBuffer)([]Value{intToValue(newLen)}, nil)
 		ret := r.speciesConstructor(o, r.global.ArrayBuffer)([]Value{intToValue(newLen)}, nil)
 		if ab, ok := ret.self.(*arrayBufferObject); ok {
 		if ab, ok := ret.self.(*arrayBufferObject); ok {
-			if ab.data == nil {
-				panic(r.NewTypeError("Species constructor returned a detached ArrayBuffer"))
-			}
+			ab.ensureNotDetached()
 			if ret == o {
 			if ret == o {
 				panic(r.NewTypeError("Species constructor returned the same ArrayBuffer"))
 				panic(r.NewTypeError("Species constructor returned the same ArrayBuffer"))
 			}
 			}
 			if int64(len(ab.data)) < newLen {
 			if int64(len(ab.data)) < newLen {
 				panic(r.NewTypeError("Species constructor returned an ArrayBuffer that is too small: %d", len(ab.data)))
 				panic(r.NewTypeError("Species constructor returned an ArrayBuffer that is too small: %d", len(ab.data)))
 			}
 			}
-			if b.data == nil {
-				panic(r.NewTypeError("Species constructor has detached the current ArrayBuffer"))
-			}
+			b.ensureNotDetached()
 
 
 			if stop > start {
 			if stop > start {
 				copy(ab.data, b.data[start:stop])
 				copy(ab.data, b.data[start:stop])
@@ -122,10 +130,13 @@ func (r *Runtime) arrayBufferProto_slice(call FunctionCall) Value {
 }
 }
 
 
 func (r *Runtime) arrayBuffer_isView(call FunctionCall) Value {
 func (r *Runtime) arrayBuffer_isView(call FunctionCall) Value {
-	if o, ok := call.This.(*Object); ok {
+	if o, ok := call.Argument(0).(*Object); ok {
 		if _, ok := o.self.(*dataViewObject); ok {
 		if _, ok := o.self.(*dataViewObject); ok {
 			return valueTrue
 			return valueTrue
 		}
 		}
+		if _, ok := o.self.(*typedArrayObject); ok {
+			return valueTrue
+		}
 	}
 	}
 	return valueFalse
 	return valueFalse
 }
 }
@@ -1047,7 +1058,7 @@ func (r *Runtime) allocateTypedArray(newTarget *Object, length int, taCtor typed
 	buf := r._newArrayBuffer(r.global.ArrayBufferPrototype, nil)
 	buf := r._newArrayBuffer(r.global.ArrayBufferPrototype, nil)
 	ta := taCtor(buf, 0, length, r.getPrototypeFromCtor(newTarget, nil, r.global.TypedArrayPrototype))
 	ta := taCtor(buf, 0, length, r.getPrototypeFromCtor(newTarget, nil, r.global.TypedArrayPrototype))
 	if length > 0 {
 	if length > 0 {
-		buf.data = make([]byte, length*ta.elemSize)
+		buf.data = allocByteSlice(length * ta.elemSize)
 	}
 	}
 	return ta.val
 	return ta.val
 }
 }
@@ -1157,7 +1168,7 @@ func (r *Runtime) _newTypedArrayFromTypedArray(src *typedArrayObject, newTarget
 	src.viewedArrayBuf.ensureNotDetached()
 	src.viewedArrayBuf.ensureNotDetached()
 	l := src.length
 	l := src.length
 	dst.viewedArrayBuf.prototype = r.getPrototypeFromCtor(r.toObject(src.viewedArrayBuf.getStr("constructor", nil)), r.global.ArrayBuffer, r.global.ArrayBufferPrototype)
 	dst.viewedArrayBuf.prototype = r.getPrototypeFromCtor(r.toObject(src.viewedArrayBuf.getStr("constructor", nil)), r.global.ArrayBuffer, r.global.ArrayBufferPrototype)
-	dst.viewedArrayBuf.data = make([]byte, int64(l)*int64(dst.elemSize))
+	dst.viewedArrayBuf.data = allocByteSlice(toInt(int64(l) * int64(dst.elemSize)))
 	if src.defaultCtor == dst.defaultCtor {
 	if src.defaultCtor == dst.defaultCtor {
 		copy(dst.viewedArrayBuf.data, src.viewedArrayBuf.data[src.offset*src.elemSize:])
 		copy(dst.viewedArrayBuf.data, src.viewedArrayBuf.data[src.offset*src.elemSize:])
 		dst.length = src.length
 		dst.length = src.length

+ 10 - 0
tc39_test.go

@@ -39,6 +39,9 @@ var (
 		"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-10.js": true, // timezone
 		"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-10.js": true, // timezone
 		"test/annexB/built-ins/escape/escape-above-astral.js":         true, // \u{xxxxx}
 		"test/annexB/built-ins/escape/escape-above-astral.js":         true, // \u{xxxxx}
 
 
+		// SharedArrayBuffer
+		"test/built-ins/ArrayBuffer/prototype/slice/this-is-sharedarraybuffer.js": true,
+
 		// class
 		// class
 		"test/language/statements/class/subclass/builtin-objects/Symbol/symbol-valid-as-extends-value.js":            true,
 		"test/language/statements/class/subclass/builtin-objects/Symbol/symbol-valid-as-extends-value.js":            true,
 		"test/language/statements/class/subclass/builtin-objects/Symbol/new-symbol-with-super-throws.js":             true,
 		"test/language/statements/class/subclass/builtin-objects/Symbol/new-symbol-with-super-throws.js":             true,
@@ -96,6 +99,10 @@ var (
 		"test/language/statements/class/subclass/builtin-objects/Array/regular-subclassing.js":                       true,
 		"test/language/statements/class/subclass/builtin-objects/Array/regular-subclassing.js":                       true,
 		"test/language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-single-argument.js":    true,
 		"test/language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-single-argument.js":    true,
 		"test/language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-multiple-arguments.js": true,
 		"test/language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-multiple-arguments.js": true,
+		"test/language/statements/class/subclass/builtin-objects/ArrayBuffer/super-must-be-called.js":                true,
+		"test/language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js":                 true,
+		"test/built-ins/ArrayBuffer/isView/arg-is-typedarray-subclass-instance.js":                                   true,
+		"test/built-ins/ArrayBuffer/isView/arg-is-dataview-subclass-instance.js":                                     true,
 
 
 		// full unicode regexp flag
 		// full unicode regexp flag
 		"test/built-ins/RegExp/prototype/Symbol.match/u-advance-after-empty.js":               true,
 		"test/built-ins/RegExp/prototype/Symbol.match/u-advance-after-empty.js":               true,
@@ -155,6 +162,7 @@ var (
 		"23.2",
 		"23.2",
 		"23.3",
 		"23.3",
 		"23.4",
 		"23.4",
+		"24.1",
 		"24.2",
 		"24.2",
 		"25.1.2",
 		"25.1.2",
 		"26.1",
 		"26.1",
@@ -170,6 +178,8 @@ var (
 		"sec-date",
 		"sec-date",
 		"sec-number",
 		"sec-number",
 		"sec-math",
 		"sec-math",
+		"sec-arraybuffer-length",
+		"sec-arraybuffer",
 	}
 	}
 )
 )