bug 737624 - memory-only encoding/decoding of scripts and functions. r=:luke
☠☠ backed out by 081b574dbad3 ☠ ☠
authorIgor Bukanov <igor@mir2.org>
Mon, 20 Feb 2012 11:58:00 +0100
changeset 90258 30798fdc5bad0d4b899faf5f979e1caf5a901484
parent 90257 7a39ee24bd89ea0d9f3be6988b3642e64389af7a
child 90259 081b574dbad3ea95b40a458e036eabc7ed7ee7d3
push id630
push usertim.taubert@gmx.de
push dateSun, 25 Mar 2012 17:36:30 +0000
treeherderfx-team@3e4735893504 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs737624
milestone14.0a1
bug 737624 - memory-only encoding/decoding of scripts and functions. r=:luke The patch shrinks the API presented in jsxdrapi.h down to 4 functions to encode/decode scripts and interpreted functions to/from the memory. The newly introduced implementation header vm/Xdr.h replaces the former JSXDRState with the template class XDRState parametrized by the enum type with two constants, XDR_ENCODE and XDR_DECODE. This way a compiler can fully eliminate the former runtime checks for the decoding/encoding mode. As a drawback this required to explicitly instantiate the xdr implementation as I do not want to put all the xdr code to header files. The memory-only XDR allows to avoid coping filename and to-be-atomized chars to a temporary buffer as the code can just access the buffer directly. Another change is that new XDRScript takes as a parameter its parent script. This allowed to avoid keeping filename in XDRState and simplify the filename management. Another change is the removal of JS_HAS_HDR. As CloneScript uses XDR to copy a script, JS_HAS_XDR cannot be disabled.
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,17 +39,16 @@
 #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 "jsxdrapi.h"
