Closed Bug 1466363 Opened 7 years ago Closed 7 years ago

Differential Testing: Different output message involving Object.seal

Categories

(Core :: JavaScript Engine: JIT, defect, P1)

defect

Tracking

()

RESOLVED FIXED
mozilla62
Tracking Status
firefox62 --- fixed

People

(Reporter: gkw, Assigned: jandem)

References

Details

(Keywords: testcase)

Attachments

(1 file)

x = {}; Array.prototype.unshift.apply(x, [(function() {}), {}, 0, undefined]); Object.seal(x); for (var p in this) { try { Object.defineProperty(x, 3, { configurable: (function() {}), enumerable: true, writable: true, value: 0, }); } catch (e1) {} } print(uneval(x[3])); $ ./js-dbg-64-dm-linux-8c9263730393 --fuzzing-safe --no-threads --no-baseline --no-ion testcase.js (void 0) $ ./js-dbg-64-dm-linux-8c9263730393 --fuzzing-safe --no-threads --baseline-eager --no-ion testcase.js 0 Tested this on m-c rev 8c9263730393. My configure flags are: 'AR=ar' 'sh' '/home/ubuntu/trees/mozilla-central/js/src/configure' '--enable-debug' '--enable-more-deterministic' '--with-ccache' '--enable-gczeal' '--enable-debug-symbols' '--disable-tests' python -u -m funfuzz.js.compile_shell -b "--enable-debug --enable-more-deterministic" -r 8c9263730393 autobisectjs shows this is probably related to the following changeset: The first bad revision is: changeset: https://hg.mozilla.org/mozilla-central/rev/b46f3ba0c766 user: Jan de Mooij date: Sat May 12 11:46:51 2018 +0200 summary: Bug 1460381 - Support sealed and non-extensible dense elements on native objects. r=anba Jan, is bug 1460381 a likely regressor?
Flags: needinfo?(jdemooij)
Attached patch PatchSplinter Review
Good find. defineProperty uses INITELEM when defining a configurable/writable/enumerable property, but the JIT can't optimize that to a set when the object is sealed, because we have to throw a TypeError then. This patch just checks for non-extensible objects when optimizing INITELEM. Annoying: I added tests for this (defineProperty on non-extensible/sealed/frozen objects) but they needed a loop to trigger this.
Assignee: nobody → jdemooij
Status: NEW → ASSIGNED
Flags: needinfo?(jdemooij)
Attachment #8982868 - Flags: review?(andrebargull)
Comment on attachment 8982868 [details] [diff] [review] Patch Review of attachment 8982868 [details] [diff] [review]: ----------------------------------------------------------------- ::: js/src/jit/CacheIR.cpp @@ +3540,5 @@ > > + // Don't optimize INITELEM (DefineProperty) on non-extensible objects: when > + // the elements are sealed, we have to throw an exception. > + if (IsPropertyInitOp(JSOp(*pc_)) && !nobj->isExtensible()) > + return false; Hmm, I don't understand why it's necessary to check for extensibility compared to just checking if the elements are sealed. For example when I replace the condition with: --- if (IsPropertyInitOp(JSOp(*pc_)) && nobj->denseElementsAreSealed()) --- the fuzz-test and basic/non-extensible-elements6.js both still pass. ::: js/src/jit/IonBuilder.cpp @@ +9158,5 @@ > + > + // Don't optimize INITELEM (DefineProperty) on potentially non-extensible > + // objects: when the array is sealed, we have to throw an exception. > + if (IsPropertyInitOp(JSOp(*pc))) > + return Ok(); Can you add a test case for this one, because it doesn't seem to be covered by basic/non-extensible-elements6.js (i.e. commenting out the if-statement didn't lead to test failures in basic/non-extensible-elements6.js.) For example with this test case I was able to get consistent failures without the change in jit/IonBuilder.cpp. --- function testSealNonExtensible() { var obj = Object.preventExtensions([0]); var desc = {value: 0, writable: true, enumerable: true, configurable: true}; var errorAt = -1; var N = 10000; for (var i = 0; i <= N; ++i) { if (i === N) { Object.seal(obj); } try { Object.defineProperty(obj, 0, desc); } catch { errorAt = i; } } assertEq(errorAt, N); } for (var i = 0; i < 15; i++) testSealNonExtensible(); ---
Attachment #8982868 - Flags: review?(andrebargull) → review+
(In reply to André Bargull [:anba] from comment #2) > Hmm, I don't understand why it's necessary to check for extensibility > compared to just checking if the elements are sealed. We have to check for extensibility because PreventExtensions triggers a Shape change. If we just check for sealed elements, the stub would fail if we pass a non-extensible object and then later seal that object (without triggering a Shape change). I will add a comment (I should have added one, sorry :/). The test you wrote fails when I change [0] to {0:0} and check for sealed-elements instead of non-extensible. It doesn't repro with arrays because sealing an array triggers a Shape change for some reason, I'll try to figure out why - must be something related to the length property. (I think using INITELEM on non-extensible objects like this is pretty rare, but if needed we could optimize this later by having StoreDenseElement guard on the SEALED flag for INITELEM ops.) > Can you add a test case for this one, because it doesn't seem to be covered > by basic/non-extensible-elements6.js (i.e. commenting out the if-statement > didn't lead to test failures in basic/non-extensible-elements6.js.) Oops yes, thanks for the test!
(In reply to Jan de Mooij [:jandem] from comment #3) > (In reply to André Bargull [:anba] from comment #2) > > Hmm, I don't understand why it's necessary to check for extensibility > > compared to just checking if the elements are sealed. > > We have to check for extensibility because PreventExtensions triggers a > Shape change. If we just check for sealed elements, the stub would fail if > we pass a non-extensible object and then later seal that object (without > triggering a Shape change). I will add a comment (I should have added one, > sorry :/). > > The test you wrote fails when I change [0] to {0:0} and check for > sealed-elements instead of non-extensible. It doesn't repro with arrays > because sealing an array triggers a Shape change for some reason, I'll try > to figure out why - must be something related to the length property. Derp, know I feel dumb. Like I was so close, but still couldn't make the connection. :-D (I was only testing with arrays and just like said, sealing an array leads to a shape change, so I was never able to create a test case where only testing for sealed elements made a different compared to testing for extensibility.)
(In reply to Jan de Mooij [:jandem] from comment #3) > It doesn't repro with arrays > because sealing an array triggers a Shape change for some reason, I'll try > to figure out why - must be something related to the length property. The length property is innocent... What's happening is that when we call Object.preventExtensions(array), we set the NOT_EXTENSIBLE bit on the BaseShape and generate a new Shape for the last property ("length" in this case). Then when we call Object.seal(array), SetIntegrityLevel looks up the initial/empty shape and passes |nobj->lastProperty()->getObjectFlags()| for the BaseShape flags and this will create a *new* shape lineage, hence the shape change. There's not an easy fix and it's probably not worth worrying about..
(In reply to Jan de Mooij [:jandem] from comment #5) > There's not an easy fix and it's probably not worth worrying about.. I guess one option is for SetIntegrityLevel to try to *reuse* shapes in |shapes| until it finds a Shape it can't reuse because it needs to set the non-configurable/non-writable attributes on it. But anyway, that's just a pre-existing issue.
Priority: -- → P1
Pushed by jandemooij@gmail.com: https://hg.mozilla.org/integration/mozilla-inbound/rev/a1765b4cd8fa Don't optimize INITELEM on non-extensible objects as we might have to throw a TypeError. r=anba
Btw I added your testcase, with separate functions for the object and array cases. I changed N from 10000 to 100 but confirmed I still get failures with --no-threads if I comment out the Ion code or change CacheIR.cpp to check for sealed elements instead of non-extensible objects.
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla62
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: