Bug 905017 (part 2, attempt 2) - Move structured clone stuff from jsapi.{h,cpp} and jsclone.{h,cpp} to js/StructuredClone.{h,cpp}. r=billm.
authorNicholas Nethercote <nnethercote@mozilla.com>
Mon, 19 Aug 2013 23:43:47 -0700
changeset 144353 781c291ec961689df23010bfd1d290cb7fb7c91f
parent 144352 dec0efbf0e554dd53d2cd96b2c44934be81c12e8
child 144354 051e287b802fb1beba2b75fe877fdb29c741da87
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersbillm
bugs905017
milestone26.0a1
Bug 905017 (part 2, attempt 2) - Move structured clone stuff from jsapi.{h,cpp} and jsclone.{h,cpp} to js/StructuredClone.{h,cpp}. r=billm.
config/check_spidermonkey_style.py
dom/base/StructuredCloneTags.h
dom/base/nsStructuredCloneContainer.cpp
dom/bluetooth/BluetoothReplyRunnable.h
dom/indexedDB/IndexedDatabase.h
dom/indexedDB/Key.h
dom/ipc/StructuredCloneUtils.cpp
dom/ipc/StructuredCloneUtils.h
dom/workers/Events.h
dom/workers/XMLHttpRequest.h
ipc/glue/IPCMessageUtils.h
js/public/StructuredClone.h
js/public/Value.h
js/src/config/check_spidermonkey_style.py
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsclone.cpp
js/src/jsclone.h
js/src/moz.build
js/src/shell/js.cpp
js/src/vm/StructuredClone.cpp
js/xpconnect/src/Sandbox.cpp
--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -332,17 +332,18 @@ class Include(object):
 
         if not self.inclname.endswith('.h'):
             return 7
 
         # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
         # handling.
         if module == module_name(self.inclname) or \
            module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
-           module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h':
+           module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h' or \
+           module == 'vm/StructuredClone' and self.inclname == 'js/StructuredClone.h':
             return 0
 
         if '/' in self.inclname:
             if self.inclname.startswith('mozilla/'):
                 return 1
 
             if self.inclname.endswith('-inl.h'):
                 return 6
--- a/dom/base/StructuredCloneTags.h
+++ b/dom/base/StructuredCloneTags.h
@@ -1,15 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef StructuredCloneTags_h__
 #define StructuredCloneTags_h__
 
+#include "js/StructuredClone.h"
+
 namespace mozilla {
 namespace dom {
 
 // CHANGING THE ORDER/PLACEMENT OF EXISTING ENUM VALUES MAY BREAK INDEXEDDB.
 // PROCEED WITH EXTREME CAUTION.
 enum StructuredCloneTags {
   SCTAG_BASE = JS_SCTAG_USER_MIN,
 
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -9,16 +9,17 @@
 
 #include "nsCOMPtr.h"
 #include "nsIScriptContext.h"
 #include "nsIVariant.h"
 #include "nsIXPConnect.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
+#include "js/StructuredClone.h"
 
 #include "mozilla/Base64.h"
 
 using namespace mozilla;
 
 NS_IMPL_ADDREF(nsStructuredCloneContainer)
 NS_IMPL_RELEASE(nsStructuredCloneContainer)
 
--- a/dom/bluetooth/BluetoothReplyRunnable.h
+++ b/dom/bluetooth/BluetoothReplyRunnable.h
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 #define mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 
 #include "mozilla/Attributes.h"
 #include "BluetoothCommon.h"
 #include "nsThreadUtils.h"
-#include "jsapi.h"
+#include "js/Value.h"
 
 class nsIDOMDOMRequest;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothReply;
 
 class BluetoothReplyRunnable : public nsRunnable
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_indexeddb_indexeddatabase_h__
 #define mozilla_dom_indexeddb_indexeddatabase_h__
 
 #include "nsIProgrammingLanguage.h"
 
 #include "mozilla/Attributes.h"
-#include "jsapi.h"
+#include "js/StructuredClone.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
 #define BEGIN_INDEXEDDB_NAMESPACE \
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -6,16 +6,18 @@
 
 #ifndef mozilla_dom_indexeddb_key_h__
 #define mozilla_dom_indexeddb_key_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "mozIStorageStatement.h"
 
+#include "js/Value.h"
+
 namespace IPC {
 template <typename T> struct ParamTraits;
 } // namespace IPC
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class Key
 {
@@ -154,17 +156,17 @@ public:
   void SetFromInteger(int64_t aInt)
   {
     mBuffer.Truncate();
     EncodeNumber(double(aInt), eFloat);
     TrimBuffer();
   }
 
   nsresult SetFromJSVal(JSContext* aCx,
-                        const jsval aVal)
+                        const JS::Value aVal)
   {
     mBuffer.Truncate();
 
     if (JSVAL_IS_NULL(aVal) || JSVAL_IS_VOID(aVal)) {
       Unset();
       return NS_OK;
     }
 
@@ -204,17 +206,17 @@ public:
     if (NS_SUCCEEDED(rv)) {
       aVal = value;
     }
     return rv;
   }
 
   nsresult AppendItem(JSContext* aCx,
                       bool aFirstOfArray,
-                      const jsval aVal)
+                      const JS::Value aVal)
   {
     nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0);
     if (NS_FAILED(rv)) {
       Unset();
       return rv;
     }
 
     return NS_OK;
@@ -298,17 +300,17 @@ private:
     while (!*end) {
       --end;
     }
 
     mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
   }
 
   // Encoding functions. These append the encoded value to the end of mBuffer
-  inline nsresult EncodeJSVal(JSContext* aCx, const jsval aVal,
+  inline nsresult EncodeJSVal(JSContext* aCx, const JS::Value aVal,
                               uint8_t aTypeOffset)
   {
     return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0);
   }
   void EncodeString(const nsAString& aString, uint8_t aTypeOffset);
   void EncodeNumber(double aFloat, uint8_t aType);
 
   // Decoding functions. aPos points into mBuffer and is adjusted to point
@@ -324,17 +326,17 @@ private:
                            const unsigned char* aEnd,
                            nsString& aString);
   static double DecodeNumber(const unsigned char*& aPos,
                              const unsigned char* aEnd);
 
   nsCString mBuffer;
 
 private:
-  nsresult EncodeJSValInternal(JSContext* aCx, const jsval aVal,
+  nsresult EncodeJSValInternal(JSContext* aCx, const JS::Value aVal,
                                uint8_t aTypeOffset, uint16_t aRecursionDepth);
 
   static nsresult DecodeJSValInternal(const unsigned char*& aPos,
                                       const unsigned char* aEnd,
                                       JSContext* aCx, uint8_t aTypeOffset,
                                       JS::MutableHandle<JS::Value> aVal, uint16_t aRecursionDepth);
 };
 
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -10,16 +10,17 @@
 #include "nsIDOMDOMException.h"
 #include "nsIMutable.h"
 #include "nsIXPConnect.h"
 
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "nsThreadUtils.h"
 #include "StructuredCloneTags.h"
+#include "jsapi.h"
 
 using namespace mozilla::dom;
 
 namespace {
 
 void
 Error(JSContext* aCx, uint32_t aErrorId)
 {
--- a/dom/ipc/StructuredCloneUtils.h
+++ b/dom/ipc/StructuredCloneUtils.h
@@ -6,17 +6,17 @@
 
 #ifndef mozilla_dom_StructuredCloneUtils_h
 #define mozilla_dom_StructuredCloneUtils_h
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsIDOMFile.h"
 
-#include "jsapi.h"
+#include "js/StructuredClone.h"
 
 namespace mozilla {
 
 struct SerializedStructuredCloneBuffer;
 
 namespace dom {
 
 struct
--- a/dom/workers/Events.h
+++ b/dom/workers/Events.h
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_events_h__
 #define mozilla_dom_workers_events_h__
 
 #include "Workers.h"
 
-class JSAutoStructuredCloneBuffer;
+#include "js/StructuredClone.h"
 
 BEGIN_WORKERS_NAMESPACE
 
 namespace events {
 
 bool
 InitClasses(JSContext* aCx, JS::Handle<JSObject*> aGlobal, bool aMainRuntime);
 
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -10,16 +10,18 @@
 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
 // Need this for XMLHttpRequestResponseType.
 #include "mozilla/dom/XMLHttpRequestBinding.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TypedArray.h"
 
+#include "js/StructuredClone.h"
+
 BEGIN_WORKERS_NAMESPACE
 
 class Proxy;
 class XMLHttpRequestUpload;
 class WorkerPrivate;
 
 class XMLHttpRequest : public XMLHttpRequestEventTarget,
                        public WorkerFeature
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -17,17 +17,17 @@
 #include "mozilla/Util.h"
 
 #include <stdint.h>
 
 #include "nsID.h"
 #include "nsMemory.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
-#include "jsapi.h"
+#include "js/StructuredClone.h"
 #include "nsCSSProperty.h"
 
 #ifdef _MSC_VER
 #pragma warning( disable : 4800 )
 #endif
 
 #if !defined(OS_POSIX)
 // This condition must be kept in sync with the one in
new file mode 100644
--- /dev/null
+++ b/js/public/StructuredClone.h
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef js_StructuredClone_h
+#define js_StructuredClone_h
+
+#include <stdint.h>
+
+#include "jstypes.h"
+
+struct JSContext;
+class JSObject;
+struct JSRuntime;
+struct JSStructuredCloneReader;
+struct JSStructuredCloneWriter;
+
+namespace JS {
+template <typename T> class Handle;
+class Value;
+}
+
+// API for the HTML5 internal structured cloning algorithm.
+
+// Read structured data from the reader r. This hook is used to read a value
+// previously serialized by a call to the WriteStructuredCloneOp hook.
+//
+// tag and data are the pair of uint32_t values from the header. The callback
+// may use the JS_Read* APIs to read any other relevant parts of the object
+// from the reader r. closure is any value passed to the JS_ReadStructuredClone
+// function. Return the new object on success, NULL on error/exception.
+typedef JSObject *(*ReadStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r,
+                                           uint32_t tag, uint32_t data, void *closure);
+
+// Structured data serialization hook. The engine can write primitive values,
+// Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other
+// type of object requires application support. This callback must first use
+// the JS_WriteUint32Pair API to write an object header, passing a value
+// greater than JS_SCTAG_USER to the tag parameter. Then it can use the
+// JS_Write* APIs to write any other relevant parts of the value v to the
+// writer w. closure is any value passed to the JS_WriteStructuredCLone function.
+//
+// Return true on success, false on error/exception.
+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.
+#define JS_STRUCTURED_CLONE_VERSION 2
+
+struct JSStructuredCloneCallbacks {
+    ReadStructuredCloneOp read;
+    WriteStructuredCloneOp write;
+    StructuredCloneErrorOp reportError;
+};
+
+// Note: if the *data contains transferable objects, it can be read only once.
+JS_PUBLIC_API(bool)
+JS_ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, uint32_t version,
+                       JS::Value *vp, const JSStructuredCloneCallbacks *optionalCallbacks,
+                       void *closure);
+
+// Note: On success, the caller is responsible for calling
+// JS_ClearStructuredClone(*datap, nbytesp).
+JS_PUBLIC_API(bool)
+JS_WriteStructuredClone(JSContext *cx, JS::Value v, uint64_t **datap, size_t *nbytesp,
+                        const JSStructuredCloneCallbacks *optionalCallbacks,
+                        void *closure, JS::Value transferable);
+
+JS_PUBLIC_API(bool)
+JS_ClearStructuredClone(const uint64_t *data, size_t nbytes);
+
+JS_PUBLIC_API(bool)
+JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes, bool *hasTransferable);
+
+JS_PUBLIC_API(bool)
+JS_StructuredClone(JSContext *cx, JS::Value v, JS::Value *vp,
+                   const JSStructuredCloneCallbacks *optionalCallbacks, void *closure);
+
+// RAII sugar for JS_WriteStructuredClone.
+class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
+    uint64_t *data_;
+    size_t nbytes_;
+    uint32_t version_;
+
+  public:
+    JSAutoStructuredCloneBuffer()
+        : data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
+
+    ~JSAutoStructuredCloneBuffer() { clear(); }
+
+    uint64_t *data() const { return data_; }
+    size_t nbytes() const { return nbytes_; }
+
+    void clear();
+
+    // Copy some memory. It will be automatically freed by the destructor.
+    bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
+
+    // Adopt some memory. It will be automatically freed by the destructor.
+    // data must have been allocated by the JS engine (e.g., extracted via
+    // JSAutoStructuredCloneBuffer::steal).
+    void adopt(uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
+
+    // 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, JS::Value *vp,
+              const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
+
+    bool write(JSContext *cx, JS::Value v,
+               const JSStructuredCloneCallbacks *optionalCallbacks=NULL, void *closure=NULL);
+
+    bool write(JSContext *cx, JS::Value v, JS::Value 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);
+    JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
+};
+
+// 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(bool)
+JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
+
+JS_PUBLIC_API(bool)
+JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
+
+JS_PUBLIC_API(bool)
+JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *vp);
+
+JS_PUBLIC_API(bool)
+JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
+
+JS_PUBLIC_API(bool)
+JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
+
+JS_PUBLIC_API(bool)
+JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v);
+
+#endif  /* js_StructuredClone_h */
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1891,12 +1891,23 @@ PRIVATE_TO_JSVAL(void *ptr)
 
 static inline void *
 JSVAL_TO_PRIVATE(jsval v)
 {
     MOZ_ASSERT(JSVAL_IS_DOUBLE(v));
     return JSVAL_TO_PRIVATE_PTR_IMPL(JSVAL_TO_IMPL(v));
 }
 
+// JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
+// constructing values from scratch (e.g. Int32Value(0)).  These constants are
+// stored in memory and initialized at startup, so testing against them and
+// using them requires memory loads and will be correspondingly slow.
+extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
+extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
+
 #undef JS_VALUE_IS_CONSTEXPR
 #undef JS_RETURN_LAYOUT_FROM_BITS
 
 #endif /* js_Value_h */
--- a/js/src/config/check_spidermonkey_style.py
+++ b/js/src/config/check_spidermonkey_style.py
@@ -332,17 +332,18 @@ class Include(object):
 
         if not self.inclname.endswith('.h'):
             return 7
 
         # A couple of modules have the .h file in js/ and the .cpp file elsewhere and so need special
         # handling.
         if module == module_name(self.inclname) or \
            module == 'jsmemorymetrics' and self.inclname == 'js/MemoryMetrics.h' or \
-           module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h':
+           module == 'vm/PropertyKey' and self.inclname == 'js/PropertyKey.h' or \
+           module == 'vm/StructuredClone' and self.inclname == 'js/StructuredClone.h':
             return 0
 
         if '/' in self.inclname:
             if self.inclname.startswith('mozilla/'):
                 return 1
 
             if self.inclname.endswith('-inl.h'):
                 return 6
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -16,17 +16,16 @@
 #include <ctype.h>
 #include <stdarg.h>
 #include <string.h>
 #include <sys/stat.h>
 
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
-#include "jsclone.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
@@ -55,16 +54,17 @@
 #include "builtin/ParallelArray.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FullParseHandler.h"  // for JS_BufferIsCompileableUnit
 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
 #include "gc/Marking.h"
 #include "jit/AsmJSLink.h"
 #include "js/CharacterEncoding.h"
+#include "js/StructuredClone.h"
 #if ENABLE_INTL_API
 #include "unicode/uclean.h"
 #include "unicode/utypes.h"
 #endif // ENABLE_INTL_API
 #include "vm/DateObject.h"
 #include "vm/Debugger.h"
 #include "vm/ErrorObject.h"
 #include "vm/Interpreter.h"
@@ -129,20 +129,18 @@ const jsid JSID_EMPTY = { size_t(JSID_TY
 #endif
 
 const jsval JSVAL_NULL  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_NULL,      0));
 const jsval JSVAL_ZERO  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32,     0));
 const jsval JSVAL_ONE   = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_INT32,     1));
 const jsval JSVAL_FALSE = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN,   false));
 const jsval JSVAL_TRUE  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_BOOLEAN,   true));
 const jsval JSVAL_VOID  = IMPL_TO_JSVAL(BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0));
