mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
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:
parent
01a1c4d2d2
commit
63cd1dc8b0
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
|
@ -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 */
|
||||
|
@ -5,9 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "jsxdrapi.h"
|
||||
|
||||
BEGIN_TEST(test_cloneScript)
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include "jsxdrapi.h"
|
||||
|
||||
static JSBool
|
||||
native(JSContext *cx, unsigned argc, jsval *vp)
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "jspubtd.h"
|
||||
#include "jstypes.h"
|
||||
#include "jsval.h"
|
||||
#include "jsxdrapi.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
|
@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include "jsxdrapi.h"
|
||||
|
||||
static JSBool
|
||||
nativeGet(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
|
@ -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[] = {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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___ */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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___ */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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___ */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
@ -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___ */
|
@ -45,6 +45,7 @@
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/MethodGuard.h"
|
||||
#include "vm/Stack.h"
|
||||
#include "vm/Xdr.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
239
js/src/vm/Xdr.cpp
Normal 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
322
js/src/vm/Xdr.h
Normal 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___ */
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user