mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
- Fix shapeless callee guarding to guard on function object value.
- Add JSOP_NULLTHIS to help the tracer guard shapeless callees (see trace-tests.js) - Culled bogus record_JSOP_CALLGVAR left-over forwarding to record_JSOP_GETGVAR. - Better shapeless callee tests.
This commit is contained in:
parent
a67dad8f4d
commit
64fc3b0367
@ -5868,9 +5868,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
default:
|
||||
/*
|
||||
* Push null as a placeholder for the global object, per ECMA-262
|
||||
* 11.2.3 step 6.
|
||||
* 11.2.3 step 6. We use JSOP_NULLTHIS to distinguish this opcode
|
||||
* from JSOP_NULL (see jstracer.cpp for one use-case).
|
||||
*/
|
||||
if (!js_EmitTree(cx, cg, pn2) || js_Emit1(cx, cg, JSOP_NULL) < 0)
|
||||
if (!js_EmitTree(cx, cg, pn2))
|
||||
return JS_FALSE;
|
||||
if (js_Emit1(cx, cg, JSOP_NULLTHIS) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -2413,9 +2413,10 @@ JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
|
||||
|
||||
/*
|
||||
* Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
|
||||
* remain distinct for the decompiler.
|
||||
* remain distinct for the decompiler. Ditto for JSOP_NULL{,THIS}.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
|
||||
JS_STATIC_ASSERT(JSOP_NULL_LENGTH == JSOP_NULLTHIS_LENGTH);
|
||||
|
||||
/* Ensure we can share deffun and closure code. */
|
||||
JS_STATIC_ASSERT(JSOP_DEFFUN_LENGTH == JSOP_CLOSURE_LENGTH);
|
||||
@ -5226,6 +5227,7 @@ js_Interpret(JSContext *cx)
|
||||
END_CASE(JSOP_ONE)
|
||||
|
||||
BEGIN_CASE(JSOP_NULL)
|
||||
BEGIN_CASE(JSOP_NULLTHIS)
|
||||
PUSH_OPND(JSVAL_NULL);
|
||||
END_CASE(JSOP_NULL)
|
||||
|
||||
|
@ -187,7 +187,9 @@ OPDEF(JSOP_STRICTNE, 73, "strictne", NULL, 1, 2, 1, 10, JOF_BYTE|
|
||||
/* Lexical closure constructor. */
|
||||
OPDEF(JSOP_CLOSURE, 74, "closure", NULL, 3, 0, 0, 0, JOF_OBJECT)
|
||||
|
||||
OPDEF(JSOP_UNUSED75, 75, "unused75", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
/* Variant of JSOP_NULL for default (global) |this| parameter pushing. */
|
||||
OPDEF(JSOP_NULLTHIS, 75, js_null_str, js_null_str, 1, 0, 1, 19, JOF_BYTE)
|
||||
|
||||
OPDEF(JSOP_UNUSED76, 76, "unused76", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_UNUSED77, 77, "unused77", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_UNUSED78, 78, "unused78", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
@ -3119,68 +3119,16 @@ TraceRecorder::record_JSOP_CALLNAME()
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_math_sin(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_cos(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_pow(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_sqrt(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_substring(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_fromCharCode(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_charCodeAt(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_charAt(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_concat(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_random(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_floor(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
bool
|
||||
TraceRecorder::guardInterpretedFunction(JSFunction* fun, LIns* fun_ins)
|
||||
{
|
||||
if (FUN_INTERPRETED(fun)) {
|
||||
guard(false,
|
||||
lir->ins_eq0(lir->ins2(LIR_and,
|
||||
lir->insLoadi(fun_ins, offsetof(JSFunction, flags) & ~3),
|
||||
lir->insImm(
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
JSFUN_INTERPRETED << 16
|
||||
#else
|
||||
JSFUN_INTERPRETED
|
||||
#endif
|
||||
))));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::guardShapelessCallee(jsval& callee)
|
||||
{
|
||||
if (JSVAL_IS_PRIMITIVE(callee))
|
||||
return false;
|
||||
if (!VALUE_IS_FUNCTION(cx, callee))
|
||||
ABORT_TRACE("shapeless callee is not a function");
|
||||
|
||||
JSObject* callee_obj = JSVAL_TO_OBJECT(callee);
|
||||
LIns* callee_ins = get(&callee);
|
||||
return guardClass(callee_obj, callee_ins, &js_FunctionClass) &&
|
||||
guardInterpretedFunction(GET_FUNCTION_PRIVATE(cx, callee_obj), callee_ins);
|
||||
guard(true,
|
||||
addName(lir->ins2(LIR_eq, get(&callee), lir->insImmPtr((void*) JSVAL_TO_OBJECT(callee))),
|
||||
"guard(shapeless callee)"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -3216,6 +3164,39 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_math_sin(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_cos(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_pow(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_sqrt(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_substring(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_fromCharCode(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_charCodeAt(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_charAt(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_str_concat(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_random(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
JSBool
|
||||
js_math_floor(JSContext* cx, uintN argc, jsval* vp);
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_CALL()
|
||||
{
|
||||
@ -4761,10 +4742,10 @@ TraceRecorder::record_JSOP_CALLGVAR()
|
||||
if (!lazilyImportGlobalSlot(slot))
|
||||
ABORT_TRACE("lazy import of global slot failed");
|
||||
|
||||
jsval* vp = &STOBJ_GET_SLOT(cx->fp->scopeChain, slot);
|
||||
stack(0, get(vp));
|
||||
jsval& v = STOBJ_GET_SLOT(cx->fp->scopeChain, slot);
|
||||
stack(0, get(&v));
|
||||
stack(1, lir->insImmPtr(NULL));
|
||||
return record_JSOP_GETGVAR() && guardShapelessCallee(*vp);
|
||||
return guardShapelessCallee(v);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4785,6 +4766,13 @@ TraceRecorder::record_JSOP_CALLARG()
|
||||
return guardShapelessCallee(argval(slot));
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_NULLTHIS()
|
||||
{
|
||||
stack(0, lir->insImmPtr(NULL));
|
||||
return guardShapelessCallee(stackval(-1));
|
||||
}
|
||||
|
||||
bool
|
||||
TraceRecorder::record_JSOP_INT8()
|
||||
{
|
||||
@ -4847,7 +4835,6 @@ TraceRecorder::record_JSOP_HOLE()
|
||||
|
||||
#define UNUSED(op) bool TraceRecorder::record_##op() { return false; }
|
||||
|
||||
UNUSED(JSOP_UNUSED75)
|
||||
UNUSED(JSOP_UNUSED76)
|
||||
UNUSED(JSOP_UNUSED77)
|
||||
UNUSED(JSOP_UNUSED78)
|
||||
|
@ -286,7 +286,6 @@ class TraceRecorder {
|
||||
bool guardDenseArrayIndex(JSObject* obj, jsint idx, nanojit::LIns* obj_ins,
|
||||
nanojit::LIns* dslots_ins, nanojit::LIns* idx_ins);
|
||||
void clearFrameSlotsFromCache();
|
||||
bool guardInterpretedFunction(JSFunction* fun, nanojit::LIns* fun_ins);
|
||||
bool guardShapelessCallee(jsval& callee);
|
||||
bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc);
|
||||
bool forInProlog(JSObject*& iterobj, nanojit::LIns*& iterobj_ins);
|
||||
|
@ -515,51 +515,73 @@ function newTest()
|
||||
newTest.expected = "0123456789";
|
||||
test(newTest);
|
||||
|
||||
function shapelessArgCalleeLoop(f, a)
|
||||
{
|
||||
for (var i = 0; i < 10; i++)
|
||||
f(i, a);
|
||||
}
|
||||
|
||||
function shapelessVarCalleeLoop(f, a)
|
||||
{
|
||||
var g = f;
|
||||
for (var i = 0; i < 10; i++)
|
||||
g(i, a);
|
||||
}
|
||||
|
||||
function shapelessLetCalleeLoop(f, a)
|
||||
// The following functions use a delay line of length 2 to change the value
|
||||
// of the callee without exiting the traced loop. This is obviously tuned to
|
||||
// match the current HOTLOOP setting of 2.
|
||||
function shapelessArgCalleeLoop(f, g, h, a)
|
||||
{
|
||||
for (var i = 0; i < 10; i++) {
|
||||
let g = f;
|
||||
g(i, a);
|
||||
f(i, a);
|
||||
f = g;
|
||||
g = h;
|
||||
}
|
||||
}
|
||||
|
||||
function shapelessUnknownCalleeLoop(f, g, a)
|
||||
function shapelessVarCalleeLoop(f0, g, h, a)
|
||||
{
|
||||
var f = f0;
|
||||
for (var i = 0; i < 10; i++) {
|
||||
f(i, a);
|
||||
f = g;
|
||||
g = h;
|
||||
}
|
||||
}
|
||||
|
||||
function shapelessLetCalleeLoop(f0, g, h, a)
|
||||
{
|
||||
for (var i = 0; i < 10; i++) {
|
||||
(f || g)(i, a);
|
||||
f = null;
|
||||
let f = f0;
|
||||
f(i, a);
|
||||
f = g;
|
||||
g = h;
|
||||
}
|
||||
}
|
||||
|
||||
function shapelessUnknownCalleeLoop(n, f, g, h, a)
|
||||
{
|
||||
for (var i = 0; i < 10; i++) {
|
||||
(n || f)(i, a);
|
||||
f = g;
|
||||
g = h;
|
||||
}
|
||||
}
|
||||
|
||||
function shapelessCalleeTest()
|
||||
{
|
||||
var a = [];
|
||||
shapelessArgCalleeLoop(function (i, a) a[i] = i, a);
|
||||
shapelessVarCalleeLoop(function (i, a) a[10 + i] = i, a);
|
||||
shapelessLetCalleeLoop(function (i, a) a[20 + i] = i, a);
|
||||
shapelessUnknownCalleeLoop(null, function (i, a) a[30 + i] = i, a);
|
||||
|
||||
var helper = function (i, a) a[i] = i;
|
||||
shapelessArgCalleeLoop(helper, helper, function (i, a) a[i] = -i, a);
|
||||
|
||||
helper = function (i, a) a[10 + i] = i;
|
||||
shapelessVarCalleeLoop(helper, helper, function (i, a) a[10 + i] = -i, a);
|
||||
|
||||
helper = function (i, a) a[20 + i] = i;
|
||||
shapelessLetCalleeLoop(helper, helper, function (i, a) a[20 + i] = -i, a);
|
||||
|
||||
helper = function (i, a) a[30 + i] = i;
|
||||
shapelessUnknownCalleeLoop(null, helper, helper, function (i, a) a[30 + i] = -i, a);
|
||||
|
||||
try {
|
||||
shapelessUnknownCalleeLoop(null, {hack: 42}, a);
|
||||
helper = {hack: 42};
|
||||
shapelessUnknownCalleeLoop(null, helper, helper, helper, a);
|
||||
} catch (e) {
|
||||
if (e + "" != "TypeError: g is not a function")
|
||||
print("shapelessUnknownCalleeLoop: unexpected exception " + e);
|
||||
}
|
||||
return a.join("");
|
||||
}
|
||||
shapelessCalleeTest.expected = "0123456789012345678901234567890123456789";
|
||||
shapelessCalleeTest.expected = "01-2-3-4-5-6-7-8-901-2-3-4-5-6-7-8-9012345678901-2-3-4-5-6-7-8-9";
|
||||
test(shapelessCalleeTest);
|
||||
|
||||
function typeofTest()
|
||||
|
Loading…
Reference in New Issue
Block a user