-const HandleValue JS::NullHandleValue =
-    HandleValue::fromMarkedLocation(&JSVAL_NULL);
-const HandleValue JS::UndefinedHandleValue =
-    HandleValue::fromMarkedLocation(&JSVAL_VOID);
+const HandleValue JS::NullHandleValue = HandleValue::fromMarkedLocation(&JSVAL_NULL);
+const HandleValue JS::UndefinedHandleValue = HandleValue::fromMarkedLocation(&JSVAL_VOID);
 
 const jsid voidIdValue = JSID_VOID;
 const jsid emptyIdValue = JSID_EMPTY;
 const HandleId JS::JSID_VOIDHANDLE = HandleId::fromMarkedLocation(&voidIdValue);
 const HandleId JS::JSID_EMPTYHANDLE = HandleId::fromMarkedLocation(&emptyIdValue);
 
 /* Make sure that jschar is two bytes unsigned integer */
 JS_STATIC_ASSERT((jschar)-1 > 0);
@@ -180,28 +178,32 @@ JS_GetEmptyStringValue(JSContext *cx)
 
 JS_PUBLIC_API(JSString *)
 JS_GetEmptyString(JSRuntime *rt)
 {
     JS_ASSERT(rt->hasContexts());
     return rt->emptyString;
 }
 
-static void
+namespace js {
+
+void
 AssertHeapIsIdle(JSRuntime *rt)
 {
     JS_ASSERT(rt->heapState == js::Idle);
 }
 
-static void
+void
 AssertHeapIsIdle(JSContext *cx)
 {
     AssertHeapIsIdle(cx->runtime());
 }
 
+}
+
 static void
 AssertHeapIsIdleOrIterating(JSRuntime *rt)
 {
     JS_ASSERT(!rt->isHeapCollecting());
 }
 
 static void
 AssertHeapIsIdleOrIterating(JSContext *cx)
