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.

--HG--
rename : js/src/jsxdrapi.cpp => js/src/vm/Xdr.cpp
This commit is contained in:
Igor Bukanov 2012-02-20 11:58:00 +01:00
parent 4358625535
commit 5a94b9c481
37 changed files with 941 additions and 1189 deletions

View File

@ -44,7 +44,6 @@
#include "nsXPIDLString.h"
#include "nsCOMPtr.h"
#include "jsapi.h"
#include "jsxdrapi.h"
#include "nsIJSRuntimeService.h"
#include "nsIServiceManager.h"
#include "nsMemory.h"

View File

@ -60,7 +60,7 @@
#include "nsNetUtil.h"
#include "nsAppDirectoryServiceDefs.h"
#include "jsxdrapi.h"
#include "jsapi.h"
#include "mozilla/Preferences.h"
#include "mozilla/scache/StartupCache.h"

View File

@ -146,7 +146,6 @@ CPPSRCS = \
jswatchpoint.cpp \
jsweakmap.cpp \
jswrapper.cpp \
jsxdrapi.cpp \
jsxml.cpp \
prmjtime.cpp \
sharkctl.cpp \
@ -177,6 +176,7 @@ CPPSRCS = \
Statistics.cpp \
StringBuffer.cpp \
Unicode.cpp \
Xdr.cpp \
$(NULL)
# Changes to internal header files, used externally, massively slow down
@ -210,7 +210,6 @@ INSTALLED_HEADERS = \
jsutil.h \
jsversion.h \
jswrapper.h \
jsxdrapi.h \
jsval.h \
$(NULL)

View File

@ -822,7 +822,7 @@ EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *body);
* 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 {

View File

@ -146,11 +146,11 @@ MSG_DEF(JSMSG_NO_INPUT, 59, 5, JSEXN_SYNTAXERR, "no input for /{0
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")

View File

@ -3,7 +3,6 @@
*/
#include "tests.h"
#include "jsxdrapi.h"
/* Do the test a bunch of times, because sometimes we seem to randomly
miss the propcache */

View File

@ -5,9 +5,7 @@
*/
#include "tests.h"
#include "jsapi.h"
#include "jsdbgapi.h"
#include "jsxdrapi.h"
BEGIN_TEST(test_cloneScript)
{

View File

@ -3,7 +3,6 @@
*/
#include "tests.h"
#include "jsxdrapi.h"
static JSBool
native(JSContext *cx, unsigned argc, jsval *vp)

View File

@ -13,7 +13,6 @@
#include "jspubtd.h"
#include "jstypes.h"
#include "jsval.h"
#include "jsxdrapi.h"
#include "js/HashTable.h"
#include "js/MemoryMetrics.h"

View File

@ -3,7 +3,6 @@
*/
#include "tests.h"
#include "jsxdrapi.h"
static JSBool
nativeGet(JSContext *cx, JSObject *obj, jsid id, jsval *vp)

View File

@ -4,7 +4,6 @@
#include "tests.h"
#include "jsscript.h"
#include "jsxdrapi.h"
static JSScript *
CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
@ -28,44 +27,18 @@ CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JSObject *obj,
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;
}
@ -75,16 +48,21 @@ 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[] = {

View File

@ -82,6 +82,7 @@
#include "jsweakmap.h"
#include "jswrapper.h"
#include "jstypedarray.h"
#include "jsxml.h"
#include "ds/LifoAlloc.h"
#include "builtin/MapObject.h"
@ -90,10 +91,10 @@
#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"
@ -112,10 +113,6 @@
#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;
@ -6638,3 +6635,43 @@ AutoEnumStateRooter::~AutoEnumStateRooter()
}
} // 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;
}

View File

@ -5410,6 +5410,24 @@ 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___ */

View File

@ -68,6 +68,7 @@
#include "jsobjinlines.h"
#include "vm/String-inl.h"
#include "vm/Xdr.h"
using namespace mozilla;
using namespace js;
@ -657,3 +658,65 @@ js_InternNonIntElementIdSlow(JSContext *cx, JSObject *obj, const Value &idval,
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);

View File

@ -478,4 +478,12 @@ js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
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___ */

View File

@ -521,8 +521,8 @@ 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 */

View File

