Backed out changeset 30798fdc5bad
authorDão Gottwald <dao@mozilla.com>
Sat, 24 Mar 2012 12:33:30 +0100
changeset 93572 081b574dbad3ea95b40a458e036eabc7ed7ee7d3
parent 93571 30798fdc5bad0d4b899faf5f979e1caf5a901484
child 93573 120e179a4af7ffae3c7d5df25f95ad0dacbe52fe
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone14.0a1
backs out30798fdc5bad0d4b899faf5f979e1caf5a901484
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 30798fdc5bad
caps/src/nsJSPrincipals.cpp
content/xul/document/src/nsXULPrototypeCache.cpp
js/src/Makefile.in
js/src/frontend/BytecodeEmitter.h
js/src/js.msg
js/src/jsapi-tests/testAddPropertyPropcache.cpp
js/src/jsapi-tests/testCloneScript.cpp
js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
js/src/jsapi-tests/testIntTypesABI.cpp
js/src/jsapi-tests/testSetProperty.cpp
js/src/jsapi-tests/testXDR.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsnum.h
js/src/jsobj.cpp
js/src/jsprvtd.h
js/src/jspubtd.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsversion.h
js/src/jsxdrapi.cpp
js/src/jsxdrapi.h
js/src/vm/ArgumentsObject.cpp
js/src/vm/RegExpObject.cpp
js/src/vm/RegExpObject.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
js/src/vm/Xdr.cpp
js/src/vm/Xdr.h
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSLoaderUtils.cpp
js/xpconnect/src/nsXPConnect.cpp
--- a/caps/src/nsJSPrincipals.cpp
+++ b/caps/src/nsJSPrincipals.cpp
@@ -39,16 +39,17 @@
 #include "nsString.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIObjectInputStream.h"
 #include "nsJSPrincipals.h"
 #include "plstr.h"
 #include "nsXPIDLString.h"
 #include "nsCOMPtr.h"
 #include "jsapi.h"
+#include "jsxdrapi.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIServiceManager.h"
 #include "nsMemory.h"
 #include "nsStringBuffer.h"
 
 // for mozilla::dom::workers::kJSPrincipalsDebugToken
 #include "mozilla/dom/workers/Workers.h"
 
--- a/content/xul/document/src/nsXULPrototypeCache.cpp
+++ b/content/xul/document/src/nsXULPrototypeCache.cpp
@@ -55,17 +55,17 @@
 #include "nsIObjectOutputStream.h"
 #include "nsIObserverService.h"
 #include "nsIStringStream.h"
 #include "nsIStorageStream.h"
 
 #include "nsNetUtil.h"
 #include "nsAppDirectoryServiceDefs.h"
 
-#include "jsapi.h"
+#include "jsxdrapi.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::scache;
 
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -141,16 +141,17 @@ CPPSRCS		= \
 		jsscope.cpp \
 		jsscript.cpp \
 		jsstr.cpp \
 		jstypedarray.cpp \
 		jsutil.cpp \
 		jswatchpoint.cpp \
 		jsweakmap.cpp \
 		jswrapper.cpp \
+		jsxdrapi.cpp \
 		jsxml.cpp \
 		prmjtime.cpp \
 		sharkctl.cpp \
 		ArgumentsObject.cpp \
 		ScopeObject.cpp \
 		Debugger.cpp \
 		GlobalObject.cpp \
 		MethodGuard.cpp \
@@ -171,17 +172,16 @@ CPPSRCS		= \
 		MemoryMetrics.cpp \
 		RegExpObject.cpp \
 		RegExpStatics.cpp \
 		RegExp.cpp \
 		Memory.cpp \
 		Statistics.cpp \
 		StringBuffer.cpp \
 		Unicode.cpp \
-		Xdr.cpp \
 		$(NULL)
 
 # Changes to internal header files, used externally, massively slow down
 # browser builds.  Don't add new files here unless you know what you're
 # doing!
 INSTALLED_HEADERS = \
 		js-config.h \
 		jscpucfg.h \
@@ -205,16 +205,17 @@ INSTALLED_HEADERS = \
 		jsproto.tbl \
 		jsprvtd.h \
 		jspubtd.h \
 		jstypedarray.h \
 		jstypes.h \
 		jsutil.h \
 		jsversion.h \
 		jswrapper.h \