@@ -5927,230 +5929,16 @@ JS_ParseJSONWithReviver(JSContext *cx, c
     RootedValue reviver(cx, reviverArg), value(cx);
     if (!ParseJSONWithReviver(cx, StableCharPtr(chars, len), len, reviver, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
-JS_PUBLIC_API(bool)
-JS_ReadStructuredClone(JSContext *cx, 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) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
-        return false;
-    }
-    const JSStructuredCloneCallbacks *callbacks =
-        optionalCallbacks ?
-        optionalCallbacks :
-        cx->runtime()->structuredCloneCallbacks;
-    return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
-}
-
-JS_PUBLIC_API(bool)
-JS_WriteStructuredClone(JSContext *cx, jsval valueArg, uint64_t **bufp, size_t *nbytesp,
-                        const JSStructuredCloneCallbacks *optionalCallbacks,
-                        void *closure, jsval transferable)
-{
-    RootedValue value(cx, valueArg);
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, value);
-
-    const JSStructuredCloneCallbacks *callbacks =
-        optionalCallbacks ?
-        optionalCallbacks :
-        cx->runtime()->structuredCloneCallbacks;
-    return WriteStructuredClone(cx, value, (uint64_t **) bufp, nbytesp,
-                                callbacks, closure, transferable);
-}
-
-JS_PUBLIC_API(bool)
-JS_ClearStructuredClone(const uint64_t *data, size_t nbytes)
-{
-    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))
-        return false;
-
-    *hasTransferable = transferable;
-    return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_StructuredClone(JSContext *cx, jsval valueArg, jsval *vp,
-                   const JSStructuredCloneCallbacks *optionalCallbacks,
-                   void *closure)
-{
-    RootedValue value(cx, valueArg);
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, value);
-
-    const JSStructuredCloneCallbacks *callbacks =
-        optionalCallbacks ?
-        optionalCallbacks :
-        cx->runtime()->structuredCloneCallbacks;
-    JSAutoStructuredCloneBuffer buf;
-    return buf.write(cx, value, callbacks, closure) &&
-           buf.read(cx, vp, callbacks, closure);
-}
-
-void
-JSAutoStructuredCloneBuffer::clear()
-{
-    if (data_) {
-        ClearStructuredClone(data_, nbytes_);
-        data_ = NULL;
-        nbytes_ = 0;
-        version_ = 0;
-    }
-}
-
-void
-JSAutoStructuredCloneBuffer::adopt(uint64_t *data, size_t nbytes, uint32_t version)
-{
-    clear();
-    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;
-    nbytes_ = nbytes;
-    version_ = version;
-    return true;
-}
-void
-JSAutoStructuredCloneBuffer::steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp)
-{
-    *datap = data_;
-    *nbytesp = nbytes_;
-    if (versionp)
-        *versionp = version_;
-
-    data_ = NULL;
-    nbytes_ = 0;
-    version_ = 0;
-}
-
-bool
-JSAutoStructuredCloneBuffer::read(JSContext *cx, jsval *vp,
-                                  const JSStructuredCloneCallbacks *optionalCallbacks,
-                                  void *closure)
-{
-    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);
-    if (!ok) {
-        data_ = NULL;
-        nbytes_ = 0;
-        version_ = JS_STRUCTURED_CLONE_VERSION;
-    }
-    return ok;
-}
-
-void
-JSAutoStructuredCloneBuffer::swap(JSAutoStructuredCloneBuffer &other)
-{
-    uint64_t *data = other.data_;
-    size_t nbytes = other.nbytes_;
-    uint32_t version = other.version_;
-
-    other.data_ = this->data_;
-    other.nbytes_ = this->nbytes_;
-    other.version_ = this->version_;
-
-    this->data_ = data;
-    this->nbytes_ = nbytes;
-    this->version_ = version;
-}
-
-JS_PUBLIC_API(void)
-JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
-{
-    rt->structuredCloneCallbacks = callbacks;
-}
-
-JS_PUBLIC_API(bool)
-JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2)
-{
-    return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
-}
-
-JS_PUBLIC_API(bool)
-JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
-{
-    return r->input().readBytes(p, len);
-}
-
-JS_PUBLIC_API(bool)
-JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data)
-{
-    return w->output().writePair(tag, data);
-}
-
-JS_PUBLIC_API(bool)
-JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
-{
-    return w->output().writeBytes(p, len);
-}
-
 /************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_ReportError(JSContext *cx, const char *format, ...)
 {
     va_list ap;
 
     AssertHeapIsIdle(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1142,64 +1142,18 @@ typedef JSObject *
 
 typedef void
 (* JSDestroyCompartmentCallback)(JSFreeOp *fop, JSCompartment *compartment);
 
 typedef void
 (* JSCompartmentNameCallback)(JSRuntime *rt, JSCompartment *compartment,
                               char *buf, size_t bufsize);
 
-/*
- * Read structured data from the reader r. This hook is used to read a value
- * previously serialized by a call to the WriteStructuredCloneOp hook.
- *
- * tag and data are the pair of uint32_t values from the header. The callback
- * may use the JS_Read* APIs to read any other relevant parts of the object
- * from the reader r. closure is any value passed to the JS_ReadStructuredClone
- * function. Return the new object on success, NULL on error/exception.
- */
-typedef JSObject *(*ReadStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r,
-                                           uint32_t tag, uint32_t data, void *closure);
-
-/*
- * Structured data serialization hook. The engine can write primitive values,
- * Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other
- * type of object requires application support. This callback must first use
- * the JS_WriteUint32Pair API to write an object header, passing a value
- * greater than JS_SCTAG_USER to the tag parameter. Then it can use the
- * JS_Write* APIs to write any other relevant parts of the value v to the
- * writer w. closure is any value passed to the JS_WriteStructuredCLone function.
- *
- * Return true on success, false on error/exception.
- */
-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);
-
 /************************************************************************/
 
