Back out b24a73b2c617 for Windows build bustage and test_xhr_timeout.html failure
authorPhil Ringnalda <philringnalda@gmail.com>
Thu, 27 Sep 2012 21:24:42 -0700
changeset 108489 9600a66b7bccfae603046b36a57034a9a1804476
parent 108488 22df14239cfbeecf7abb721810c691f7357fe8af
child 108490 5ed440d28b5382ef35fdc2c267d182c12850c36d
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
milestone18.0a1
backs outb24a73b2c617f96be7a160642510750f87b8607a
Back out b24a73b2c617 for Windows build bustage and test_xhr_timeout.html failure
content/base/test/test_XHR_timeout.js
dom/base/nsStructuredCloneContainer.cpp
dom/ipc/StructuredCloneUtils.cpp
dom/ipc/StructuredCloneUtils.h
dom/workers/Worker.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerPrivate.h
dom/workers/WorkerScope.cpp
dom/workers/test/Makefile.in
dom/workers/test/test_transferable.html
dom/workers/test/transferable_worker.js
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsclone.cpp
js/src/jsclone.h
js/src/shell/js.cpp
--- a/content/base/test/test_XHR_timeout.js
+++ b/content/base/test/test_XHR_timeout.js
@@ -7,40 +7,33 @@
 
 var inWorker = false;
 try {
   inWorker = !(self instanceof Window);
 } catch (e) {
   inWorker = true;
 }
 
