Bug 1165053 - Part 1: Handle when ArrayBuffer species constructor returns wrapped ArrayBuffer. r=jwalden
authorTooru Fujisawa <arai_a@mac.com>
Thu, 14 Jan 2016 15:11:26 +0900
changeset 292142 38d7887d6f237ea38887bb076d9cdad5d86a54c6
parent 292141 12c5896fe0d221c27a3576059b7f010560b46053
child 292143 5cdf65882fe2279e713b578ca319e0862072a491
push id74764
push userarai_a@mac.com
push dateThu, 07 Apr 2016 10:49:15 +0000
treeherdermozilla-inbound@4d0f975a2311 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1165053
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1165053 - Part 1: Handle when ArrayBuffer species constructor returns wrapped ArrayBuffer. r=jwalden
js/src/builtin/TypedArray.js
js/src/vm/SelfHosting.cpp
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1303,17 +1303,17 @@ function TypedArrayStaticOf(/*...items*/
     // Steps 6-7.
     for (var k = 0; k < len; k++)
         newObj[k] = items[k]
 
     // Step 8.
     return newObj;
 }
 
-// ES 2016 draft Dec 10, 2015 24.1.4.3.
+// ES 2016 draft Mar 25, 2016 24.1.4.3.
 function ArrayBufferSlice(start, end) {
     // Step 1.
     var O = this;
 
     // Steps 2-3,
     // This function is not generic.
     if (!IsObject(O) || !IsArrayBuffer(O)) {
         return callFunction(CallArrayBufferMethodIfWrapped, O, start, end,
@@ -1346,40 +1346,54 @@ function ArrayBufferSlice(start, end) {
     var newLen = std_Math_max(final - first, 0);
 
     // Step 11
     var ctor = SpeciesConstructor(O, GetBuiltinConstructor("ArrayBuffer"));
 
     // Step 12.
     var new_ = new ctor(newLen);
 
-    // Step 13.
-    if (!IsArrayBuffer(new_))
-        ThrowTypeError(JSMSG_NON_ARRAY_BUFFER_RETURNED);
+    var isWrapped = false;
+    if (IsArrayBuffer(new_)) {
+        // Step 14.
+        if (IsDetachedBuffer(new_))
+            ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+    } else {
+        // Step 13.
+        if (!IsWrappedArrayBuffer(new_))
+            ThrowTypeError(JSMSG_NON_ARRAY_BUFFER_RETURNED);
 
-    // Step 14.
-    if (IsDetachedBuffer(new_))
-        ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+        isWrapped = true;
+
+        // Step 14.
+        if (callFunction(CallArrayBufferMethodIfWrapped, new_, "IsDetachedBufferThis"))
+            ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
+    }
 
     // Step 15.
-    if (new_ == O)
+    if (new_ === O)
         ThrowTypeError(JSMSG_SAME_ARRAY_BUFFER_RETURNED);
 
     // Step 16.
-    if (ArrayBufferByteLength(new_) < newLen)
-        ThrowTypeError(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, newLen, ArrayBufferByteLength(new_));
+    var actualLen = PossiblyWrappedArrayBufferByteLength(new_);
+    if (actualLen < newLen)
+        ThrowTypeError(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, newLen, actualLen);
 
     // Step 18.
     if (IsDetachedBuffer(O))
         ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
 
     // Steps 19-21.
-    ArrayBufferCopyData(new_, O, first | 0, newLen | 0);
+    ArrayBufferCopyData(new_, O, first | 0, newLen | 0, isWrapped);
 
     // Step 22.
     return new_;
 }
 
+function IsDetachedBufferThis() {
+  return IsDetachedBuffer(this);
+}
+
 function ArrayBufferStaticSlice(buf, start, end) {
     if (arguments.length < 1)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'ArrayBuffer.slice');
     return callFunction(ArrayBufferSlice, buf, start, end);
 }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -36,16 +36,17 @@
 #include "jit/AtomicOperations.h"
 #include "jit/InlinableNatives.h"
 #include "js/Date.h"
 #include "vm/Compression.h"
 #include "vm/GeneratorObject.h"
 #include "vm/Interpreter.h"
 #include "vm/String.h"
 #include "vm/TypedArrayCommon.h"
+#include "vm/WrapperObject.h"
 
 #include "jsfuninlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/BooleanObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/NumberObject-inl.h"
@@ -864,16 +865,43 @@ intrinsic_GeneratorSetClosed(JSContext* 
     MOZ_ASSERT(args[0].isObject());
 
     GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
     genObj->setClosed();
     return true;
 }
 
 static bool
+intrinsic_IsWrappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    MOZ_ASSERT(args.length() == 1);
+
+    if (!args[0].isObject()) {
+        args.rval().setBoolean(false);
+        return true;
+    }
+
+    JSObject* obj = &args[0].toObject();
+    if (!obj->is<WrapperObject>()) {
+        args.rval().setBoolean(false);
+        return true;
+    }
+
+    JSObject* unwrapped = CheckedUnwrap(obj);
+    if (!unwrapped) {
+        JS_ReportError(cx, "Permission denied to access object");
+        return false;
+    }
+
+    args.rval().setBoolean(unwrapped->is<ArrayBufferObject>());
+    return true;
+}
+
+static bool
 intrinsic_ArrayBufferByteLength(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 1);
     MOZ_ASSERT(args[0].isObject());
     MOZ_ASSERT(args[0].toObject().is<ArrayBufferObject>());
 
     size_t byteLength = args[0].toObject().as<ArrayBufferObject>().byteLength();
@@ -897,25 +925,32 @@ intrinsic_PossiblyWrappedArrayBufferByte
     args.rval().setInt32(mozilla::AssertedCast<int32_t>(length));
     return true;
 }
 
 static bool
 intrinsic_ArrayBufferCopyData(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    MOZ_ASSERT(args.length() == 4);
-    MOZ_ASSERT(args[0].isObject());
-    MOZ_ASSERT(args[0].toObject().is<ArrayBufferObject>());
-    MOZ_ASSERT(args[1].isObject());
-    MOZ_ASSERT(args[1].toObject().is<ArrayBufferObject>());
-    MOZ_ASSERT(args[2].isInt32());
-    MOZ_ASSERT(args[3].isInt32());
-
-    Rooted<ArrayBufferObject*> toBuffer(cx, &args[0].toObject().as<ArrayBufferObject>());
+    MOZ_ASSERT(args.length() == 5);
+
+    bool isWrapped = args[4].toBoolean();
+    Rooted<ArrayBufferObject*> toBuffer(cx);
+    if (!isWrapped) {
+        toBuffer = &args[0].toObject().as<ArrayBufferObject>();
+    } else {
+        JSObject* wrapped = &args[0].toObject();
+        MOZ_ASSERT(wrapped->is<WrapperObject>());
+        RootedObject toBufferObj(cx, CheckedUnwrap(wrapped));
+        if (!toBufferObj) {
+            JS_ReportError(cx, "Permission denied to access object");
+            return false;
+        }
+        toBuffer = toBufferObj.as<ArrayBufferObject>();
+    }
     Rooted<ArrayBufferObject*> fromBuffer(cx, &args[1].toObject().as<ArrayBufferObject>());
     uint32_t fromIndex = uint32_t(args[2].toInt32());
     uint32_t count = uint32_t(args[3].toInt32());
 
     ArrayBufferObject::copyData(toBuffer, fromBuffer, fromIndex, count);
 
     args.rval().setUndefined();
     return true;
@@ -2162,22 +2197,23 @@ static const JSFunctionSpec intrinsic_fu
 
     JS_FN("GeneratorIsRunning",      intrinsic_GeneratorIsRunning,      1,0),
     JS_FN("GeneratorSetClosed",      intrinsic_GeneratorSetClosed,      1,0),
 
     JS_FN("IsArrayBuffer",
           intrinsic_IsInstanceOfBuiltin<ArrayBufferObject>,             1,0),
     JS_FN("IsSharedArrayBuffer",
           intrinsic_IsInstanceOfBuiltin<SharedArrayBufferObject>,       1,0),
+    JS_FN("IsWrappedArrayBuffer",    intrinsic_IsWrappedArrayBuffer,    1,0),
 
     JS_INLINABLE_FN("ArrayBufferByteLength",   intrinsic_ArrayBufferByteLength, 1,0,
                     IntrinsicArrayBufferByteLength),
     JS_INLINABLE_FN("PossiblyWrappedArrayBufferByteLength", intrinsic_PossiblyWrappedArrayBufferByteLength, 1,0,
                     IntrinsicPossiblyWrappedArrayBufferByteLength),
-    JS_FN("ArrayBufferCopyData",     intrinsic_ArrayBufferCopyData,     4,0),
+    JS_FN("ArrayBufferCopyData",     intrinsic_ArrayBufferCopyData,     5,0),
 
     JS_FN("IsUint8TypedArray",        intrinsic_IsUint8TypedArray,      1,0),
     JS_FN("IsInt8TypedArray",         intrinsic_IsInt8TypedArray,       1,0),
     JS_FN("IsUint16TypedArray",       intrinsic_IsUint16TypedArray,     1,0),
     JS_FN("IsInt16TypedArray",        intrinsic_IsInt16TypedArray,      1,0),
     JS_FN("IsUint32TypedArray",       intrinsic_IsUint32TypedArray,     1,0),
     JS_FN("IsInt32TypedArray",        intrinsic_IsInt32TypedArray,      1,0),
     JS_FN("IsFloat32TypedArray",      intrinsic_IsFloat32TypedArray,    1,0),