Closed
Bug 1350864
Opened 8 years ago
Closed 8 years ago
Freezing an array does not set non-writable length correctly
Categories
(Core :: JavaScript Engine, defect)
Core
JavaScript Engine
Tracking
()
RESOLVED
FIXED
mozilla55
Tracking | Status | |
---|---|---|
firefox55 | --- | fixed |
People
(Reporter: jandem, Assigned: jandem)
References
Details
Attachments
(1 file)
5.83 KB,
patch
|
Waldo
:
review+
|
Details | Diff | Splinter Review |
We have an invariant that arrays with non-writable length have capacity <= initializedLength, so the JITs don't have to check for non-writable length when adding new elements.
However, when we freeze an array, we set the NONWRITABLE_ARRAY_LENGTH ObjectElements flag but we don't ensure capacity <= initializedLength. This is a regression from bug 1283334 and observable with inlined Array#push in Ion.
The attached patch moves this code from ArraySetLength into ArrayObject::setNonWritableLength, so we can also call it from SetIntegrityLevel.
Attachment #8851564 -
Flags: review?(jwalden+bmo)
Comment 1•8 years ago
|
||
Comment on attachment 8851564 [details] [diff] [review]
Patch
Review of attachment 8851564 [details] [diff] [review]:
-----------------------------------------------------------------
> We have an invariant that arrays with non-writable length have
> capacity <= initializedLength, so the JITs don't have to check
> for non-writable length when adding new elements.
You meant capacity <= length, right? I'm pretty sure initializedLength <= capacity is the *actual* invariant between these two fields.
Despite that flub, the patch does seem to actually be implementing the real invariant.
::: js/src/jit-test/tests/ion/array-push-frozen-array.js
@@ +11,5 @@
> + try {
> + arr.push(2);
> + assertEq(i <= 1500, true);
> + } catch(e) {
> + assertEq(e.toString().includes("non-writable length"), true);
I'd prefer if you just checked for instanceof TypeError, to not depend on error messages that might change.
::: js/src/vm/ArrayObject.h
@@ +42,5 @@
> + if (getElementsHeader()->capacity > len) {
> + shrinkElements(cx, len);
> + getElementsHeader()->capacity = len;
> + }
> + getElementsHeader()->setNonwritableArrayLength();
A |ObjectElements* header = getElementsHeader();| local would be better than calling the function multiple times, IMO.
::: js/src/vm/NativeObject.h
@@ +231,5 @@
> return flags & NONWRITABLE_ARRAY_LENGTH;
> }
> void setNonwritableArrayLength() {
> + // See ArrayObject::setNonWritableLength.
> + MOZ_ASSERT(capacity <= initializedLength);
Mm. I wish this could be folded directly into ArrayObject::setNonWritableArrayLength, while still preserving its encapsulation of flags-modification, given that's the only caller now. :-\
Based on that being the only caller, and in light of the existing invariants on initializedLength/capacity/length, this should flatly assert |capacity == initializedLength|.
Attachment #8851564 -
Flags: review?(jwalden+bmo) → review+
Pushed by jandemooij@gmail.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/e03b31080750
Fix SetIntegrityLevel to set non-writable length correctly when freezing arrays. r=Waldo
Comment 3•8 years ago
|
||
bugherder |
Status: ASSIGNED → RESOLVED
Closed: 8 years ago
status-firefox55:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla55
You need to log in
before you can comment on or make changes to this bug.
Description
•