-function message(data) {
-  if (inWorker)
-    self.postMessage(data);
-  else
-    self.postMessage(data, "*");
-}
-
 function is(got, expected, msg) {
   var obj = {};
   obj.type = "is";
   obj.got = got;
   obj.expected = expected;
   obj.msg = msg;
 
-  message(obj);
+  self.postMessage(obj, "*");
 }
 
 function ok(bool, msg) {
   var obj = {};
   obj.type = "ok";
   obj.bool = bool;
   obj.msg = msg;
 
-  message(obj);
+  self.postMessage(obj, "*");
 }
 
 /**
  * Generate and track results from a XMLHttpRequest with regards to timeouts.
  *
  * @param {String} id         The test description.
  * @param {Number} timeLimit  The initial setting for the request timeout.
  * @param {Number} resetAfter (Optional) The time after sending the request, to
@@ -325,17 +318,17 @@ var TestCounter = {
 
   next: function() {
     var test = TestRequests.shift();
 
     if (test) {
       test.startXHR();
     }
     else {
-      message("done");
+      self.postMessage("done", "*");
     }
   }
 };
 
 self.addEventListener("message", function (event) {
   if (event.data == "start") {
     TestCounter.next();
   }
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -46,44 +46,47 @@ nsStructuredCloneContainer::InitFromVari
   // First, try to extract a jsval from the variant |aData|.  This works only
   // if the variant implements GetAsJSVal.
   jsval jsData;
   nsresult rv = aData->GetAsJSVal(&jsData);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
   // Make sure that we serialize in the right context.
   JSAutoRequest ar(aCx);
-  JSAutoCompartment ac(aCx, JS_GetGlobalObject(aCx));
+ JSAutoCompartment ac(aCx, JS_GetGlobalObject(aCx));
   JS_WrapValue(aCx, &jsData);
 
   nsCxPusher cxPusher;
   cxPusher.Push(aCx);
 
   uint64_t* jsBytes = nullptr;
   bool success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize,
-                                           nullptr, nullptr, JSVAL_VOID);
+                                           nullptr, nullptr);
   NS_ENSURE_STATE(success);
   NS_ENSURE_STATE(jsBytes);
 
   // Copy jsBytes into our own buffer.
   mData = (uint64_t*) malloc(mSize);
   if (!mData) {
     mSize = 0;
     mVersion = 0;
 
-    JS_ClearStructuredClone(jsBytes, mSize);
+    // FIXME This should really be js::Foreground::Free, but that's not public.
+    JS_free(aCx, jsBytes);
+
     return NS_ERROR_FAILURE;
   }
   else {
     mVersion = JS_STRUCTURED_CLONE_VERSION;
   }
 
   memcpy(mData, jsBytes, mSize);
 
-  JS_ClearStructuredClone(jsBytes, mSize);
+  // FIXME Similarly, this should be js::Foreground::free.
+  JS_free(aCx, jsBytes);
   return NS_OK;
 }
 
 nsresult
 nsStructuredCloneContainer::InitFromBase64(const nsAString &aData,
                                            uint32_t aFormatVersion,
                                            JSContext *aCx)
 {
@@ -111,24 +114,19 @@ nsStructuredCloneContainer::DeserializeT
                                                  nsIVariant **aData)
 {
   NS_ENSURE_STATE(mData);
   NS_ENSURE_ARG_POINTER(aData);
   *aData = nullptr;
 
   // Deserialize to a jsval.
   jsval jsStateObj;
-  JSBool hasTransferable;
   bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion,
-                                          &jsStateObj, nullptr, nullptr) &&
-                 JS_StructuredCloneHasTransferables(mData, mSize,
-                                                    &hasTransferable);
-  // We want to be sure that mData doesn't contain transferable objects
-  MOZ_ASSERT(!hasTransferable);
-  NS_ENSURE_STATE(success && !hasTransferable);
+                                          &jsStateObj, nullptr, nullptr);
+  NS_ENSURE_STATE(success);
 
   // Now wrap the jsval as an nsIVariant.
   nsCOMPtr<nsIVariant> varStateObj;
   nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
   NS_ENSURE_STATE(xpconnect);
   xpconnect->JSValToVariant(aCx, &jsStateObj, getter_AddRefs(varStateObj));
   NS_ENSURE_STATE(varStateObj);
 
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -161,17 +161,17 @@ JSStructuredCloneCallbacks gCallbacks = 
 };
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 
 bool
-ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength,
+ReadStructuredClone(JSContext* aCx, const uint64_t* aData, size_t aDataLength,
                     const StructuredCloneClosure& aClosure, JS::Value* aClone)
 {
   void* closure = &const_cast<StructuredCloneClosure&>(aClosure);
   return !!JS_ReadStructuredClone(aCx, aData, aDataLength,
                                   JS_STRUCTURED_CLONE_VERSION, aClone,
                                   &gCallbacks, closure);
 }
 
--- a/dom/ipc/StructuredCloneUtils.h
+++ b/dom/ipc/StructuredCloneUtils.h
@@ -29,17 +29,17 @@ StructuredCloneData
 {
   StructuredCloneData() : mData(nullptr), mDataLength(0) {}
   uint64_t* mData;
   size_t mDataLength;
   StructuredCloneClosure mClosure;
 };
 
 bool
-ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength,
+ReadStructuredClone(JSContext* aCx, const uint64_t* aData, size_t aDataLength,
                     const StructuredCloneClosure& aClosure, JS::Value* aClone);
 
 inline bool
 ReadStructuredClone(JSContext* aCx, const StructuredCloneData& aData,
                     JS::Value* aClone)
 {
   return ReadStructuredClone(aCx, aData.mData, aData.mDataLength,
                              aData.mClosure, aClone);
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -281,23 +281,21 @@ private:
 
     const char*& name = sFunctions[1].name;
     WorkerPrivate* worker = GetInstancePrivate(aCx, obj, name);
     if (!worker) {
       return !JS_IsExceptionPending(aCx);
     }
 
     jsval message;
-    jsval transferable = JSVAL_VOID;
-    if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/v",
-                             &message, &transferable)) {
+    if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &message)) {
       return false;
     }
 
-    return worker->PostMessage(aCx, message, transferable);
+    return worker->PostMessage(aCx, message);
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
 // When this DOMJSClass is removed and it's the last consumer of
 // sNativePropertyHooks then sNativePropertyHooks should be removed too.
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2226,18 +2226,17 @@ WorkerPrivateParent<Derived>::ForgetMain
   SwapToISupportsArray(mPrincipal, aDoomed);
   SwapToISupportsArray(mCSP, aDoomed);
 
   mMainThreadObjectsForgotten = true;
 }
 
 template <class Derived>
 bool
-WorkerPrivateParent<Derived>::PostMessage(JSContext* aCx, jsval aMessage,
-                                          jsval aTransferable)
+WorkerPrivateParent<Derived>::PostMessage(JSContext* aCx, jsval aMessage)
 {
   AssertIsOnParentThread();
 
   {
     MutexAutoLock lock(mMutex);
     if (mParentStatus != Running) {
       return true;
     }
@@ -2261,17 +2260,17 @@ WorkerPrivateParent<Derived>::PostMessag
     else {
       callbacks = &gMainThreadWorkerStructuredCloneCallbacks;
     }
   }
 
   nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
 
   JSAutoStructuredCloneBuffer buffer;
-  if (!buffer.write(aCx, aMessage, aTransferable, callbacks, &clonedObjects)) {
+  if (!buffer.write(aCx, aMessage, callbacks, &clonedObjects)) {
     return false;
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(ParentAsWorkerPrivate(),
                              WorkerRunnable::WorkerThread, buffer,
                              clonedObjects);
   return runnable->Dispatch(aCx);
@@ -3418,30 +3417,29 @@ WorkerPrivate::StopSyncLoop(uint32_t aSy
 
   NS_ASSERTION(!syncQueue->mComplete, "Already called StopSyncLoop?!");
 
   syncQueue->mResult = aSyncResult;
   syncQueue->mComplete = true;
 }
 
 bool
-WorkerPrivate::PostMessageToParent(JSContext* aCx, jsval aMessage,
-                                   jsval aTransferable)
+WorkerPrivate::PostMessageToParent(JSContext* aCx, jsval aMessage)
 {
   AssertIsOnWorkerThread();
 
   JSStructuredCloneCallbacks* callbacks =
     IsChromeWorker() ?
     &gChromeWorkerStructuredCloneCallbacks :
     &gWorkerStructuredCloneCallbacks;
 
   nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
 
   JSAutoStructuredCloneBuffer buffer;
-  if (!buffer.write(aCx, aMessage, aTransferable, callbacks, &clonedObjects)) {
+  if (!buffer.write(aCx, aMessage, callbacks, &clonedObjects)) {
     return false;
   }
 
   nsRefPtr<MessageEventRunnable> runnable =
     new MessageEventRunnable(this, WorkerRunnable::ParentThread, buffer,
                              clonedObjects);
   return runnable->Dispatch(aCx);
 }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -289,17 +289,17 @@ public:
 
   bool
   RootJSObject(JSContext* aCx, bool aRoot);
 
   void
   ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
 
   bool
-  PostMessage(JSContext* aCx, jsval aMessage, jsval aTransferable);
+  PostMessage(JSContext* aCx, jsval aMessage);
 
   uint64_t
   GetInnerWindowId();
 
   void
   UpdateJSContextOptions(JSContext* aCx, uint32_t aOptions);
 
   void
@@ -657,18 +657,17 @@ public:
 
   bool
   RunSyncLoop(JSContext* aCx, uint32_t aSyncLoopKey);
 
   void
   StopSyncLoop(uint32_t aSyncLoopKey, bool aSyncResult);
 
   bool
-  PostMessageToParent(JSContext* aCx, jsval aMessage,
-                      jsval transferable);
+  PostMessageToParent(JSContext* aCx, jsval aMessage);
 
   bool
   NotifyInternal(JSContext* aCx, Status aStatus);
 
   void
   ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport);
 
   bool
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -834,23 +834,21 @@ private:
 
     const char*& name = sFunctions[0].name;
     DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, obj, name);
     if (!scope) {
       return false;
     }
 
     jsval message;
-    jsval transferable = JSVAL_VOID;
-    if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/v",
-                             &message, &transferable)) {
+    if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &message)) {
       return false;
     }
 
-    return scope->mWorker->PostMessageToParent(aCx, message, transferable);
+    return scope->mWorker->PostMessageToParent(aCx, message);
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
 
 // When this DOMJSClass is removed and it's the last consumer of
 // sNativePropertyHooks then sNativePropertyHooks should be removed too.
--- a/dom/workers/test/Makefile.in
+++ b/dom/workers/test/Makefile.in
@@ -95,18 +95,16 @@ MOCHITEST_FILES = \
   test_xhr_parameters.js \
   test_xhr_system.html \
   test_xhr_system.js \
   test_blobConstructor.html \
   test_csp.html \
   test_csp.js \
   test_csp.html^headers^ \
   csp_worker.js \
-  test_transferable.html \
-  transferable_worker.js \
   $(NULL)
 
 _SUBDIRMOCHITEST_FILES = \
   relativeLoad_sub_worker.js \
   relativeLoad_sub_worker2.js \
   relativeLoad_sub_import.js \
   $(NULL)
 
deleted file mode 100644
--- a/dom/workers/test/test_transferable.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<!DOCTYPE HTML>
-<html>
-<!--
-Tests of DOM Worker transferable objects
--->
-<head>
-  <title>Test for DOM Worker transferable objects</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-</head>
-<body>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script class="testbody" language="javascript">
-
-  function test1(sizes) {
-    if (!sizes.length) {
-      SimpleTest.finish();
-      return;
-    }
-
-    var size = sizes.pop();
-
-    var worker = new Worker("transferable_worker.js");
-    worker.onmessage = function(event) {
-      ok(event.data.status, event.data.event);
-      if (!event.data.status) {
-        SimpleTest.finish();
-        return;
-      }
-
-      if (!event.data.last)
-        return;
-
-      test1(sizes);
-    }
-    worker.onerror = function(event) {
-      ok(false, "No errors!");
-    }
-
-    try {
-      worker.postMessage(42, true);
-      ok(false, "P: PostMessage - Exception for wrong type");
-    } catch(e) {
-      ok(true, "P: PostMessage - Exception for wrong type");
-    }
-
-    try {
-      ab = new ArrayBuffer(size);
-      worker.postMessage(42,[ab, ab]);
-      ok(false, "P: PostMessage - Exception for duplicate");
-    } catch(e) {
-      ok(true, "P: PostMessage - Exception for duplicate");
-    }
-
-    ab = new ArrayBuffer(size);
-    ok(ab.byteLength == size, "P: The size is: " + size + " == " + ab.byteLength);
-    worker.postMessage({ data: 0, timeout: 0, ab: ab, cb: ab, size: size }, [ab]);
-    ok(ab.byteLength == 0, "P: PostMessage - The size is: 0 == " + ab.byteLength)
-  }
-
-  test1([1024 * 1024 * 32, 128, 4]);
-  SimpleTest.waitForExplicitFinish();
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/workers/test/transferable_worker.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-onmessage = function(event) {
-  if (event.data.data == 0) {
-    ab = new ArrayBuffer(event.data.size);
-    postMessage({ event: "W: The size is: " + event.data.size + " == " + ab.byteLength,
-                  status: ab.byteLength == event.data.size, last: false });
-
-    postMessage({ event: "W: postMessage with arrayBuffer", status: true,
-                  ab: ab, bc: [ ab, ab, { dd: ab } ] }, [ab]);
-
-    postMessage({ event: "W: The size is: 0 == " + ab.byteLength,
-                  status: ab.byteLength == 0, last: false });
-
-    postMessage({ event: "last one!", status: true, last: true });
-
-  } else {
-    var worker = new Worker('sync_worker.js');
-    worker.onmessage = function(event) {
-      postMessage(event.data);
-    }
-    worker.onsyncmessage = function(event) {
-      var v = postSyncMessage(event.data, null, 500);
-      event.reply(v);
-    }
-
-    --event.data.data;
-    worker.postMessage(event.data);
-  }
-}
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6401,17 +6401,17 @@ JS_ParseJSONWithReviver(JSContext *cx, c
     if (!ParseJSONWithReviver(cx, chars, len, reviver, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_ReadStructuredClone(JSContext *cx, uint64_t *buf, size_t nbytes,
+JS_ReadStructuredClone(JSContext *cx, const uint64_t *buf, size_t nbytes,
                        uint32_t version, jsval *vp,
                        const JSStructuredCloneCallbacks *optionalCallbacks,
                        void *closure)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     if (version > JS_STRUCTURED_CLONE_VERSION) {
@@ -6423,47 +6423,28 @@ JS_ReadStructuredClone(JSContext *cx, ui
         optionalCallbacks :
         cx->runtime->structuredCloneCallbacks;
     return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_WriteStructuredClone(JSContext *cx, jsval valueArg, uint64_t **bufp, size_t *nbytesp,
                         const JSStructuredCloneCallbacks *optionalCallbacks,
-                        void *closure, jsval transferable)
+                        void *closure)
 {
     RootedValue value(cx, valueArg);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value);
 
     const JSStructuredCloneCallbacks *callbacks =
         optionalCallbacks ?
         optionalCallbacks :
         cx->runtime->structuredCloneCallbacks;
-    return WriteStructuredClone(cx, valueArg, (uint64_t **) bufp, nbytesp,
-                                callbacks, closure, transferable);
-}
-
-JS_PUBLIC_API(JSBool)
-JS_ClearStructuredClone(const uint64_t *data, size_t nbytes)
-{
-    return ClearStructuredClone(data, nbytes);
-}
-
-JS_PUBLIC_API(JSBool)
-JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
-                                   JSBool *hasTransferable)
-{
-    bool transferable;
-    if (!StructuredCloneHasTransferObjects(data, nbytes, &transferable))
-        return false;
-
-    *hasTransferable = transferable;
-    return true;
+    return WriteStructuredClone(cx, value, (uint64_t **) bufp, nbytesp, callbacks, closure);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_StructuredClone(JSContext *cx, jsval valueArg, jsval *vp,
                    const JSStructuredCloneCallbacks *optionalCallbacks,
                    void *closure)
 {
     RootedValue value(cx, valueArg);
@@ -6479,17 +6460,17 @@ JS_StructuredClone(JSContext *cx, jsval 
     return buf.write(cx, value, callbacks, closure) &&
            buf.read(cx, vp, callbacks, closure);
 }
 
 void
 JSAutoStructuredCloneBuffer::clear()
 {
     if (data_) {
-        ClearStructuredClone(data_, nbytes_);
+        js_free(data_);
         data_ = NULL;
         nbytes_ = 0;
         version_ = 0;
     }
 }
 
 void
 JSAutoStructuredCloneBuffer::adopt(uint64_t *data, size_t nbytes, uint32_t version)
@@ -6498,22 +6479,16 @@ JSAutoStructuredCloneBuffer::adopt(uint6
     data_ = data;
     nbytes_ = nbytes;
     version_ = version;
 }
 
 bool
 JSAutoStructuredCloneBuffer::copy(const uint64_t *srcData, size_t nbytes, uint32_t version)
 {
-    // transferable objects cannot be copied
-    bool hasTransferable;
-    if (!StructuredCloneHasTransferObjects(data_, nbytes_, &hasTransferable) ||
-        hasTransferable)
-        return false;
-
     uint64_t *newData = static_cast<uint64_t *>(js_malloc(nbytes));
     if (!newData)
         return false;
 
     js_memcpy(newData, srcData, nbytes);
 
     clear();
     data_ = newData;
@@ -6532,44 +6507,33 @@ JSAutoStructuredCloneBuffer::steal(uint6
     data_ = NULL;
     nbytes_ = 0;
     version_ = 0;
 }
 
 bool
 JSAutoStructuredCloneBuffer::read(JSContext *cx, jsval *vp,
                                   const JSStructuredCloneCallbacks *optionalCallbacks,
-                                  void *closure)
+                                  void *closure) const
 {
     JS_ASSERT(cx);
     JS_ASSERT(data_);
     return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
                                     optionalCallbacks, closure);
 }
 
 bool
 JSAutoStructuredCloneBuffer::write(JSContext *cx, jsval valueArg,
                                    const JSStructuredCloneCallbacks *optionalCallbacks,
                                    void *closure)
 {
-    jsval transferable = JSVAL_VOID;
-    return write(cx, valueArg, transferable, optionalCallbacks, closure);
-}
-
-bool
-JSAutoStructuredCloneBuffer::write(JSContext *cx, jsval valueArg,
-                                   jsval transferable,
-                                   const JSStructuredCloneCallbacks *optionalCallbacks,
-                                   void *closure)
-{
     RootedValue value(cx, valueArg);
     clear();
     bool ok = !!JS_WriteStructuredClone(cx, value, &data_, &nbytes_,
-                                        optionalCallbacks, closure,
-                                        transferable);
+                                        optionalCallbacks, closure);
     if (!ok) {
         data_ = NULL;
         nbytes_ = 0;
         version_ = JS_STRUCTURED_CLONE_VERSION;
     }
     return ok;
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2038,19 +2038,19 @@ typedef JSObject *(*ReadStructuredCloneO
  * writer w. closure is any value passed to the JS_WriteStructuredCLone function.
  *
  * Return true on success, false on error/exception.
  */
 typedef JSBool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w,
                                          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.
