Fix Object.assign with array target losing length update (#2126)#2399
Conversation
86094e5 to
a58aa1f
Compare
|
For reviewer context: this PR implements exactly the approach @aardvark179 outlined in #2126 (comment):
Scope is intentionally narrow — only the Also pushed an update that adds the exact reproducer from the original issue ( |
|
@Finomosec pleasr run ./gradlew spotlessApply to correct the formatting |
Object.assign([], src) returned an empty array instead of a copy of src's
enumerable own properties. Integer-keyed property writes went through
AbstractEcmaObjectOperations.put -> ScriptableObject.putOwnProperty ->
putImpl, which bypasses NativeArray.put(int) and so the array's length
was never updated. The slots got stored but stayed invisible to iteration
and serialization.
Short-circuit to the array's own put() when the target is a NativeArray so
length is maintained. Same special-case for the String-key code path, since
NativeArray treats numeric string keys ("0", "1", ...) as indexed properties
that affect length.
Tests cover the original report, length-maintenance, sparse-source skipping
holes, multi-source assigns, mix with push/spread/forEach/map/reduce/splice,
pre-sized arrays via the Array constructor, and the object-target baseline
(must remain unchanged). All tests run in both interpreter and compiled
mode via Utils.assertWithAllModes_ES6.
Fixes mozilla#2126
5b5b388 to
77078c1
Compare
|
Looks great, going to give the others a minute to take a look, thanks! |
|
I rebased the tests and ran them locally, and no test262 tests failed, but sadly no new tests passed either. I still think we should merge this though! |
|
@gbrail did something similar, same result. |
|
Still a good fix though -- thanks! |
Summary
Object.assign([], src)returned an empty array instead of a copy ofsrc'senumerable own properties. The integer-keyed property writes went through
AbstractEcmaObjectOperations.put→ScriptableObject.putOwnProperty→putImpl, which bypassesNativeArray.put(int)and so the array's lengthwas never updated. The slots got stored but stayed invisible to iteration
and serialization.
Reproducer (failing before this PR):
Fix
Short-circuit to
targetObj.put(...)inNativeObject.js_assignwhen thetarget is a
NativeArray, so the array's own put-path (which maintainslength) is used. Same special-case for the String-key path, since numericstring keys like
"0","1"are also indexed properties for arrays.The non-array code path stays exactly as before.
Tests
New
ObjectAssignArrayTargetTest(32 cases) covering:push/ spread /forEach/map/reduce/splicenew Array(n)(length must not shrink)Object.assignchains, 100-entry volume testAll tests run in both interpreter and compiled mode via
Utils.assertWithAllModes_ES6.Context
Refs #2126.