+		jsxdrapi.h \
 		jsval.h \
 		$(NULL)
 
 ######################################################
 # BEGIN exported headers that are only exported
 #       because of inclusion by an INSTALLED_HEADER
 #
 EXPORTS_NAMESPACES += ds gc
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -817,17 +817,17 @@ EmitFunctionScript(JSContext *cx, Byteco
  * enum, so its initializers need to match the order here.
  *
  * Note on adding new source notes: every pair of bytecodes (A, B) where A and
  * B have disjoint sets of source notes that could apply to each bytecode may
  * reuse the same note type value for two notes (snA, snB) that have the same
  * arity in JSSrcNoteSpec. This is why SRC_IF and SRC_INITPROP have the same
  * value below.
  *
- * Don't forget to update XDR_BYTECODE_VERSION in vm/Xdr.h for all such
+ * Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such
  * incompatible source note or other bytecode changes.
  */
 enum SrcNoteType {
     SRC_NULL        = 0,        /* terminates a note vector */
     SRC_IF          = 1,        /* JSOP_IFEQ bytecode is from an if-then */
     SRC_BREAK       = 1,        /* JSOP_GOTO is a break */
     SRC_INITPROP    = 1,        /* disjoint meaning applied to JSOP_INITELEM or
                                    to an index label in a regular (structuring)
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -141,21 +141,21 @@ MSG_DEF(JSMSG_MISSING_PAREN,           5
 MSG_DEF(JSMSG_UNTERM_CLASS,            55, 1, JSEXN_SYNTAXERR, "unterminated character class {0}")
 MSG_DEF(JSMSG_TRAILING_SLASH,          56, 0, JSEXN_SYNTAXERR, "trailing \\ in regular expression")
 MSG_DEF(JSMSG_BAD_CLASS_RANGE,         57, 0, JSEXN_SYNTAXERR, "invalid range in character class")
 MSG_DEF(JSMSG_BAD_REGEXP_FLAG,         58, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}")
 MSG_DEF(JSMSG_NO_INPUT,                59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}")
 MSG_DEF(JSMSG_CANT_OPEN,               60, 2, JSEXN_ERR, "can't open {0}: {1}")
 MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 61, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
 MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN,   62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
-MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE,       63, 0, JSEXN_INTERNALERR, "data are to big to encode")
-MSG_DEF(JSMSG_UNUSED64,                64, 0, JSEXN_NONE,    "")
-MSG_DEF(JSMSG_UNUSED65,                65, 0, JSEXN_NONE,    "")
-MSG_DEF(JSMSG_UNUSED66,                66, 0, JSEXN_NONE,    "")
-MSG_DEF(JSMSG_UNUSED67,                67, 0, JSEXN_NONE,    "")
+MSG_DEF(JSMSG_END_OF_DATA,             63, 0, JSEXN_INTERNALERR, "unexpected end of data")
+MSG_DEF(JSMSG_SEEK_BEYOND_START,       64, 0, JSEXN_INTERNALERR, "illegal seek beyond start")
+MSG_DEF(JSMSG_SEEK_BEYOND_END,         65, 0, JSEXN_INTERNALERR, "illegal seek beyond end")
+MSG_DEF(JSMSG_END_SEEK,                66, 0, JSEXN_INTERNALERR, "illegal end-based seek")
+MSG_DEF(JSMSG_WHITHER_WHENCE,          67, 1, JSEXN_INTERNALERR, "unknown seek whence: {0}")
 MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC,        68, 0, JSEXN_INTERNALERR, "bad script XDR magic number")
 MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL,     69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
 MSG_DEF(JSMSG_MISSING_FORMAL,          70, 0, JSEXN_SYNTAXERR, "missing formal parameter")
 MSG_DEF(JSMSG_PAREN_AFTER_FORMAL,      71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
 MSG_DEF(JSMSG_CURLY_BEFORE_BODY,       72, 0, JSEXN_SYNTAXERR, "missing { before function body")
 MSG_DEF(JSMSG_CURLY_AFTER_BODY,        73, 0, JSEXN_SYNTAXERR, "missing } after function body")
 MSG_DEF(JSMSG_PAREN_BEFORE_COND,       74, 0, JSEXN_SYNTAXERR, "missing ( before condition")
 MSG_DEF(JSMSG_PAREN_AFTER_COND,        75, 0, JSEXN_SYNTAXERR, "missing ) after condition")
--- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp
+++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
+#include "jsxdrapi.h"
 
 /* Do the test a bunch of times, because sometimes we seem to randomly
    miss the propcache */
 static const int expectedCount = 100;
 static int callCount = 0;
 
 static JSBool
 addProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
--- a/js/src/jsapi-tests/testCloneScript.cpp
+++ b/js/src/jsapi-tests/testCloneScript.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  *
  * Test script cloning.
  */
 
 #include "tests.h"
+#include "jsapi.h"
 #include "jsdbgapi.h"
+#include "jsxdrapi.h"
 
 BEGIN_TEST(test_cloneScript)
 {
     JSObject *A, *B;
 
     CHECK(A = createGlobal());
     CHECK(B = createGlobal());
 
--- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
+++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
+#include "jsxdrapi.h"
 
 static JSBool
 native(JSContext *cx, unsigned argc, jsval *vp)
 {
     return JS_TRUE;
 }
 
 static const char PROPERTY_NAME[] = "foo";
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -8,16 +8,17 @@
  */
 #include "js-config.h"
 #include "jsapi.h"
 #include "jsclass.h"
 #include "jscpucfg.h"
 #include "jspubtd.h"
 #include "jstypes.h"
 #include "jsval.h"
+#include "jsxdrapi.h"
 
 #include "js/HashTable.h"
 #include "js/MemoryMetrics.h"
 #include "js/TemplateLib.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 /*
--- a/js/src/jsapi-tests/testSetProperty.cpp
+++ b/js/src/jsapi-tests/testSetProperty.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
+#include "jsxdrapi.h"
 
 static JSBool
 nativeGet(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     *vp = INT_TO_JSVAL(17);
     return JS_TRUE;
 }
 
--- a/js/src/jsapi-tests/testXDR.cpp
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  */
 
 #include "tests.h"
 #include "jsscript.h"
+#include "jsxdrapi.h"
 
 static JSScript *
 CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
                                         JSPrincipals *principals, JSPrincipals *originPrincipals,
                                         const char *bytes, size_t nbytes,
                                         const char *filename, unsigned lineno,
                                         JSVersion version)
 {
@@ -22,52 +23,73 @@ CompileScriptForPrincipalsVersionOrigin(
     JSScript *script = JS_CompileUCScriptForPrincipalsVersionOrigin(cx, obj,
                                                                     principals, originPrincipals,
                                                                     chars, nchars,
                                                                     filename, lineno, version);
     free(chars);
     return script;
 }
 
-JSScript *
-FreezeThaw(JSContext *cx, JSScript *script)
+template<typename T>
+T *
+FreezeThawImpl(JSContext *cx, T *thing, JSBool (*xdrAction)(JSXDRState *xdr, T **))
 {
     // freeze
+    JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
+    if (!w)
+        return NULL;
+
+    void *memory = NULL;
     uint32_t nbytes;
-    void *memory = JS_EncodeScript(cx, script, &nbytes);
+    if (xdrAction(w, &thing)) {
+        void *p = JS_XDRMemGetData(w, &nbytes);
+        if (p) {
+            memory = JS_malloc(cx, nbytes);
+            if (memory)
+                memcpy(memory, p, nbytes);
+        }
+    }
+    JS_XDRDestroy(w);
     if (!memory)
         return NULL;
 
     // thaw
-    script = JS_DecodeScript(cx, memory, nbytes, script->principals, script->originPrincipals);
-    js_free(memory);
+    JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
+    JS_XDRMemSetData(r, memory, nbytes);
+
+    JSScript *script = GetScript(cx, thing);
+    JS_XDRSetPrincipals(r, script->principals, script->originPrincipals);
+    if (!xdrAction(r, &thing))
+        thing = NULL;
+    JS_XDRDestroy(r);  // this frees `memory
+    return thing;
+}
+
+static JSScript *
+GetScript(JSContext *cx, JSScript *script)
+{
     return script;
 }
 
 static JSScript *
 GetScript(JSContext *cx, JSObject *funobj)
 {
     return JS_GetFunctionScript(cx, JS_GetObjectFunction(funobj));
 }
 
-JSObject *
+static JSScript *
+FreezeThaw(JSContext *cx, JSScript *script)
+{
+    return FreezeThawImpl(cx, script, JS_XDRScript);
+}
+
+static JSObject *
 FreezeThaw(JSContext *cx, JSObject *funobj)
 {
-    // freeze
-    uint32_t nbytes;
-    void *memory = JS_EncodeInterpretedFunction(cx, funobj, &nbytes);
-    if (!memory)
-        return NULL;
-
-    // thaw
-    JSScript *script = GetScript(cx, funobj);
-    funobj = JS_DecodeInterpretedFunction(cx, memory, nbytes,
-                                          script->principals, script->originPrincipals);
-    js_free(memory);
-    return funobj;
+    return FreezeThawImpl(cx, funobj, JS_XDRFunctionObject);
 }
 
 static JSPrincipals testPrincipals[] = {
     { 1 },
     { 1 },
 };
 
 BEGIN_TEST(testXDR_principals)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -77,29 +77,28 @@
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "prmjtime.h"
 #include "jsweakmap.h"
 #include "jswrapper.h"
 #include "jstypedarray.h"
-#include "jsxml.h"
 
 #include "ds/LifoAlloc.h"
 #include "builtin/MapObject.h"
 #include "builtin/RegExp.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "gc/Memory.h"
 #include "js/MemoryMetrics.h"
+#include "mozilla/Util.h"
 #include "yarr/BumpPointerAllocator.h"
 #include "vm/MethodGuard.h"
 #include "vm/StringBuffer.h"
-#include "vm/Xdr.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/ObjectImpl-inl.h"
@@ -108,16 +107,20 @@
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 #if ENABLE_YARR_JIT
 #include "assembler/jit/ExecutableAllocator.h"
 #include "methodjit/Logging.h"
 #endif
 
+#if JS_HAS_XML_SUPPORT
+#include "jsxml.h"
+#endif
+
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 /*
  * This class is a version-establising barrier at the head of a VM entry or
  * re-entry. It ensures that:
  *
@@ -6630,48 +6633,8 @@ AutoGCRooter::AutoGCRooter(JSContext *cx
 
 AutoEnumStateRooter::~AutoEnumStateRooter()
 {
     if (!stateValue.isNull())
         MOZ_ALWAYS_TRUE(obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0));
 }
 
 } // namespace JS
-
-JS_PUBLIC_API(void *)
-JS_EncodeScript(JSContext *cx, JSScript *script, uint32_t *lengthp)
-{
-    XDREncoder encoder(cx);
-    if (!encoder.codeScript(&script))
-        return NULL;
-    return encoder.forgetData(lengthp);
-}
-
-JS_PUBLIC_API(void *)
-JS_EncodeInterpretedFunction(JSContext *cx, JSObject *funobj, uint32_t *lengthp)
-{
-    XDREncoder encoder(cx);
-    if (!encoder.codeFunction(&funobj))
-        return NULL;
-    return encoder.forgetData(lengthp);
-}
-
-JS_PUBLIC_API(JSScript *)
-JS_DecodeScript(JSContext *cx, const void *data, uint32_t length,
-                JSPrincipals *principals, JSPrincipals *originPrincipals)
-{
-    XDRDecoder decoder(cx, data, length, principals, originPrincipals);
-    JSScript *script;
-    if (!decoder.codeScript(&script))
-        return NULL;
-    return script;
-}
-
-JS_PUBLIC_API(JSObject *)
-JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
-                             JSPrincipals *principals, JSPrincipals *originPrincipals)
-{
-    XDRDecoder decoder(cx, data, length, principals, originPrincipals);
-    JSObject *funobj;
-    if (!decoder.codeFunction(&funobj))
-        return NULL;
-    return funobj;
-}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5405,29 +5405,11 @@ JS_IsIdentifier(JSContext *cx, JSString 
 /*
  * Return the current script and line number of the most currently running
  * frame. Returns true if a scripted frame was found, false otherwise.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_DescribeScriptedCaller(JSContext *cx, JSScript **script, unsigned *lineno);
 
 
-/*
- * Encode/Decode interpreted scripts and functions to/from memory.
- */
-
-extern JS_PUBLIC_API(void *)
-JS_EncodeScript(JSContext *cx, JSScript *script, uint32_t *lengthp);
-
-extern JS_PUBLIC_API(void *)
-JS_EncodeInterpretedFunction(JSContext *cx, JSObject *funobj, uint32_t *lengthp);
-
-extern JS_PUBLIC_API(JSScript *)
-JS_DecodeScript(JSContext *cx, const void *data, uint32_t length,
-                JSPrincipals *principals, JSPrincipals *originPrincipals);
-
-extern JS_PUBLIC_API(JSObject *)
-JS_DecodeInterpretedFunction(JSContext *cx, const void *data, uint32_t length,
-                             JSPrincipals *principals, JSPrincipals *originPrincipals);
-
 JS_END_EXTERN_C
 
 #endif /* jsapi_h___ */
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -63,17 +63,16 @@
 
 #include "frontend/Parser.h"
 
 #include "jsstrinlines.h"
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/String-inl.h"
-#include "vm/Xdr.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 
 const size_t JSAtomState::commonAtomsOffset = offsetof(JSAtomState, emptyAtom);
 const size_t JSAtomState::lazyAtomsOffset = offsetof(JSAtomState, lazy);
 
@@ -653,70 +652,8 @@ js_InternNonIntElementIdSlow(JSContext *
 
     if (js_ValueToStringId(cx, idval, idp)) {
         vp->setString(JSID_TO_STRING(*idp));
         return true;
     }
     return false;
 }
 #endif
-
-template<XDRMode mode>
-bool
-js::XDRAtom(XDRState<mode> *xdr, JSAtom **atomp)
-{
-    if (mode == XDR_ENCODE) {
-        JSString *str = *atomp;
-        return xdr->codeString(&str);
-    }
-
-    /*
-     * Inline XDRState::codeString when decoding to avoid JSString allocation
-     * for already existing atoms. See bug 321985.
-     */
-    uint32_t nchars;
-    if (!xdr->codeUint32(&nchars))
-        return false;
-
-    JSContext *cx = xdr->cx();
-    JSAtom *atom;
-#if IS_LITTLE_ENDIAN
-    /* Directly access the little endian chars in the XDR buffer. */
-    const jschar *chars = reinterpret_cast<const jschar *>(xdr->buf.read(nchars * sizeof(jschar)));
-    atom = js_AtomizeChars(cx, chars, nchars);
-#else
-    /*
-     * We must copy chars to a temporary buffer to convert between little and
-     * big endian data.
-     */ 
-    jschar *chars;
-    jschar stackChars[256];
-    if (nchars <= ArrayLength(stackChars)) {
-        chars = stackChars;
-    } else {
-        /*
-         * This is very uncommon. Don't use the tempLifoAlloc arena for this as
-         * most allocations here will be bigger than tempLifoAlloc's default
-         * chunk size.
-         */
-        chars = static_cast<jschar *>(cx->runtime->malloc_(nchars * sizeof(jschar)));
-        if (!chars)
-            return false;
-    }
-
-    JS_ALWAYS_TRUE(xdr->codeChars(chars, nchars));
-    atom = js_AtomizeChars(cx, chars, nchars);
-    if (chars != stackChars)
-        Foreground::free_(chars);
-#endif /* !IS_LITTLE_ENDIAN */
-
-    if (!atom)
-        return false;
-    *atomp = atom;
-    return true;
-}
-
-template bool
-js::XDRAtom(XDRState<XDR_ENCODE> *xdr, JSAtom **atomp);
-
-template bool
-js::XDRAtom(XDRState<XDR_DECODE> *xdr, JSAtom **atomp);
-
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -473,17 +473,9 @@ js_InternNonIntElementId(JSContext *cx, 
 /*
  * For all unmapped atoms recorded in al, add a mapping from the atom's index
  * to its address. map->length must already be set to the number of atoms in
  * the list and map->vector must point to pre-allocated memory.
  */
 extern void
 js_InitAtomMap(JSContext *cx, js::AtomIndexMap *indices, JSAtom **atoms);
 
-namespace js {
-
-template<XDRMode mode>
-bool
-XDRAtom(XDRState<mode> *xdr, JSAtom **atomp);
-
-} /* namespace js */
-
 #endif /* jsatom_h___ */
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -516,18 +516,18 @@ StringIsArrayIndex(JSLinearString *str, 
 JS_FRIEND_API(void)
 SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback);
 
 JS_FRIEND_API(bool)
 IsObjectInContextCompartment(const JSObject *obj, const JSContext *cx);
 
 /*
  * NB: these flag bits are encoded into the bytecode stream in the immediate
- * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's
- * XDR_BYTECODE_VERSION.
+ * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's
+ * JSXDR_BYTECODE_VERSION.
  */
 #define JSITER_ENUMERATE  0x1   /* for-in compatible hidden default iterator */
 #define JSITER_FOREACH    0x2   /* return [key, value] pair rather than key */
 #define JSITER_KEYVALUE   0x4   /* destructuring for-in wants [key, value] */
 #define JSITER_OWNONLY    0x8   /* iterate over obj's own properties only */
 #define JSITER_HIDDEN     0x10  /* also enumerate non-enumerable properties */
 #define JSITER_FOR_OF     0x20  /* harmony for-of loop */
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -47,43 +47,47 @@
 
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
-#include "jsexn.h"
+#include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
 #include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jspropertytree.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
+#include "jsexn.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/TokenStream.h"
 #include "vm/Debugger.h"
 #include "vm/MethodGuard.h"
 #include "vm/ScopeObject.h"
-#include "vm/Xdr.h"
 
 #if JS_HAS_GENERATORS
 # include "jsiter.h"
 #endif
 
+#if JS_HAS_XDR
+# include "jsxdrapi.h"
+#endif
+
 #ifdef JS_METHODJIT
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
@@ -471,30 +475,33 @@ fun_resolve(JSContext *cx, JSObject *obj
             *objp = fun;
             return true;
         }
     }
 
     return true;
 }
 
-template<XDRMode mode>
-bool
-js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript)
+#if JS_HAS_XDR
+
+/* XXX store parent and proto, if defined */
+JSBool
+js::XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
 {
+    JSContext *cx;
     JSFunction *fun;
     JSAtom *atom;
     uint32_t firstword;           /* flag telling whether fun->atom is non-null,
                                    plus for fun->u.i.skipmin, fun->u.i.wrapper,
                                    and 14 bits reserved for future use */
     uint32_t flagsword;           /* word for argument count and fun->flags */
 
-    JSContext *cx = xdr->cx();
+    cx = xdr->cx;
     JSScript *script;
-    if (mode == XDR_ENCODE) {
+    if (xdr->mode == JSXDR_ENCODE) {
         fun = (*objp)->toFunction();
         if (!fun->isInterpreted()) {
             JSAutoByteString funNameBytes;
             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
                                      name);
             }
             return false;
@@ -511,47 +518,43 @@ js::XDRInterpretedFunction(XDRState<mode
         if (!fun->clearParent(cx))
             return false;
         if (!fun->clearType(cx))
             return false;
         atom = NULL;
         script = NULL;
     }
 
-    if (!xdr->codeUint32(&firstword))
+    if (!JS_XDRUint32(xdr, &firstword))
         return false;
-    if ((firstword & 1U) && !XDRAtom(xdr, &atom))
+    if ((firstword & 1U) && !js_XDRAtom(xdr, &atom))
         return false;
-    if (!xdr->codeUint32(&flagsword))
+    if (!JS_XDRUint32(xdr, &flagsword))
         return false;
 
-    if (!XDRScript(xdr, &script, parentScript))
+    if (!XDRScript(xdr, &script))
         return false;
 
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         fun->nargs = flagsword >> 16;
         JS_ASSERT((flagsword & JSFUN_KINDMASK) >= JSFUN_INTERPRETED);
         fun->flags = uint16_t(flagsword);
         fun->atom.init(atom);
         fun->initScript(script);
         if (!script->typeSetFunction(cx, fun))
             return false;
         JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
         js_CallNewScriptHook(cx, fun->script(), fun);
         *objp = fun;
     }
 
     return true;
 }
 
-template bool
-js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *xdr, JSObject **objp, JSScript *parentScript);
-
-template bool
-js::XDRInterpretedFunction(XDRState<XDR_DECODE> *xdr, JSObject **objp, JSScript *parentScript);
+#endif /* JS_HAS_XDR */
 
 /*
  * [[HasInstance]] internal method for Function objects: fetch the .prototype
  * property of its 'this' parameter, and walks the prototype chain of v (only
  * if v is an object) returning true if .prototype is found.
  */
 static JSBool
 fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -351,19 +351,18 @@ JSFunction::toExtended() const
 extern void
 js_PutArgsObject(js::StackFrame *fp);
 
 inline bool
 js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
 
 namespace js {
 
-template<XDRMode mode>
-bool
-XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
+extern JSBool
+XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
 
 } /* namespace js */
 
 extern JSBool
 js_fun_apply(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern JSBool
 js_fun_call(JSContext *cx, unsigned argc, js::Value *vp);
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -69,27 +69,27 @@
 #define JSDOUBLE_HI32_EXPMASK   0x7ff00000
 #define JSDOUBLE_HI32_MANTMASK  0x000fffff
 #define JSDOUBLE_HI32_NAN       0x7ff80000
 #define JSDOUBLE_LO32_NAN       0x00000000
 
 #define JSDOUBLE_HI32_EXPSHIFT  20
 #define JSDOUBLE_EXPBIAS        1023
 
-union jsdpun {
+typedef union jsdpun {
     struct {
 #if defined(IS_LITTLE_ENDIAN) && !defined(FPU_IS_ARM_FPA)
         uint32_t lo, hi;
 #else
         uint32_t hi, lo;
 #endif
     } s;
     uint64_t u64;
     double d;
-};
+} jsdpun;
 
 static inline int
 JSDOUBLE_IS_NaN(double d)
 {
     jsdpun u;
     u.d = d;
     return (u.u64 & JSDOUBLE_EXPMASK) == JSDOUBLE_EXPMASK &&
            (u.u64 & JSDOUBLE_MANTMASK) != 0;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -71,35 +71,41 @@
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsdbgapi.h"
 #include "json.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
-#include "jsxml.h"
 
 #include "builtin/MapObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
+#include "vm/StringBuffer.h"
 #include "js/MemoryMetrics.h"
-#include "vm/StringBuffer.h"
-#include "vm/Xdr.h"
 
 #include "jsarrayinlines.h"
 #include "jsatominlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/MethodGuard-inl.h"
 
+#if JS_HAS_XML_SUPPORT
+#include "jsxml.h"
+#endif
+
+#if JS_HAS_XDR
+#include "jsxdrapi.h"
+#endif
+
 #include "jsautooplen.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 JS_STATIC_ASSERT(int32_t((JSObject::NELEMENTS_LIMIT - 1) * sizeof(Value)) == int64_t((JSObject::NELEMENTS_LIMIT - 1) * sizeof(Value)));
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -311,24 +311,16 @@ typedef Handle<JSFunction*>        Handl
 typedef Handle<Shape*>             HandleShape;
 typedef Handle<BaseShape*>         HandleBaseShape;
 typedef Handle<types::TypeObject*> HandleTypeObject;
 typedef Handle<JSString*>          HandleString;
 typedef Handle<JSAtom*>            HandleAtom;
 typedef Handle<jsid>               HandleId;
 typedef Handle<Value>              HandleValue;
 
-enum XDRMode {
-    XDR_ENCODE,
-    XDR_DECODE
-};
-
-template <XDRMode mode>
-class XDRState;
-
 } /* namespace js */
 
 namespace JSC {
 
 class ExecutableAllocator;
 
 } /* namespace JSC */
 
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -221,24 +221,25 @@ typedef struct JSPropertySpec           
 typedef struct JSRuntime                    JSRuntime;
 typedef struct JSSecurityCallbacks          JSSecurityCallbacks;
 typedef struct JSStackFrame                 JSStackFrame;
 typedef struct JSScript          JSScript;
 typedef struct JSStructuredCloneCallbacks   JSStructuredCloneCallbacks;
 typedef struct JSStructuredCloneReader      JSStructuredCloneReader;
 typedef struct JSStructuredCloneWriter      JSStructuredCloneWriter;
 typedef struct JSTracer                     JSTracer;
+typedef struct JSXDRState                   JSXDRState;
 
 #ifdef __cplusplus
 class                                       JSFlatString;
 class                                       JSString;
 #else
 typedef struct JSFlatString                 JSFlatString;
 typedef struct JSString                     JSString;
-#endif /* !__cplusplus */
+#endif
 
 #ifdef JS_THREADSAFE
 typedef struct PRCallOnceType    JSCallOnceType;
 #else
 typedef JSBool                   JSCallOnceType;
 #endif
 typedef JSBool                 (*JSInitCallback)(void);
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -57,24 +57,26 @@
 #include "jsgc.h"
 #include "jsgcmark.h"
 #include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
+#if JS_HAS_XDR
+#include "jsxdrapi.h"
+#endif
 
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Retcon.h"
 #include "vm/Debugger.h"
-#include "vm/Xdr.h"
 
 #include "jsinferinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 using namespace js;
 using namespace js::gc;
@@ -289,21 +291,20 @@ Bindings::makeImmutable()
 
 void
 Bindings::trace(JSTracer *trc)
 {
     if (lastBinding)
         MarkShape(trc, &lastBinding, "shape");
 }
 
-} /* namespace js */
+#if JS_HAS_XDR
 