+ * This is called when JS_WriteStructuredClone finds that the object to be
+ * written is recursive. To follow HTML5, the application must throw a
+ * DATA_CLONE_ERR DOMException. errorid is always JS_SCERR_RECURSION.
  */
 typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid);
 
 /************************************************************************/
 
 JS_BEGIN_EXTERN_C
 
 /*
@@ -5700,37 +5700,27 @@ JS_ParseJSONWithReviver(JSContext *cx, c
 #define JS_STRUCTURED_CLONE_VERSION 1
 
 struct JSStructuredCloneCallbacks {
     ReadStructuredCloneOp read;
     WriteStructuredCloneOp write;
     StructuredCloneErrorOp reportError;
 };
 
-/* Note: if the *data contains transferable objects, it can be read
- * only once */
 JS_PUBLIC_API(JSBool)
-JS_ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes,
+JS_ReadStructuredClone(JSContext *cx, const uint64_t *data, size_t nbytes,
                        uint32_t version, jsval *vp,
                        const JSStructuredCloneCallbacks *optionalCallbacks,
                        void *closure);
 
-/* Note: On success, the caller is responsible for calling
- * JS_ClearStructuredClone(*datap, nbytesp). */
+/* Note: On success, the caller is responsible for calling js::Foreground::free(*datap). */
 JS_PUBLIC_API(JSBool)
 JS_WriteStructuredClone(JSContext *cx, jsval v, uint64_t **datap, size_t *nbytesp,
                         const JSStructuredCloneCallbacks *optionalCallbacks,
-                        void *closure, jsval transferable);
-
-JS_PUBLIC_API(JSBool)
-JS_ClearStructuredClone(const uint64_t *data, size_t nbytes);
-
-JS_PUBLIC_API(JSBool)
-JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
-                                   JSBool *hasTransferable);
+                        void *closure);
 
 JS_PUBLIC_API(JSBool)
 JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
                    const JSStructuredCloneCallbacks *optionalCallbacks,
                    void *closure);
 
 #ifdef __cplusplus
 JS_END_EXTERN_C
@@ -5766,27 +5756,22 @@ class JS_PUBLIC_API(JSAutoStructuredClon
      * Remove the buffer so that it will not be automatically freed.
      * After this, the caller is responsible for feeding the memory back to
      * JSAutoStructuredCloneBuffer::adopt.
      */
     void steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp=NULL);
 
     bool read(JSContext *cx, jsval *vp,
               const JSStructuredCloneCallbacks *optionalCallbacks=NULL,
-              void *closure=NULL);
+              void *closure=NULL) const;
 
     bool write(JSContext *cx, jsval v,
                const JSStructuredCloneCallbacks *optionalCallbacks=NULL,
                void *closure=NULL);
 
-    bool write(JSContext *cx, jsval v,
-               jsval transferable,
-               const JSStructuredCloneCallbacks *optionalCallbacks=NULL,
-               void *closure=NULL);
-
     /**
      * Swap ownership with another JSAutoStructuredCloneBuffer.
      */
     void swap(JSAutoStructuredCloneBuffer &other);
 
   private:
     /* Copy and assignment are not supported. */
     JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other);
@@ -5798,17 +5783,16 @@ JS_BEGIN_EXTERN_C
 
 /* API for implementing custom serialization behavior (for ImageData, File, etc.) */
 
 /* The range of tag values the application may use for its own custom object types. */
 #define JS_SCTAG_USER_MIN  ((uint32_t) 0xFFFF8000)
 #define JS_SCTAG_USER_MAX  ((uint32_t) 0xFFFFFFFF)
 
 #define JS_SCERR_RECURSION 0
