Last Comment Bug 671947 - Unqualified function invocation uses the global object the property was gotten from as |this|
: Unqualified function invocation uses the global object the property was gotte...
Status: RESOLVED FIXED
: dev-doc-complete
Product: Core
Classification: Components
Component: JavaScript Engine (show other bugs)
: unspecified
: All All
: -- major with 1 vote (vote)
: mozilla8
Assigned To: Brendan Eich [:brendan]
:
: Jason Orendorff [:jorendorff]
Mentors:
Depends on: 634590 635582 636364 636795 636820 653959
Blocks:
  Show dependency treegraph
 
Reported: 2011-07-15 13:24 PDT by Brendan Eich [:brendan]
Modified: 2013-12-27 14:21 PST (History)
34 users (show)
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---
final+


Attachments
patch in progress (3.34 KB, patch)
2011-07-15 14:29 PDT, Brendan Eich [:brendan]
no flags Details | Diff | Splinter Review
proposed fix (10.53 KB, patch)
2011-07-15 17:32 PDT, Brendan Eich [:brendan]
no flags Details | Diff | Splinter Review
proposed fix, v2 (12.08 KB, patch)
2011-07-15 18:04 PDT, Brendan Eich [:brendan]
luke: review+
Details | Diff | Splinter Review
proposed fix, v3 (16.29 KB, patch)
2011-07-18 17:02 PDT, Brendan Eich [:brendan]
luke: review+
Details | Diff | Splinter Review

Description Brendan Eich [:brendan] 2011-07-15 13:24:58 PDT
See https://bugs.webkit.org/show_bug.cgi?id=64250 and kudos to Gavin and Oliver for blazing the trail toward ES5+multiple-globals righteousness.

We should try again, not so late in a cycle (with our new fast releases, this means nightly now targeting IINM Firefox 8), and evangelize any site or other content that breaks.

The V8 issue is http://code.google.com/p/v8/issues/detail?id=1547.

/be
Comment 1 Brendan Eich [:brendan] 2011-07-15 14:29:21 PDT
Created attachment 546226 [details] [diff] [review]
patch in progress

Needs the testcase. I have a js shell test based on Gavin Barraclough's version of the one I hacked up from Mark Miller's original HTML testcase.

It may be possible to minimize the patch further. This one does pass the test.

/be
Comment 2 Boris Zbarsky [:bz] (still a bit busy) 2011-07-15 16:16:55 PDT
I don't get it.

In strict mode, we don't have the bug that JSC had there, right?  If I modify the testcase in bug 634590 to use a strict-mode function then |this| is undefined.

