mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 517117: don't trace JSOP_ARGCNT if arguments.length has been overridden, r=dvander
--HG-- extra : rebase_source : a53403064c533bdc3270408f0d29eeec12970040
This commit is contained in:
parent
28f39d7f60
commit
b152e9656d
@ -81,43 +81,6 @@
|
||||
|
||||
#include "jsatominlines.h"
|
||||
|
||||
/*
|
||||
* Reserved slot structure for Arguments objects:
|
||||
*
|
||||
* JSSLOT_PRIVATE - the corresponding frame until the frame exits.
|
||||
* JSSLOT_ARGS_LENGTH - the number of actual arguments and a flag indicating
|
||||
* whether arguments.length was overwritten.
|
||||
* JSSLOT_ARGS_CALLEE - the arguments.callee value or JSVAL_HOLE if that was
|
||||
* overwritten.
|
||||
* JSSLOT_ARGS_COPY_START .. - room to store the corresponding arguments after
|
||||
* the frame exists. The slot's value will be JSVAL_HOLE
|
||||
* if arguments[i] was deleted or overwritten.
|
||||
*/
|
||||
const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
|
||||
const uint32 JSSLOT_ARGS_CALLEE = JSSLOT_PRIVATE + 2;
|
||||
const uint32 JSSLOT_ARGS_COPY_START = JSSLOT_PRIVATE + 3;
|
||||
|
||||
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
|
||||
const uint32 ARGS_CLASS_FIXED_RESERVED_SLOTS = JSSLOT_ARGS_COPY_START -
|
||||
JSSLOT_ARGS_LENGTH;
|
||||
|
||||
/*
|
||||
* JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as int jsval.
|
||||
* Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must fit JSVAL_INT_MAX. To assert that
|
||||
* we check first that the shift does not overflow uint32.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30));
|
||||
JS_STATIC_ASSERT(jsval((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX);
|
||||
|
||||
static inline bool
|
||||
IsOverriddenArgsLength(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass);
|
||||
|
||||
jsval v = obj->fslots[JSSLOT_ARGS_LENGTH];
|
||||
return (JSVAL_TO_INT(v) & 1) != 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
SetOverriddenArgsLength(JSObject *obj)
|
||||
{
|
||||
@ -136,7 +99,7 @@ InitArgsLengthSlot(JSObject *obj, uint32 argc)
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
JS_ASSERT(obj->fslots[JSSLOT_ARGS_LENGTH] == JSVAL_VOID);
|
||||
obj->fslots[JSSLOT_ARGS_LENGTH] = INT_TO_JSVAL(argc << 1);
|
||||
JS_ASSERT(!IsOverriddenArgsLength(obj));
|
||||
JS_ASSERT(!js_IsOverriddenArgsLength(obj));
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
@ -225,7 +188,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp)
|
||||
}
|
||||
} else if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
|
||||
JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj);
|
||||
if (argsobj && IsOverriddenArgsLength(argsobj))
|
||||
if (argsobj && js_IsOverriddenArgsLength(argsobj))
|
||||
return argsobj->getProperty(cx, id, vp);
|
||||
*vp = INT_TO_JSVAL(jsint(fp->argc));
|
||||
}
|
||||
@ -561,7 +524,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp)
|
||||
}
|
||||
}
|
||||
} else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
|
||||
if (!IsOverriddenArgsLength(obj))
|
||||
if (!js_IsOverriddenArgsLength(obj))
|
||||
*vp = INT_TO_JSVAL(GetArgsLength(obj));
|
||||
} else {
|
||||
JS_ASSERT(idval == ATOM_KEY(cx->runtime->atomState.calleeAtom));
|
||||
@ -641,7 +604,7 @@ args_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
|
||||
id = INT_JSVAL_TO_JSID(idval);
|
||||
}
|
||||
} else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
|
||||
if (!IsOverriddenArgsLength(obj))
|
||||
if (!js_IsOverriddenArgsLength(obj))
|
||||
id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
|
||||
} else if (idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)) {
|
||||
|
@ -334,6 +334,43 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp);
|
||||
extern void
|
||||
js_PutArgsObject(JSContext *cx, JSStackFrame *fp);
|
||||
|
||||
/*
|
||||
* Reserved slot structure for Arguments objects:
|
||||
*
|
||||
* JSSLOT_PRIVATE - the corresponding frame until the frame exits.
|
||||
* JSSLOT_ARGS_LENGTH - the number of actual arguments and a flag indicating
|
||||
* whether arguments.length was overwritten.
|
||||
* JSSLOT_ARGS_CALLEE - the arguments.callee value or JSVAL_HOLE if that was
|
||||
* overwritten.
|
||||
* JSSLOT_ARGS_COPY_START .. - room to store the corresponding arguments after
|
||||
* the frame exists. The slot's value will be JSVAL_HOLE
|
||||
* if arguments[i] was deleted or overwritten.
|
||||
*/
|
||||
const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
|
||||
const uint32 JSSLOT_ARGS_CALLEE = JSSLOT_PRIVATE + 2;
|
||||
const uint32 JSSLOT_ARGS_COPY_START = JSSLOT_PRIVATE + 3;
|
||||
|
||||
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
|
||||
const uint32 ARGS_CLASS_FIXED_RESERVED_SLOTS = JSSLOT_ARGS_COPY_START -
|
||||
JSSLOT_ARGS_LENGTH;
|
||||
|
||||
/*
|
||||
* JSSLOT_ARGS_LENGTH stores ((argc << 1) | overwritten_flag) as int jsval.
|
||||
* Thus (JS_ARGS_LENGTH_MAX << 1) | 1 must fit JSVAL_INT_MAX. To assert that
|
||||
* we check first that the shift does not overflow uint32.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30));
|
||||
JS_STATIC_ASSERT(jsval((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX);
|
||||
|
||||
JS_INLINE bool
|
||||
js_IsOverriddenArgsLength(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_ArgumentsClass);
|
||||
|
||||
jsval v = obj->fslots[JSSLOT_ARGS_LENGTH];
|
||||
return (JSVAL_TO_INT(v) & 1) != 0;
|
||||
}
|
||||
|
||||
extern JSBool
|
||||
js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
|
||||
|
||||
|
@ -12710,13 +12710,17 @@ TraceRecorder::record_JSOP_ARGCNT()
|
||||
// argc is fixed on trace, so ideally we would simply generate LIR for
|
||||
// constant argc. But the user can mutate arguments.length in the
|
||||
// interpreter, so we have to check for that in the trace entry frame.
|
||||
// We also have to check that arguments.length has not been mutated
|
||||
// at record time, because if so we will generate incorrect constant
|
||||
// LIR, which will assert in alu().
|
||||
if (cx->fp->argsobj && js_IsOverriddenArgsLength(JSVAL_TO_OBJECT(cx->fp->argsobj)))
|
||||
ABORT_TRACE("can't trace JSOP_ARGCNT if arguments.length has been modified");
|
||||
LIns *a_ins = get(&cx->fp->argsobj);
|
||||
if (callDepth == 0) {
|
||||
LIns *br = lir->insBranch(LIR_jt, lir->ins_peq0(a_ins), NULL);
|
||||
|
||||
// The following implements IsOverriddenArgsLength on trace.
|
||||
// The '2' bit is set set if length was overridden.
|
||||
const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
|
||||
// The following implements js_IsOverriddenArgsLength on trace.
|
||||
// The '2' bit is set if length was overridden.
|
||||
LIns *len_ins = stobj_get_fslot(a_ins, JSSLOT_ARGS_LENGTH);
|
||||
LIns *ovr_ins = lir->ins2(LIR_piand, len_ins, INS_CONSTWORD(2));
|
||||
|
||||
|
12
js/src/trace-test/tests/basic/setArgumentsLength2.js
Normal file
12
js/src/trace-test/tests/basic/setArgumentsLength2.js
Normal file
@ -0,0 +1,12 @@
|
||||
// don't crash
|
||||
|
||||
var q;
|
||||
|
||||
function f() {
|
||||
while (arguments.length > 0) {
|
||||
q = arguments[arguments.length-1];
|
||||
arguments.length--;
|
||||
}
|
||||
}
|
||||
|
||||
f(1, 2, 3, 4, 5);
|
Loading…
Reference in New Issue
Block a user