-#define JS_SCERR_TRANSFERABLE 1
 
 JS_PUBLIC_API(void)
 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks);
 
 JS_PUBLIC_API(JSBool)
 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
 
 JS_PUBLIC_API(JSBool)
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -13,16 +13,49 @@
 
 #include "vm/BooleanObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
 
+JS_FRIEND_API(uint64_t)
+js_GetSCOffset(JSStructuredCloneWriter* writer)
+{
+    JS_ASSERT(writer);
+    return writer->output().count() * sizeof(uint64_t);
+}
+
+namespace js {
+
+bool
+WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp,
+                     const JSStructuredCloneCallbacks *cb, void *cbClosure)
+{
+    SCOutput out(cx);
+    JSStructuredCloneWriter w(out, cb, cbClosure);
+    return w.init() && w.write(v) && out.extractBuffer(bufp, nbytesp);
+}
+
+bool
+ReadStructuredClone(JSContext *cx, const uint64_t *data, size_t nbytes, Value *vp,
+                    const JSStructuredCloneCallbacks *cb, void *cbClosure)
+{
+    SCInput in(cx, data, nbytes);
+
+    /* XXX disallow callers from using internal pointers to GC things. */
+    SkipRoot skip(cx, &in);
+
+    JSStructuredCloneReader r(in, cb, cbClosure);
+    return r.read(vp);
+}
+
+} /* namespace js */
+
 enum StructuredDataType {
     /* Structured data types provided by the engine */
     SCTAG_FLOAT_MAX = 0xFFF00000,
     SCTAG_NULL = 0xFFFF0000,
     SCTAG_UNDEFINED,
     SCTAG_BOOLEAN,
     SCTAG_INDEX,
     SCTAG_STRING,
@@ -30,44 +63,30 @@ 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_TRANSFER_MAP_HEADER,
-    SCTAG_TRANSFER_MAP,
     SCTAG_TYPED_ARRAY_MIN = 0xFFFF0100,
     SCTAG_TYPED_ARRAY_INT8 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_INT8,
     SCTAG_TYPED_ARRAY_UINT8 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_UINT8,
     SCTAG_TYPED_ARRAY_INT16 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_INT16,
     SCTAG_TYPED_ARRAY_UINT16 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_UINT16,
     SCTAG_TYPED_ARRAY_INT32 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_INT32,
     SCTAG_TYPED_ARRAY_UINT32 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_UINT32,
     SCTAG_TYPED_ARRAY_FLOAT32 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_FLOAT32,
     SCTAG_TYPED_ARRAY_FLOAT64 = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_FLOAT64,
     SCTAG_TYPED_ARRAY_UINT8_CLAMPED = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_UINT8_CLAMPED,
     SCTAG_TYPED_ARRAY_MAX = SCTAG_TYPED_ARRAY_MIN + TypedArray::TYPE_MAX - 1,
     SCTAG_END_OF_BUILTIN_TYPES
 };
 
-enum TransferableMapHeader {
-    SCTAG_TM_NOT_MARKED = 0,
-    SCTAG_TM_MARKED
-};
-
-JS_FRIEND_API(uint64_t)
-js_GetSCOffset(JSStructuredCloneWriter* writer)
-{
-    JS_ASSERT(writer);
-    return writer->output().count() * sizeof(uint64_t);
-}
-
 static StructuredDataType
 ArrayTypeToTag(uint32_t type)
 {
     JS_ASSERT(type < TypedArray::TYPE_MAX);
     return static_cast<StructuredDataType>(uint32_t(SCTAG_TYPED_ARRAY_MIN) + type);
 }
 
 JS_STATIC_ASSERT(SCTAG_END_OF_BUILTIN_TYPES <= JS_SCTAG_USER_MIN);
