Skip to content

Commit 39e6041

Browse files
committed
perf(array): add dense fast path to Array.prototype.push
Array.prototype.push was going through the generic [[Set]] machinery for every element, which involves property descriptor validation and prototype chain walks. This is unnecessary for dense arrays where we can append directly to the indexed storage. Add a fast path that mirrors the PushValueToArray opcode: verify the array is extensible and its shape matches the default array template (guaranteeing length is writable), then push directly via push_dense() and update the length in-place. Falls through to the existing slow path for sparse arrays, non-extensible arrays, arrays with modified property descriptors, and array-like objects. ~49% improvement on a push-dominated microbenchmark, ~20% on a realistic mixed workload (push objects + filter).
1 parent f5e88de commit 39e6041

40 files changed

Lines changed: 3444 additions & 0 deletions

.claude/settings.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(gh issue:*)",
5+
"Bash(git stash:*)",
6+
"Bash(cargo bench:*)",
7+
"Bash(tee /tmp/bench_main.txt)",
8+
"Bash(tee /tmp/bench_pr.txt)",
9+
"Bash(find /Users/kumartanay/boa -type f -name \"*.rs\" -exec grep -l \"struct.*VM\\\\|pub struct VM\" {})",
10+
"Bash(find /Users/kumartanay/boa -type f -name \"*.rs\" -exec grep -l \"fn __call__\" {})",
11+
"Bash(grep -r \"SmallVec\" /Users/kumartanay/boa/Cargo.toml /Users/kumartanay/boa/core/*/Cargo.toml)",
12+
"Bash(grep -n \"fn frame_mut\\\\|fn push_frame\\\\|fn close_iterators\\\\|fn pop_environments\" /Users/kumartanay/boa/core/engine/src/vm/*.rs)",
13+
"Bash(grep -n \"Opcode::decode\" /Users/kumartanay/boa/core/engine/src/vm/*.rs)",
14+
"Bash(grep -n \"fn decode\" /Users/kumartanay/boa/core/engine/src/vm/opcode/*.rs)",
15+
"Bash(grep -n \"EXIT_EARLY\\\\|exit_early\" /Users/kumartanay/boa/core/engine/src/vm/*.rs)",
16+
"Bash(grep -n \"struct CallFrame\\\\|pub struct CallFrame\" /Users/kumartanay/boa/core/engine/src/vm/*.rs)",
17+
"Bash(pandoc proposal-tco-dispatch.md -o proposal-tco-dispatch.docx --from markdown --to docx)",
18+
"WebFetch(domain:github.com)",
19+
"WebFetch(domain:blog.sdslabs.co)",
20+
"WebFetch(domain:medium.com)",
21+
"WebFetch(domain:gsocguide.vercel.app)",
22+
"WebFetch(domain:raw.githubusercontent.com)",
23+
"Bash(pandoc \"Chrome DevTools Protocol Integration.docx\" -t markdown -o cdp-extracted.md)",
24+
"Bash(pandoc proposal-cdp-debugger.md -o \"Chrome DevTools Protocol Integration.docx\" --from markdown --to docx)",
25+
"Bash(ls -la /Users/kumartanay/boa/gsoc-proposals/*.docx)",
26+
"Bash(pandoc proposal-cdp-debugger.md -o \"Chrome DevTools Protocol Integration-v2.docx\" --from markdown --to docx)",
27+
"Bash(ls -la *.docx)",
28+
"Bash(pandoc 'Chrome DevTools Protocol Integration.docx' -t plain)",
29+
"Bash(git fetch:*)",
30+
"Bash(git merge:*)",
31+
"Bash(git remote:*)",
32+
"Bash(cargo run:*)",
33+
"Bash(node -e 'console.log\\(Number.prototype.toExponential.call\\(Infinity\\)\\); console.log\\(Number.prototype.toExponential.call\\(-Infinity\\)\\);')",
34+
"Bash(cargo fmt:*)",
35+
"Bash(GIT_PUSH_OPTION_COUNT=0 git push origin fix/finalization-registry-symbol-support --no-verify)",
36+
"Bash(grep -E \"^[[:space:]]+\\(/// |[A-Z][a-zA-Z]+\\(\\\\s*\\\\{|,\\)\\)\" /Users/kumartanay/boa/core/engine/src/vm/opcode/mod.rs)",
37+
"Bash(wc -l /Users/kumartanay/boa/gsoc-proposals/*.md)",
38+
"Bash(grep -E \"^ [A-Z][a-zA-Z]+\\(\\\\s*\\(\\\\{|,\\)|$\\)\" /Users/kumartanay/boa/core/engine/src/vm/opcode/mod.rs)",
39+
"Bash(grep -r \"performance\\\\|conformance\\\\|v1.0\\\\|E-hard\\\\|E-medium\" /Users/kumartanay/boa/*.md)",
40+
"Bash(ls -lah /Users/kumartanay/boa/*.md)",
41+
"Bash(find /Users/kumartanay/boa -name \"*.md\" -type f -exec grep -l \"conformance\\\\|test262\\\\|pass rate\" {})",
42+
"Bash(find /Users/kumartanay/boa -path */benches/* -name *.rs)",
43+
"Bash(git -C /Users/kumartanay/boa log --oneline --all --grep=\"GC\\\\|garbage\\\\|collect\\\\|memory\")",
44+
"Bash(git -C /Users/kumartanay/boa log --oneline --all -- core/gc)",
45+
"Bash(pandoc proposal-inline-caching.md -o \"Inline Caching Expansion.docx\" --from markdown --to docx)"
46+
]
47+
}
48+
}

