mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Checkpoint arguments tour-de-force (453730).
This commit is contained in:
parent
ff7bea2566
commit
fc936fa1da
@ -98,6 +98,10 @@ BUILTIN3(Object_p_propertyIsEnumerable,
|
||||
BUILTIN2(BooleanToNumber, LO, LO, F, jsdouble, JSContext*, jsint, 1, 1)
|
||||
BUILTIN2(ObjectToString, LO, LO, P, JSString*, JSContext*, JSObject*, 0, 0)
|
||||
BUILTIN3(Array_1int, LO, LO, LO, P, JSObject*, JSContext*, JSObject*, jsint, 0, 0)
|
||||
BUILTIN3(Array_1str, LO, LO, LO, P, JSObject*, JSContext*, JSObject*, JSString*, 0, 0)
|
||||
BUILTIN4(Array_2obj, LO, LO, LO, LO, P, JSObject*, JSContext*, JSObject*, JSObject*, JSObject**, 0, 0)
|
||||
BUILTIN5(Array_3num, LO, LO, F, F, F, P, JSObject*, JSContext*, JSObject*, jsdouble, jsdouble, jsdouble, 0, 0)
|
||||
BUILTIN1(Arguments, LO, P, JSObject*, JSContext*, 0, 0)
|
||||
|
||||
// soft float
|
||||
BUILTIN1(fneg, F, F, jsdouble, jsdouble, 1, 1)
|
||||
@ -112,6 +116,3 @@ BUILTIN2(fmul, F, F, F, jsdouble, jsdouble, jsdouble, 1, 1)
|
||||
BUILTIN2(fadd, F, F, F, jsdouble, jsdouble, jsdouble, 1, 1)
|
||||
BUILTIN2(fdiv, F, F, F, jsdouble, jsdouble, jsdouble, 1, 1)
|
||||
BUILTIN2(fsub, F, F, F, jsdouble, jsdouble, jsdouble, 1, 1)
|
||||
BUILTIN3(Array_1str, LO, LO, LO, P, JSObject*, JSContext*, JSObject*, JSString*, 0, 0)
|
||||
BUILTIN4(Array_2obj, LO, LO, LO, LO, P, JSObject*, JSContext*, JSObject*, JSObject*, JSObject**, 0, 0)
|
||||
BUILTIN5(Array_3num, LO, LO, F, F, F, P, JSObject*, JSContext*, JSObject*, jsdouble, jsdouble, jsdouble, 0, 0)
|
||||
|
@ -718,6 +718,12 @@ js_Array_3num(JSContext* cx, JSObject* proto, jsdouble n1, jsdouble n2, jsdouble
|
||||
return NULL;)
|
||||
}
|
||||
|
||||
JSObject* FASTCALL
|
||||
js_Arguments(JSContext* cx)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* soft float */
|
||||
|
||||
jsdouble FASTCALL
|
||||
|
@ -347,7 +347,7 @@ static bool isPromoteInt(LIns* i)
|
||||
{
|
||||
jsdouble d;
|
||||
return isi2f(i) || i->isconst() ||
|
||||
(i->isconstq() && ((d = i->constvalf()) == (jsdouble)(jsint)d) && !JSDOUBLE_IS_NEGZERO(d));
|
||||
(i->isconstq() && (d = i->constvalf()) == jsdouble(jsint(d)) && !JSDOUBLE_IS_NEGZERO(d));
|
||||
}
|
||||
|
||||
static bool isPromoteUint(LIns* i)
|
||||
@ -803,8 +803,9 @@ TraceRecorder::TraceRecorder(JSContext* cx, GuardRecord* _anchor, Fragment* _fra
|
||||
this->callDepth = _fragment->calldepth;
|
||||
JS_ASSERT(!_anchor || _anchor->calldepth == _fragment->calldepth);
|
||||
this->atoms = cx->fp->script->atomMap.vector;
|
||||
this->trashTree = false;
|
||||
this->deepAborted = false;
|
||||
this->applyingArguments = false;
|
||||
this->trashTree = false;
|
||||
this->whichTreeToTrash = _fragment->root;
|
||||
|
||||
debug_only_v(printf("recording starting from %s:%u@%u\n", cx->fp->script->filename,
|
||||
@ -1353,8 +1354,8 @@ TraceRecorder::set(jsval* p, LIns* i, bool initializing)
|
||||
/* If we are writing to this location for the first time, calculate the offset into the
|
||||
native frame manually, otherwise just look up the last load or store associated with
|
||||
the same source address (p) and use the same offset/base. */
|
||||
LIns* x;
|
||||
if ((x = nativeFrameTracker.get(p)) == NULL) {
|
||||
LIns* x = nativeFrameTracker.get(p);
|
||||
if (!x) {
|
||||
if (isGlobal(p))
|
||||
x = writeBack(i, gp_ins, nativeGlobalOffset(p));
|
||||
else
|
||||
@ -2481,6 +2482,11 @@ bool
|
||||
js_MonitorRecording(JSContext* cx)
|
||||
{
|
||||
TraceRecorder *tr = JS_TRACE_MONITOR(cx).recorder;
|
||||
|
||||
// Clear one-shot flag used to communicate between record_JSOP_CALL and record_EnterFrame.
|
||||
tr->applyingArguments = false;
|
||||
|
||||
// Process deepAbort() requests now.
|
||||
if (tr->wasDeepAborted()) {
|
||||
js_AbortRecording(cx, NULL, "deep abort requested");
|
||||
return false;
|
||||
@ -3644,10 +3650,20 @@ TraceRecorder::record_EnterFrame()
|
||||
|
||||
jsval* vp = &fp->argv[fp->argc];
|
||||
jsval* vpstop = vp + (fp->fun->nargs - fp->argc);
|
||||
while (vp < vpstop) {
|
||||
if (vp >= fp->down->regs->sp)
|
||||
if (applyingArguments) {
|
||||
applyingArguments = false;
|
||||
while (vp < vpstop) {
|
||||
JS_ASSERT(vp >= fp->down->regs->sp);
|
||||
nativeFrameTracker.set(vp, (LIns*)0);
|
||||
set(vp++, void_ins, true);
|
||||
LIns* arg_ins = get(&fp->down->argv[fp->argc + (vp - vpstop)]);
|
||||
set(vp++, arg_ins, true);
|
||||
}
|
||||
} else {
|
||||
while (vp < vpstop) {
|
||||
if (vp >= fp->down->regs->sp)
|
||||
nativeFrameTracker.set(vp, (LIns*)0);
|
||||
set(vp++, void_ins, true);
|
||||
}
|
||||
}
|
||||
|
||||
vp = &fp->slots[0];
|
||||
@ -3742,7 +3758,11 @@ TraceRecorder::record_JSOP_IFNE()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_ARGUMENTS()
|
||||
{
|
||||
return false;
|
||||
LIns* args[] = { cx_ins };
|
||||
LIns* a_ins = lir->insCall(F_Arguments, args);
|
||||
guard(false, lir->ins_eq0(a_ins), OOM_EXIT);
|
||||
stack(0, a_ins);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4549,10 +4569,11 @@ KNOWN_NATIVE_DECL(js_str_substring)
|
||||
bool
|
||||
TraceRecorder::record_JSOP_CALL()
|
||||
{
|
||||
jsbytecode *pc = cx->fp->regs->pc;
|
||||
JSStackFrame* fp = cx->fp;
|
||||
jsbytecode *pc = fp->regs->pc;
|
||||
uintN argc = GET_ARGC(pc);
|
||||
jsval& fval = stackval(0 - (argc + 2));
|
||||
JS_ASSERT(&fval >= StackBase(cx->fp));
|
||||
JS_ASSERT(&fval >= StackBase(fp));
|
||||
|
||||
jsval& tval = stackval(0 - (argc + 1));
|
||||
LIns* this_ins = get(&tval);
|
||||
@ -4618,6 +4639,11 @@ TraceRecorder::record_JSOP_CALL()
|
||||
if (argc != 2)
|
||||
ABORT_TRACE("can't trace Function.prototype.apply with other than 2 args");
|
||||
|
||||
if (!guardShapelessCallee(tval))
|
||||
return false;
|
||||
JSObject* tfunobj = JSVAL_TO_OBJECT(tval);
|
||||
JSFunction* tfun = GET_FUNCTION_PRIVATE(cx, tfunobj);
|
||||
|
||||
jsval& oval = stackval(-2);
|
||||
if (JSVAL_IS_PRIMITIVE(oval))
|
||||
ABORT_TRACE("can't trace Function.prototype.apply with primitive 1st arg");
|
||||
@ -4625,22 +4651,54 @@ TraceRecorder::record_JSOP_CALL()
|
||||
jsval& aval = stackval(-1);
|
||||
if (JSVAL_IS_PRIMITIVE(aval))
|
||||
ABORT_TRACE("can't trace Function.prototype.apply with primitive 2nd arg");
|
||||
JSObject* aobj = JSVAL_TO_OBJECT(aval);
|
||||
|
||||
LIns* aval_ins = get(&aval);
|
||||
if (!aval_ins->isCall() || aval_ins->fid() != F_Array_1str)
|
||||
ABORT_TRACE("can't yet trace Function.prototype.apply on other than [str] 2nd arg");
|
||||
if (!aval_ins->isCall())
|
||||
ABORT_TRACE("can't trace Function.prototype.apply on non-builtin-call 2nd arg");
|
||||
|
||||
if (aval_ins->fid() == F_Arguments) {
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, aobj) == &js_ArgumentsClass);
|
||||
JS_ASSERT(OBJ_GET_PRIVATE(cx, aobj) == fp);
|
||||
if (!FUN_INTERPRETED(tfun))
|
||||
ABORT_TRACE("can't trace Function.prototype.apply(native_function, arguments)");
|
||||
|
||||
argc = fp->argc;
|
||||
if (tfun->nargs != argc)
|
||||
ABORT_TRACE("can't trace Function.prototype.apply(scripted_function, arguments)");
|
||||
|
||||
jsval* sp = fp->regs->sp - 4;
|
||||
set(sp, get(&tval));
|
||||
*sp++ = tval;
|
||||
set(sp, get(&oval));
|
||||
*sp++ = oval;
|
||||
jsval* newsp = sp + argc;
|
||||
if (newsp > fp->slots + fp->script->nslots) {
|
||||
JSArena* a = cx->stackPool.current;
|
||||
if (jsuword(newsp) > a->limit)
|
||||
ABORT_TRACE("can't grow stack for Function.prototype.apply");
|
||||
if (jsuword(newsp) > a->avail)
|
||||
a->avail = jsuword(newsp);
|
||||
}
|
||||
|
||||
jsval* argv = fp->argv;
|
||||
for (uintN i = 0; i < JS_MIN(argc, 2); i++) {
|
||||
set(&sp[i], get(&argv[i]));
|
||||
sp[i] = argv[i];
|
||||
}
|
||||
applyingArguments = true;
|
||||
return interpretedFunctionCall(tval, tfun, argc);
|
||||
}
|
||||
|
||||
if (aval_ins->fid() != F_Array_1str)
|
||||
ABORT_TRACE("can't trace Function.prototype.apply on other than [str] 2nd arg");
|
||||
|
||||
JSObject* aobj = JSVAL_TO_OBJECT(aval);
|
||||
JS_ASSERT(OBJ_IS_ARRAY(cx, aobj));
|
||||
JS_ASSERT(aobj->fslots[JSSLOT_ARRAY_LENGTH] == 1);
|
||||
JS_ASSERT(JSVAL_IS_STRING(aobj->dslots[0]));
|
||||
|
||||
if (!guardShapelessCallee(tval))
|
||||
return false;
|
||||
JSObject* tfunobj = JSVAL_TO_OBJECT(tval);
|
||||
JSFunction* tfun = GET_FUNCTION_PRIVATE(cx, tfunobj);
|
||||
if (FUN_INTERPRETED(tfun))
|
||||
ABORT_TRACE("can't yet trace Function.prototype.apply for scripted functions");
|
||||
ABORT_TRACE("can't trace Function.prototype.apply for scripted functions");
|
||||
|
||||
JSTraceableNative* known;
|
||||
for (;;) {
|
||||
@ -4907,7 +4965,7 @@ bool
|
||||
TraceRecorder::elem(jsval& l, jsval& r, jsval*& vp, LIns*& v_ins, LIns*& addr_ins)
|
||||
{
|
||||
/* no guards for type checks, trace specialized this already */
|
||||
if (!JSVAL_IS_INT(r) || JSVAL_IS_PRIMITIVE(l))
|
||||
if (JSVAL_IS_PRIMITIVE(l) || !JSVAL_IS_INT(r))
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -5672,13 +5730,27 @@ TraceRecorder::record_JSOP_NOP()
|
||||
bool
|
||||
TraceRecorder::record_JSOP_ARGSUB()
|
||||
{
|
||||
return false;
|
||||
JSStackFrame* fp = cx->fp;
|
||||
if (!(fp->fun->flags & JSFUN_HEAVYWEIGHT)) {
|
||||
uintN slot = GET_ARGNO(fp->regs->pc);
|
||||
if (slot < fp->argc && !fp->argsobj) {
|
||||
stack(0, get(&cx->fp->argv[slot]));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ABORT_TRACE("can't trace JSOP_ARGSUB hard case");
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_ARGCNT()
|
||||
{
|
||||
return false;
|
||||
if (!(cx->fp->fun->flags & JSFUN_HEAVYWEIGHT)) {
|
||||
jsdpun u;
|
||||
u.d = cx->fp->argc;
|
||||
stack(0, lir->insImmq(u.u64));
|
||||
return true;
|
||||
}
|
||||
ABORT_TRACE("can't trace heavyweight JSOP_ARGCNT");
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -232,8 +232,9 @@ class TraceRecorder {
|
||||
nanojit::LIns* rval_ins;
|
||||
nanojit::LIns* inner_sp_ins;
|
||||
nanojit::SideExit exit;
|
||||
bool trashTree;
|
||||
bool deepAborted;
|
||||
bool applyingArguments;
|
||||
bool trashTree;
|
||||
nanojit::Fragment* whichTreeToTrash;
|
||||
Queue<jsbytecode*> inlinedLoopEdges;
|
||||
Queue<jsbytecode*> cfgMerges;
|
||||
@ -331,7 +332,10 @@ class TraceRecorder {
|
||||
|
||||
void trackCfgMerges(jsbytecode* pc);
|
||||
void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
|
||||
|
||||
public:
|
||||
friend bool js_MonitorRecording(JSContext* cx);
|
||||
|
||||
TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*, TreeInfo*,
|
||||
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
|
||||
nanojit::GuardRecord* expectedInnerExit);
|
||||
@ -370,8 +374,7 @@ public:
|
||||
TraceRecorder* r = JS_TRACE_MONITOR(cx).recorder; \
|
||||
if (!js_MonitorRecording(cx)) { \
|
||||
ENABLE_TRACER(0); \
|
||||
} else \
|
||||
if (!r->record_##x()) { \
|
||||
} else if (!r->record_##x()) { \
|
||||
js_AbortRecording(cx, NULL, #x); \
|
||||
ENABLE_TRACER(0); \
|
||||
} \
|
||||
|
@ -1211,6 +1211,64 @@ function testTypeofHole() {
|
||||
testTypeofHole.expected = "undefined,undefined,undefined,undefined,undefined,number"
|
||||
test(testTypeofHole);
|
||||
|
||||
function test_JSOP_ARGSUB() {
|
||||
function f0() { return arguments[0]; }
|
||||
function f1() { return arguments[1]; }
|
||||
function f2() { return arguments[2]; }
|
||||
function f3() { return arguments[3]; }
|
||||
function f4() { return arguments[4]; }
|
||||
function f5() { return arguments[5]; }
|
||||
function f6() { return arguments[6]; }
|
||||
function f7() { return arguments[7]; }
|
||||
function f8() { return arguments[8]; }
|
||||
function f9() { return arguments[9]; }
|
||||
var a = [];
|
||||
for (var i = 0; i < 10; i++) {
|
||||
a[0] = f0('a');
|
||||
a[1] = f1('a','b');
|
||||
a[2] = f2('a','b','c');
|
||||
a[3] = f3('a','b','c','d');
|
||||
a[4] = f4('a','b','c','d','e');
|
||||
a[5] = f5('a','b','c','d','e','f');
|
||||
a[6] = f6('a','b','c','d','e','f','g');
|
||||
a[7] = f7('a','b','c','d','e','f','g','h');
|
||||
a[8] = f8('a','b','c','d','e','f','g','h','i');
|
||||
a[9] = f9('a','b','c','d','e','f','g','h','i','j');
|
||||
}
|
||||
return a.join("");
|
||||
}
|
||||
test_JSOP_ARGSUB.expected = "abcdefghij";
|
||||
test(test_JSOP_ARGSUB);
|
||||
|
||||
function test_JSOP_ARGCNT() {
|
||||
function f0() { return arguments.length; }
|
||||
function f1() { return arguments.length; }
|
||||
function f2() { return arguments.length; }
|
||||
function f3() { return arguments.length; }
|
||||
function f4() { return arguments.length; }
|
||||
function f5() { return arguments.length; }
|
||||
function f6() { return arguments.length; }
|
||||
function f7() { return arguments.length; }
|
||||
function f8() { return arguments.length; }
|
||||
function f9() { return arguments.length; }
|
||||
var a = [];
|
||||
for (var i = 0; i < 10; i++) {
|
||||
a[0] = f0('a');
|
||||
a[1] = f1('a','b');
|
||||
a[2] = f2('a','b','c');
|
||||
a[3] = f3('a','b','c','d');
|
||||
a[4] = f4('a','b','c','d','e');
|
||||
a[5] = f5('a','b','c','d','e','f');
|
||||
a[6] = f6('a','b','c','d','e','f','g');
|
||||
a[7] = f7('a','b','c','d','e','f','g','h');
|
||||
a[8] = f8('a','b','c','d','e','f','g','h','i');
|
||||
a[9] = f9('a','b','c','d','e','f','g','h','i','j');
|
||||
}
|
||||
return a.join(",");
|
||||
}
|
||||
test_JSOP_ARGCNT.expected = "1,2,3,4,5,6,7,8,9,10";
|
||||
test(test_JSOP_ARGCNT);
|
||||
|
||||
/* Keep these at the end so that we can see the summary after the trace-debug spew. */
|
||||
print("\npassed:", passes.length && passes.join(","));
|
||||
print("\nFAILED:", fails.length && fails.join(","));
|
||||
|
Loading…
Reference in New Issue
Block a user