-template<XDRMode mode>
 static bool
-XDRScriptConst(XDRState<mode> *xdr, HeapValue *vp)
+XDRScriptConst(JSXDRState *xdr, HeapValue *vp)
 {
     /*
      * A script constant can be an arbitrary primitive value as they are used
      * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
      * bug 407186.
      */
     enum ConstTag {
         SCRIPT_INT     = 0,
@@ -311,17 +312,17 @@ XDRScriptConst(XDRState<mode> *xdr, Heap
         SCRIPT_STRING  = 2,
         SCRIPT_TRUE    = 3,
         SCRIPT_FALSE   = 4,
         SCRIPT_NULL    = 5,
         SCRIPT_VOID    = 6
     };
 
     uint32_t tag;
-    if (mode == XDR_ENCODE) {
+    if (xdr->mode == JSXDR_ENCODE) {
         if (vp->isInt32()) {
             tag = SCRIPT_INT;
         } else if (vp->isDouble()) {
             tag = SCRIPT_DOUBLE;
         } else if (vp->isString()) {
             tag = SCRIPT_STRING;
         } else if (vp->isTrue()) {
             tag = SCRIPT_TRUE;
@@ -330,121 +331,119 @@ XDRScriptConst(XDRState<mode> *xdr, Heap
         } else if (vp->isNull()) {
             tag = SCRIPT_NULL;
         } else {
             JS_ASSERT(vp->isUndefined());
             tag = SCRIPT_VOID;
         }
     }
 
-    if (!xdr->codeUint32(&tag))
+    if (!JS_XDRUint32(xdr, &tag))
         return false;
 
     switch (tag) {
       case SCRIPT_INT: {
         uint32_t i;
-        if (mode == XDR_ENCODE)
+        if (xdr->mode == JSXDR_ENCODE)
             i = uint32_t(vp->toInt32());
-        if (!xdr->codeUint32(&i))
+        if (!JS_XDRUint32(xdr, &i))
             return JS_FALSE;
-        if (mode == XDR_DECODE)
+        if (xdr->mode == JSXDR_DECODE)
             vp->init(Int32Value(int32_t(i)));
         break;
       }
       case SCRIPT_DOUBLE: {
         double d;
-        if (mode == XDR_ENCODE)
+        if (xdr->mode == JSXDR_ENCODE)
             d = vp->toDouble();
-        if (!xdr->codeDouble(&d))
+        if (!JS_XDRDouble(xdr, &d))
             return false;
-        if (mode == XDR_DECODE)
+        if (xdr->mode == JSXDR_DECODE)
             vp->init(DoubleValue(d));
         break;
       }
       case SCRIPT_STRING: {
         JSString *str;
-        if (mode == XDR_ENCODE)
+        if (xdr->mode == JSXDR_ENCODE)
             str = vp->toString();
-        if (!xdr->codeString(&str))
+        if (!JS_XDRString(xdr, &str))
             return false;
-        if (mode == XDR_DECODE)
+        if (xdr->mode == JSXDR_DECODE)
             vp->init(StringValue(str));
         break;
       }
       case SCRIPT_TRUE:
-        if (mode == XDR_DECODE)
+        if (xdr->mode == JSXDR_DECODE)
             vp->init(BooleanValue(true));
         break;
       case SCRIPT_FALSE:
-        if (mode == XDR_DECODE)
+        if (xdr->mode == JSXDR_DECODE)
             vp->init(BooleanValue(false));
         break;
       case SCRIPT_NULL:
-        if (mode == XDR_DECODE)
+        if (xdr->mode == JSXDR_DECODE)
             vp->init(NullValue());
         break;
       case SCRIPT_VOID:
-        if (mode == XDR_DECODE)
+        if (xdr->mode == JSXDR_DECODE)
             vp->init(UndefinedValue());
         break;
     }
     return true;
 }
 
 static const char *
 SaveScriptFilename(JSContext *cx, const char *filename);
 
-template<XDRMode mode>
-bool
-js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
+JSBool
+XDRScript(JSXDRState *xdr, JSScript **scriptp)
 {
     enum ScriptBits {
         NoScriptRval,
         SavedCallerFun,
         StrictModeCode,
         UsesEval,
         MayNeedArgsObj,
         NeedsArgsObj,
         OwnFilename,
-        ParentFilename
+        SharedFilename
     };
 
     uint32_t length, lineno, nslots;
     uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, i;
     uint32_t prologLength, version, encodedClosedCount;
     uint16_t nClosedArgs = 0, nClosedVars = 0;
     uint32_t nTypeSets = 0;
     uint32_t scriptBits = 0;
 
-    JSContext *cx = xdr->cx();
+    JSContext *cx = xdr->cx;
     JSScript *script;
     nsrcnotes = ntrynotes = natoms = nobjects = nregexps = nconsts = 0;
     jssrcnote *notes = NULL;
 
     /* XDR arguments, local vars, and upvars. */
     uint16_t nargs, nvars;
 #if defined(DEBUG) || defined(__GNUC__) /* quell GCC overwarning */
     script = NULL;
     nargs = nvars = Bindings::BINDING_COUNT_LIMIT;
 #endif
     uint32_t argsVars;
-    if (mode == XDR_ENCODE) {
+    if (xdr->mode == JSXDR_ENCODE) {
         script = *scriptp;
-        JS_ASSERT_IF(parentScript, parentScript->compartment() == script->compartment());
-    
+
         /* Should not XDR scripts optimized for a single global object. */
         JS_ASSERT(!JSScript::isValidOffset(script->globalsOffset));
 
         nargs = script->bindings.countArgs();
         nvars = script->bindings.countVars();
         argsVars = (nargs << 16) | nvars;
     }
-    if (!xdr->codeUint32(&argsVars))
+    if (!JS_XDRUint32(xdr, &argsVars))
         return false;
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         nargs = argsVars >> 16;
         nvars = argsVars & 0xFFFF;
     }
     JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT);
     JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT);
 
     Bindings bindings(cx);
     uint32_t nameCount = nargs + nvars;
@@ -462,74 +461,74 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
         unsigned bitmapLength = JS_HOWMANY(nameCount, JS_BITS_PER_UINT32);
         uint32_t *bitmap = cx->tempLifoAlloc().newArray<uint32_t>(bitmapLength);
         if (!bitmap) {
             js_ReportOutOfMemory(cx);
             return false;
         }
 
         Vector<JSAtom *> names(cx);
-        if (mode == XDR_ENCODE) {
+        if (xdr->mode == JSXDR_ENCODE) {
             if (!script->bindings.getLocalNameArray(cx, &names))
                 return false;
             PodZero(bitmap, bitmapLength);
             for (unsigned i = 0; i < nameCount; i++) {
                 if (i < nargs && names[i])
                     bitmap[i >> JS_BITS_PER_UINT32_LOG2] |= JS_BIT(i & (JS_BITS_PER_UINT32 - 1));
             }
         }
         for (unsigned i = 0; i < bitmapLength; ++i) {
-            if (!xdr->codeUint32(&bitmap[i]))
+            if (!JS_XDRUint32(xdr, &bitmap[i]))
                 return false;
         }
 
         for (unsigned i = 0; i < nameCount; i++) {
             if (i < nargs &&
                 !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] & JS_BIT(i & (JS_BITS_PER_UINT32 - 1))))
             {
-                if (mode == XDR_DECODE) {
+                if (xdr->mode == JSXDR_DECODE) {
                     uint16_t dummy;
                     if (!bindings.addDestructuring(cx, &dummy))
                         return false;
                 } else {
                     JS_ASSERT(!names[i]);
                 }
                 continue;
             }
 
             JSAtom *name;
-            if (mode == XDR_ENCODE)
+            if (xdr->mode == JSXDR_ENCODE)
                 name = names[i];
-            if (!XDRAtom(xdr, &name))
+            if (!js_XDRAtom(xdr, &name))
                 return false;
-            if (mode == XDR_DECODE) {
+            if (xdr->mode == JSXDR_DECODE) {
                 BindingKind kind = (i < nargs)
                                    ? ARGUMENT
                                    : (bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
                                       JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
                                      ? CONSTANT
                                      : VARIABLE);
                 if (!bindings.add(cx, name, kind))
                     return false;
             }
         }
     }
 
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         if (!bindings.ensureShape(cx))
             return false;
         bindings.makeImmutable();
     }
 
-    if (mode == XDR_ENCODE)
+    if (xdr->mode == JSXDR_ENCODE)
         length = script->length;
-    if (!xdr->codeUint32(&length))
+    if (!JS_XDRUint32(xdr, &length))
         return JS_FALSE;
 
-    if (mode == XDR_ENCODE) {
+    if (xdr->mode == JSXDR_ENCODE) {
         prologLength = script->mainOffset;
         JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN);
         version = (uint32_t)script->getVersion() | (script->nfixed << 16);
         lineno = script->lineno;
         nslots = (uint32_t)script->nslots;
         nslots = (uint32_t)((script->staticLevel << 16) | script->nslots);
         natoms = script->natoms;
 
@@ -565,54 +564,54 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
              * In some cases, the front-end calls setNeedsArgsObj when the
              * script definitely needsArgsObj; preserve this information which
              * would otherwise be lost.
              */
             if (script->analyzedArgsUsage() && script->needsArgsObj())
                 scriptBits |= (1 << NeedsArgsObj);
         }
         if (script->filename) {
-            scriptBits |= (parentScript && parentScript->filename == script->filename)
-                          ? (1 << ParentFilename)
-                          : (1 << OwnFilename);
+            scriptBits |= (script->filename != xdr->sharedFilename)
+                          ? (1 << OwnFilename)
+                          : (1 << SharedFilename);
         }
 
         JS_ASSERT(!script->compileAndGo);
         JS_ASSERT(!script->hasSingletons);
     }
 
-    if (!xdr->codeUint32(&prologLength))
+    if (!JS_XDRUint32(xdr, &prologLength))
         return JS_FALSE;
-    if (!xdr->codeUint32(&version))
+    if (!JS_XDRUint32(xdr, &version))
         return JS_FALSE;
 
     /*
      * To fuse allocations, we need srcnote, atom, objects, regexp, and trynote
      * counts early.
      */
-    if (!xdr->codeUint32(&natoms))
+    if (!JS_XDRUint32(xdr, &natoms))
         return JS_FALSE;
-    if (!xdr->codeUint32(&nsrcnotes))
+    if (!JS_XDRUint32(xdr, &nsrcnotes))
         return JS_FALSE;
-    if (!xdr->codeUint32(&ntrynotes))
+    if (!JS_XDRUint32(xdr, &ntrynotes))
         return JS_FALSE;
-    if (!xdr->codeUint32(&nobjects))
+    if (!JS_XDRUint32(xdr, &nobjects))
         return JS_FALSE;
-    if (!xdr->codeUint32(&nregexps))
+    if (!JS_XDRUint32(xdr, &nregexps))
         return JS_FALSE;
-    if (!xdr->codeUint32(&nconsts))
+    if (!JS_XDRUint32(xdr, &nconsts))
         return JS_FALSE;
-    if (!xdr->codeUint32(&encodedClosedCount))
+    if (!JS_XDRUint32(xdr, &encodedClosedCount))
         return JS_FALSE;
-    if (!xdr->codeUint32(&nTypeSets))
+    if (!JS_XDRUint32(xdr, &nTypeSets))
         return JS_FALSE;
-    if (!xdr->codeUint32(&scriptBits))
+    if (!JS_XDRUint32(xdr, &scriptBits))
         return JS_FALSE;
 
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         nClosedArgs = encodedClosedCount >> 16;
         nClosedVars = encodedClosedCount & 0xFFFF;
 
         /* Note: version is packed into the 32b space with another 16b value. */
         JSVersion version_ = JSVersion(version & JS_BITMASK(16));
         JS_ASSERT((version_ & VersionFlags::FULL_MASK) == unsigned(version_));
         script = JSScript::NewScript(cx, length, nsrcnotes, natoms, nobjects,
                                      nregexps, ntrynotes, nconsts, 0, nClosedArgs,
@@ -633,101 +632,116 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
             script->noScriptRval = true;
         if (scriptBits & (1 << SavedCallerFun))
             script->savedCallerFun = true;
         if (scriptBits & (1 << StrictModeCode))
             script->strictModeCode = true;
         if (scriptBits & (1 << UsesEval))
             script->usesEval = true;
         if (scriptBits & (1 << MayNeedArgsObj)) {
-            script->setMayNeedArgsObj();
+            script->mayNeedArgsObj_ = true;
             if (scriptBits & (1 << NeedsArgsObj))
                 script->setNeedsArgsObj(true);
         } else {
             JS_ASSERT(!(scriptBits & (1 << NeedsArgsObj)));
         }
     }
 
