Closed
Bug 1341061
Opened 8 years ago
Closed 8 years ago
post-increment operator inside "with" ends up checking @@unscopables twice
Categories
(Core :: JavaScript Engine, defect)
Core
JavaScript Engine
Tracking
()
RESOLVED
FIXED
mozilla54
Tracking | Status | |
---|---|---|
firefox54 | --- | fixed |
People
(Reporter: bzbarsky, Unassigned)
Details
Attachments
(5 files, 1 obsolete file)
11.80 KB,
patch
|
arai
:
review+
|
Details | Diff | Splinter Review |
15.01 KB,
patch
|
arai
:
review+
|
Details | Diff | Splinter Review |
7.50 KB,
patch
|
arai
:
review+
|
Details | Diff | Splinter Review |
14.48 KB,
patch
|
arai
:
review+
|
Details | Diff | Splinter Review |
1.65 KB,
patch
|
arai
:
review+
|
Details | Diff | Splinter Review |
Testcase (from es-discuss; see <https://mail.mozilla.org/pipermail/es-discuss/2017-February/047724.html>):
var a, b, flag = true
with (a = { x: 7 })
with (b = { x: 4, get [Symbol.unscopables]() { return { x: flag=!flag } } })
x++
after that executes, a.x should be 7 and b.x should be 5, as far as I can tell. We end up with b.x == 8 instead.
The reason for that is that we get @@unscopables twice: the first time from JSOP_BINDNAME calling LookupNameUnqualified etc, and the second time from JSOP_GETNAME calling GetNameOperation which calls js::LookupName which calls js::LookupProperty which calls into with_LookupProperty _again_.
As far as I can tell per spec, only the bindname should end up doing a property lookup kinda thing in the "x++" case. The get should use the existing Reference, as should the Set.
Comment 1•8 years ago
|
||
Oo, thanks for debugging this bz.
For these read-modify-write ops, we'll need a GETNAME variant that uses the environment BINDNAME already pushed onto the scope.
Comment 2•8 years ago
|
||
A note for posterity: AIUI, the Reference returned when looking up a name in the |with| scope, if found, has as its object base the environment record (the "receiver" instead of the actual object where the property was found). So while getting @@unscopables should happen only once, things like looking up the prototype to do the actual get/set happen multiple times.
Comment 3•8 years ago
|
||
Attachment #8839758 -
Flags: review?(arai.unmht)
Comment 4•8 years ago
|
||
Attachment #8839759 -
Flags: review?(arai.unmht)
Comment 5•8 years ago
|
||
Comment 6•8 years ago
|
||
Jan, I'm having trouble figuring out how to JIT the BINDGETNAME ops I introduced above. The op basically fuses together BINDNAME and GETNAME: it pushes both the environment the name is found on and the value of the name. No other ops currently push two values, and I don't know how to make VMFunctions return 2 values. Any ideas?
In exploring the design space of the fix, I also played around with decomposing BINDGETNAME to 2 ops:
1. FINDNAME, which finds the env and raises an error if not found (unlike BINDNAME)
2. GETFOUNDNAME, which gets the name off the env on the top of the stack.
The problem with that approach is that it's inefficient. FINDNAME basically does a LookupNameUnqualified, which, during the lookup, returns a PropertyResult if the name is found. This should be communicated to subsequent GETFOUNDNAME so that we don't always do the slowest, most generic GetProperty. Secondarily, this split also makes the VM code a little messier.
Flags: needinfo?(jdemooij)
Comment 7•8 years ago
|
||
Ted, whatever approach we decide on in comment 6, I'd really appreciate someone doing the JIT parts. Up for it?
Flags: needinfo?(tcampbell)
Comment 8•8 years ago
|
||
Comment on attachment 8839758 [details] [diff] [review]
Refactor NAME-related runtime functions.
Review of attachment 8839758 [details] [diff] [review]:
-----------------------------------------------------------------
Nice refactoring :)
Attachment #8839758 -
Flags: review?(arai.unmht) → review+
Comment 9•8 years ago
|
||
Comment on attachment 8839759 [details] [diff] [review]
Fix Opcodes.h comments to say 'environment' instead of 'scope' to refer to the runtime objects.
Review of attachment 8839759 [details] [diff] [review]:
-----------------------------------------------------------------
::: js/src/vm/Opcodes.h
@@ +1090,4 @@
> * Category: Variables and Scopes
> * Type: Variables
> * Operands: uint32_t nameIndex
> * Stack: => scope
=> env
Attachment #8839759 -
Flags: review?(arai.unmht) → review+
Comment 11•8 years ago
|
||
Attachment #8840236 -
Flags: review?(arai.unmht)
Comment 12•8 years ago
|
||
Also refactor some stuff in this area.
Documenting why I think it's correct to use GETBOUNDNAME only for
dynamic (vs global) lookups, without the normal NAME checks:
1. GETBOUNDNAME doesn't need to check TDZ because BINDNAME does it
already, and GETBOUNDNAME is always preceded by BINDNAME.
2. '.this' doesn't need to be checked, because '.this' can't be assigned
to in a compound assignment or inc/dec.
3. For a global name there is never @@unscopables on the global
environments, so GNAME ops, while doing repeated lookups, remain valid
optimizations because the repetition is unobservable.
4. We *will* do double @@unscopable lookup in the case of a script
compiled for a syntactic scope then run under a non-syntactic
WithEnvironmentObject (e.g. like frame scripts). But this is
Gecko-specific and outside the spec, so we can do whatever we want
here.
Attachment #8840237 -
Flags: review?(arai.unmht)
Updated•8 years ago
|
Attachment #8839760 -
Attachment is obsolete: true
Comment 13•8 years ago
|
||
Comment on attachment 8840236 [details] [diff] [review]
Rename GETXPROP to GETBOUNDNAME for clarity.
Review of attachment 8840236 [details] [diff] [review]:
-----------------------------------------------------------------
::: js/src/vm/Opcodes.h
@@ +1997,2 @@
> /*
> * Pops the top of stack value, gets an extant property value of it,
would be nice to say what "bound" is.
(and also remove "extant" maybe?
Attachment #8840236 -
Flags: review?(arai.unmht) → review+
Comment 14•8 years ago
|
||
Will remove once https://github.com/tc39/test262/pull/869 merges and we
sync.
Attachment #8840249 -
Flags: review?(arai.unmht)
Comment 15•8 years ago
|
||
Comment on attachment 8840237 [details] [diff] [review]
Manually unwrap WithEnvironmentObjects in GETBOUNDNAME.
Review of attachment 8840237 [details] [diff] [review]:
-----------------------------------------------------------------
thank you for detailed explanation :)
::: js/src/vm/NativeObject.cpp
@@ +2135,5 @@
> + // up via BINDNAME, calling HasProperty on the WithEnvironmentObject is
> + // equivalent to calling HasBinding a second time. This results in the
> + // incorrect behavior of performing the @@unscopables check again.
> + RootedObject env(cx, MaybeUnwrapSyntacticWithEnvironment(envArg));
> + RootedValue receiver(cx, ObjectValue(*env));
wouldn't it be nice to avoid having 2 roots for them?
just moving `MaybeUnwrapSyntacticWithEnvironment(envArg)` to ObjectValue argument will reduce extra root.
Attachment #8840237 -
Flags: review?(arai.unmht) → review+
Comment 16•8 years ago
|
||
Comment on attachment 8840249 [details] [diff] [review]
Test.
Review of attachment 8840249 [details] [diff] [review]:
-----------------------------------------------------------------
::: js/src/tests/test262/local/unscopables-inc-dec.js
@@ +20,5 @@
> +---*/
> +
> +var a, b, flag = true;
> +with (a = { x: 7 }) {
> + with (b = { x: 4, get [Symbol.unscopables]() { return { x: flag=!flag }; } }) {
might be nice to count how many times the getter is called.
to catch the case that it's called 3 times (maybe just a overkill tho)
Attachment #8840249 -
Flags: review?(arai.unmht) → review+
Comment 17•8 years ago
|
||
(In reply to Tooru Fujisawa [:arai] from comment #15)
> Comment on attachment 8840237 [details] [diff] [review]
> Manually unwrap WithEnvironmentObjects in GETBOUNDNAME.
>
> Review of attachment 8840237 [details] [diff] [review]:
> -----------------------------------------------------------------
>
> thank you for detailed explanation :)
>
> ::: js/src/vm/NativeObject.cpp
> @@ +2135,5 @@
> > + // up via BINDNAME, calling HasProperty on the WithEnvironmentObject is
> > + // equivalent to calling HasBinding a second time. This results in the
> > + // incorrect behavior of performing the @@unscopables check again.
> > + RootedObject env(cx, MaybeUnwrapSyntacticWithEnvironment(envArg));
> > + RootedValue receiver(cx, ObjectValue(*env));
>
> wouldn't it be nice to avoid having 2 roots for them?
> just moving `MaybeUnwrapSyntacticWithEnvironment(envArg)` to ObjectValue
> argument will reduce extra root.
Note that |env| is also passed to the GetProperty calls below, so moving that Unwrap call into the ObjectValue isn't correct.
Comment 18•8 years ago
|
||
(In reply to Shu-yu Guo [:shu] from comment #17)
> Note that |env| is also passed to the GetProperty calls below, so moving
> that Unwrap call into the ObjectValue isn't correct.
wow, overlooked that.
thanks.
Comment 19•8 years ago
|
||
Pushed by shu@rfrn.org:
https://hg.mozilla.org/integration/mozilla-inbound/rev/82cdbd24d06f
Refactor NAME-related runtime functions. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/2cb11cb34069
Fix Opcodes.h comments to say 'environment' instead of 'scope' to refer to the runtime objects. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/76c74d43a9b0
Rename GETXPROP to GETBOUNDNAME for clarity. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/559f43c43369
Manually unwrap WithEnvironmentObjects in GETBOUNDNAME. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/456c1dcfe087
Test. (r=arai)
Comment 20•8 years ago
|
||
Since we're using GETBOUNDNAME (GETXPROP) for non-global name lookups only, I don't think there's a pressing need to JIT anything any longer.
Flags: needinfo?(tcampbell)
![]() |
||
Comment 21•8 years ago
|
||
Backed out for failing crashtest 366271-1.html and mochitest test_bug841466.html:
https://hg.mozilla.org/integration/mozilla-inbound/rev/b5a2c80de72fc3b32c2ef44006e75c44917453d4
https://hg.mozilla.org/integration/mozilla-inbound/rev/7b972ab5bd1a8cc31c7fe60ba0862cd8a845a709
https://hg.mozilla.org/integration/mozilla-inbound/rev/49187b2a839656915a614feac8de963bbe35483e
https://hg.mozilla.org/integration/mozilla-inbound/rev/9e6402a66c388736bb193fcd4c9d40594785ca4b
https://hg.mozilla.org/integration/mozilla-inbound/rev/39be2cc943a7c3b48104811065ae0768de8eeaf6
Push with failures: https://treeherder.mozilla.org/#/jobs?repo=mozilla-inbound&revision=cc682c2db247433a4aad347f0d20ddbc968eb26b&filter-resultStatus=testfailed&filter-resultStatus=busted&filter-resultStatus=exception&filter-resultStatus=retry&filter-resultStatus=usercancel&filter-resultStatus=runnable
Failure log crashtest: https://treeherder.mozilla.org/logviewer.html#?job_id=80073717&repo=mozilla-inbound
[task 2017-02-24T21:31:44.077217Z] 21:31:44 INFO - REFTEST TEST-UNEXPECTED-FAIL | file:///home/worker/workspace/build/tests/reftest/tests/layout/base/crashtests/366271-1.html | load failed: timed out waiting for reftest-wait to be removed
Failure log mochitest: [task 2017-02-24T21:31:44.077217Z] 21:31:44 INFO - REFTEST TEST-UNEXPECTED-FAIL | file:///home/worker/workspace/build/tests/reftest/tests/layout/base/crashtests/366271-1.html | load failed: timed out waiting for reftest-wait to be removed
[task 2017-02-24T21:55:38.374356Z] 21:55:38 INFO - TEST-START | dom/html/test/test_bug841466.html
[task 2017-02-24T21:55:38.599943Z] 21:55:38 INFO - ++DOMWINDOW == 30 (0x7f658b720400) [pid = 3356] [serial = 1032] [outer = 0x7f658f12d800]
[task 2017-02-24T21:55:38.883324Z] 21:55:38 INFO - TEST-INFO | started process screentopng
[task 2017-02-24T21:55:40.760073Z] 21:55:40 INFO - TEST-INFO | screentopng: exit 0
[task 2017-02-24T21:55:40.765548Z] 21:55:40 INFO - TEST-UNEXPECTED-FAIL | dom/html/test/test_bug841466.html | TypeError: 'get localName' called on an object that does not implement interface Element.
[task 2017-02-24T21:55:40.765932Z] 21:55:40 INFO - onclick@dom/html/test/test_bug841466.html:1:96
[task 2017-02-24T21:55:40.767340Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:24:3
[task 2017-02-24T21:55:40.767588Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:15:1
[task 2017-02-24T21:55:40.770465Z] 21:55:40 INFO - Not taking screenshot here: see the one that was previously logged
[task 2017-02-24T21:55:40.772535Z] 21:55:40 INFO - TEST-UNEXPECTED-FAIL | dom/html/test/test_bug841466.html | TypeError: 'get localName' called on an object that does not implement interface Element.
[task 2017-02-24T21:55:40.774501Z] 21:55:40 INFO - onclick@dom/html/test/test_bug841466.html:1:96
[task 2017-02-24T21:55:40.779147Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:24:3
[task 2017-02-24T21:55:40.785473Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:15:1
[task 2017-02-24T21:55:40.787618Z] 21:55:40 INFO - Not taking screenshot here: see the one that was previously logged
[task 2017-02-24T21:55:40.789890Z] 21:55:40 INFO - TEST-UNEXPECTED-FAIL | dom/html/test/test_bug841466.html | TypeError: 'get localName' called on an object that does not implement interface Element.
[task 2017-02-24T21:55:40.793373Z] 21:55:40 INFO - onclick@dom/html/test/test_bug841466.html:1:96
[task 2017-02-24T21:55:40.798716Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:24:3
[task 2017-02-24T21:55:40.800464Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:15:1
[task 2017-02-24T21:55:40.802578Z] 21:55:40 INFO - TEST-FAIL | dom/html/test/test_bug841466.html | Bug 101019 - got "select", expected "keygen"
[task 2017-02-24T21:55:40.805206Z] 21:55:40 INFO - Not taking screenshot here: see the one that was previously logged
[task 2017-02-24T21:55:40.808745Z] 21:55:40 INFO - TEST-UNEXPECTED-FAIL | dom/html/test/test_bug841466.html | TypeError: 'get localName' called on an object that does not implement interface Element.
[task 2017-02-24T21:55:40.813463Z] 21:55:40 INFO - onclick@dom/html/test/test_bug841466.html:1:96
[task 2017-02-24T21:55:40.818716Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:24:3
[task 2017-02-24T21:55:40.820958Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:15:1
[task 2017-02-24T21:55:40.822834Z] 21:55:40 INFO - Not taking screenshot here: see the one that was previously logged
[task 2017-02-24T21:55:40.824801Z] 21:55:40 INFO - TEST-UNEXPECTED-FAIL | dom/html/test/test_bug841466.html | TypeError: 'get localName' called on an object that does not implement interface Element.
[task 2017-02-24T21:55:40.826614Z] 21:55:40 INFO - onclick@dom/html/test/test_bug841466.html:1:96
[task 2017-02-24T21:55:40.830135Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:24:3
[task 2017-02-24T21:55:40.834934Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:15:1
[task 2017-02-24T21:55:40.836982Z] 21:55:40 INFO - TEST-PASS | dom/html/test/test_bug841466.html | expected value bar from expando on element select
[task 2017-02-24T21:55:40.839413Z] 21:55:40 INFO - Not taking screenshot here: see the one that was previously logged
[task 2017-02-24T21:55:40.841637Z] 21:55:40 INFO - TEST-UNEXPECTED-FAIL | dom/html/test/test_bug841466.html | TypeError: 'get localName' called on an object that does not implement interface Element.
[task 2017-02-24T21:55:40.844276Z] 21:55:40 INFO - onclick@dom/html/test/test_bug841466.html:1:96
[task 2017-02-24T21:55:40.848455Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:24:3
[task 2017-02-24T21:55:40.850421Z] 21:55:40 INFO - @dom/html/test/test_bug841466.html:15:1
Flags: needinfo?(shu)
Comment 22•8 years ago
|
||
Pushed by shu@rfrn.org:
https://hg.mozilla.org/integration/mozilla-inbound/rev/3e4be5b2b23d
Refactor NAME-related runtime functions. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/a295d7cb1e9b
Fix Opcodes.h comments to say 'environment' instead of 'scope' to refer to the runtime objects. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/0dd554e057c6
Rename GETXPROP to GETBOUNDNAME for clarity. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/80067470282b
Manually unwrap WithEnvironmentObjects in GETBOUNDNAME. (r=arai)
https://hg.mozilla.org/integration/mozilla-inbound/rev/561a3cd11c7f
Test. (r=arai)
Updated•8 years ago
|
Flags: needinfo?(shu)
Comment 23•8 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/3e4be5b2b23d
https://hg.mozilla.org/mozilla-central/rev/a295d7cb1e9b
https://hg.mozilla.org/mozilla-central/rev/0dd554e057c6
https://hg.mozilla.org/mozilla-central/rev/80067470282b
https://hg.mozilla.org/mozilla-central/rev/561a3cd11c7f
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla54
Comment 25•8 years ago
|
||
(In reply to Boris Zbarsky [:bz] (still a bit busy) from comment #24)
> What was the issue that caused comment 21?
When a getter is called with a WithEnvirnomentObject as the receiver, we unwrap the WithEnvironmentObject, since the getter expects the unwrapped object to be the receiver. This needs to happen regardless of the WithEnvironmentObject being syntactic or non-syntactic. In one of my refactoring patches above, I incorrectly refactored code in FetchName to only unwrap syntactic WithEnvironmentObjects.
The test in comment 21 has an svg with an onload script: http://searchfox.org/mozilla-central/source/layout/base/crashtests/366271-1-frame.svg#3
That onload script uses |location|, which is a getter on a non-syntactic WithEnvironmentObject on the env chain. The incorrect refactoring caused that getter to fail.
Flags: needinfo?(shu)
Comment 26•8 years ago
|
||
Pushed by shu@rfrn.org:
https://hg.mozilla.org/integration/mozilla-inbound/rev/2a03a46e5e8a
Followup: remove local copy of unscopables-inc-dec.
Comment 27•8 years ago
|
||
bugherder |
You need to log in
before you can comment on or make changes to this bug.
Description
•