@ -52,7 +52,7 @@
#include "jsatom.h"
#include "jsbool.h"
#include "jscntxt.h"
#include "jsversion.h"
#include "jsexn.h"
#include "jsfun.h"
#include "jsgc.h"
#include "jsgcmark.h"
@ -66,7 +66,6 @@
#include "jsscope.h"
#include "jsscript.h"
#include "jsstr.h"
#include "jsexn.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/BytecodeEmitter.h"
@ -74,15 +73,12 @@
#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
@ -480,13 +476,10 @@ fun_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
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,
@ -494,9 +487,9 @@ js::XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
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;
@ -523,17 +516,17 @@ js::XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
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);
@ -549,7 +542,11 @@ js::XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
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

View File

@ -356,8 +356,9 @@ js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->a
namespace js {
extern JSBool
XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
template<XDRMode mode>
bool
XDRInterpretedFunction(XDRState<mode> *xdr, JSObject **objp, JSScript *parentScript);
} /* namespace js */

View File

@ -74,7 +74,7 @@
#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;
@ -84,7 +84,7 @@ typedef union jsdpun {
} s;
uint64_t u64;
double d;
} jsdpun;
};
static inline int
JSDOUBLE_IS_NaN(double d)

View File

@ -76,13 +76,15 @@
#include "json.h"
#include "jswatchpoint.h"
#include "jswrapper.h"
#include "jsxml.h"
#include "builtin/MapObject.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/BytecodeEmitter.h"
#include "frontend/Parser.h"
#include "vm/StringBuffer.h"
#include "js/MemoryMetrics.h"
#include "vm/StringBuffer.h"
#include "vm/Xdr.h"
#include "jsarrayinlines.h"
#include "jsatominlines.h"
@ -93,14 +95,6 @@
#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;

View File