+#include "jsapi.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,17 +141,16 @@ 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 \
@@ -172,16 +171,17 @@ 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,17 +205,16 @@ 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 JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such
+ * Don't forget to update XDR_BYTECODE_VERSION in vm/Xdr.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_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_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_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,14 +1,13 @@
 /* -*- 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,18 +1,16 @@
 /* -*- 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,14 +1,13 @@
 /* -*- 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,17 +8,16 @@
  */
 #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,14 +1,13 @@
 /* -*- 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,15 +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 "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)
 {
@@ -23,73 +22,52 @@ CompileScriptForPrincipalsVersionOrigin(
     JSScript *script = JS_CompileUCScriptForPrincipalsVersionOrigin(cx, obj,
                                                                     principals, originPrincipals,
                                                                     chars, nchars,
                                                                     filename, lineno, version);
     free(chars);
     return script;
 }
 
-template<typename T>
-T *
-FreezeThawImpl(JSContext *cx, T *thing, JSBool (*xdrAction)(JSXDRState *xdr, T **))
+JSScript *
+FreezeThaw(JSContext *cx, JSScript *script)
 {
     // freeze
-    JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
-    if (!w)
-        return NULL;
-
-    void *memory = NULL;
     uint32_t 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);
+    void *memory = JS_EncodeScript(cx, script, &nbytes);
     if (!memory)
         return NULL;
 
     // thaw
-    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)
-{
+    script = JS_DecodeScript(cx, memory, nbytes, script->principals, script->originPrincipals);
+    js_free(memory);
     return script;
 }
 
 static JSScript *
 GetScript(JSContext *cx, JSObject *funobj)
 {
     return JS_GetFunctionScript(cx, JS_GetObjectFunction(funobj));
 }
 
-static JSScript *
-FreezeThaw(JSContext *cx, JSScript *script)
-{
-    return FreezeThawImpl(cx, script, JS_XDRScript);
-}
-
-static JSObject *
+JSObject *
 FreezeThaw(JSContext *cx, JSObject *funobj)
 {
-    return FreezeThawImpl(cx, funobj, JS_XDRFunctionObject);
+    // 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;
 }
 
 static JSPrincipals testPrincipals[] = {
     { 1 },
     { 1 },
 };
 
 BEGIN_TEST(testXDR_principals)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -77,28 +77,29 @@
 #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"
@@ -107,20 +108,16 @@
 #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:
  *
@@ -6633,8 +6630,48 @@ 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,11 +5405,29 @@ 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,16 +63,17 @@
 
 #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);
 
@@ -652,8 +653,70 @@ 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,9 +473,17 @@ 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 jsxdrapi.h's
- * JSXDR_BYTECODE_VERSION.
+ * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's
+ * XDR_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,47 +47,43 @@
 
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
-#include "jsversion.h"
+#include "jsexn.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"
@@ -475,33 +471,30 @@ fun_resolve(JSContext *cx, JSObject *obj
             *objp = fun;
             return true;
         }
     }
 
     return true;
 }
 
-#if JS_HAS_XDR
-
-/* XXX store parent and proto, if defined */
-JSBool
-js::XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
+template<XDRMode mode>
+bool
+js::XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript)
 {
-    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 */
 
-    cx = xdr->cx;
+    JSContext *cx = xdr->cx();
     JSScript *script;
-    if (xdr->mode == JSXDR_ENCODE) {
+    if (mode == XDR_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;
@@ -518,43 +511,47 @@ js::XDRFunctionObject(JSXDRState *xdr, J
         if (!fun->clearParent(cx))
             return false;
         if (!fun->clearType(cx))
             return false;
         atom = NULL;
         script = NULL;
     }
 
-    if (!JS_XDRUint32(xdr, &firstword))
+    if (!xdr->codeUint32(&firstword))
         return false;
-    if ((firstword & 1U) && !js_XDRAtom(xdr, &atom))
+    if ((firstword & 1U) && !XDRAtom(xdr, &atom))
         return false;
-    if (!JS_XDRUint32(xdr, &flagsword))
+    if (!xdr->codeUint32(&flagsword))
         return false;
 
-    if (!XDRScript(xdr, &script))
+    if (!XDRScript(xdr, &script, parentScript))
         return false;
 
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_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;
 }
 
-#endif /* JS_HAS_XDR */
+template bool
+js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *xdr, JSObject **objp, JSScript *parentScript);
+
+template bool
+js::XDRInterpretedFunction(XDRState<XDR_DECODE> *xdr, JSObject **objp, JSScript *parentScript);
 
 /*
  * [[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,18 +351,19 @@ 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 {
 
-extern JSBool
-XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
+template<XDRMode mode>
+bool
+XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
 
 } /* 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
 
-typedef union jsdpun {
+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,41 +71,35 @@
 #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 "js/MemoryMetrics.h"
 #include "vm/StringBuffer.h"
-#include "js/MemoryMetrics.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,16 +311,24 @@ 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,25 +221,24 @@ 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
+#endif /* !__cplusplus */
 
 #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,26 +57,24 @@
 #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;
@@ -291,20 +289,21 @@ Bindings::makeImmutable()
 
 void
 Bindings::trace(JSTracer *trc)
 {
     if (lastBinding)
         MarkShape(trc, &lastBinding, "shape");
 }
 
-#if JS_HAS_XDR
+} /* namespace js */
 
+template<XDRMode mode>
 static bool