@@ -115,99 +134,24 @@ SwapBytes(uint64_t u)
            ((u & 0x0000ff0000000000LLU) >> 24) |
            ((u & 0x00ff000000000000LLU) >> 40) |
            ((u & 0xff00000000000000LLU) >> 56);
 #else
     return u;
 #endif
 }
 
-namespace js {
-
-bool
-WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp,
-                     const JSStructuredCloneCallbacks *cb, void *cbClosure,
-                     jsval transferable)
-{
-    SCOutput out(cx);
-    JSStructuredCloneWriter w(out, cb, cbClosure, transferable);
-    return w.init() && w.write(v) && out.extractBuffer(bufp, nbytesp);
-}
-
-bool
-ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
-                    const JSStructuredCloneCallbacks *cb, void *cbClosure)
-{
-    SCInput in(cx, data, nbytes);
-
-    /* XXX disallow callers from using internal pointers to GC things. */
-    SkipRoot skip(cx, &in);
-
-    JSStructuredCloneReader r(in, cb, cbClosure);
-    return r.read(vp);
-}
-
-bool
-ClearStructuredClone(const uint64_t *data, size_t nbytes)
-{
-    const uint64_t *point = data;
-    const uint64_t *end = data + nbytes / 8;
-
-    uint64_t u = SwapBytes(*point++);
-    uint32_t tag = uint32_t(u >> 32);
-    if (tag == SCTAG_TRANSFER_MAP_HEADER) {
-        if ((TransferableMapHeader)uint32_t(u) == SCTAG_TM_NOT_MARKED) {
-            while (point != end) {
-                uint64_t u = SwapBytes(*point++);
-                uint32_t tag = uint32_t(u >> 32);
-                if (tag == SCTAG_TRANSFER_MAP) {
-                    u = SwapBytes(*point++);
-                    js_free(reinterpret_cast<void*>(u));
-                }
-            }
-        }
-    }
-
-    js_free((void *)data);
-    return true;
-}
-
-bool
-StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes,
-                                  bool *hasTransferable)
-{
-    *hasTransferable = false;
-
-    if (data) {
-        uint64_t u = SwapBytes(*data);
-        uint32_t tag = uint32_t(u >> 32);
-        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
 SCInput::eof()
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "truncated");
     return false;
 }
 
-SCInput::SCInput(JSContext *cx, uint64_t *data, size_t nbytes)
+SCInput::SCInput(JSContext *cx, const uint64_t *data, size_t nbytes)
     : cx(cx), point(data), end(data + nbytes / 8)
 {
     JS_ASSERT((uintptr_t(data) & 7) == 0);
     JS_ASSERT((nbytes & 7) == 0);
 }
 
 bool
 SCInput::read(uint64_t *p)
@@ -225,52 +169,16 @@ SCInput::readPair(uint32_t *tagp, uint32
     bool ok = read(&u);
     if (ok) {
         *tagp = uint32_t(u >> 32);
         *datap = uint32_t(u);
     }
     return ok;
 }
 