@ -316,6 +316,14 @@ 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 {

View File

@ -1,4 +1,4 @@
/* -*- 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
@ -226,7 +226,6 @@ typedef struct JSStructuredCloneCallbacks JSStructuredCloneCallbacks;
typedef struct JSStructuredCloneReader JSStructuredCloneReader;
typedef struct JSStructuredCloneWriter JSStructuredCloneWriter;
typedef struct JSTracer JSTracer;
typedef struct JSXDRState JSXDRState;
#ifdef __cplusplus
class JSFlatString;
@ -234,7 +233,7 @@ class JSString;
#else
typedef struct JSFlatString JSFlatString;
typedef struct JSString JSString;
#endif
#endif /* !__cplusplus */
#ifdef JS_THREADSAFE
typedef struct PRCallOnceType JSCallOnceType;

View File

@ -62,9 +62,6 @@
#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"
@ -72,6 +69,7 @@
#include "methodjit/MethodJIT.h"
#include "methodjit/Retcon.h"
#include "vm/Debugger.h"
#include "vm/Xdr.h"
#include "jsinferinlines.h"
#include "jsinterpinlines.h"
@ -296,10 +294,11 @@ Bindings::trace(JSTracer *trc)
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
@ -317,7 +316,7 @@ XDRScriptConst(JSXDRState *xdr, HeapValue *vp)
};
uint32_t tag;
if (xdr->mode == JSXDR_ENCODE) {
if (mode == XDR_ENCODE) {
if (vp->isInt32()) {
tag = SCRIPT_INT;
} else if (vp->isDouble()) {
@ -336,54 +335,54 @@ XDRScriptConst(JSXDRState *xdr, HeapValue *vp)
}
}
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;
}
@ -393,8 +392,9 @@ XDRScriptConst(JSXDRState *xdr, HeapValue *vp)
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,
@ -404,7 +404,7 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
MayNeedArgsObj,
NeedsArgsObj,
OwnFilename,
SharedFilename
ParentFilename
};
uint32_t length, lineno, nslots;
@ -414,7 +414,7 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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;
@ -426,9 +426,10 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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));
@ -436,9 +437,9 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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;
}
@ -466,7 +467,7 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
}
Vector<JSAtom *> names(cx);
if (xdr->mode == JSXDR_ENCODE) {
if (mode == XDR_ENCODE) {
if (!script->bindings.getLocalNameArray(cx, &names))
return false;
PodZero(bitmap, bitmapLength);
@ -476,7 +477,7 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
}
}
for (unsigned i = 0; i < bitmapLength; ++i) {
if (!JS_XDRUint32(xdr, &bitmap[i]))
if (!xdr->codeUint32(&bitmap[i]))
return false;
}
@ -484,7 +485,7 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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;
@ -495,11 +496,11 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
}
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] &
@ -512,18 +513,18 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
}
}
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);
@ -569,44 +570,44 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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;
@ -637,7 +638,7 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
if (scriptBits & (1 << UsesEval))
script->usesEval = true;
if (scriptBits & (1 << MayNeedArgsObj)) {
script->mayNeedArgsObj_ = true;
script->setMayNeedArgsObj();
if (scriptBits & (1 << NeedsArgsObj))
script->setNeedsArgsObj(true);
} else {
@ -645,56 +646,41 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
}
}
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;
}
@ -707,16 +693,16 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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 {
@ -732,11 +718,11 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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;
}
@ -755,16 +741,16 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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);
}
@ -779,7 +765,7 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
}
}
if (xdr->mode == JSXDR_DECODE) {
if (mode == XDR_DECODE) {
if (cx->hasRunOption(JSOPTION_PCCOUNT))
(void) script->initCounts(cx);
*scriptp = script;
@ -788,9 +774,11 @@ XDRScript(JSXDRState *xdr, JSScript **scriptp)
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)
@ -844,8 +832,6 @@ JSScript::destroyCounts(JSContext *cx)
}
}
namespace js {
/*
* Shared script filename management.
*/
@ -924,8 +910,6 @@ FreeScriptFilenames(JSCompartment *comp)
table.clear();
}
} /* namespace js */
/*
* JSScript data structures memory alignment:
*
@ -1240,7 +1224,7 @@ JSScript::NewScriptFromEmitter(JSContext *cx, BytecodeEmitter *bce)
if (bce->inFunction()) {
bool needsArgsObj = bce->mayOverwriteArguments() || bce->needsEagerArguments();
if (needsArgsObj || bce->usesArguments()) {
script->mayNeedArgsObj_ = true;
script->setMayNeedArgsObj();
if (needsArgsObj)
script->setNeedsArgsObj(true);
}
@ -1626,74 +1610,32 @@ CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, unsigned *line
*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)
{

View File

@ -323,14 +323,6 @@ class DebugScript
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;
@ -356,8 +348,6 @@ struct JSScript : public js::gc::Cell
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
@ -445,6 +435,10 @@ struct JSScript : public js::gc::Cell
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 */
@ -890,6 +884,15 @@ CurrentScriptFileLineOrigin(JSContext *cx, unsigned *linenop, LineOption = NOT_C
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___ */

View File

@ -85,7 +85,6 @@
#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 */
@ -108,7 +107,6 @@
#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 */
@ -127,7 +125,6 @@
#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 */
@ -146,7 +143,6 @@
#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 */
@ -165,7 +161,6 @@
#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 */

View File

@ -1,589 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/Util.h"
#include "jsversion.h"
#if JS_HAS_XDR
#include <string.h>
#include "jstypes.h"
#include "jsutil.h"
#include "jsdhash.h"
#include "jsprf.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsnum.h"
#include "jsscript.h" /* js_XDRScript */
#include "jsstr.h"
#include "jsxdrapi.h"
#include "vm/Debugger.h"
#include "jsobjinlines.h"
using namespace mozilla;
using namespace js;
#ifdef DEBUG
#define DBG(x) x
#else
#define DBG(x) ((void)0)
#endif
typedef struct JSXDRMemState {
JSXDRState state;
char *base;
uint32_t count;
uint32_t limit;
} JSXDRMemState;
#define MEM_BLOCK 8192
#define MEM_PRIV(xdr) ((JSXDRMemState *)(xdr))
#define MEM_BASE(xdr) (MEM_PRIV(xdr)->base)
#define MEM_COUNT(xdr) (MEM_PRIV(xdr)->count)
#define MEM_LIMIT(xdr) (MEM_PRIV(xdr)->limit)
#define MEM_LEFT(xdr, bytes) \
JS_BEGIN_MACRO \
if ((xdr)->mode == JSXDR_DECODE && \
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \
JSMSG_END_OF_DATA); \
return 0; \
} \
JS_END_MACRO
#define MEM_NEED(xdr, bytes) \
JS_BEGIN_MACRO \
if ((xdr)->mode == JSXDR_ENCODE) { \
if (MEM_LIMIT(xdr) && \
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
uint32_t limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\
void *data_ = (xdr)->cx->realloc_(MEM_BASE(xdr), limit_); \
if (!data_) \
return 0; \
MEM_BASE(xdr) = (char *) data_; \
MEM_LIMIT(xdr) = limit_; \
} \
} else { \
MEM_LEFT(xdr, bytes); \
} \
JS_END_MACRO
#define MEM_DATA(xdr) ((void *)(MEM_BASE(xdr) + MEM_COUNT(xdr)))
#define MEM_INCR(xdr,bytes) (MEM_COUNT(xdr) += (bytes))
static JSBool
mem_get32(JSXDRState *xdr, uint32_t *lp)
{
MEM_LEFT(xdr, 4);
*lp = *(uint32_t *)MEM_DATA(xdr);
MEM_INCR(xdr, 4);
return JS_TRUE;
}
static JSBool
mem_set32(JSXDRState *xdr, uint32_t *lp)
{
MEM_NEED(xdr, 4);
*(uint32_t *)MEM_DATA(xdr) = *lp;
MEM_INCR(xdr, 4);
return JS_TRUE;
}
static JSBool
mem_getbytes(JSXDRState *xdr, char *bytes, uint32_t len)
{
MEM_LEFT(xdr, len);
js_memcpy(bytes, MEM_DATA(xdr), len);
MEM_INCR(xdr, len);
return JS_TRUE;
}
static JSBool
mem_setbytes(JSXDRState *xdr, char *bytes, uint32_t len)
{
MEM_NEED(xdr, len);
js_memcpy(MEM_DATA(xdr), bytes, len);
MEM_INCR(xdr, len);
return JS_TRUE;
}
static void *
mem_raw(JSXDRState *xdr, uint32_t len)
{
void *data;
if (xdr->mode == JSXDR_ENCODE) {
MEM_NEED(xdr, len);
} else if (xdr->mode == JSXDR_DECODE) {
MEM_LEFT(xdr, len);
}
data = MEM_DATA(xdr);
MEM_INCR(xdr, len);
return data;
}
static JSBool
mem_seek(JSXDRState *xdr, int32_t offset, JSXDRWhence whence)
{
switch (whence) {
case JSXDR_SEEK_CUR:
if ((int32_t)MEM_COUNT(xdr) + offset < 0) {
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
JSMSG_SEEK_BEYOND_START);
return JS_FALSE;
}
if (offset > 0)
MEM_NEED(xdr, offset);
MEM_COUNT(xdr) += offset;
return JS_TRUE;
case JSXDR_SEEK_SET:
if (offset < 0) {
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
JSMSG_SEEK_BEYOND_START);
return JS_FALSE;
}
if (xdr->mode == JSXDR_ENCODE) {
if ((uint32_t)offset > MEM_COUNT(xdr))
MEM_NEED(xdr, offset - MEM_COUNT(xdr));
MEM_COUNT(xdr) = offset;
} else {
if ((uint32_t)offset > MEM_LIMIT(xdr)) {
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
JSMSG_SEEK_BEYOND_END);
return JS_FALSE;
}
MEM_COUNT(xdr) = offset;
}
return JS_TRUE;
case JSXDR_SEEK_END:
if (offset >= 0 ||
xdr->mode == JSXDR_ENCODE ||
(int32_t)MEM_LIMIT(xdr) + offset < 0) {
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
JSMSG_END_SEEK);
return JS_FALSE;
}
MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset;
return JS_TRUE;
default: {
char numBuf[12];
JS_snprintf(numBuf, sizeof numBuf, "%d", whence);
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
JSMSG_WHITHER_WHENCE, numBuf);
return JS_FALSE;
}
}
}
static uint32_t
mem_tell(JSXDRState *xdr)
{
return MEM_COUNT(xdr);
}
static void
mem_finalize(JSXDRState *xdr)
{
xdr->cx->free_(MEM_BASE(xdr));
}
static JSXDROps xdrmem_ops = {
mem_get32, mem_set32, mem_getbytes, mem_setbytes,
mem_raw, mem_seek, mem_tell, mem_finalize
};
JS_PUBLIC_API(void)
JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx)
{
xdr->mode = mode;
xdr->cx = cx;
xdr->sharedFilename = NULL;
xdr->principals = NULL;
xdr->originPrincipals = NULL;
}
JS_PUBLIC_API(JSXDRState *)
JS_XDRNewMem(JSContext *cx, JSXDRMode mode)
{
JSXDRState *xdr = (JSXDRState *) cx->malloc_(sizeof(JSXDRMemState));
if (!xdr)
return NULL;
JS_XDRInitBase(xdr, mode, cx);
if (mode == JSXDR_ENCODE) {
if (!(MEM_BASE(xdr) = (char *) cx->malloc_(MEM_BLOCK))) {
cx->free_(xdr);
return NULL;
}
} else {
/* XXXbe ok, so better not deref MEM_BASE(xdr) if not ENCODE */
MEM_BASE(xdr) = NULL;
}
xdr->ops = &xdrmem_ops;
MEM_COUNT(xdr) = 0;
MEM_LIMIT(xdr) = MEM_BLOCK;
return xdr;
}
JS_PUBLIC_API(void *)
JS_XDRMemGetData(JSXDRState *xdr, uint32_t *lp)
{
if (xdr->ops != &xdrmem_ops)
return NULL;
*lp = MEM_COUNT(xdr);
return MEM_BASE(xdr);
}
JS_PUBLIC_API(void)
JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32_t len)
{
if (xdr->ops != &xdrmem_ops)
return;
MEM_LIMIT(xdr) = len;
MEM_BASE(xdr) = (char *) data;
MEM_COUNT(xdr) = 0;
}
JS_PUBLIC_API(uint32_t)
JS_XDRMemDataLeft(JSXDRState *xdr)
{
if (xdr->ops != &xdrmem_ops)
return 0;
return MEM_LIMIT(xdr) - MEM_COUNT(xdr);
}
JS_PUBLIC_API(void)
JS_XDRMemResetData(JSXDRState *xdr)
{
if (xdr->ops != &xdrmem_ops)
return;
MEM_COUNT(xdr) = 0;
}
JS_PUBLIC_API(void)
JS_XDRDestroy(JSXDRState *xdr)
{
JSContext *cx = xdr->cx;
xdr->ops->finalize(xdr);
cx->free_(xdr);
}
JS_PUBLIC_API(void)
JS_XDRSetPrincipals(JSXDRState *xdr, JSPrincipals *principals, JSPrincipals *originPrincipals)
{
JS_ASSERT(xdr->mode == JSXDR_DECODE);
xdr->principals = principals;
xdr->originPrincipals = JSScript::normalizeOriginPrincipals(principals, originPrincipals);
}
JS_PUBLIC_API(JSBool)
JS_XDRUint8(JSXDRState *xdr, uint8_t *b)
{
uint32_t l = *b;
if (!JS_XDRUint32(xdr, &l))
return JS_FALSE;
*b = (uint8_t) l;
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)
JS_XDRUint16(JSXDRState *xdr, uint16_t *s)
{
uint32_t l = *s;
if (!JS_XDRUint32(xdr, &l))
return JS_FALSE;
*s = (uint16_t) l;
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)
JS_XDRUint32(JSXDRState *xdr, uint32_t *lp)
{
JSBool ok = JS_TRUE;
if (xdr->mode == JSXDR_ENCODE) {
uint32_t xl = JSXDR_SWAB32(*lp);
ok = xdr->ops->set32(xdr, &xl);
} else if (xdr->mode == JSXDR_DECODE) {
ok = xdr->ops->get32(xdr, lp);
*lp = JSXDR_SWAB32(*lp);
}
return ok;
}
JS_PUBLIC_API(JSBool)
JS_XDRBytes(JSXDRState *xdr, char *bytes, uint32_t len)
{
uint32_t padlen;
static char padbuf[JSXDR_ALIGN-1];
if (xdr->mode == JSXDR_ENCODE) {
if (!xdr->ops->setbytes(xdr, bytes, len))
return JS_FALSE;
} else {
if (!xdr->ops->getbytes(xdr, bytes, len))
return JS_FALSE;
}
len = xdr->ops->tell(xdr);
if (len % JSXDR_ALIGN) {
padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN);
if (xdr->mode == JSXDR_ENCODE) {
if (!xdr->ops->setbytes(xdr, padbuf, padlen))
return JS_FALSE;
} else {
if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR))
return JS_FALSE;
}
}
return JS_TRUE;
}
/**
* Convert between a C string and the XDR representation:
* leading 32-bit count, then counted vector of chars,
* then possibly \0 padding to multiple of 4.
*/
JS_PUBLIC_API(JSBool)
JS_XDRCString(JSXDRState *xdr, char **sp)
{
uint32_t len;
if (xdr->mode == JSXDR_ENCODE)
len = strlen(*sp);
JS_XDRUint32(xdr, &len);
if (xdr->mode == JSXDR_DECODE) {
if (!(*sp = (char *) xdr->cx->malloc_(len + 1)))
return JS_FALSE;
}
if (!JS_XDRBytes(xdr, *sp, len)) {
if (xdr->mode == JSXDR_DECODE)
xdr->cx->free_(*sp);
return JS_FALSE;
}
if (xdr->mode == JSXDR_DECODE) {
(*sp)[len] = '\0';
}
return JS_TRUE;
}
static JSBool
XDRChars(JSXDRState *xdr, jschar *chars, uint32_t nchars)
{
uint32_t i, padlen, nbytes;
jschar *raw;
nbytes = nchars * sizeof(jschar);
padlen = nbytes % JSXDR_ALIGN;
if (padlen) {
padlen = JSXDR_ALIGN - padlen;
nbytes += padlen;
}
if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes)))
return JS_FALSE;
if (xdr->mode == JSXDR_ENCODE) {
for (i = 0; i != nchars; i++)
raw[i] = JSXDR_SWAB16(chars[i]);
if (padlen)
memset((char *)raw + nbytes - padlen, 0, padlen);
} else if (xdr->mode == JSXDR_DECODE) {
for (i = 0; i != nchars; i++)
chars[i] = JSXDR_SWAB16(raw[i]);
}
return JS_TRUE;
}
/*
* Convert between a JS (Unicode) string and the XDR representation.
*/
JS_PUBLIC_API(JSBool)
JS_XDRString(JSXDRState *xdr, JSString **strp)
{
uint32_t nchars;
jschar *chars;
if (xdr->mode == JSXDR_ENCODE)
nchars = (*strp)->length();
if (!JS_XDRUint32(xdr, &nchars))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE)
chars = (jschar *) xdr->cx->malloc_((nchars + 1) * sizeof(jschar));
else
chars = const_cast<jschar *>((*strp)->getChars(xdr->cx));
if (!chars)
return JS_FALSE;
if (!XDRChars(xdr, chars, nchars))
goto bad;
if (xdr->mode == JSXDR_DECODE) {
chars[nchars] = 0;
*strp = JS_NewUCString(xdr->cx, chars, nchars);
if (!*strp)
goto bad;
}
return JS_TRUE;
bad:
if (xdr->mode == JSXDR_DECODE)
xdr->cx->free_(chars);
return JS_FALSE;
}
JS_PUBLIC_API(JSBool)
JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp)
{
uint32_t null = (*strp == NULL);
if (!JS_XDRUint32(xdr, &null))
return JS_FALSE;
if (null) {
*strp = NULL;
return JS_TRUE;
}
return JS_XDRString(xdr, strp);
}
JS_PUBLIC_API(JSBool)
JS_XDRDouble(JSXDRState *xdr, double *dp)
{
jsdpun u;
u.d = (xdr->mode == JSXDR_ENCODE) ? *dp : 0.0;
if (!JS_XDRUint32(xdr, &u.s.lo) || !JS_XDRUint32(xdr, &u.s.hi))
return false;
if (xdr->mode == JSXDR_DECODE)
*dp = u.d;
return true;
}
extern JSBool
js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
{
JSString *str;
uint32_t nchars;
JSAtom *atom;
JSContext *cx;
jschar *chars;
jschar stackChars[256];
if (xdr->mode == JSXDR_ENCODE) {
str = *atomp;
return JS_XDRString(xdr, &str);
}
/*
* Inline JS_XDRString when decoding to avoid JSString allocation
* for already existing atoms. See bug 321985.
*/
if (!JS_XDRUint32(xdr, &nchars))
return JS_FALSE;
atom = NULL;
cx = xdr->cx;
if (nchars <= ArrayLength(stackChars)) {
chars = stackChars;
} else {
/*
* This is very uncommon. Don't use the tempLifoAlloc arena for this as
* most allocations here will be bigger than tempLifoAlloc's default
* chunk size.
*/
chars = (jschar *) cx->malloc_(nchars * sizeof(jschar));
if (!chars)
return JS_FALSE;
}
if (XDRChars(xdr, chars, nchars))
atom = js_AtomizeChars(cx, chars, nchars);
if (chars != stackChars)
cx->free_(chars);
if (!atom)
return JS_FALSE;
*atomp = atom;
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)
JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
{
return XDRFunctionObject(xdr, objp);
}
JS_PUBLIC_API(JSBool)
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
{
JSScript *script;
uint32_t magic;
uint32_t bytecodeVer;
if (xdr->mode == JSXDR_DECODE) {
script = NULL;
*scriptp = NULL;
} else {
script = *scriptp;
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
bytecodeVer = JSXDR_BYTECODE_VERSION;
}
if (!JS_XDRUint32(xdr, &magic))
return false;
if (!JS_XDRUint32(xdr, &bytecodeVer))
return false;
if (magic != JSXDR_MAGIC_SCRIPT_CURRENT ||
bytecodeVer != JSXDR_BYTECODE_VERSION) {
/* We do not provide binary compatibility with older scripts. */
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, JSMSG_BAD_SCRIPT_MAGIC);
return false;
}
if (!XDRScript(xdr, &script))
return false;
if (xdr->mode == JSXDR_DECODE) {
JS_ASSERT(!script->compileAndGo);
script->globalObject = GetCurrentGlobal(xdr->cx);
js_CallNewScriptHook(xdr->cx, script, NULL);
Debugger::onNewScript(xdr->cx, script, NULL);
*scriptp = script;
}
return true;
}
#endif /* JS_HAS_XDR */