-XDRScriptConst(JSXDRState *xdr, HeapValue *vp)
+XDRScriptConst(XDRState<mode> *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,
@@ -312,17 +311,17 @@ XDRScriptConst(JSXDRState *xdr, HeapValu
         SCRIPT_STRING  = 2,
         SCRIPT_TRUE    = 3,
         SCRIPT_FALSE   = 4,
         SCRIPT_NULL    = 5,
         SCRIPT_VOID    = 6
     };
 
     uint32_t tag;
-    if (xdr->mode == JSXDR_ENCODE) {
+    if (mode == XDR_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;
@@ -331,119 +330,121 @@ XDRScriptConst(JSXDRState *xdr, HeapValu
         } else if (vp->isNull()) {
             tag = SCRIPT_NULL;
         } else {
             JS_ASSERT(vp->isUndefined());
             tag = SCRIPT_VOID;
         }
     }
 
-    if (!JS_XDRUint32(xdr, &tag))
+    if (!xdr->codeUint32(&tag))
         return false;
 
     switch (tag) {
       case SCRIPT_INT: {
         uint32_t i;
-        if (xdr->mode == JSXDR_ENCODE)
+        if (mode == XDR_ENCODE)
             i = uint32_t(vp->toInt32());
-        if (!JS_XDRUint32(xdr, &i))
+        if (!xdr->codeUint32(&i))
             return JS_FALSE;
-        if (xdr->mode == JSXDR_DECODE)
+        if (mode == XDR_DECODE)
             vp->init(Int32Value(int32_t(i)));
         break;
       }
       case SCRIPT_DOUBLE: {
         double d;
-        if (xdr->mode == JSXDR_ENCODE)
+        if (mode == XDR_ENCODE)
             d = vp->toDouble();
-        if (!JS_XDRDouble(xdr, &d))
+        if (!xdr->codeDouble(&d))
             return false;
-        if (xdr->mode == JSXDR_DECODE)
+        if (mode == XDR_DECODE)
             vp->init(DoubleValue(d));
         break;
       }
       case SCRIPT_STRING: {
         JSString *str;
-        if (xdr->mode == JSXDR_ENCODE)
+        if (mode == XDR_ENCODE)
             str = vp->toString();
-        if (!JS_XDRString(xdr, &str))
+        if (!xdr->codeString(&str))
             return false;
-        if (xdr->mode == JSXDR_DECODE)
+        if (mode == XDR_DECODE)
             vp->init(StringValue(str));
         break;
       }
       case SCRIPT_TRUE:
-        if (xdr->mode == JSXDR_DECODE)
+        if (mode == XDR_DECODE)
             vp->init(BooleanValue(true));
         break;
       case SCRIPT_FALSE:
-        if (xdr->mode == JSXDR_DECODE)
+        if (mode == XDR_DECODE)
             vp->init(BooleanValue(false));
         break;
       case SCRIPT_NULL:
-        if (xdr->mode == JSXDR_DECODE)
+        if (mode == XDR_DECODE)
             vp->init(NullValue());
         break;
       case SCRIPT_VOID:
-        if (xdr->mode == JSXDR_DECODE)
+        if (mode == XDR_DECODE)
             vp->init(UndefinedValue());
         break;
     }
     return true;
 }
 
 static const char *
 SaveScriptFilename(JSContext *cx, const char *filename);
 
-JSBool
-XDRScript(JSXDRState *xdr, JSScript **scriptp)
+template<XDRMode mode>
+bool
+js::XDRScript(XDRState<mode> *xdr, JSScript **scriptp, JSScript *parentScript)
 {
     enum ScriptBits {
         NoScriptRval,
         SavedCallerFun,
         StrictModeCode,
         UsesEval,
         MayNeedArgsObj,
         NeedsArgsObj,
         OwnFilename,
-        SharedFilename
+        ParentFilename
     };
 
     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 (xdr->mode == JSXDR_ENCODE) {
+    if (mode == XDR_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 (!JS_XDRUint32(xdr, &argsVars))
+    if (!xdr->codeUint32(&argsVars))
         return false;
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_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;
@@ -461,74 +462,74 @@ XDRScript(JSXDRState *xdr, JSScript **sc
         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 (xdr->mode == JSXDR_ENCODE) {
+        if (mode == XDR_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 (!JS_XDRUint32(xdr, &bitmap[i]))
+            if (!xdr->codeUint32(&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 (xdr->mode == JSXDR_DECODE) {
+                if (mode == XDR_DECODE) {
                     uint16_t dummy;
                     if (!bindings.addDestructuring(cx, &dummy))
                         return false;
                 } else {
                     JS_ASSERT(!names[i]);
                 }
                 continue;
             }
 
             JSAtom *name;
-            if (xdr->mode == JSXDR_ENCODE)
+            if (mode == XDR_ENCODE)
                 name = names[i];
-            if (!js_XDRAtom(xdr, &name))
+            if (!XDRAtom(xdr, &name))
                 return false;
-            if (xdr->mode == JSXDR_DECODE) {
+            if (mode == XDR_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 (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_DECODE) {
         if (!bindings.ensureShape(cx))
             return false;
         bindings.makeImmutable();
     }
 
-    if (xdr->mode == JSXDR_ENCODE)
+    if (mode == XDR_ENCODE)
         length = script->length;
-    if (!JS_XDRUint32(xdr, &length))
+    if (!xdr->codeUint32(&length))
         return JS_FALSE;
 
-    if (xdr->mode == JSXDR_ENCODE) {
+    if (mode == XDR_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;
 
@@ -564,54 +565,54 @@ XDRScript(JSXDRState *xdr, JSScript **sc
              * 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 |= (script->filename != xdr->sharedFilename)
-                          ? (1 << OwnFilename)
-                          : (1 << SharedFilename);
+            scriptBits |= (parentScript && parentScript->filename == script->filename)
+                          ? (1 << ParentFilename)
+                          : (1 << OwnFilename);
         }
 
         JS_ASSERT(!script->compileAndGo);
         JS_ASSERT(!script->hasSingletons);
     }
 
-    if (!JS_XDRUint32(xdr, &prologLength))
+    if (!xdr->codeUint32(&prologLength))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &version))
+    if (!xdr->codeUint32(&version))
         return JS_FALSE;
 
     /*
      * To fuse allocations, we need srcnote, atom, objects, regexp, and trynote
      * counts early.
      */
-    if (!JS_XDRUint32(xdr, &natoms))
+    if (!xdr->codeUint32(&natoms))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &nsrcnotes))
+    if (!xdr->codeUint32(&nsrcnotes))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &ntrynotes))
+    if (!xdr->codeUint32(&ntrynotes))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &nobjects))
+    if (!xdr->codeUint32(&nobjects))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &nregexps))
+    if (!xdr->codeUint32(&nregexps))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &nconsts))
+    if (!xdr->codeUint32(&nconsts))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &encodedClosedCount))
+    if (!xdr->codeUint32(&encodedClosedCount))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &nTypeSets))
+    if (!xdr->codeUint32(&nTypeSets))
         return JS_FALSE;
