Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/test/js-perf-test/Classes/default-constructor.js b/test/js-perf-test/Classes/default-constructor.js
new file mode 100644
index 0000000..49dcaa6
--- /dev/null
+++ b/test/js-perf-test/Classes/default-constructor.js
@@ -0,0 +1,33 @@
+// Copyright 2014 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.
+'use strict';
+
+var DefaultConstructorBenchmark = new BenchmarkSuite('DefaultConstructor',
+ [100], [
+ new Benchmark('NoSuperClass', false, false, 0, NoSuperClass),
+ new Benchmark('WithSuperClass', false, false, 0, WithSuperClass),
+ new Benchmark('WithSuperClassArguments', false, false, 0,
+ WithSuperClassArguments),
+ ]);
+
+
+class BaseClass {}
+
+
+class DerivedClass extends BaseClass {}
+
+
+function NoSuperClass() {
+ return new BaseClass();
+}
+
+
+function WithSuperClass() {
+ return new DerivedClass();
+}
+
+
+function WithSuperClassArguments() {
+ return new DerivedClass(0, 1, 2, 3, 4);
+}
diff --git a/test/js-perf-test/Classes/run.js b/test/js-perf-test/Classes/run.js
new file mode 100644
index 0000000..5d48b32
--- /dev/null
+++ b/test/js-perf-test/Classes/run.js
@@ -0,0 +1,28 @@
+// Copyright 2014 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.
+
+
+load('../base.js');
+load('super.js');
+load('default-constructor.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+ print(name + '-Classes(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+ PrintResult(name, error);
+ success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+ NotifyError: PrintError });
diff --git a/test/js-perf-test/Classes/super.js b/test/js-perf-test/Classes/super.js
new file mode 100644
index 0000000..a9ec766
--- /dev/null
+++ b/test/js-perf-test/Classes/super.js
@@ -0,0 +1,59 @@
+// Copyright 2014 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.
+'use strict';
+
+var SuperBenchmark = new BenchmarkSuite('Super', [100], [
+ new Benchmark('SuperMethodCall', false, false, 0, SuperMethodCall),
+ new Benchmark('SuperGetterCall', false, false, 0, SuperGetterCall),
+ new Benchmark('SuperSetterCall', false, false, 0, SuperSetterCall),
+]);
+
+
+function Base() { }
+Base.prototype = {
+ constructor: Base,
+ get x() {
+ return this._x++;
+ },
+ set x(v) {
+ this._x += v;
+ return this._x;
+ }
+}
+
+Base.prototype.f = function() {
+ return this._x++;
+}.toMethod(Base.prototype);
+
+function Derived() {
+ this._x = 1;
+}
+Derived.prototype = Object.create(Base.prototype);
+Object.setPrototypeOf(Derived, Base);
+
+Derived.prototype.SuperCall = function() {
+ return super.f();
+}.toMethod(Derived.prototype);
+
+Derived.prototype.GetterCall = function() {
+ return super.x;
+}.toMethod(Derived.prototype);
+
+Derived.prototype.SetterCall = function() {
+ return super.x = 5;
+}.toMethod(Derived.prototype);
+
+var derived = new Derived();
+
+function SuperMethodCall() {
+ return derived.SuperCall();
+}
+
+function SuperGetterCall() {
+ return derived.GetterCall();
+}
+
+function SuperSetterCall() {
+ return derived.SetterCall();
+}
diff --git a/test/js-perf-test/Collections/common.js b/test/js-perf-test/Collections/common.js
new file mode 100644
index 0000000..3ea3933
--- /dev/null
+++ b/test/js-perf-test/Collections/common.js
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+
+var N = 10;
+var keys;
+
+
+function SetupSmiKeys() {
+ keys = new Array(N * 2);
+ for (var i = 0; i < N * 2; i++) {
+ keys[i] = i;
+ }
+}
+
+
+function SetupStringKeys() {
+ keys = new Array(N * 2);
+ for (var i = 0; i < N * 2; i++) {
+ keys[i] = 's' + i;
+ }
+}
+
+
+function SetupObjectKeys() {
+ keys = new Array(N * 2);
+ for (var i = 0; i < N * 2; i++) {
+ keys[i] = {};
+ }
+}
diff --git a/test/js-perf-test/Collections/map.js b/test/js-perf-test/Collections/map.js
new file mode 100644
index 0000000..4f55798
--- /dev/null
+++ b/test/js-perf-test/Collections/map.js
@@ -0,0 +1,217 @@
+// Copyright 2014 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.
+
+
+var MapSmiBenchmark = new BenchmarkSuite('Map-Smi', [1000], [
+ new Benchmark('Set', false, false, 0, MapSetSmi, MapSetupSmiBase, MapTearDown),
+ new Benchmark('Has', false, false, 0, MapHasSmi, MapSetupSmi, MapTearDown),
+ new Benchmark('Get', false, false, 0, MapGetSmi, MapSetupSmi, MapTearDown),
+ new Benchmark('Delete', false, false, 0, MapDeleteSmi, MapSetupSmi, MapTearDown),
+]);
+
+
+var MapStringBenchmark = new BenchmarkSuite('Map-String', [1000], [
+ new Benchmark('Set', false, false, 0, MapSetString, MapSetupStringBase, MapTearDown),
+ new Benchmark('Has', false, false, 0, MapHasString, MapSetupString, MapTearDown),
+ new Benchmark('Get', false, false, 0, MapGetString, MapSetupString, MapTearDown),
+ new Benchmark('Delete', false, false, 0, MapDeleteString, MapSetupString, MapTearDown),
+]);
+
+
+var MapObjectBenchmark = new BenchmarkSuite('Map-Object', [1000], [
+ new Benchmark('Set', false, false, 0, MapSetObject, MapSetupObjectBase, MapTearDown),
+ new Benchmark('Has', false, false, 0, MapHasObject, MapSetupObject, MapTearDown),
+ new Benchmark('Get', false, false, 0, MapGetObject, MapSetupObject, MapTearDown),
+ new Benchmark('Delete', false, false, 0, MapDeleteObject, MapSetupObject, MapTearDown),
+]);
+
+
+var MapIterationBenchmark = new BenchmarkSuite('Map-Iteration', [1000], [
+ new Benchmark('ForEach', false, false, 0, MapForEach, MapSetupSmi, MapTearDown),
+]);
+
+
+var map;
+
+
+function MapSetupSmiBase() {
+ SetupSmiKeys();
+ map = new Map;
+}
+
+
+function MapSetupSmi() {
+ MapSetupSmiBase();
+ MapSetSmi();
+}
+
+
+function MapSetupStringBase() {
+ SetupStringKeys();
+ map = new Map;
+}
+
+
+function MapSetupString() {
+ MapSetupStringBase();
+ MapSetString();
+}
+
+
+function MapSetupObjectBase() {
+ SetupObjectKeys();
+ map = new Map;
+}
+
+
+function MapSetupObject() {
+ MapSetupObjectBase();
+ MapSetObject();
+}
+
+
+function MapTearDown() {
+ map = null;
+}
+
+
+function MapSetSmi() {
+ for (var i = 0; i < N; i++) {
+ map.set(keys[i], i);
+ }
+}
+
+
+function MapHasSmi() {
+ for (var i = 0; i < N; i++) {
+ if (!map.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (map.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function MapGetSmi() {
+ for (var i = 0; i < N; i++) {
+ if (map.get(keys[i]) !== i) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (map.get(keys[i]) !== undefined) {
+ throw new Error();
+ }
+ }
+}
+
+
+function MapDeleteSmi() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ map.delete(keys[i]);
+ }
+}
+
+
+function MapSetString() {
+ for (var i = 0; i < N; i++) {
+ map.set(keys[i], i);
+ }
+}
+
+
+function MapHasString() {
+ for (var i = 0; i < N; i++) {
+ if (!map.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (map.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function MapGetString() {
+ for (var i = 0; i < N; i++) {
+ if (map.get(keys[i]) !== i) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (map.get(keys[i]) !== undefined) {
+ throw new Error();
+ }
+ }
+}
+
+
+function MapDeleteString() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ map.delete(keys[i]);
+ }
+}
+
+
+function MapSetObject() {
+ for (var i = 0; i < N; i++) {
+ map.set(keys[i], i);
+ }
+}
+
+
+function MapHasObject() {
+ for (var i = 0; i < N; i++) {
+ if (!map.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (map.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function MapGetObject() {
+ for (var i = 0; i < N; i++) {
+ if (map.get(keys[i]) !== i) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (map.get(keys[i]) !== undefined) {
+ throw new Error();
+ }
+ }
+}
+
+
+function MapDeleteObject() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ map.delete(keys[i]);
+ }
+}
+
+
+function MapForEach() {
+ map.forEach(function(v, k) {
+ if (v !== k) {
+ throw new Error();
+ }
+ });
+}
diff --git a/test/js-perf-test/Collections/run.js b/test/js-perf-test/Collections/run.js
new file mode 100644
index 0000000..50f1ee1
--- /dev/null
+++ b/test/js-perf-test/Collections/run.js
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+
+load('../base.js');
+load('common.js');
+load('map.js');
+load('set.js');
+load('weakmap.js');
+load('weakset.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+ print(name + '-Collections(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+ PrintResult(name, error);
+ success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+ NotifyError: PrintError });
diff --git a/test/js-perf-test/Collections/set.js b/test/js-perf-test/Collections/set.js
new file mode 100644
index 0000000..3be27f5
--- /dev/null
+++ b/test/js-perf-test/Collections/set.js
@@ -0,0 +1,172 @@
+// Copyright 2014 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.
+
+
+var SetSmiBenchmark = new BenchmarkSuite('Set-Smi', [1000], [
+ new Benchmark('Set', false, false, 0, SetAddSmi, SetSetupSmiBase, SetTearDown),
+ new Benchmark('Has', false, false, 0, SetHasSmi, SetSetupSmi, SetTearDown),
+ new Benchmark('Delete', false, false, 0, SetDeleteSmi, SetSetupSmi, SetTearDown),
+]);
+
+
+var SetStringBenchmark = new BenchmarkSuite('Set-String', [1000], [
+ new Benchmark('Set', false, false, 0, SetAddString, SetSetupStringBase, SetTearDown),
+ new Benchmark('Has', false, false, 0, SetHasString, SetSetupString, SetTearDown),
+ new Benchmark('Delete', false, false, 0, SetDeleteString, SetSetupString, SetTearDown),
+]);
+
+
+var SetObjectBenchmark = new BenchmarkSuite('Set-Object', [1000], [
+ new Benchmark('Set', false, false, 0, SetAddObject, SetSetupObjectBase, SetTearDown),
+ new Benchmark('Has', false, false, 0, SetHasObject, SetSetupObject, SetTearDown),
+ new Benchmark('Delete', false, false, 0, SetDeleteObject, SetSetupObject, SetTearDown),
+]);
+
+
+var SetIterationBenchmark = new BenchmarkSuite('Set-Iteration', [1000], [
+ new Benchmark('ForEach', false, false, 0, SetForEach, SetSetupSmi, SetTearDown),
+]);
+
+
+var set;
+
+
+function SetSetupSmiBase() {
+ SetupSmiKeys();
+ set = new Set;
+}
+
+
+function SetSetupSmi() {
+ SetSetupSmiBase();
+ SetAddSmi();
+}
+
+
+function SetSetupStringBase() {
+ SetupStringKeys();
+ set = new Set;
+}
+
+
+function SetSetupString() {
+ SetSetupStringBase();
+ SetAddString();
+}
+
+
+function SetSetupObjectBase() {
+ SetupObjectKeys();
+ set = new Set;
+}
+
+
+function SetSetupObject() {
+ SetSetupObjectBase();
+ SetAddObject();
+}
+
+
+function SetTearDown() {
+ set = null;
+}
+
+
+function SetAddSmi() {
+ for (var i = 0; i < N; i++) {
+ set.add(keys[i], i);
+ }
+}
+
+
+function SetHasSmi() {
+ for (var i = 0; i < N; i++) {
+ if (!set.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (set.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function SetDeleteSmi() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ set.delete(keys[i]);
+ }
+}
+
+
+function SetAddString() {
+ for (var i = 0; i < N; i++) {
+ set.add(keys[i], i);
+ }
+}
+
+
+function SetHasString() {
+ for (var i = 0; i < N; i++) {
+ if (!set.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (set.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function SetDeleteString() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ set.delete(keys[i]);
+ }
+}
+
+
+function SetAddObject() {
+ for (var i = 0; i < N; i++) {
+ set.add(keys[i], i);
+ }
+}
+
+
+function SetHasObject() {
+ for (var i = 0; i < N; i++) {
+ if (!set.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (set.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function SetDeleteObject() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ set.delete(keys[i]);
+ }
+}
+
+
+function SetForEach() {
+ set.forEach(function(v, k) {
+ if (v !== k) {
+ throw new Error();
+ }
+ });
+}
diff --git a/test/js-perf-test/Collections/weakmap.js b/test/js-perf-test/Collections/weakmap.js
new file mode 100644
index 0000000..9aa265f
--- /dev/null
+++ b/test/js-perf-test/Collections/weakmap.js
@@ -0,0 +1,79 @@
+// Copyright 2014 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.
+
+
+var MapBenchmark = new BenchmarkSuite('WeakMap', [1000], [
+ new Benchmark('Set', false, false, 0, WeakMapSet, WeakMapSetupBase,
+ WeakMapTearDown),
+ new Benchmark('Has', false, false, 0, WeakMapHas, WeakMapSetup,
+ WeakMapTearDown),
+ new Benchmark('Get', false, false, 0, WeakMapGet, WeakMapSetup,
+ WeakMapTearDown),
+ new Benchmark('Delete', false, false, 0, WeakMapDelete, WeakMapSetup,
+ WeakMapTearDown),
+]);
+
+
+var wm;
+
+
+function WeakMapSetupBase() {
+ SetupObjectKeys();
+ wm = new WeakMap;
+}
+
+
+function WeakMapSetup() {
+ WeakMapSetupBase();
+ WeakMapSet();
+}
+
+
+function WeakMapTearDown() {
+ wm = null;
+}
+
+
+function WeakMapSet() {
+ for (var i = 0; i < N; i++) {
+ wm.set(keys[i], i);
+ }
+}
+
+
+function WeakMapHas() {
+ for (var i = 0; i < N; i++) {
+ if (!wm.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (wm.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function WeakMapGet() {
+ for (var i = 0; i < N; i++) {
+ if (wm.get(keys[i]) !== i) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (wm.get(keys[i]) !== undefined) {
+ throw new Error();
+ }
+ }
+}
+
+
+function WeakMapDelete() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ wm.delete(keys[i]);
+ }
+}
diff --git a/test/js-perf-test/Collections/weakset.js b/test/js-perf-test/Collections/weakset.js
new file mode 100644
index 0000000..2936477
--- /dev/null
+++ b/test/js-perf-test/Collections/weakset.js
@@ -0,0 +1,63 @@
+// Copyright 2014 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.
+
+
+var SetBenchmark = new BenchmarkSuite('WeakSet', [1000], [
+ new Benchmark('Add', false, false, 0, WeakSetAdd, WeakSetSetupBase,
+ WeakSetTearDown),
+ new Benchmark('Has', false, false, 0, WeakSetHas, WeakSetSetup,
+ WeakSetTearDown),
+ new Benchmark('Delete', false, false, 0, WeakSetDelete, WeakSetSetup,
+ WeakSetTearDown),
+]);
+
+
+var ws;
+
+
+function WeakSetSetupBase() {
+ SetupObjectKeys();
+ ws = new WeakSet;
+}
+
+
+function WeakSetSetup() {
+ WeakSetSetupBase();
+ WeakSetAdd();
+}
+
+
+function WeakSetTearDown() {
+ ws = null;
+}
+
+
+function WeakSetAdd() {
+ for (var i = 0; i < N; i++) {
+ ws.add(keys[i]);
+ }
+}
+
+
+function WeakSetHas() {
+ for (var i = 0; i < N; i++) {
+ if (!ws.has(keys[i])) {
+ throw new Error();
+ }
+ }
+ for (var i = N; i < 2 * N; i++) {
+ if (ws.has(keys[i])) {
+ throw new Error();
+ }
+ }
+}
+
+
+function WeakSetDelete() {
+ // This is run more than once per setup so we will end up deleting items
+ // more than once. Therefore, we do not the return value of delete.
+ for (var i = 0; i < N; i++) {
+ ws.delete(keys[i]);
+ }
+}
diff --git a/test/js-perf-test/Iterators/forof.js b/test/js-perf-test/Iterators/forof.js
new file mode 100644
index 0000000..1877ebe
--- /dev/null
+++ b/test/js-perf-test/Iterators/forof.js
@@ -0,0 +1,94 @@
+// Copyright 2014 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.
+
+new BenchmarkSuite('ForOf', [1000], [
+ new Benchmark('ArrayValues', false, false, 0,
+ ForOf, ForOfArraySetup, ForOfTearDown),
+ new Benchmark('ArrayKeys', false, false, 0,
+ ForOf, ForOfArrayKeysSetup, ForOfTearDown),
+ new Benchmark('ArrayEntries', false, false, 0,
+ ForOf, ForOfArrayEntriesSetup, ForOfTearDown),
+ new Benchmark('Uint8Array', false, false, 0,
+ ForOf, ForOfUint8ArraySetup, ForOfTearDown),
+ new Benchmark('Float64Array', false, false, 0,
+ ForOf, ForOfFloat64ArraySetup, ForOfTearDown),
+ new Benchmark('String', false, false, 0,
+ ForOf, ForOfStringSetup, ForOfTearDown),
+]);
+
+
+var iterable;
+var N = 100;
+var expected, result;
+
+
+function ForOfArraySetupHelper(constructor) {
+ iterable = new constructor(N);
+ for (var i = 0; i < N; i++) iterable[i] = i;
+ expected = N - 1;
+}
+
+
+function ForOfArraySetup() {
+ ForOfArraySetupHelper(Array);
+ // Default iterator is values().
+}
+
+
+function ForOfArrayKeysSetup() {
+ ForOfArraySetupHelper(Array);
+ iterable = iterable.keys();
+}
+
+
+function ForOfArrayEntriesSetup() {
+ ForOfArraySetupHelper(Array);
+ iterable = iterable.entries();
+ expected = [N-1, N-1];
+}
+
+
+function ForOfUint8ArraySetup() {
+ ForOfArraySetupHelper(Uint8Array);
+}
+
+
+function ForOfFloat64ArraySetup() {
+ ForOfArraySetupHelper(Float64Array);
+}
+
+
+function ForOfStringSetup() {
+ iterable = "abcdefhijklmnopqrstuvwxyzABCDEFHIJKLMNOPQRSTUVWXYZ0123456789";
+ expected = "9";
+}
+
+
+function Equals(expected, actual) {
+ if (expected === actual) return true;
+ if (typeof expected !== typeof actual) return false;
+ if (typeof expected !== 'object') return false;
+ for (var k of Object.keys(expected)) {
+ if (!(k in actual)) return false;
+ if (!Equals(expected[k], actual[k])) return false;
+ }
+ for (var k of Object.keys(actual)) {
+ if (!(k in expected)) return false;
+ }
+ return true;
+}
+
+function ForOfTearDown() {
+ iterable = null;
+ if (!Equals(expected, result)) {
+ throw new Error("Bad result: " + result);
+ }
+}
+
+
+function ForOf() {
+ for (var x of iterable) {
+ result = x;
+ }
+}
diff --git a/test/js-perf-test/Iterators/run.js b/test/js-perf-test/Iterators/run.js
new file mode 100644
index 0000000..ff4897f
--- /dev/null
+++ b/test/js-perf-test/Iterators/run.js
@@ -0,0 +1,27 @@
+// Copyright 2014 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.
+
+
+load('../base.js');
+load('forof.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+ print(name + '-Iterators(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+ PrintResult(name, error);
+ success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+ NotifyError: PrintError });
diff --git a/test/js-perf-test/JSTests.json b/test/js-perf-test/JSTests.json
new file mode 100644
index 0000000..0a99ad4
--- /dev/null
+++ b/test/js-perf-test/JSTests.json
@@ -0,0 +1,86 @@
+{
+ "name": "JSTests",
+ "run_count": 5,
+ "run_count_android_arm": 3,
+ "run_count_android_arm64": 3,
+ "units": "score",
+ "total": true,
+ "resources": ["base.js"],
+ "tests": [
+ {
+ "name": "Classes",
+ "path": ["Classes"],
+ "main": "run.js",
+ "resources": ["super.js", "default-constructor.js"],
+ "flags": ["--harmony-classes"],
+ "results_regexp": "^%s\\-Classes\\(Score\\): (.+)$",
+ "tests": [
+ {"name": "Super"},
+ {"name": "DefaultConstructor"}
+ ]
+ },
+ {
+ "name": "Collections",
+ "path": ["Collections"],
+ "main": "run.js",
+ "resources": [
+ "common.js",
+ "map.js",
+ "run.js",
+ "set.js",
+ "weakmap.js",
+ "weakset.js"
+ ],
+ "results_regexp": "^%s\\-Collections\\(Score\\): (.+)$",
+ "tests": [
+ {"name": "Map-Smi"},
+ {"name": "Map-String"},
+ {"name": "Map-Object"},
+ {"name": "Map-Iteration"},
+ {"name": "Set-Smi"},
+ {"name": "Set-String"},
+ {"name": "Set-Object"},
+ {"name": "Set-Iteration"},
+ {"name": "WeakMap"},
+ {"name": "WeakSet"}
+ ]
+ },
+ {
+ "name": "Iterators",
+ "path": ["Iterators"],
+ "main": "run.js",
+ "resources": ["forof.js"],
+ "results_regexp": "^%s\\-Iterators\\(Score\\): (.+)$",
+ "tests": [
+ {"name": "ForOf"}
+ ]
+ },
+ {
+ "name": "Strings",
+ "path": ["Strings"],
+ "main": "run.js",
+ "resources": ["harmony-string.js"],
+ "flags": ["--harmony-strings"],
+ "results_regexp": "^%s\\-Strings\\(Score\\): (.+)$",
+ "tests": [
+ {"name": "StringFunctions"}
+ ]
+ },
+ {
+ "name": "Templates",
+ "path": ["Templates"],
+ "main": "run.js",
+ "resources": ["templates.js"],
+ "flags": ["--harmony-templates"],
+ "run_count": 5,
+ "units": "score",
+ "results_regexp": "^%s\\-Templates\\(Score\\): (.+)$",
+ "total": true,
+ "tests": [
+ {"name": "Untagged"},
+ {"name": "LargeUntagged"},
+ {"name": "Tagged"}
+ ]
+ }
+ ]
+}
diff --git a/test/js-perf-test/Strings/harmony-string.js b/test/js-perf-test/Strings/harmony-string.js
new file mode 100644
index 0000000..c2eac4e
--- /dev/null
+++ b/test/js-perf-test/Strings/harmony-string.js
@@ -0,0 +1,111 @@
+// Copyright 2014 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.
+
+new BenchmarkSuite('StringFunctions', [1000], [
+ new Benchmark('StringRepeat', false, false, 0,
+ Repeat, RepeatSetup, RepeatTearDown),
+ new Benchmark('StringStartsWith', false, false, 0,
+ StartsWith, WithSetup, WithTearDown),
+ new Benchmark('StringEndsWith', false, false, 0,
+ EndsWith, WithSetup, WithTearDown),
+ new Benchmark('StringIncludes', false, false, 0,
+ Includes, IncludesSetup, WithTearDown),
+ new Benchmark('StringFromCodePoint', false, false, 0,
+ FromCodePoint, FromCodePointSetup, FromCodePointTearDown),
+ new Benchmark('StringCodePointAt', false, false, 0,
+ CodePointAt, CodePointAtSetup, CodePointAtTearDown),
+]);
+
+
+var result;
+
+var stringRepeatSource = "abc";
+
+function RepeatSetup() {
+ result = undefined;
+}
+
+function Repeat() {
+ result = stringRepeatSource.repeat(500);
+}
+
+function RepeatTearDown() {
+ var expected = "";
+ for(var i = 0; i < 1000; i++) {
+ expected += stringRepeatSource;
+ }
+ return result === expected;
+}
+
+
+var str;
+var substr;
+
+function WithSetup() {
+ str = "abc".repeat(500);
+ substr = "abc".repeat(200);
+ result = undefined;
+}
+
+function WithTearDown() {
+ return !!result;
+}
+
+function StartsWith() {
+ result = str.startsWith(substr);
+}
+
+function EndsWith() {
+ result = str.endsWith(substr);
+}
+
+function IncludesSetup() {
+ str = "def".repeat(100) + "abc".repeat(100) + "qqq".repeat(100);
+ substr = "abc".repeat(100);
+}
+
+function Includes() {
+ result = str.includes(substr);
+}
+
+var MAX_CODE_POINT = 0xFFFFF;
+
+function FromCodePointSetup() {
+ result = new Array(MAX_CODE_POINT + 1);
+}
+
+function FromCodePoint() {
+ for (var i = 0; i <= MAX_CODE_POINT; i++) {
+ result[i] = String.fromCodePoint(i);
+ }
+}
+
+function FromCodePointTearDown() {
+ for (var i = 0; i <= MAX_CODE_POINT; i++) {
+ if (i !== result[i].codePointAt(0)) return false;
+ }
+ return true;
+}
+
+
+var allCodePoints;
+
+function CodePointAtSetup() {
+ allCodePoints = new Array(MAX_CODE_POINT + 1);
+ for (var i = 0; i <= MAX_CODE_POINT; i++) {
+ allCodePoints = String.fromCodePoint(i);
+ }
+ result = undefined;
+}
+
+function CodePointAt() {
+ result = 0;
+ for (var i = 0; i <= MAX_CODE_POINT; i++) {
+ result += allCodePoints.codePointAt(i);
+ }
+}
+
+function CodePointAtTearDown() {
+ return result === MAX_CODE_POINT * (MAX_CODE_POINT + 1) / 2;
+}
diff --git a/test/js-perf-test/Strings/run.js b/test/js-perf-test/Strings/run.js
new file mode 100644
index 0000000..79ca26e
--- /dev/null
+++ b/test/js-perf-test/Strings/run.js
@@ -0,0 +1,27 @@
+// Copyright 2014 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.
+
+
+load('../base.js');
+load('harmony-string.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+ print(name + '-Strings(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+ PrintResult(name, error);
+ success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+ NotifyError: PrintError });
diff --git a/test/js-perf-test/Templates/run.js b/test/js-perf-test/Templates/run.js
new file mode 100644
index 0000000..73f1edd
--- /dev/null
+++ b/test/js-perf-test/Templates/run.js
@@ -0,0 +1,27 @@
+// Copyright 2014 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.
+
+
+load('../base.js');
+load('templates.js');
+
+
+var success = true;
+
+function PrintResult(name, result) {
+ print(name + '-Templates(Score): ' + result);
+}
+
+
+function PrintError(name, error) {
+ PrintResult(name, error);
+ success = false;
+}
+
+
+BenchmarkSuite.config.doWarmup = undefined;
+BenchmarkSuite.config.doDeterministic = undefined;
+
+BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
+ NotifyError: PrintError });
diff --git a/test/js-perf-test/Templates/templates.js b/test/js-perf-test/Templates/templates.js
new file mode 100644
index 0000000..4034ce7
--- /dev/null
+++ b/test/js-perf-test/Templates/templates.js
@@ -0,0 +1,87 @@
+// Copyright 2014 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.
+
+new BenchmarkSuite('Untagged', [1000], [
+ new Benchmark('Untagged-Simple', false, false, 0,
+ Untagged, UntaggedSetup, UntaggedTearDown),
+]);
+
+new BenchmarkSuite('LargeUntagged', [1000], [
+ new Benchmark('Untagged-Large', false, false, 0,
+ UntaggedLarge, UntaggedLargeSetup, UntaggedLargeTearDown),
+]);
+
+new BenchmarkSuite('Tagged', [1000], [
+ new Benchmark('TaggedRawSimple', false, false, 0,
+ TaggedRaw, TaggedRawSetup, TaggedRawTearDown),
+]);
+
+var result;
+var SUBJECT = 'Bob';
+var TARGET = 'Mary';
+var OBJECT = 'apple';
+
+function UntaggedSetup() {
+ result = undefined;
+}
+
+function Untagged() {
+ result = `${SUBJECT} gives ${TARGET} an ${OBJECT}.`;
+}
+
+function UntaggedTearDown() {
+ var expected = '' + SUBJECT + ' gives ' + TARGET + ' an ' + OBJECT + '.';
+ return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
+
+function UntaggedLargeSetup() {
+ result = undefined;
+}
+
+function UntaggedLarge() {
+ result = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
+ aliquam, elit euismod vestibulum ${0}lacinia, arcu odio sagittis mauris, id
+ blandit dolor felis pretium nisl. Maecenas porttitor, nunc ut accumsan mollis,
+ arcu metus rutrum arcu, ${1}ut varius dolor lorem nec risus. Integer convallis
+ tristique ante, non pretium ante suscipit at. Sed egestas massa enim, convallis
+ fermentum neque vehicula ac. Donec imperdiet a tortor ac semper. Morbi accumsan
+ quam nec erat viverra iaculis. ${2}Donec a scelerisque cras amet.`;
+}
+
+function UntaggedLargeTearDown() {
+ var expected = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
+ "Vivamus\n aliquam, elit euismod vestibulum " + 0 + "lacinia, arcu odio" +
+ " sagittis mauris, id\n blandit dolor felis pretium nisl. Maecenas " +
+ "porttitor, nunc ut accumsan mollis,\n arcu metus rutrum arcu, " + 1 +
+ "ut varius dolor lorem nec risus. Integer convallis\n tristique ante, " +
+ "non pretium ante suscipit at. Sed egestas massa enim, convallis\n " +
+ "fermentum neque vehicula ac. Donec imperdiet a tortor ac semper. Morbi" +
+ " accumsan\n quam nec erat viverra iaculis. " + 2 + "Donec a " +
+ "scelerisque cras amet.";
+ return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+function TaggedRawSetup() {
+ result = undefined;
+}
+
+function TaggedRaw() {
+ result = String.raw `${SUBJECT} gives ${TARGET} an ${OBJECT} \ud83c\udf4f.`;
+}
+
+function TaggedRawTearDown() {
+ var expected =
+ '' + SUBJECT + ' gives ' + TARGET + ' an ' + OBJECT + ' \\ud83c\\udf4f.';
+ return result === expected;
+}
+
+
+// ----------------------------------------------------------------------------
diff --git a/test/js-perf-test/base.js b/test/js-perf-test/base.js
new file mode 100644
index 0000000..b0ce40b
--- /dev/null
+++ b/test/js-perf-test/base.js
@@ -0,0 +1,367 @@
+// Copyright 2014 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.
+
+
+// Performance.now is used in latency benchmarks, the fallback is Date.now.
+var performance = performance || {};
+performance.now = (function() {
+ return performance.now ||
+ performance.mozNow ||
+ performance.msNow ||
+ performance.oNow ||
+ performance.webkitNow ||
+ Date.now;
+})();
+
+// Simple framework for running the benchmark suites and
+// computing a score based on the timing measurements.
+
+
+// A benchmark has a name (string) and a function that will be run to
+// do the performance measurement. The optional setup and tearDown
+// arguments are functions that will be invoked before and after
+// running the benchmark, but the running time of these functions will
+// not be accounted for in the benchmark score.
+function Benchmark(name, doWarmup, doDeterministic, deterministicIterations,
+ run, setup, tearDown, rmsResult, minIterations) {
+ this.name = name;
+ this.doWarmup = doWarmup;
+ this.doDeterministic = doDeterministic;
+ this.deterministicIterations = deterministicIterations;
+ this.run = run;
+ this.Setup = setup ? setup : function() { };
+ this.TearDown = tearDown ? tearDown : function() { };
+ this.rmsResult = rmsResult ? rmsResult : null;
+ this.minIterations = minIterations ? minIterations : 32;
+}
+
+
+// Benchmark results hold the benchmark and the measured time used to
+// run the benchmark. The benchmark score is computed later once a
+// full benchmark suite has run to completion. If latency is set to 0
+// then there is no latency score for this benchmark.
+function BenchmarkResult(benchmark, time, latency) {
+ this.benchmark = benchmark;
+ this.time = time;
+ this.latency = latency;
+}
+
+
+// Automatically convert results to numbers. Used by the geometric
+// mean computation.
+BenchmarkResult.prototype.valueOf = function() {
+ return this.time;
+}
+
+
+// Suites of benchmarks consist of a name and the set of benchmarks in
+// addition to the reference timing that the final score will be based
+// on. This way, all scores are relative to a reference run and higher
+// scores implies better performance.
+function BenchmarkSuite(name, reference, benchmarks) {
+ this.name = name;
+ this.reference = reference;
+ this.benchmarks = benchmarks;
+ BenchmarkSuite.suites.push(this);
+}
+
+
+// Keep track of all declared benchmark suites.
+BenchmarkSuite.suites = [];
+
+// Scores are not comparable across versions. Bump the version if
+// you're making changes that will affect that scores, e.g. if you add
+// a new benchmark or change an existing one.
+BenchmarkSuite.version = '1';
+
+
+// Defines global benchsuite running mode that overrides benchmark suite
+// behavior. Intended to be set by the benchmark driver. Undefined
+// values here allow a benchmark to define behaviour itself.
+BenchmarkSuite.config = {
+ doWarmup: undefined,
+ doDeterministic: undefined
+};
+
+
+// Override the alert function to throw an exception instead.
+alert = function(s) {
+ throw "Alert called with argument: " + s;
+};
+
+
+// To make the benchmark results predictable, we replace Math.random
+// with a 100% deterministic alternative.
+BenchmarkSuite.ResetRNG = function() {
+ Math.random = (function() {
+ var seed = 49734321;
+ return function() {
+ // Robert Jenkins' 32 bit integer hash function.
+ seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
+ seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
+ seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
+ seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
+ seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
+ seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
+ return (seed & 0xfffffff) / 0x10000000;
+ };
+ })();
+}
+
+
+// Runs all registered benchmark suites and optionally yields between
+// each individual benchmark to avoid running for too long in the
+// context of browsers. Once done, the final score is reported to the
+// runner.
+BenchmarkSuite.RunSuites = function(runner, skipBenchmarks) {
+ skipBenchmarks = typeof skipBenchmarks === 'undefined' ? [] : skipBenchmarks;
+ var continuation = null;
+ var suites = BenchmarkSuite.suites;
+ var length = suites.length;
+ BenchmarkSuite.scores = [];
+ var index = 0;
+ function RunStep() {
+ while (continuation || index < length) {
+ if (continuation) {
+ continuation = continuation();
+ } else {
+ var suite = suites[index++];
+ if (runner.NotifyStart) runner.NotifyStart(suite.name);
+ if (skipBenchmarks.indexOf(suite.name) > -1) {
+ suite.NotifySkipped(runner);
+ } else {
+ continuation = suite.RunStep(runner);
+ }
+ }
+ if (continuation && typeof window != 'undefined' && window.setTimeout) {
+ window.setTimeout(RunStep, 25);
+ return;
+ }
+ }
+
+ // show final result
+ if (runner.NotifyScore) {
+ var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);
+ var formatted = BenchmarkSuite.FormatScore(100 * score);
+ runner.NotifyScore(formatted);
+ }
+ }
+ RunStep();
+}
+
+
+// Counts the total number of registered benchmarks. Useful for
+// showing progress as a percentage.
+BenchmarkSuite.CountBenchmarks = function() {
+ var result = 0;
+ var suites = BenchmarkSuite.suites;
+ for (var i = 0; i < suites.length; i++) {
+ result += suites[i].benchmarks.length;
+ }
+ return result;
+}
+
+
+// Computes the geometric mean of a set of numbers.
+BenchmarkSuite.GeometricMean = function(numbers) {
+ var log = 0;
+ for (var i = 0; i < numbers.length; i++) {
+ log += Math.log(numbers[i]);
+ }
+ return Math.pow(Math.E, log / numbers.length);
+}
+
+
+// Computes the geometric mean of a set of throughput time measurements.
+BenchmarkSuite.GeometricMeanTime = function(measurements) {
+ var log = 0;
+ for (var i = 0; i < measurements.length; i++) {
+ log += Math.log(measurements[i].time);
+ }
+ return Math.pow(Math.E, log / measurements.length);
+}
+
+
+// Computes the geometric mean of a set of rms measurements.
+BenchmarkSuite.GeometricMeanLatency = function(measurements) {
+ var log = 0;
+ var hasLatencyResult = false;
+ for (var i = 0; i < measurements.length; i++) {
+ if (measurements[i].latency != 0) {
+ log += Math.log(measurements[i].latency);
+ hasLatencyResult = true;
+ }
+ }
+ if (hasLatencyResult) {
+ return Math.pow(Math.E, log / measurements.length);
+ } else {
+ return 0;
+ }
+}
+
+
+// Converts a score value to a string with at least three significant
+// digits.
+BenchmarkSuite.FormatScore = function(value) {
+ if (value > 100) {
+ return value.toFixed(0);
+ } else {
+ return value.toPrecision(3);
+ }
+}
+
+// Notifies the runner that we're done running a single benchmark in
+// the benchmark suite. This can be useful to report progress.
+BenchmarkSuite.prototype.NotifyStep = function(result) {
+ this.results.push(result);
+ if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);
+}
+
+
+// Notifies the runner that we're done with running a suite and that
+// we have a result which can be reported to the user if needed.
+BenchmarkSuite.prototype.NotifyResult = function() {
+ var mean = BenchmarkSuite.GeometricMeanTime(this.results);
+ var score = this.reference[0] / mean;
+ BenchmarkSuite.scores.push(score);
+ if (this.runner.NotifyResult) {
+ var formatted = BenchmarkSuite.FormatScore(100 * score);
+ this.runner.NotifyResult(this.name, formatted);
+ }
+ if (this.reference.length == 2) {
+ var meanLatency = BenchmarkSuite.GeometricMeanLatency(this.results);
+ if (meanLatency != 0) {
+ var scoreLatency = this.reference[1] / meanLatency;
+ BenchmarkSuite.scores.push(scoreLatency);
+ if (this.runner.NotifyResult) {
+ var formattedLatency = BenchmarkSuite.FormatScore(100 * scoreLatency)
+ this.runner.NotifyResult(this.name + "Latency", formattedLatency);
+ }
+ }
+ }
+}
+
+
+BenchmarkSuite.prototype.NotifySkipped = function(runner) {
+ BenchmarkSuite.scores.push(1); // push default reference score.
+ if (runner.NotifyResult) {
+ runner.NotifyResult(this.name, "Skipped");
+ }
+}
+
+
+// Notifies the runner that running a benchmark resulted in an error.
+BenchmarkSuite.prototype.NotifyError = function(error) {
+ if (this.runner.NotifyError) {
+ this.runner.NotifyError(this.name, error);
+ }
+ if (this.runner.NotifyStep) {
+ this.runner.NotifyStep(this.name);
+ }
+}
+
+
+// Runs a single benchmark for at least a second and computes the
+// average time it takes to run a single iteration.
+BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark, data) {
+ var config = BenchmarkSuite.config;
+ var doWarmup = config.doWarmup !== undefined
+ ? config.doWarmup
+ : benchmark.doWarmup;
+ var doDeterministic = config.doDeterministic !== undefined
+ ? config.doDeterministic
+ : benchmark.doDeterministic;
+
+ function Measure(data) {
+ var elapsed = 0;
+ var start = new Date();
+
+ // Run either for 1 second or for the number of iterations specified
+ // by minIterations, depending on the config flag doDeterministic.
+ for (var i = 0; (doDeterministic ?
+ i<benchmark.deterministicIterations : elapsed < 1000); i++) {
+ benchmark.run();
+ elapsed = new Date() - start;
+ }
+ if (data != null) {
+ data.runs += i;
+ data.elapsed += elapsed;
+ }
+ }
+
+ // Sets up data in order to skip or not the warmup phase.
+ if (!doWarmup && data == null) {
+ data = { runs: 0, elapsed: 0 };
+ }
+
+ if (data == null) {
+ Measure(null);
+ return { runs: 0, elapsed: 0 };
+ } else {
+ Measure(data);
+ // If we've run too few iterations, we continue for another second.
+ if (data.runs < benchmark.minIterations) return data;
+ var usec = (data.elapsed * 1000) / data.runs;
+ var rms = (benchmark.rmsResult != null) ? benchmark.rmsResult() : 0;
+ this.NotifyStep(new BenchmarkResult(benchmark, usec, rms));
+ return null;
+ }
+}
+
+
+// This function starts running a suite, but stops between each
+// individual benchmark in the suite and returns a continuation
+// function which can be invoked to run the next benchmark. Once the
+// last benchmark has been executed, null is returned.
+BenchmarkSuite.prototype.RunStep = function(runner) {
+ BenchmarkSuite.ResetRNG();
+ this.results = [];
+ this.runner = runner;
+ var length = this.benchmarks.length;
+ var index = 0;
+ var suite = this;
+ var data;
+
+ // Run the setup, the actual benchmark, and the tear down in three
+ // separate steps to allow the framework to yield between any of the
+ // steps.
+
+ function RunNextSetup() {
+ if (index < length) {
+ try {
+ suite.benchmarks[index].Setup();
+ } catch (e) {
+ suite.NotifyError(e);
+ return null;
+ }
+ return RunNextBenchmark;
+ }
+ suite.NotifyResult();
+ return null;
+ }
+
+ function RunNextBenchmark() {
+ try {
+ data = suite.RunSingleBenchmark(suite.benchmarks[index], data);
+ } catch (e) {
+ suite.NotifyError(e);
+ return null;
+ }
+ // If data is null, we're done with this benchmark.
+ return (data == null) ? RunNextTearDown : RunNextBenchmark();
+ }
+
+ function RunNextTearDown() {
+ try {
+ suite.benchmarks[index++].TearDown();
+ } catch (e) {
+ suite.NotifyError(e);
+ return null;
+ }
+ return RunNextSetup;
+ }
+
+ // Start out running the setup.
+ return RunNextSetup();
+}