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 143991 781c291ec961689df23010bfd1d290cb7fb7c91f
parent 143990 dec0efbf0e554dd53d2cd96b2c44934be81c12e8
child 143992 051e287b802fb1beba2b75fe877fdb29c741da87
push id32837
push usernnethercote@mozilla.com
push dateFri, 23 Aug 2013 02:42:38 +0000
treeherdermozilla-inbound@051e287b802f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs905017
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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"