-    if (!JS_XDRUint32(xdr, &scriptBits))
+    if (!xdr->codeUint32(&scriptBits))
         return JS_FALSE;
 
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_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,
@@ -632,116 +633,101 @@ XDRScript(JSXDRState *xdr, JSScript **sc
             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->mayNeedArgsObj_ = true;
+            script->setMayNeedArgsObj();
             if (scriptBits & (1 << NeedsArgsObj))
                 script->setNeedsArgsObj(true);
         } else {
             JS_ASSERT(!(scriptBits & (1 << NeedsArgsObj)));
         }
     }
 
-    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)) {
+    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)) {
         return false;
     }
 
     if (scriptBits & (1 << OwnFilename)) {
-        char *filename;
-        if (xdr->mode == JSXDR_ENCODE)
-            filename = const_cast<char *>(script->filename);
-        if (!JS_XDRCString(xdr, &filename))
+        const char *filename;
+        if (mode == XDR_ENCODE)
+            filename = script->filename;
+        if (!xdr->codeCString(&filename))
             return false;
-        if (xdr->mode == JSXDR_DECODE) {
-            script->filename = SaveScriptFilename(xdr->cx, filename);
-            Foreground::free_(filename);
+        if (mode == XDR_DECODE) {
+            script->filename = SaveScriptFilename(cx, filename);
             if (!script->filename)
                 return false;
         }
-        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;
+    } else if (scriptBits & (1 << ParentFilename)) {
+        JS_ASSERT(parentScript);
+        if (mode == XDR_DECODE)
+            script->filename = parentScript->filename;
     }
 
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_DECODE) {
         script->lineno = lineno;
         script->nslots = uint16_t(nslots);
         script->staticLevel = uint16_t(nslots >> 16);
-
-        /* 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);
-        }
+        xdr->initScriptPrincipals(script);
     }
 
     for (i = 0; i != natoms; ++i) {
-        if (!js_XDRAtom(xdr, &script->atoms[i]))
+        if (!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 (xdr->mode == JSXDR_ENCODE) {
+        if (mode == XDR_ENCODE) {
             JSObject *obj = *objp;
             JS_ASSERT(obj->isFunction() || obj->isStaticBlock());
             isBlock = obj->isBlock() ? 1 : 0;
         }
-        if (!JS_XDRUint32(xdr, &isBlock))
+        if (!xdr->codeUint32(&isBlock))
             return false;
         if (isBlock == 0) {
             JSObject *tmp = *objp;
-            if (!XDRFunctionObject(xdr, &tmp))
+            if (!XDRInterpretedFunction(xdr, &tmp, parentScript))
                 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 (!JS_XDRUint32(xdr, &script->closedSlots[i]))
+        if (!xdr->codeUint32(&script->closedSlots[i]))
             return false;
     }
     for (i = 0; i != nClosedVars; ++i) {
-        if (!JS_XDRUint32(xdr, &script->closedSlots[nClosedArgs + i]))
+        if (!xdr->codeUint32(&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.
          */
@@ -750,52 +736,54 @@ XDRScript(JSXDRState *xdr, JSScript **sc
         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 (xdr->mode == JSXDR_ENCODE) {
+            if (mode == XDR_ENCODE) {
                 kindAndDepth = (uint32_t(tn->kind) << 16)
                                | uint32_t(tn->stackDepth);
             }
-            if (!JS_XDRUint32(xdr, &kindAndDepth) ||
-                !JS_XDRUint32(xdr, &tn->start) ||
-                !JS_XDRUint32(xdr, &tn->length)) {
+            if (!xdr->codeUint32(&kindAndDepth) ||
+                !xdr->codeUint32(&tn->start) ||
+                !xdr->codeUint32(&tn->length)) {
                 return false;
             }
-            if (xdr->mode == JSXDR_DECODE) {
+            if (mode == XDR_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 (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_DECODE) {
         if (cx->hasRunOption(JSOPTION_PCCOUNT))
             (void) script->initCounts(cx);
         *scriptp = script;
     }
 
     return true;
 }
 
-#endif /* JS_HAS_XDR */
+template bool
+js::XDRScript(XDRState<XDR_ENCODE> *xdr, JSScript **scriptp, JSScript *parentScript);
 
-} /* namespace js */
+template bool
+js::XDRScript(XDRState<XDR_DECODE> *xdr, JSScript **scriptp, JSScript *parentScript);
 
 bool
 JSScript::initCounts(JSContext *cx)
 {
     JS_ASSERT(!pcCounters);
 
     size_t count = 0;
 
@@ -839,18 +827,16 @@ 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;
@@ -919,18 +905,16 @@ 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.
@@ -1235,17 +1219,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->mayNeedArgsObj_ = true;
+            script->setMayNeedArgsObj();
             if (needsArgsObj)
                 script->setNeedsArgsObj(true);
         }
     }
 
     if (bce->globalUses.length()) {
         PodCopy<GlobalSlotArray::Entry>(script->globals()->vector, &bce->globalUses[0],
                                         bce->globalUses.length());
@@ -1621,84 +1605,42 @@ CurrentScriptFileLineOriginSlow(JSContex
     }
 
     JSScript *script = iter.fp()->script();
     *file = script->filename;
     *linenop = PCToLineNumber(iter.fp()->script(), iter.pc());
     *origin = script->originPrincipals;
 }
 
-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
-};
+}  /* namespace js */
 
 JSScript *
-CloneScript(JSContext *cx, JSScript *script)
+js::CloneScript(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(cx->compartment != script->compartment());
 
     /* Serialize script. */
-    AutoJSXDRState w(JS_XDRNewMem(cx, JSXDR_ENCODE));
-    if (!w)
-        return NULL;
+    XDREncoder encoder(cx);
 
-    if (!XDRScript(w, &script))
+    if (!XDRScript(&encoder, &script, NULL))
         return NULL;
 
     uint32_t nbytes;
-    void *p = JS_XDRMemGetData(w, &nbytes);
-    if (!p)
-        return NULL;
+    const void *p = encoder.getData(&nbytes);
 
     /* De-serialize script. */
-    AutoJSXDRState r(JS_XDRNewMem(cx, JSXDR_DECODE));
-    if (!r)
-        return NULL;
+    XDRDecoder decoder(cx, p, nbytes, cx->compartment->principals, script->originPrincipals);
 
-    /*
-     * 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))
+    JSScript *newScript;
+    if (!XDRScript(&decoder, &newScript, NULL))
         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,24 +318,16 @@ 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
@@ -351,18 +343,16 @@ 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 */
@@ -440,16 +430,20 @@ 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 */
@@ -885,11 +879,20 @@ 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,17 +80,16 @@
 
 #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 */
@@ -103,17 +102,16 @@
 
 #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 */
@@ -122,17 +120,16 @@
 #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 */
@@ -141,17 +138,16 @@
 #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 */
@@ -160,17 +156,16 @@
 #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 */
deleted file mode 100644
--- a/js/src/jsxdrapi.h
+++ /dev/null
@@ -1,224 +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 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,16 +40,17 @@
 
 #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,16 +37,17 @@
  * 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;
@@ -741,41 +742,43 @@ js::ParseRegExpFlags(JSContext *cx, JSSt
             return false;
           }
         }
 #undef HANDLE_FLAG
     }
     return true;
 }
 
-#if JS_HAS_XDR
-# include "jsxdrapi.h"
-
+template<XDRMode mode>
 bool
-js::XDRScriptRegExpObject(JSXDRState *xdr, HeapPtrObject *objp)
+js::XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp)
 {
     JSAtom *source = 0;
     uint32_t flagsword = 0;
 
-    if (xdr->mode == JSXDR_ENCODE) {
+    if (mode == XDR_ENCODE) {
         JS_ASSERT(objp);
         RegExpObject &reobj = (*objp)->asRegExp();
         source = reobj.getSource();
         flagsword = reobj.getFlags();
     }
-    if (!js_XDRAtom(xdr, &source) || !JS_XDRUint32(xdr, &flagsword))
+    if (!XDRAtom(xdr, &source) || !xdr->codeUint32(&flagsword))
         return false;
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_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,14 +464,15 @@ 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(JSXDRState *xdr, HeapPtrObject *objp);
+XDRScriptRegExpObject(XDRState<mode> *xdr, HeapPtrObject *objp);
 
 } /* namespace js */
 
 #endif
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -37,22 +37,20 @@
  * 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;
@@ -931,18 +929,16 @@ 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) {
@@ -952,42 +948,43 @@ FindObjectIndex(JSObjectArray *array, JS
             if (array->vector[--i] == obj)
                 return i;
         } while (i != 0);
     }
 
     return NO_PARENT_INDEX;
 }
 
+template<XDRMode mode>
 bool
-js::XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **objp)
+js::XDRStaticBlockObject(XDRState<mode> *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 (xdr->mode == JSXDR_ENCODE) {
+    if (mode == XDR_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 (!JS_XDRUint32(xdr, &parentId))
+    if (!xdr->codeUint32(&parentId))
         return false;
 
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_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
@@ -995,31 +992,31 @@ js::XDRStaticBlockObject(JSXDRState *xdr
          */
         obj->setEnclosingBlock(parentId == NO_PARENT_INDEX
                                ? NULL
                                : &script->getObject(parentId)->asStaticBlock());
     }
 
     AutoObjectRooter tvr(cx, obj);
 
-    if (!JS_XDRUint32(xdr, &depthAndCount))
+    if (!xdr->codeUint32(&depthAndCount))
         return false;
 
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_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 (!js_XDRAtom(xdr, &atom))
+            if (!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;
@@ -1049,16 +1046,20 @@ js::XDRStaticBlockObject(JSXDRState *xdr
             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 (!js_XDRAtom(xdr, &atom))
+            if (!XDRAtom(xdr, &atom))
                 return false;
         }
     }
     return true;
 }
 
-#endif  /* JS_HAS_XDR */
+template bool
+js::XDRStaticBlockObject(XDRState<XDR_ENCODE> *xdr, JSScript *script, StaticBlockObject **objp);
+
+template bool
+js::XDRStaticBlockObject(XDRState<XDR_DECODE> *xdr, JSScript *script, StaticBlockObject **objp);
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -271,14 +271,15 @@ 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);
 };
 
