зеркало из https://github.com/mozilla/pjs.git
Fix unqualified function invocation etc., part deux (635582, r=gal).
This commit is contained in:
Родитель
4260195b08
Коммит
36a3bd94b5
|
@ -3,5 +3,10 @@ var sb = evalcx('');
|
|||
sb.name = "inner";
|
||||
sb.parent = this;
|
||||
function f() { return this.name; }
|
||||
assertEq(evalcx('this.f = parent.f; var s = ""; for (i = 0; i < 10; ++i) s += f(); s', sb),
|
||||
assertEq(evalcx('this.f = parent.f;\n' +
|
||||
'var s = "";\n' +
|
||||
'for (i = 0; i < 10; ++i)\n' +
|
||||
' s += f();\n' +
|
||||
's',
|
||||
sb),
|
||||
"innerinnerinnerinnerinnerinnerinnerinnerinnerinner");
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
this.name = "outer";
|
||||
var sb = evalcx('');
|
||||
sb.name = "inner";
|
||||
sb.parent = this;
|
||||
function f() { return this.name; }
|
||||
f.notMuchTodo = '42';
|
||||
assertEq(evalcx('{\n' +
|
||||
' let f = parent.f;\n' +
|
||||
' let name = "block";\n' +
|
||||
' (function () {\n' +
|
||||
' eval(f.notMuchTodo);\n' + // reify Block
|
||||
' var s = "";\n' +
|
||||
' for (i = 0; i < 10; ++i)\n' +
|
||||
' s += f();\n' +
|
||||
' return s;\n' +
|
||||
' })();\n' +
|
||||
'}',
|
||||
sb),
|
||||
"outerouterouterouterouterouterouterouterouterouter");
|
|
@ -0,0 +1,20 @@
|
|||
this.name = "outer";
|
||||
var sb = evalcx('');
|
||||
sb.name = "inner";
|
||||
sb.parent = this;
|
||||
function f() { return this.name; }
|
||||
f.notMuchTodo = '42';
|
||||
assertEq(evalcx('(function () {\n' +
|
||||
' arguments = null;\n' + // force heavyweight
|
||||
' var f = parent.f;\n' +
|
||||
' var name = "call";\n' +
|
||||
' return (function () {\n' +
|
||||
' eval(f.notMuchTodo);\n' + // reify Call, make f() compile to JSOP_CALLNAME
|
||||
' var s = "";\n' +
|
||||
' for (i = 0; i < 10; ++i)\n' +
|
||||
' s += f();\n' +
|
||||
' return s;\n' +
|
||||
' })();\n' +
|
||||
'})()',
|
||||
sb),
|
||||
"outerouterouterouterouterouterouterouterouterouter");
|
|
@ -0,0 +1,15 @@
|
|||
this.name = "outer";
|
||||
var sb = evalcx('');
|
||||
sb.name = "inner";
|
||||
sb.parent = this;
|
||||
this.f = function name(outer) {
|
||||
if (outer) return name(false);
|
||||
return this.name;
|
||||
}
|
||||
assertEq(evalcx('this.f = parent.f;\n' +
|
||||
'var s = "";\n' +
|
||||
'for (i = 0; i < 10; ++i)\n' +
|
||||
' s += f(true);\n' +
|
||||
's',
|
||||
sb),
|
||||
"outerouterouterouterouterouterouterouterouterouter");
|
|
@ -55,11 +55,16 @@ static inline bool
|
|||
IsSafeForLazyThisCoercion(JSContext *cx, JSObject *callee)
|
||||
{
|
||||
/*
|
||||
* Look past any wrappers. If the callee is a strict function it is always
|
||||
* safe because we won't do 'this' coercion in strict mode. Otherwise the
|
||||
* callee is only safe to transform into the lazy 'this' token (undefined)
|
||||
* if it is in the current scope. Without this restriction, lazy 'this'
|
||||
* coercion would pick up the wrong global in the other scope.
|
||||
* Look past any function wrappers. If the callee is a wrapped strict-mode
|
||||
* function, lazy 'this' coercion is vacuously safe because strict-mode
|
||||
* functions don't coerce 'this' at all. Otherwise, the callee is safe to
|
||||
* transform into the lazy 'this' cookie (the undefined value) only if it
|
||||
* is in the current scope.
|
||||
*
|
||||
* Without this restriction, lazy 'this' coercion would pick up the "wrong"
|
||||
* global at the end of the callee function object's scope, rather than the
|
||||
* "right" (backward compatible since 1995) global that was the "Reference
|
||||
* base object" in the callee expression.
|
||||
*/
|
||||
if (callee->isProxy()) {
|
||||
callee = callee->unwrap();
|
||||
|
|
|
@ -2179,11 +2179,12 @@ ScriptPrologue(JSContext *cx, JSStackFrame *fp)
|
|||
}
|
||||
|
||||
static inline bool
|
||||
SlowThis(JSContext *cx, JSObject *obj, const Value &funval, Value *vp)
|
||||
ComputeThis(JSContext *cx, JSObject *obj, const Value &funval, Value *vp)
|
||||
{
|
||||
if (!funval.isObject() ||
|
||||
((obj->isGlobal() || IsCacheableNonGlobalScope(obj)) &&
|
||||
IsSafeForLazyThisCoercion(cx, &funval.toObject()))) {
|
||||
(obj->isGlobal()
|
||||
? IsSafeForLazyThisCoercion(cx, &funval.toObject())
|
||||
: IsCacheableNonGlobalScope(obj))) {
|
||||
/*
|
||||
* We can avoid computing 'this' eagerly and push the implicit 'this'
|
||||
* value (undefined), as long the scope is cachable and we are not
|
||||
|
@ -4816,10 +4817,10 @@ BEGIN_CASE(JSOP_SETCALL)
|
|||
}
|
||||
END_CASE(JSOP_SETCALL)
|
||||
|
||||
#define SLOW_PUSH_THISV(cx, obj, funval) \
|
||||
#define PUSH_THISV(cx, obj, funval) \
|
||||
JS_BEGIN_MACRO \
|
||||
Value v; \
|
||||
if (!SlowThis(cx, obj, funval, &v)) \
|
||||
if (!ComputeThis(cx, obj, funval, &v)) \
|
||||
goto error; \
|
||||
PUSH_COPY(v); \
|
||||
JS_END_MACRO \
|
||||
|
@ -4853,16 +4854,8 @@ BEGIN_CASE(JSOP_CALLNAME)
|
|||
}
|
||||
|
||||
JS_ASSERT(obj->isGlobal() || IsCacheableNonGlobalScope(obj));
|
||||
if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME) {
|
||||
if (regs.sp[-1].isObject() &&
|
||||
!IsSafeForLazyThisCoercion(cx, ®s.sp[-1].toObject())) {
|
||||
if (!(obj = obj->thisObject(cx)))
|
||||
return false;
|
||||
PUSH_OBJECT(*obj);
|
||||
} else {
|
||||
PUSH_UNDEFINED();
|
||||
}
|
||||
}
|
||||
if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
|
||||
PUSH_THISV(cx, obj, regs.sp[-1]);
|
||||
len = JSOP_NAME_LENGTH;
|
||||
DO_NEXT_OP(len);
|
||||
}
|
||||
|
@ -4900,7 +4893,7 @@ BEGIN_CASE(JSOP_CALLNAME)
|
|||
|
||||
/* obj must be on the scope chain, thus not a function. */
|
||||
if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
|
||||
SLOW_PUSH_THISV(cx, obj, rval);
|
||||
PUSH_THISV(cx, obj, rval);
|
||||
}
|
||||
END_CASE(JSOP_NAME)
|
||||
|
||||
|
@ -6403,7 +6396,7 @@ BEGIN_CASE(JSOP_XMLNAME)
|
|||
goto error;
|
||||
regs.sp[-1] = rval;
|
||||
if (op == JSOP_CALLXMLNAME)
|
||||
SLOW_PUSH_THISV(cx, obj, rval);
|
||||
PUSH_THISV(cx, obj, rval);
|
||||
}
|
||||
END_CASE(JSOP_XMLNAME)
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче