mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Avoid JSOP_POPV in global scripts from load(), etc.
This commit is contained in:
parent
4560ed961f
commit
a8c6046d8c
@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
@ -269,12 +269,12 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
|
||||
ungetc(ch, file);
|
||||
|
||||
oldopts = JS_GetOptions(cx);
|
||||
JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO);
|
||||
JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
|
||||
script = JS_CompileFileHandle(cx, obj, filename, file);
|
||||
JS_SetOptions(cx, oldopts);
|
||||
if (script) {
|
||||
if (!compileOnly)
|
||||
(void)JS_ExecuteScript(cx, obj, script, &result);
|
||||
(void)JS_ExecuteScript(cx, obj, script, NULL);
|
||||
JS_DestroyScript(cx, script);
|
||||
}
|
||||
|
||||
@ -653,14 +653,14 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
filename = JS_GetStringBytes(str);
|
||||
errno = 0;
|
||||
oldopts = JS_GetOptions(cx);
|
||||
JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO);
|
||||
JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
|
||||
script = JS_CompileFile(cx, obj, filename);
|
||||
JS_SetOptions(cx, oldopts);
|
||||
if (!script) {
|
||||
ok = JS_FALSE;
|
||||
} else {
|
||||
ok = !compileOnly
|
||||
? JS_ExecuteScript(cx, obj, script, &result)
|
||||
? JS_ExecuteScript(cx, obj, script, NULL)
|
||||
: JS_TRUE;
|
||||
JS_DestroyScript(cx, script);
|
||||
}
|
||||
@ -1437,7 +1437,7 @@ DisassFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
|
||||
filename = JS_GetStringBytes(str);
|
||||
oldopts = JS_GetOptions(cx);
|
||||
JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO);
|
||||
JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
|
||||
script = JS_CompileFile(cx, obj, filename);
|
||||
JS_SetOptions(cx, oldopts);
|
||||
if (!script)
|
||||
|
@ -4585,6 +4585,10 @@ JS_CompileUCScript(JSContext *cx, JSObject *obj,
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#define JS_OPTIONS_TO_TCFLAGS(cx) \
|
||||
((((cx)->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | \
|
||||
(((cx)->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0))
|
||||
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
||||
JSPrincipals *principals,
|
||||
@ -4595,7 +4599,7 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
||||
JSScript *script;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
|
||||
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
||||
script = js_CompileScript(cx, obj, principals, tcflags,
|
||||
chars, length, NULL, filename, lineno);
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
@ -4661,7 +4665,7 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
|
||||
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
||||
script = js_CompileScript(cx, obj, NULL, tcflags,
|
||||
NULL, 0, fp, filename, 1);
|
||||
if (fp != stdin)
|
||||
@ -4686,7 +4690,7 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
|
||||
JSScript *script;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
tcflags = JS_HAS_COMPILE_N_GO_OPTION(cx) ? TCF_COMPILE_N_GO : 0;
|
||||
tcflags = JS_OPTIONS_TO_TCFLAGS(cx);
|
||||
script = js_CompileScript(cx, obj, principals, tcflags,
|
||||
NULL, 0, file, filename, 1);
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
@ -5022,7 +5026,10 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
||||
JSBool ok;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
script = js_CompileScript(cx, obj, principals, TCF_COMPILE_N_GO,
|
||||
script = js_CompileScript(cx, obj, principals,
|
||||
!rval
|
||||
? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
|
||||
: TCF_COMPILE_N_GO,
|
||||
chars, length, NULL, filename, lineno);
|
||||
if (!script)
|
||||
return JS_FALSE;
|
||||
|
@ -588,6 +588,11 @@ JS_StringToVersion(const char *string);
|
||||
|
||||
#define JSOPTION_JIT JS_BIT(11) /* Enable JIT compilation. */
|
||||
|
||||
#define JSOPTION_NO_SCRIPT_RVAL JS_BIT(12) /* A promise to the compiler
|
||||
that a null rval out-param
|
||||
will be passed to each call
|
||||
to JS_ExecuteScript. */
|
||||
|
||||
extern JS_PUBLIC_API(uint32)
|
||||
JS_GetOptions(JSContext *cx);
|
||||
|
||||
|
@ -5225,8 +5225,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* debugger, and eval frames may need the value of the ultimate
|
||||
* expression statement as the script's result, despite the fact
|
||||
* that it appears useless to the compiler.
|
||||
*
|
||||
* API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
|
||||
* calling JS_Compile* suppress JSOP_POPV.
|
||||
*/
|
||||
useful = wantval = !(cg->treeContext.flags & TCF_IN_FUNCTION);
|
||||
useful = wantval =
|
||||
!(cg->treeContext.flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));
|
||||
if (!useful) {
|
||||
if (!CheckSideEffects(cx, cg, pn2, &useful))
|
||||
return JS_FALSE;
|
||||
|
@ -193,6 +193,8 @@ struct JSTreeContext { /* tree context for semantic checks */
|
||||
#define TCF_COMPILE_N_GO 0x800 /* compiler-and-go mode of script, can
|
||||
optimize name references based on scope
|
||||
chain */
|
||||
#define TCF_NO_SCRIPT_RVAL 0x1000 /* API caller does not want result value
|
||||
from global script */
|
||||
|
||||
/*
|
||||
* Flags to propagate out of the blocks.
|
||||
|
@ -1554,7 +1554,8 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
}
|
||||
|
||||
ok = js_Interpret(cx);
|
||||
*result = frame.rval;
|
||||
if (result)
|
||||
*result = frame.rval;
|
||||
|
||||
if (hookData) {
|
||||
hook = cx->debugHooks->executeHook;
|
||||
|
@ -566,7 +566,7 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
||||
void *sbrk(ptrdiff_t), *before = sbrk(0);
|
||||
#endif
|
||||
|
||||
JS_ASSERT(!(tcflags & ~TCF_COMPILE_N_GO));
|
||||
JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL)));
|
||||
|
||||
if (!js_InitParseContext(cx, &pc, principals, chars, length, file,
|
||||
filename, lineno)) {
|
||||
|
@ -69,7 +69,7 @@
|
||||
/* Number of times we wait to exit on a side exit before we try to extend the tree. */
|
||||
#define HOTEXIT 0
|
||||
|
||||
/* Maximum number of guards after which we no longer try to demote loop variables.
|
||||
/* Maximum number of guards after which we no longer try to demote loop variables.
|
||||
0=off */
|
||||
#define DEMOTE_THRESHOLD 32
|
||||
|
||||
@ -311,7 +311,7 @@ public:
|
||||
out->insGuard(LIR_xt, out->ins1(LIR_ov, result), recorder.snapshot());
|
||||
return out->ins1(LIR_i2f, result);
|
||||
}
|
||||
} else if (v == LIR_or &&
|
||||
} else if (v == LIR_or &&
|
||||
s0->isop(LIR_lsh) && isconst(s0->oprnd2(), 16) &&
|
||||
s1->isop(LIR_and) && isconst(s1->oprnd2(), 0xffff)) {
|
||||
LIns* msw = s0->oprnd1();
|
||||
@ -319,12 +319,12 @@ public:
|
||||
LIns* x;
|
||||
LIns* y;
|
||||
if (lsw->isop(LIR_add) &&
|
||||
lsw->oprnd1()->isop(LIR_and) &&
|
||||
lsw->oprnd1()->isop(LIR_and) &&
|
||||
lsw->oprnd2()->isop(LIR_and) &&
|
||||
isconst(lsw->oprnd1()->oprnd2(), 0xffff) &&
|
||||
isconst(lsw->oprnd1()->oprnd2(), 0xffff) &&
|
||||
isconst(lsw->oprnd2()->oprnd2(), 0xffff) &&
|
||||
msw->isop(LIR_add) &&
|
||||
msw->oprnd1()->isop(LIR_add) &&
|
||||
msw->isop(LIR_add) &&
|
||||
msw->oprnd1()->isop(LIR_add) &&
|
||||
msw->oprnd2()->isop(LIR_rsh) &&
|
||||
msw->oprnd1()->oprnd1()->isop(LIR_rsh) &&
|
||||
msw->oprnd1()->oprnd2()->isop(LIR_rsh) &&
|
||||
@ -408,7 +408,7 @@ public:
|
||||
JS_END_MACRO
|
||||
|
||||
/* This macro can be used to iterate over all slots in currently pending
|
||||
frames that make up the native frame, consisting of rval, args, vars,
|
||||
frames that make up the native frame, consisting of rval, args, vars,
|
||||
and stack (except for the top-level frame which does not have args or vars. */
|
||||
#define FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth, code) \
|
||||
JS_BEGIN_MACRO \
|
||||
@ -504,12 +504,12 @@ TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor,
|
||||
#endif
|
||||
ptrdiff_t offset = 0;
|
||||
FORALL_GLOBAL_SLOTS(cx, treeInfo->ngslots, treeInfo->gslots,
|
||||
import(gp_ins, offset, vp, *m, vpname, vpnum, localNames);
|
||||
import(gp_ins, offset, vp, *m, vpname, vpnum, localNames);
|
||||
m++; offset += sizeof(double);
|
||||
);
|
||||
offset = -treeInfo->nativeStackBase + 8;
|
||||
FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
|
||||
import(lirbuf->sp, offset, vp, *m, vpname, vpnum, localNames);
|
||||
import(lirbuf->sp, offset, vp, *m, vpname, vpnum, localNames);
|
||||
m++; offset += sizeof(double);
|
||||
);
|
||||
#ifdef DEBUG
|
||||
@ -596,7 +596,7 @@ findInternableGlobals(JSContext* cx, JSStackFrame* fp, uint16* slots)
|
||||
|
||||
/* Calculate the total number of native frame slots we need from this frame
|
||||
all the way back to the entry frame, including the current stack usage. */
|
||||
static unsigned nativeStackSlots(unsigned callDepth,
|
||||
static unsigned nativeStackSlots(unsigned callDepth,
|
||||
JSStackFrame* fp, JSFrameRegs& regs)
|
||||
{
|
||||
unsigned slots = 0;
|
||||
@ -618,17 +618,17 @@ TraceRecorder::nativeGlobalOffset(jsval* p) const
|
||||
size_t offset = 0;
|
||||
unsigned ngslots = treeInfo->ngslots;
|
||||
uint16* gslots = treeInfo->gslots;
|
||||
for (unsigned n = 0; n < ngslots; ++n, offset += sizeof(double))
|
||||
if (p == &STOBJ_GET_SLOT(globalObj, gslots[n]))
|
||||
for (unsigned n = 0; n < ngslots; ++n, offset += sizeof(double))
|
||||
if (p == &STOBJ_GET_SLOT(globalObj, gslots[n]))
|
||||
return offset;
|
||||
return -1; /* not a global */
|
||||
}
|
||||
|
||||
|
||||
/* Determine the offset in the native stack for a jsval we track */
|
||||
ptrdiff_t
|
||||
TraceRecorder::nativeStackOffset(jsval* p) const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
size_t slow_offset = 0;
|
||||
FORALL_SLOTS_IN_PENDING_FRAMES(cx, callDepth,
|
||||
if (vp == p) goto done;
|
||||
@ -638,7 +638,7 @@ TraceRecorder::nativeStackOffset(jsval* p) const
|
||||
sp but below script->depth */
|
||||
JS_ASSERT(size_t(p - StackBase(cx->fp)) < StackDepth(cx->fp->script));
|
||||
slow_offset += size_t(p - cx->fp->regs->sp) * sizeof(double);
|
||||
done:
|
||||
done:
|
||||
#define RETURN(offset) { JS_ASSERT((offset) == slow_offset); return offset; }
|
||||
#else
|
||||
#define RETURN(offset) { return offset; }
|
||||
@ -657,7 +657,7 @@ done:
|
||||
for (;; fp = fp->down) { *fsp-- = fp; if (fp == entryFrame) break; }
|
||||
for (fsp = fstack; fsp < fspstop; ++fsp) {
|
||||
JSStackFrame* f = *fsp;
|
||||
if (p == &f->rval)
|
||||
if (p == &f->rval)
|
||||
RETURN(offset);
|
||||
offset += sizeof(double);
|
||||
if (f->callee) {
|
||||
@ -677,7 +677,7 @@ done:
|
||||
JS_ASSERT(size_t(p - StackBase(currentFrame)) < StackDepth(currentFrame->script));
|
||||
offset += size_t(p - currentFrame->regs->sp) * sizeof(double);
|
||||
RETURN(offset);
|
||||
#undef RETURN
|
||||
#undef RETURN
|
||||
}
|
||||
|
||||
/* Track the maximum number of native frame slots we need during
|
||||
@ -870,7 +870,7 @@ box(JSContext* cx, unsigned ngslots, uint16* gslots, unsigned callDepth,
|
||||
|
||||
/* Emit load instructions onto the trace that read the initial stack state. */
|
||||
void
|
||||
TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, uint8& t,
|
||||
TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, uint8& t,
|
||||
const char *prefix, int index, jsuword *localNames)
|
||||
{
|
||||
JS_ASSERT(TYPEMAP_GET_TYPE(t) != TYPEMAP_TYPE_ANY);
|
||||
@ -931,7 +931,7 @@ TraceRecorder::set(jsval* p, LIns* i, bool initializing)
|
||||
if ((x = nativeFrameTracker.get(p)) == NULL) {
|
||||
ptrdiff_t offset = nativeGlobalOffset(p);
|
||||
nativeFrameTracker.set(p, (offset == -1) /* not a global */
|
||||
? lir->insStorei(i, lirbuf->sp,
|
||||
? lir->insStorei(i, lirbuf->sp,
|
||||
-treeInfo->nativeStackBase + nativeStackOffset(p) + 8)
|
||||
: lir->insStorei(i, gp_ins,
|
||||
offset));
|
||||
@ -954,7 +954,7 @@ TraceRecorder::set(jsval* p, LIns* i, bool initializing)
|
||||
lir->insStorei(i, x->oprnd2(), x->immdisp());
|
||||
}
|
||||
}
|
||||
#undef ASSERT_VALID_CACHE_HIT
|
||||
#undef ASSERT_VALID_CACHE_HIT
|
||||
}
|
||||
|
||||
LIns*
|
||||
@ -1078,7 +1078,7 @@ TraceRecorder::checkType(jsval& v, uint8& t)
|
||||
#ifdef DEBUG
|
||||
ptrdiff_t offset;
|
||||
printf("demoting type of a slot #%d failed, locking it and re-compiling\n",
|
||||
((offset = nativeGlobalOffset(&v)) == -1)
|
||||
((offset = nativeGlobalOffset(&v)) == -1)
|
||||
? nativeStackOffset(&v)
|
||||
: offset);
|
||||
#endif
|
||||
@ -1236,7 +1236,7 @@ js_ExecuteTree(JSContext* cx, Fragment* f)
|
||||
debug_only(*(uint64*)&global[ti->ngslots] = 0xdeadbeefdeadbeefLL;)
|
||||
double* stack = (double *)alloca((ti->maxNativeStackSlots+1) * sizeof(double));
|
||||
debug_only(*(uint64*)&stack[ti->maxNativeStackSlots] = 0xdeadbeefdeadbeefLL;)
|
||||
if (!unbox(cx, ti->ngslots, ti->gslots, 0 /*callDepth*/,
|
||||
if (!unbox(cx, ti->ngslots, ti->gslots, 0 /*callDepth*/,
|
||||
ti->typeMap, global, stack)) {
|
||||
AUDIT(typeMapMismatchAtEntry);
|
||||
debug_only(printf("type-map mismatch, skipping trace.\n");)
|
||||
@ -1271,13 +1271,13 @@ js_ExecuteTree(JSContext* cx, Fragment* f)
|
||||
state.sp, lr->jmp,
|
||||
(rdtsc() - start));
|
||||
#endif
|
||||
box(cx, ti->ngslots, ti->gslots, lr->calldepth,
|
||||
box(cx, ti->ngslots, ti->gslots, lr->calldepth,
|
||||
lr->exit->typeMap, global, stack);
|
||||
JS_ASSERT(*(uint64*)&stack[ti->maxNativeStackSlots] == 0xdeadbeefdeadbeefLL);
|
||||
JS_ASSERT(*(uint64*)&global[ti->ngslots] == 0xdeadbeefdeadbeefLL);
|
||||
|
||||
AUDIT(sideExitIntoInterpreter);
|
||||
|
||||
|
||||
return lr;
|
||||
}
|
||||
|
||||
@ -1394,10 +1394,10 @@ js_LoopEdge(JSContext* cx, jsbytecode* oldpc)
|
||||
}
|
||||
|
||||
GuardRecord* lr = js_ExecuteTree(cx, f);
|
||||
|
||||
|
||||
if (!lr) /* did the tree actually execute? */
|
||||
return false;
|
||||
|
||||
|
||||
/* if the side exit terminates the loop, don't try to attach a trace here */
|
||||
if (lr->exit->loopExit)
|
||||
return false;
|
||||
@ -1549,7 +1549,7 @@ TraceRecorder::inc(jsval& v, jsint incr, bool pre)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* On exit, v_ins is the incremented unboxed value, and the appropriate
|
||||
* value (pre- or post-increment as described by pre) is stacked.
|
||||
*/
|
||||
@ -2001,7 +2001,7 @@ TraceRecorder::record_EnterFrame()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
TraceRecorder::record_LeaveFrame()
|
||||
{
|
||||
if (callDepth-- <= 0)
|
||||
|
Loading…
Reference in New Issue
Block a user