-extern bool
-XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **objp);
+template<XDRMode mode>
+bool
+XDRStaticBlockObject(XDRState<mode> *xdr, JSScript *script, StaticBlockObject **objp);
 
 }  /* namespace js */
 
 #endif /* ScopeObject_h___ */
rename from js/src/jsxdrapi.cpp
rename to js/src/vm/Xdr.cpp
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -36,554 +36,204 @@
  * 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 "jsscript.h"
 #include "jsstr.h"
-#include "jsxdrapi.h"
-#include "vm/Debugger.h"
+
+#include "Xdr.h"
+#include "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
+namespace js {
 
-#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
+XDRBuffer::freeBuffer()
 {
-    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;
+    Foreground::free_(base);
+#ifdef DEBUG
+    memset(this, 0xe2, sizeof *this);
+#endif
 }
 
-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)
+bool
+XDRBuffer::grow(size_t n)
 {
-    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_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;
 }
-
-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)
+    
+template<XDRMode mode>
+bool
+XDRState<mode>::codeChars(jschar *chars, size_t nchars)
 {
-    uint32_t padlen;
-    static char padbuf[JSXDR_ALIGN-1];
-
-    if (xdr->mode == JSXDR_ENCODE) {
-        if (!xdr->ops->setbytes(xdr, bytes, len))
-            return JS_FALSE;
+    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 {
-        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;
+        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 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;
+    return true;
 }
 
 /*
  * Convert between a JS (Unicode) string and the XDR representation.
  */
-JS_PUBLIC_API(JSBool)
-JS_XDRString(JSXDRState *xdr, JSString **strp)
+template<XDRMode mode>
+bool
+XDRState<mode>::codeString(JSString **strp)
 {
     uint32_t nchars;
     jschar *chars;
 
-    if (xdr->mode == JSXDR_ENCODE)
+    if (mode == XDR_ENCODE)
         nchars = (*strp)->length();
-    if (!JS_XDRUint32(xdr, &nchars))
-        return JS_FALSE;
+    if (!codeUint32(&nchars))
+        return false;
 
-    if (xdr->mode == JSXDR_DECODE)
-        chars = (jschar *) xdr->cx->malloc_((nchars + 1) * sizeof(jschar));
+    if (mode == XDR_DECODE)
+        chars = (jschar *) cx()->malloc_((nchars + 1) * sizeof(jschar));
     else
-        chars = const_cast<jschar *>((*strp)->getChars(xdr->cx));
+        chars = const_cast<jschar *>((*strp)->getChars(cx()));
     if (!chars)
-        return JS_FALSE;
+        return false;
 
-    if (!XDRChars(xdr, chars, nchars))
+    if (!codeChars(chars, nchars))
         goto bad;
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_DECODE) {
         chars[nchars] = 0;
-        *strp = JS_NewUCString(xdr->cx, chars, nchars);
+        *strp = JS_NewUCString(cx(), chars, nchars);
         if (!*strp)
             goto bad;
     }
-    return JS_TRUE;
+    return true;
 
 bad:
-    if (xdr->mode == JSXDR_DECODE)
-        xdr->cx->free_(chars);
-    return JS_FALSE;
+    if (mode == XDR_DECODE)
+        Foreground::free_(chars);
+    return false;
 }
 
-JS_PUBLIC_API(JSBool)
-JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp)
+template<XDRMode mode>
+static bool
+VersionCheck(XDRState<mode> *xdr)
 {
-    uint32_t null = (*strp == NULL);
-    if (!JS_XDRUint32(xdr, &null))
-        return JS_FALSE;
-    if (null) {
-        *strp = NULL;
-        return JS_TRUE;
+    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 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)
+template<XDRMode mode>
+bool
+XDRState<mode>::codeFunction(JSObject **objp)
 {
-    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;
+    if (mode == XDR_DECODE)
+        *objp = NULL;
+        
+    return VersionCheck(this) && XDRInterpretedFunction(this, objp, NULL);
 }
 
-JS_PUBLIC_API(JSBool)
-JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
-{
-    return XDRFunctionObject(xdr, objp);
-}
-
-JS_PUBLIC_API(JSBool)
-JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
+template<XDRMode mode>
+bool
+XDRState<mode>::codeScript(JSScript **scriptp)
 {
     JSScript *script;
-    uint32_t magic;
-    uint32_t bytecodeVer;
-    if (xdr->mode == JSXDR_DECODE) {
+    if (mode == XDR_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))
+    if (!VersionCheck(this) || !XDRScript(this, &script, NULL))
         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) {
+    if (mode == XDR_DECODE) {
         JS_ASSERT(!script->compileAndGo);
-        script->globalObject = GetCurrentGlobal(xdr->cx);
-        js_CallNewScriptHook(xdr->cx, script, NULL);
-        Debugger::onNewScript(xdr->cx, script, NULL);
+        script->globalObject = GetCurrentGlobal(cx());
+        js_CallNewScriptHook(cx(), script, NULL);
+        Debugger::onNewScript(cx(), script, NULL);
         *scriptp = script;
     }
 
     return true;
 }
 
-#endif /* JS_HAS_XDR */
+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 */
+
new file mode 100644
--- /dev/null
+++ b/js/src/vm/Xdr.h
@@ -0,0 +1,322 @@
+/* -*- 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,17 +73,16 @@
 #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,74 +35,54 @@
  *
  * ***** 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 **script)
+                 nsIPrincipal *systemPrincipal, JSScript **scriptp)
 {
     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;
-    }
 
-    ::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;
+    JSScript *script = JS_DecodeScript(cx, buf, len, nsJSPrincipals::get(systemPrincipal), nsnull);
+    if (!script)
+        return NS_ERROR_OUT_OF_MEMORY;
+    *scriptp = script;
+    return NS_OK;
 }
 
 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));
 
-    JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE);
-    if (!xdr) {
+    uint32_t size;
+    void *data = JS_EncodeScript(cx, script, &size);
+    if (!data)
         return NS_ERROR_OUT_OF_MEMORY;
-    }
 
-    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);
+    MOZ_ASSERT(size);
+    nsresult rv = cache->PutBuffer(PromiseFlatCString(uri).get(), static_cast<char *>(data), size);
+    js_free(data);
     return rv;
 }
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -48,17 +48,16 @@
 
 #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"
@@ -2834,44 +2833,33 @@ WriteScriptOrFunction(nsIObjectOutputStr
     }
 
     if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) {
         rv = stream->WriteObject(originPrincipal, true);
         if (NS_FAILED(rv))
             return rv;
     }
 
-    JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_ENCODE);
-    if (!xdr)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    JSBool ok;
+    uint32_t size;
+    void* data;
     {
         JSAutoRequest ar(cx);
         if (functionObj)
-            ok = JS_XDRFunctionObject(xdr, &functionObj);
+            data = JS_EncodeInterpretedFunction(cx, functionObj, &size);
         else
-            ok = JS_XDRScript(xdr, &script);
+            data = JS_EncodeScript(cx, script, &size);
     }
 
-    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);
+    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);
 
     return rv;
 }
 
 static nsresult
 ReadScriptOrFunction(nsIObjectInputStream *stream, JSContext *cx,
                      JSScript **scriptp, JSObject **functionObjp)
 {
@@ -2906,41 +2894,36 @@ 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)
-            ok = JS_XDRScript(xdr, scriptp);
-        else
-            ok = JS_XDRFunctionObject(xdr, functionObjp);
+        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;
+        }
     }
 
-    // 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 ok ? NS_OK : NS_ERROR_FAILURE;
+    return rv;
 }
 
 NS_IMETHODIMP
 nsXPConnect::WriteScript(nsIObjectOutputStream *stream, JSContext *cx, JSScript *script)
 {
     return WriteScriptOrFunction(stream, cx, script, nsnull);
 }