-    JS_STATIC_ASSERT(sizeof(jsbytecode) == 1);
-    JS_STATIC_ASSERT(sizeof(jssrcnote) == 1);
-    if (!xdr->codeBytes(script->code, length) ||
-        !xdr->codeBytes(notes, nsrcnotes) ||
-        !xdr->codeUint32(&lineno) ||
-        !xdr->codeUint32(&nslots)) {
+    if (!JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode)))
+        return false;
+
+    if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
+        !JS_XDRUint32(xdr, &lineno) ||
+        !JS_XDRUint32(xdr, &nslots)) {
         return false;
     }
 
     if (scriptBits & (1 << OwnFilename)) {
-        const char *filename;
-        if (mode == XDR_ENCODE)
-            filename = script->filename;
-        if (!xdr->codeCString(&filename))
+        char *filename;
+        if (xdr->mode == JSXDR_ENCODE)
+            filename = const_cast<char *>(script->filename);
+        if (!JS_XDRCString(xdr, &filename))
             return false;
-        if (mode == XDR_DECODE) {
-            script->filename = SaveScriptFilename(cx, filename);
+        if (xdr->mode == JSXDR_DECODE) {
+            script->filename = SaveScriptFilename(xdr->cx, filename);
+            Foreground::free_(filename);
             if (!script->filename)
                 return false;
         }
-    } else if (scriptBits & (1 << ParentFilename)) {
-        JS_ASSERT(parentScript);
-        if (mode == XDR_DECODE)
-            script->filename = parentScript->filename;
+        if (!xdr->sharedFilename)
+            xdr->sharedFilename = script->filename;
+    } else if (scriptBits & (1 << SharedFilename)) {
+        JS_ASSERT(xdr->sharedFilename);
+        if (xdr->mode == JSXDR_DECODE)
+            script->filename = xdr->sharedFilename;
     }
 
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         script->lineno = lineno;
         script->nslots = uint16_t(nslots);
         script->staticLevel = uint16_t(nslots >> 16);
-        xdr->initScriptPrincipals(script);
+
+        /* The origin principals must be normalized at this point. */ 
+        JS_ASSERT_IF(xdr->principals, xdr->originPrincipals);
+        JS_ASSERT(!script->principals);
+        JS_ASSERT(!script->originPrincipals);
+        if (xdr->principals) {
+            script->principals = xdr->principals;
+            JS_HoldPrincipals(xdr->principals);
+        }
+        if (xdr->originPrincipals) {
+            script->originPrincipals = xdr->originPrincipals;
+            JS_HoldPrincipals(xdr->originPrincipals);
+        }
     }
 
     for (i = 0; i != natoms; ++i) {
-        if (!XDRAtom(xdr, &script->atoms[i]))
+        if (!js_XDRAtom(xdr, &script->atoms[i]))
             return false;
     }
 
     /*
      * Here looping from 0-to-length to xdr objects is essential. It ensures
      * that block objects from the script->objects array will be written and
      * restored in the outer-to-inner order. js_XDRBlockObject relies on this
      * to restore the parent chain.
      */
     for (i = 0; i != nobjects; ++i) {
         HeapPtr<JSObject> *objp = &script->objects()->vector[i];
         uint32_t isBlock;
-        if (mode == XDR_ENCODE) {
+        if (xdr->mode == JSXDR_ENCODE) {
             JSObject *obj = *objp;
             JS_ASSERT(obj->isFunction() || obj->isStaticBlock());
             isBlock = obj->isBlock() ? 1 : 0;
         }
-        if (!xdr->codeUint32(&isBlock))
+        if (!JS_XDRUint32(xdr, &isBlock))
             return false;
         if (isBlock == 0) {
             JSObject *tmp = *objp;
-            if (!XDRInterpretedFunction(xdr, &tmp, parentScript))
+            if (!XDRFunctionObject(xdr, &tmp))
                 return false;
             *objp = tmp;
         } else {
             JS_ASSERT(isBlock == 1);
             StaticBlockObject *tmp = static_cast<StaticBlockObject *>(objp->get());
             if (!XDRStaticBlockObject(xdr, script, &tmp))
                 return false;
             *objp = tmp;
         }
     }
     for (i = 0; i != nregexps; ++i) {
         if (!XDRScriptRegExpObject(xdr, &script->regexps()->vector[i]))
             return false;
     }
     for (i = 0; i != nClosedArgs; ++i) {
-        if (!xdr->codeUint32(&script->closedSlots[i]))
+        if (!JS_XDRUint32(xdr, &script->closedSlots[i]))
             return false;
     }
     for (i = 0; i != nClosedVars; ++i) {
-        if (!xdr->codeUint32(&script->closedSlots[nClosedArgs + i]))
+        if (!JS_XDRUint32(xdr, &script->closedSlots[nClosedArgs + i]))
             return false;
     }
 
     if (ntrynotes != 0) {
         /*
          * We combine tn->kind and tn->stackDepth when serializing as XDR is not
          * efficient when serializing small integer types.
          */
@@ -736,54 +750,52 @@ js::XDRScript(XDRState<mode> *xdr, JSScr
         JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8_t));
         JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16_t));
 
         tnfirst = script->trynotes()->vector;
         JS_ASSERT(script->trynotes()->length == ntrynotes);
         tn = tnfirst + ntrynotes;
         do {
             --tn;
-            if (mode == XDR_ENCODE) {
+            if (xdr->mode == JSXDR_ENCODE) {
                 kindAndDepth = (uint32_t(tn->kind) << 16)
                                | uint32_t(tn->stackDepth);
             }
-            if (!xdr->codeUint32(&kindAndDepth) ||
-                !xdr->codeUint32(&tn->start) ||
-                !xdr->codeUint32(&tn->length)) {
+            if (!JS_XDRUint32(xdr, &kindAndDepth) ||
+                !JS_XDRUint32(xdr, &tn->start) ||
+                !JS_XDRUint32(xdr, &tn->length)) {
                 return false;
             }
-            if (mode == XDR_DECODE) {
+            if (xdr->mode == JSXDR_DECODE) {
                 tn->kind = uint8_t(kindAndDepth >> 16);
                 tn->stackDepth = uint16_t(kindAndDepth);
             }
         } while (tn != tnfirst);
     }
 
     if (nconsts) {
         HeapValue *vector = script->consts()->vector;
         for (i = 0; i != nconsts; ++i) {
             if (!XDRScriptConst(xdr, &vector[i]))
                 return false;
         }
     }
 
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         if (cx->hasRunOption(JSOPTION_PCCOUNT))
             (void) script->initCounts(cx);
         *scriptp = script;
     }
 
     return true;
 }
 
-template bool
-js::XDRScript(XDRState<XDR_ENCODE> *xdr, JSScript **scriptp, JSScript *parentScript);
+#endif /* JS_HAS_XDR */
 
-template bool
-js::XDRScript(XDRState<XDR_DECODE> *xdr, JSScript **scriptp, JSScript *parentScript);
+} /* namespace js */
 
 bool
 JSScript::initCounts(JSContext *cx)
 {
     JS_ASSERT(!pcCounters);
 
     size_t count = 0;
 
@@ -827,16 +839,18 @@ void
 JSScript::destroyCounts(JSContext *cx)
 {
     if (pcCounters) {
         cx->free_(pcCounters.counts);
         pcCounters.counts = NULL;
     }
 }
 
+namespace js {
+
 /*
  * Shared script filename management.
  */
 
 static const char *
 SaveScriptFilename(JSContext *cx, const char *filename)
 {
     JSCompartment *comp = cx->compartment;
@@ -905,16 +919,18 @@ FreeScriptFilenames(JSCompartment *comp)
 {
     ScriptFilenameTable &table = comp->scriptFilenameTable;
     for (ScriptFilenameTable::Enum e(table); !e.empty(); e.popFront())
         Foreground::free_(e.front());
 
     table.clear();
 }
 
+} /* namespace js */
+
 /*
  * JSScript data structures memory alignment:
  *
  * JSScript
  * JSObjectArray    script objects' descriptor if JSScript.objectsOffset != 0,
  *                    use script->objects() to access it.
  * JSObjectArray    script regexps' descriptor if JSScript.regexpsOffset != 0,
  *                    use script->regexps() to access it.
@@ -1219,17 +1235,17 @@ JSScript::NewScriptFromEmitter(JSContext
     /*
      * The arguments-usage analysis in analyzeSSA only looks at
      * JSOP_ARGUMENTS use. Therefore, anything else that definitely requires an
      * arguments object needs to be accounted for here.
      */
     if (bce->inFunction()) {
         bool needsArgsObj = bce->mayOverwriteArguments() || bce->needsEagerArguments();
         if (needsArgsObj || bce->usesArguments()) {
-            script->setMayNeedArgsObj();
+            script->mayNeedArgsObj_ = true;
             if (needsArgsObj)
                 script->setNeedsArgsObj(true);
         }
     }
 
     if (bce->globalUses.length()) {
         PodCopy<GlobalSlotArray::Entry>(script->globals()->vector, &bce->globalUses[0],
                                         bce->globalUses.length());
@@ -1605,42 +1621,84 @@ CurrentScriptFileLineOriginSlow(JSContex
     }
 
     JSScript *script = iter.fp()->script();
     *file = script->filename;
     *linenop = PCToLineNumber(iter.fp()->script(), iter.pc());
     *origin = script->originPrincipals;
 }
 
-}  /* namespace js */
+class AutoJSXDRState {
+  public:
+    AutoJSXDRState(JSXDRState *x
+                   JS_GUARD_OBJECT_NOTIFIER_PARAM)
+        : xdr(x)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+    ~AutoJSXDRState()
+    {
+        JS_XDRDestroy(xdr);
+    }
+
+    operator JSXDRState*() const
+    {
+        return xdr;
+    }
+
+    JSXDRState* operator->() const
+    {
+        return xdr;
+    }
+
+  private:
+    JSXDRState *const xdr;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
 
 JSScript *
-js::CloneScript(JSContext *cx, JSScript *script)
+CloneScript(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(cx->compartment != script->compartment());
 
     /* Serialize script. */
-    XDREncoder encoder(cx);
+    AutoJSXDRState w(JS_XDRNewMem(cx, JSXDR_ENCODE));
+    if (!w)
+        return NULL;
 
-    if (!XDRScript(&encoder, &script, NULL))
+    if (!XDRScript(w, &script))
         return NULL;
 
     uint32_t nbytes;
-    const void *p = encoder.getData(&nbytes);
+    void *p = JS_XDRMemGetData(w, &nbytes);
+    if (!p)
+        return NULL;
 
     /* De-serialize script. */
-    XDRDecoder decoder(cx, p, nbytes, cx->compartment->principals, script->originPrincipals);
+    AutoJSXDRState r(JS_XDRNewMem(cx, JSXDR_DECODE));
+    if (!r)
+        return NULL;
 
-    JSScript *newScript;
-    if (!XDRScript(&decoder, &newScript, NULL))
+    /*
+     * Hand p off from w to r.  Don't want them to share the data mem, lest
+     * they both try to free it in JS_XDRDestroy.
+     */
+    JS_XDRMemSetData(r, p, nbytes);
+    JS_XDRMemSetData(w, NULL, 0);
+
+    JS_XDRSetPrincipals(r, cx->compartment->principals, script->originPrincipals);
+    JSScript *newScript = NULL;
+    if (!XDRScript(r, &newScript))
         return NULL;
 
     return newScript;
 }
 
+}  /* namespace js */
+
 void
 JSScript::copyClosedSlotsTo(JSScript *other)
 {
     js_memcpy(other->closedSlots, closedSlots, nClosedArgs + nClosedVars);
 }
 
 bool
 JSScript::ensureHasDebug(JSContext *cx)
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -318,16 +318,24 @@ class DebugScript
 
     /*
      * Array with all breakpoints installed at opcodes in the script, indexed
      * by the offset of the opcode into the script.
      */
     BreakpointSite  *breakpoints[1];
 };
 
+/*
+ * NB: after a successful JSXDR_DECODE, js_XDRScript callers must do any
+ * required subsequent set-up of owning function or script object and then call
+ * js_CallNewScriptHook.
+ */
+extern JSBool
+XDRScript(JSXDRState *xdr, JSScript **scriptp);
+
 } /* namespace js */
 
 static const uint32_t JS_SCRIPT_COOKIE = 0xc00cee;
 
 struct JSScript : public js::gc::Cell
 {
     /*
      * Two successively less primitive ways to make a new JSScript.  The first
@@ -343,16 +351,18 @@ struct JSScript : public js::gc::Cell
     static JSScript *NewScript(JSContext *cx, uint32_t length, uint32_t nsrcnotes, uint32_t natoms,
                                uint32_t nobjects, uint32_t nregexps,
                                uint32_t ntrynotes, uint32_t nconsts, uint32_t nglobals,
                                uint16_t nClosedArgs, uint16_t nClosedVars, uint32_t nTypeSets,
                                JSVersion version);
 
     static JSScript *NewScriptFromEmitter(JSContext *cx, js::BytecodeEmitter *bce);
 
+    friend JSBool js::XDRScript(JSXDRState *, JSScript **);
+
 #ifdef JS_CRASH_DIAGNOSTICS
     /*
      * Make sure that the cookie size does not affect the GC alignment
      * requirements.
      */
     uint32_t        cookie1[Cell::CellSize / sizeof(uint32_t)];
 #endif
     jsbytecode      *code;      /* bytecodes and their immediate operands */
@@ -430,20 +440,16 @@ struct JSScript : public js::gc::Cell
     bool            needsArgsObj_:1;
   public:
     bool mayNeedArgsObj() const { return mayNeedArgsObj_; }
     bool analyzedArgsUsage() const { return analyzedArgsUsage_; }
     bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; }
     void setNeedsArgsObj(bool needsArgsObj);
     bool applySpeculationFailed(JSContext *cx);
 
-    void setMayNeedArgsObj() {
-        mayNeedArgsObj_ = true;
-    }
-
     uint32_t        natoms;     /* length of atoms array */
     uint16_t        nslots;     /* vars plus maximum stack depth */
     uint16_t        staticLevel;/* static level for display maintenance */
 
     uint16_t        nClosedArgs; /* number of args which are closed over. */
     uint16_t        nClosedVars; /* number of vars which are closed over. */
 
     const char      *filename;  /* source filename or null */
@@ -879,20 +885,11 @@ enum LineOption {
 };
 
 inline void
 CurrentScriptFileLineOrigin(JSContext *cx, unsigned *linenop, LineOption = NOT_CALLED_FROM_JSOP_EVAL);
 
 extern JSScript *
 CloneScript(JSContext *cx, JSScript *script);
 
-/*
- * NB: after a successful XDR_DECODE, XDRScript callers must do any required
- * subsequent set-up of owning function or script object and then call
- * js_CallNewScriptHook.
- */
-template<XDRMode mode>
-bool
-XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript);
-
-} /* namespace js */
+}
 
 #endif /* jsscript_h___ */
--- a/js/src/jsversion.h
+++ b/js/src/jsversion.h
@@ -80,16 +80,17 @@
 
 #define JS_HAS_STR_HTML_HELPERS 0       /* has str.anchor, str.bold, etc. */
 #if JS_VERSION == JS_VERSION_ECMA_3_TEST
 #define JS_HAS_OBJ_PROTO_PROP   1       /* has o.__proto__ etc. */
 #else
 #define JS_HAS_OBJ_PROTO_PROP   0       /* has o.__proto__ etc. */
 #endif
 #define JS_HAS_OBJ_WATCHPOINT   0       /* has o.watch and o.unwatch */
+#define JS_HAS_XDR              0       /* has XDR API and internal support */
 #define JS_HAS_TOSOURCE         0       /* has Object/Array toSource method */
 #define JS_HAS_CATCH_GUARD      0       /* has exception handling catch guard */
 #define JS_HAS_UNEVAL           0       /* has uneval() top-level function */
 #define JS_HAS_CONST            0       /* has JS2 const as alternative var */
 #define JS_HAS_FUN_EXPR_STMT    0       /* has function expression statement */
 #define JS_HAS_NO_SUCH_METHOD   0       /* has o.__noSuchMethod__ handler */
 #define JS_HAS_XML_SUPPORT      0       /* has ECMAScript for XML support */
 #define JS_HAS_GENERATORS       0       /* has yield in generator function */
@@ -102,16 +103,17 @@
 
 #error "unsupported JS_VERSION"
 
 #elif JS_VERSION == 150
 
 #define JS_HAS_STR_HTML_HELPERS 1       /* has str.anchor, str.bold, etc. */
 #define JS_HAS_OBJ_PROTO_PROP   1       /* has o.__proto__ etc. */
 #define JS_HAS_OBJ_WATCHPOINT   1       /* has o.watch and o.unwatch */
+#define JS_HAS_XDR              1       /* has XDR API and internal support */
 #define JS_HAS_TOSOURCE         1       /* has Object/Array toSource method */
 #define JS_HAS_CATCH_GUARD      1       /* has exception handling catch guard */
 #define JS_HAS_UNEVAL           1       /* has uneval() top-level function */
 #define JS_HAS_CONST            1       /* has JS2 const as alternative var */
 #define JS_HAS_FUN_EXPR_STMT    1       /* has function expression statement */
 #define JS_HAS_NO_SUCH_METHOD   1       /* has o.__noSuchMethod__ handler */
 #define JS_HAS_XML_SUPPORT      0       /* has ECMAScript for XML support */
 #define JS_HAS_GENERATORS       0       /* has yield in generator function */
@@ -120,16 +122,17 @@
 #define JS_HAS_GENERATOR_EXPRS  0       /* has (expr for (lhs in iterable)) */
 #define JS_HAS_EXPR_CLOSURES    0       /* has function (formals) listexpr */
 
 #elif JS_VERSION == 160
 
 #define JS_HAS_STR_HTML_HELPERS 1       /* has str.anchor, str.bold, etc. */
 #define JS_HAS_OBJ_PROTO_PROP   1       /* has o.__proto__ etc. */
 #define JS_HAS_OBJ_WATCHPOINT   1       /* has o.watch and o.unwatch */
+#define JS_HAS_XDR              1       /* has XDR API and internal support */
 #define JS_HAS_TOSOURCE         1       /* has Object/Array toSource method */
 #define JS_HAS_CATCH_GUARD      1       /* has exception handling catch guard */
 #define JS_HAS_UNEVAL           1       /* has uneval() top-level function */
 #define JS_HAS_CONST            1       /* has JS2 const as alternative var */
 #define JS_HAS_FUN_EXPR_STMT    1       /* has function expression statement */
 #define JS_HAS_NO_SUCH_METHOD   1       /* has o.__noSuchMethod__ handler */
 #define JS_HAS_XML_SUPPORT      1       /* has ECMAScript for XML support */
 #define JS_HAS_GENERATORS       0       /* has yield in generator function */
@@ -138,16 +141,17 @@
 #define JS_HAS_GENERATOR_EXPRS  0       /* has (expr for (lhs in iterable)) */
 #define JS_HAS_EXPR_CLOSURES    0       /* has function (formals) listexpr */
 
 #elif JS_VERSION == 170
 
 #define JS_HAS_STR_HTML_HELPERS 1       /* has str.anchor, str.bold, etc. */
 #define JS_HAS_OBJ_PROTO_PROP   1       /* has o.__proto__ etc. */
 #define JS_HAS_OBJ_WATCHPOINT   1       /* has o.watch and o.unwatch */
+#define JS_HAS_XDR              1       /* has XDR API and internal support */
 #define JS_HAS_TOSOURCE         1       /* has Object/Array toSource method */
 #define JS_HAS_CATCH_GUARD      1       /* has exception handling catch guard */
 #define JS_HAS_UNEVAL           1       /* has uneval() top-level function */
 #define JS_HAS_CONST            1       /* has JS2 const as alternative var */
 #define JS_HAS_FUN_EXPR_STMT    1       /* has function expression statement */
 #define JS_HAS_NO_SUCH_METHOD   1       /* has o.__noSuchMethod__ handler */
 #define JS_HAS_XML_SUPPORT      1       /* has ECMAScript for XML support */
 #define JS_HAS_GENERATORS       1       /* has yield in generator function */
@@ -156,16 +160,17 @@
 #define JS_HAS_GENERATOR_EXPRS  0       /* has (expr for (lhs in iterable)) */
 #define JS_HAS_EXPR_CLOSURES    0       /* has function (formals) listexpr */
 
 #elif 180 <= JS_VERSION && JS_VERSION <= 185
 
 #define JS_HAS_STR_HTML_HELPERS 1       /* has str.anchor, str.bold, etc. */
 #define JS_HAS_OBJ_PROTO_PROP   1       /* has o.__proto__ etc. */
 #define JS_HAS_OBJ_WATCHPOINT   1       /* has o.watch and o.unwatch */
+#define JS_HAS_XDR              1       /* has XDR API and internal support */
 #define JS_HAS_TOSOURCE         1       /* has Object/Array toSource method */
 #define JS_HAS_CATCH_GUARD      1       /* has exception handling catch guard */
 #define JS_HAS_UNEVAL           1       /* has uneval() top-level function */
 #define JS_HAS_CONST            1       /* has JS2 const as alternative var */
 #define JS_HAS_FUN_EXPR_STMT    1       /* has function expression statement */
 #define JS_HAS_NO_SUCH_METHOD   1       /* has o.__noSuchMethod__ handler */
 #define JS_HAS_XML_SUPPORT      1       /* has ECMAScript for XML support */
 #define JS_HAS_GENERATORS       1       /* has yield in generator function */