-/*
- * JS constants. For efficiency, prefer predicates (e.g. v.isNull()) and
- * constructing values from scratch (e.g. Int32Value(0)).  These constants are
- * stored in memory and initialized at startup, so testing against them and
- * using them requires memory loads and will be correspondingly slow.
- */
-extern JS_PUBLIC_DATA(const jsval) JSVAL_NULL;
-extern JS_PUBLIC_DATA(const jsval) JSVAL_ZERO;
-extern JS_PUBLIC_DATA(const jsval) JSVAL_ONE;
-extern JS_PUBLIC_DATA(const jsval) JSVAL_FALSE;
-extern JS_PUBLIC_DATA(const jsval) JSVAL_TRUE;
-extern JS_PUBLIC_DATA(const jsval) JSVAL_VOID;
-
 static JS_ALWAYS_INLINE jsval
 JS_NumberValue(double d)
 {
     int32_t i;
     d = JS_CANONICALIZE_NAN(d);
     if (mozilla::DoubleIsInt32(d, &i))
         return INT_TO_JSVAL(i);
     return DOUBLE_TO_JSVAL(d);
@@ -1871,16 +1825,22 @@ template <> struct GCMethods<jsid>
     static bool poisoned(jsid id) { return JS::IsPoisonedId(id); }
     static bool needsPostBarrier(jsid id) { return false; }
 #ifdef JSGC_GENERATIONAL
     static void postBarrier(jsid *idp) {}
     static void relocate(jsid *idp) {}
 #endif
 };
 
