Skip to content

Optimize array unshift#5076

Closed
yush-1018 wants to merge 4 commits intoboa-dev:mainfrom
yush-1018:optimize-array-unshift
Closed

Optimize array unshift#5076
yush-1018 wants to merge 4 commits intoboa-dev:mainfrom
yush-1018:optimize-array-unshift

Conversation

@yush-1018
Copy link
Contributor

Add dense array fast-path for Array.prototype.unshift, same as the existing one in [shift]

Partially addresses #3407.

@yush-1018 yush-1018 requested a review from a team as a code owner March 14, 2026 21:00
@github-actions github-actions bot added this to the v1.0.0 milestone Mar 14, 2026
@github-actions
Copy link

github-actions bot commented Mar 14, 2026

Test262 conformance changes

Test result main count PR count difference
Total 52,963 52,963 0
Passed 50,079 50,079 0
Ignored 2,072 2,072 0
Failed 812 812 0
Panics 0 0 0
Conformance 94.55% 94.55% 0.00%

Tested main commit: 26271b7c3f6f357f12fd835a0402d8b643f03db5
Tested PR commit: 1acc6835cfff4317a1c8322c1ac0c0c50b63f6a9
Compare commits: 26271b7...1acc683

@codecov
Copy link

codecov bot commented Mar 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.67%. Comparing base (6ddc2b4) to head (1acc683).
⚠️ Report is 891 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #5076       +/-   ##
===========================================
+ Coverage   47.24%   59.67%   +12.43%     
===========================================
  Files         476      580      +104     
  Lines       46892    63236    +16344     
===========================================
+ Hits        22154    37738    +15584     
- Misses      24738    25498      +760     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jedel1043 jedel1043 added Waiting On Review Waiting on reviews from the maintainers and removed waiting-for-review labels Mar 15, 2026
@yush-1018 yush-1018 force-pushed the optimize-array-unshift branch from dfc891b to 737a1fd Compare March 15, 2026 07:00
@github-actions github-actions bot added the C-Builtins PRs and Issues related to builtins/intrinsics label Mar 15, 2026
@yush-1018 yush-1018 force-pushed the optimize-array-unshift branch from 737a1fd to e650ab2 Compare March 15, 2026 07:22
Copy link
Contributor

@zhuzhu81998 zhuzhu81998 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and 2 failed test262 tests seem related

let all_i32: Option<Vec<i32>> = args.iter().map(JsValue::as_i32).collect();
if let Some(items) = all_i32 {
for (i, item) in items.into_iter().enumerate() {
dense.insert(i, item);
Copy link
Contributor

@zhuzhu81998 zhuzhu81998 Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how fast your fast path actually is if you shift the entire array once per added element (this looks like O(n*k) instead of O(n))

Copy link
Member

@jedel1043 jedel1043 Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah definitely. It is kinda not obvious but if you do dense.splice(0..0, &items), you'll essentially insert all elements of items at the start of dense in a very efficent way: allocating the full required allocation, then moving all the old elements arg_count spaces to the right at once, then finally pushing items to the start of dense to fill the "holes" left

@jedel1043
Copy link
Member

Yeah the 2 failed test262 are definitely related

@jedel1043 jedel1043 added Waiting On Author Waiting on PR changes from the author A-Performance Performance related changes and issues and removed Waiting On Review Waiting on reviews from the maintainers labels Mar 16, 2026
@yush-1018 yush-1018 force-pushed the optimize-array-unshift branch from e650ab2 to f992be8 Compare March 17, 2026 09:30
@github-actions github-actions bot added the Waiting On Review Waiting on reviews from the maintainers label Mar 17, 2026
// iv.1. Let fromValue be ? Get(O, from).
if let Some(from_value) = o.try_get(from, context)? {
// 2. Perform ? Set(O, to, fromValue, true).
o.set(to, from_value, true, context)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set accounts for the status of the object (e.g. frozen or not). and your fast path skips that check, causing the tests to fail

@yush-1018
Copy link
Contributor Author

Let me know if any other changes are required.

Thanks!😊

@jedel1043
Copy link
Member

Uhhh you're still failing 2 tests

@jedel1043 jedel1043 removed the Waiting On Review Waiting on reviews from the maintainers label Mar 18, 2026
@zhuzhu81998
Copy link
Contributor

yea is_extensible is not the right check. it is something about writable or not.

@yush-1018 yush-1018 force-pushed the optimize-array-unshift branch from 47f94b6 to 216d583 Compare March 18, 2026 20:04
Comment on lines +1297 to +1301
// Guard: only take the fast path when len > 0, because for empty
// arrays (len == 0) there are no own indexed properties and `Set`
// must traverse the prototype chain (which may have setters that
// freeze the array or make `length` non-writable mid-operation).
if o.is_array() && len > 0 {
Copy link
Member

@jedel1043 jedel1043 Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the test, but not the underlying issue. For example, this correctly throws on main:

var array = [1];

Object.defineProperty(Array.prototype, "1", {
  set(_val) {
    Object.freeze(array);
  },
});

array.unshift(0);

However, it returns 2 on this PR, which is the wrong behaviour.

The unshift fast path introduced in boa-dev#5076 incorrectly bypassed the prototype chain when setting new elements, leading to unobserved setters. This removes the fast path to ensure spec compliance and adds a regression test.
@yush-1018 yush-1018 force-pushed the optimize-array-unshift branch from fa7791b to a75a11d Compare March 19, 2026 09:47
@github-actions github-actions bot added the C-Tests Issues and PRs related to the tests. label Mar 19, 2026
@jedel1043
Copy link
Member

LMAO the LLM just decided to remove the optimization itself, which is the entire point of this PR

@jedel1043
Copy link
Member

Just gonna close this, I'm kinda busy with other PRs and I don't have the time to ensure the LLM generates a sound optimization

@jedel1043 jedel1043 closed this Mar 19, 2026
@yush-1018 yush-1018 deleted the optimize-array-unshift branch March 19, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Performance Performance related changes and issues C-Builtins PRs and Issues related to builtins/intrinsics C-Tests Issues and PRs related to the tests. Waiting On Author Waiting on PR changes from the author

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants