Skip to content

perf(android): read numeric array arguments in bulk - #128

Open
ammarahm-ed wants to merge 1 commit into
perf/jni-08-weak-wrappersfrom
perf/jni-09-bulk-arrays
Open

ammarahm-ed wants to merge 1 commit into
perf/jni-08-weak-wrappersfrom
perf/jni-09-bulk-arrays

Conversation

@ammarahm-ed

@ammarahm-ed ammarahm-ed commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

A JS array passed as int[] or double[] was read one element at a time: a handle, a conversion call and a status check per element. The elements are now copied into a double buffer in one pass and converted from there.

  • Node-API. New js_get_array_doubles in each engine's jsr.cpp. On V8 it walks the packed backing store with v8::Array::Iterate; the other engines loop over napi_get_element.
  • Direct runtime. New Array::copyNumbers on each engine backend, the same split.

If an element is not a number, or a dictionary-mode array skipped a hole, the bulk read reports failure and the existing per-element path runs, so conversion results do not change. For int[] the buffer is also range-checked: a value outside the int range falls back to the per-element path, which applies the engine's own wrapping, instead of a cast that is undefined for out-of-range doubles.

Results

V8 release build on a Sony SO-01M (Android 11, arm64), AOT-compiled with cmd package compile -m speed. One warm-up launch is discarded, then 5 launches; values are the median ns per call.

Case Node-API before after Δ Direct before after Δ
Pass a 16 Int Array 4,668 2,918 -37% 5,262 3,532 -33%
Pass a 16 Double Array 5,012 3,368 -33% 5,931 4,059 -32%
Pass an Int Array 3,264 2,836 -13% 4,135 3,452 -17%
Pass a Double Array 3,134 2,858 -9% 3,970 3,477 -12%
Pass a String Array 5,661 5,401 -5% 6,846 6,693 -2%
Pass a Boolean Array 2,980 3,084 +3% 3,812 3,688 -3%

The 3-element rows and the 16-element rows are the same code path, so the gain grows with the array length. String and boolean arrays do not use this path and are unchanged.

All cases
Case Node-API before after Δ Direct before after Δ
Void Method on instance 662 648 -2% 596 589 -1%
Field on instance 804 855 +6% 835 852 +2%
Int Field on instance 377 370 -2% 386 380 -1%
Get Static Field 813 901 +11% 850 832 -2%
Void Static Method 292 298 +2% 313 311 -1%
multiply(a, b) 486 479 -1% 520 534 +3%
Pass and return string 1,218 1,245 +2% 1,202 1,142 -5%
Return a String 836 804 -4% 760 766 +1%
Return an Int 315 326 +3% 315 320 +2%
Pass a String 700 699 -0% 687 693 +1%
Return a Boolean 313 317 +1% 313 311 -1%
Return a Double 399 391 -2% 395 379 -4%
Pass an Int 415 376 -9% 420 447 +6%
Pass a Double 397 386 -3% 425 436 +3%
Pass a Boolean 480 478 -0% 424 439 +3%
Return an Int Array 27,918 27,821 -0% 20,068 20,322 +1%
Pass an Int Array 3,264 2,836 -13% 4,135 3,452 -17%
Return a String Array 29,130 29,956 +3% 21,210 21,494 +1%
Pass a String Array 5,661 5,401 -5% 6,846 6,693 -2%
Return a Double Array 27,120 27,452 +1% 20,490 21,228 +4%
Pass a Double Array 3,134 2,858 -9% 3,970 3,477 -12%
Return a Boolean Array 26,139 26,138 -0% 19,611 20,402 +4%
Pass a Boolean Array 2,980 3,084 +3% 3,812 3,688 -3%
Int Array[0] read 361 352 -2% 240 240 +0%
String Array[0] read 784 792 +1% 666 670 +1%
Double Array[0] read 426 476 +12% 342 346 +1%
Boolean Array[0] read 350 353 +1% 234 235 +0%
Int Array[0] write 511 462 -10% 364 362 -0%
String Array[0] write 1,220 1,122 -8% 1,072 1,060 -1%
Double Array[0] write 546 465 -15% 373 369 -1%
Boolean Array[0] write 513 475 -7% 367 363 -1%
Return a Date Object 13,411 14,326 +7% 13,814 13,925 +1%
Pass a Date Object 3,688 3,926 +6% 3,749 3,576 -5%
Invoke void callback 7,358 7,692 +5% 6,899 6,890 -0%
Instance add(a, b) 832 812 -2% 796 798 +0%
Pass and return non-ASCII string 1,252 1,253 +0% 1,190 1,125 -5%
Pass and return 1KB string 5,040 5,027 -0% 5,114 5,096 -0%
Return a Char 343 352 +3% 350 350 +0%
Return this 1,261 1,392 +10% 1,354 1,315 -3%
Return a new object 12,744 13,189 +3% 12,359 12,439 +1%
Call a method on a new object 19,368 19,556 +1% 19,891 19,832 -0%
Pass a 16 Int Array 4,668 2,918 -37% 5,262 3,532 -33%
Pass a 16 Double Array 5,012 3,368 -33% 5,931 4,059 -32%
Invoke int callback 10,765 13,802 +28% 10,634 9,772 -8%
Invoke string callback 8,908 9,389 +5% 11,360 8,767 -23%
Native heap after run (MB) 106 MB 106 MB +0% 97 MB 97 MB +0%

Only V8 was built and run. The Hermes, JSC, QuickJS-NG and PrimJS readers in this change have not been built or run.

@coderabbitai

coderabbitai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2414aad3-3d67-430c-8fa0-5a6f1d307310

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@ammarahm-ed
ammarahm-ed added this pull request to stack #121 November 9, 2026 07:06

This branch has not been deployed

No deployments
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.

1 participant