+void
+AssertHeapIsIdle(JSRuntime *rt);
+
+void
+AssertHeapIsIdle(JSContext *cx);
+
 } /* namespace js */
 
 class JSAutoRequest
 {
   public:
     JSAutoRequest(JSContext *cx
                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : mContext(cx)
@@ -4704,144 +4664,16 @@ JS_PUBLIC_API(bool)
 JS_ParseJSON(JSContext *cx, const jschar *chars, uint32_t len, JS::MutableHandle<JS::Value> vp);
 
 JS_PUBLIC_API(bool)
 JS_ParseJSONWithReviver(JSContext *cx, const jschar *chars, uint32_t len, jsval reviver,
                         jsval *vp);
 
 /************************************************************************/
 
-/* API for the HTML5 internal structured cloning algorithm. */
-
-/* The maximum supported structured-clone serialization format version. */
-#define JS_STRUCTURED_CLONE_VERSION 2
-
-struct JSStructuredCloneCallbacks {
-    ReadStructuredCloneOp read;
-    WriteStructuredCloneOp write;
-    StructuredCloneErrorOp reportError;
-};
-
-/* Note: if the *data contains transferable objects, it can be read
- * only once */
-JS_PUBLIC_API(bool)
-JS_ReadStructuredClone(JSContext *cx, 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). */
-JS_PUBLIC_API(bool)
-JS_WriteStructuredClone(JSContext *cx, jsval v, uint64_t **datap, size_t *nbytesp,
-                        const JSStructuredCloneCallbacks *optionalCallbacks,
-                        void *closure, jsval transferable);
-
-JS_PUBLIC_API(bool)
-JS_ClearStructuredClone(const uint64_t *data, size_t nbytes);
-
-JS_PUBLIC_API(bool)
-JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes,
-                                   bool *hasTransferable);
-
-JS_PUBLIC_API(bool)
-JS_StructuredClone(JSContext *cx, jsval v, jsval *vp,
-                   const JSStructuredCloneCallbacks *optionalCallbacks,
-                   void *closure);
-
-/* RAII sugar for JS_WriteStructuredClone. */
-class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
-    uint64_t *data_;
-    size_t nbytes_;
-    uint32_t version_;
-
-  public:
-    JSAutoStructuredCloneBuffer()
-        : data_(NULL), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION) {}
-
-    ~JSAutoStructuredCloneBuffer() { clear(); }
-
-    uint64_t *data() const { return data_; }
-    size_t nbytes() const { return nbytes_; }
-
-    void clear();
-
-    /* Copy some memory. It will be automatically freed by the destructor. */
-    bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
-
-    /*
-     * Adopt some memory. It will be automatically freed by the destructor.
-     * data must have been allocated by the JS engine (e.g., extracted via
-     * JSAutoStructuredCloneBuffer::steal).
-     */
-    void adopt(uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
-
-    /*
-     * 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);
-
-    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);
-    JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other);
-};
-
-/* 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(bool)
-JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2);
-
-JS_PUBLIC_API(bool)
-JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len);
-
-JS_PUBLIC_API(bool)
-JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp);
-
-JS_PUBLIC_API(bool)
-JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data);
-
-JS_PUBLIC_API(bool)
-JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len);
-
-JS_PUBLIC_API(bool)
-JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
-
-/************************************************************************/
-
 /*
  * The default locale for the ECMAScript Internationalization API
  * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
  * Note that the Internationalization API encourages clients to
  * specify their own locales.
  * The locale string remains owned by the caller.
  */
 extern JS_PUBLIC_API(bool)
deleted file mode 100644
--- a/js/src/jsclone.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jsclone_h
-#define jsclone_h
-
-#include "jsapi.h"
-#include "jscntxt.h"
-
-#include "js/Vector.h"
-
-namespace js {
-
-bool
-WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
-                     const JSStructuredCloneCallbacks *cb, void *cbClosure,
-                     jsval transferable);
-
-bool
-ReadStructuredClone(JSContext *cx, 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);
-
-    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;
-};
-
-} /* namespace js */
-
-struct JSStructuredCloneReader {
-  public:
-    explicit JSStructuredCloneReader(js::SCInput &in, const JSStructuredCloneCallbacks *cb,
-                                     void *cbClosure)
-        : in(in), objs(in.context()), allObjs(in.context()),
-          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 arrayType, uint32_t nelems, js::Value *vp, bool v1Read = false);
-    bool readArrayBuffer(uint32_t nbytes, js::Value *vp);
-    bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, js::Value *vp);
-    bool readId(jsid *idp);
-    bool startRead(js::Value *vp);
-
-    js::SCInput &in;
-
-    // Stack of objects with properties remaining to be read.
-    js::AutoValueVector objs;
-
-    // Stack of all objects read during this deserialization
-    js::AutoValueVector allObjs;
-
-    // The user defined callbacks that will be used for cloning.
-    const JSStructuredCloneCallbacks *callbacks;
-
-    // Any value passed to JS_ReadStructuredClone.
-    void *closure;
-
-    friend bool 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(out.context(), tVal), transferableObjects(out.context()) { }
-
-    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(); }
-
-    bool writeTransferMap();
-
-    bool writeString(uint32_t tag, JSString *str);
-    bool writeId(jsid id);
-    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();
-
-    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.
-    js::AutoValueVector objs;
-
-    // counts[i] is the number of properties of objs[i] remaining to be written.
-    // counts.length() == objs.length() and sum(counts) == ids.length().
-    js::Vector<size_t> counts;
-
-    // Ids of properties remaining to be written.
-    js::AutoIdVector ids;
-
-    // The "memory" list described in the HTML5 internal structured cloning algorithm.
-    // memory is a superset of objs; items are never removed from Memory
-    // until a serialization operation is finished
-    typedef js::AutoObjectUnsigned32HashMap CloneMemory;
-    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
-    JS::RootedValue transferable;
-    js::AutoObjectHashSet transferableObjects;
-
-    friend bool JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v);
-};
-
-#endif /* jsclone_h */
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -66,16 +66,17 @@ EXPORTS.js += [
     '../public/GCAPI.h',
     '../public/HashTable.h',
     '../public/HeapAPI.h',
     '../public/LegacyIntTypes.h',
     '../public/MemoryMetrics.h',
     '../public/PropertyKey.h',
     '../public/RequiredDefines.h',
     '../public/RootingAPI.h',
+    '../public/StructuredClone.h',
     '../public/Utility.h',
     '../public/Value.h',
     '../public/Vector.h',
 ]
 
 CPP_SOURCES += [
     'ArgumentsObject.cpp',
     'BinaryData.cpp',
@@ -120,16 +121,17 @@ CPP_SOURCES += [
     'ScopeObject.cpp',
     'SelfHosting.cpp',
     'Shape.cpp',
     'Stack.cpp',
     'Statistics.cpp',
     'StoreBuffer.cpp',
     'String.cpp',
     'StringBuffer.cpp',
+    'StructuredClone.cpp',
     'TestingFunctions.cpp',
     'ThreadPool.cpp',
     'TokenStream.cpp',
     'TypedArrayObject.cpp',
     'Unicode.cpp',
     'Verifier.cpp',
     'Xdr.cpp',
     'YarrCanonicalizeUCS2.cpp',
@@ -138,17 +140,16 @@ CPP_SOURCES += [
     'YarrSyntaxChecker.cpp',
     'Zone.cpp',
     'jsalloc.cpp',
     'jsanalyze.cpp',
     'jsapi.cpp',
     'jsarray.cpp',
     'jsatom.cpp',
     'jsbool.cpp',
-    'jsclone.cpp',
     'jscntxt.cpp',
     'jscompartment.cpp',
     'jscrashreport.cpp',
     'jsdate.cpp',
     'jsdbgapi.cpp',
     'jsdtoa.cpp',
     'jsexn.cpp',
     'jsfriendapi.cpp',
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -57,16 +57,17 @@
 #if JS_TRACE_LOGGING
 #include "TraceLogging.h"
 #endif
 
 #include "builtin/TestingFunctions.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "jit/Ion.h"
+#include "js/StructuredClone.h"
 #include "perf/jsperf.h"
 #include "shell/jsheaptools.h"
 #include "shell/jsoptparse.h"
 #include "vm/Shape.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jsfuninlines.h"
rename from js/src/jsclone.cpp
rename to js/src/vm/StructuredClone.cpp
--- a/js/src/jsclone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -22,21 +22,23 @@
  * in fact the typed array was added to 'memory' first.
  *
  * So during writing, we add objects to the memory when first encountering
  * them. When reading a typed array, a placeholder is pushed onto allObjs until
  * the ArrayBuffer has been read, then it is updated with the actual typed
  * array object.
  */
 
-#include "jsclone.h"
+#include "js/StructuredClone.h"
 
 #include "mozilla/Endian.h"
 #include "mozilla/FloatingPoint.h"
 
+#include "jsapi.h"
+#include "jscntxt.h"
 #include "jsdate.h"
 #include "jswrapper.h"
 
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
@@ -81,52 +83,229 @@ enum StructuredDataType {
     SCTAG_END_OF_BUILTIN_TYPES
 };
 
 enum TransferableMapHeader {
     SCTAG_TM_NOT_MARKED = 0,
     SCTAG_TM_MARKED
 };
 
+namespace js {
+
+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);
+
+    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;
+};
+
+}
+
+struct JSStructuredCloneReader {
+  public:
+    explicit JSStructuredCloneReader(js::SCInput &in, const JSStructuredCloneCallbacks *cb,
+                                     void *cbClosure)
+        : in(in), objs(in.context()), allObjs(in.context()),
+          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 arrayType, uint32_t nelems, js::Value *vp, bool v1Read = false);
+    bool readArrayBuffer(uint32_t nbytes, js::Value *vp);
+    bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, js::Value *vp);
+    bool readId(jsid *idp);
+    bool startRead(js::Value *vp);
+
+    js::SCInput &in;
+
+    // Stack of objects with properties remaining to be read.
+    js::AutoValueVector objs;
+
+    // Stack of all objects read during this deserialization
+    js::AutoValueVector allObjs;
+
+    // The user defined callbacks that will be used for cloning.
+    const JSStructuredCloneCallbacks *callbacks;
+
+    // Any value passed to JS_ReadStructuredClone.
+    void *closure;
+
+    friend bool JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *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(out.context(), tVal), transferableObjects(out.context()) { }
+
+    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(); }
+
+    bool writeTransferMap();
+
+    bool writeString(uint32_t tag, JSString *str);
+    bool writeId(jsid id);
+    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();
+
+    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.
+    js::AutoValueVector objs;
+
+    // counts[i] is the number of properties of objs[i] remaining to be written.
+    // counts.length() == objs.length() and sum(counts) == ids.length().
+    js::Vector<size_t> counts;
+
+    // Ids of properties remaining to be written.
+    js::AutoIdVector ids;
+
+    // The "memory" list described in the HTML5 internal structured cloning algorithm.
+    // memory is a superset of objs; items are never removed from Memory
+    // until a serialization operation is finished
+    typedef js::AutoObjectUnsigned32HashMap CloneMemory;
+    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
+    JS::RootedValue transferable;
+    js::AutoObjectHashSet transferableObjects;
+
+    friend bool JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v);
+};
+
 JS_FRIEND_API(uint64_t)
 js_GetSCOffset(JSStructuredCloneWriter* writer)
 {
     JS_ASSERT(writer);
     return writer->output().count() * sizeof(uint64_t);
 }
 
 JS_STATIC_ASSERT(SCTAG_END_OF_BUILTIN_TYPES <= JS_SCTAG_USER_MIN);
 JS_STATIC_ASSERT(JS_SCTAG_USER_MIN <= JS_SCTAG_USER_MAX);
 JS_STATIC_ASSERT(TypedArrayObject::TYPE_INT8 == 0);
 
