Don't build a stack frame to execute empty scripts (516827, r=igor).

This commit is contained in:
Brendan Eich 2009-10-18 17:41:24 -07:00
Родитель 515b46d86c
Коммит 7bbe5bcd01
16 изменённых файлов: 287 добавлений и 42 удалений

Просмотреть файл

@ -53,3 +53,40 @@ BEGIN_TEST(testXDR_bug506491)
return true;
}
END_TEST(testXDR_bug506491)
BEGIN_TEST(testXDR_bug516827)
{
// compile an empty script
JSScript *script = JS_CompileScript(cx, global, "", 0, __FILE__, __LINE__);
CHECK(script);
JSObject *scrobj = JS_NewScriptObject(cx, script);
CHECK(scrobj);
jsvalRoot v(cx, OBJECT_TO_JSVAL(scrobj));
// freeze
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
CHECK(w);
CHECK(JS_XDRScript(w, &script));
uint32 nbytes;
void *p = JS_XDRMemGetData(w, &nbytes);
CHECK(p);
void *frozen = malloc(nbytes);
CHECK(frozen);
memcpy(frozen, p, nbytes);
JS_XDRDestroy(w);
// thaw
script = NULL;
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
JS_XDRMemSetData(r, frozen, nbytes);
CHECK(JS_XDRScript(r, &script));
JS_XDRDestroy(r); // this frees `frozen`
scrobj = JS_NewScriptObject(cx, script);
CHECK(scrobj);
v = OBJECT_TO_JSVAL(scrobj);
// execute with null result meaning no result wanted
CHECK(JS_ExecuteScript(cx, global, script, NULL));
return true;
}
END_TEST(testXDR_bug516827)

Просмотреть файл

@ -4612,7 +4612,7 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
JSScript *script;
CHECK_REQUEST(cx);
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
script = JSCompiler::compileScript(cx, obj, NULL, principals, tcflags,
chars, length, NULL, filename, lineno);
LAST_FRAME_CHECKS(cx, script);

Просмотреть файл

@ -745,6 +745,12 @@ struct JSRuntime {
double lengthSquaredSum;
double strdepLengthSum;
double strdepLengthSquaredSum;
/* Script instrumentation. */
jsrefcount liveScripts;
jsrefcount totalScripts;
jsrefcount liveEmptyScripts;
jsrefcount totalEmptyScripts;
#endif /* DEBUG || JS_DUMP_PROPTREE_STATS */
#ifdef JS_SCOPE_DEPTH_METER

Просмотреть файл

@ -144,6 +144,12 @@ JS_SetTrap(JSContext *cx, JSScript *script, jsbytecode *pc,
JSRuntime *rt;
uint32 sample;
if (script == JSScript::emptyScript()) {
JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
NULL, JSMSG_READ_ONLY, "empty script");
return JS_FALSE;
}
JS_ASSERT((JSOp) *pc != JSOP_TRAP);
junk = NULL;
rt = cx->runtime;

Просмотреть файл

@ -272,7 +272,15 @@ struct JSTreeContext { /* tree context for semantic checks */
* between assignment-like and declaration-like destructuring
* patterns, and why they need to be treated differently.
*/
#define TCF_DECL_DESTRUCTURING 0x10000
#define TCF_DECL_DESTRUCTURING 0x10000
/*
* A request flag passed to JSCompiler::compileScript and then down via
* JSCodeGenerator to js_NewScriptFromCG, from script_compile_sub and any
* kindred functions that need to make mutable scripts (even empty ones;
* i.e., they can't share the const JSScript::emptyScript() singleton).
*/
#define TCF_NEED_MUTABLE_SCRIPT 0x20000
/*
* Sticky deoptimization flags to propagate from FunctionBody.

Просмотреть файл

@ -1668,15 +1668,17 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp)
js_FreezeLocalNames(cx, fun);
}
if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
if (!js_XDRScript(xdr, &fun->u.i.script, false, NULL))
goto bad;
if (xdr->mode == JSXDR_DECODE) {
*objp = FUN_OBJECT(fun);
if (fun->u.i.script != JSScript::emptyScript()) {
#ifdef CHECK_SCRIPT_OWNER
fun->u.i.script->owner = NULL;
fun->u.i.script->owner = NULL;
#endif
js_CallNewScriptHook(cx, fun->u.i.script, fun);
js_CallNewScriptHook(cx, fun->u.i.script, fun);
}
}
out:
@ -2352,14 +2354,7 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj)
fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
if (!fun)
return NULL;
fun->u.i.script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0);
if (!fun->u.i.script)
return NULL;
fun->u.i.script->code[0] = JSOP_STOP;
*fun->u.i.script->notes() = SRC_NULL;
#ifdef CHECK_SCRIPT_OWNER
fun->u.i.script->owner = NULL;
#endif
fun->u.i.script = JSScript::emptyScript();
return proto;
}

Просмотреть файл

@ -1185,6 +1185,17 @@ have_fun:
native = NULL;
script = fun->u.i.script;
JS_ASSERT(script);
if (script->isEmpty()) {
if (flags & JSINVOKE_CONSTRUCT) {
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
*vp = vp[1];
} else {
*vp = JSVAL_VOID;
}
ok = JS_TRUE;
goto out2;
}
} else {
native = fun->u.n.native;
script = NULL;
@ -1474,6 +1485,12 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
JSObject *obj, *tmp;
JSBool ok;
if (script->isEmpty()) {
if (result)
*result = JSVAL_VOID;
return JS_TRUE;
}
js_LeaveTrace(cx);
#ifdef INCLUDE_MOZILLA_DTRACE
@ -2795,7 +2812,8 @@ js_Interpret(JSContext *cx)
/* Set registerized frame pointer and derived script pointer. */
fp = cx->fp;
script = fp->script;
JS_ASSERT(script->length != 0);
JS_ASSERT(!script->isEmpty());
JS_ASSERT(script->length > 1);
/* Count of JS function calls that nest in this C js_Interpret frame. */
inlineCallCount = 0;

Просмотреть файл

@ -1426,8 +1426,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* Get the prior (cache-filling) eval's saved caller function.
* See JSCompiler::compileScript in jsparse.cpp.
*/
JSFunction *fun;
fun = script->getFunction(0);
JSFunction *fun = script->getFunction(0);
if (fun == caller->fun) {
/*
@ -1446,6 +1445,7 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
*/
JSObjectArray *objarray = script->objects();
int i = 1;
if (objarray->length == 1) {
if (script->regexpsOffset != 0) {
objarray = script->regexps();
@ -1483,7 +1483,8 @@ obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
callerFrame = (staticLevel != 0) ? caller : NULL;
if (!script) {
script = JSCompiler::compileScript(cx, scopeobj, callerFrame,
principals, TCF_COMPILE_N_GO,
principals,
TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT,
str->chars(), str->length(),
NULL, file, line, str, staticLevel);
if (!script) {

Просмотреть файл

@ -2028,12 +2028,17 @@ BEGIN_CASE(JSOP_NEW)
}
rval = vp[1];
obj2 = js_NewObject(cx, &js_ObjectClass,
JSVAL_IS_OBJECT(rval)
? JSVAL_TO_OBJECT(rval)
: NULL,
JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL,
OBJ_GET_PARENT(cx, obj));
if (!obj2)
goto error;
if (fun->u.i.script->isEmpty()) {
*vp = OBJECT_TO_JSVAL(obj2);
regs.sp = vp + 1;
goto end_new;
}
vp[1] = OBJECT_TO_JSVAL(obj2);
flags = JSFRAME_CONSTRUCTING;
goto inline_call;
@ -2045,6 +2050,8 @@ BEGIN_CASE(JSOP_NEW)
regs.sp = vp + 1;
CHECK_INTERRUPT_HANDLER();
TRACE_0(NativeCallComplete);
end_new:
END_CASE(JSOP_NEW)
BEGIN_CASE(JSOP_CALL)
@ -2071,6 +2078,14 @@ BEGIN_CASE(JSOP_APPLY)
JSInlineFrame *newifp;
JSInterpreterHook hook;
script = fun->u.i.script;
if (script->isEmpty()) {
script = fp->script;
*vp = JSVAL_VOID;
regs.sp = vp + 1;
goto end_call;
}
/* Restrict recursion of lightweight functions. */
if (inlineCallCount >= JS_MAX_INLINE_CALL_COUNT) {
js_ReportOverRecursed(cx);
@ -2078,9 +2093,7 @@ BEGIN_CASE(JSOP_APPLY)
}
/* Compute the total number of stack slots needed by fun. */
nframeslots = JS_HOWMANY(sizeof(JSInlineFrame),
sizeof(jsval));
script = fun->u.i.script;
nframeslots = JS_HOWMANY(sizeof(JSInlineFrame), sizeof(jsval));
atoms = script->atomMap.vector;
nbytes = (nframeslots + script->nslots) * sizeof(jsval);

Просмотреть файл

@ -801,7 +801,7 @@ JSCompiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *cal
void *sbrk(ptrdiff_t), *before = sbrk(0);
#endif
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL)));
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_NEED_MUTABLE_SCRIPT)));
/*
* The scripted callerFrame can only be given for compile-and-go scripts

Просмотреть файл

@ -207,7 +207,6 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
const char *file;
uintN line;
JSPrincipals *principals;
uint32 tcflags;
jsint execDepth;
/* Make sure obj is a Script object. */
@ -263,8 +262,8 @@ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
* match the compile-time. TCF_COMPILE_N_GO is tested in jsemit.c and
* jsparse.c to optimize based on identity of run- and compile-time scope.
*/
tcflags = 0;
script = JSCompiler::compileScript(cx, scopeobj, NULL, principals, tcflags,
script = JSCompiler::compileScript(cx, scopeobj, NULL, principals,
TCF_NEED_MUTABLE_SCRIPT,
str->chars(), str->length(),
NULL, file, line);
if (!script)
@ -408,10 +407,20 @@ script_exec(JSContext *cx, uintN argc, jsval *vp)
#endif /* JS_HAS_SCRIPT_OBJECT */
static const jsbytecode emptyScriptCode[] = {JSOP_STOP, SRC_NULL};
/* static */ const JSScript JSScript::emptyScriptConst = {
const_cast<jsbytecode*>(emptyScriptCode),
1, JSVERSION_DEFAULT, 0, 0, 0, 0, 0, 1, 0, 0,
const_cast<jsbytecode*>(emptyScriptCode),
{0, NULL}, NULL, 0, 0, 0, NULL
};
#if JS_HAS_XDR
JSBool
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
JSBool *hasMagic)
{
JSContext *cx;
JSScript *script, *oldscript;
@ -450,8 +459,32 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
if (hasMagic)
*hasMagic = JS_TRUE;
/*
* Since the shortest possible script has JSOP_STOP as its only bytecode,
* encode only the length 1 for the emptyScript singleton, and return the
* emptyScript instead of a new script when decoding a script of length 1.
*/
if (xdr->mode == JSXDR_ENCODE)
length = (script == JSScript::emptyScript()) ? 1 : script->length;
if (!JS_XDRUint32(xdr, &length))
return JS_FALSE;
JS_ASSERT(length != 0);
if (length == 1) {
if (xdr->mode == JSXDR_ENCODE) {
JS_ASSERT(*scriptp == JSScript::emptyScript());
return JS_TRUE;
}
/* Decoding: check whether we need a mutable empty script. */
if (cx->debugHooks->newScriptHook)
needMutableScript = true;
if (!needMutableScript) {
*scriptp = JSScript::emptyScript();
return JS_TRUE;
}
}
if (xdr->mode == JSXDR_ENCODE) {
length = script->length;
prologLength = script->main - script->code;
JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);
version = (uint32)script->version | (script->nfixed << 16);
@ -477,8 +510,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
ntrynotes = script->trynotes()->length;
}
if (!JS_XDRUint32(xdr, &length))
return JS_FALSE;
if (!JS_XDRUint32(xdr, &prologLength))
return JS_FALSE;
if (!JS_XDRUint32(xdr, &version))
@ -604,7 +635,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
JS_ASSERT(clasp == &js_FunctionClass ||
clasp == &js_BlockClass);
isBlock = (clasp == &js_BlockClass) ? 1 : 0;
}
}
if (!JS_XDRUint32(xdr, &isBlock))
goto error;
if (isBlock == 0) {
@ -706,7 +737,7 @@ script_freeze(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
/* write */
ok = js_XDRScript(xdr, &script, &hasMagic);
ok = js_XDRScript(xdr, &script, false, &hasMagic);
if (!ok)
goto out;
if (!hasMagic) {
@ -797,7 +828,7 @@ script_thaw(JSContext *cx, uintN argc, jsval *vp)
JS_XDRMemSetData(xdr, buf, len);
/* XXXbe should magic mismatch be error, or false return value? */
ok = js_XDRScript(xdr, &script, &hasMagic);
ok = js_XDRScript(xdr, &script, true, &hasMagic);
if (!ok)
goto out;
if (!hasMagic) {
@ -1369,6 +1400,16 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
JSScript *script;
uint8 *cursor;
if (length == 1) {
JS_ASSERT(nsrcnotes == 1);
JS_ASSERT(natoms == 0);
JS_ASSERT(nobjects == 0);
JS_ASSERT(nupvars == 0);
JS_ASSERT(nregexps == 0);
JS_ASSERT(ntrynotes == 0);
return JSScript::emptyScript();
}
size = sizeof(JSScript) +
sizeof(JSAtom *) * natoms +
length * sizeof(jsbytecode) +
@ -1485,6 +1526,41 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
mainLength = CG_OFFSET(cg);
prologLength = CG_PROLOG_OFFSET(cg);
if (!cx->debugHooks->newScriptHook &&
!(cg->flags & TCF_NEED_MUTABLE_SCRIPT) &&
prologLength + mainLength <= 3) {
/*
* Check very short scripts to see whether they are "empty" and return
* the const empty-script singleton if so. We are deliberately flexible
* about whether JSOP_TRACE is in the prolog.
*/
jsbytecode *pc = prologLength ? CG_PROLOG_BASE(cg) : CG_BASE(cg);
if (JSOp(*pc) == JSOP_TRACE) {
++pc;
if (pc == CG_PROLOG_BASE(cg) + prologLength)
pc = CG_BASE(cg);
}
if ((cg->flags & TCF_NO_SCRIPT_RVAL) && JSOp(*pc) == JSOP_FALSE)
++pc;
if (JSOp(*pc) == JSOP_STOP) {
JSScript *empty = JSScript::emptyScript();
if (cg->flags & TCF_IN_FUNCTION) {
fun = cg->fun;
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
js_FreezeLocalNames(cx, fun);
fun->u.i.nupvars = 0;
fun->u.i.script = empty;
}
JS_RUNTIME_METER(cx->runtime, liveEmptyScripts);
JS_RUNTIME_METER(cx->runtime, totalEmptyScripts);
return empty;
}
}
CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
script = js_NewScript(cx, prologLength + mainLength, nsrcnotes,
cg->atomList.count, cg->objectList.length,
@ -1552,8 +1628,10 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
if (cg->flags & TCF_IN_FUNCTION) {
fun = cg->fun;
JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
JS_ASSERT_IF(script->upvarsOffset != 0,
script->upvars()->length == fun->u.i.nupvars);
if (script->upvarsOffset != 0)
JS_ASSERT(script->upvars()->length == fun->u.i.nupvars);
else
fun->u.i.nupvars = 0;
js_FreezeLocalNames(cx, fun);
fun->u.i.script = script;
@ -1566,6 +1644,8 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
/* Tell the debugger about this compiled script. */
js_CallNewScriptHook(cx, script, fun);
JS_RUNTIME_METER(cx->runtime, liveScripts);
JS_RUNTIME_METER(cx->runtime, totalScripts);
return script;
bad:
@ -1576,6 +1656,8 @@ bad:
JS_FRIEND_API(void)
js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
{
JS_ASSERT(script != JSScript::emptyScript());
JSNewScriptHook hook;
hook = cx->debugHooks->newScriptHook;
@ -1590,6 +1672,8 @@ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
JS_FRIEND_API(void)
js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
{
JS_ASSERT(script != JSScript::emptyScript());
JSDestroyScriptHook hook;
hook = cx->debugHooks->destroyScriptHook;
@ -1600,6 +1684,11 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
void
js_DestroyScript(JSContext *cx, JSScript *script)
{
if (script == JSScript::emptyScript()) {
JS_RUNTIME_UNMETER(cx->runtime, liveEmptyScripts);
return;
}
js_CallDestroyScriptHook(cx, script);
JS_ClearScriptTraps(cx, script);
@ -1654,6 +1743,8 @@ js_DestroyScript(JSContext *cx, JSScript *script)
#endif
cx->free(script);
JS_RUNTIME_UNMETER(cx->runtime, liveScripts);
}
void

Просмотреть файл

@ -172,6 +172,33 @@ struct JSScript {
inline JSFunction *getFunction(size_t index);
inline JSObject *getRegExp(size_t index);
/*
* The isEmpty method tells whether this script has code that computes any
* result (not return value, result AKA normal completion value) other than
* JSVAL_VOID, or any other effects. It has a fast path for the case where
* |this| is the emptyScript singleton, but it also checks this->length and
* this->code, to handle debugger-generated mutable empty scripts.
*/
inline bool isEmpty() const;
/*
* Accessor for the emptyScriptConst singleton, to consolidate const_cast.
* See the private member declaration.
*/
static JSScript *emptyScript() {
return const_cast<JSScript *>(&emptyScriptConst);
}
private:
/*
* Use const to put this in read-only memory if possible. We are stuck with
* non-const JSScript * and jsbytecode * by legacy code (back in the 1990s,
* const wasn't supported correctly on all target platforms). The debugger
* does mutate bytecode, and script->u.object may be set after construction
* in some cases, so making JSScript pointers const will be "hard".
*/
static const JSScript emptyScriptConst;
};
#define SHARP_NSLOTS 2 /* [#array, #depth] slots if the script
@ -317,11 +344,19 @@ js_GetOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
* If magic is null, js_XDRScript returns false on bad magic number errors,
* which it reports.
*
* NB: callers must call js_CallNewScriptHook after successful JSXDR_DECODE
* and subsequent set-up of owning function or script object, if any.
* NB: after a successful JSXDR_DECODE, and provided that *scriptp is not the
* JSScript::emptyScript() immutable singleton, js_XDRScript callers must do
* any required subsequent set-up of owning function or script object and then
* call js_CallNewScriptHook.
*
* If the caller requires a mutable empty script (for debugging or u.object
* ownership setting), pass true for needMutableScript. Otherwise pass false.
* Call js_CallNewScriptHook only with a mutable script, i.e. never with the
* JSScript::emptyScript() singleton.
*/
extern JSBool
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic);
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
JSBool *hasMagic);
JS_END_EXTERN_C

Просмотреть файл

@ -42,6 +42,7 @@
#define jsscriptinlines_h___
#include "jsfun.h"
#include "jsopcode.h"
#include "jsregexp.h"
#include "jsscript.h"
@ -66,4 +67,23 @@ JSScript::getRegExp(size_t index)
return obj;
}
inline bool
JSScript::isEmpty() const
{
if (this == emptyScript())
return true;
if (length <= 3) {
jsbytecode *pc = code;
if (JSOp(*pc) == JSOP_TRACE)
++pc;
if (noScriptRval && JSOp(*pc) == JSOP_FALSE)
++pc;
if (JSOp(*pc) == JSOP_STOP)
return true;
}
return false;
}
#endif /* jsscriptinlines_h___ */

Просмотреть файл

@ -12032,6 +12032,20 @@ TraceRecorder::guardArguments(JSObject *obj, LIns* obj_ins, unsigned *depthp)
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing)
{
/*
* The function's identity (JSFunction and therefore JSScript) is guarded,
* so we can optimize for the empty script singleton right away. No need to
* worry about crossing globals or relocating argv, even, in this case!
*
* Note that the interpreter shortcuts empty-script call and construct too,
* and does not call any TR::record_*CallComplete hook.
*/
if (fun->u.i.script->isEmpty()) {
LIns* rval_ins = constructing ? stack(-1 - argc) : INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
stack(-2 - argc, rval_ins);
return RECORD_CONTINUE;
}
if (JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(fval)) != globalObj)
RETURN_STOP("JSOP_CALL or JSOP_NEW crosses global scopes");

Просмотреть файл

@ -681,7 +681,7 @@ js_XDRStringAtom(JSXDRState *xdr, JSAtom **atomp)
JS_PUBLIC_API(JSBool)
JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
{
if (!js_XDRScript(xdr, scriptp, NULL))
if (!js_XDRScript(xdr, scriptp, true, NULL))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE)
js_CallNewScriptHook(xdr->cx, *scriptp, NULL);

Просмотреть файл

@ -193,7 +193,8 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
#define JSXDR_MAGIC_SCRIPT_7 0xdead0007
#define JSXDR_MAGIC_SCRIPT_8 0xdead0008
#define JSXDR_MAGIC_SCRIPT_9 0xdead0009
#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_9
#define JSXDR_MAGIC_SCRIPT_10 0xdead000a
#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_10
/*
* Bytecode version number. Increment the subtrahend whenever JS bytecode
@ -204,7 +205,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
* before deserialization of bytecode. If the saved version does not match
* the current version, abort deserialization and invalidate the file.
*/
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 55)
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 56)
/*
* Library-private functions.