-bool
-SCInput::get(uint64_t *p)
-{
-    if (point == end)
-        return eof();
-    *p = SwapBytes(*point);
-    return true;
-}
-
-bool
-SCInput::getPair(uint32_t *tagp, uint32_t *datap)
-{
-    uint64_t u;
-    if (!get(&u))
-        return false;
-
-    *tagp = uint32_t(u >> 32);
-    *datap = uint32_t(u);
-    return true;
-}
-
-bool
-SCInput::replace(uint64_t u)
-{
-    if (point == end)
-       return eof();
-    *point = SwapBytes(u);
-    return true;
-}
-
-bool
-SCInput::replacePair(uint32_t tag, uint32_t data)
-{
-    return replace(PairToUInt64(tag, data));
-}
-
 /*
  * The purpose of this never-inlined function is to avoid a strange g++ build
  * error on OS X 10.5 (see bug 624080).  :-(
  */
 static JS_NEVER_INLINE double
 CanonicalizeNan(double d)
 {
     return JS_CANONICALIZE_NAN(d);
@@ -323,30 +231,30 @@ SCInput::readBytes(void *p, size_t nbyte
 
 bool
 SCInput::readChars(jschar *p, size_t nchars)
 {
     JS_ASSERT(sizeof(jschar) == sizeof(uint16_t));
     return readArray((uint16_t *) p, nchars);
 }
 
-bool
-SCInput::readPtr(void **p)
-{
-    return read((uint64_t *)p);
-}
-
 SCOutput::SCOutput(JSContext *cx) : cx(cx), buf(cx) {}
 
 bool
 SCOutput::write(uint64_t u)
 {
     return buf.append(SwapBytes(u));
 }
 
+static inline uint64_t
+PairToUInt64(uint32_t tag, uint32_t data)
+{
+    return uint64_t(data) | (uint64_t(tag) << 32);
+}
+
 bool
 SCOutput::writePair(uint32_t tag, uint32_t data)
 {
     /*
      * As it happens, the tag word appears after the data word in the output.
      * This is because exponents occupy the last 2 bytes of doubles on the
      * little-endian platforms we care most about.
      *
@@ -432,92 +340,25 @@ SCOutput::writeBytes(const void *p, size
 bool
 SCOutput::writeChars(const jschar *p, size_t nchars)
 {
     JS_ASSERT(sizeof(jschar) == sizeof(uint16_t));
     return writeArray((const uint16_t *) p, nchars);
 }
 
 bool
-SCOutput::writePtr(const void *p)
-{
-    return write(reinterpret_cast<uint64_t>(p));
-}
-
-bool
 SCOutput::extractBuffer(uint64_t **datap, size_t *sizep)
 {
     *sizep = buf.length() * sizeof(uint64_t);
     return (*datap = buf.extractRawBuffer()) != NULL;
 }
 
 JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
 
 bool
-JSStructuredCloneWriter::parseTransferable()
-{
-    transferableObjects.clear();
-
-    if (JSVAL_IS_NULL(transferable) || JSVAL_IS_VOID(transferable))
-        return true;
-
-    if (!transferable.isObject()) {
-        reportErrorTransferable();
-        return false;
-    }
-
-    JSObject* array = &transferable.toObject();
-    if (!JS_IsArrayObject(context(), array)) {
-        reportErrorTransferable();
-        return false;
-    }
-
-    uint32_t length;
-    if (!JS_GetArrayLength(context(), array, &length)) {
-        return false;
-    }
-
-    for (uint32_t i = 0; i < length; ++i) {
-        Value v;
-        if (!JS_GetElement(context(), array, i, &v)) {
-            return false;
-        }
-
-        if (!v.isObject()) {
-            reportErrorTransferable();
-            return false;
-        }
-
-        JSObject* tObj = &v.toObject();
-        if (!tObj->isArrayBuffer()) {
-            reportErrorTransferable();
-            return false;
-        }
-
-        // No duplicate:
-        if (transferableObjects.has(tObj)) {
-            reportErrorTransferable();
-            return false;
-        }
-
-        if (!transferableObjects.putNew(tObj))
-            return false;
-    }
-
-    return true;
-}
-
-void
-JSStructuredCloneWriter::reportErrorTransferable()
-{
-    if (callbacks && callbacks->reportError)
-        return callbacks->reportError(context(), JS_SCERR_TRANSFERABLE);
-}
-
-bool
 JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
 {
     size_t length = str->length();
     const jschar *chars = str->getChars(context());
     if (!chars)
         return false;
     return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length);
 }
@@ -708,42 +549,16 @@ JSStructuredCloneWriter::startWrite(cons
         /* else fall through */
     }
 
     JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_UNSUPPORTED_TYPE);
     return false;
 }
 
 bool
-JSStructuredCloneWriter::writeTransferMap()
-{
-    if (!transferableObjects.empty()) {
-        if (!out.writePair(SCTAG_TRANSFER_MAP_HEADER, (uint32_t)SCTAG_TM_NOT_MARKED))
-            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;
-            if (!JS_StealArrayBufferContents(context(), obj, &content))
-               return false;
-
-            if (!out.writePair(SCTAG_TRANSFER_MAP, 0) || !out.writePtr(content))
-                return false;
-        }
-    }
-
-    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);
@@ -1029,30 +844,16 @@ JSStructuredCloneReader::startRead(Value
                                  JSMSG_SC_BAD_SERIALIZED_DATA,
                                  "invalid back reference in input");
             return false;
         }
         *vp = allObjs[data];
         return true;
       }
 
-      case SCTAG_TRANSFER_MAP_HEADER:
-        // A map header cannot be here but just at the beginning of the buffer.
-        JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL,
-                             JSMSG_SC_BAD_SERIALIZED_DATA,
-                             "invalid input");
-        return false;
-
-      case SCTAG_TRANSFER_MAP:
-        // A map cannot be here but just at the beginning of the buffer.
-        JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL,
-                             JSMSG_SC_BAD_SERIALIZED_DATA,
-                             "invalid input");
-        return false;
-
       case SCTAG_ARRAY_BUFFER_OBJECT:
         if (!readArrayBuffer(data, vp))
             return false;
         break;
 
       default: {
         if (tag <= SCTAG_FLOAT_MAX) {
             double d = ReinterpretPairAsDouble(tag, data);
@@ -1111,58 +912,18 @@ JSStructuredCloneReader::readId(jsid *id
         *idp = JSID_VOID;
         return true;
     }
     JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, "id");
     return false;
 }
 
 bool
-JSStructuredCloneReader::readTransferMap()
-{
-    uint32_t tag, data;
-    if (!in.getPair(&tag, &data))
-        return false;
-
-    if (tag != SCTAG_TRANSFER_MAP_HEADER ||
-        (TransferableMapHeader)data == SCTAG_TM_MARKED)
-        return true;
-
-    if (!in.replacePair(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_MARKED))
-        return false;
-
-    if (!in.readPair(&tag, &data))
-        return false;
-
-    while (1) {
-        if (!in.getPair(&tag, &data))
-            return false;
-
-        if (tag != SCTAG_TRANSFER_MAP)
-            break;
-
-        void *content;
-
-        if (!in.readPair(&tag, &data) || !in.readPtr(&content))
-            return false;
-
-        JSObject *obj = JS_NewArrayBufferWithContents(context(), content);
-        if (!obj || !allObjs.append(ObjectValue(*obj)))
-            return false;
-    }
-
-    return true;
-}
-
-bool
 JSStructuredCloneReader::read(Value *vp)
 {
-    if (!readTransferMap())
-        return false;
-
     if (!startRead(vp))
         return false;
 
     while (objs.length() != 0) {
         RootedObject obj(context(), &objs.back().toObject());
 
         RootedId id(context());
         if (!readId(id.address()))
--- a/js/src/jsclone.h
+++ b/js/src/jsclone.h
@@ -11,89 +11,73 @@
 
 #include "js/HashTable.h"
 #include "js/Vector.h"
 
 namespace js {
 
 bool
 WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp,
-                     const JSStructuredCloneCallbacks *cb, void *cbClosure,
-                     jsval transferable);
+                     const JSStructuredCloneCallbacks *cb, void *cbClosure);
 
 bool
-ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
+ReadStructuredClone(JSContext *cx, const uint64_t *data, size_t nbytes, Value *vp,
                     const JSStructuredCloneCallbacks *cb, void *cbClosure);
 
-bool
-ClearStructuredClone(const uint64_t *data, size_t nbytes);
-
-bool
-StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes,
-                                  bool *hasTransferable);
-
 struct SCOutput {
   public:
     explicit SCOutput(JSContext *cx);
 
     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() { return buf.length(); }
 
   private:
     JSContext *cx;
     js::Vector<uint64_t> buf;
 };
 
 struct SCInput {
   public:
-    SCInput(JSContext *cx, uint64_t *data, size_t nbytes);
+    SCInput(JSContext *cx, const uint64_t *data, size_t nbytes);
 
     JSContext *context() const { return cx; }
 
     bool read(uint64_t *p);
     bool readPair(uint32_t *tagp, uint32_t *datap);
     bool readDouble(double *p);
     bool readBytes(void *p, size_t nbytes);
     bool readChars(jschar *p, size_t nchars);
-    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);
 
     template <class T>
     bool readArray(T *p, size_t nelems);
 
   private:
     bool eof();
 
     void staticAssertions() {
         JS_STATIC_ASSERT(sizeof(jschar) == 2);
         JS_STATIC_ASSERT(sizeof(uint32_t) == 4);
         JS_STATIC_ASSERT(sizeof(double) == 8);
     }
 
     JSContext *cx;
-    uint64_t *point;
-    uint64_t *end;
+    const uint64_t *point;
+    const uint64_t *end;
 };
 
 }
 
 struct JSStructuredCloneReader {
   public:
     explicit JSStructuredCloneReader(js::SCInput &in, const JSStructuredCloneCallbacks *cb,
                                      void *cbClosure)
@@ -101,18 +85,16 @@ struct JSStructuredCloneReader {
           callbacks(cb), closure(cbClosure) { }
 
     js::SCInput &input() { return in; }
     bool read(js::Value *vp);
 
   private:
     JSContext *context() { return in.context(); }
 
-    bool readTransferMap();
-
     bool checkDouble(double d);
     JSString *readString(uint32_t nchars);
     bool readTypedArray(uint32_t tag, uint32_t nelems, js::Value *vp);
     bool readArrayBuffer(uint32_t nbytes, js::Value *vp);
     bool readId(jsid *idp);
     bool startRead(js::Value *vp);
 
     js::SCInput &in;
@@ -129,48 +111,38 @@ struct JSStructuredCloneReader {
     // Any value passed to JS_ReadStructuredClone.
     void *closure;
 
     friend JSBool JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp);
 };
 
 struct JSStructuredCloneWriter {
   public:
-    explicit JSStructuredCloneWriter(js::SCOutput &out,
-                                     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(tVal), transferableObjects(out.context()) { }
+    explicit JSStructuredCloneWriter(js::SCOutput &out, const JSStructuredCloneCallbacks *cb,
+                                     void *cbClosure)
+        : out(out), objs(out.context()), counts(out.context()), ids(out.context()),
+          memory(out.context()), callbacks(cb), closure(cbClosure) { }
 
-    bool init() { return transferableObjects.init() && parseTransferable() &&
-                         memory.init() && writeTransferMap(); }
+    bool init() { return memory.init(); }
 
     bool write(const js::Value &v);
 
     js::SCOutput &output() { return out; }
 
   private:
     JSContext *context() { return out.context(); }
 
-    bool writeTransferMap();
-
     bool writeString(uint32_t tag, JSString *str);
     bool writeId(jsid id);
     bool writeArrayBuffer(JSHandleObject obj);
     bool writeTypedArray(JSHandleObject obj);
     bool startObject(JSHandleObject obj, bool *backref);
     bool startWrite(const js::Value &v);
     bool traverseObject(JSHandleObject obj);
 
-    bool parseTransferable();
-    void reportErrorTransferable();
-
     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
     // entered before any manipulation is performed.
@@ -190,16 +162,12 @@ struct JSStructuredCloneWriter {
     CloneMemory memory;
 
     // 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
-    jsval transferable;
-    js::HashSet<JSObject*> transferableObjects;
-
     friend JSBool JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
 };
 
 #endif /* jsclone_h___ */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3285,28 +3285,27 @@ WrapWithProto(JSContext *cx, unsigned ar
 }
 
 static JSBool
 Serialize(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval v = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
     uint64_t *datap;
     size_t nbytes;
-    if (!JS_WriteStructuredClone(cx, v, &datap, &nbytes, NULL, NULL, JSVAL_VOID))
+    if (!JS_WriteStructuredClone(cx, v, &datap, &nbytes, NULL, NULL))
         return false;
 
     JSObject *array = JS_NewUint8Array(cx, nbytes);
     if (!array) {
         JS_free(cx, datap);
         return false;
     }
     JS_ASSERT((uintptr_t(TypedArray::viewData(array)) & 7) == 0);
     js_memcpy(TypedArray::viewData(array), datap, nbytes);
-
-    JS_ClearStructuredClone(datap, nbytes);
+    JS_free(cx, datap);
     JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(array));
     return true;
 }
 
 static JSBool
 Deserialize(JSContext *cx, unsigned argc, jsval *vp)
 {
     Rooted<jsval> v(cx, argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID);