Bug 1079844 - Rename isNeutered() to isDetached(), and rename isNeutered() on views to hasDetachedBuffer(). r=sfink
authorJeff Walden <jwalden@mit.edu>
Sun, 24 Jan 2016 23:41:40 -0800
changeset 281963 86e7bff461f85ac192c774d297a942c121b26385
parent 281962 faa7773ee97fe3673685c9a5d2da821f6c795698
child 281964 9429a672f3e567e02d62d5ea202d9422ac35c14a
push id19510
push usergwagner@mozilla.com
push dateMon, 08 Feb 2016 15:56:48 +0000
treeherderb2g-inbound@a3d54e32dee1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1079844
milestone47.0a1
Bug 1079844 - Rename isNeutered() to isDetached(), and rename isNeutered() on views to hasDetachedBuffer(). r=sfink
js/src/builtin/TypedObject.cpp
js/src/jsapi-tests/testArrayBuffer.cpp
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/SelfHosting.cpp
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1381,39 +1381,39 @@ TypedObject::typedMemBase() const
 bool
 TypedObject::isAttached() const
 {
     if (is<InlineTransparentTypedObject>()) {
         ObjectWeakMap* table = compartment()->lazyArrayBuffers;
         if (table) {
             JSObject* buffer = table->lookup(this);
             if (buffer)
-                return !buffer->as<ArrayBufferObject>().isNeutered();
+                return !buffer->as<ArrayBufferObject>().isDetached();
         }
         return true;
     }
     if (is<InlineOpaqueTypedObject>())
         return true;
     if (!as<OutlineTypedObject>().outOfLineTypedMem())
         return false;
     JSObject& owner = as<OutlineTypedObject>().owner();
-    if (owner.is<ArrayBufferObject>() && owner.as<ArrayBufferObject>().isNeutered())
+    if (owner.is<ArrayBufferObject>() && owner.as<ArrayBufferObject>().isDetached())
         return false;
     return true;
 }
 
 bool
 TypedObject::maybeForwardedIsAttached() const
 {
     if (is<InlineTypedObject>())
         return true;
     if (!as<OutlineTypedObject>().outOfLineTypedMem())
         return false;
     JSObject& owner = *MaybeForwarded(&as<OutlineTypedObject>().owner());
-    if (owner.is<ArrayBufferObject>() && owner.as<ArrayBufferObject>().isNeutered())
+    if (owner.is<ArrayBufferObject>() && owner.as<ArrayBufferObject>().isDetached())
         return false;
     return true;
 }
 
 /* static */ bool
 TypedObject::GetBuffer(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -2351,17 +2351,17 @@ TypedObject::construct(JSContext* cx, un
         return true;
     }
 
     // Buffer constructor.
     if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
         Rooted<ArrayBufferObject*> buffer(cx);
         buffer = &args[0].toObject().as<ArrayBufferObject>();
 
-        if (callee->opaque() || buffer->isNeutered()) {
+        if (callee->opaque() || buffer->isDetached()) {
             JS_ReportErrorNumber(cx, GetErrorMessage,
                                  nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
             return false;
         }
 
         int32_t offset;
         if (args.length() >= 2 && !args[1].isUndefined()) {
             if (!args[1].isInt32()) {
--- a/js/src/jsapi-tests/testArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testArrayBuffer.cpp
@@ -101,17 +101,17 @@ BEGIN_TEST(testArrayBuffer_bug720949_vie
     // One view.
     {
         buffer = JS_NewArrayBuffer(cx, 2000);
         JS::RootedObject view(cx, JS_NewUint8ArrayWithBuffer(cx, buffer, 0, -1));
         void* contents = JS_StealArrayBufferContents(cx, buffer);
         CHECK(contents != nullptr);
         JS_free(nullptr, contents);
         GC(cx);
-        CHECK(isNeutered(view));
+        CHECK(hasDetachedBuffer(view));
         CHECK(JS_IsDetachedArrayBufferObject(buffer));
         view = nullptr;
         GC(cx);
         buffer = nullptr;
         GC(cx);
     }
 
     // Two views
@@ -126,18 +126,18 @@ BEGIN_TEST(testArrayBuffer_bug720949_vie
         GC(cx);
         view2 = JS_NewUint8ArrayWithBuffer(cx, buffer, 1, 200);
 
         // Detach
         void* contents = JS_StealArrayBufferContents(cx, buffer);
         CHECK(contents != nullptr);
         JS_free(nullptr, contents);
 
-        CHECK(isNeutered(view1));
-        CHECK(isNeutered(view2));
+        CHECK(hasDetachedBuffer(view1));
+        CHECK(hasDetachedBuffer(view2));
         CHECK(JS_IsDetachedArrayBufferObject(buffer));
 
         view1 = nullptr;
         GC(cx);
         view2 = nullptr;
         GC(cx);
         buffer = nullptr;
         GC(cx);
@@ -147,14 +147,14 @@ BEGIN_TEST(testArrayBuffer_bug720949_vie
 }
 
 static void GC(JSContext* cx)
 {
     JS_GC(JS_GetRuntime(cx));
     JS_GC(JS_GetRuntime(cx)); // Trigger another to wait for background finalization to end
 }
 
-bool isNeutered(JS::HandleObject obj) {
+bool hasDetachedBuffer(JS::HandleObject obj) {
     JS::RootedValue v(cx);
     return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0;
 }
 
 END_TEST(testArrayBuffer_bug720949_viewList)
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -296,17 +296,17 @@ ArrayBufferObject::neuter(JSContext* cx,
             buffer->setFirstView(nullptr);
         }
     }
 
     if (newContents.data() != buffer->dataPointer())
         buffer->setNewOwnedData(cx->runtime()->defaultFreeOp(), newContents);
 
     buffer->setByteLength(0);
-    buffer->setIsNeutered();
+    buffer->setIsDetached();
     return true;
 }
 
 void
 ArrayBufferObject::setNewOwnedData(FreeOp* fop, BufferContents newContents)
 {
     if (ownsData()) {
         MOZ_ASSERT(newContents.data() != dataPointer());
@@ -1156,17 +1156,17 @@ JS_DetachArrayBuffer(JSContext* cx, Hand
 
 JS_FRIEND_API(bool)
 JS_IsDetachedArrayBufferObject(JSObject* obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return false;
 
-    return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isNeutered();
+    return obj->is<ArrayBufferObject>() && obj->as<ArrayBufferObject>().isDetached();
 }
 
 JS_FRIEND_API(JSObject*)
 JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes)
 {
     MOZ_ASSERT(nbytes <= INT32_MAX);
     return ArrayBufferObject::create(cx, nbytes);
 }
@@ -1218,17 +1218,17 @@ JS_StealArrayBufferContents(JSContext* c
         return nullptr;
 
     if (!obj->is<ArrayBufferObject>()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return nullptr;
     }
 
     Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
-    if (buffer->isNeutered()) {
+    if (buffer->isDetached()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return nullptr;
     }
 
     // The caller assumes that a plain malloc'd buffer is returned.
     // hasStealableContents is true for mapped buffers, so we must additionally
     // require that the buffer is plain. In the future, we could consider
     // returning something that handles releasing the memory.
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -239,22 +239,22 @@ class ArrayBufferObject : public ArrayBu
                                         Handle<ArrayBufferObject*> buffer,
                                         bool hasStealableContents);
 
     bool hasStealableContents() const {
         // Inline elements strictly adhere to the corresponding buffer.
         if (!ownsData())
             return false;
 
-        // Neutered contents aren't transferrable because we want a neutered
-        // array's contents to be backed by zeroed memory equal in length to
+        // Detached contents aren't transferrable because we want a detached
+        // buffer's contents to be backed by zeroed memory equal in length to
         // the original buffer contents.  Transferring these contents would
         // allocate new ones based on the current byteLength, which is 0 for a
-        // neutered array -- not the original byteLength.
-        return !isNeutered();
+        // detached buffer -- not the original byteLength.
+        return !isDetached();
     }
 
     // Return whether the buffer is allocated by js_malloc and should be freed
     // with js_free.
     bool hasMallocedContents() const {
         return (ownsData() && isPlain()) || isAsmJSMalloced();
     }
 
@@ -308,17 +308,17 @@ class ArrayBufferObject : public ArrayBu
     }
 
     BufferKind bufferKind() const { return BufferKind(flags() & BUFFER_KIND_MASK); }
     bool isPlain() const { return bufferKind() == PLAIN; }
     bool isAsmJSMapped() const { return bufferKind() == ASMJS_MAPPED; }
     bool isAsmJSMalloced() const { return bufferKind() == ASMJS_MALLOCED; }
     bool isAsmJS() const { return isAsmJSMapped() || isAsmJSMalloced(); }
     bool isMapped() const { return bufferKind() == MAPPED; }
-    bool isNeutered() const { return flags() & DETACHED; }
+    bool isDetached() const { return flags() & DETACHED; }
 
     static bool prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buffer,
                                 bool usesSignalHandlers);
     static bool prepareForAsmJSNoSignals(JSContext* cx, Handle<ArrayBufferObject*> buffer);
 
     static void finalize(FreeOp* fop, JSObject* obj);
 
     static BufferContents createMappedContents(int fd, size_t offset, size_t length);
@@ -349,17 +349,17 @@ class ArrayBufferObject : public ArrayBu
     bool ownsData() const { return flags() & OWNS_DATA; }
     void setOwnsData(OwnsState owns) {
         setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
     }
 
     bool hasTypedObjectViews() const { return flags() & TYPED_OBJECT_VIEWS; }
 
     void setIsAsmJSMalloced() { setFlags((flags() & ~KIND_MASK) | ASMJS_MALLOCED); }
-    void setIsNeutered() { setFlags(flags() | DETACHED); }
+    void setIsDetached() { setFlags(flags() | DETACHED); }
 
     void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
         setByteLength(byteLength);
         setFlags(0);
         setFirstView(nullptr);
         setDataPointer(contents, ownsState);
     }
 };
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -881,19 +881,19 @@ intrinsic_MoveTypedArrayElements(JSConte
 
     Rooted<TypedArrayObject*> tarray(cx, &args[0].toObject().as<TypedArrayObject>());
     uint32_t to = uint32_t(args[1].toInt32());
     uint32_t from = uint32_t(args[2].toInt32());
     uint32_t count = uint32_t(args[3].toInt32());
 
     MOZ_ASSERT(count > 0,
                "don't call this method if copying no elements, because then "
-               "the not-neutered requirement is wrong");
+               "the not-detached requirement is wrong");
 
-    if (tarray->isNeutered() && tarray->hasBuffer()) {
+    if (tarray->hasDetachedBuffer()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
 
     // Don't multiply by |tarray->bytesPerElement()| in case the compiler can't
     // strength-reduce multiplication by 1/2/4/8 into the equivalent shift.
     const size_t ElementShift = TypedArrayShift(tarray->type());
 
@@ -965,18 +965,19 @@ DangerouslyUnwrapTypedArray(JSContext* c
 // ES6 draft 20150403 22.2.3.22.2, steps 12-24, 29.
 static bool
 intrinsic_SetFromTypedArrayApproach(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 4);
 
     Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
-    MOZ_ASSERT(!target->hasBuffer() || !target->isNeutered(),
-               "something should have defended against a neutered target");
+    MOZ_ASSERT(!target->hasDetachedBuffer(),
+               "something should have defended against a target viewing a "
+               "detached buffer");
 
     // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
     // variables derived from it to counsel extreme caution here.
     Rooted<TypedArrayObject*> unsafeTypedArrayCrossCompartment(cx);
     unsafeTypedArrayCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[1].toObject());
     if (!unsafeTypedArrayCrossCompartment)
         return false;
 
@@ -985,19 +986,17 @@ intrinsic_SetFromTypedArrayApproach(JSCo
 
     uint32_t targetLength = uint32_t(args[3].toInt32());
 
     // Handle all checks preceding the actual element-setting.  A visual skim
     // of 22.2.3.22.2 should confirm these are the only steps after steps 1-11
     // that might abort processing (other than for reason of internal error.)
 
     // Steps 12-13.
-    if (unsafeTypedArrayCrossCompartment->hasBuffer() &&
-        unsafeTypedArrayCrossCompartment->isNeutered())
-    {
+    if (unsafeTypedArrayCrossCompartment->hasDetachedBuffer()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
     // Steps 21, 23.
     uint32_t unsafeSrcLengthCrossCompartment = unsafeTypedArrayCrossCompartment->length();
     if (unsafeSrcLengthCrossCompartment + doubleTargetOffset > targetLength) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
@@ -1211,19 +1210,19 @@ js::SetDisjointTypedElements(TypedArrayO
 
 static bool
 intrinsic_SetDisjointTypedElements(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 3);
 
     Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
-    MOZ_ASSERT(!target->hasBuffer() || !target->isNeutered(),
-               "a neutered typed array has no elements to set, so "
-               "it's nonsensical to be setting them");
+    MOZ_ASSERT(!target->hasDetachedBuffer(),
+               "a typed array viewing a detached buffer has no elements to "
+               "set, so it's nonsensical to be setting them");
 
     uint32_t targetOffset = uint32_t(args[1].toInt32());
 
     // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
     // variables derived from it to counsel extreme caution here.
     Rooted<TypedArrayObject*> unsafeSrcCrossCompartment(cx);
     unsafeSrcCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[2].toObject());
     if (!unsafeSrcCrossCompartment)
@@ -1237,18 +1236,18 @@ intrinsic_SetDisjointTypedElements(JSCon
 
 static bool
 intrinsic_SetOverlappingTypedElements(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 3);
 
     Rooted<TypedArrayObject*> target(cx, &args[0].toObject().as<TypedArrayObject>());
-    MOZ_ASSERT(!target->hasBuffer() || !target->isNeutered(),
-               "shouldn't be setting elements if neutered");
+    MOZ_ASSERT(!target->hasDetachedBuffer(),
+               "shouldn't set elements if underlying buffer is detached");
 
     uint32_t targetOffset = uint32_t(args[1].toInt32());
 
     // As directed by |DangerouslyUnwrapTypedArray|, sigil this pointer and all
     // variables derived from it to counsel extreme caution here.
     Rooted<TypedArrayObject*> unsafeSrcCrossCompartment(cx);
     unsafeSrcCrossCompartment = DangerouslyUnwrapTypedArray(cx, &args[2].toObject());
     if (!unsafeSrcCrossCompartment)
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -394,17 +394,17 @@ class TypedArrayObjectTemplate : public 
 
 #ifdef DEBUG
         if (buffer) {
             uint32_t arrayByteLength = obj->byteLength();
             uint32_t arrayByteOffset = obj->byteOffset();
             uint32_t bufferByteLength = buffer->byteLength();
             // Unwraps are safe: both are for the pointer value.
             if (IsArrayBuffer(buffer.get())) {
-                MOZ_ASSERT_IF(!AsArrayBuffer(buffer.get()).isNeutered(),
+                MOZ_ASSERT_IF(!AsArrayBuffer(buffer.get()).isDetached(),
                               buffer->dataPointerEither().unwrap(/*safe*/) <= obj->viewDataEither().unwrap(/*safe*/));
             }
             MOZ_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
             MOZ_ASSERT(arrayByteOffset <= bufferByteLength);
         }
 
         // Verify that the private slot is at the expected place
         MOZ_ASSERT(obj->numFixedSlots() == TypedArrayObject::DATA_SLOT);
@@ -587,17 +587,17 @@ class TypedArrayObjectTemplate : public 
         if (!IsArrayBuffer(bufobj) && !IsSharedArrayBuffer(bufobj)) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // must be arrayBuffer
         }
 
         Rooted<ArrayBufferObjectMaybeShared*> buffer(cx);
         if (IsArrayBuffer(bufobj)) {
             ArrayBufferObject& buf = AsArrayBuffer(bufobj);
-            if (buf.isNeutered()) {
+            if (buf.isDetached()) {
                 JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
                 return nullptr;
             }
 
             buffer = static_cast<ArrayBufferObjectMaybeShared*>(&buf);
         } else {
             buffer = static_cast<ArrayBufferObjectMaybeShared*>(&AsSharedArrayBuffer(bufobj));
         }
@@ -721,17 +721,17 @@ TypedArrayObjectTemplate<T>::fromArray(J
     // subclassing.
     RootedObject proto(cx);
 
     uint32_t len;
     if (other->is<TypedArrayObject>()) {
         if (!GetPrototypeForInstance(cx, newTarget, &proto))
             return nullptr;
 
-        if (other->as<TypedArrayObject>().isNeutered()) {
+        if (other->as<TypedArrayObject>().hasDetachedBuffer()) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
             return nullptr;
         }
         len = other->as<TypedArrayObject>().length();
     } else {
         if (!GetLengthProperty(cx, other, &len))
             return nullptr;
         if (!GetPrototypeForInstance(cx, newTarget, &proto))
@@ -1104,17 +1104,17 @@ DataViewObject::getAndCheckConstructorAr
         if (!ToUint32(cx, args[1], &byteOffset))
             return false;
         if (byteOffset > INT32_MAX) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
             return false;
         }
     }
 
-    if (buffer->isNeutered()) {
+    if (buffer->isDetached()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
     if (args.length() > 1) {
         if (byteOffset > byteLength) {
             JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
             return false;
@@ -1355,17 +1355,17 @@ DataViewObject::read(JSContext* cx, Hand
     }
 
     uint32_t offset;
     if (!ToUint32(cx, args[0], &offset))
         return false;
 
     bool fromLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
 
-    if (obj->arrayBuffer().isNeutered()) {
+    if (obj->arrayBuffer().isDetached()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
     uint8_t* data = DataViewObject::getDataPointer<NativeType>(cx, obj, offset);
     if (!data)
         return false;
 
@@ -1421,17 +1421,17 @@ DataViewObject::write(JSContext* cx, Han
         return false;
 
     NativeType value;
     if (!WebIDLCast(cx, args[1], &value))
         return false;
 
     bool toLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
 
-    if (obj->arrayBuffer().isNeutered()) {
+    if (obj->arrayBuffer().isDetached()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
     uint8_t* data = DataViewObject::getDataPointer<NativeType>(cx, obj, offset);
     if (!data)
         return false;
 
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -202,18 +202,28 @@ class TypedArrayObject : public NativeOb
         // raw pointer escape untagged into C++ code.
         initPrivate(viewData.unwrap(/*safe - see above*/));
     }
     void* viewDataUnshared() const {
         MOZ_ASSERT(!isSharedMemory());
         return viewDataEither_();
     }
 
-    bool isNeutered() const {
-        return !isSharedMemory() && bufferUnshared() && bufferUnshared()->isNeutered();
+    bool hasDetachedBuffer() const {
+        // Shared buffers can't be detached.
+        if (isSharedMemory())
+            return false;
+
+        // A typed array with a null buffer has never had its buffer exposed to
+        // become detached.
+        ArrayBufferObject* buffer = bufferUnshared();
+        if (!buffer)
+            return false;
+
+        return buffer->isDetached();
     }
 
   private:
     void* viewDataEither_() const {
         // Note, do not check whether shared or not
         // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
         return static_cast<void*>(getPrivate(DATA_SLOT));
     }