new file mode 100644
--- /dev/null
+++ b/js/src/jsxdrapi.cpp
@@ -0,0 +1,589 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "mozilla/Util.h"
+
+#include "jsversion.h"
+
+#if JS_HAS_XDR
+
+#include <string.h>
+#include "jstypes.h"
+#include "jsutil.h"
+#include "jsdhash.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jsnum.h"
+#include "jsscript.h"           /* js_XDRScript */
+#include "jsstr.h"
+#include "jsxdrapi.h"
+#include "vm/Debugger.h"
+
+#include "jsobjinlines.h"
+
+using namespace mozilla;
+using namespace js;
+
+#ifdef DEBUG
+#define DBG(x) x
+#else
+#define DBG(x) ((void)0)
+#endif
+
+typedef struct JSXDRMemState {
+    JSXDRState  state;
+    char        *base;
+    uint32_t    count;
+    uint32_t    limit;
+} JSXDRMemState;
+
+#define MEM_BLOCK       8192
+#define MEM_PRIV(xdr)   ((JSXDRMemState *)(xdr))
+
+#define MEM_BASE(xdr)   (MEM_PRIV(xdr)->base)
+#define MEM_COUNT(xdr)  (MEM_PRIV(xdr)->count)
+#define MEM_LIMIT(xdr)  (MEM_PRIV(xdr)->limit)
+
+#define MEM_LEFT(xdr, bytes)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        if ((xdr)->mode == JSXDR_DECODE &&                                    \
+            MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) {                        \
+            JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL,         \
+                                 JSMSG_END_OF_DATA);                          \
+            return 0;                                                         \
+        }                                                                     \
+    JS_END_MACRO
+
+#define MEM_NEED(xdr, bytes)                                                  \
+    JS_BEGIN_MACRO                                                            \
+        if ((xdr)->mode == JSXDR_ENCODE) {                                    \
+            if (MEM_LIMIT(xdr) &&                                             \
+                MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) {                    \
+                uint32_t limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\
+                void *data_ = (xdr)->cx->realloc_(MEM_BASE(xdr), limit_);      \
+                if (!data_)                                                   \
+                    return 0;                                                 \
+                MEM_BASE(xdr) = (char *) data_;                               \
+                MEM_LIMIT(xdr) = limit_;                                      \
+            }                                                                 \
+        } else {                                                              \
+            MEM_LEFT(xdr, bytes);                                             \
+        }                                                                     \
+    JS_END_MACRO
+
+#define MEM_DATA(xdr)        ((void *)(MEM_BASE(xdr) + MEM_COUNT(xdr)))
+#define MEM_INCR(xdr,bytes)  (MEM_COUNT(xdr) += (bytes))
+
+static JSBool
+mem_get32(JSXDRState *xdr, uint32_t *lp)
+{
+    MEM_LEFT(xdr, 4);
+    *lp = *(uint32_t *)MEM_DATA(xdr);
+    MEM_INCR(xdr, 4);
+    return JS_TRUE;
+}
+
+static JSBool
+mem_set32(JSXDRState *xdr, uint32_t *lp)
+{
+    MEM_NEED(xdr, 4);
+    *(uint32_t *)MEM_DATA(xdr) = *lp;
+    MEM_INCR(xdr, 4);
+    return JS_TRUE;
+}
+
+static JSBool
+mem_getbytes(JSXDRState *xdr, char *bytes, uint32_t len)
+{
+    MEM_LEFT(xdr, len);
+    js_memcpy(bytes, MEM_DATA(xdr), len);
+    MEM_INCR(xdr, len);
+    return JS_TRUE;
+}
+
+static JSBool
+mem_setbytes(JSXDRState *xdr, char *bytes, uint32_t len)
+{
+    MEM_NEED(xdr, len);
+    js_memcpy(MEM_DATA(xdr), bytes, len);
+    MEM_INCR(xdr, len);
+    return JS_TRUE;
+}
+
+static void *
+mem_raw(JSXDRState *xdr, uint32_t len)
+{
+    void *data;
+    if (xdr->mode == JSXDR_ENCODE) {
+        MEM_NEED(xdr, len);
+    } else if (xdr->mode == JSXDR_DECODE) {
+        MEM_LEFT(xdr, len);
+    }
+    data = MEM_DATA(xdr);
+    MEM_INCR(xdr, len);
+    return data;
+}
+
+static JSBool
+mem_seek(JSXDRState *xdr, int32_t offset, JSXDRWhence whence)
+{
+    switch (whence) {
+      case JSXDR_SEEK_CUR:
+        if ((int32_t)MEM_COUNT(xdr) + offset < 0) {
+            JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+                                 JSMSG_SEEK_BEYOND_START);
+            return JS_FALSE;
+        }
+        if (offset > 0)
+            MEM_NEED(xdr, offset);
+        MEM_COUNT(xdr) += offset;
+        return JS_TRUE;
+      case JSXDR_SEEK_SET:
+        if (offset < 0) {
+            JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+                                 JSMSG_SEEK_BEYOND_START);
+            return JS_FALSE;
+        }
+        if (xdr->mode == JSXDR_ENCODE) {
+            if ((uint32_t)offset > MEM_COUNT(xdr))
+                MEM_NEED(xdr, offset - MEM_COUNT(xdr));
+            MEM_COUNT(xdr) = offset;
+        } else {
+            if ((uint32_t)offset > MEM_LIMIT(xdr)) {
+                JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+                                     JSMSG_SEEK_BEYOND_END);
+                return JS_FALSE;
+            }
+            MEM_COUNT(xdr) = offset;
+        }
+        return JS_TRUE;
+      case JSXDR_SEEK_END:
+        if (offset >= 0 ||
+            xdr->mode == JSXDR_ENCODE ||
+            (int32_t)MEM_LIMIT(xdr) + offset < 0) {
+            JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+                                 JSMSG_END_SEEK);
+            return JS_FALSE;
+        }
+        MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset;
+        return JS_TRUE;
+      default: {
+        char numBuf[12];
+        JS_snprintf(numBuf, sizeof numBuf, "%d", whence);
+        JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
+                             JSMSG_WHITHER_WHENCE, numBuf);
+        return JS_FALSE;
+      }
+    }
+}
+
+static uint32_t
+mem_tell(JSXDRState *xdr)
+{
+    return MEM_COUNT(xdr);
+}
+
+static void
+mem_finalize(JSXDRState *xdr)
+{
+    xdr->cx->free_(MEM_BASE(xdr));
+}
+
+static JSXDROps xdrmem_ops = {
+    mem_get32,      mem_set32,      mem_getbytes,   mem_setbytes,
+    mem_raw,        mem_seek,       mem_tell,       mem_finalize
+};
+
+JS_PUBLIC_API(void)
+JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx)
+{
+    xdr->mode = mode;
+    xdr->cx = cx;
+    xdr->sharedFilename = NULL;
+    xdr->principals = NULL;
+    xdr->originPrincipals = NULL;
+}
+
+JS_PUBLIC_API(JSXDRState *)
+JS_XDRNewMem(JSContext *cx, JSXDRMode mode)
+{
+    JSXDRState *xdr = (JSXDRState *) cx->malloc_(sizeof(JSXDRMemState));
+    if (!xdr)
+        return NULL;
+    JS_XDRInitBase(xdr, mode, cx);
+    if (mode == JSXDR_ENCODE) {
+        if (!(MEM_BASE(xdr) = (char *) cx->malloc_(MEM_BLOCK))) {
+            cx->free_(xdr);
+            return NULL;
+        }
+    } else {
+        /* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */
+        MEM_BASE(xdr) = NULL;
+    }
+    xdr->ops = &xdrmem_ops;
+    MEM_COUNT(xdr) = 0;
+    MEM_LIMIT(xdr) = MEM_BLOCK;
+    return xdr;
+}
+
+JS_PUBLIC_API(void *)
+JS_XDRMemGetData(JSXDRState *xdr, uint32_t *lp)
+{
+    if (xdr->ops != &xdrmem_ops)
+        return NULL;
+    *lp = MEM_COUNT(xdr);
+    return MEM_BASE(xdr);
+}
+
+JS_PUBLIC_API(void)
+JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32_t len)
+{
+    if (xdr->ops != &xdrmem_ops)
+        return;
+    MEM_LIMIT(xdr) = len;
+    MEM_BASE(xdr) = (char *) data;
+    MEM_COUNT(xdr) = 0;
+}
+
+JS_PUBLIC_API(uint32_t)
+JS_XDRMemDataLeft(JSXDRState *xdr)
+{
+    if (xdr->ops != &xdrmem_ops)
+        return 0;
+    return MEM_LIMIT(xdr) - MEM_COUNT(xdr);
+}
+
+JS_PUBLIC_API(void)
+JS_XDRMemResetData(JSXDRState *xdr)
+{
+    if (xdr->ops != &xdrmem_ops)
+        return;
+    MEM_COUNT(xdr) = 0;
+}
+
+JS_PUBLIC_API(void)
+JS_XDRDestroy(JSXDRState *xdr)
+{
+    JSContext *cx = xdr->cx;
+    xdr->ops->finalize(xdr);
+    cx->free_(xdr);
+}
+
+JS_PUBLIC_API(void)
+JS_XDRSetPrincipals(JSXDRState *xdr, JSPrincipals *principals, JSPrincipals *originPrincipals)
+{
+    JS_ASSERT(xdr->mode == JSXDR_DECODE);
+    xdr->principals = principals;
+    xdr->originPrincipals = JSScript::normalizeOriginPrincipals(principals, originPrincipals);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRUint8(JSXDRState *xdr, uint8_t *b)
+{
+    uint32_t l = *b;
+    if (!JS_XDRUint32(xdr, &l))
+        return JS_FALSE;
+    *b = (uint8_t) l;
+    return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRUint16(JSXDRState *xdr, uint16_t *s)
+{
+    uint32_t l = *s;
+    if (!JS_XDRUint32(xdr, &l))
+        return JS_FALSE;
+    *s = (uint16_t) l;
+    return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRUint32(JSXDRState *xdr, uint32_t *lp)
+{
+    JSBool ok = JS_TRUE;
+    if (xdr->mode == JSXDR_ENCODE) {
+        uint32_t xl = JSXDR_SWAB32(*lp);
+        ok = xdr->ops->set32(xdr, &xl);
+    } else if (xdr->mode == JSXDR_DECODE) {
+        ok = xdr->ops->get32(xdr, lp);
+        *lp = JSXDR_SWAB32(*lp);
+    }
+    return ok;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32_t len)
+{
+    uint32_t padlen;
+    static char padbuf[JSXDR_ALIGN-1];
+
+    if (xdr->mode == JSXDR_ENCODE) {
+        if (!xdr->ops->setbytes(xdr, bytes, len))
+            return JS_FALSE;
+    } else {
+        if (!xdr->ops->getbytes(xdr, bytes, len))
+            return JS_FALSE;
+    }
+    len = xdr->ops->tell(xdr);
+    if (len % JSXDR_ALIGN) {
+        padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN);
+        if (xdr->mode == JSXDR_ENCODE) {
+            if (!xdr->ops->setbytes(xdr, padbuf, padlen))
+                return JS_FALSE;
+        } else {
+            if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR))
+                return JS_FALSE;
+        }
+    }
+    return JS_TRUE;
+}
+
+/**
+ * Convert between a C string and the XDR representation:
+ * leading 32-bit count, then counted vector of chars,
+ * then possibly \0 padding to multiple of 4.
+ */
+JS_PUBLIC_API(JSBool)
+JS_XDRCString(JSXDRState *xdr, char **sp)
+{
+    uint32_t len;
+
+    if (xdr->mode == JSXDR_ENCODE)
+        len = strlen(*sp);
+    JS_XDRUint32(xdr, &len);
+    if (xdr->mode == JSXDR_DECODE) {
+        if (!(*sp = (char *) xdr->cx->malloc_(len + 1)))
+            return JS_FALSE;
+    }
+    if (!JS_XDRBytes(xdr, *sp, len)) {
+        if (xdr->mode == JSXDR_DECODE)
+            xdr->cx->free_(*sp);
+        return JS_FALSE;
+    }
+    if (xdr->mode == JSXDR_DECODE) {
+        (*sp)[len] = '\0';
+    }
+    return JS_TRUE;
+}
+
+static JSBool
+XDRChars(JSXDRState *xdr, jschar *chars, uint32_t nchars)
+{
+    uint32_t i, padlen, nbytes;
+    jschar *raw;
+
+    nbytes = nchars * sizeof(jschar);
+    padlen = nbytes % JSXDR_ALIGN;
+    if (padlen) {
+        padlen = JSXDR_ALIGN - padlen;
+        nbytes += padlen;
+    }
+    if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes)))
+        return JS_FALSE;
+    if (xdr->mode == JSXDR_ENCODE) {
+        for (i = 0; i != nchars; i++)
+            raw[i] = JSXDR_SWAB16(chars[i]);
+        if (padlen)
+            memset((char *)raw + nbytes - padlen, 0, padlen);
+    } else if (xdr->mode == JSXDR_DECODE) {
+        for (i = 0; i != nchars; i++)
+            chars[i] = JSXDR_SWAB16(raw[i]);
+    }
+    return JS_TRUE;
+}
+
+/*
+ * Convert between a JS (Unicode) string and the XDR representation.
+ */
+JS_PUBLIC_API(JSBool)
+JS_XDRString(JSXDRState *xdr, JSString **strp)
+{
+    uint32_t nchars;
+    jschar *chars;
+
+    if (xdr->mode == JSXDR_ENCODE)
+        nchars = (*strp)->length();
+    if (!JS_XDRUint32(xdr, &nchars))
+        return JS_FALSE;
+
+    if (xdr->mode == JSXDR_DECODE)
+        chars = (jschar *) xdr->cx->malloc_((nchars + 1) * sizeof(jschar));
+    else
+        chars = const_cast<jschar *>((*strp)->getChars(xdr->cx));
+    if (!chars)
+        return JS_FALSE;
+
+    if (!XDRChars(xdr, chars, nchars))
+        goto bad;
+    if (xdr->mode == JSXDR_DECODE) {
+        chars[nchars] = 0;
+        *strp = JS_NewUCString(xdr->cx, chars, nchars);
+        if (!*strp)
+            goto bad;
+    }
+    return JS_TRUE;
+
+bad:
+    if (xdr->mode == JSXDR_DECODE)
+        xdr->cx->free_(chars);
+    return JS_FALSE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp)
+{
+    uint32_t null = (*strp == NULL);
+    if (!JS_XDRUint32(xdr, &null))
+        return JS_FALSE;
+    if (null) {
+        *strp = NULL;
+        return JS_TRUE;
+    }
+    return JS_XDRString(xdr, strp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRDouble(JSXDRState *xdr, double *dp)
+{
+    jsdpun u;
+
+    u.d = (xdr->mode == JSXDR_ENCODE) ? *dp : 0.0;
+    if (!JS_XDRUint32(xdr, &u.s.lo) || !JS_XDRUint32(xdr, &u.s.hi))
+        return false;
+    if (xdr->mode == JSXDR_DECODE)
+        *dp = u.d;
+    return true;
+}
+
+extern JSBool
+js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
+{
+    JSString *str;
+    uint32_t nchars;
+    JSAtom *atom;
+    JSContext *cx;
+    jschar *chars;
+    jschar stackChars[256];
+
+    if (xdr->mode == JSXDR_ENCODE) {
+        str = *atomp;
+        return JS_XDRString(xdr, &str);
+    }
+
+    /*
+     * Inline JS_XDRString when decoding to avoid JSString allocation
+     * for already existing atoms. See bug 321985.
+     */
+    if (!JS_XDRUint32(xdr, &nchars))
+        return JS_FALSE;
+    atom = NULL;
+    cx = xdr->cx;
+    if (nchars <= ArrayLength(stackChars)) {
+        chars = stackChars;
+    } else {
+        /*
+         * This is very uncommon. Don't use the tempLifoAlloc arena for this as
+         * most allocations here will be bigger than tempLifoAlloc's default
+         * chunk size.
+         */
+        chars = (jschar *) cx->malloc_(nchars * sizeof(jschar));
+        if (!chars)
+            return JS_FALSE;
+    }
+
+    if (XDRChars(xdr, chars, nchars))
+        atom = js_AtomizeChars(cx, chars, nchars);
+    if (chars != stackChars)
+        cx->free_(chars);
+
+    if (!atom)
+        return JS_FALSE;
+    *atomp = atom;
+    return JS_TRUE;
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
+{
+    return XDRFunctionObject(xdr, objp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
+{
+    JSScript *script;
+    uint32_t magic;
+    uint32_t bytecodeVer;
+    if (xdr->mode == JSXDR_DECODE) {
+        script = NULL;
+        *scriptp = NULL;
+    } else {
+        script = *scriptp;
+        magic = JSXDR_MAGIC_SCRIPT_CURRENT;
+        bytecodeVer = JSXDR_BYTECODE_VERSION;
+    }
+
+    if (!JS_XDRUint32(xdr, &magic))
+        return false;
+    if (!JS_XDRUint32(xdr, &bytecodeVer))
+        return false;
+
+    if (magic != JSXDR_MAGIC_SCRIPT_CURRENT ||
+        bytecodeVer != JSXDR_BYTECODE_VERSION) {
+        /* We do not provide binary compatibility with older scripts. */
+        JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, JSMSG_BAD_SCRIPT_MAGIC);
+        return false;
+    }
+
+    if (!XDRScript(xdr, &script))
+        return false;
+
+    if (xdr->mode == JSXDR_DECODE) {
+        JS_ASSERT(!script->compileAndGo);
+        script->globalObject = GetCurrentGlobal(xdr->cx);
+        js_CallNewScriptHook(xdr->cx, script, NULL);
+        Debugger::onNewScript(xdr->cx, script, NULL);
+        *scriptp = script;
+    }
+
+    return true;
+}
+
+#endif /* JS_HAS_XDR */
new file mode 100644
--- /dev/null
+++ b/js/src/jsxdrapi.h
@@ -0,0 +1,224 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=78:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef jsxdrapi_h___
+#define jsxdrapi_h___
+
+/*
+ * JS external data representation interface API.
+ *
+ * The XDR system is comprised of three major parts:
+ *
+ * - the state serialization/deserialization APIs, which allow consumers
+ *   of the API to serialize JS runtime state (script bytecodes, atom maps,
+ *   object graphs, etc.) for later restoration.  These portions
+ *   are implemented in various appropriate files, such as jsscript.c
+ *   for the script portions and jsobj.c for object state.
+ * - the callback APIs through which the runtime requests an opaque
+ *   representation of a native object, and through which the runtime
+ *   constructs a live native object from an opaque representation. These
+ *   portions are the responsibility of the native object implementor.
+ * - utility functions for en/decoding of primitive types, such as
+ *   JSStrings.  This portion is implemented in jsxdrapi.c.
+ *
+ * Spiritually guided by Sun's XDR, where appropriate.
+ */
+
+#include "jspubtd.h"
+#include "jsprvtd.h"
+
+JS_BEGIN_EXTERN_C
+
+/* We use little-endian byteorder for all encoded data */
+
+#if defined IS_LITTLE_ENDIAN
+#define JSXDR_SWAB32(x) x
+#define JSXDR_SWAB16(x) x
+#elif defined IS_BIG_ENDIAN
+#define JSXDR_SWAB32(x) (((uint32_t)(x) >> 24) |                              \
+                         (((uint32_t)(x) >> 8) & 0xff00) |                    \
+                         (((uint32_t)(x) << 8) & 0xff0000) |                  \
+                         ((uint32_t)(x) << 24))
+#define JSXDR_SWAB16(x) (((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8))
+#else
+#error "unknown byte order"
+#endif
+
+#define JSXDR_ALIGN     4
+
+typedef enum JSXDRMode {
+    JSXDR_ENCODE,
+    JSXDR_DECODE
+} JSXDRMode;
+
+typedef enum JSXDRWhence {
+    JSXDR_SEEK_SET,
+    JSXDR_SEEK_CUR,
+    JSXDR_SEEK_END
+} JSXDRWhence;
+
+typedef struct JSXDROps {
+    JSBool      (*get32)(JSXDRState *, uint32_t *);
+    JSBool      (*set32)(JSXDRState *, uint32_t *);
+    JSBool      (*getbytes)(JSXDRState *, char *, uint32_t);
+    JSBool      (*setbytes)(JSXDRState *, char *, uint32_t);
+    void *      (*raw)(JSXDRState *, uint32_t);
+    JSBool      (*seek)(JSXDRState *, int32_t, JSXDRWhence);
+    uint32_t    (*tell)(JSXDRState *);
+    void        (*finalize)(JSXDRState *);
+} JSXDROps;
+
+struct JSXDRState {
+    JSXDRMode   mode;
+    JSXDROps    *ops;
+    JSContext   *cx;
+    const char  *sharedFilename;
+    JSPrincipals *principals;
+    JSPrincipals *originPrincipals;
+};
+
+extern JS_PUBLIC_API(void)
+JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx);
+
+extern JS_PUBLIC_API(JSXDRState *)
+JS_XDRNewMem(JSContext *cx, JSXDRMode mode);
+
+extern JS_PUBLIC_API(void *)
+JS_XDRMemGetData(JSXDRState *xdr, uint32_t *lp);
+
+extern JS_PUBLIC_API(void)
+JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32_t len);
+
+extern JS_PUBLIC_API(uint32_t)
+JS_XDRMemDataLeft(JSXDRState *xdr);
+
+extern JS_PUBLIC_API(void)
+JS_XDRMemResetData(JSXDRState *xdr);
+
+extern JS_PUBLIC_API(void)
+JS_XDRDestroy(JSXDRState *xdr);
+
+/*
+ * Set principals that should be assigned to decoded scripts and functions.
+ * The principals is not held via JS_HoldPrincipals/JS_DropPrincipals unless
+ * they are stored in a decoded script. Thus the caller must either ensure
+ * that the principals outlive the XDR instance or are explicitly set to NULL
+ * before they release by the caller.
+ */
+extern JS_PUBLIC_API(void)
+JS_XDRSetPrincipals(JSXDRState *xdr, JSPrincipals *principals, JSPrincipals *originPrincipals);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRUint8(JSXDRState *xdr, uint8_t *b);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRUint16(JSXDRState *xdr, uint16_t *s);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRUint32(JSXDRState *xdr, uint32_t *lp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32_t len);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRCString(JSXDRState *xdr, char **sp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRString(JSXDRState *xdr, JSString **strp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRDouble(JSXDRState *xdr, double *dp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_XDRScript(JSXDRState *xdr, JSScript **scriptp);
+
+/*
+ * Magic numbers.
+ */
+#define JSXDR_MAGIC_SCRIPT_1        0xdead0001
+#define JSXDR_MAGIC_SCRIPT_2        0xdead0002
+#define JSXDR_MAGIC_SCRIPT_3        0xdead0003
+#define JSXDR_MAGIC_SCRIPT_4        0xdead0004
+#define JSXDR_MAGIC_SCRIPT_5        0xdead0005
+#define JSXDR_MAGIC_SCRIPT_6        0xdead0006
+#define JSXDR_MAGIC_SCRIPT_7        0xdead0007
+#define JSXDR_MAGIC_SCRIPT_8        0xdead0008
+#define JSXDR_MAGIC_SCRIPT_9        0xdead0009
+#define JSXDR_MAGIC_SCRIPT_10       0xdead000a
+#define JSXDR_MAGIC_SCRIPT_11       0xdead000b
+#define JSXDR_MAGIC_SCRIPT_12       0xdead000c
+#define JSXDR_MAGIC_SCRIPT_CURRENT  JSXDR_MAGIC_SCRIPT_12
+
+/*
+ * Bytecode version number. Increment the subtrahend whenever JS bytecode
+ * changes incompatibly.
+ *
+ * This version number is XDR'd near the front of xdr bytecode and
+ * aborts deserialization if there is a mismatch between the current
+ * and saved versions. If deserialization fails, the data should be
+ * invalidated if possible.
+ */
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 111)
+
+JS_END_EXTERN_C
+
+/*
+ * Library-private functions.
+ */
+extern JSBool
+js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
+
+/*
+ * Set principals that should be assigned to decoded scripts and functions.
+ * The principals is not held via JS_HoldPrincipals/JS_DropPrincipals unless
+ * they are stored in a decoded script. Thus the caller must either ensure
+ * that principal outlive the XDR instance or are explicitly set to NULL
+ * before they release by the caller.
+ */
+extern void
+js_XDRSetPrincipals(JSXDRState *xdr, JSPrincipals *principals, JSPrincipals *originPrincipals);
+
+#endif /* ! jsxdrapi_h___ */
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -40,17 +40,16 @@
 
 #include "jsgc.h"
 #include "jsinfer.h"
 #include "jsinterp.h"
 
 #include "vm/GlobalObject.h"
 #include "vm/MethodGuard.h"
 #include "vm/Stack.h"
-#include "vm/Xdr.h"
 
 #include "jsobjinlines.h"
 
 #include "gc/Barrier-inl.h"
 #include "vm/ArgumentsObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -37,17 +37,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "frontend/TokenStream.h"
 #include "vm/MatchPairs.h"
 #include "vm/RegExpStatics.h"
 #include "vm/StringBuffer.h"
-#include "vm/Xdr.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 
 using namespace js;
 using js::detail::RegExpCode;
@@ -742,43 +741,41 @@ js::ParseRegExpFlags(JSContext *cx, JSSt
             return false;
           }
         }
 #undef HANDLE_FLAG
     }
     return true;
 }
 
-template<XDRMode mode>
+#if JS_HAS_XDR
+# include "jsxdrapi.h"
+
 bool
-js::XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp)
+js::XDRScriptRegExpObject(JSXDRState *xdr, HeapPtrObject *objp)
 {
     JSAtom *source = 0;
     uint32_t flagsword = 0;
 
-    if (mode == XDR_ENCODE) {
+    if (xdr->mode == JSXDR_ENCODE) {
         JS_ASSERT(objp);
         RegExpObject &reobj = (*objp)->asRegExp();
         source = reobj.getSource();
         flagsword = reobj.getFlags();
     }
-    if (!XDRAtom(xdr, &source) || !xdr->codeUint32(&flagsword))
+    if (!js_XDRAtom(xdr, &source) || !JS_XDRUint32(xdr, &flagsword))
         return false;
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         RegExpFlag flags = RegExpFlag(flagsword);
-        RegExpObject *reobj = RegExpObject::createNoStatics(xdr->cx(), source, flags, NULL);
+        RegExpObject *reobj = RegExpObject::createNoStatics(xdr->cx, source, flags, NULL);
         if (!reobj)
             return false;
 
-        if (!reobj->clearParent(xdr->cx()))
+        if (!reobj->clearParent(xdr->cx))
             return false;
-        if (!reobj->clearType(xdr->cx()))
+        if (!reobj->clearType(xdr->cx))
             return false;
         objp->init(reobj);
     }
     return true;
 }
+#endif /* !JS_HAS_XDR */
 
-template bool
-js::XDRScriptRegExpObject(XDRState<XDR_ENCODE> *xdr, HeapPtrObject *objp);
-
-template bool
-js::XDRScriptRegExpObject(XDRState<XDR_DECODE> *xdr, HeapPtrObject *objp);
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -464,15 +464,14 @@ ParseRegExpFlags(JSContext *cx, JSString
  * Beware: this RegExpShared can be owned by a compartment other than
  * cx->compartment. Normal RegExpGuard (which is necessary anyways)
  * will protect the object but it is important not to assign the return value
  * to be the private of any RegExpObject.
  */
 inline bool
 RegExpToShared(JSContext *cx, JSObject &obj, RegExpGuard *g);
 
-template<XDRMode mode>
 bool
-XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp);
+XDRScriptRegExpObject(JSXDRState *xdr, HeapPtrObject *objp);
 
 } /* namespace js */
 
 #endif
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -37,20 +37,22 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "jscompartment.h"
 #include "jsiter.h"
 #include "jsscope.h"
+#if JS_HAS_XDR
+#include "jsxdrapi.h"
+#endif
 
 #include "GlobalObject.h"
 #include "ScopeObject.h"
-#include "Xdr.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 #include "ScopeObject-inl.h"
 
 using namespace js;
 using namespace js::types;
@@ -929,16 +931,18 @@ Class js::BlockClass = {
     JS_PropertyStub,         /* delProperty */
     JS_PropertyStub,         /* getProperty */
     JS_StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     JS_ResolveStub,
     JS_ConvertStub
 };
 
+#if JS_HAS_XDR
+
 #define NO_PARENT_INDEX UINT32_MAX
 
 static uint32_t
 FindObjectIndex(JSObjectArray *array, JSObject *obj)
 {
     size_t i;
 
     if (array) {
@@ -948,43 +952,42 @@ FindObjectIndex(JSObjectArray *array, JS
             if (array->vector[--i] == obj)
                 return i;
         } while (i != 0);
     }
 
     return NO_PARENT_INDEX;
 }
 
-template<XDRMode mode>
 bool
-js::XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp)
+js::XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **objp)
 {
-    JSContext *cx = xdr->cx();
+    JSContext *cx = xdr->cx;
 
     StaticBlockObject *obj = NULL;
     uint32_t parentId = 0;
     uint32_t count = 0;
     uint32_t depthAndCount = 0;
-    if (mode == XDR_ENCODE) {
+    if (xdr->mode == JSXDR_ENCODE) {
         obj = *objp;
         parentId = JSScript::isValidOffset(script->objectsOffset)
                    ? FindObjectIndex(script->objects(), obj->enclosingBlock())
                    : NO_PARENT_INDEX;
         uint32_t depth = obj->stackDepth();
         JS_ASSERT(depth <= UINT16_MAX);
         count = obj->slotCount();
         JS_ASSERT(count <= UINT16_MAX);
         depthAndCount = (depth << 16) | uint16_t(count);
     }
 
     /* First, XDR the parent atomid. */
-    if (!xdr->codeUint32(&parentId))
+    if (!JS_XDRUint32(xdr, &parentId))
         return false;
 
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         obj = StaticBlockObject::create(cx);
         if (!obj)
             return false;
         *objp = obj;
 
         /*
          * If there's a parent id, then get the parent out of our script's
          * object array. We know that we XDR block object in outer-to-inner
@@ -992,31 +995,31 @@ js::XDRStaticBlockObject(XDRState<mode> 
          */
         obj->setEnclosingBlock(parentId == NO_PARENT_INDEX
                                ? NULL
                                : &script->getObject(parentId)->asStaticBlock());
     }
 
     AutoObjectRooter tvr(cx, obj);
 
-    if (!xdr->codeUint32(&depthAndCount))
+    if (!JS_XDRUint32(xdr, &depthAndCount))
         return false;
 
-    if (mode == XDR_DECODE) {
+    if (xdr->mode == JSXDR_DECODE) {
         uint32_t depth = uint16_t(depthAndCount >> 16);
         count = uint16_t(depthAndCount);
         obj->setStackDepth(depth);
 
         /*
          * XDR the block object's properties. We know that there are 'count'
          * properties to XDR, stored as id/shortid pairs.
          */
         for (unsigned i = 0; i < count; i++) {
             JSAtom *atom;
-            if (!XDRAtom(xdr, &atom))
+            if (!js_XDRAtom(xdr, &atom))
                 return false;
 
             /* The empty string indicates an int id. */
             jsid id = atom != cx->runtime->emptyString
                       ? ATOM_TO_JSID(atom)
                       : INT_TO_JSID(i);
 
             bool redeclared;
@@ -1046,20 +1049,16 @@ js::XDRStaticBlockObject(XDRState<mode> 
             jsid propid = shape->propid();
             JS_ASSERT(JSID_IS_ATOM(propid) || JSID_IS_INT(propid));
 
             /* The empty string indicates an int id. */
             JSAtom *atom = JSID_IS_ATOM(propid)
                            ? JSID_TO_ATOM(propid)
                            : cx->runtime->emptyString;
 
-            if (!XDRAtom(xdr, &atom))
+            if (!js_XDRAtom(xdr, &atom))
                 return false;
         }
     }
     return true;
 }
 
-template bool
-js::XDRStaticBlockObject(XDRState<XDR_ENCODE> *xdr, JSScript *script, StaticBlockObject **objp);
-
-template bool
-js::XDRStaticBlockObject(XDRState<XDR_DECODE> *xdr, JSScript *script, StaticBlockObject **objp);
+#endif  /* JS_HAS_XDR */
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -271,15 +271,14 @@ class ClonedBlockObject : public BlockOb
 
     /* Assuming 'put' has been called, return the value of the ith let var. */
     const Value &closedSlot(unsigned i);
 
     /* Return whether this environment contains 'name' and, if so, its value. */
     bool containsVar(PropertyName *name, Value *vp, JSContext *cx);
 };
 
-template<XDRMode mode>
-bool
-XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp);
+extern bool
+XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **objp);
 
 }  /* namespace js */
 
 #endif /* ScopeObject_h___ */