+namespace js {
+
 bool
-js::WriteStructuredClone(JSContext *cx, HandleValue v, uint64_t **bufp, size_t *nbytesp,
-                         const JSStructuredCloneCallbacks *cb, void *cbClosure,
-                         jsval transferable)
+WriteStructuredClone(JSContext *cx, HandleValue 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
-js::ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, Value *vp,
-                        const JSStructuredCloneCallbacks *cb, void *cbClosure)
+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
-js::ClearStructuredClone(const uint64_t *data, size_t nbytes)
+ClearStructuredClone(const uint64_t *data, size_t nbytes)
 {
     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) {
         if ((TransferableMapHeader)uint32_t(u) == SCTAG_TM_NOT_MARKED) {
@@ -147,31 +326,33 @@ js::ClearStructuredClone(const uint64_t 
         }
     }
 
     js_free((void *)data);
     return true;
 }
 
 bool
-js::StructuredCloneHasTransferObjects(const uint64_t *data, size_t nbytes, bool *hasTransferable)
+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) {
             *hasTransferable = true;
         }
     }
 
     return true;
 }
 
+}
+
 static inline uint64_t
 PairToUInt64(uint32_t tag, uint32_t data)
 {
     return uint64_t(data) | (uint64_t(tag) << 32);
 }
 
 bool
 SCInput::eof()
@@ -556,34 +737,16 @@ JSStructuredCloneWriter::checkStack()
         JS_ASSERT(total <= ids.length());
 
     size_t j = objs.length();
     for (size_t i = 0; i < limit; i++)
         JS_ASSERT(memory.has(&objs[--j].toObject()));
 #endif
 }
 
-JS_PUBLIC_API(bool)
-JS_WriteTypedArray(JSStructuredCloneWriter *w, jsval v)
-{
-    JS_ASSERT(v.isObject());
-    assertSameCompartment(w->context(), v);
-    RootedObject obj(w->context(), &v.toObject());
-
-    // If the object is a security wrapper, see if we're allowed to unwrap it.
-    // If we aren't, throw.
-    if (obj->is<WrapperObject>())
-        obj = CheckedUnwrap(obj);
-    if (!obj) {
-        JS_ReportError(w->context(), "Permission denied to access object");
-        return false;
-    }
-    return w->writeTypedArray(obj);
-}
-
 /*
  * Write out a typed array. Note that post-v1 structured clone buffers do not
  * perform endianness conversion on stored data, so multibyte typed arrays
  * cannot be deserialized into a different endianness machine. Endianness
  * conversion would prevent sharing ArrayBuffers: if you have Int8Array and
  * Int16Array views of the same ArrayBuffer, should the data bytes be
  * byte-swapped when writing or not? The Int8Array requires them to not be
  * swapped; the Int16Array requires that they are.
@@ -847,36 +1010,16 @@ JSStructuredCloneReader::readString(uint
 
 static uint32_t
 TagToV1ArrayType(uint32_t tag)
 {
     JS_ASSERT(tag >= SCTAG_TYPED_ARRAY_V1_MIN && tag <= SCTAG_TYPED_ARRAY_V1_MAX);
     return tag - SCTAG_TYPED_ARRAY_V1_MIN;
 }
 
-JS_PUBLIC_API(bool)
-JS_ReadTypedArray(JSStructuredCloneReader *r, jsval *vp)
-{
-    uint32_t tag, nelems;
-    if (!r->input().readPair(&tag, &nelems))
-        return false;
-    if (tag >= SCTAG_TYPED_ARRAY_V1_MIN && tag <= SCTAG_TYPED_ARRAY_V1_MAX) {
-        return r->readTypedArray(TagToV1ArrayType(tag), nelems, vp, true);
-    } else if (tag == SCTAG_TYPED_ARRAY_OBJECT) {
-        uint64_t arrayType;
-        if (!r->input().read(&arrayType))
-            return false;
-        return r->readTypedArray(arrayType, nelems, vp);
-    } else {
-        JS_ReportErrorNumber(r->context(), js_GetErrorMessage, NULL,
-                             JSMSG_SC_BAD_SERIALIZED_DATA, "expected type array");
-        return false;
-    }
-}
-
 bool
 JSStructuredCloneReader::readTypedArray(uint32_t arrayType, uint32_t nelems, Value *vp,
                                         bool v1Read)
 {
     if (arrayType > TypedArrayObject::TYPE_UINT8_CLAMPED) {
         JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL,
                              JSMSG_SC_BAD_SERIALIZED_DATA, "unhandled typed array element type");
         return false;
@@ -1275,8 +1418,262 @@ JSStructuredCloneReader::read(Value *vp)
                 return false;
         }
     }
 
     allObjs.clear();
 
     return true;
 }
+using namespace js;
+
+JS_PUBLIC_API(bool)
+JS_ReadStructuredClone(JSContext *cx, uint64_t *buf, size_t nbytes,
+                       uint32_t version, JS::Value *vp,
+                       const JSStructuredCloneCallbacks *optionalCallbacks,
+                       void *closure)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+
+    if (version > JS_STRUCTURED_CLONE_VERSION) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CLONE_VERSION);
+        return false;
+    }
+    const JSStructuredCloneCallbacks *callbacks =
+        optionalCallbacks ?
+        optionalCallbacks :
+        cx->runtime()->structuredCloneCallbacks;
+    return ReadStructuredClone(cx, buf, nbytes, vp, callbacks, closure);
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteStructuredClone(JSContext *cx, JS::Value valueArg, uint64_t **bufp, size_t *nbytesp,
+                        const JSStructuredCloneCallbacks *optionalCallbacks,
+                        void *closure, JS::Value transferable)
+{
+    RootedValue value(cx, valueArg);
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, value);
+
+    const JSStructuredCloneCallbacks *callbacks =
+        optionalCallbacks ?
+        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)
+{
+    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))
+        return false;
+
+    *hasTransferable = transferable;
+    return true;
+}
+
+JS_PUBLIC_API(bool)
+JS_StructuredClone(JSContext *cx, JS::Value valueArg, JS::Value *vp,
+                   const JSStructuredCloneCallbacks *optionalCallbacks,
+                   void *closure)
+{
+    RootedValue value(cx, valueArg);
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, value);
+
+    const JSStructuredCloneCallbacks *callbacks =
+        optionalCallbacks ?
+        optionalCallbacks :
+        cx->runtime()->structuredCloneCallbacks;
+    JSAutoStructuredCloneBuffer buf;
+    return buf.write(cx, value, callbacks, closure) &&
+           buf.read(cx, vp, callbacks, closure);
+}
+
+void
+JSAutoStructuredCloneBuffer::clear()
+{
+    if (data_) {
+        ClearStructuredClone(data_, nbytes_);
+        data_ = NULL;
+        nbytes_ = 0;
+        version_ = 0;
+    }
+}
+
+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;
+    nbytes_ = nbytes;
+    version_ = version;
+    return true;
+}
+
+void
+JSAutoStructuredCloneBuffer::adopt(uint64_t *data, size_t nbytes, uint32_t version)
+{
+    clear();
+    data_ = data;
+    nbytes_ = nbytes;
+    version_ = version;
+}
+
+void
+JSAutoStructuredCloneBuffer::steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp)
+{
+    *datap = data_;
+    *nbytesp = nbytes_;
+    if (versionp)
+        *versionp = version_;
+
+    data_ = NULL;
+    nbytes_ = 0;
+    version_ = 0;
+}
+
+bool
+JSAutoStructuredCloneBuffer::read(JSContext *cx, JS::Value *vp,
+                                  const JSStructuredCloneCallbacks *optionalCallbacks,
+                                  void *closure)
+{
+    JS_ASSERT(cx);
+    JS_ASSERT(data_);
+    return !!JS_ReadStructuredClone(cx, data_, nbytes_, version_, vp,
+                                    optionalCallbacks, closure);
+}
+
+bool
+JSAutoStructuredCloneBuffer::write(JSContext *cx, JS::Value valueArg,
+                                   const JSStructuredCloneCallbacks *optionalCallbacks,
+                                   void *closure)
+{
+    JS::Value transferable = JSVAL_VOID;
+    return write(cx, valueArg, transferable, optionalCallbacks, closure);
+}
+
+bool
+JSAutoStructuredCloneBuffer::write(JSContext *cx, JS::Value valueArg,
+                                   JS::Value transferable,
+                                   const JSStructuredCloneCallbacks *optionalCallbacks,
+                                   void *closure)
+{
+    RootedValue value(cx, valueArg);
+    clear();
+    bool ok = !!JS_WriteStructuredClone(cx, value, &data_, &nbytes_,
+                                        optionalCallbacks, closure,
+                                        transferable);
+    if (!ok) {
+        data_ = NULL;
+        nbytes_ = 0;
+        version_ = JS_STRUCTURED_CLONE_VERSION;
+    }
+    return ok;
+}
+
+void
+JSAutoStructuredCloneBuffer::swap(JSAutoStructuredCloneBuffer &other)
+{
+    uint64_t *data = other.data_;
+    size_t nbytes = other.nbytes_;
+    uint32_t version = other.version_;
+
+    other.data_ = this->data_;
+    other.nbytes_ = this->nbytes_;
+    other.version_ = this->version_;
+
+    this->data_ = data;
+    this->nbytes_ = nbytes;
+    this->version_ = version;
+}
+
+JS_PUBLIC_API(void)
+JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks)
+{
+    rt->structuredCloneCallbacks = callbacks;
+}
+
+JS_PUBLIC_API(bool)
+JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2)
+{
+    return r->input().readPair((uint32_t *) p1, (uint32_t *) p2);
+}
+
+JS_PUBLIC_API(bool)
+JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len)
+{
+    return r->input().readBytes(p, len);
+}
+
+JS_PUBLIC_API(bool)
+JS_ReadTypedArray(JSStructuredCloneReader *r, JS::Value *vp)
+{
+    uint32_t tag, nelems;
+    if (!r->input().readPair(&tag, &nelems))
+        return false;
+    if (tag >= SCTAG_TYPED_ARRAY_V1_MIN && tag <= SCTAG_TYPED_ARRAY_V1_MAX) {
+        return r->readTypedArray(TagToV1ArrayType(tag), nelems, vp, true);
+    } else if (tag == SCTAG_TYPED_ARRAY_OBJECT) {
+        uint64_t arrayType;
+        if (!r->input().read(&arrayType))
+            return false;
+        return r->readTypedArray(arrayType, nelems, vp);
+    } else {
+        JS_ReportErrorNumber(r->context(), js_GetErrorMessage, NULL,
+                             JSMSG_SC_BAD_SERIALIZED_DATA, "expected type array");
+        return false;
+    }
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data)
+{
+    return w->output().writePair(tag, data);
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len)
+{
+    return w->output().writeBytes(p, len);
+}
+
+JS_PUBLIC_API(bool)
+JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::Value v)
+{
+    JS_ASSERT(v.isObject());
+    assertSameCompartment(w->context(), v);
+    RootedObject obj(w->context(), &v.toObject());
+
+    // If the object is a security wrapper, see if we're allowed to unwrap it.
+    // If we aren't, throw.
+    if (obj->is<WrapperObject>())
+        obj = CheckedUnwrap(obj);
+    if (!obj) {
+        JS_ReportError(w->context(), "Permission denied to access object");
+        return false;
+    }
+    return w->writeTypedArray(obj);
+}
+
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -7,16 +7,17 @@
 /*
  * The Components.Sandbox object.
  */
 
 #include "AccessCheck.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 #include "jsproxy.h"
+#include "js/StructuredClone.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsGlobalWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"