So is this bug about changing the behavior of non-strict-mode functions?
Comment 3 Brendan Eich [:brendan] 2011-07-15 17:21:27 PDT
(In reply to comment #2)
> In strict mode, we don't have the bug that JSC had there, right?

In strict mode *where*? The test covers strict caller and strict callee. The issue for us is not strict callee (you always get 'u' as the returned char).

> If I
> modify the testcase in bug 634590 to use a strict-mode function then |this|
> is undefined.

Yes, that is not in dispute (at least not yet -- IE10pp still gets that wrong but that is just a bug, and the ES5 spec is black letter law when it comes to strict callee |this| binding).

> So is this bug about changing the behavior of non-strict-mode functions?

Non-strict callers -- yes, of course.

/be
Comment 4 Brendan Eich [:brendan] 2011-07-15 17:22:44 PDT
Waldo wanted to stick with ES5 in the Fx4 run-up, but it was not the time to break things. His desire is on target, though. ES5 is simpler, faster, and ocap secure. We are trying for a breaking change here. They've happened in the past, sometimes by accident. Better with intentional support.

/be
Comment 5 Brendan Eich [:brendan] 2011-07-15 17:32:55 PDT
Created attachment 546262 [details] [diff] [review]
proposed fix
Comment 6 Brendan Eich [:brendan] 2011-07-15 17:42:21 PDT
The workaround, of course, is to call with an explicit object.property() form of the callee expression. Instead of f() vs, (1, f)() having different |this| bindings, we fix the bug so they get the same |this| (the callee decides if it is non-strict to replace undefined with its global). If you want the caller's global because f is a property of that object, use this.f() or window.f().

/be
Comment 7 Boris Zbarsky [:bz] (still a bit busy) 2011-07-15 17:49:14 PDT
OK.  Seems like we should message that far and wide now-ish, given that we _know_ there's content depending on this behavior...

It still bothers me that we're intentionally changing something that works interoperably across all browsers.  :(
Comment 8 Brendan Eich [:brendan] 2011-07-15 18:04:29 PDT
Created attachment 546265 [details] [diff] [review]
proposed fix, v2

Two js1_8_5 tests needed tweaking.

/be
Comment 9 Brendan Eich [:brendan] 2011-07-15 18:26:50 PDT
(In reply to comment #7)
> OK.  Seems like we should message that far and wide now-ish, given that we
> _know_ there's content depending on this behavior...
> 
> It still bothers me that we're intentionally changing something that works
> interoperably across all browsers.  :(

Only Firefox (after Netscape) and IE did this anywhere near interoperably over the long haul. Chrome 12 and Opera 11.50 return 'i' not 'o' (and doesn't do ES5 yet). Safari JSC of course is changing, but not so long ago they did something incompatible, I'm told.

This is not a place where all the browsers have agreed for long, unless by "all" you mean IE and Mozilla. I agree that's a concern, but it isn't clear how big the compatibility constraint is given Chrome and Safari (until recently) differing from the top two.

/be
Comment 10 Boris Zbarsky [:bz] (still a bit busy) 2011-07-15 19:32:59 PDT
> Chrome 12 and Opera 11.50 return 'i' not 'o'

The testcase in bug 634590 comment 7 is interoperable in all browsers for a very liberal meaning of all (Chrome, Safari, Opera, us, IE).

I realize that there are other similar situations that are not interoperable.  But that particular situation _is_....  or am I missing something?
Comment 11 Brendan Eich [:brendan] 2011-07-15 21:33:09 PDT
(In reply to comment #10)
> > Chrome 12 and Opera 11.50 return 'i' not 'o'
> 
> The testcase in bug 634590 comment 7 is interoperable in all browsers for a
> very liberal meaning of all (Chrome, Safari, Opera, us, IE).
> 
> I realize that there are other similar situations that are not
> interoperable.  But that particular situation _is_....  or am I missing
> something?

No, you're right -- that one is the hard case. If it used window.f() instead of f(), it would work with this bug's patch. It may be not much content counts on the old behavior. It may be we can evangelize. Since JSC is trying to conform to ES5, we should too, and compare notes. Ideally V8 will match in nightlies of Chrome. We'll be talking to IE folks at the upcoming TC39 meeting.

/be
Comment 12 Luke Wagner [:luke] 2011-07-16 17:03:01 PDT
Comment on attachment 546265 [details] [diff] [review]
proposed fix, v2

Review of attachment 546265 [details] [diff] [review]:
-----------------------------------------------------------------

Great change!  I am happy to see the expected results for cross-global-implicit-this.js.

::: js/src/jsinterpinlines.h
@@ +211,5 @@
>   * Compute the implicit |this| parameter for a call expression where the callee
>   * is an unqualified name reference.
>   *
>   * We can avoid computing |this| eagerly and push the implicit callee-coerced
>   * |this| value, undefined, according to this decision tree:

Enough time has passed since I r+'d the last patch that I got to rediscover the magic of 'this' and re-understand this comment.  I think, in the new simplified world, we can simplify the comment as well.  How about something roughly like:

Dynamic name lookup found the callee 'funval' on 'obj'. This function computes the 'this' value to be passed when calling 'funval'. According to ES? ?.?.?, the correct 'this' value is:
 1. 'obj', if 'obj' is a 'with' object;
 2. 'undefined', if funval is a strict-mode function or not a function at all;
 3. the global of the callee's scope chain, otherwise.

As an optimization, JSOP_THIS in a non-strict function coerces 'undefined' to the global of the current scope chain. Thus case 3 also computes 'undefined'.

To discriminate case 1 from 2 and 3, the predicate IsCacheableNonGlobalScope is used. This predicate returns 'true' for normal lexical scope objects (Call, Block, DeclEnv) and 'false' for all others. As a side-effect, other types of objects on the scope chain (introduced through the JSAPI) get treated like 'with' objects.

::: js/src/tests/ecma_5/Global/cross-global-implicit-this.js
@@ +49,5 @@
> +       ' results += (function(){return eval("f()");})();\n' +
> +       ' /* Same cases as above, but wrapped in a with. The first & last of these cases pass b, */\n' +
> +       ' /* the object scoped by the with, as the this value. */\n' +
> +       ' /* a.f() still passes the explicit base, a. (1,f)() is a little tricksier - this passes */\n' +
> +       ' /* undefined (promoted to the callee global object) since teh comma operator calles GetValue */\n' +

teh
Comment 13 Luke Wagner [:luke] 2011-07-18 10:53:49 PDT
This is probably followup material (with a comment in this patch for future readers): I think generateGlobalStub can be optimized to not guard on the callee's global.
Comment 14 Brendan Eich [:brendan] 2011-07-18 15:09:04 PDT
(In reply to comment #13)
> This is probably followup material (with a comment in this patch for future
> readers): I think generateGlobalStub can be optimized to not guard on the
> callee's global.

Happy to do it here, just need a few minutes!

/be
Comment 15 Brendan Eich [:brendan] 2011-07-18 17:02:37 PDT
Created attachment 546677 [details] [diff] [review]
proposed fix, v3

I left the big comment more as before, but folded in good feedback from your last review -- thanks.

My reading of methodjit/Compiler.cpp jsop_this says this is correct, and tests all like it, but I need close reviewer attention.

/be
Comment 16 Luke Wagner [:luke] 2011-07-18 17:23:15 PDT
Comment on attachment 546677 [details] [diff] [review]
proposed fix, v3

Review of attachment 546677 [details] [diff] [review]:
-----------------------------------------------------------------
Comment 17 Brendan Eich [:brendan] 2011-07-20 14:40:32 PDT
http://hg.mozilla.org/integration/mozilla-inbound/rev/bedd0f79b82d

/be
Comment 18 Marco Bonardo [::mak] 2011-07-21 06:12:22 PDT
http://hg.mozilla.org/mozilla-central/rev/bedd0f79b82d
Comment 19 Jason Orendorff [:jorendorff] 2011-07-22 07:46:00 PDT
Brendan, this changeset added an entry to ecma_5/Global/jstests.list:

@@ -1,5 +1,6 @@
 url-prefix ../../jsreftest.html?test=ecma_5/Global/
 fails-if(!xulRuntime.shell) script adding-global-var-nonextensible-error.js
+fails-if(!xulRuntime.shell) script cross-global-implicit-this.js
 script parseInt-01.js
 script parseFloat-01.js

but it didn't add the file. Check it in?
Comment 20 Brendan Eich [:brendan] 2011-07-26 08:48:32 PDT
Sorry!

http://hg.mozilla.org/integration/mozilla-inbound/rev/735e1dc41b44

Checkin message references bug 588061 by mistake, comment there points here.

/be
Comment 21 Marco Bonardo [::mak] 2011-07-27 03:23:44 PDT
yay! Found the right bug!
http://hg.mozilla.org/mozilla-central/rev/735e1dc41b44
Comment 22 Bob Clary [:bc:] 2011-07-27 16:28:20 PDT
brendan: since evalcx is shell only, shouldn't you just skip the test cross-global-implicit-this.js in the browser rather than mark it as a fails?
Comment 23 Eric Shepherd [:sheppy] 2011-10-18 11:10:43 PDT
Is there a blog post or anything explaining what this impact is? I could use more insight into this change before I start writing.
Comment 24 Eric Shepherd [:sheppy] 2011-10-18 13:44:27 PDT
evilpie documented this, so we're good to go. The documentation was already correct but we now have a note mentioning that it wasn't always done properly.

Note You need to log in before you can comment on or make changes to this bug.