зеркало из https://github.com/mozilla/gecko-dev.git
Statically bind global variables where possible (bug 561923, r=brendan).
This commit is contained in:
Родитель
9d857ed6ca
Коммит
26458364a5
|
@ -936,6 +936,14 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||
0, /* JSOP_UNBRANDTHIS */
|
||||
0, /* JSOP_SHARPINIT */
|
||||
3, /* JSOP_OBJTOSTR */
|
||||
0, /* JSOP_GETGLOBAL */
|
||||
0, /* JSOP_SETGLOBAL */
|
||||
0, /* JSOP_INCGLOBAL */
|
||||
0, /* JSOP_DECGLOBAL */
|
||||
0, /* JSOP_GLOBALINC */
|
||||
0, /* JSOP_GLOBALDEC */
|
||||
0, /* JSOP_CALLGLOBAL */
|
||||
0, /* JSOP_FORGLOBAL */
|
||||
};
|
||||
#define JSOP_IS_IMACOP(x) (0 \
|
||||
|| x == JSOP_BITOR \
|
||||
|
|
|
@ -102,7 +102,8 @@ JSCodeGenerator::JSCodeGenerator(Parser *parser,
|
|||
numSpanDeps(0), numJumpTargets(0), spanDepTodo(0),
|
||||
arrayCompDepth(0),
|
||||
emitLevel(0),
|
||||
constMap(parser->context)
|
||||
constMap(parser->context),
|
||||
globalUses(ContextAllocPolicy(parser->context))
|
||||
{
|
||||
flags = TCF_COMPILING;
|
||||
memset(&prolog, 0, sizeof prolog);
|
||||
|
@ -2161,6 +2162,40 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
}
|
||||
|
||||
if (dn->pn_dflags & PND_GVAR) {
|
||||
if (js_CodeSpec[dn->pn_op].type() == JOF_GLOBAL) {
|
||||
switch (op) {
|
||||
case JSOP_NAME: op = JSOP_GETGLOBAL; break;
|
||||
case JSOP_SETNAME: op = JSOP_SETGLOBAL; break;
|
||||
case JSOP_INCNAME: op = JSOP_INCGLOBAL; break;
|
||||
case JSOP_NAMEINC: op = JSOP_GLOBALINC; break;
|
||||
case JSOP_DECNAME: op = JSOP_DECGLOBAL; break;
|
||||
case JSOP_NAMEDEC: op = JSOP_GLOBALDEC; break;
|
||||
case JSOP_FORNAME: op = JSOP_FORGLOBAL; break;
|
||||
case JSOP_SETCONST:
|
||||
case JSOP_DELNAME:
|
||||
/* Not supported. */
|
||||
return JS_TRUE;
|
||||
default: JS_NOT_REACHED("gvar");
|
||||
}
|
||||
|
||||
JSCodeGenerator *globalCg = cg->compiler()->globalScope->cg;
|
||||
if (globalCg != cg) {
|
||||
uint32 slot = globalCg->globalUses[cookie].slot;
|
||||
|
||||
/* Fall back to NAME if we can't add a slot. */
|
||||
if (!cg->addGlobalUse(atom, slot, &cookie))
|
||||
return JS_FALSE;
|
||||
|
||||
if (cookie == FREE_UPVAR_COOKIE)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
pn->pn_op = op;
|
||||
pn->pn_cookie = cookie;
|
||||
pn->pn_dflags |= PND_BOUND;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a global reference from within a function, leave pn_op as
|
||||
* JSOP_NAME, etc. We could emit JSOP_*GVAR ops within function code if
|
||||
|
@ -2426,6 +2461,40 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
bool
|
||||
JSCodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, uint32 *indexp)
|
||||
{
|
||||
JSAtomListElement *ale = globalMap.lookup(atom);
|
||||
if (ale) {
|
||||
*indexp = ALE_INDEX(ale);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Don't bother encoding indexes >= uint16 */
|
||||
if (globalUses.length() >= UINT16_LIMIT) {
|
||||
*indexp = FREE_UPVAR_COOKIE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Find or add an existing atom table entry. */
|
||||
ale = atomList.add(parser, atom);
|
||||
if (!ale)
|
||||
return false;
|
||||
|
||||
*indexp = uint32(globalUses.length());
|
||||
|
||||
GlobalSlotArray::Entry entry = { ALE_INDEX(ale), slot };
|
||||
if (!globalUses.append(entry))
|
||||
return false;
|
||||
|
||||
ale = globalMap.add(parser, atom);
|
||||
if (!ale)
|
||||
return false;
|
||||
|
||||
ALE_SET_INDEX(ale, *indexp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If pn contains a useful expression, return true with *answer set to true.
|
||||
* If pn contains a useless expression, return true with *answer set to false.
|
||||
|
@ -2653,6 +2722,9 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
|||
JS_ASSERT(!cg->funbox);
|
||||
op = JSOP_CALLGVAR;
|
||||
break;
|
||||
case JSOP_GETGLOBAL:
|
||||
op = JSOP_CALLGLOBAL;
|
||||
break;
|
||||
case JSOP_GETARG:
|
||||
op = JSOP_CALLARG;
|
||||
break;
|
||||
|
@ -3671,7 +3743,9 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
|
|||
}
|
||||
|
||||
if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
|
||||
(!cg->inFunction() || (cg->flags & TCF_FUN_HEAVYWEIGHT))) {
|
||||
(!cg->inFunction() || (cg->flags & TCF_FUN_HEAVYWEIGHT)) &&
|
||||
js_CodeSpec[pn->pn_op].type() != JOF_GLOBAL)
|
||||
{
|
||||
CG_SWITCH_TO_PROLOG(cg);
|
||||
if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
|
||||
return JS_FALSE;
|
||||
|
@ -3783,6 +3857,7 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
|
||||
case JSOP_SETARG:
|
||||
case JSOP_SETGVAR:
|
||||
case JSOP_SETGLOBAL:
|
||||
slot = (jsuint) pn->pn_cookie;
|
||||
EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
|
||||
if (js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||
|
@ -4822,6 +4897,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
case JSOP_SETGVAR: op = JSOP_FORNAME; break;
|
||||
case JSOP_GETLOCAL: /* FALL THROUGH */
|
||||
case JSOP_SETLOCAL: op = JSOP_FORLOCAL; break;
|
||||
case JSOP_GETGLOBAL: /* FALL THROUGH */
|
||||
case JSOP_SETGLOBAL: op = JSOP_FORGLOBAL; break;
|
||||
default: JS_ASSERT(0);
|
||||
}
|
||||
} else {
|
||||
|
@ -5826,6 +5903,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
JS_ASSERT(PN_OP(pn2) != JSOP_GETUPVAR);
|
||||
EMIT_UINT16_IMM_OP((PN_OP(pn2) == JSOP_SETGVAR)
|
||||
? JSOP_GETGVAR
|
||||
: (PN_OP(pn2) == JSOP_SETGLOBAL)
|
||||
? JSOP_GETGLOBAL
|
||||
: (PN_OP(pn2) == JSOP_SETARG)
|
||||
? JSOP_GETARG
|
||||
: JSOP_GETLOCAL,
|
||||
|
|
|
@ -245,6 +245,11 @@ struct JSStmtInfo {
|
|||
*/
|
||||
#define TCF_FUN_USES_EVAL 0x800000
|
||||
|
||||
/*
|
||||
* Compiling an eval() script.
|
||||
*/
|
||||
#define TCF_COMPILE_FOR_EVAL 0x1000000
|
||||
|
||||
/*
|
||||
* Flags to check for return; vs. return expr; in a function.
|
||||
*/
|
||||
|
@ -341,6 +346,8 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
int sharpSlotBase;
|
||||
bool ensureSharpSlots();
|
||||
|
||||
js::Compiler *compiler() { return (js::Compiler *)parser; }
|
||||
|
||||
// Return true there is a generator function within |skip| lexical scopes
|
||||
// (going upward) from this context's lexical scope. Always return true if
|
||||
// this context is itself a generator.
|
||||
|
@ -487,6 +494,11 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
JSAtomList upvarList; /* map of atoms to upvar indexes */
|
||||
JSUpvarArray upvarMap; /* indexed upvar pairs (JS_realloc'ed) */
|
||||
|
||||
typedef js::Vector<js::GlobalSlotArray::Entry, 16, js::ContextAllocPolicy> GlobalUseVector;
|
||||
|
||||
GlobalUseVector globalUses; /* per-script global uses */
|
||||
JSAtomList globalMap; /* per-script map of global name to globalUses vector */
|
||||
|
||||
/*
|
||||
* Initialize cg to allocate bytecode space from codePool, source note
|
||||
* space from notePool, and all other arena-allocated temporaries from
|
||||
|
@ -506,6 +518,8 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
*/
|
||||
~JSCodeGenerator();
|
||||
|
||||
bool addGlobalUse(JSAtom *atom, uint32 slot, uint32 *indexp);
|
||||
|
||||
bool hasSharps() {
|
||||
bool rv = !!(flags & TCF_HAS_SHARPS);
|
||||
JS_ASSERT((sharpSlotBase >= 0) == rv);
|
||||
|
@ -515,6 +529,8 @@ struct JSCodeGenerator : public JSTreeContext
|
|||
uintN sharpSlots() {
|
||||
return hasSharps() ? SHARP_NSLOTS : 0;
|
||||
}
|
||||
|
||||
bool compilingForEval() { return !!(flags & TCF_COMPILE_FOR_EVAL); }
|
||||
};
|
||||
|
||||
#define CG_TS(cg) TS((cg)->parser)
|
||||
|
|
|
@ -393,6 +393,9 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio
|
|||
: 0,
|
||||
(script->trynotesOffset != 0)
|
||||
? script->trynotes()->length
|
||||
: 0,
|
||||
(script->globalsOffset != 0)
|
||||
? script->globals()->length
|
||||
: 0);
|
||||
if (!wscript)
|
||||
return NULL;
|
||||
|
@ -415,6 +418,10 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio
|
|||
memcpy(wscript->trynotes()->vector, script->trynotes()->vector,
|
||||
wscript->trynotes()->length * sizeof(JSTryNote));
|
||||
}
|
||||
if (script->globalsOffset != 0) {
|
||||
memcpy(wscript->globals()->vector, script->globals()->vector,
|
||||
wscript->globals()->length * sizeof(GlobalSlotArray::Entry));
|
||||
}
|
||||
|
||||
if (wfun->u.i.nupvars != 0) {
|
||||
JS_ASSERT(wfun->u.i.nupvars == wscript->upvars()->length);
|
||||
|
|
|
@ -1358,9 +1358,9 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
|||
*/
|
||||
JSStackFrame *callerFrame = (staticLevel != 0) ? caller : NULL;
|
||||
if (!script) {
|
||||
uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL;
|
||||
script = Compiler::compileScript(cx, scopeobj, callerFrame,
|
||||
principals,
|
||||
TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT,
|
||||
principals, tcflags,
|
||||
str->chars(), str->length(),
|
||||
NULL, file, line, str, staticLevel);
|
||||
if (!script)
|
||||
|
|
|
@ -386,6 +386,15 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc,
|
|||
fprintf(fp, " %s", bytes);
|
||||
break;
|
||||
|
||||
case JOF_GLOBAL:
|
||||
atom = script->getGlobalAtom(GET_SLOTNO(pc));
|
||||
v = ATOM_TO_JSVAL(atom);
|
||||
bytes = ToDisassemblySource(cx, v);
|
||||
if (!bytes)
|
||||
return 0;
|
||||
fprintf(fp, " %s", bytes);
|
||||
break;
|
||||
|
||||
case JOF_UINT16PAIR:
|
||||
i = (jsint)GET_UINT16(pc);
|
||||
fprintf(fp, " %d", i);
|
||||
|
@ -1411,6 +1420,7 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
|
|||
LOCAL_ASSERT(*pc == JSOP_POP);
|
||||
break;
|
||||
|
||||
case JSOP_SETGLOBAL:
|
||||
case JSOP_SETARG:
|
||||
case JSOP_SETGVAR:
|
||||
case JSOP_SETLOCAL:
|
||||
|
@ -1425,6 +1435,8 @@ DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc,
|
|||
LOCAL_ASSERT(atom);
|
||||
} else if (op == JSOP_SETGVAR) {
|
||||
LOAD_ATOM(0);
|
||||
} else if (op == JSOP_SETGLOBAL) {
|
||||
atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
|
||||
} else if (IsVarSlot(jp, pc, &i)) {
|
||||
atom = GetArgOrVarAtom(jp, i);
|
||||
LOCAL_ASSERT(atom);
|
||||
|
@ -3365,6 +3377,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
xval = "&&";
|
||||
goto do_logical_connective;
|
||||
|
||||
case JSOP_FORGLOBAL:
|
||||
atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
|
||||
goto do_forname;
|
||||
|
||||
case JSOP_FORARG:
|
||||
sn = NULL;
|
||||
i = GET_ARGNO(pc);
|
||||
|
@ -3388,6 +3404,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
|
||||
case JSOP_FORNAME:
|
||||
LOAD_ATOM(0);
|
||||
|
||||
do_forname:
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
todo = SprintCString(&ss->sprinter, VarPrefix(sn));
|
||||
if (todo < 0 || !QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0))
|
||||
|
@ -3500,6 +3518,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
LOCAL_ASSERT(atom);
|
||||
goto do_setname;
|
||||
|
||||
case JSOP_SETGLOBAL:
|
||||
atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
|
||||
goto do_setname;
|
||||
|
||||
case JSOP_SETCONST:
|
||||
case JSOP_SETNAME:
|
||||
case JSOP_SETGVAR:
|
||||
|
@ -3716,6 +3738,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
LOCAL_ASSERT(atom);
|
||||
goto do_incatom;
|
||||
|
||||
case JSOP_INCGLOBAL:
|
||||
case JSOP_DECGLOBAL:
|
||||
atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
|
||||
goto do_incatom;
|
||||
|
||||
case JSOP_INCNAME:
|
||||
case JSOP_DECNAME:
|
||||
case JSOP_INCGVAR:
|
||||
|
@ -3772,6 +3799,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
LOCAL_ASSERT(atom);
|
||||
goto do_atominc;
|
||||
|
||||
case JSOP_GLOBALINC:
|
||||
case JSOP_GLOBALDEC:
|
||||
atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
|
||||
goto do_atominc;
|
||||
|
||||
case JSOP_NAMEINC:
|
||||
case JSOP_NAMEDEC:
|
||||
case JSOP_GVARINC:
|
||||
|
@ -3978,6 +4010,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
#endif
|
||||
goto do_name;
|
||||
|
||||
case JSOP_CALLGLOBAL:
|
||||
case JSOP_GETGLOBAL:
|
||||
atom = jp->script->getGlobalAtom(GET_SLOTNO(pc));
|
||||
goto do_name;
|
||||
|
||||
case JSOP_CALLNAME:
|
||||
case JSOP_NAME:
|
||||
case JSOP_GETGVAR:
|
||||
|
|
|
@ -85,6 +85,7 @@ typedef enum JSOp {
|
|||
#define JOF_INT8 18 /* int8 immediate operand */
|
||||
#define JOF_ATOMOBJECT 19 /* uint16 constant index + object index */
|
||||
#define JOF_UINT16PAIR 20 /* pair of uint16 immediates */
|
||||
#define JOF_GLOBAL 21 /* uint16 global array index */
|
||||
#define JOF_TYPEMASK 0x001f /* mask for above immediate types */
|
||||
|
||||
#define JOF_NAME (1U<<5) /* name operation */
|
||||
|
@ -254,6 +255,8 @@ struct JSCodeSpec {
|
|||
int8 ndefs; /* number of stack results */
|
||||
uint8 prec; /* operator precedence */
|
||||
uint32 format; /* immediate operand format */
|
||||
|
||||
uint32 type() const { return JOF_TYPE(format); }
|
||||
};
|
||||
|
||||
extern const JSCodeSpec js_CodeSpec[];
|
||||
|
|
|
@ -610,3 +610,14 @@ OPDEF(JSOP_SHARPINIT, 239,"sharpinit", NULL, 3, 0, 0, 0, JOF_UINT16
|
|||
* If the argument is an object, perform toString conversion (E-262-3 section 9.8).
|
||||
*/
|
||||
OPDEF(JSOP_OBJTOSTR, 240,"objtostr", NULL, 1, 1, 1, 0, JOF_BYTE)
|
||||
|
||||
/* Static binding for globals. */
|
||||
OPDEF(JSOP_GETGLOBAL, 241,"getglobal", NULL, 3, 0, 1, 19, JOF_GLOBAL|JOF_NAME)
|
||||
OPDEF(JSOP_SETGLOBAL, 242,"setglobal", NULL, 3, 1, 1, 3, JOF_GLOBAL|JOF_NAME|JOF_SET|JOF_DETECTING)
|
||||
OPDEF(JSOP_INCGLOBAL, 243,"incglobal", NULL, 3, 0, 1, 15, JOF_GLOBAL|JOF_NAME|JOF_INC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_DECGLOBAL, 244,"decglobal", NULL, 3, 0, 1, 15, JOF_GLOBAL|JOF_NAME|JOF_DEC|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_GLOBALINC, 245,"globalinc", NULL, 3, 0, 1, 15, JOF_GLOBAL|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_GLOBALDEC, 246,"globaldec", NULL, 3, 0, 1, 15, JOF_GLOBAL|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT2)
|
||||
OPDEF(JSOP_CALLGLOBAL, 247,"callglobal", NULL, 3, 0, 2, 19, JOF_GLOBAL|JOF_NAME|JOF_CALLOP)
|
||||
OPDEF(JSOP_FORGLOBAL, 248,"forglobal", NULL, 3, 1, 1, 19, JOF_GLOBAL|JOF_NAME|JOF_FOR|JOF_TMPSLOT)
|
||||
|
||||
|
|
|
@ -1499,6 +1499,23 @@ do_incop:
|
|||
int incr, incr2;
|
||||
Value *vp;
|
||||
|
||||
BEGIN_CASE(JSOP_INCGLOBAL)
|
||||
incr = 1; incr2 = 1; goto do_bound_global_incop;
|
||||
BEGIN_CASE(JSOP_DECGLOBAL)
|
||||
incr = -1; incr2 = -1; goto do_bound_global_incop;
|
||||
BEGIN_CASE(JSOP_GLOBALINC)
|
||||
incr = 1; incr2 = 0; goto do_bound_global_incop;
|
||||
BEGIN_CASE(JSOP_GLOBALDEC)
|
||||
incr = -1; incr2 = 0; goto do_bound_global_incop;
|
||||
|
||||
do_bound_global_incop:
|
||||
uint32 slot = GET_SLOTNO(regs.pc);
|
||||
slot = script->getGlobalSlot(slot);
|
||||
JSObject *obj = fp->scopeChain->getGlobal();
|
||||
vp = &obj->getSlotRef(slot);
|
||||
goto do_int_fast_incop;
|
||||
END_CASE(JSOP_INCGLOBAL)
|
||||
|
||||
/* Position cases so the most frequent i++ does not need a jump. */
|
||||
BEGIN_CASE(JSOP_DECARG)
|
||||
incr = -1; incr2 = -1; goto do_arg_incop;
|
||||
|
@ -1510,7 +1527,7 @@ BEGIN_CASE(JSOP_ARGINC)
|
|||
incr = 1; incr2 = 0;
|
||||
|
||||
do_arg_incop:
|
||||
uint32 slot = GET_ARGNO(regs.pc);
|
||||
slot = GET_ARGNO(regs.pc);
|
||||
JS_ASSERT(slot < fp->fun->nargs);
|
||||
METER_SLOT_OP(op, slot);
|
||||
vp = fp->argv + slot;
|
||||
|
@ -2965,6 +2982,62 @@ BEGIN_CASE(JSOP_CALLDSLOT)
|
|||
}
|
||||
END_CASE(JSOP_GETDSLOT)
|
||||
|
||||
BEGIN_CASE(JSOP_GETGLOBAL)
|
||||
BEGIN_CASE(JSOP_CALLGLOBAL)
|
||||
{
|
||||
uint32 slot = GET_SLOTNO(regs.pc);
|
||||
slot = script->getGlobalSlot(slot);
|
||||
JSObject *obj = fp->scopeChain->getGlobal();
|
||||
JS_ASSERT(slot < obj->scope()->freeslot);
|
||||
PUSH_COPY(obj->getSlot(slot));
|
||||
if (op == JSOP_CALLGLOBAL)
|
||||
PUSH_NULL();
|
||||
}
|
||||
END_CASE(JSOP_GETGLOBAL)
|
||||
|
||||
BEGIN_CASE(JSOP_FORGLOBAL)
|
||||
{
|
||||
Value rval;
|
||||
if (!IteratorNext(cx, ®s.sp[-1].asObject(), &rval))
|
||||
goto error;
|
||||
PUSH_COPY(rval);
|
||||
uint32 slot = GET_SLOTNO(regs.pc);
|
||||
slot = script->getGlobalSlot(slot);
|
||||
JSObject *obj = fp->scopeChain->getGlobal();
|
||||
JS_ASSERT(slot < obj->scope()->freeslot);
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
{
|
||||
JSScope *scope = obj->scope();
|
||||
if (!scope->methodWriteBarrier(cx, slot, rval)) {
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
goto error;
|
||||
}
|
||||
obj->lockedSetSlot(slot, rval);
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
}
|
||||
regs.sp--;
|
||||
}
|
||||
END_CASE(JSOP_FORGLOBAL)
|
||||
|
||||
BEGIN_CASE(JSOP_SETGLOBAL)
|
||||
{
|
||||
uint32 slot = GET_SLOTNO(regs.pc);
|
||||
slot = script->getGlobalSlot(slot);
|
||||
JSObject *obj = fp->scopeChain->getGlobal();
|
||||
JS_ASSERT(slot < obj->scope()->freeslot);
|
||||
{
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
JSScope *scope = obj->scope();
|
||||
if (!scope->methodWriteBarrier(cx, slot, regs.sp[-1])) {
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
goto error;
|
||||
}
|
||||
obj->lockedSetSlot(slot, regs.sp[-1]);
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
}
|
||||
}
|
||||
END_SET_CASE(JSOP_SETGLOBAL)
|
||||
|
||||
BEGIN_CASE(JSOP_GETGVAR)
|
||||
BEGIN_CASE(JSOP_CALLGVAR)
|
||||
{
|
||||
|
|
|
@ -734,7 +734,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
|||
void *sbrk(ptrdiff_t), *before = sbrk(0);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_NEED_MUTABLE_SCRIPT)));
|
||||
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_NEED_MUTABLE_SCRIPT |
|
||||
TCF_COMPILE_FOR_EVAL)));
|
||||
|
||||
/*
|
||||
* The scripted callerFrame can only be given for compile-and-go scripts
|
||||
|
@ -761,11 +762,21 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
|||
|
||||
MUST_FLOW_THROUGH("out");
|
||||
|
||||
JSObject *globalObj = scopeChain ? scopeChain->getGlobal() : NULL;
|
||||
js::GlobalScope globalScope(cx, globalObj, &cg);
|
||||
if (globalObj) {
|
||||
JS_ASSERT(globalObj->isNative());
|
||||
JS_ASSERT((globalObj->getClass()->flags & JSCLASS_GLOBAL_FLAGS) == JSCLASS_GLOBAL_FLAGS);
|
||||
globalScope.globalFreeSlot = globalObj->scope()->freeslot;
|
||||
}
|
||||
|
||||
/* Null script early in case of error, to reduce our code footprint. */
|
||||
script = NULL;
|
||||
|
||||
globalScope.cg = &cg;
|
||||
cg.flags |= tcflags;
|
||||
cg.scopeChain = scopeChain;
|
||||
compiler.globalScope = &globalScope;
|
||||
if (!SetStaticLevel(&cg, staticLevel))
|
||||
goto out;
|
||||
|
||||
|
@ -926,6 +937,27 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
|||
}
|
||||
}
|
||||
|
||||
if (globalScope.defs.length()) {
|
||||
JS_ASSERT(globalObj->scope()->freeslot == globalScope.globalFreeSlot);
|
||||
JS_ASSERT(!cg.compilingForEval());
|
||||
for (size_t i = 0; i < globalScope.defs.length(); i++) {
|
||||
JSAtom *atom = globalScope.defs[i];
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
JSProperty *prop;
|
||||
|
||||
if (!js_DefineNativeProperty(cx, globalObj, id, Value(UndefinedTag()), PropertyStub,
|
||||
PropertyStub, JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
0, 0, &prop)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
JS_ASSERT(prop);
|
||||
JS_ASSERT(((JSScopeProperty*)prop)->slot == globalScope.globalFreeSlot + i);
|
||||
|
||||
globalObj->dropProperty(cx, prop);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef METER_PARSENODES
|
||||
printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",
|
||||
(char *)sbrk(0) - (char *)before,
|
||||
|
@ -3253,7 +3285,70 @@ OuterLet(JSTreeContext *tc, JSStmtInfo *stmt, JSAtom *atom)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
DefineGlobal(JSParseNode *pn, JSCodeGenerator *cg, JSAtom *atom)
|
||||
{
|
||||
GlobalScope *globalScope = cg->compiler()->globalScope;
|
||||
JSObject *globalObj = globalScope->globalObj;
|
||||
|
||||
if (!cg->compileAndGo() || !globalObj || cg->compilingForEval())
|
||||
return true;
|
||||
|
||||
JS_LOCK_OBJ(cg->parser->context, globalObj);
|
||||
JSScope *scope = globalObj->scope();
|
||||
if (JSScopeProperty *sprop = scope->lookup(ATOM_TO_JSID(atom))) {
|
||||
/*
|
||||
* If the property was found, bind the slot immediately if
|
||||
* we can. If we can't, don't bother emitting a GVAR op,
|
||||
* since it's unlikely that it will optimize either.
|
||||
*/
|
||||
uint32 index;
|
||||
if (!sprop->configurable() &&
|
||||
SPROP_HAS_VALID_SLOT(sprop, globalObj->scope()) &&
|
||||
sprop->hasDefaultGetterOrIsMethod() &&
|
||||
sprop->hasDefaultSetter() &&
|
||||
cg->addGlobalUse(atom, sprop->slot, &index) &&
|
||||
index != FREE_UPVAR_COOKIE)
|
||||
{
|
||||
pn->pn_op = JSOP_GETGLOBAL;
|
||||
pn->pn_cookie = index;
|
||||
pn->pn_dflags |= PND_BOUND | PND_GVAR;
|
||||
}
|
||||
|
||||
JS_UNLOCK_SCOPE(cg->parser->context, scope);
|
||||
return true;
|
||||
}
|
||||
JS_UNLOCK_SCOPE(cg->parser->context, scope);
|
||||
|
||||
/* Definitions from |var| are not redefined, like functions. */
|
||||
JS_ASSERT(!cg->globalMap.lookup(atom));
|
||||
|
||||
uint32 slot = globalScope->globalFreeSlot + globalScope->defs.length();
|
||||
if (!globalScope->defs.append(atom))
|
||||
return false;
|
||||
|
||||
uint32 index;
|
||||
if (!cg->addGlobalUse(atom, slot, &index))
|
||||
return false;
|
||||
|
||||
if (index != FREE_UPVAR_COOKIE) {
|
||||
pn->pn_op = JSOP_GETGLOBAL;
|
||||
pn->pn_cookie = index;
|
||||
pn->pn_dflags |= PND_BOUND | PND_GVAR;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If compile-and-go, and a global object is present, try to bake in either
|
||||
* an already available slot or a predicted slot that will be defined after
|
||||
* compiling is completed.
|
||||
*
|
||||
* If not compile-and-go, or compiling for eval, this optimization is invalid.
|
||||
* The old path (explained below), which works for global references only, is
|
||||
* thus preserved at the bottom of BindGvar().
|
||||
*
|
||||
* If we are generating global or eval-called-from-global code, bind a "gvar"
|
||||
* here, as soon as possible. The JSOP_GETGVAR, etc., ops speed up interpreted
|
||||
* global variable access by memoizing name-to-slot mappings during execution
|
||||
|
@ -3274,27 +3369,38 @@ BindGvar(JSParseNode *pn, JSTreeContext *tc, bool inWith = false)
|
|||
JS_ASSERT(pn->pn_op == JSOP_NAME);
|
||||
JS_ASSERT(!tc->inFunction());
|
||||
|
||||
if (tc->compiling() && !tc->parser->callerFrame) {
|
||||
JSCodeGenerator *cg = (JSCodeGenerator *) tc;
|
||||
if (!tc->compiling() || tc->parser->callerFrame)
|
||||
return true;
|
||||
|
||||
/* Index pn->pn_atom so we can map fast global number to name. */
|
||||
JSAtomListElement *ale = cg->atomList.add(tc->parser, pn->pn_atom);
|
||||
if (!ale)
|
||||
JSCodeGenerator *cg = (JSCodeGenerator *) tc;
|
||||
|
||||
if (!(pn->pn_dflags & PND_CONST) && !inWith) {
|
||||
if (!DefineGlobal(pn, cg, pn->pn_atom))
|
||||
return false;
|
||||
|
||||
/* Defend against cg->ngvars 16-bit overflow. */
|
||||
uintN slot = ALE_INDEX(ale);
|
||||
if ((slot + 1) >> 16)
|
||||
if (pn->pn_dflags & PND_BOUND)
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((uint16)(slot + 1) > cg->ngvars)
|
||||
cg->ngvars = (uint16)(slot + 1);
|
||||
/* If direct binding failed, try the old gvar optimization. */
|
||||
|
||||
if (!inWith) {
|
||||
pn->pn_op = JSOP_GETGVAR;
|
||||
pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, slot);
|
||||
pn->pn_dflags |= PND_BOUND | PND_GVAR;
|
||||
}
|
||||
/* Index pn->pn_atom so we can map fast global number to name. */
|
||||
JSAtomListElement *ale = cg->atomList.add(tc->parser, pn->pn_atom);
|
||||
if (!ale)
|
||||
return false;
|
||||
|
||||
/* Defend against cg->ngvars 16-bit overflow. */
|
||||
uintN slot = ALE_INDEX(ale);
|
||||
if ((slot + 1) >> 16)
|
||||
return true;
|
||||
|
||||
if ((uint16)(slot + 1) > cg->ngvars)
|
||||
cg->ngvars = (uint16)(slot + 1);
|
||||
|
||||
/* See bug 561011; don't optimize, but slot must be reserved above. */
|
||||
if (!inWith) {
|
||||
pn->pn_op = JSOP_GETGVAR;
|
||||
pn->pn_cookie = MAKE_UPVAR_COOKIE(tc->staticLevel, slot);
|
||||
pn->pn_dflags |= PND_BOUND | PND_GVAR;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -3572,10 +3678,12 @@ BindDestructuringVar(JSContext *cx, BindData *data, JSParseNode *pn,
|
|||
* done by the data->binder function.
|
||||
*/
|
||||
if (pn->pn_dflags & PND_BOUND) {
|
||||
JS_ASSERT_IF((pn->pn_dflags & PND_GVAR),
|
||||
PN_OP(pn) == JSOP_GETGVAR || PN_OP(pn) == JSOP_GETGLOBAL);
|
||||
pn->pn_op = (pn->pn_op == JSOP_ARGUMENTS)
|
||||
? JSOP_SETNAME
|
||||
: (pn->pn_dflags & PND_GVAR)
|
||||
? JSOP_SETGVAR
|
||||
? (PN_OP(pn) == JSOP_GETGVAR ? JSOP_SETGVAR : JSOP_SETGLOBAL)
|
||||
: JSOP_SETLOCAL;
|
||||
} else {
|
||||
pn->pn_op = (data->op == JSOP_DEFCONST)
|
||||
|
@ -5847,10 +5955,13 @@ Parser::variables(bool inLetHead)
|
|||
pn2->pn_expr = init;
|
||||
}
|
||||
|
||||
JS_ASSERT_IF((pn2->pn_dflags & PND_GVAR),
|
||||
PN_OP(pn2) == JSOP_GETGVAR || PN_OP(pn2) == JSOP_GETGLOBAL);
|
||||
|
||||
pn2->pn_op = (PN_OP(pn2) == JSOP_ARGUMENTS)
|
||||
? JSOP_SETNAME
|
||||
: (pn2->pn_dflags & PND_GVAR)
|
||||
? JSOP_SETGVAR
|
||||
? (PN_OP(pn2) == JSOP_GETGVAR ? JSOP_SETGVAR : JSOP_SETGLOBAL)
|
||||
: (pn2->pn_dflags & PND_BOUND)
|
||||
? JSOP_SETLOCAL
|
||||
: (data.op == JSOP_DEFCONST)
|
||||
|
|
|
@ -287,6 +287,21 @@ typedef enum JSParseNodeArity {
|
|||
|
||||
struct JSDefinition;
|
||||
|
||||
namespace js {
|
||||
|
||||
struct GlobalScope {
|
||||
GlobalScope(JSContext *cx, JSObject *globalObj, JSCodeGenerator *cg)
|
||||
: globalObj(globalObj), cg(cg), defs(ContextAllocPolicy(cx))
|
||||
{ }
|
||||
|
||||
JSObject *globalObj;
|
||||
JSCodeGenerator *cg;
|
||||
Vector<JSAtom *, 16, ContextAllocPolicy> defs;
|
||||
uint32 globalFreeSlot;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
struct JSParseNode {
|
||||
uint32 pn_type:16, /* TOK_* type, see jsscan.h */
|
||||
pn_op:8, /* see JSOp enum and jsopcode.tbl */
|
||||
|
@ -1060,6 +1075,7 @@ private:
|
|||
struct Compiler
|
||||
{
|
||||
Parser parser;
|
||||
GlobalScope *globalScope;
|
||||
|
||||
Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
|
||||
: parser(cx, prin, cfp)
|
||||
|
|
|
@ -75,7 +75,7 @@ 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, true, false, false, false,
|
||||
1, JSVERSION_DEFAULT, 0, 0, 0, 0, 0, 0, true, false, false, false,
|
||||
const_cast<jsbytecode*>(emptyScriptCode),
|
||||
{0, NULL}, NULL, 0, 0, 0, NULL
|
||||
};
|
||||
|
@ -105,6 +105,9 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
|||
filenameWasSaved = JS_FALSE;
|
||||
notes = NULL;
|
||||
|
||||
/* Should not XDR scripts optimized for a single global object. */
|
||||
JS_ASSERT_IF(script, !script->globalsOffset);
|
||||
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
magic = JSXDR_MAGIC_SCRIPT_CURRENT;
|
||||
if (!JS_XDRUint32(xdr, &magic))
|
||||
|
@ -146,7 +149,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
|||
* the shorthand (0 length word) for us. Make a new mutable empty
|
||||
* script here and return it immediately.
|
||||
*/
|
||||
script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0);
|
||||
script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0);
|
||||
if (!script)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -214,7 +217,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript,
|
|||
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars,
|
||||
nregexps, ntrynotes);
|
||||
nregexps, ntrynotes, 0);
|
||||
if (!script)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -806,7 +809,7 @@ JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) +
|
|||
JSScript *
|
||||
js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
||||
uint32 nobjects, uint32 nupvars, uint32 nregexps,
|
||||
uint32 ntrynotes)
|
||||
uint32 ntrynotes, uint32 nglobals)
|
||||
{
|
||||
size_t size, vectorSize;
|
||||
JSScript *script;
|
||||
|
@ -824,6 +827,8 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
|||
size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
|
||||
if (ntrynotes != 0)
|
||||
size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
|
||||
if (nglobals != 0)
|
||||
size += sizeof(GlobalSlotArray) + nglobals * sizeof(GlobalSlotArray::Entry);
|
||||
|
||||
script = (JSScript *) cx->malloc(size);
|
||||
if (!script)
|
||||
|
@ -849,6 +854,11 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
|||
script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
|
||||
cursor += sizeof(JSTryNoteArray);
|
||||
}
|
||||
if (nglobals != 0) {
|
||||
JS_ASSERT((cursor - (uint8*)script) <= 0xFF);
|
||||
script->globalsOffset = (uint8)(cursor - (uint8 *)script);
|
||||
cursor += sizeof(GlobalSlotArray);
|
||||
}
|
||||
|
||||
if (natoms != 0) {
|
||||
script->atomMap.length = natoms;
|
||||
|
@ -889,6 +899,13 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
|||
cursor += vectorSize;
|
||||
}
|
||||
|
||||
if (nglobals != 0) {
|
||||
script->globals()->length = nglobals;
|
||||
script->globals()->vector = (GlobalSlotArray::Entry *)cursor;
|
||||
vectorSize = nglobals * sizeof(script->globals()->vector[0]);
|
||||
cursor += vectorSize;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: We allocate the vector of uint32 upvar cookies after all vectors of
|
||||
* pointers, to avoid misalignment on 64-bit platforms. See bug 514645.
|
||||
|
@ -988,7 +1005,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||
script = js_NewScript(cx, prologLength + mainLength, nsrcnotes,
|
||||
cg->atomList.count, cg->objectList.length,
|
||||
cg->upvarList.count, cg->regexpList.length,
|
||||
cg->ntrynotes);
|
||||
cg->ntrynotes, cg->globalUses.length());
|
||||
if (!script)
|
||||
return NULL;
|
||||
|
||||
|
@ -1044,6 +1061,11 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
|
|||
cg->upvarMap.vector = NULL;
|
||||
}
|
||||
|
||||
if (cg->globalUses.length()) {
|
||||
memcpy(script->globals()->vector, &cg->globalUses[0],
|
||||
cg->globalUses.length() * sizeof(GlobalSlotArray::Entry));
|
||||
}
|
||||
|
||||
/*
|
||||
* We initialize fun->u.script to be the script constructed above
|
||||
* so that the debugger has a valid FUN_SCRIPT(fun).
|
||||
|
|
|
@ -86,6 +86,19 @@ typedef struct JSUpvarArray {
|
|||
uint32 length; /* count of indexed upvar cookies */
|
||||
} JSUpvarArray;
|
||||
|
||||
namespace js {
|
||||
|
||||
struct GlobalSlotArray {
|
||||
struct Entry {
|
||||
uint32 atomIndex; /* index into atom table */
|
||||
uint32 slot; /* global obj slot number */
|
||||
};
|
||||
Entry *vector;
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#define CALLEE_UPVAR_SLOT 0xffff
|
||||
#define FREE_STATIC_LEVEL 0x3fff
|
||||
#define FREE_UPVAR_COOKIE 0xffffffff
|
||||
|
@ -115,6 +128,8 @@ struct JSScript {
|
|||
regexps or 0 if none. */
|
||||
uint8 trynotesOffset; /* offset to the array of try notes or
|
||||
0 if none */
|
||||
uint8 globalsOffset; /* offset to the array of global slots or
|
||||
0 if none */
|
||||
bool noScriptRval:1; /* no need for result value of last
|
||||
expression statement */
|
||||
bool savedCallerFun:1; /* object 0 is caller function */
|
||||
|
@ -159,6 +174,11 @@ struct JSScript {
|
|||
return (JSTryNoteArray *) ((uint8 *) this + trynotesOffset);
|
||||
}
|
||||
|
||||
js::GlobalSlotArray *globals() {
|
||||
JS_ASSERT(globalsOffset != 0);
|
||||
return (js::GlobalSlotArray *) ((uint8 *)this + globalsOffset);
|
||||
}
|
||||
|
||||
JSAtom *getAtom(size_t index) {
|
||||
JS_ASSERT(index < atomMap.length);
|
||||
return atomMap.vector[index];
|
||||
|
@ -170,6 +190,18 @@ struct JSScript {
|
|||
return arr->vector[index];
|
||||
}
|
||||
|
||||
uint32 getGlobalSlot(size_t index) {
|
||||
js::GlobalSlotArray *arr = globals();
|
||||
JS_ASSERT(index < arr->length);
|
||||
return arr->vector[index].slot;
|
||||
}
|
||||
|
||||
JSAtom *getGlobalAtom(size_t index) {
|
||||
js::GlobalSlotArray *arr = globals();
|
||||
JS_ASSERT(index < arr->length);
|
||||
return getAtom(arr->vector[index].atomIndex);
|
||||
}
|
||||
|
||||
inline JSFunction *getFunction(size_t index);
|
||||
|
||||
inline JSObject *getRegExp(size_t index);
|
||||
|
@ -286,7 +318,7 @@ js_SweepScriptFilenames(JSRuntime *rt);
|
|||
extern JSScript *
|
||||
js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
|
||||
uint32 nobjects, uint32 nupvars, uint32 nregexps,
|
||||
uint32 ntrynotes);
|
||||
uint32 ntrynotes, uint32 nglobals);
|
||||
|
||||
extern JSScript *
|
||||
js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg);
|
||||
|
|
|
@ -13760,6 +13760,21 @@ TraceRecorder::record_JSOP_FORLOCAL()
|
|||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_FORGLOBAL()
|
||||
{
|
||||
LIns* v_ins;
|
||||
CHECK_STATUS_A(unboxNextValue(v_ins));
|
||||
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
set(&globalObj->getSlotRef(slot), v_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_POPN()
|
||||
{
|
||||
|
@ -15296,6 +15311,81 @@ TraceRecorder::record_JSOP_SHARPINIT()
|
|||
return ARECORD_STOP;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_GETGLOBAL()
|
||||
{
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
stack(0, get(&globalObj->getSlotRef(slot)));
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_SETGLOBAL()
|
||||
{
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
set(&globalObj->getSlotRef(slot), stack(-1));
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_CALLGLOBAL()
|
||||
{
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
jsval& v = globalObj->getSlotRef(slot);
|
||||
stack(0, get(&v));
|
||||
stack(1, INS_NULL());
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_GLOBALDEC()
|
||||
{
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
return InjectStatus(inc(globalObj->getSlotRef(slot), -1, false));
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_DECGLOBAL()
|
||||
{
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
return InjectStatus(inc(globalObj->getSlotRef(slot), -1, true));
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_INCGLOBAL()
|
||||
{
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
return InjectStatus(inc(globalObj->getSlotRef(slot), 1, true));
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_GLOBALINC()
|
||||
{
|
||||
uint32 slot = cx->fp->script->getGlobalSlot(GET_SLOTNO(cx->regs->pc));
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
RETURN_STOP_A("lazy import of global slot failed");
|
||||
|
||||
return InjectStatus(inc(globalObj->getSlotRef(slot), 1, false));
|
||||
}
|
||||
|
||||
#define DBG_STUB(OP) \
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus \
|
||||
TraceRecorder::record_##OP() \
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
/* Test that NaN does not trigger js_InitMathClass & constants while parsing. */
|
||||
var NaN
|
||||
|
||||
var x = 2;
|
||||
|
Загрузка…
Ссылка в новой задаче