mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 561359 - Change JSOP_LAMBDA to apply the method optimization deterministically. In particular, it no longer depends on whether enclosing Blocks have been reified. This prevents incorrect behavior and assertions when a JSOP_LAMBDA, JSOP_INITMETHOD pair apply the method optimization once, populating the property cache, but later the same JSOP_LAMBDA instruction does not (under the old code) apply the optimization. With this patch, if JSOP_LAMBDA pushes the uncloned function once, it always will. r=brendan.
This commit is contained in:
parent
f93c39ea90
commit
efd9982808
@ -218,8 +218,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
|
|||||||
/*
|
/*
|
||||||
* Wrappers should really be parented to the wrapped parent of the wrapped
|
* Wrappers should really be parented to the wrapped parent of the wrapped
|
||||||
* object, but in that case a wrapped global object would have a NULL
|
* object, but in that case a wrapped global object would have a NULL
|
||||||
* parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead
|
* parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead,
|
||||||
,
|
|
||||||
* we parent all wrappers to the global object in their home compartment.
|
* we parent all wrappers to the global object in their home compartment.
|
||||||
* This loses us some transparency, and is generally very cheesy.
|
* This loses us some transparency, and is generally very cheesy.
|
||||||
*/
|
*/
|
||||||
|
@ -5588,10 +5588,9 @@ BEGIN_CASE(JSOP_LAMBDA)
|
|||||||
/* do-while(0) so we can break instead of using a goto. */
|
/* do-while(0) so we can break instead of using a goto. */
|
||||||
do {
|
do {
|
||||||
JSObject *parent;
|
JSObject *parent;
|
||||||
if (FUN_NULL_CLOSURE(fun)) {
|
if (fun->joinable()) {
|
||||||
parent = ®s.fp->scopeChain();
|
parent = ®s.fp->scopeChain();
|
||||||
|
|
||||||
if (obj->getParent() == parent) {
|
|
||||||
jsbytecode *pc2 = AdvanceOverBlockchainOp(regs.pc + JSOP_LAMBDA_LENGTH);
|
jsbytecode *pc2 = AdvanceOverBlockchainOp(regs.pc + JSOP_LAMBDA_LENGTH);
|
||||||
JSOp op2 = JSOp(*pc2);
|
JSOp op2 = JSOp(*pc2);
|
||||||
|
|
||||||
@ -5670,7 +5669,6 @@ BEGIN_CASE(JSOP_LAMBDA)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (rt->functionMeterFilename) {
|
if (rt->functionMeterFilename) {
|
||||||
|
@ -313,7 +313,9 @@ bool
|
|||||||
JSFunctionBox::joinable() const
|
JSFunctionBox::joinable() const
|
||||||
{
|
{
|
||||||
return FUN_NULL_CLOSURE((JSFunction *) object) &&
|
return FUN_NULL_CLOSURE((JSFunction *) object) &&
|
||||||
!(tcflags & (TCF_FUN_USES_ARGUMENTS | TCF_FUN_USES_OWN_NAME));
|
(tcflags & (TCF_FUN_USES_ARGUMENTS |
|
||||||
|
TCF_FUN_USES_OWN_NAME |
|
||||||
|
TCF_COMPILE_N_GO)) == TCF_COMPILE_N_GO;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -4732,8 +4734,6 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc)
|
|||||||
|
|
||||||
#endif /* JS_HAS_DESTRUCTURING */
|
#endif /* JS_HAS_DESTRUCTURING */
|
||||||
|
|
||||||
extern const char js_with_statement_str[];
|
|
||||||
|
|
||||||
static JSParseNode *
|
static JSParseNode *
|
||||||
ContainsStmt(JSParseNode *pn, TokenKind tt)
|
ContainsStmt(JSParseNode *pn, TokenKind tt)
|
||||||
{
|
{
|
||||||
|
@ -15556,7 +15556,7 @@ TraceRecorder::record_JSOP_LAMBDA()
|
|||||||
* JSOP_INITMETHOD logic governing the early ARECORD_CONTINUE returns below
|
* JSOP_INITMETHOD logic governing the early ARECORD_CONTINUE returns below
|
||||||
* must agree with the corresponding break-from-do-while(0) logic there.
|
* must agree with the corresponding break-from-do-while(0) logic there.
|
||||||
*/
|
*/
|
||||||
if (FUN_NULL_CLOSURE(fun) && FUN_OBJECT(fun)->getParent() == &cx->fp()->scopeChain()) {
|
if (fun->joinable()) {
|
||||||
jsbytecode *pc2 = AdvanceOverBlockchainOp(cx->regs->pc + JSOP_LAMBDA_LENGTH);
|
jsbytecode *pc2 = AdvanceOverBlockchainOp(cx->regs->pc + JSOP_LAMBDA_LENGTH);
|
||||||
JSOp op2 = JSOp(*pc2);
|
JSOp op2 = JSOp(*pc2);
|
||||||
|
|
||||||
|
@ -1419,33 +1419,42 @@ stubs::RegExp(VMFrame &f, JSObject *regex)
|
|||||||
JSObject * JS_FASTCALL
|
JSObject * JS_FASTCALL
|
||||||
stubs::LambdaForInit(VMFrame &f, JSFunction *fun)
|
stubs::LambdaForInit(VMFrame &f, JSFunction *fun)
|
||||||
{
|
{
|
||||||
|
JS_ASSERT(fun->joinable());
|
||||||
|
JS_ASSERT(FUN_NULL_CLOSURE(fun));
|
||||||
|
JS_ASSERT(f.fp()->script()->compileAndGo);
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
|
JS_ASSERT(obj->getParent() != NULL);
|
||||||
|
|
||||||
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc)));
|
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc)));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
|
||||||
return Lambda(f, fun);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject * JS_FASTCALL
|
JSObject * JS_FASTCALL
|
||||||
stubs::LambdaForSet(VMFrame &f, JSFunction *fun)
|
stubs::LambdaForSet(VMFrame &f, JSFunction *fun)
|
||||||
{
|
{
|
||||||
|
JS_ASSERT(fun->joinable());
|
||||||
|
JS_ASSERT(FUN_NULL_CLOSURE(fun));
|
||||||
|
JS_ASSERT(f.fp()->script()->compileAndGo);
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
|
JS_ASSERT(obj->getParent() != NULL);
|
||||||
|
|
||||||
const Value &lref = f.regs.sp[-1];
|
const Value &lref = f.regs.sp[-1];
|
||||||
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
|
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
|
||||||
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc)));
|
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc)));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Lambda(f, fun);
|
return Lambda(f, fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject * JS_FASTCALL
|
JSObject * JS_FASTCALL
|
||||||
stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
|
stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
|
||||||
{
|
{
|
||||||
|
JS_ASSERT(fun->joinable());
|
||||||
|
JS_ASSERT(FUN_NULL_CLOSURE(fun));
|
||||||
|
JS_ASSERT(f.fp()->script()->compileAndGo);
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
|
JS_ASSERT(obj->getParent() != NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Array.prototype.sort and String.prototype.replace are
|
* Array.prototype.sort and String.prototype.replace are
|
||||||
* optimized as if they are special form. We know that they
|
* optimized as if they are special form. We know that they
|
||||||
@ -1474,7 +1483,6 @@ stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Lambda(f, fun);
|
return Lambda(f, fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,10 @@ script regress-559438.js
|
|||||||
script regress-560101.js
|
script regress-560101.js
|
||||||
script regress-560998-1.js
|
script regress-560998-1.js
|
||||||
script regress-560998-2.js
|
script regress-560998-2.js
|
||||||
|
script regress-561359-1.js
|
||||||
|
script regress-561359-2.js
|
||||||
|
script regress-561359-3.js
|
||||||
|
script regress-561359-4.js
|
||||||
script regress-563210.js
|
script regress-563210.js
|
||||||
script regress-563221.js
|
script regress-563221.js
|
||||||
script regress-566549.js
|
script regress-566549.js
|
||||||
|
13
js/src/tests/js1_8_5/regress/regress-561359-1.js
Normal file
13
js/src/tests/js1_8_5/regress/regress-561359-1.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
// Contributor: Gary Kwong <gary@rumblingedge.com>
|
||||||
|
|
||||||
|
for (let z = 0; z < 2; z++) {
|
||||||
|
with({
|
||||||
|
x: function() {}
|
||||||
|
}) {
|
||||||
|
for (l in [x]) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reportCompare(0, 0, 'ok');
|
14
js/src/tests/js1_8_5/regress/regress-561359-2.js
Normal file
14
js/src/tests/js1_8_5/regress/regress-561359-2.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
// Contributor: Jason Orendorff <jorendorff@mozilla.com>
|
||||||
|
|
||||||
|
function f(s) {
|
||||||
|
var obj = {m: function () { return a; }};
|
||||||
|
eval(s);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
var obj = f("var a = 'right';");
|
||||||
|
var a = 'wrong';
|
||||||
|
assertEq(obj.m(), 'right');
|
||||||
|
|
||||||
|
reportCompare(0, 0, 'ok');
|
13
js/src/tests/js1_8_5/regress/regress-561359-3.js
Normal file
13
js/src/tests/js1_8_5/regress/regress-561359-3.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
// Contributor: Jason Orendorff <jorendorff@mozilla.com>
|
||||||
|
|
||||||
|
function f(s) {
|
||||||
|
with (s)
|
||||||
|
return {m: function () { return a; }};
|
||||||
|
}
|
||||||
|
var obj = f({a: 'right'});
|
||||||
|
var a = 'wrong';
|
||||||
|
assertEq(obj.m(), 'right');
|
||||||
|
|
||||||
|
reportCompare(0, 0, 'ok');
|
10
js/src/tests/js1_8_5/regress/regress-561359-4.js
Normal file
10
js/src/tests/js1_8_5/regress/regress-561359-4.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
// Contributor: Jason Orendorff <jorendorff@mozilla.com>
|
||||||
|
|
||||||
|
var x;
|
||||||
|
for (let i = 0; i < 2; i++)
|
||||||
|
x = {m: function () {}, n: function () { i++; }};
|
||||||
|
x.m;
|
||||||
|
|
||||||
|
reportCompare(0, 0, 'ok');
|
Loading…
Reference in New Issue
Block a user