deleted file mode 100644
--- a/js/src/vm/Xdr.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code, released
- * March 31, 1998.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "mozilla/Util.h"
-
-#include "jsversion.h"
-
-#include <string.h>
-#include "jstypes.h"
-#include "jsutil.h"
-#include "jsdhash.h"
-#include "jsprf.h"
-#include "jsapi.h"
-#include "jscntxt.h"
-#include "jsnum.h"
-#include "jsscript.h"
-#include "jsstr.h"
-
-#include "Xdr.h"
-#include "Debugger.h"
-
-#include "jsobjinlines.h"
-
-using namespace mozilla;
-using namespace js;
-
-namespace js {
-
-void
-XDRBuffer::freeBuffer()
-{
-    Foreground::free_(base);
-#ifdef DEBUG
-    memset(this, 0xe2, sizeof *this);
-#endif
-}
-
-bool
-XDRBuffer::grow(size_t n)
-{
-    JS_ASSERT(n > size_t(limit - cursor));
-    
-    const size_t MEM_BLOCK = 8192;
-    size_t offset = cursor - base;
-    size_t newCapacity = JS_ROUNDUP(offset + n, MEM_BLOCK);
-    if (isUint32Overflow(newCapacity)) {
-        JS_ReportErrorNumber(cx(), js_GetErrorMessage, NULL, JSMSG_TOO_BIG_TO_ENCODE);
-        return false;
-    }
-        
-    void *data = OffTheBooks::realloc_(base, newCapacity);
-    if (!data) {
-        js_ReportOutOfMemory(cx());
-        return false;
-    }
-    base = static_cast<uint8_t *>(data);
-    cursor = base + offset;
-    limit = base + newCapacity;
-    return true;
-}
-    
-template<XDRMode mode>
-bool
-XDRState<mode>::codeChars(jschar *chars, size_t nchars)
-{
-    size_t nbytes = nchars * sizeof(jschar);
-    if (mode == XDR_ENCODE) {
-        uint8_t *ptr = buf.write(nbytes);
-        if (!ptr)
-            return false;
-#ifdef IS_LITTLE_ENDIAN
-        memcpy(ptr, chars, nbytes);
-#else
-        for (size_t i = 0; i != nchars; i++) {
-            uint16_t tmp = NormalizeByteOrder16(chars[i]);
-            memcpy(ptr, &tmp, sizeof tmp);
-            ptr += sizeof tmp;
-        }
-#endif
-    } else {
-        const uint8_t *ptr = buf.read(nbytes);
-#ifdef IS_LITTLE_ENDIAN
-        memcpy(chars, ptr, nbytes);
-#else
-        for (size_t i = 0; i != nchars; i++) {
-            uint16_t tmp;
-            memcpy(&tmp, ptr, sizeof tmp);
-            chars[i] = NormalizeByteOrder16(tmp);
-            ptr += sizeof tmp;
-        }
-#endif
-    }
-    return true;
-}
-
-/*
- * Convert between a JS (Unicode) string and the XDR representation.
- */
-template<XDRMode mode>
-bool
-XDRState<mode>::codeString(JSString **strp)
-{
-    uint32_t nchars;
-    jschar *chars;
-
-    if (mode == XDR_ENCODE)
-        nchars = (*strp)->length();
-    if (!codeUint32(&nchars))
-        return false;
-
-    if (mode == XDR_DECODE)
-        chars = (jschar *) cx()->malloc_((nchars + 1) * sizeof(jschar));
-    else
-        chars = const_cast<jschar *>((*strp)->getChars(cx()));
-    if (!chars)
-        return false;
-
-    if (!codeChars(chars, nchars))
-        goto bad;
-    if (mode == XDR_DECODE) {
-        chars[nchars] = 0;
-        *strp = JS_NewUCString(cx(), chars, nchars);
-        if (!*strp)
-            goto bad;
-    }
-    return true;
-
-bad:
-    if (mode == XDR_DECODE)
-        Foreground::free_(chars);
-    return false;
-}
-
-template<XDRMode mode>
-static bool
-VersionCheck(XDRState<mode> *xdr)
-{
-    uint32_t bytecodeVer;
-    if (mode == XDR_ENCODE)
-        bytecodeVer = XDR_BYTECODE_VERSION;
-
-    if (!xdr->codeUint32(&bytecodeVer))
-        return false;
-
-    if (mode == XDR_DECODE && bytecodeVer != XDR_BYTECODE_VERSION) {
-        /* We do not provide binary compatibility with older scripts. */
-        JS_ReportErrorNumber(xdr->cx(), js_GetErrorMessage, NULL, JSMSG_BAD_SCRIPT_MAGIC);
-        return false;
-    }
-
-    return true;
-}
-
-template<XDRMode mode>
-bool
-XDRState<mode>::codeFunction(JSObject **objp)
-{
-    if (mode == XDR_DECODE)
-        *objp = NULL;
-        
-    return VersionCheck(this) && XDRInterpretedFunction(this, objp, NULL);
-}
-
-template<XDRMode mode>
-bool
-XDRState<mode>::codeScript(JSScript **scriptp)
-{
-    JSScript *script;
-    if (mode == XDR_DECODE) {
-        script = NULL;
-        *scriptp = NULL;
-    } else {
-        script = *scriptp;
-    }
-
-    if (!VersionCheck(this) || !XDRScript(this, &script, NULL))
-        return false;
-
-    if (mode == XDR_DECODE) {
-        JS_ASSERT(!script->compileAndGo);
-        script->globalObject = GetCurrentGlobal(cx());
-        js_CallNewScriptHook(cx(), script, NULL);
-        Debugger::onNewScript(cx(), script, NULL);
-        *scriptp = script;
-    }
-
-    return true;
-}
-
-XDRDecoder::XDRDecoder(JSContext *cx, const void *data, uint32_t length,
-                       JSPrincipals *principals, JSPrincipals *originPrincipals)
-  : XDRState<XDR_DECODE>(cx)
-{
-    buf.setData(data, length);
-    this->principals = principals;
-    this->originPrincipals = JSScript::normalizeOriginPrincipals(principals, originPrincipals);
-}
-
-template class XDRState<XDR_ENCODE>;
-template class XDRState<XDR_DECODE>;
-
-} /* namespace js */
-
deleted file mode 100644
--- a/js/src/vm/Xdr.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=78:
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is SpiderMonkey string object code.
- *
- * The Initial Developer of the Original Code is
- * the Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2011
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef Xdr_h___
-#define Xdr_h___
-
-#include "jsapi.h"
-#include "jsprvtd.h"
-#include "jsnum.h"
-
-namespace js {
-
-/*
- * Bytecode version number. Increment the subtrahend whenever JS bytecode
- * changes incompatibly.
- *
- * This version number is XDR'd near the front of xdr bytecode and
- * aborts deserialization if there is a mismatch between the current
- * and saved versions. If deserialization fails, the data should be
- * invalidated if possible.
- */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 112);
-
-class XDRBuffer {
-  public:
-    XDRBuffer(JSContext *cx)
-      : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
-
-    JSContext *cx() const {
-        return context;
-    }
-
-    void *getData(uint32_t *lengthp) const {
-        JS_ASSERT(size_t(cursor - base) <= size_t(UINT32_MAX));
-        *lengthp = uint32_t(cursor - base);
-        return base;
-    }
-
-    void setData(const void *data, uint32_t length) {
-        base = static_cast<uint8_t *>(const_cast<void *>(data));
-        cursor = base;
-        limit = base + length;
-    }
-
-    const uint8_t *read(size_t n) {
-        JS_ASSERT(n <= size_t(limit - cursor));
-        uint8_t *ptr = cursor;
-        cursor += n;
-        return ptr;
-    }
-
-    const char *readCString() {
-        char *ptr = reinterpret_cast<char *>(cursor);
-        cursor = reinterpret_cast<uint8_t *>(strchr(ptr, '\0')) + 1;
-        JS_ASSERT(base < cursor);
-        JS_ASSERT(cursor <= limit);
-        return ptr;
-    }
-
-    uint8_t *write(size_t n) {
-        if (n > size_t(limit - cursor)) {
-            if (!grow(n))
-                return NULL;
-        }
-        uint8_t *ptr = cursor;
-        cursor += n;
-        return ptr;
-    }
-
-    static bool isUint32Overflow(size_t n) {
-        return size_t(-1) > size_t(UINT32_MAX) && n > size_t(UINT32_MAX);
-    }
-
-    void freeBuffer();
-
-  private:
-    bool grow(size_t n);
-
-    JSContext   *const context;
-    uint8_t     *base;
-    uint8_t     *cursor;
-    uint8_t     *limit;
-};
-
-/* We use little-endian byteorder for all encoded data */
-
-#if defined IS_LITTLE_ENDIAN
-
-inline uint32_t
-NormalizeByteOrder32(uint32_t x)
-{
-    return x;
-}
-
-inline uint16_t
-NormalizeByteOrder16(uint16_t x)
-{
-    return x;
-}
-
-#elif defined IS_BIG_ENDIAN
-
-inline uint32_t
-NormalizeByteOrder32(uint32_t x)
-{
-    return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
-}
-
-inline uint16_t
-NormalizeByteOrder16(uint16_t x)
-{
-    return (x >> 8) | (x << 8);
-}
-
-#else
-#error "unknown byte order"
-#endif
-
-template <XDRMode mode>
-class XDRState {
-  public:
-    XDRBuffer buf;
-
-  protected:
-    JSPrincipals *principals;
-    JSPrincipals *originPrincipals;
-
-    XDRState(JSContext *cx)
-      : buf(cx), principals(NULL), originPrincipals(NULL) {
-    }
-
-  public:
-    JSContext *cx() const {
-        return buf.cx();
-    }
-
-    bool codeUint8(uint8_t *n) {
-        if (mode == XDR_ENCODE) {
-            uint8_t *ptr = buf.write(sizeof *n);
-            if (!ptr)
-                return false;
-            *ptr = *n;
-        } else {
-            *n = *buf.read(sizeof *n);
-        }
-        return true;
-    }
-
-    bool codeUint16(uint16_t *n) {
-        uint16_t tmp;
-        if (mode == XDR_ENCODE) {
-            uint8_t *ptr = buf.write(sizeof tmp);
-            if (!ptr)
-                return false;
-            tmp = NormalizeByteOrder16(*n);
-            memcpy(ptr, &tmp, sizeof tmp);
-        } else {
-            memcpy(&tmp, buf.read(sizeof tmp), sizeof tmp);
-            *n = NormalizeByteOrder16(tmp);
-        }
-        return true;
-    }
-
-    bool codeUint32(uint32_t *n) {
-        uint32_t tmp;
-        if (mode == XDR_ENCODE) {
-            uint8_t *ptr = buf.write(sizeof tmp);
-            if (!ptr)
-                return false;
-            tmp = NormalizeByteOrder32(*n);
-            memcpy(ptr, &tmp, sizeof tmp);
-        } else {
-            memcpy(&tmp, buf.read(sizeof tmp), sizeof tmp);
-            *n = NormalizeByteOrder32(tmp);
-        }
-        return true;
-    }
-
-    bool codeDouble(double *dp) {
-        jsdpun tmp;
-        if (mode == XDR_ENCODE) {
-            uint8_t *ptr = buf.write(sizeof tmp);
-            if (!ptr)
-                return false;
-            tmp.d = *dp;
-            tmp.s.lo = NormalizeByteOrder32(tmp.s.lo);
-            tmp.s.hi = NormalizeByteOrder32(tmp.s.hi);
-            memcpy(ptr, &tmp.s.lo, sizeof tmp.s.lo);
-            memcpy(ptr + sizeof tmp.s.lo, &tmp.s.hi, sizeof tmp.s.hi);
-        } else {
-            const uint8_t *ptr = buf.read(sizeof tmp);
-            memcpy(&tmp.s.lo, ptr, sizeof tmp.s.lo);
-            memcpy(&tmp.s.hi, ptr + sizeof tmp.s.lo, sizeof tmp.s.hi);
-            tmp.s.lo = NormalizeByteOrder32(tmp.s.lo);
-            tmp.s.hi = NormalizeByteOrder32(tmp.s.hi);
-            *dp = tmp.d;
-        }
-        return true;
-    }
-
-    bool codeBytes(void *bytes, size_t len) {
-        if (mode == XDR_ENCODE) {
-            uint8_t *ptr = buf.write(len);
-            if (!ptr)
-                return false;
-            memcpy(ptr, bytes, len);
-        } else {
-            memcpy(bytes, buf.read(len), len);
-        }
-        return true;
-    }
-
-    /*
-     * During encoding the string is written into the buffer together with its
-     * terminating '\0'. During decoding the method returns a pointer into the
-     * decoding buffer and the caller must copy the string if it will outlive
-     * the decoding buffer.
-     */
-    bool codeCString(const char **sp) {
-        if (mode == XDR_ENCODE) {
-            size_t n = strlen(*sp) + 1;
-            uint8_t *ptr = buf.write(n);
-            if (!ptr)
-                return false;
-            memcpy(ptr, *sp, n);
-        } else {
-            *sp = buf.readCString();
-        }
-        return true;
-    }
-
-    bool codeChars(jschar *chars, size_t nchars);
-    bool codeString(JSString **strp);
-
-    bool codeFunction(JSObject **objp);
-    bool codeScript(JSScript **scriptp);
-
-    void initScriptPrincipals(JSScript *script) {
-        JS_ASSERT(mode == XDR_DECODE);
-        
-        /* The origin principals must be normalized at this point. */
-        JS_ASSERT_IF(principals, originPrincipals);
-        JS_ASSERT(!script->principals);
-        JS_ASSERT(!script->originPrincipals);
-        if (principals) {
-            script->principals = principals;
-            JS_HoldPrincipals(principals);
-        }
-        if (originPrincipals) {
-            script->originPrincipals = originPrincipals;
-            JS_HoldPrincipals(originPrincipals);
-        }
-    }
-};
-
-class XDREncoder : public XDRState<XDR_ENCODE> {
-  public:
-    XDREncoder(JSContext *cx)
-      : XDRState<XDR_ENCODE>(cx) {
-    }
-
-    ~XDREncoder() {
-        buf.freeBuffer();
-    }
-
-    const void *getData(uint32_t *lengthp) const {
-        return buf.getData(lengthp);
-    }
-
-    void *forgetData(uint32_t *lengthp) {
-        void *data = buf.getData(lengthp);
-        buf.setData(NULL, 0);
-        return data;
-    }
-};
-
-class XDRDecoder : public XDRState<XDR_DECODE> {
-  public:
-    XDRDecoder(JSContext *cx, const void *data, uint32_t length,
-               JSPrincipals *principals, JSPrincipals *originPrincipals);
-
-};
-
-} /* namespace js */
-
-#endif /* Xdr_h___ */
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -73,16 +73,17 @@
 #include "nsIXPCScriptable.h"
 #include "nsString.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsIFileURL.h"
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #include "nsDOMFile.h"
+#include "jsxdrapi.h"
 #include "jsprf.h"
 #include "nsJSPrincipals.h"
 // For reporting errors with the console service
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsIStorageStream.h"
 #include "nsIStringStream.h"
 #include "prmem.h"
--- a/js/xpconnect/loader/mozJSLoaderUtils.cpp
+++ b/js/xpconnect/loader/mozJSLoaderUtils.cpp
@@ -35,54 +35,74 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAutoPtr.h"
 #include "nsScriptLoader.h"
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
+#include "jsxdrapi.h"
 
 #include "nsJSPrincipals.h"
 
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 
 using namespace mozilla::scache;
 
 // We only serialize scripts with system principals. So we don't serialize the
 // principals when writing a script. Instead, when reading it back, we set the
 // principals to the system principals.
 nsresult
 ReadCachedScript(StartupCache* cache, nsACString &uri, JSContext *cx,
-                 nsIPrincipal *systemPrincipal, JSScript **scriptp)
+                 nsIPrincipal *systemPrincipal, JSScript **script)
 {
     nsAutoArrayPtr<char> buf;
     PRUint32 len;
     nsresult rv = cache->GetBuffer(PromiseFlatCString(uri).get(),
                                    getter_Transfers(buf), &len);
-    if (NS_FAILED(rv))
+    if (NS_FAILED(rv)) {
         return rv; // don't warn since NOT_AVAILABLE is an ok error
+    }
+
+    JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_DECODE);
+    if (!xdr) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
 
-    JSScript *script = JS_DecodeScript(cx, buf, len, nsJSPrincipals::get(systemPrincipal), nsnull);
-    if (!script)
-        return NS_ERROR_OUT_OF_MEMORY;
-    *scriptp = script;
-    return NS_OK;
+    ::JS_XDRMemSetData(xdr, buf, len);
+    ::JS_XDRSetPrincipals(xdr, nsJSPrincipals::get(systemPrincipal), nsnull);
+
+    JSBool ok = ::JS_XDRScript(xdr, script);
+    
+    // Prevent XDR from automatically freeing the buffer.
+    ::JS_XDRMemSetData(xdr, NULL, 0);
+    ::JS_XDRDestroy(xdr);
+
+    return ok ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 nsresult
 WriteCachedScript(StartupCache* cache, nsACString &uri, JSContext *cx,
                   nsIPrincipal *systemPrincipal, JSScript *script)
 {
     MOZ_ASSERT(JS_GetScriptPrincipals(script) == nsJSPrincipals::get(systemPrincipal));
     MOZ_ASSERT(JS_GetScriptOriginPrincipals(script) == nsJSPrincipals::get(systemPrincipal));
 
-    uint32_t size;
-    void *data = JS_EncodeScript(cx, script, &size);
-    if (!data)
+    JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE);
+    if (!xdr) {
         return NS_ERROR_OUT_OF_MEMORY;
+    }
 
-    MOZ_ASSERT(size);
-    nsresult rv = cache->PutBuffer(PromiseFlatCString(uri).get(), static_cast<char *>(data), size);
-    js_free(data);
+    nsresult rv;
+    if (!::JS_XDRScript(xdr, &script)) {
+        rv = NS_ERROR_OUT_OF_MEMORY;
+    } else {
+        uint32_t size;
+        char* data = static_cast<char *>(::JS_XDRMemGetData(xdr, &size));
+        MOZ_ASSERT(size);
+        rv = cache->PutBuffer(PromiseFlatCString(uri).get(), data, size);
+    }
+
+    ::JS_XDRDestroy(xdr);
     return rv;
 }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -48,16 +48,17 @@
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "nsBaseHashtable.h"
 #include "nsHashKeys.h"
 #include "jsatom.h"
 #include "jsfriendapi.h"
 #include "jsgc.h"
+#include "jsxdrapi.h"
 #include "dom_quickstubs.h"
 #include "nsNullPrincipal.h"
 #include "nsIURI.h"
 #include "nsJSEnvironment.h"
 #include "nsThreadUtils.h"
 
 #include "XrayWrapper.h"
 #include "WrapperFactory.h"
@@ -2833,33 +2834,44 @@ WriteScriptOrFunction(nsIObjectOutputStr
     }
 
     if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
         rv = stream->WriteObject(originPrincipal, true);
         if (NS_FAILED(rv))
             return rv;
     }
 
-    uint32_t size;
-    void* data;
+    JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_ENCODE);
+    if (!xdr)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    JSBool ok;
     {
         JSAutoRequest ar(cx);
         if (functionObj)
-            data = JS_EncodeInterpretedFunction(cx, functionObj, &size);
+            ok = JS_XDRFunctionObject(xdr, &functionObj);
         else
-            data = JS_EncodeScript(cx, script, &size);
+            ok = JS_XDRScript(xdr, &script);
     }
 
-    if (!data)
-        return NS_ERROR_OUT_OF_MEMORY;
-    MOZ_ASSERT(size);
-    rv = stream->Write32(size);
-    if (NS_SUCCEEDED(rv))
-        rv = stream->WriteBytes(static_cast<char *>(data), size);
-    js_free(data);
+    if (!ok) {
+        rv = NS_ERROR_OUT_OF_MEMORY;
+    } else {
+        // Get the encoded JSXDRState data and write it.  The JSXDRState owns
+        // this buffer memory and will free it beneath JS_XDRDestroy.
+        uint32_t size;
+        const char* data = reinterpret_cast<const char*>(::JS_XDRMemGetData(xdr, &size));
+        NS_ASSERTION(data, "no decoded JSXDRState data!");
+
+        rv = stream->Write32(size);
+        if (NS_SUCCEEDED(rv))
+            rv = stream->WriteBytes(data, size);
+    }
+
+    JS_XDRDestroy(xdr);
 
     return rv;
 }
 
 static nsresult
 ReadScriptOrFunction(nsIObjectInputStream *stream, JSContext *cx,
                      JSScript **scriptp, JSObject **functionObjp)
 {
@@ -2894,36 +2906,41 @@ ReadScriptOrFunction(nsIObjectInputStrea
     if (NS_FAILED(rv))
         return rv;
 
     char* data;
     rv = stream->ReadBytes(size, &data);
     if (NS_FAILED(rv))
         return rv;
 
+    JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_DECODE);
+    if (!xdr) {
+        nsMemory::Free(data);
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    JS_XDRMemSetData(xdr, data, size);
+    JS_XDRSetPrincipals(xdr, principal, originPrincipal);
+
+    JSBool ok;
     {
         JSAutoRequest ar(cx);
-        if (scriptp) {
-            JSScript *script = JS_DecodeScript(cx, data, size, principal, originPrincipal);
-            if (!script)
-                rv = NS_ERROR_OUT_OF_MEMORY;
-            else
-                *scriptp = script;
-        } else {
-            JSObject *funobj = JS_DecodeInterpretedFunction(cx, data, size,
-                                                            principal, originPrincipal);
-            if (!funobj)
-                rv = NS_ERROR_OUT_OF_MEMORY;
-            else
-                *functionObjp = funobj;
-        }
+        if (scriptp)
+            ok = JS_XDRScript(xdr, scriptp);
+        else
+            ok = JS_XDRFunctionObject(xdr, functionObjp);
     }
 
+    // We cannot rely on XDR automatically freeing the data memory as we must
+    // use nsMemory::Free to release it.
+    JS_XDRMemSetData(xdr, NULL, 0);
+    JS_XDRDestroy(xdr);
     nsMemory::Free(data);
-    return rv;
+
+    return ok ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsXPConnect::WriteScript(nsIObjectOutputStream *stream, JSContext *cx, JSScript *script)
 {
     return WriteScriptOrFunction(stream, cx, script, nsnull);
 }