// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. function ObjectWithKeys(count, keyOffset, keyGen) { if (keyOffset === undefined) keyOffset = 0; if (keyGen === undefined) keyGen = (i) => { return "key" + i }; var o = {}; for (var i = 0; i < count; i++) { var key = keyGen(i + keyOffset); o[key] = "value"; } return o } function ObjectWithMixedKeys(count, keyOffset) { return ObjectWithKeys(count, keyOffset, (key) => { if (key % 2 == 0) return key; return "key" + key; }); } // Create an object with #depth prototypes each having #keys properties. function ObjectWithProtoKeys(depth, keys, cacheable) { var o = ObjectWithKeys(keys); var current = o; var keyOffset = 0; for (var i = 0; i < depth; i++) { keyOffset += keys; current.__proto__ = ObjectWithKeys(keys, keyOffset); current = current.__proto__; } if (cacheable === false) { // Add an empty proxy at the prototype chain to make caching properties // impossible. current.__proto__ = new Proxy({}, {}); } return o; } function HoleyIntArray(size) { var array = new Array(size); for (var i = 0; i < size; i += 3) { array[i] = i; } return array } function IntArray(size) { var array = new Array(size); for (var i = 0; i < size; i++) { array[i] = i; } return array; } // ============================================================================ var object_empty = {}; var array_empty = []; var array_int_50 = IntArray(50); var array_int_50_proto_elements = IntArray(50); array_int_50_proto_elements.__proto__ = [51, 52, 53, 54]; var array_int_holey_50 = HoleyIntArray(50); var empty_proto_5_10 = ObjectWithKeys(5); empty_proto_5_10.__proto__ = ObjectWithProtoKeys(10, 0); var empty_proto_5_0 = ObjectWithKeys(5); var empty_proto_5_5_slow = ObjectWithKeys(5); empty_proto_5_5_slow.__proto__ = ObjectWithProtoKeys(5, 0, false); var object_elements_proto_5_10 = ObjectWithKeys(5); object_elements_proto_5_10.__proto__ = ObjectWithProtoKeys(10, 0); // Add some properties further up the prototype chain, the rest stays // empty. for (var i = 0; i < 5; i++) { object_elements_proto_5_10.__proto__.__proto__.__proto__["proto" + i] = true; } var TestObjects = { object_empty: object_empty, array_empty: array_empty, array_int_50: array_int_50, array_int_holey_50: array_int_holey_50, array_int_50_proto_elements: array_int_50_proto_elements, empty_proto_5_10: empty_proto_5_10, empty_proto_5_5_slow: empty_proto_5_5_slow, object_elements_proto_5_10: object_elements_proto_5_10 } var TestArrays = { array_empty: array_empty, array_int_50: array_int_50, array_int_holey_50: array_int_holey_50, array_int_50_proto_elements: array_int_50_proto_elements, } // ============================================================================ function CreateTestFunctionGen(fn) { // Force a new function for each test-object to avoid side-effects due to ICs. return (object) => { var random_comment = "\n// random comment" + Math.random() + "\n"; return eval(random_comment + fn.toString()); } } var TestFunctions = { "Object.keys()": CreateTestFunctionGen(() => {return Object.keys(object)}), "for-in": CreateTestFunctionGen(() => { var count = 0; var result; for (var key in object) { count++; result = object[key]; }; return [result, count]; }), "for-in hasOwnProperty()": CreateTestFunctionGen(() => { var count = 0; var result; for (var key in object) { if (!object.hasOwnProperty(key)) continue; count++; result = object[key]; }; return [result, count]; }), "for (i < Object.keys().length)": CreateTestFunctionGen(() => { var count = 0; var result; var keys = Object.keys(object); for (var i = 0; i < keys.length; i++) { count++; result = object[keys[i]]; }; return [result, count]; }), "Object.keys().forEach()": CreateTestFunctionGen(() => { var count = 0; var result; Object.keys(object).forEach((value, index, obj) => { count++; result = value; }); return [result, count]; }), "for-in-multi-objects": CreateTestFunctionGen(() => { var count = 0; var result; for (var key in object) { count++; result = object[key]; if (empty_proto_5_0[key]) { count++; } } return [result, count]; }), } var TestFunctionsArrays = { "for (i < array.length)": CreateTestFunctionGen(() => { var count = 0; var result; for (var i = 0; i < object.length; i++) { count++; result = object[i]; }; return [result, count]; }), "for (i < length)": CreateTestFunctionGen(() => { var count = 0; var result; var length = object.length; for (var i = 0; i < length; i++) { count++; result = object[i]; }; return [result, count]; }) } // ============================================================================ // Create the benchmark suites. We create a suite for each of the test // functions above and each suite contains benchmarks for each object type. var Benchmarks = []; function NewBenchmark( test_function_gen, test_function_name, test_object, test_object_name) { var object = test_object; var name = test_function_name + " " + test_object_name; var test_function = test_function_gen(object); return new Benchmark(name, false, false, 0, test_function) } for (var test_function_name in TestFunctions) { var test_function_gen = TestFunctions[test_function_name]; var benchmarks = []; for (var test_object_name in TestObjects) { var test_object = TestObjects[test_object_name]; var benchmark = NewBenchmark( test_function_gen, test_function_name, test_object, test_object_name); benchmarks.push(benchmark); } Benchmarks.push(new BenchmarkSuite(test_function_name, [100], benchmarks)); } for (var test_function_name in TestFunctionsArrays) { var test_function_gen = TestFunctionsArrays[test_function_name]; var benchmarks = []; for (var test_array_name in TestArrays) { var test_array = TestArrays[test_array_name]; var benchmark = NewBenchmark( test_function_gen, test_function_name, test_array, test_array_name); benchmarks.push(benchmark); } Benchmarks.push(new BenchmarkSuite(test_function_name, [100], benchmarks)); } // ============================================================================