facebook / hermes

A JavaScript engine optimized for running React Native.

Home Page:https://hermesengine.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Array.protoype.indexOf() Performance Regression

tctacm opened this issue · comments

Bug Description

The Array.prototype.indexOf() functions seems to be significantly slower on Hermes when compared to JSC. I first noticed the issue in React Native 0.64 inside the JSTimers file: https://github.com/facebook/react-native/blob/0645c38014e8310d8e387dabc860c8c5878beb6e/Libraries/Core/Timers/JSTimers.js#L62 , however, I have reproduced a case using the Hermes CLI to verify my findings.

  • I have run gradle clean and confirmed this bug does not occur with JSC
  • The issue is reproducible with the latest version of React Native.

Hermes git revision (if applicable): release-v0.12? I'm using Hermes CLI with version 0.12.0
React Native version: N/A
OS: macOS Sonoma 14.2.1
Platform (most likely one of arm64-v8a, armeabi-v7a, x86, x86_64): x86_64

Steps To Reproduce

The following code running on Hermes will take significantly longer:

index_of_test.js:

const ARR_SIZE = 10000;

// Make an array of ARR_SIZE increasing non-negative integers
// [0, 1, 2, 3, 4, 5, 6, 7, 8, ...]
var test_arr = [];
for (var i = 0; i < ARR_SIZE; i++) {
  test_arr.push(i);
}

// Call indexOf 1000 times with the last element in the array
var start = Date.now();
for (var i = 0; i < 1000; i++) {
  test_arr.indexOf(ARR_SIZE - 1);
}
var end = Date.now();
print('Array.indexOf last element time: ' + (end - start));

// Call indexOf 1000 times with the first element in the array
var start = Date.now();
for (var i = 0; i < 1000; i++) {
  test_arr.indexOf(0);
}
var end = Date.now();
print('Array.indexOf first element time: ' + (end - start));
  1. Run with hermes cli: hermes ./index_of_test.js
Array.indexOf last element time: 253
Array.indexOf first element time: 0
  1. Run with JSC cli: jsc --useJIT=false ./index_of_test.js
Array.indexOf last element time: 3
Array.indexOf first element time: 0

My example seems to indicate that Hermes is much slower at iterating through and comparing Array values when compared to JSC.

Funnily enough, the same test using Array.prototype.includes() has similar performance between Hermes and JSC. I would assume (probably incorrectly) that the two functions use a similar algorithm. Although in this case, JSC is also much slower compared to its indexOf performance.

  1. Run with hermes ~/includes_test.js
Array.includes last element time: 122
Array.includes first element time: 0
  1. Run with jsc --useJIT=false ~/includes_test.js
Array.includes last element time: 116
Array.includes first element time: 0

The Expected Behavior

Hermes performance on Array.protoype.indexOf() should be on-par with JSC performance.

Thank you for reporting this! We can reproduce it and will address it. This is most likely because Array.protoype.indexOf() doesn't have a fast-path checking for an array.