1/* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16declare function print(arg:any): string; 17 18declare interface ArkTools { 19 timeInUs(arg: any): number; 20 isStableJsArray(arr: any[]): boolean; 21 getElementsKind(arr: any[]): number; 22} 23 24const REP_COUNT = 100_000; 25 26function initializeDenseArray(target: any, len: number, a: number, b: number, intOnly = true) { 27 for (let i = 0; i < len; i++) { 28 target[i] = (i * a + b) % len; 29 if (!intOnly && i % 2 == 0) { 30 target[i] += i / len; // int : double = 50% : 50% 31 } 32 } 33} 34 35function initializeSparseArray(target: any, len: number, nNonHole: number, a: number, b: number, intOnly = true) { 36 let last = 0; 37 const getNextElement = () => { 38 const res = (last * a + b) % len; 39 last = res; 40 return res; 41 } 42 for (let i = 0; i < nNonHole; i++) { 43 const index = getNextElement(); 44 let value = getNextElement(); 45 if (!intOnly && i % 2 == 0) { 46 value += i / len; // int : double = 50% : 50% 47 } 48 target[index] = value; 49 } 50} 51 52const result = {}; 53 54function testArrayFunc(fnName: string, caseName: string, arr: number[]) { 55 print(`-------- Starts new test of Array.prototype.${fnName}() --------`) 56 print(`Is arr stable array? ${ArkTools.isStableJsArray(arr)}`); 57 print(`arr.length = ${arr.length}. ElementsKind of arr: ${ArkTools.getElementsKind(arr)}`); 58 const someObj = { x: 1, y: 2, valueOf() { return 3; } }; 59 60 let start: number; 61 let end: number; 62 let endExtra: number; 63 64 start = ArkTools.timeInUs(); 65 for (let i = 0; i < REP_COUNT; i++) { 66 arr[fnName](i); 67 } 68 end = ArkTools.timeInUs(); 69 for (let i = 0; i < REP_COUNT; i++) { 70 arr[fnName]; 71 i; 72 } 73 endExtra = ArkTools.timeInUs(); 74 const durationI = result[`${fnName}.${caseName}.intIndex`] = (2 * end - start - endExtra) / 1000; 75 print(`\tsearchElement is integer: ${durationI.toFixed(3)} ms.`); 76 77 start = ArkTools.timeInUs(); 78 for (let i = 0; i < REP_COUNT; i++) { 79 arr[fnName](1.1 * i); // Expects early exit when target is not within int32 (90% chance) 80 } 81 end = ArkTools.timeInUs(); 82 for (let i = 0; i < REP_COUNT; i++) { 83 arr[fnName]; 84 1.1 * i; 85 } 86 endExtra = ArkTools.timeInUs(); 87 const durationF = result[`${fnName}.${caseName}.doubleIndex`] = (2 * end - start - endExtra) / 1000; 88 print(`\tsearchElement is double: ${durationF.toFixed(3)} ms.`); 89 90 start = ArkTools.timeInUs(); 91 for (let i = 0; i < REP_COUNT; i++) { 92 arr[fnName]("1"); // Expects early exit 93 } 94 end = ArkTools.timeInUs(); 95 for (let i = 0; i < REP_COUNT; i++) { 96 arr[fnName]; 97 "1"; 98 } 99 endExtra = ArkTools.timeInUs(); 100 const durationS = result[`${fnName}.${caseName}.stringIndex`] = (2 * end - start - endExtra) / 1000; 101 print(`\tsearchElement is string: ${durationS.toFixed(3)} ms.`); 102 103 start = ArkTools.timeInUs(); 104 for (let i = 0; i < REP_COUNT; i++) { 105 arr[fnName](someObj); // Expects early exit 106 } 107 end = ArkTools.timeInUs(); 108 for (let i = 0; i < REP_COUNT; i++) { 109 arr[fnName]; 110 someObj; 111 } 112 endExtra = ArkTools.timeInUs(); 113 const durationO = result[`${fnName}.${caseName}.objectIndex`] = (2 * end - start - endExtra) / 1000; 114 print(`\tsearchElement is object: ${durationO.toFixed(3)} ms.`); 115} 116 117for (const fnName of ['includes', 'indexOf', 'lastIndexOf']) { 118 { 119 const empty = []; 120 testArrayFunc(fnName, 'empty', empty); 121 } 122 { 123 const [ARR_LENGTH, N_NOT_HOLE_ELEMENTS, GEN_A, GEN_B] = [1499, 100, 233, 1]; 124 const arr = new Array<number>(ARR_LENGTH); 125 initializeSparseArray(arr, ARR_LENGTH, N_NOT_HOLE_ELEMENTS, GEN_A, GEN_B); 126 testArrayFunc(fnName, `sparse.len${ARR_LENGTH}.generic`, arr); // ElementKind = 31 (GENERIC) 127 } 128 { 129 const [ARR_LENGTH, GEN_A, GEN_B] = [10007, 233, 1]; 130 const arr = new Array<number>(ARR_LENGTH); 131 initializeDenseArray(arr, ARR_LENGTH, GEN_A, GEN_B); 132 testArrayFunc(fnName, `dense.len${ARR_LENGTH}.generic`, arr); // ElementKind = 31 (GENERIC) 133 } 134 for (const intOnly of [true, false]) { 135 { 136 const [ARR_LENGTH, GEN_A, GEN_B] = [17, 5, 1]; 137 const arr: number[] = []; 138 initializeDenseArray(arr, ARR_LENGTH, GEN_A, GEN_B, intOnly); 139 testArrayFunc(fnName, `dense.len${ARR_LENGTH}.${intOnly ? 'int' : 'number'}`, arr); 140 } 141 { 142 const [ARR_LENGTH, N_NOT_HOLE_ELEMENTS, GEN_A, GEN_B] = [1499, 100, 233, 1]; 143 const arr: number[] = []; 144 initializeSparseArray(arr, ARR_LENGTH, N_NOT_HOLE_ELEMENTS, GEN_A, GEN_B, intOnly); 145 testArrayFunc(fnName, `sparse.len${ARR_LENGTH}.hole${intOnly ? 'Int' : 'Number'}`, arr); 146 } 147 { 148 const [ARR_LENGTH, GEN_A, GEN_B] = [10007, 233, 1]; 149 const arr: number[] = []; 150 initializeDenseArray(arr, ARR_LENGTH, GEN_A, GEN_B, intOnly); 151 testArrayFunc(fnName, `dense.len${ARR_LENGTH}.${intOnly ? 'int' : 'number'}`, arr); 152 } 153 } 154} 155 156print(JSON.stringify(result, null, 4)); 157