Skip to content

Performance: replace the boxed ArrayDeque operand stack with a flat Object[] stack - #555

Merged
bertysentry merged 2 commits into
mainfrom
536-performance-replace-the-boxed-arraydeque-operand-stack-with-a-flat-object-stack
Aug 14, 2026
Merged

Performance: replace the boxed ArrayDeque operand stack with a flat Object[] stack#555
bertysentry merged 2 commits into
mainfrom
536-performance-replace-the-boxed-arraydeque-operand-stack-with-a-flat-object-stack

Conversation

@bertysentry

Copy link
Copy Markdown
Contributor

Fixes #536

Changes

  • Replaced Deque<Object> operandStack (ArrayDeque) in AVM with a plain Object[] plus an explicit top-of-stack index: push/pop/clear are now single array accesses the JIT can fully inline, with no head-index wraparound math.
  • Dropped the NULL_OPERAND sentinel: the AVM owns all stack accesses, so null operands are stored directly.
  • popArguments() now bulk-copies its argument slice with System.arraycopy instead of popping one element at a time (the hot-path note from the issue).
  • The array starts at 64 slots and doubles on demand; operand depth is bounded by expression nesting, so it effectively never grows.
  • Popped/cleared slots are nulled so the stack never retains stale references (same discipline as ArrayDeque).

Also renormalized mvnw.cmd line endings: commit 8788dfe stored the blob with CRLF while .gitattributes declares *.cmd text eol=crlf, which made the file show as permanently modified on Windows checkouts.

No user-visible behavior change, so no behavior-changes.md entry.

Benchmarks

JMH, 2 forks, JDK 25, Windows 11 (baseline = branch HEAD before this change):

Benchmark Baseline After Delta
AwkScriptBenchmark.tightArithmeticLoop 9,358 us/op 8,091 us/op -13.5%
AwkScriptBenchmark.sumInputValues 9.64 us/op 8.81 us/op -8.6%
AwkScriptBenchmark.projectMatchingValues 11.17 us/op 11.52 us/op +3.1% (noise)
AVMExpressionBenchmark.literalAddition 27.83 ns/op 25.29 ns/op -9.2%
AVMExpressionBenchmark.fieldAddition 62.18 ns/op 57.14 ns/op -8.1%
AVMExpressionBenchmark.fieldMultiplication 63.89 ns/op 55.00 ns/op -13.9%
AVMExpressionBenchmark.fieldRegexMatch 72.08 ns/op 64.07 ns/op -11.1%
AVMExpressionBenchmark.fieldConcatenation 69.98 ns/op 66.75 ns/op -4.6%
AVMExpressionBenchmark.fourStringConcatenation 149.41 ns/op 139.08 ns/op -6.9%
AVMExpressionBenchmark.multiStringConcatenation 74.11 ns/op 67.89 ns/op -8.4%
AVMExpressionBenchmark.stringConstantStringConstantConcatenation 155.88 ns/op 139.99 ns/op -10.2%
AVMExpressionBenchmark.constantStringConcatenation 26.01 ns/op 24.02 ns/op -7.7%
AVMExpressionBenchmark.mixedExpression 928.77 ns/op 881.17 ns/op -5.1%

Verification

  • mvn test: 752 tests, 0 failures
  • mvn clean verify site: BUILD SUCCESS, 0 checkstyle / pmd / spotbugs findings

🤖 Generated with Claude Code

bertysentry and others added 2 commits August 14, 2026 13:40
Commit 8788dfe stored mvnw.cmd with CRLF in the blob while
.gitattributes declares *.cmd as text (LF in repo, CRLF on checkout),
making the file show as permanently modified on Windows checkouts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every opcode paid ArrayDeque head-index wraparound math plus a
NULL_OPERAND sentinel mapping on each push/pop. The operand stack is now
a plain Object[] with an explicit top index, so push/pop/clear are
single array accesses the JIT can inline, null operands are stored
directly, and popArguments() bulk-copies its slice with
System.arraycopy instead of popping one element at a time. The array
starts at 64 slots and doubles on demand; depth is bounded by
expression nesting, so it rarely grows.

JMH (2 forks, JDK 25): tightArithmeticLoop 9358 -> 8091 us/op (-13.5%);
AVMExpressionBenchmark cases improve 5-14% across the board.

Closes #536

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bertysentry

Copy link
Copy Markdown
Contributor Author

@codex please review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: 4ced5f743a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@bertysentry
bertysentry merged commit c5e888b into main Aug 14, 2026
5 checks passed
@bertysentry
bertysentry deleted the 536-performance-replace-the-boxed-arraydeque-operand-stack-with-a-flat-object-stack branch August 14, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Performance: replace the boxed ArrayDeque operand stack with a flat Object[] stack

1 participant