Backed out 5 changesets (bug 861925) so I can backout bug 900669 cleanly
authorWes Kocher <wkocher@mozilla.com>
Tue, 15 Oct 2013 18:51:50 -0700
changeset 164674 d0fa5c45cabf3653f4587a8b499005705ee62c50
parent 164673 da7c23b2d1c7e3bd07eba75d2c088a9fa9369789
child 164675 65262f9e75805837dfd57119c8ac8099e8606fcc
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs861925, 900669
milestone27.0a1
backs out8febf2f0e35dcc341b8acea6ae882a338144cc72
e646195f32aea58681eb93eef3fe4dcc99579354
015a92e94c0713bdf60dc4b6e0a62699882c3b2f
4546406915c1888356caac095999d46bb4d9e8cf
63321a464309937658f29bbb0be94498f1f8c261
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
Backed out 5 changesets (bug 861925) so I can backout bug 900669 cleanly Backed out changeset 8febf2f0e35d (bug 861925) Backed out changeset e646195f32ae (bug 861925) Backed out changeset 015a92e94c07 (bug 861925) Backed out changeset 4546406915c1 (bug 861925) Backed out changeset 63321a464309 (bug 861925)
js/public/StructuredClone.h
js/src/builtin/TestingFunctions.cpp
js/src/builtin/TestingFunctions.h
js/src/js.msg
js/src/jsapi.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/shell/js.cpp
js/src/tests/js1_8_5/extensions/clone-forge.js
js/src/tests/js1_8_5/extensions/clone-object.js
js/src/tests/js1_8_5/extensions/clone-transferables.js
js/src/tests/js1_8_5/extensions/clone-v1-typed-array-data.dat
js/src/tests/js1_8_5/extensions/clone-v1-typed-array.js
js/src/tests/js1_8_5/extensions/shell.js
js/src/vm/StructuredClone.cpp
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -43,19 +43,17 @@ typedef JSObject *(*ReadStructuredCloneO
 typedef bool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w,
                                          JS::Handle<JSObject*> obj, void *closure);
 
 // This is called when JS_WriteStructuredClone is given an invalid transferable.
 // To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
 // with error set to one of the JS_SCERR_* values.
 typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid);
 
-// The maximum supported structured-clone serialization format version. Note
-// that this does not need to be bumped for Transferable-only changes, since
-// they are never saved to persistent storage.
+// The maximum supported structured-clone serialization format version.
 #define JS_STRUCTURED_CLONE_VERSION 2
 
 struct JSStructuredCloneCallbacks {
     ReadStructuredCloneOp read;
     WriteStructuredCloneOp write;
     StructuredCloneErrorOp reportError;
 };
 
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -13,33 +13,28 @@
 #include "jsobj.h"
 #ifndef JS_MORE_DETERMINISTIC
 #include "jsprf.h"
 #endif
 #include "jswrapper.h"
 
 #include "jit/AsmJS.h"
 #include "jit/AsmJSLink.h"
-#include "js/StructuredClone.h"
 #include "vm/ForkJoin.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/ProxyObject.h"
 
 #include "jscntxtinlines.h"
 
 using namespace js;
 using namespace JS;
 
 using mozilla::ArrayLength;
 
-// If fuzzingSafe is set, remove functionality that could cause problems with
-// fuzzers. Set this via the environment variable MOZ_FUZZING_SAFE.
-static bool fuzzingSafe = false;
-
 static bool
 GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
 {
     RootedObject info(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
     if (!info)
         return false;
     RootedValue value(cx);
 
@@ -1091,238 +1086,16 @@ static bool
 SetIonAssertGraphCoherency(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     jit::js_IonOptions.assertGraphConsistency = ToBoolean(args.get(0));
     args.rval().setUndefined();
     return true;
 }
 
-class CloneBufferObject : public JSObject {
-    static const JSPropertySpec props_[2];
-    static const size_t DATA_SLOT   = 0;
-    static const size_t LENGTH_SLOT = 1;
-    static const size_t NUM_SLOTS   = 2;
-
-  public:
-    static const Class class_;
-
-    static CloneBufferObject *Create(JSContext *cx) {
-        RootedObject obj(cx, JS_NewObject(cx, Jsvalify(&class_), nullptr, nullptr));
-        if (!obj)
-            return nullptr;
-        obj->setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
-        obj->setReservedSlot(LENGTH_SLOT, Int32Value(0));
-
-        if (!JS_DefineProperties(cx, obj, props_))
-            return nullptr;
-
-        return &obj->as<CloneBufferObject>();
-    }
-
-    static CloneBufferObject *Create(JSContext *cx, JSAutoStructuredCloneBuffer *buffer) {
-        Rooted<CloneBufferObject*> obj(cx, Create(cx));
-        if (!obj)
-            return nullptr;
-        uint64_t *datap;
-        size_t nbytes;
-        buffer->steal(&datap, &nbytes);
-        obj->setData(datap);
-        obj->setNBytes(nbytes);
-        return obj;
-    }
-
-    uint64_t *data() const {
-        return static_cast<uint64_t*>(getReservedSlot(0).toPrivate());
-    }
-
-    void setData(uint64_t *aData) {
-        JS_ASSERT(!data());
-        setReservedSlot(DATA_SLOT, PrivateValue(aData));
-    }
-
-    size_t nbytes() const {
-        return getReservedSlot(LENGTH_SLOT).toInt32();
-    }
-
-    void setNBytes(size_t nbytes) {
-        JS_ASSERT(nbytes <= UINT32_MAX);
-        setReservedSlot(LENGTH_SLOT, Int32Value(nbytes));
-    }
-
-    // Discard an owned clone buffer.
-    void discard() {
-        if (data())
-            JS_ClearStructuredClone(data(), nbytes());
-        setReservedSlot(DATA_SLOT, PrivateValue(nullptr));
-    }
-
-    static bool
-    setCloneBuffer_impl(JSContext* cx, CallArgs args) {
-        if (args.length() != 1 || !args[0].isString()) {
-            JS_ReportError(cx,
-                           "the first argument argument must be maxBytes, "
-                           "maxMallocBytes, gcStackpoolLifespan, gcBytes or "
-                           "gcNumber");
-            JS_ReportError(cx, "clonebuffer setter requires a single string argument");
-            return false;
-        }
-
-        if (fuzzingSafe) {
-            // A manually-created clonebuffer could easily trigger a crash
-            args.rval().setUndefined();
-            return true;
-        }
-
-        Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
-        obj->discard();
-
-        char *str = JS_EncodeString(cx, args[0].toString());
-        if (!str)
-            return false;
-        obj->setData(reinterpret_cast<uint64_t*>(str));
-        obj->setNBytes(JS_GetStringLength(args[0].toString()));
-
-        args.rval().setUndefined();
-        return true;
-    }
-
-    static bool
-    is(HandleValue v) {
-        return v.isObject() && v.toObject().is<CloneBufferObject>();
-    }
-
-    static bool
-    setCloneBuffer(JSContext* cx, unsigned int argc, JS::Value* vp) {
-        CallArgs args = CallArgsFromVp(argc, vp);
-        return CallNonGenericMethod<is, setCloneBuffer_impl>(cx, args);
-    }
-
-    static bool
-    getCloneBuffer_impl(JSContext* cx, CallArgs args) {
-        Rooted<CloneBufferObject*> obj(cx, &args.thisv().toObject().as<CloneBufferObject>());
-        JS_ASSERT(args.length() == 0);
-
-        if (!obj->data()) {
-            args.rval().setUndefined();
-            return true;
-        }
-
-        bool hasTransferable;
-        if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
-            return false;
-
-        if (hasTransferable) {
-            JS_ReportError(cx, "cannot retrieve structured clone buffer with transferables");
-            return false;
-        }
-
-        JSString *str = JS_NewStringCopyN(cx, reinterpret_cast<char*>(obj->data()), obj->nbytes());
-        if (!str)
-            return false;
-        args.rval().setString(str);
-        return true;
-    }
-
-    static bool
-    getCloneBuffer(JSContext* cx, unsigned int argc, JS::Value* vp) {
-        CallArgs args = CallArgsFromVp(argc, vp);
-        return CallNonGenericMethod<is, getCloneBuffer_impl>(cx, args);
-    }
-
-    static void Finalize(FreeOp *fop, JSObject *obj) {
-        obj->as<CloneBufferObject>().discard();
-    }
-};
-
-const Class CloneBufferObject::class_ = {
-    "CloneBuffer", JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS),
-    JS_PropertyStub,       /* addProperty */
-    JS_DeletePropertyStub, /* delProperty */
-    JS_PropertyStub,       /* getProperty */
-    JS_StrictPropertyStub, /* setProperty */
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    Finalize,
-    nullptr,                  /* checkAccess */
-    nullptr,                  /* call */
-    nullptr,                  /* hasInstance */
-    nullptr,                  /* construct */
-    nullptr,                  /* trace */
-    JS_NULL_CLASS_EXT,
-    JS_NULL_OBJECT_OPS
-};
-
-const JSPropertySpec CloneBufferObject::props_[] = {
-    JS_PSGS("clonebuffer", getCloneBuffer, setCloneBuffer, 0),
-    JS_PS_END
-};
-
-static bool
-Serialize(JSContext *cx, unsigned argc, jsval *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    Value v = args.length() > 0 ? args[0] : UndefinedValue();
-    Value transferables = args.length() > 1 ? args[1] : UndefinedValue();
-
-    JSAutoStructuredCloneBuffer clonebuf;
-    if (!clonebuf.write(cx, v, transferables))
-        return false;
-
-    RootedObject obj(cx, CloneBufferObject::Create(cx, &clonebuf));
-    if (!obj)
-        return false;
-
-    args.rval().setObject(*obj);
-    return true;
-}
-
-static bool
-Deserialize(JSContext *cx, unsigned argc, jsval *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-
-    if (args.length() != 1 || !args[0].isObject()) {
-        JS_ReportError(cx, "deserialize requires a single clonebuffer argument");
-        return false;
-    }
-
-    if (!args[0].toObject().is<CloneBufferObject>()) {
-        JS_ReportError(cx, "deserialize requires a clonebuffer");
-        return false;
-    }
-
-    Rooted<CloneBufferObject*> obj(cx, &args[0].toObject().as<CloneBufferObject>());
-
-    // Clone buffer was already consumed?
-    if (!obj->data()) {
-        JS_ReportError(cx, "deserialize given invalid clone buffer "
-                       "(transferables already consumed?)");
-        return false;
-    }
-
-    bool hasTransferable;
-    if (!JS_StructuredCloneHasTransferables(obj->data(), obj->nbytes(), &hasTransferable))
-        return false;
-
-    RootedValue deserialized(cx);
-    if (!JS_ReadStructuredClone(cx, obj->data(), obj->nbytes(),
-                                JS_STRUCTURED_CLONE_VERSION, deserialized.address(), NULL, NULL)) {
-        return false;
-    }
-    args.rval().set(deserialized);
-
-    if (hasTransferable)
-        obj->discard();
-
-    return true;
-}
-
 static const JSFunctionSpecWithHelp TestingFunctions[] = {
     JS_FN_HELP("gc", ::GC, 0, 0,
 "gc([obj] | 'compartment')",
 "  Run the garbage collector. When obj is given, GC only its compartment.\n"
 "  If 'compartment' is given, GC any compartments that were scheduled for\n"
 "  GC via schedulegc."),
 
     JS_FN_HELP("minorgc", ::MinorGC, 0, 0,
@@ -1518,28 +1291,16 @@ static const JSFunctionSpecWithHelp Test
 "  Set a compiler option indexed in JSCompileOption enum to a number.\n"),
 
     JS_FN_HELP("setIonAssertGraphCoherency", SetIonAssertGraphCoherency, 1, 0,
 "setIonAssertGraphCoherency(bool)",
 "  Set whether Ion should perform graph consistency (DEBUG-only) assertions. These assertions\n"
 "  are valuable and should be generally enabled, however they can be very expensive for large\n"
 "  (asm.js) programs."),
 
-    JS_FN_HELP("serialize", Serialize, 1, 0,
-"serialize(data, [transferables])",
-"  Serialize 'data' using JS_WriteStructuredClone. Returns a structured\n"
-"  clone buffer object."),
-
-    JS_FN_HELP("deserialize", Deserialize, 1, 0,
-"deserialize(clonebuffer)",
-"  Deserialize data generated by serialize."),
-
     JS_FS_HELP_END
 };
 
 bool
-js::DefineTestingFunctions(JSContext *cx, HandleObject obj, bool fuzzingSafe_)
+js::DefineTestingFunctions(JSContext *cx, HandleObject obj)
 {
-    fuzzingSafe = fuzzingSafe_;
-    if (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0')
-        fuzzingSafe = true;
     return JS_DefineFunctionsWithHelp(cx, obj, TestingFunctions);
 }
--- a/js/src/builtin/TestingFunctions.h
+++ b/js/src/builtin/TestingFunctions.h
@@ -7,17 +7,17 @@
 #ifndef builtin_TestingFunctions_h
 #define builtin_TestingFunctions_h
 
 #include "NamespaceImports.h"
 
 namespace js {
 
 bool
-DefineTestingFunctions(JSContext *cx, HandleObject obj, bool fuzzingSafe);
+DefineTestingFunctions(JSContext *cx, HandleObject obj);
 
 bool
 testingFunc_inParallelSection(JSContext *cx, unsigned argc, Value *vp);
 
 bool
 testingFunc_bailout(JSContext *cx, unsigned argc, Value *vp);
 
 bool
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -228,18 +228,18 @@ MSG_DEF(JSMSG_UNUSED174,              17
 MSG_DEF(JSMSG_NESTING_GENERATOR,      175, 0, JSEXN_TYPEERR, "already executing generator")
 MSG_DEF(JSMSG_UNUSED176,              176, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED177,              177, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED178,              178, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED179,              179, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED180,              180, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED181,              181, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_BAD_GENERATOR_SEND,     182, 1, JSEXN_TYPEERR, "attempt to send {0} to newborn generator")
-MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE,    183, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone")
-MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE,    184, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone")
+MSG_DEF(JSMSG_UNUSED183,              183, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_UNUSED184,              184, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 185, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
 MSG_DEF(JSMSG_UNUSED186,              186, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED187,              187, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,    188, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
 MSG_DEF(JSMSG_UNUSED189,              189, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED190,              190, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED191,              191, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED192,              192, 0, JSEXN_NONE, "")
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -219,39 +219,32 @@ class AutoArrayRooter : private AutoGCRo
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     js::SkipRoot skip;
 };
 
 template<class T>
 class AutoVectorRooter : protected AutoGCRooter
 {
-    typedef js::Vector<T, 8> VectorImpl;
-    VectorImpl vector;
-
-    /* Prevent overwriting of inline elements in vector. */
-    js::SkipRoot vectorRoot;
-
   public:
     explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag
                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     explicit AutoVectorRooter(js::ContextFriendFields *cx, ptrdiff_t tag
                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     typedef T ElementType;
-    typedef typename VectorImpl::Range Range;
 
     size_t length() const { return vector.length(); }
     bool empty() const { return vector.empty(); }
 
     bool append(const T &v) { return vector.append(v); }
     bool appendAll(const AutoVectorRooter<T> &other) {
         return vector.appendAll(other.vector);
     }
@@ -301,29 +294,33 @@ class AutoVectorRooter : protected AutoG
     }
 
     const T *begin() const { return vector.begin(); }
     T *begin() { return vector.begin(); }
 
     const T *end() const { return vector.end(); }
     T *end() { return vector.end(); }
 
-    Range all() { return vector.all(); }
-
     const T &back() const { return vector.back(); }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
   private:
     void makeRangeGCSafe(size_t oldLength) {
         T *t = vector.begin() + oldLength;
         for (size_t i = oldLength; i < vector.length(); ++i, ++t)
             memset(t, 0, sizeof(T));
     }
 
+    typedef js::Vector<T, 8> VectorImpl;
+    VectorImpl vector;
+
+    /* Prevent overwriting of inline elements in vector. */
+    js::SkipRoot vectorRoot;
+
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 template<class Key, class Value>
 class AutoHashMapRooter : protected AutoGCRooter
 {
   private:
     typedef js::HashMap<Key, Value> HashMapImpl;
@@ -333,17 +330,16 @@ class AutoHashMapRooter : protected Auto
                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, tag), map(cx)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     typedef Key KeyType;
     typedef Value ValueType;
-    typedef typename HashMapImpl::Entry Entry;
     typedef typename HashMapImpl::Lookup Lookup;
     typedef typename HashMapImpl::Ptr Ptr;
     typedef typename HashMapImpl::AddPtr AddPtr;
 
     bool init(uint32_t len = 16) {
         return map.init(len);
     }
     bool initialized() const {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1013,17 +1013,17 @@ JS::ObjectPtr::trace(JSTracer *trc, cons
 
 JS_FRIEND_API(JSObject *)
 js::GetTestingFunctions(JSContext *cx)
 {
     RootedObject obj(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
     if (!obj)
         return nullptr;
 
-    if (!DefineTestingFunctions(cx, obj, false))
+    if (!DefineTestingFunctions(cx, obj))
         return nullptr;
 
     return obj;
 }
 
 #ifdef DEBUG
 JS_FRIEND_API(unsigned)
 js::GetEnterCompartmentDepth(JSContext *cx)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1236,22 +1236,16 @@ JS_GetArrayBufferViewData(JSObject *obj)
  * Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
  * neutered, this will still return the neutered buffer. |obj| must be an
  * object that would return true for JS_IsArrayBufferViewObject().
  */
 extern JS_FRIEND_API(JSObject *)
 JS_GetArrayBufferViewBuffer(JSObject *obj);
 
 /*
- * Set an ArrayBuffer's length to 0 and neuter all of its views.
- */
-extern JS_FRIEND_API(void)
-JS_NeuterArrayBuffer(JSObject *obj, JSContext *cx);
-
-/*
  * Check whether obj supports JS_GetDataView* APIs.
  */
 JS_FRIEND_API(bool)
 JS_IsDataViewObject(JSObject *obj);
 
 /*
  * Return the byte offset of a data view into its array buffer. |obj| must be a
  * DataView.
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3828,16 +3828,66 @@ WrapWithProto(JSContext *cx, unsigned ar
                                      &Wrapper::singletonWithPrototype);
     if (!wrapped)
         return false;
 
     JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(wrapped));
     return true;
 }
 
+static bool
+Serialize(JSContext *cx, unsigned argc, jsval *vp)
+{
+    jsval v = argc > 0 ? JS_ARGV(cx, vp)[0] : UndefinedValue();
+    uint64_t *datap;
+    size_t nbytes;
+    if (!JS_WriteStructuredClone(cx, v, &datap, &nbytes, nullptr, nullptr, UndefinedValue()))
+        return false;
+
+    JSObject *obj = JS_NewUint8Array(cx, nbytes);
+    if (!obj) {
+        JS_free(cx, datap);
+        return false;
+    }
+    TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
+    JS_ASSERT((uintptr_t(tarr->viewData()) & 7) == 0);
+    js_memcpy(tarr->viewData(), datap, nbytes);
+
+    JS_ClearStructuredClone(datap, nbytes);
+    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(tarr));
+    return true;
+}
+
+static bool
+Deserialize(JSContext *cx, unsigned argc, jsval *vp)
+{
+    Rooted<jsval> v(cx, argc > 0 ? JS_ARGV(cx, vp)[0] : UndefinedValue());
+    JSObject *obj;
+    if (JSVAL_IS_PRIMITIVE(v) || !(obj = JSVAL_TO_OBJECT(v))->is<TypedArrayObject>()) {
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "deserialize");
+        return false;
+    }
+    TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
+    if ((tarr->byteLength() & 7) != 0) {
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "deserialize");
+        return false;
+    }
+    if ((uintptr_t(tarr->viewData()) & 7) != 0) {
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_BAD_ALIGNMENT);
+        return false;
+    }
+
+    if (!JS_ReadStructuredClone(cx, (uint64_t *) tarr->viewData(), tarr->byteLength(),
+                                JS_STRUCTURED_CLONE_VERSION, v.address(), nullptr, nullptr)) {
+        return false;
+    }
+    JS_SET_RVAL(cx, vp, v);
+    return true;
+}
+
 static JSObject *
 NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options);
 
 static bool
 NewGlobal(JSContext *cx, unsigned argc, jsval *vp)
 {
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
@@ -4304,16 +4354,24 @@ static const JSFunctionSpecWithHelp shel
     JS_FN_HELP("wrap", Wrap, 1, 0,
 "wrap(obj)",
 "  Wrap an object into a noop wrapper."),
 
     JS_FN_HELP("wrapWithProto", WrapWithProto, 2, 0,
 "wrapWithProto(obj)",
 "  Wrap an object into a noop wrapper with prototype semantics."),
 
+    JS_FN_HELP("serialize", Serialize, 1, 0,
+"serialize(sd)",
+"  Serialize sd using JS_WriteStructuredClone. Returns a TypedArray."),
+
+    JS_FN_HELP("deserialize", Deserialize, 1, 0,
+"deserialize(a)",
+"  Deserialize data generated by serialize."),
+
     JS_FN_HELP("newGlobal", NewGlobal, 1, 0,
 "newGlobal([options])",
 "  Return a new global object in a new compartment. If options\n"
 "  is given, it may have any of the following properties:\n"
 "      sameZoneAs: the compartment will be in the same zone as the given object (defaults to a new zone)\n"
 "      invisibleToDebugger: the global will be invisible to the debugger (default false)"),
 
     JS_FN_HELP("enableStackWalkingAssertion", EnableStackWalkingAssertion, 1, 0,
@@ -5331,17 +5389,17 @@ NewGlobalObject(JSContext *cx, JS::Compa
             return nullptr;
         if (!JS::RegisterPerfMeasurement(cx, glob))
             return nullptr;
         if (!JS_DefineFunctionsWithHelp(cx, glob, shell_functions) ||
             !JS_DefineProfilingFunctions(cx, glob))
         {
             return nullptr;
         }
-        if (!js::DefineTestingFunctions(cx, glob, fuzzingSafe))
+        if (!js::DefineTestingFunctions(cx, glob))
             return nullptr;
 
         if (!fuzzingSafe && !JS_DefineFunctionsWithHelp(cx, glob, fuzzing_unsafe_functions))
             return nullptr;
 
         /* Initialize FakeDOMObject. */
         static const js::DOMCallbacks DOMcallbacks = {
             InstanceClassHasProtoAtDepth
@@ -5636,18 +5694,16 @@ Shell(JSContext *cx, OptionParser *op, c
      */
     if (op->getBoolOption("no-ti")) {
         enableTypeInference = false;
         ContextOptionsRef(cx).toggleTypeInference();
     }
 
     if (op->getBoolOption("fuzzing-safe"))
         fuzzingSafe = true;
-    else
-        fuzzingSafe = (getenv("MOZ_FUZZING_SAFE") && getenv("MOZ_FUZZING_SAFE")[0] != '0');
 
     RootedObject glob(cx);
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
     glob = NewGlobalObject(cx, options);
     if (!glob)
         return 1;
 
--- a/js/src/tests/js1_8_5/extensions/clone-forge.js
+++ b/js/src/tests/js1_8_5/extensions/clone-forge.js
@@ -9,31 +9,24 @@ function assertThrows(f) {
         f();
     } catch (exc) {
         ok = true;
     }
     if (!ok)
         throw new TypeError("Assertion failed: " + f + " did not throw as expected");
 }
 
-function byteArray(str) {
-    return [ c.charCodeAt(0) for (c of str.split('')) ];
-}
-
 // Don't allow forging bogus Date objects.
-var mutated = byteArray(serialize(new Date(NaN)).clonebuffer);
-
+var buf = serialize(new Date(NaN));
 var a = [1/0, -1/0,
          Number.MIN_VALUE, -Number.MIN_VALUE,
          Math.PI, 1286523948674.5,
          Number.MAX_VALUE, -Number.MAX_VALUE,
          8.64e15 + 1, -(8.64e15 + 1)];
 for (var i = 0; i < a.length; i++) {
     var n = a[i];
     var nbuf = serialize(n);
-    var data = byteArray(nbuf.clonebuffer);
     for (var j = 0; j < 8; j++)
-      mutated[j+8] = data[j];
-    nbuf.clonebuffer = String.fromCharCode.apply(null, mutated);
-    assertThrows(function () { deserialize(nbuf); });
+        buf[j + 8] = nbuf[j];
+    assertThrows(function () { deserialize(buf); });
 }
 
 reportCompare(0, 0);
--- a/js/src/tests/js1_8_5/extensions/clone-object.js
+++ b/js/src/tests/js1_8_5/extensions/clone-object.js
@@ -203,17 +203,17 @@ function test() {
 
     // Clone an array with holes.
     check([0, 1, 2, , 4, 5, 6]);
 
     // Array holes should not take up space.
     b = [];
     b[255] = 1;
     check(b);
-    assertEq(serialize(b).clonebuffer.length < 255, true);
+    assertEq(serialize(b).length < 255, true);
 
     // Self-modifying object.
     // This should never read through to b's prototype.
     b = Object.create({y: 2}, 
                       {x: {enumerable: true,
                            configurable: true,
                            get: function() { if (this.hasOwnProperty("y")) delete this.y; return 1; }},
                        y: {enumerable: true,
deleted file mode 100644
--- a/js/src/tests/js1_8_5/extensions/clone-transferables.js
+++ /dev/null
@@ -1,87 +0,0 @@
-// |reftest| skip-if(!xulRuntime.shell)
-// Any copyright is dedicated to the Public Domain.
-// http://creativecommons.org/licenses/publicdomain/
-
-function test() {
-    // Note: -8 and -200 will trigger asm.js link failures because 8 and 200
-    // bytes are below the minimum allowed size, and the buffer will not
-    // actually be converted to an asm.js buffer.
-    for (var size of [0, 8, 16, 200, 1000, 4096, -8, -200, -8192, -65536]) {
-        var buffer_ctor = (size < 0) ? AsmJSArrayBuffer : ArrayBuffer;
-        size = Math.abs(size);
-
-        var old = buffer_ctor(size);
-        var copy = deserialize(serialize(old, [old]));
-        assertEq(old.byteLength, 0);
-        assertEq(copy.byteLength, size);
-
-        var constructors = [ Int8Array,
-                             Uint8Array,
-                             Int16Array,
-                             Uint16Array,
-                             Int32Array,
-                             Uint32Array,
-                             Float32Array,
-                             Float64Array,
-                             Uint8ClampedArray ];
-
-        for (var ctor of constructors) {
-            var buf = buffer_ctor(size);
-            var old_arr = ctor(buf);
-            assertEq(buf.byteLength, size);
-            assertEq(buf, old_arr.buffer);
-            assertEq(old_arr.length, size / old_arr.BYTES_PER_ELEMENT);
-
-            var copy_arr = deserialize(serialize(old_arr, [ buf ]));
-            assertEq(buf.byteLength, 0, "donor array buffer should be neutered");
-            assertEq(old_arr.length, 0, "donor typed array should be neutered");
-            assertEq(copy_arr.buffer.byteLength == size, true);
-            assertEq(copy_arr.length, size / old_arr.BYTES_PER_ELEMENT);
-
-            buf = null;
-            old_arr = null;
-            gc(); // Tickle the ArrayBuffer -> view management
-        }
-
-        for (var ctor of constructors) {
-            var buf = buffer_ctor(size);
-            var old_arr = ctor(buf);
-            var dv = DataView(buf); // Second view
-            var copy_arr = deserialize(serialize(old_arr, [ buf ]));
-            assertEq(buf.byteLength, 0, "donor array buffer should be neutered");
-            assertEq(old_arr.length, 0, "donor typed array should be neutered");
-            assertEq(dv.byteLength, 0, "all views of donor array buffer should be neutered");
-
-            buf = null;
-            old_arr = null;
-            gc(); // Tickle the ArrayBuffer -> view management
-        }
-
-        // Mutate the buffer during the clone operation. The modifications should be visible.
-        if (size >= 4) {
-            old = buffer_ctor(size);
-            var view = Int32Array(old);
-            view[0] = 1;
-            var mutator = { get foo() { view[0] = 2; } };
-            var copy = deserialize(serialize([ old, mutator ], [old]));
-            var viewCopy = Int32Array(copy[0]);
-            assertEq(view.length, 0); // Neutered
-            assertEq(viewCopy[0], 2);
-        }
-
-        // Neuter the buffer during the clone operation. Should throw an exception.
-        if (size >= 4) {
-            old = buffer_ctor(size);
-            var mutator = {
-                get foo() {
-                    deserialize(serialize(old, [old]));
-                }
-            };
-            // The throw is not yet implemented, bug 919259.
-            //var copy = deserialize(serialize([ old, mutator ], [old]));
-        }
-    }
-}
-
-test();
-reportCompare(0, 0, 'ok');
--- a/js/src/tests/js1_8_5/extensions/clone-v1-typed-array-data.dat
+++ b/js/src/tests/js1_8_5/extensions/clone-v1-typed-array-data.dat
@@ -1,32 +1,32 @@
 var captured = [];
-captured[0] = serialize(0); captured[0].clonebuffer = String.fromCharCode(0, 0, 0, 0, 9, 0, 255, 255);
-captured[1] = serialize(0); captured[1].clonebuffer = String.fromCharCode(7, 0, 0, 0, 9, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0);
+captured[0] = new Uint8Array([0, 0, 0, 0, 9, 0, 255, 255]);
+captured[1] = new Uint8Array([7, 0, 0, 0, 9, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0]);
 captured[2] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[3] = serialize(0); captured[3].clonebuffer = String.fromCharCode(0, 0, 0, 0, 0, 1, 255, 255);
-captured[4] = serialize(0); captured[4].clonebuffer = String.fromCharCode(100, 0, 0, 0, 0, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+captured[3] = new Uint8Array([0, 0, 0, 0, 0, 1, 255, 255]);
+captured[4] = new Uint8Array([100, 0, 0, 0, 0, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 captured[5] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[6] = serialize(0); captured[6].clonebuffer = String.fromCharCode(0, 0, 0, 0, 1, 1, 255, 255);
-captured[7] = serialize(0); captured[7].clonebuffer = String.fromCharCode(100, 0, 0, 0, 1, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+captured[6] = new Uint8Array([0, 0, 0, 0, 1, 1, 255, 255]);
+captured[7] = new Uint8Array([100, 0, 0, 0, 1, 1, 255, 255, 1, 7, 49, 87, 97, 167, 145, 247, 193, 71, 241, 151, 33, 231, 81, 55, 129, 135, 177, 216, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 captured[8] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[9] = serialize(0); captured[9].clonebuffer = String.fromCharCode(0, 0, 0, 0, 2, 1, 255, 255);
-captured[10] = serialize(0); captured[10].clonebuffer = String.fromCharCode(100, 0, 0, 0, 2, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+captured[9] = new Uint8Array([0, 0, 0, 0, 2, 1, 255, 255]);
+captured[10] = new Uint8Array([100, 0, 0, 0, 2, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 captured[11] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[12] = serialize(0); captured[12].clonebuffer = String.fromCharCode(0, 0, 0, 0, 3, 1, 255, 255);
-captured[13] = serialize(0); captured[13].clonebuffer = String.fromCharCode(100, 0, 0, 0, 3, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+captured[12] = new Uint8Array([0, 0, 0, 0, 3, 1, 255, 255]);
+captured[13] = new Uint8Array([100, 0, 0, 0, 3, 1, 255, 255, 1, 0, 7, 0, 49, 0, 87, 1, 97, 9, 167, 65, 145, 203, 247, 144, 193, 246, 71, 191, 241, 58, 151, 156, 33, 72, 231, 248, 81, 206, 55, 164, 129, 125, 135, 110, 177, 5, 216, 39, 224, 22, 0, 160, 0, 96, 0, 160, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 captured[14] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[15] = serialize(0); captured[15].clonebuffer = String.fromCharCode(0, 0, 0, 0, 4, 1, 255, 255);
-captured[16] = serialize(0); captured[16].clonebuffer = String.fromCharCode(100, 0, 0, 0, 4, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+captured[15] = new Uint8Array([0, 0, 0, 0, 4, 1, 255, 255]);
+captured[16] = new Uint8Array([100, 0, 0, 0, 4, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 captured[17] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[18] = serialize(0); captured[18].clonebuffer = String.fromCharCode(0, 0, 0, 0, 5, 1, 255, 255);
-captured[19] = serialize(0); captured[19].clonebuffer = String.fromCharCode(100, 0, 0, 0, 5, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+captured[18] = new Uint8Array([0, 0, 0, 0, 5, 1, 255, 255]);
+captured[19] = new Uint8Array([100, 0, 0, 0, 5, 1, 255, 255, 1, 0, 0, 0, 7, 0, 0, 0, 49, 0, 0, 0, 87, 1, 0, 0, 97, 9, 0, 0, 167, 65, 0, 0, 145, 203, 1, 0, 247, 144, 12, 0, 193, 246, 87, 0, 71, 191, 103, 2, 241, 58, 214, 16, 151, 156, 219, 117, 33, 72, 1, 57, 231, 248, 8, 143, 81, 206, 62, 233, 55, 164, 183, 96, 129, 125, 5, 165, 135, 110, 38, 131, 177, 5, 13, 150, 216, 39, 91, 26, 224, 22, 126, 184, 0, 160, 114, 11, 0, 96, 34, 80, 0, 160, 240, 48, 0, 128, 148, 86, 0, 0, 16, 94, 0, 0, 112, 146, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
 captured[20] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[21] = serialize(0); captured[21].clonebuffer = String.fromCharCode(0, 0, 0, 0, 6, 1, 255, 255);
-captured[22] = serialize(0); captured[22].clonebuffer = String.fromCharCode(100, 0, 0, 0, 6, 1, 255, 255, 0, 0, 128, 63, 0, 0, 224, 64, 0, 0, 68, 66, 0, 128, 171, 67, 0, 16, 22, 69, 0, 78, 131, 70, 128, 200, 229, 71, 112, 15, 73, 73, 130, 237, 175, 74, 210, 239, 25, 76, 216, 177, 134, 77, 57, 183, 235, 78, 82, 64, 78, 80, 72, 120, 180, 81, 63, 233, 29, 83, 23, 44, 138, 84, 40, 205, 241, 85, 131, 147, 83, 87, 19, 33, 185, 88, 240, 252, 33, 90, 82, 189, 141, 91, 80, 11, 248, 92, 230, 9, 89, 94, 169, 232, 189, 95, 148, 43, 38, 97, 34, 102, 145, 98, 187, 114, 254, 99, 100, 164, 94, 101, 215, 207, 194, 102, 220, 117, 42, 104, 33, 39, 149, 105, 61, 130, 2, 107, 234, 99, 100, 108, 109, 215, 199, 109, 127, 220, 46, 111, 239, 0, 153, 112, 209, 224, 5, 114, 110, 73, 106, 115, 65, 0, 205, 116, 57, 96, 51, 118, 49, 244, 156, 119, 171, 85, 9, 121, 236, 85, 112, 122, 46, 75, 210, 123, 200, 1, 56, 125, 143, 1, 161, 126, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 192, 127);
+captured[21] = new Uint8Array([0, 0, 0, 0, 6, 1, 255, 255]);
+captured[22] = new Uint8Array([100, 0, 0, 0, 6, 1, 255, 255, 0, 0, 128, 63, 0, 0, 224, 64, 0, 0, 68, 66, 0, 128, 171, 67, 0, 16, 22, 69, 0, 78, 131, 70, 128, 200, 229, 71, 112, 15, 73, 73, 130, 237, 175, 74, 210, 239, 25, 76, 216, 177, 134, 77, 57, 183, 235, 78, 82, 64, 78, 80, 72, 120, 180, 81, 63, 233, 29, 83, 23, 44, 138, 84, 40, 205, 241, 85, 131, 147, 83, 87, 19, 33, 185, 88, 240, 252, 33, 90, 82, 189, 141, 91, 80, 11, 248, 92, 230, 9, 89, 94, 169, 232, 189, 95, 148, 43, 38, 97, 34, 102, 145, 98, 187, 114, 254, 99, 100, 164, 94, 101, 215, 207, 194, 102, 220, 117, 42, 104, 33, 39, 149, 105, 61, 130, 2, 107, 234, 99, 100, 108, 109, 215, 199, 109, 127, 220, 46, 111, 239, 0, 153, 112, 209, 224, 5, 114, 110, 73, 106, 115, 65, 0, 205, 116, 57, 96, 51, 118, 49, 244, 156, 119, 171, 85, 9, 121, 236, 85, 112, 122, 46, 75, 210, 123, 200, 1, 56, 125, 143, 1, 161, 126, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 128, 127, 0, 0, 192, 127]);
 captured[23] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[24] = serialize(0); captured[24].clonebuffer = String.fromCharCode(0, 0, 0, 0, 7, 1, 255, 255);
-captured[25] = serialize(0); captured[25].clonebuffer = String.fromCharCode(100, 0, 0, 0, 7, 1, 255, 255, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 28, 64, 0, 0, 0, 0, 0, 128, 72, 64, 0, 0, 0, 0, 0, 112, 117, 64, 0, 0, 0, 0, 0, 194, 162, 64, 0, 0, 0, 0, 192, 105, 208, 64, 0, 0, 0, 0, 16, 185, 252, 64, 0, 0, 0, 0, 238, 33, 41, 65, 0, 0, 0, 64, 176, 253, 85, 65, 0, 0, 0, 56, 250, 61, 131, 65, 0, 0, 0, 241, 58, 214, 176, 65, 0, 0, 192, 37, 231, 118, 221, 65, 0, 0, 8, 65, 10, 200, 9, 66, 0, 0, 231, 248, 8, 143, 54, 66, 0, 32, 202, 217, 39, 189, 99, 66, 0, 220, 144, 222, 130, 69, 145, 66, 0, 129, 125, 5, 165, 57, 190, 66, 224, 208, 205, 100, 112, 114, 234, 66, 196, 22, 52, 88, 34, 36, 23, 67, 236, 147, 45, 13, 158, 63, 68, 67, 110, 225, 135, 75, 170, 183, 113, 67, 128, 202, 45, 4, 106, 1, 159, 67, 48, 17, 168, 195, 60, 33, 203, 67, 10, 15, 51, 43, 21, 189, 247, 67, 41, 173, 204, 133, 114, 197, 36, 68, 132, 23, 19, 53, 196, 44, 82, 68, 39, 105, 225, 92, 87, 206, 127, 68, 2, 60, 69, 113, 140, 212, 171, 68, 130, 148, 28, 227, 250, 89, 216, 68, 242, 1, 185, 134, 187, 78, 5, 69, 180, 225, 225, 21, 228, 164, 50, 69, 126, 165, 37, 147, 71, 80, 96, 69, 156, 225, 129, 65, 125, 140, 140, 69, 104, 165, 81, 153, 237, 250, 184, 69, 187, 112, 39, 230, 143, 219, 229, 69, 164, 130, 98, 233, 29, 32, 19, 70, 80, 50, 54, 44, 26, 188, 64, 70, 12, 216, 94, 205, 45, 73, 109, 70, 10, 253, 178, 19, 8, 160, 153, 70, 105, 157, 60, 17, 7, 108, 198, 70, 188, 9, 21, 47, 134, 158, 243, 70, 132, 104, 50, 105, 181, 42, 33, 71, 231, 54, 24, 120, 189, 10, 78, 71, 10, 48, 21, 201, 101, 73, 122, 71, 9, 138, 242, 15, 57, 0, 167, 71, 200, 56, 244, 237, 49, 32, 212, 71, 175, 177, 53, 176, 43, 156, 1, 72, 242, 246, 93, 116, 76, 209, 46, 72, 20, 56, 210, 229, 34, 247, 90, 72, 18, 241, 23, 137, 62, 152, 135, 72, 240, 242, 244, 183, 54, 165, 180, 72, 146, 84, 246, 224, 143, 16, 226, 72, 0, 20, 175, 201, 251, 156, 15, 73, 128, 49, 121, 80, 92, 169, 59, 73, 80, 11, 106, 198, 48, 52, 104, 73, 230, 201, 156, 173, 170, 45, 149, 73, 169, 48, 233, 87, 245, 135, 194, 73, 148, 10, 236, 172, 246, 54, 240, 73, 131, 18, 157, 174, 47, 96, 28, 74, 51, 112, 201, 184, 41, 212, 72, 74, 45, 66, 176, 129, 164, 185, 117, 74, 231, 57, 122, 241, 111, 2, 163, 74, 170, 242, 74, 243, 33, 162, 208, 74, 170, 40, 195, 105, 187, 27, 253, 74, 149, 195, 138, 252, 67, 120, 41, 75, 34, 107, 249, 124, 59, 73, 86, 75, 190, 61, 90, 13, 20, 128, 131, 75, 6, 246, 174, 139, 17, 16, 177, 75, 138, 46, 114, 180, 30, 220, 221, 75, 185, 232, 227, 221, 154, 32, 10, 76, 162, 107, 39, 130, 135, 220, 54, 76, 46, 126, 226, 145, 246, 0, 100, 76, 104, 46, 166, 191, 215, 128, 145, 76, 54, 209, 98, 143, 121, 161, 190, 76, 15, 119, 118, 93, 74, 205, 234, 76, 45, 168, 199, 17, 161, 115, 23, 77, 39, 179, 142, 239, 44, 133, 68, 77, 194, 220, 156, 81, 135, 244, 113, 77, 84, 130, 210, 206, 236, 107, 159, 77, 10, 50, 248, 52, 111, 126, 203, 77, 201, 43, 89, 78, 161, 14, 248, 77, 80, 6, 142, 36, 205, 12, 37, 78, 134, 69, 252, 127, 51, 107, 82, 78, 213, 188, 252, 15, 205, 29, 128, 78, 117, 74, 250, 219, 38, 52, 172, 78, 38, 1, 123, 0, 162, 173, 216, 78, 1, 161, 107, 192, 237, 151, 5, 79, 225, 44, 94, 8, 240, 228, 50, 79, 69, 103, 82, 7, 82, 136, 96, 79, 185, 52, 208, 140, 143, 238, 140, 79, 34, 46, 54, 155, 189, 80, 185, 79, 94, 104, 207, 231, 165, 38, 230, 79, 82, 123, 213, 42, 209, 97, 19, 80, 232, 203, 122, 5, 151, 245, 64, 80, 214, 228, 150, 73, 200, 173, 109, 80, 59, 8, 100, 64, 15, 248, 153, 80, 52, 135, 87, 88, 13, 185, 198, 80, 78, 150, 76, 173, 235, 225, 243, 80, 132, 3, 163, 55, 174, 101, 33, 81, 0, 0, 0, 0, 0, 0, 248, 127);
+captured[24] = new Uint8Array([0, 0, 0, 0, 7, 1, 255, 255]);
+captured[25] = new Uint8Array([100, 0, 0, 0, 7, 1, 255, 255, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 28, 64, 0, 0, 0, 0, 0, 128, 72, 64, 0, 0, 0, 0, 0, 112, 117, 64, 0, 0, 0, 0, 0, 194, 162, 64, 0, 0, 0, 0, 192, 105, 208, 64, 0, 0, 0, 0, 16, 185, 252, 64, 0, 0, 0, 0, 238, 33, 41, 65, 0, 0, 0, 64, 176, 253, 85, 65, 0, 0, 0, 56, 250, 61, 131, 65, 0, 0, 0, 241, 58, 214, 176, 65, 0, 0, 192, 37, 231, 118, 221, 65, 0, 0, 8, 65, 10, 200, 9, 66, 0, 0, 231, 248, 8, 143, 54, 66, 0, 32, 202, 217, 39, 189, 99, 66, 0, 220, 144, 222, 130, 69, 145, 66, 0, 129, 125, 5, 165, 57, 190, 66, 224, 208, 205, 100, 112, 114, 234, 66, 196, 22, 52, 88, 34, 36, 23, 67, 236, 147, 45, 13, 158, 63, 68, 67, 110, 225, 135, 75, 170, 183, 113, 67, 128, 202, 45, 4, 106, 1, 159, 67, 48, 17, 168, 195, 60, 33, 203, 67, 10, 15, 51, 43, 21, 189, 247, 67, 41, 173, 204, 133, 114, 197, 36, 68, 132, 23, 19, 53, 196, 44, 82, 68, 39, 105, 225, 92, 87, 206, 127, 68, 2, 60, 69, 113, 140, 212, 171, 68, 130, 148, 28, 227, 250, 89, 216, 68, 242, 1, 185, 134, 187, 78, 5, 69, 180, 225, 225, 21, 228, 164, 50, 69, 126, 165, 37, 147, 71, 80, 96, 69, 156, 225, 129, 65, 125, 140, 140, 69, 104, 165, 81, 153, 237, 250, 184, 69, 187, 112, 39, 230, 143, 219, 229, 69, 164, 130, 98, 233, 29, 32, 19, 70, 80, 50, 54, 44, 26, 188, 64, 70, 12, 216, 94, 205, 45, 73, 109, 70, 10, 253, 178, 19, 8, 160, 153, 70, 105, 157, 60, 17, 7, 108, 198, 70, 188, 9, 21, 47, 134, 158, 243, 70, 132, 104, 50, 105, 181, 42, 33, 71, 231, 54, 24, 120, 189, 10, 78, 71, 10, 48, 21, 201, 101, 73, 122, 71, 9, 138, 242, 15, 57, 0, 167, 71, 200, 56, 244, 237, 49, 32, 212, 71, 175, 177, 53, 176, 43, 156, 1, 72, 242, 246, 93, 116, 76, 209, 46, 72, 20, 56, 210, 229, 34, 247, 90, 72, 18, 241, 23, 137, 62, 152, 135, 72, 240, 242, 244, 183, 54, 165, 180, 72, 146, 84, 246, 224, 143, 16, 226, 72, 0, 20, 175, 201, 251, 156, 15, 73, 128, 49, 121, 80, 92, 169, 59, 73, 80, 11, 106, 198, 48, 52, 104, 73, 230, 201, 156, 173, 170, 45, 149, 73, 169, 48, 233, 87, 245, 135, 194, 73, 148, 10, 236, 172, 246, 54, 240, 73, 131, 18, 157, 174, 47, 96, 28, 74, 51, 112, 201, 184, 41, 212, 72, 74, 45, 66, 176, 129, 164, 185, 117, 74, 231, 57, 122, 241, 111, 2, 163, 74, 170, 242, 74, 243, 33, 162, 208, 74, 170, 40, 195, 105, 187, 27, 253, 74, 149, 195, 138, 252, 67, 120, 41, 75, 34, 107, 249, 124, 59, 73, 86, 75, 190, 61, 90, 13, 20, 128, 131, 75, 6, 246, 174, 139, 17, 16, 177, 75, 138, 46, 114, 180, 30, 220, 221, 75, 185, 232, 227, 221, 154, 32, 10, 76, 162, 107, 39, 130, 135, 220, 54, 76, 46, 126, 226, 145, 246, 0, 100, 76, 104, 46, 166, 191, 215, 128, 145, 76, 54, 209, 98, 143, 121, 161, 190, 76, 15, 119, 118, 93, 74, 205, 234, 76, 45, 168, 199, 17, 161, 115, 23, 77, 39, 179, 142, 239, 44, 133, 68, 77, 194, 220, 156, 81, 135, 244, 113, 77, 84, 130, 210, 206, 236, 107, 159, 77, 10, 50, 248, 52, 111, 126, 203, 77, 201, 43, 89, 78, 161, 14, 248, 77, 80, 6, 142, 36, 205, 12, 37, 78, 134, 69, 252, 127, 51, 107, 82, 78, 213, 188, 252, 15, 205, 29, 128, 78, 117, 74, 250, 219, 38, 52, 172, 78, 38, 1, 123, 0, 162, 173, 216, 78, 1, 161, 107, 192, 237, 151, 5, 79, 225, 44, 94, 8, 240, 228, 50, 79, 69, 103, 82, 7, 82, 136, 96, 79, 185, 52, 208, 140, 143, 238, 140, 79, 34, 46, 54, 155, 189, 80, 185, 79, 94, 104, 207, 231, 165, 38, 230, 79, 82, 123, 213, 42, 209, 97, 19, 80, 232, 203, 122, 5, 151, 245, 64, 80, 214, 228, 150, 73, 200, 173, 109, 80, 59, 8, 100, 64, 15, 248, 153, 80, 52, 135, 87, 88, 13, 185, 198, 80, 78, 150, 76, 173, 235, 225, 243, 80, 132, 3, 163, 55, 174, 101, 33, 81, 0, 0, 0, 0, 0, 0, 248, 127]);
 captured[26] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[27] = serialize(0); captured[27].clonebuffer = String.fromCharCode(0, 0, 0, 0, 8, 1, 255, 255);
-captured[28] = serialize(0); captured[28].clonebuffer = String.fromCharCode(100, 0, 0, 0, 8, 1, 255, 255, 1, 7, 49, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0);
+captured[27] = new Uint8Array([0, 0, 0, 0, 8, 1, 255, 255]);
+captured[28] = new Uint8Array([100, 0, 0, 0, 8, 1, 255, 255, 1, 7, 49, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0]);
 captured[29] = (new TypeError("unsupported type for structured data", "js1_8_5/extensions/clone-v1-typed-array.js", 19));
-captured[30] = serialize(0); captured[30].clonebuffer = String.fromCharCode(0, 0, 0, 0, 7, 0, 255, 255, 0, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255);
+captured[30] = new Uint8Array([0, 0, 0, 0, 7, 0, 255, 255, 0, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 0, 1, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 255, 255, 3, 0, 0, 0, 0, 1, 255, 255, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255]);
--- a/js/src/tests/js1_8_5/extensions/clone-v1-typed-array.js
+++ b/js/src/tests/js1_8_5/extensions/clone-v1-typed-array.js
@@ -115,16 +115,14 @@ function test() {
 
 test();
 reportCompare(0, 0, 'ok');
 
 if ("JS_RECORD_RESULTS" in environment) {
   print("var captured = [];");
   for (var i in captured) {
     var s = "captured[" + i + "] = ";
-    if (captured[i] instanceof Error) {
+    if (captured[i] instanceof Error)
       print(s + captured[i].toSource() + ";");
-    } else {
-      data = [ c.charCodeAt(0) for (c of captured[i].clonebuffer.split('')) ];
-      print(s + "serialize(0); captured[" + i + "].clonebuffer = String.fromCharCode(" + data.join(", ") + ");");
-    }
+    else
+      print(s + "new Uint8Array(" + [...captured[i]].toSource() + ");");
   }
 }
--- a/js/src/tests/js1_8_5/extensions/shell.js
+++ b/js/src/tests/js1_8_5/extensions/shell.js
@@ -192,21 +192,8 @@ function referencesVia(from, edge, to) {
         print("referent is not referenced via: " + uneval(edge));
         print("but it is referenced via:       " + uneval(alternatives));
     }
     print("all incoming edges, from any object:");
     for (var e in edges)
         print(e);
     return false;
 }
-
-// Note that AsmJS ArrayBuffers have a minimum size, currently 4096 bytes. If a
-// smaller size is given, a regular ArrayBuffer will be returned instead.
-function AsmJSArrayBuffer(size) {
-    var ab = new ArrayBuffer(size);
-    (new Function('global', 'foreign', 'buffer', '' +
-'        "use asm";' +
-'        var i32 = new global.Int32Array(buffer);' +
-'        function g() {};' +
-'        return g;' +
-''))(this,null,ab);
-    return ab;
-}
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -27,18 +27,16 @@
  * array object.
  */
 
 #include "js/StructuredClone.h"
 
 #include "mozilla/Endian.h"
 #include "mozilla/FloatingPoint.h"
 
-#include <algorithm>
-
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jswrapper.h"
 
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 
@@ -63,86 +61,59 @@ enum StructuredDataType {
     SCTAG_REGEXP_OBJECT,
     SCTAG_ARRAY_OBJECT,
     SCTAG_OBJECT_OBJECT,
     SCTAG_ARRAY_BUFFER_OBJECT,
     SCTAG_BOOLEAN_OBJECT,
     SCTAG_STRING_OBJECT,
     SCTAG_NUMBER_OBJECT,
     SCTAG_BACK_REFERENCE_OBJECT,
-    SCTAG_DO_NOT_USE_1,
-    SCTAG_DO_NOT_USE_2,
+    SCTAG_TRANSFER_MAP_HEADER,
+    SCTAG_TRANSFER_MAP,
     SCTAG_TYPED_ARRAY_OBJECT,
     SCTAG_TYPED_ARRAY_V1_MIN = 0xFFFF0100,
     SCTAG_TYPED_ARRAY_V1_INT8 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_INT8,
     SCTAG_TYPED_ARRAY_V1_UINT8 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT8,
     SCTAG_TYPED_ARRAY_V1_INT16 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_INT16,
     SCTAG_TYPED_ARRAY_V1_UINT16 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT16,
     SCTAG_TYPED_ARRAY_V1_INT32 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_INT32,
     SCTAG_TYPED_ARRAY_V1_UINT32 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT32,
     SCTAG_TYPED_ARRAY_V1_FLOAT32 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_FLOAT32,
     SCTAG_TYPED_ARRAY_V1_FLOAT64 = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_FLOAT64,
     SCTAG_TYPED_ARRAY_V1_UINT8_CLAMPED = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_UINT8_CLAMPED,
     SCTAG_TYPED_ARRAY_V1_MAX = SCTAG_TYPED_ARRAY_V1_MIN + ScalarTypeRepresentation::TYPE_MAX - 1,
-
-    /*
-     * Define a separate range of numbers for Transferable-only tags, since
-     * they are not used for persistent clone buffers and therefore do not
-     * require bumping JS_STRUCTURED_CLONE_VERSION.
-     */
-    SCTAG_TRANSFER_MAP_HEADER = 0xFFFF0200,
-    SCTAG_TRANSFER_MAP_ENTRY,
-
     SCTAG_END_OF_BUILTIN_TYPES
 };
 
-// Data associated with an SCTAG_TRANSFER_MAP_HEADER that tells whether the
-// contents have been read out yet or not.
 enum TransferableMapHeader {
-    SCTAG_TM_UNREAD = 0,
-    SCTAG_TM_TRANSFERRED
-};
-
-enum TransferableObjectType {
-    // Transferable data has not been filled in yet
-    SCTAG_TM_UNFILLED = 0,
-
-    // Structured clone buffer does not yet own the data
-    SCTAG_TM_UNOWNED = 1,
-
-    // All values at least this large are owned by the clone buffer
-    SCTAG_TM_FIRST_OWNED = 2,
-
-    // Data is a pointer that can be freed
-    SCTAG_TM_ALLOC_DATA = 2,
+    SCTAG_TM_NOT_MARKED = 0,
+    SCTAG_TM_MARKED
 };
 
 namespace js {
 
 struct SCOutput {
   public:
     explicit SCOutput(JSContext *cx);
-    ~SCOutput();
 
     JSContext *context() const { return cx; }
 
     bool write(uint64_t u);
     bool writePair(uint32_t tag, uint32_t data);
     bool writeDouble(double d);
     bool writeBytes(const void *p, size_t nbytes);
     bool writeChars(const jschar *p, size_t nchars);
     bool writePtr(const void *);
 
     template <class T>
     bool writeArray(const T *p, size_t nbytes);
 
     bool extractBuffer(uint64_t **datap, size_t *sizep);
 
-    uint64_t count() const { return buf.length(); }
-    uint64_t *rawBuffer() { return buf.begin(); }
+    uint64_t count() { return buf.length(); }
 
   private:
     JSContext *cx;
     js::Vector<uint64_t> buf;
 };
 
 struct SCInput {
   public:
@@ -158,22 +129,16 @@ struct SCInput {
     bool readPtr(void **);
 
     bool get(uint64_t *p);
     bool getPair(uint32_t *tagp, uint32_t *datap);
 
     bool replace(uint64_t u);
     bool replacePair(uint32_t tag, uint32_t data);
 
-    uint64_t *tell() const { return point; }
-    void seek(uint64_t *pos) {
-        JS_ASSERT(pos <= end);
-        point = pos;
-    }
-
     template <class T>
     bool readArray(T *p, size_t nelems);
 
   private:
     bool eof();
 
     void staticAssertions() {
         JS_STATIC_ASSERT(sizeof(jschar) == 2);
@@ -234,17 +199,18 @@ struct JSStructuredCloneWriter {
                                      const JSStructuredCloneCallbacks *cb,
                                      void *cbClosure,
                                      jsval tVal)
         : out(out), objs(out.context()),
           counts(out.context()), ids(out.context()),
           memory(out.context()), callbacks(cb), closure(cbClosure),
           transferable(out.context(), tVal), transferableObjects(out.context()) { }
 
-    bool init() { return parseTransferable() && memory.init() && writeTransferMap(); }
+    bool init() { return transferableObjects.init() && parseTransferable() &&
+                         memory.init() && writeTransferMap(); }
 
     bool write(const js::Value &v);
 
     js::SCOutput &output() { return out; }
 
   private:
     JSContext *context() { return out.context(); }
 
@@ -255,17 +221,16 @@ struct JSStructuredCloneWriter {
     bool writeArrayBuffer(JS::HandleObject obj);
     bool writeTypedArray(JS::HandleObject obj);
     bool startObject(JS::HandleObject obj, bool *backref);
     bool startWrite(const js::Value &v);
     bool traverseObject(JS::HandleObject obj);
 
     bool parseTransferable();
     void reportErrorTransferable();
-    bool transferOwnership();
 
     inline void checkStack();
 
     js::SCOutput &out;
 
     // Vector of objects with properties remaining to be written.
     //
     // NB: These can span multiple compartments, so the compartment must be
@@ -288,17 +253,17 @@ struct JSStructuredCloneWriter {
     // The user defined callbacks that will be used for cloning.
     const JSStructuredCloneCallbacks *callbacks;
 
     // Any value passed to JS_WriteStructuredClone.
     void *closure;
 
     // List of transferable objects
     JS::RootedValue transferable;
-    JS::AutoObjectVector transferableObjects;
+    js::AutoObjectHashSet transferableObjects;
 
     friend bool JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v);
 };
 
 JS_FRIEND_API(uint64_t)
 js_GetSCOffset(JSStructuredCloneWriter* writer)
 {
     JS_ASSERT(writer);
@@ -325,75 +290,64 @@ bool
 ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
                     const JSStructuredCloneCallbacks *cb, void *cbClosure)
 {
     SCInput in(cx, data, nbytes);
     JSStructuredCloneReader r(in, cb, cbClosure);
     return r.read(vp);
 }
 
-// This may acquire new ways of discarding transfer map entries as new
-// Transferables are implemented.
-static void
-DiscardEntry(uint32_t mapEntryDescriptor, const uint64_t *ptr)
+bool
+ClearStructuredClone(const uint64_t *data, size_t nbytes)
 {
-    JS_ASSERT(mapEntryDescriptor == SCTAG_TM_ALLOC_DATA);
-    uint64_t u = LittleEndian::readUint64(ptr);
-    js_free(reinterpret_cast<void*>(u));
-}
-
-static void
-Discard(const uint64_t *begin, const uint64_t *end)
-{
-    const uint64_t *point = begin;
+    const uint64_t *point = data;
+    const uint64_t *end = data + nbytes / 8;
 
     uint64_t u = LittleEndian::readUint64(point++);
     uint32_t tag = uint32_t(u >> 32);
-    if (tag != SCTAG_TRANSFER_MAP_HEADER)
-        return;
-
-    if (TransferableMapHeader(u) == SCTAG_TM_TRANSFERRED)
-        return;
-
-    uint64_t numTransferables = LittleEndian::readUint64(point++);
-    while (numTransferables--) {
-        uint64_t u = LittleEndian::readUint64(point++);
-        JS_ASSERT(uint32_t(u >> 32) == SCTAG_TRANSFER_MAP_ENTRY);
-        uint32_t mapEntryDescriptor = uint32_t(u);
-        if (mapEntryDescriptor >= SCTAG_TM_FIRST_OWNED) {
-            DiscardEntry(mapEntryDescriptor, point);
-            point += 2; // Pointer and userdata
+    if (tag == SCTAG_TRANSFER_MAP_HEADER) {
+        if ((TransferableMapHeader)uint32_t(u) == SCTAG_TM_NOT_MARKED) {
+            while (point != end) {
+                uint64_t u = LittleEndian::readUint64(point++);
+                uint32_t tag = uint32_t(u >> 32);
+                if (tag == SCTAG_TRANSFER_MAP) {
+                    u = LittleEndian::readUint64(point++);
+                    js_free(reinterpret_cast<void*>(u));
+                } else {
+                    // The only things in the transfer map should be
+                    // SCTAG_TRANSFER_MAP tags paired with pointers. If we find
+                    // any other tag, we've walked off the end of the transfer
+                    // map.
+                    break;
+                }
+            }
         }
     }
-}
 
-static void
-ClearStructuredClone(const uint64_t *data, size_t nbytes)
-{
-    JS_ASSERT(nbytes % 8 == 0);
-    Discard(data, data + nbytes / 8);
-    js_free(const_cast<uint64_t*>(data));
+    js_free((void *)data);
+    return true;
 }
 
 bool
 StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable)
 {
     *hasTransferable = false;
 
     if (data) {
         uint64_t u = LittleEndian::readUint64(data);
         uint32_t tag = uint32_t(u >> 32);
-        if (tag == SCTAG_TRANSFER_MAP_HEADER)
+        if (tag == SCTAG_TRANSFER_MAP_HEADER) {
             *hasTransferable = true;
+        }
     }
 
     return true;
 }
 
-} /* namespace js */
+}
 
 static inline uint64_t
 PairToUInt64(uint32_t tag, uint32_t data)
 {
     return uint64_t(data) | (uint64_t(tag) << 32);
 }
 
 bool
@@ -492,18 +446,17 @@ SCInput::readDouble(double *p)
     *p = CanonicalizeNan(pun.d);
     return true;
 }
 
 template <typename T>
 static void
 copyAndSwapFromLittleEndian(T *dest, const void *src, size_t nelems)
 {
-    if (nelems > 0)
-        NativeEndian::copyAndSwapFromLittleEndian(dest, src, nelems);
+    NativeEndian::copyAndSwapFromLittleEndian(dest, src, nelems);
 }
 
 template <>
 void
 copyAndSwapFromLittleEndian(uint8_t *dest, const void *src, size_t nelems)
 {
     memcpy(dest, src, nelems);
 }
@@ -548,22 +501,16 @@ SCInput::readPtr(void **p)
     uint64_t tmp;
     bool ret = read(&tmp);
     *p = reinterpret_cast<void*>(tmp);
     return ret;
 }
 
 SCOutput::SCOutput(JSContext *cx) : cx(cx), buf(cx) {}
 
-SCOutput::~SCOutput()
-{
-    // Free any transferable data left lying around in the buffer
-    Discard(rawBuffer(), rawBuffer() + count());
-}
-
 bool
 SCOutput::write(uint64_t u)
 {
     return buf.append(NativeEndian::swapToLittleEndian(u));
 }
 
 bool
 SCOutput::writePair(uint32_t tag, uint32_t data)
@@ -613,18 +560,17 @@ SCOutput::writeDouble(double d)
 {
     return write(ReinterpretDoubleAsUInt64(CanonicalizeNan(d)));
 }
 
 template <typename T>
 static void
 copyAndSwapToLittleEndian(void *dest, const T *src, size_t nelems)
 {
-    if (nelems > 0)
-        NativeEndian::copyAndSwapToLittleEndian(dest, src, nelems);
+    NativeEndian::copyAndSwapToLittleEndian(dest, src, nelems);
 }
 
 template <>
 void
 copyAndSwapToLittleEndian(void *dest, const uint8_t *src, size_t nelems)
 {
     memcpy(dest, src, nelems);
 }
@@ -681,80 +627,77 @@ SCOutput::extractBuffer(uint64_t **datap
     return (*datap = buf.extractRawBuffer()) != nullptr;
 }
 
 JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
 
 bool
 JSStructuredCloneWriter::parseTransferable()
 {
-    MOZ_ASSERT(transferableObjects.empty(), "parseTransferable called with stale data");
+    transferableObjects.clear();
 
     if (JSVAL_IS_NULL(transferable) || JSVAL_IS_VOID(transferable))
         return true;
 
     if (!transferable.isObject()) {
         reportErrorTransferable();
         return false;
     }
 
-    JSContext *cx = context();
-    RootedObject array(cx, &transferable.toObject());
-    if (!JS_IsArrayObject(cx, array)) {
+    RootedObject array(context(), &transferable.toObject());
+    if (!JS_IsArrayObject(context(), array)) {
         reportErrorTransferable();
         return false;
     }
 
     uint32_t length;
-    if (!JS_GetArrayLength(cx, array, &length)) {
+    if (!JS_GetArrayLength(context(), array, &length)) {
         return false;
     }
 
     RootedValue v(context());
 
     for (uint32_t i = 0; i < length; ++i) {
-        if (!JS_GetElement(cx, array, i, &v)) {
+        if (!JS_GetElement(context(), array, i, &v)) {
             return false;
         }
 
         if (!v.isObject()) {
             reportErrorTransferable();
             return false;
         }
 
         JSObject* tObj = CheckedUnwrap(&v.toObject());
         if (!tObj) {
-            JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_UNWRAP_DENIED);
+            JS_ReportError(context(), "Permission denied to access object");
             return false;
         }
         if (!tObj->is<ArrayBufferObject>()) {
             reportErrorTransferable();
             return false;
         }
 
-        // No duplicates allowed
-        if (std::find(transferableObjects.begin(), transferableObjects.end(), tObj) != transferableObjects.end()) {
-            JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_DUP_TRANSFERABLE);
+        // No duplicate:
+        if (transferableObjects.has(tObj)) {
+            reportErrorTransferable();
             return false;
         }
 
-        if (!transferableObjects.append(tObj))
+        if (!transferableObjects.putNew(tObj))
             return false;
     }
 
     return true;
 }
 
 void
 JSStructuredCloneWriter::reportErrorTransferable()
 {
     if (callbacks && callbacks->reportError)
         return callbacks->reportError(context(), JS_SCERR_TRANSFERABLE);
-    else
-        JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_NOT_TRANSFERABLE);
 }
 
 bool
 JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
 {
     size_t length = str->length();
     const jschar *chars = str->getChars(context());
     if (!chars)
@@ -946,84 +889,41 @@ JSStructuredCloneWriter::startWrite(cons
 
     JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, JSMSG_SC_UNSUPPORTED_TYPE);
     return false;
 }
 
 bool
 JSStructuredCloneWriter::writeTransferMap()
 {
-    if (transferableObjects.empty())
-        return true;
-
-    if (!out.writePair(SCTAG_TRANSFER_MAP_HEADER, (uint32_t)SCTAG_TM_UNREAD))
-        return false;
-
-    if (!out.write(transferableObjects.length()))
-        return false;
-
-    for (JS::AutoObjectVector::Range tr = transferableObjects.all();
-         !tr.empty(); tr.popFront())
-    {
-        JSObject *obj = tr.front();
-
-        if (!memory.put(obj, memory.count()))
+    if (!transferableObjects.empty()) {
+        if (!out.writePair(SCTAG_TRANSFER_MAP_HEADER, (uint32_t)SCTAG_TM_NOT_MARKED))
             return false;
 
-        // Emit a placeholder pointer. We will steal the data and neuter the
-        // transferable later.
-        if (!out.writePair(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_UNFILLED) ||
-            !out.writePtr(NULL) ||
-            !out.write(0))
-        {
-            return false;
+        for (HashSet<JSObject*>::Range r = transferableObjects.all();
+             !r.empty(); r.popFront()) {
+            JSObject *obj = r.front();
+
+            if (!memory.put(obj, memory.count()))
+                return false;
+
+            void *content;
+            uint8_t *data;
+            if (!JS_StealArrayBufferContents(context(), obj, &content, &data))
+               return false;
+
+            if (!out.writePair(SCTAG_TRANSFER_MAP, 0) || !out.writePtr(content))
+                return false;
         }
     }
 
     return true;
 }
 
 bool
-JSStructuredCloneWriter::transferOwnership()
-{
-    if (transferableObjects.empty())
-        return true;
-
-    // Walk along the transferables and the transfer map at the same time,
-    // grabbing out pointers from the transferables and stuffing them into the
-    // transfer map.
-    uint64_t *point = out.rawBuffer();
-    JS_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_HEADER);
-    point++;
-    JS_ASSERT(LittleEndian::readUint64(point) == transferableObjects.length());
-    point++;
-
-    for (JS::AutoObjectVector::Range tr = transferableObjects.all();
-         !tr.empty();
-         tr.popFront())
-    {
-        void *content;
-        uint8_t *data;
-        if (!JS_StealArrayBufferContents(context(), tr.front(), &content, &data))
-            return false; // Destructor will clean up the already-transferred data
-
-        MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_ENTRY);
-        LittleEndian::writeUint64(point++, PairToUInt64(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_ALLOC_DATA));
-        LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(content));
-        LittleEndian::writeUint64(point++, 0);
-    }
-
-    JS_ASSERT(point <= out.rawBuffer() + out.count());
-    JS_ASSERT_IF(point < out.rawBuffer() + out.count(),
-                 uint32_t(LittleEndian::readUint64(point) >> 32) != SCTAG_TRANSFER_MAP_ENTRY);
-
-    return true;
-}
-
-bool
 JSStructuredCloneWriter::write(const Value &v)
 {
     if (!startWrite(v))
         return false;
 
     while (!counts.empty()) {
         RootedObject obj(context(), &objs.back().toObject());
         AutoCompartment ac(context(), obj);
@@ -1056,17 +956,18 @@ JSStructuredCloneWriter::write(const Val
         } else {
             out.writePair(SCTAG_NULL, 0);
             objs.popBack();
             counts.popBack();
         }
     }
 
     memory.clear();
-    return transferOwnership();
+
+    return true;
 }
 
 bool
 JSStructuredCloneReader::checkDouble(double d)
 {
     jsval_layout l;
     l.asDouble = d;
     if (!JSVAL_IS_DOUBLE_IMPL(l)) {
@@ -1382,17 +1283,17 @@ JSStructuredCloneReader::startRead(Value
 
       case SCTAG_TRANSFER_MAP_HEADER:
         // A map header cannot be here but just at the beginning of the buffer.
         JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr,
                              JSMSG_SC_BAD_SERIALIZED_DATA,
                              "invalid input");
         return false;
 
-      case SCTAG_TRANSFER_MAP_ENTRY:
+      case SCTAG_TRANSFER_MAP:
         // A map cannot be here but just at the beginning of the buffer.
         JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr,
                              JSMSG_SC_BAD_SERIALIZED_DATA,
                              "invalid input");
         return false;
 
       case SCTAG_ARRAY_BUFFER_OBJECT:
         if (!readArrayBuffer(data, vp))
@@ -1468,67 +1369,47 @@ JSStructuredCloneReader::readId(jsid *id
     JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr,
                          JSMSG_SC_BAD_SERIALIZED_DATA, "id");
     return false;
 }
 
 bool
 JSStructuredCloneReader::readTransferMap()
 {
-    uint64_t *headerPos = in.tell();
-
     uint32_t tag, data;
     if (!in.getPair(&tag, &data))
         return false;
 
-    if (tag != SCTAG_TRANSFER_MAP_HEADER || TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
+    if (tag != SCTAG_TRANSFER_MAP_HEADER ||
+        (TransferableMapHeader)data == SCTAG_TM_MARKED)
         return true;
 
-    uint64_t numTransferables;
-    MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
-    if (!in.read(&numTransferables))
+    if (!in.replacePair(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_MARKED))
+        return false;
+
+    if (!in.readPair(&tag, &data))
         return false;
 
-    for (uint64_t i = 0; i < numTransferables; i++) {
-        uint64_t *pos = in.tell();
+    while (1) {
+        if (!in.getPair(&tag, &data))
+            return false;
 
-        if (!in.readPair(&tag, &data))
-            return false;
-        JS_ASSERT(tag == SCTAG_TRANSFER_MAP_ENTRY);
-        JS_ASSERT(data == SCTAG_TM_ALLOC_DATA);
+        if (tag != SCTAG_TRANSFER_MAP)
+            break;
 
         void *content;
-        if (!in.readPtr(&content))
-            return false;
 
-        uint64_t userdata;
-        if (!in.read(&userdata))
+        if (!in.readPair(&tag, &data) || !in.readPtr(&content))
             return false;
 
         JSObject *obj = JS_NewArrayBufferWithContents(context(), content);
-        if (!obj)
-            return false;
-
-        // Rewind to the SCTAG_TRANSFER_MAP_ENTRY and mark this entry as unowned by
-        // the input buffer.
-        uint64_t *next = in.tell();
-        in.seek(pos);
-        MOZ_ALWAYS_TRUE(in.replacePair(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_UNOWNED));
-        in.seek(next);
-
-        if (!allObjs.append(ObjectValue(*obj)))
+        if (!obj || !allObjs.append(ObjectValue(*obj)))
             return false;
     }
 
-    // Mark the whole transfer map as consumed
-    uint64_t *endPos = in.tell();
-    in.seek(headerPos);
-    MOZ_ALWAYS_TRUE(in.replacePair(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED));
-    in.seek(endPos);
-
     return true;
 }
 
 bool
 JSStructuredCloneReader::read(Value *vp)
 {
     if (!readTransferMap())
         return false;
@@ -1593,18 +1474,17 @@ JS_WriteStructuredClone(JSContext *cx, J
         optionalCallbacks :
         cx->runtime()->structuredCloneCallbacks;
     return WriteStructuredClone(cx, value, bufp, nbytesp, callbacks, closure, transferable);
 }
 
 JS_PUBLIC_API(bool)
 JS_ClearStructuredClone(const uint64_t *data, size_t nbytes)
 {
-    ClearStructuredClone(data, nbytes);
-    return true;
+    return ClearStructuredClone(data, nbytes);
 }
 
 JS_PUBLIC_API(bool)
 JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
                                    bool *hasTransferable)
 {
     bool transferable;
     if (!StructuredCloneHasTransferObjects(data, nbytes, &transferable))
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -239,17 +239,17 @@ AllocateArrayBufferContents(JSContext *m
             js_ReportOutOfMemory(maybecx);
         return nullptr;
     }
 
     if (initdata)
         memcpy(newheader->elements(), initdata, nbytes);
 
     // we rely on this being correct
-    ArrayBufferObject::updateElementsHeader(newheader, nbytes);
+    ArrayBufferObject::setElementsHeader(newheader, nbytes);
 
     return newheader;
 }
 
 bool
 ArrayBufferObject::allocateSlots(JSContext *maybecx, uint32_t bytes, uint8_t *contents)
 {
     /*
@@ -269,17 +269,17 @@ ArrayBufferObject::allocateSlots(JSConte
     } else {
         elements = fixedElements();
         if (contents)
             memcpy(elements, contents, bytes);
         else
             memset(elements, 0, bytes);
     }
 
-    initElementsHeader(getElementsHeader(), bytes);
+    setElementsHeader(getElementsHeader(), bytes);
 
     return true;
 }
 
 static inline void
 PostBarrierTypedArrayObject(JSObject *obj)
 {
 #ifdef JSGC_GENERATIONAL
@@ -292,17 +292,17 @@ PostBarrierTypedArrayObject(JSObject *ob
 
 // The list of views must be stored somewhere in the ArrayBufferObject, but
 // the slots are already being used for the element storage and the private
 // field is used for a delegate object. The ObjectElements header has space
 // for it, but I don't want to mess around with adding unions to it with
 // JS_USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much
 // more cleanly.
 struct OldObjectRepresentationHack {
-    uint32_t flags;
+    uint32_t capacity;
     uint32_t initializedLength;
     EncapsulatedPtr<ArrayBufferViewObject> views;
 };
 
 static ArrayBufferViewObject *
 GetViewList(ArrayBufferObject *obj)
 {
     return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
@@ -325,117 +325,54 @@ InitViewList(ArrayBufferObject *obj, Arr
 static EncapsulatedPtr<ArrayBufferViewObject> &
 GetViewListRef(ArrayBufferObject *obj)
 {
     JS_ASSERT(obj->runtimeFromMainThread()->isHeapBusy());
     return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
 }
 
 void
-ArrayBufferObject::neuterViews(JSContext *maybecx)
-{
-    ArrayBufferViewObject *view;
-    for (view = GetViewList(this); view; view = view->nextView()) {
-        view->neuter();
-
-        // Notify compiled jit code that the base pointer has moved.
-        if (maybecx)
-            MarkObjectStateChange(maybecx, view);
-    }
-
-    // neuterAsmJSArrayBuffer adjusts state specific to the ArrayBuffer data
-    // itself, but it only affects the behavior of views
-    if (isAsmJSArrayBuffer())
-        ArrayBufferObject::neuterAsmJSArrayBuffer(*this);
-}
-
-void
 ArrayBufferObject::changeContents(JSContext *maybecx, ObjectElements *newHeader)
 {
-    // Grab out data before invalidating it.
-    uint32_t byteLengthCopy = byteLength();
-    uintptr_t oldDataPointer = uintptr_t(dataPointer());
-    ArrayBufferViewObject *viewListHead = GetViewList(this);
-
-    // Update all views.
-    uintptr_t newDataPointer = uintptr_t(newHeader->elements());
-    for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
-        uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer;
-        view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr));
-
-        // Notify compiled jit code that the base pointer has moved.
-        if (maybecx)
-            MarkObjectStateChange(maybecx, view);
-    }
-
-    // The list of views in the old header is reachable if the contents are
-    // being transferred, so NULL it out
-    SetViewList(this, NULL);
-
-    elements = newHeader->elements();
-
-    initElementsHeader(newHeader, byteLengthCopy);
-    InitViewList(this, viewListHead);
-}
-
-void
-ArrayBufferObject::neuter(JSContext *cx)
-{
-    JS_ASSERT(cx);
-    if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
-        ObjectElements *oldHeader = getElementsHeader();
-        changeContents(cx, ObjectElements::fromElements(fixedElements()));
-
-        FreeOp fop(cx->runtime(), false);
-        fop.free_(oldHeader);
-    }
-
-    uint32_t byteLen = 0;
-    updateElementsHeader(getElementsHeader(), byteLen);
+   // Grab out data before invalidating it.
+   uint32_t byteLengthCopy = byteLength();
+   uintptr_t oldDataPointer = uintptr_t(dataPointer());
+   ArrayBufferViewObject *viewListHead = GetViewList(this);
+
+   // Update all views.
+   uintptr_t newDataPointer = uintptr_t(newHeader->elements());
+   for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
+       uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer;
+       view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr));
+
+       // Notify compiled jit code that the base pointer has moved.
+       if (maybecx)
+           MarkObjectStateChange(maybecx, view);
+   }
+
+   // Change to the new header (now, so we can use SetViewList).
+   elements = newHeader->elements();
+
+   // Initialize 'newHeader'.
+   ArrayBufferObject::setElementsHeader(newHeader, byteLengthCopy);
+   SetViewList(this, viewListHead);
 }
 
 bool
-ArrayBufferObject::copyData(JSContext *maybecx)
-{
-    ObjectElements *newHeader = AllocateArrayBufferContents(maybecx, byteLength(), dataPointer());
-    if (!newHeader)
-        return false;
-
-    changeContents(maybecx, newHeader);
-    return true;
-}
-
-bool
-ArrayBufferObject::ensureNonInline(JSContext *maybecx)
+ArrayBufferObject::uninlineData(JSContext *maybecx)
 {
-    if (hasDynamicElements())
-        return true;
-    return copyData(maybecx);
-}
-
-// If the ArrayBuffer already contains dynamic contents, hand them back.
-// Otherwise, allocate some new contents and copy the data over, but in no case
-// modify the original ArrayBuffer. (Also, any allocated contents will have no
-// views linked to in its header.)
-ObjectElements *
-ArrayBufferObject::getTransferableContents(JSContext *maybecx, bool *callerOwns)
-{
-    if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
-        *callerOwns = false;
-        return getElementsHeader();
-    }
-
-    uint32_t byteLen = byteLength();
-    ObjectElements *newheader = AllocateArrayBufferContents(maybecx, byteLen, dataPointer());
-    if (!newheader)
-        return NULL;
-
-    initElementsHeader(newheader, byteLen);
-    *callerOwns = true;
-    return newheader;
+   if (hasDynamicElements())
+       return true;
+
+   ObjectElements *newHeader = AllocateArrayBufferContents(maybecx, byteLength(), dataPointer());
+   if (!newHeader)
+       return false;
+
+   changeContents(maybecx, newHeader);
+   return true;
 }
 
 #if defined(JS_ION) && defined(JS_CPU_X64)
 // To avoid dynamically checking bounds on each load/store, asm.js code relies
 // on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works
 // if we can guarantee that *any* out-of-bounds access generates a fault. This
 // isn't generally true since an out-of-bounds access could land on other
 // Mozilla data. To overcome this on x64, we reserve an entire 4GB space,
@@ -537,19 +474,18 @@ ArrayBufferObject::neuterAsmJSArrayBuffe
     if (mprotect(buffer.dataPointer(), buffer.byteLength(), PROT_NONE))
         MOZ_CRASH();
 #endif
 }
 #else  /* defined(JS_ION) && defined(JS_CPU_X64) */
 bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
-    if (!buffer->copyData(cx))
+    if (!buffer->uninlineData(cx))
         return false;
-    JS_ASSERT(buffer->hasDynamicElements());
 
     buffer->getElementsHeader()->setIsAsmJSArrayBuffer();
     return true;
 }
 
 void
 ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
 {
@@ -656,38 +592,51 @@ ArrayBufferObject::createDataViewForThis
 bool
 ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
 }
 
 bool
-ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents, uint8_t **data)
+ArrayBufferObject::stealContents(JSContext *cx, JSObject *obj, void **contents,
+                                 uint8_t **data)
 {
     ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
-
-    // Make the data stealable
-    bool own;
-    ObjectElements *header = reinterpret_cast<ObjectElements*>(buffer.getTransferableContents(cx, &own));
-    if (!header)
-        return false;
-    *contents = header;
-    *data = reinterpret_cast<uint8_t *>(header + 1);
-
-    // Neuter the views, which may also mprotect(PROT_NONE) the buffer. So do
-    // it after copying out the data.
-    buffer.neuterViews(cx);
-
-    if (!own) {
-        // If header has dynamically allocated elements, revert it back to
-        // fixed-element storage before neutering it.
-        buffer.changeContents(cx, ObjectElements::fromElements(buffer.fixedElements()));
+    ArrayBufferViewObject *views = GetViewList(&buffer);
+    js::ObjectElements *header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
+    if (buffer.hasDynamicElements() && !buffer.isAsmJSArrayBuffer()) {
+        SetViewList(&buffer, nullptr);
+        *contents = header;
+        *data = buffer.dataPointer();
+
+        buffer.setFixedElements();
+        header = js::ObjectElements::fromElements((js::HeapSlot*)buffer.dataPointer());
+    } else {
+        uint32_t length = buffer.byteLength();
+        js::ObjectElements *newheader =
+            AllocateArrayBufferContents(cx, length, buffer.dataPointer());
+        if (!newheader) {
+            js_ReportOutOfMemory(cx);
+            return false;
+        }
+
+        ArrayBufferObject::setElementsHeader(newheader, length);
+        *contents = newheader;
+        *data = reinterpret_cast<uint8_t *>(newheader + 1);
+
+        if (buffer.isAsmJSArrayBuffer())
+            ArrayBufferObject::neuterAsmJSArrayBuffer(buffer);
     }
-    buffer.neuter(cx);
+
+    // Neuter the donor ArrayBufferObject and all views of it
+    ArrayBufferObject::setElementsHeader(header, 0);
+    InitViewList(&buffer, views);
+    for (ArrayBufferViewObject *view = views; view; view = view->nextView())
+        view->neuter();
 
     return true;
 }
 
 void
 ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
 {
     /*
@@ -4012,29 +3961,21 @@ JS_GetArrayBufferByteLength(JSObject *ob
 
 JS_FRIEND_API(uint8_t *)
 JS_GetArrayBufferData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
-    if (!buffer.ensureNonInline(NULL))
+    if (!buffer.uninlineData(nullptr))
         return nullptr;
     return buffer.dataPointer();
 }
 
-JS_FRIEND_API(void)
-JS_NeuterArrayBuffer(JSObject *obj, JSContext *cx)
-{
-    ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
-    buffer.neuterViews(cx);
-    buffer.neuter(cx);
-}
-
 JS_FRIEND_API(JSObject *)
 JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
 {
     JS_ASSERT(nbytes <= INT32_MAX);
     return ArrayBufferObject::create(cx, nbytes);
 }
 
 JS_PUBLIC_API(JSObject *)
@@ -4051,31 +3992,31 @@ JS_NewArrayBufferWithContents(JSContext 
 
 JS_PUBLIC_API(bool)
 JS_AllocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data)
 {
     js::ObjectElements *header = AllocateArrayBufferContents(cx, nbytes, nullptr);
     if (!header)
         return false;
 
-    ArrayBufferObject::updateElementsHeader(header, nbytes);
+    ArrayBufferObject::setElementsHeader(header, nbytes);
 
     *contents = header;
     *data = reinterpret_cast<uint8_t*>(header->elements());
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_ReallocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void **contents, uint8_t **data)
 {
     js::ObjectElements *header = AllocateArrayBufferContents(cx, nbytes, nullptr, *contents);
     if (!header)
         return false;
 
-    ArrayBufferObject::initElementsHeader(header, nbytes);
+    ArrayBufferObject::setElementsHeader(header, nbytes);
 
     *contents = header;
     *data = reinterpret_cast<uint8_t*>(header->elements());
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_StealArrayBufferContents(JSContext *cx, JSObject *obj, void **contents,
@@ -4315,18 +4256,18 @@ JS_GetObjectAsArrayBufferView(JSObject *
                                   ? obj->as<DataViewObject>().dataPointer()
                                   : obj->as<TypedArrayObject>().viewData());
     return obj;
 }
 
 JS_FRIEND_API(JSObject *)
 JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
 {
-    if (!(obj = CheckedUnwrap(obj)))
-        return nullptr;
+   if (!(obj = CheckedUnwrap(obj)))
+       return nullptr;
     if (!obj->is<ArrayBufferObject>())
         return nullptr;
 
     *length = obj->as<ArrayBufferObject>().byteLength();
     *data = obj->as<ArrayBufferObject>().dataPointer();
 
     return obj;
 }
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -141,81 +141,51 @@ class ArrayBufferObject : public JSObjec
 
     static void resetArrayBufferList(JSCompartment *rt);
     static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
     static void restoreArrayBufferLists(ArrayBufferVector &vector);
 
     static bool stealContents(JSContext *cx, JSObject *obj, void **contents,
                               uint8_t **data);
 
-    static void updateElementsHeader(js::ObjectElements *header, uint32_t bytes) {
+    static void setElementsHeader(js::ObjectElements *header, uint32_t bytes) {
+        header->flags = 0;
         header->initializedLength = bytes;
 
         // NB: one or both of these fields is clobbered by GetViewList to store
         // the 'views' link. Set them to 0 to effectively initialize 'views'
         // to nullptr.
         header->length = 0;
         header->capacity = 0;
     }
 
-    static void initElementsHeader(js::ObjectElements *header, uint32_t bytes) {
-        header->flags = 0;
-        updateElementsHeader(header, bytes);
-    }
-
     static uint32_t headerInitializedLength(const js::ObjectElements *header) {
         return header->initializedLength;
     }
 
     void addView(ArrayBufferViewObject *view);
 
     bool allocateSlots(JSContext *cx, uint32_t size, uint8_t *contents = nullptr);
-
     void changeContents(JSContext *cx, ObjectElements *newHeader);
 
     /*
-     * Copy the data into freshly-allocated memory. Used when un-inlining or
-     * when converting an ArrayBuffer to an AsmJS (MMU-assisted) ArrayBuffer.
-     */
-    bool copyData(JSContext *maybecx);
-
-    /*
-     * Ensure data is not stored inline in the object. Used when handing back a
+     * Ensure that the data is not stored inline. Used when handing back a
      * GC-safe pointer.
      */
-    bool ensureNonInline(JSContext *maybecx);
+    bool uninlineData(JSContext *cx);
 
     uint32_t byteLength() const {
         return getElementsHeader()->initializedLength;
     }
 
-    /*
-     * Return the contents of an ArrayBuffer without modifying the ArrayBuffer
-     * itself. Set *callerOwns to true if the caller has the only pointer to
-     * the returned contents (which is the case for inline or asm.js buffers),
-     * and false if the ArrayBuffer still owns the pointer.
-     */
-    ObjectElements *getTransferableContents(JSContext *maybecx, bool *callerOwns);
-
-    /*
-     * Neuter all views of an ArrayBuffer.
-     */
-    void neuterViews(JSContext *maybecx);
-
     inline uint8_t * dataPointer() const {
         return (uint8_t *) elements;
     }
 
     /*
-     * Discard the ArrayBuffer contents. For asm.js buffers, at least, should
-     * be called after neuterViews().
-     */
-    void neuter(JSContext *maybecx);
-
-    /*
      * Check if the arrayBuffer contains any data. This will return false for
      * ArrayBuffer.prototype and neutered ArrayBuffers.
      */
     bool hasData() const {
         return getClass() == &class_;
     }
 
     bool isAsmJSArrayBuffer() const {
@@ -546,17 +516,16 @@ class DataViewObject : public ArrayBuffe
 
     static bool setFloat32Impl(JSContext *cx, CallArgs args);
     static bool fun_setFloat32(JSContext *cx, unsigned argc, Value *vp);
 
     static bool setFloat64Impl(JSContext *cx, CallArgs args);
     static bool fun_setFloat64(JSContext *cx, unsigned argc, Value *vp);
 
     static JSObject *initClass(JSContext *cx);
-    static void neuter(JSObject *view);
     static bool getDataPointer(JSContext *cx, Handle<DataViewObject*> obj,
                                CallArgs args, size_t typeSize, uint8_t **data);
     template<typename NativeType>
     static bool read(JSContext *cx, Handle<DataViewObject*> obj,
                      CallArgs &args, NativeType *val, const char *method);
     template<typename NativeType>
     static bool write(JSContext *cx, Handle<DataViewObject*> obj,
                       CallArgs &args, const char *method);