BENCH_ARRAY_CLONE.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## Benchmark Results
2+
3+
Ran `cargo bench -p boa_benches` on `main` vs this PR branch.
4+
5+
| Benchmark | main | PR | Change | Significant? |
6+
|-----------|------|-----|--------|-------------|
7+
| strings/slice | 1.030 ms | 1.007 ms | **-2.3%** | Yes (improved) |
8+
| strings/split | 2.931 ms | 2.940 ms | +0.3% | No (noise) |
9+
| basic/call-loop | 5.418 ms | 5.390 ms | -0.5% | No (noise) |
10+
| basic/nested-loop | 12.56 ms | 12.64 ms | +0.6% | No (noise) |
11+
| v8/raytrace | 4.986 µs | 4.932 µs | -1.0% | No (noise) |
12+
| v8/navier-stokes | 5.083 µs | 5.036 µs | -1.2% | No (noise) |
13+
| v8/deltablue | 5.052 µs | 4.973 µs | **-1.4%** | Yes (improved) |
14+
| v8/richards | 5.018 µs | 4.957 µs | **-1.5%** | Yes (improved) |
15+
| v8/splay | 5.019 µs | 4.939 µs | **-1.5%** | Yes (improved) |
16+
| v8/earley-boyer | 5.632 µs | 5.564 µs | -1.0% | No (noise) |
17+
| v8/regexp | 5.157 µs | 5.105 µs | -0.6% | No (noise) |
18+
| v8/crypto | 10.924 s | 10.925 s | 0.0% | No |
19+
20+
Criterion marked **strings/slice, deltablue, richards, splay** as statistically significant improvements. No regressions detected.
21+
22+
**Note:** The existing benchmarks don't heavily exercise array iteration methods (`.map()`, `.filter()`, `.forEach()`, `.every()`, `.some()`, `.reduce()`). The real win from this PR is on workloads that call these methods on large arrays, where N unnecessary `o.clone().into()` conversions per call are eliminated. Each clone involves a GC reference count increment + JsValue construction — hoisting it before the loop reduces this to exactly 1 per method call regardless of array size.

CLAUDE.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
Boa is a JavaScript (ECMAScript) engine written in Rust. It includes a lexer, parser, bytecode compiler, and virtual machine. Rust edition 2024, minimum rust-version 1.91.0.
8+
9+
## Common Commands
10+
11+
### Build & Run
12+
```sh
13+
cargo build # Build all workspace crates
14+
cargo run # Run the REPL (boa_cli)
15+
cargo run -- file.js # Execute a JS file
16+
```
17+
18+
### Testing
19+
```sh
20+
cargo test # Run all unit tests
21+
cargo test -p boa_engine # Test a single crate
22+
cargo test -p boa_engine -- name_of_test # Run a specific test
23+
24+
# Bytecode snapshot tests (requires cargo-insta)
25+
cargo insta test -p insta-bytecode --review
26+
cargo insta review --manifest-path ./tests/insta-bytecode/Cargo.toml
27+
28+
# ECMAScript test262 conformance suite
29+
cargo run --release --bin boa_tester -- run -v 2> error.log
30+
cargo run --release --bin boa_tester -- run -vv -d -s test/language/types/number 2> error.log
31+
cargo run --release --bin boa_tester -- compare <base-results> <new-results>
32+
```
33+
34+
### Linting & Formatting
35+
```sh
36+
cargo fmt --all # Format code
37+
cargo fmt -- --check # Check formatting
38+
cargo clippy --all-features --all-targets # Lint with all features
39+
cargo clippy --no-default-features # Lint with no features
40+
cargo make run-ci # Run all CI checks locally (fmt + both clippy passes)
41+
```
42+
43+
### Documentation
44+
```sh
45+
cargo doc --all-features --document-private-items --workspace --no-deps
46+
```
47+
48+
## Architecture
49+
50+
The engine pipeline is: **Source → Lexer → Parser → AST → ByteCompiler → Bytecode → VM → Result**
51+
52+
### Workspace Crates
53+
54+
**Core crates** (in `core/`):
55+
- **`boa_parser`** — Lexer and parser, produces AST
56+
- **`boa_ast`** — ECMAScript AST node types
57+
- **`boa_engine`** — The main crate: bytecode compiler, VM, builtins, object model, `Context`
58+
- **`boa_gc`** — Garbage collector (`Gc<T>`, `Trace`, `Finalize` traits)
59+
- **`boa_interner`** — String interning (`Interner`)
60+
- **`boa_string`** — UTF-16 `JsString` implementation
61+
- **`boa_runtime`** — WebAPI extensions (console, fetch, timers, URL, etc.)
62+
- **`boa_macros`** — Procedural macros
63+
- **`boa_icu_provider`** — ICU4X data for internationalization
64+
65+
**Other crates**: `cli` (REPL), `examples`, `benches`, `tests/` (tester, fuzz, insta-bytecode), `ffi/`, `utils/` (tag_ptr, small_btree)
66+
67+
### Key Subsystems in `boa_engine`
68+
69+
- **`bytecompiler/`** — Recursive AST→bytecode lowering. Subdirs: `statement/`, `expression/`, `declaration/`, `class.rs`, `function.rs`. Uses `RegisterAllocator` and jump patching.
70+
- **`vm/`** — Stack-based VM with `CallFrame` stack, value stack, and register file. `CodeBlock` holds bytecode for a function.
71+
- **`vm/opcode/`** — Opcodes defined via `generate_opcodes!` macro. Each opcode has an `Operation` trait impl. Dispatch via `OPCODE_HANDLERS[256]` function pointer table.
72+
- **`builtins/`** — 30+ builtin objects. Each implements `IntrinsicObject` trait with `init()` method. Use `BuiltInBuilder` fluent API.
73+
- **`object/`** — Shape-based property storage, prototype chains, internal slots.
74+
- **`context/`**`Context` is the top-level execution context (realm, intrinsics, VM instance).
75+
76+
### Error Handling
77+
- `JsResult<T>` = `Result<T, JsError>` — used throughout the engine
78+
- Spec's `? Operation()` maps to Rust's `?` operator
79+
- Spec's `! Operation()` maps to `.expect()`
80+
81+
## Code Conventions
82+
83+
### Clippy Rules
84+
Disallowed methods (use `cow_utils::CowUtils` alternatives instead):
85+
- `str::to_ascii_lowercase``cow_to_ascii_lowercase`
86+
- `str::to_ascii_uppercase``cow_to_ascii_uppercase`
87+
- `str::to_lowercase``cow_to_lowercase`
88+
- `str::to_uppercase``cow_to_uppercase`
89+
- `str::replace``cow_replace`
90+
- `str::replacen``cow_replacen`
91+
92+
### ECMAScript Spec Mapping
93+
When implementing spec algorithms, map code to spec steps and add comments indicating which steps are being implemented. Use spec terminology (abstract operations, internal slots `[[SlotName]]`, completion records). See `core/engine/src/builtins/` for examples.

CONTRIBUTION_GUIDE.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Boa Contribution Guide – Avoiding Blunders
2+
3+
## Lesson from console.timeStamp Rejection
4+
5+
**Maintainer feedback:** "This should at least be standardized first before trying to implement it."
6+
7+
### What Went Wrong
8+
9+
- Implemented `console.timeStamp()` without confirming it was standardized
10+
- WHATWG Console spec is a "living standard" – not all methods are considered standardized by Boa
11+
- No prior discussion or claim on an issue before implementing
12+
13+
---
14+
15+
## Safe Contribution Checklist
16+
17+
Before implementing anything:
18+
19+
1. **Claim the issue first** – Comment on the GitHub issue that you want to work on it. Wait for maintainer assignment. (From [CONTRIBUTING.md](CONTRIBUTING.md))
20+
21+
2. **Verify standardization** – For new features:
22+
- **ECMA-262** (JavaScript language): Safe – it's the official JS standard
23+
- **Test262 tests**: Safe – they test against the spec
24+
- **WHATWG/Web APIs**: Check with maintainers – "living standards" may not all be accepted
25+
- **Stage 3 proposals**: Avoid unless Boa has an `experimental` flag for them
26+
27+
3. **Prefer existing issues** – Work on issues created by maintainers (jedel1043, jasonwilliams, HalidOdat). They've already vetted scope and relevance.
28+
29+
4. **Bug fixes with spec references** – Issues that cite ECMA-262 sections (e.g. "Section 22.1.3.21") are safe – they're fixing spec non-compliance.
30+
31+
---
32+
33+
## Safe Issue Types (Low Risk)
34+
35+
| Type | Why Safe | Example |
36+
| ---------------------- | ---------------------------------- | ---------------------------- |
37+
| **Dead code removal** | No spec, pure cleanup | OrderedHashMap removal ✓ |
38+
| **CI/workflow fixes** | Infrastructure, no spec | wasm-pack Node deprecation ✓ |
39+
| **ECMA-262 bug fixes** | Explicit spec reference | String.prototype.split #4663 |
40+
| **Test additions** | Improves coverage of existing code | JsSymbol tests #3489 |
41+
| **Documentation** | No behavioral change | Document Bytecompiler #1608 |
42+
43+
---
44+
45+
## Issue Types to Avoid (Unless Explicitly Approved)
46+
47+
| Type | Why Risky |
48+
| --------------------------------- | --------------------------------------- |
49+
| **New Web API methods** | May not be "standardized" in Boa's view |
50+
| **Console API additions** | WHATWG Console is a living standard |
51+
| **Proposal-stage features** | May change before standardization |
52+
| **Implementing without an issue** | No maintainer vetting of scope |
53+
54+
---
55+
56+
## Recommended Workflow
57+
58+
1. Browse [open issues](https://github.com/boa-dev/boa/issues) – filter by `good first issue`, `E-Easy`
59+
2. Pick an issue → **Comment to claim it** → Wait for assignment
60+
3. If unsure about standardization: **Ask in the issue** before coding
61+
4. Implement → Open PR referencing the issue
62+
63+
---
64+
65+
## Current Unclaimed / Low-Risk Issues to Consider
66+
67+
_Always claim before implementing._
68+
69+
- **#2703** – Update README GIF (documentation, no spec)
70+
- **#3431** – Add Boa to Test262-Harness (ecosystem, maintainer-created)
71+
- **#4360** – toString missing on TryIntoJs (API bug, may need design discussion)
72+
- **#4330** – StdClock not monotonic (API bug, maintainer-created)
73+
74+
---
75+
76+
## If You're Unsure
77+
78+
**Ask in the issue:** "I'd like to work on this. Is [X] standardized enough for Boa, or should I focus on something else?"

0 commit comments

Comments
 (0)