View File

@ -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___ */

View File

@ -45,6 +45,7 @@
#include "vm/GlobalObject.h"
#include "vm/MethodGuard.h"
#include "vm/Stack.h"
#include "vm/Xdr.h"
#include "jsobjinlines.h"

View File

@ -42,6 +42,7 @@
#include "vm/MatchPairs.h"
#include "vm/RegExpStatics.h"
#include "vm/StringBuffer.h"
#include "vm/Xdr.h"
#include "jsobjinlines.h"
@ -746,36 +747,38 @@ js::ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut)
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);

View File

@ -469,8 +469,9 @@ ParseRegExpFlags(JSContext *cx, JSString *flagStr, RegExpFlag *flagsOut);
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 */

View File

@ -42,12 +42,10 @@
#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"
@ -936,8 +934,6 @@ Class js::BlockClass = {
JS_ConvertStub
};
#if JS_HAS_XDR
#define NO_PARENT_INDEX UINT32_MAX
static uint32_t
@ -957,16 +953,17 @@ FindObjectIndex(JSObjectArray *array, JSObject *obj)
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())
@ -979,10 +976,10 @@ js::XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **
}
/* 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;
@ -1000,10 +997,10 @@ js::XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **
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);
@ -1014,7 +1011,7 @@ js::XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **
*/
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. */
@ -1054,11 +1051,15 @@ js::XDRStaticBlockObject(JSXDRState *xdr, JSScript *script, StaticBlockObject **
? 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);

View File

@ -276,8 +276,9 @@ class ClonedBlockObject : public BlockObject
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 */

239
js/src/vm/Xdr.cpp Normal file
View File

@ -0,0 +1,239 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/Util.h"
#include "jsversion.h"
#include <string.h>
#include "jstypes.h"
#include "jsutil.h"
#include "jsdhash.h"
#include "jsprf.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsnum.h"
#include "jsscript.h"
#include "jsstr.h"
#include "Xdr.h"
#include "Debugger.h"
#include "jsobjinlines.h"
using namespace mozilla;
using namespace js;
namespace js {
void
XDRBuffer::freeBuffer()
{
Foreground::free_(base);
#ifdef DEBUG
memset(this, 0xe2, sizeof *this);
#endif
}
bool
XDRBuffer::grow(size_t n)
{
JS_ASSERT(n > size_t(limit - cursor));
const size_t MEM_BLOCK = 8192;
size_t offset = cursor - base;
size_t newCapacity = JS_ROUNDUP(offset + n, MEM_BLOCK);
if (isUint32Overflow(newCapacity)) {
JS_ReportErrorNumber(cx(), js_GetErrorMessage, NULL, JSMSG_TOO_BIG_TO_ENCODE);
return false;
}
void *data = OffTheBooks::realloc_(base, newCapacity);
if (!data) {
js_ReportOutOfMemory(cx());
return false;
}
base = static_cast<uint8_t *>(data);
cursor = base + offset;
limit = base + newCapacity;
return true;
}
template<XDRMode mode>
bool
XDRState<mode>::codeChars(jschar *chars, size_t nchars)
{
size_t nbytes = nchars * sizeof(jschar);
if (mode == XDR_ENCODE) {
uint8_t *ptr = buf.write(nbytes);
if (!ptr)
return false;
#ifdef IS_LITTLE_ENDIAN
memcpy(ptr, chars, nbytes);
#else
for (size_t i = 0; i != nchars; i++) {
uint16_t tmp = NormalizeByteOrder16(chars[i]);
memcpy(ptr, &tmp, sizeof tmp);
ptr += sizeof tmp;
}
#endif
} else {
const uint8_t *ptr = buf.read(nbytes);
#ifdef IS_LITTLE_ENDIAN
memcpy(chars, ptr, nbytes);
#else
for (size_t i = 0; i != nchars; i++) {
uint16_t tmp;
memcpy(&tmp, ptr, sizeof tmp);
chars[i] = NormalizeByteOrder16(tmp);
ptr += sizeof tmp;
}
#endif
}
return true;
}
/*
* Convert between a JS (Unicode) string and the XDR representation.
*/
template<XDRMode mode>
bool
XDRState<mode>::codeString(JSString **strp)
{
uint32_t nchars;
jschar *chars;
if (mode == XDR_ENCODE)
nchars = (*strp)->length();
if (!codeUint32(&nchars))
return false;
if (mode == XDR_DECODE)
chars = (jschar *) cx()->malloc_((nchars + 1) * sizeof(jschar));
else
chars = const_cast<jschar *>((*strp)->getChars(cx()));
if (!chars)
return false;
if (!codeChars(chars, nchars))
goto bad;
if (mode == XDR_DECODE) {
chars[nchars] = 0;
*strp = JS_NewUCString(cx(), chars, nchars);
if (!*strp)
goto bad;
}
return true;
bad:
if (mode == XDR_DECODE)
Foreground::free_(chars);
return false;
}
template<XDRMode mode>
static bool
VersionCheck(XDRState<mode> *xdr)
{
uint32_t bytecodeVer;
if (mode == XDR_ENCODE)
bytecodeVer = XDR_BYTECODE_VERSION;
if (!xdr->codeUint32(&bytecodeVer))
return false;
if (mode == XDR_DECODE && bytecodeVer != XDR_BYTECODE_VERSION) {
/* We do not provide binary compatibility with older scripts. */
JS_ReportErrorNumber(xdr->cx(), js_GetErrorMessage, NULL, JSMSG_BAD_SCRIPT_MAGIC);
return false;
}
return true;
}
template<XDRMode mode>
bool
XDRState<mode>::codeFunction(JSObject **objp)
{
if (mode == XDR_DECODE)
*objp = NULL;
return VersionCheck(this) && XDRInterpretedFunction(this, objp, NULL);
}
template<XDRMode mode>
bool
XDRState<mode>::codeScript(JSScript **scriptp)
{
JSScript *script;
if (mode == XDR_DECODE) {
script = NULL;
*scriptp = NULL;
} else {
script = *scriptp;
}
if (!VersionCheck(this) || !XDRScript(this, &script, NULL))
return false;
if (mode == XDR_DECODE) {
JS_ASSERT(!script->compileAndGo);
script->globalObject = GetCurrentGlobal(cx());
js_CallNewScriptHook(cx(), script, NULL);
Debugger::onNewScript(cx(), script, NULL);
*scriptp = script;
}
return true;
}
XDRDecoder::XDRDecoder(JSContext *cx, const void *data, uint32_t length,
JSPrincipals *principals, JSPrincipals *originPrincipals)
: XDRState<XDR_DECODE>(cx)
{
buf.setData(data, length);
this->principals = principals;
this->originPrincipals = JSScript::normalizeOriginPrincipals(principals, originPrincipals);
}
template class XDRState<XDR_ENCODE>;
template class XDRState<XDR_DECODE>;
} /* namespace js */

322
js/src/vm/Xdr.h Normal file
View File

@ -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___ */

View File

@ -78,7 +78,6 @@
#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

View File

@ -40,7 +40,6 @@
#include "jsapi.h"
#include "jsdbgapi.h"
#include "jsxdrapi.h"
#include "nsJSPrincipals.h"
@ -54,31 +53,20 @@ using namespace mozilla::scache;
// 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) {
JSScript *script = JS_DecodeScript(cx, buf, len, nsJSPrincipals::get(systemPrincipal), nsnull);
if (!script)
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;
*scriptp = script;
return NS_OK;
}
nsresult
@ -88,21 +76,13 @@ WriteCachedScript(StartupCache* cache, nsACString &uri, JSContext *cx,
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;
}

View File

@ -53,7 +53,6 @@
#include "jsatom.h"
#include "jsfriendapi.h"
#include "jsgc.h"
#include "jsxdrapi.h"
#include "dom_quickstubs.h"
#include "nsNullPrincipal.h"
#include "nsIURI.h"
@ -2839,34 +2838,23 @@ WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx,
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;
}
@ -2911,31 +2899,26 @@ ReadScriptOrFunction(nsIObjectInputStream *stream, JSContext *cx,
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