From 4dc81d37886f49512eb60dafe13b794af5ffeb29 Mon Sep 17 00:00:00 2001
From: Mike Pennisi <mike@mikepennisi.com>
Date: Mon, 1 Feb 2016 12:10:33 -0500
Subject: [PATCH] Add tests for tail-call optimization

ECMAScript 2015 introduced tail call optimization for function calls
occuring in a number of positions in the grammar. Assert expected
behavior by triggering a large (but configurable) number of recursive
function calls in these positions. Compliant runtimes will execute such
programs without error; non-compliant runtimes are expected to fail
these tests by throwing an error or crashing when system resources are
exhausted.
---
 harness/tco-helper.js                         |  4 +++
 .../expressions/call/tco-call-args.js         | 20 +++++++++++++++
 .../expressions/call/tco-member-args.js       | 19 ++++++++++++++
 test/language/expressions/comma/tco-final.js  | 19 ++++++++++++++
 .../expressions/conditional/tco-cond.js       | 19 ++++++++++++++
 .../expressions/conditional/tco-pos.js        | 19 ++++++++++++++
 .../expressions/logical-and/tco-right.js      | 19 ++++++++++++++
 .../expressions/logical-or/tco-right.js       | 19 ++++++++++++++
 .../expressions/tagged-template/tco-call.js   | 25 +++++++++++++++++++
 .../expressions/tagged-template/tco-member.js | 22 ++++++++++++++++
 test/language/expressions/tco-pos.js          | 19 ++++++++++++++
 .../statements/block/tco-stmt-list.js         | 19 ++++++++++++++
 test/language/statements/block/tco-stmt.js    | 19 ++++++++++++++
 test/language/statements/do-while/tco-body.js | 21 ++++++++++++++++
 .../language/statements/for/tco-const-body.js | 21 ++++++++++++++++
 test/language/statements/for/tco-let-body.js  | 21 ++++++++++++++++
 test/language/statements/for/tco-lhs-body.js  | 22 ++++++++++++++++
 test/language/statements/for/tco-var-body.js  | 21 ++++++++++++++++
 test/language/statements/if/tco-else-body.js  | 19 ++++++++++++++
 test/language/statements/if/tco-if-body.js    | 19 ++++++++++++++
 test/language/statements/labeled/tco.js       | 19 ++++++++++++++
 test/language/statements/return/tco.js        | 19 ++++++++++++++
 .../statements/switch/tco-case-body-dflt.js   | 19 ++++++++++++++
 .../statements/switch/tco-case-body.js        | 19 ++++++++++++++
 .../statements/switch/tco-dftl-body.js        | 19 ++++++++++++++
 .../statements/try/tco-catch-finally.js       | 21 ++++++++++++++++
 test/language/statements/try/tco-catch.js     | 23 +++++++++++++++++
 test/language/statements/try/tco-finally.js   | 21 ++++++++++++++++
 test/language/statements/while/tco-body.js    | 21 ++++++++++++++++
 29 files changed, 567 insertions(+)
 create mode 100644 harness/tco-helper.js
 create mode 100644 test/language/expressions/call/tco-call-args.js
 create mode 100644 test/language/expressions/call/tco-member-args.js
 create mode 100644 test/language/expressions/comma/tco-final.js
 create mode 100644 test/language/expressions/conditional/tco-cond.js
 create mode 100644 test/language/expressions/conditional/tco-pos.js
 create mode 100644 test/language/expressions/logical-and/tco-right.js
 create mode 100644 test/language/expressions/logical-or/tco-right.js
 create mode 100644 test/language/expressions/tagged-template/tco-call.js
 create mode 100644 test/language/expressions/tagged-template/tco-member.js
 create mode 100644 test/language/expressions/tco-pos.js
 create mode 100644 test/language/statements/block/tco-stmt-list.js
 create mode 100644 test/language/statements/block/tco-stmt.js
 create mode 100644 test/language/statements/do-while/tco-body.js
 create mode 100644 test/language/statements/for/tco-const-body.js
 create mode 100644 test/language/statements/for/tco-let-body.js
 create mode 100644 test/language/statements/for/tco-lhs-body.js
 create mode 100644 test/language/statements/for/tco-var-body.js
 create mode 100644 test/language/statements/if/tco-else-body.js
 create mode 100644 test/language/statements/if/tco-if-body.js
 create mode 100644 test/language/statements/labeled/tco.js
 create mode 100644 test/language/statements/return/tco.js
 create mode 100644 test/language/statements/switch/tco-case-body-dflt.js
 create mode 100644 test/language/statements/switch/tco-case-body.js
 create mode 100644 test/language/statements/switch/tco-dftl-body.js
 create mode 100644 test/language/statements/try/tco-catch-finally.js
 create mode 100644 test/language/statements/try/tco-catch.js
 create mode 100644 test/language/statements/try/tco-finally.js
 create mode 100644 test/language/statements/while/tco-body.js

diff --git a/harness/tco-helper.js b/harness/tco-helper.js
new file mode 100644
index 0000000000..5e9bee2257
--- /dev/null
+++ b/harness/tco-helper.js
@@ -0,0 +1,4 @@
+// This defines the number of consecutive recursive function calls that must be
+// made in order to prove that stack frames are properly destroyed according to
+// ES2015 tail call optimization semantics.
+var $MAX_ITERATIONS = 100000;
diff --git a/test/language/expressions/call/tco-call-args.js b/test/language/expressions/call/tco-call-args.js
new file mode 100644
index 0000000000..586c06ddac
--- /dev/null
+++ b/test/language/expressions/call/tco-call-args.js
@@ -0,0 +1,20 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  function getF() { return f; }
+  return getF()(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/expressions/call/tco-member-args.js b/test/language/expressions/call/tco-member-args.js
new file mode 100644
index 0000000000..4db0c9d180
--- /dev/null
+++ b/test/language/expressions/call/tco-member-args.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/expressions/comma/tco-final.js b/test/language/expressions/comma/tco-final.js
new file mode 100644
index 0000000000..a47bebbe2b
--- /dev/null
+++ b/test/language/expressions/comma/tco-final.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return 0, f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/expressions/conditional/tco-cond.js b/test/language/expressions/conditional/tco-cond.js
new file mode 100644
index 0000000000..910746f002
--- /dev/null
+++ b/test/language/expressions/conditional/tco-cond.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return true ? f(n - 1) : 0;
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/expressions/conditional/tco-pos.js b/test/language/expressions/conditional/tco-pos.js
new file mode 100644
index 0000000000..55cd30016a
--- /dev/null
+++ b/test/language/expressions/conditional/tco-pos.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return false ? 0 : f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/expressions/logical-and/tco-right.js b/test/language/expressions/logical-and/tco-right.js
new file mode 100644
index 0000000000..f4c34e71b8
--- /dev/null
+++ b/test/language/expressions/logical-and/tco-right.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return true && f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/expressions/logical-or/tco-right.js b/test/language/expressions/logical-or/tco-right.js
new file mode 100644
index 0000000000..035218ffe3
--- /dev/null
+++ b/test/language/expressions/logical-or/tco-right.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return false || f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/expressions/tagged-template/tco-call.js b/test/language/expressions/tagged-template/tco-call.js
new file mode 100644
index 0000000000..bcd50bcbf8
--- /dev/null
+++ b/test/language/expressions/tagged-template/tco-call.js
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+(function() {
+  var finished = false;
+  function getF() {
+    return f;
+  }
+  function f(_, n) {
+    if (n === 0) {
+      finished = true;
+      return;
+    }
+    return getF()`${n-1}`;
+  }
+  f(null, $MAX_ITERATIONS);
+  return finished;
+}());
diff --git a/test/language/expressions/tagged-template/tco-member.js b/test/language/expressions/tagged-template/tco-member.js
new file mode 100644
index 0000000000..c1148b9ff7
--- /dev/null
+++ b/test/language/expressions/tagged-template/tco-member.js
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+(function() {
+  var finished = false;
+  function f(_, n) {
+    if (n === 0) {
+      finished = true;
+      return;
+    }
+    return f`${n-1}`;
+  }
+  f(null, $MAX_ITERATIONS);
+  return finished;
+}());
diff --git a/test/language/expressions/tco-pos.js b/test/language/expressions/tco-pos.js
new file mode 100644
index 0000000000..652c1b54bc
--- /dev/null
+++ b/test/language/expressions/tco-pos.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return (f(n - 1));
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/block/tco-stmt-list.js b/test/language/statements/block/tco-stmt-list.js
new file mode 100644
index 0000000000..f60ac5fb0a
--- /dev/null
+++ b/test/language/statements/block/tco-stmt-list.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  { void 0; return f(n - 1); }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/block/tco-stmt.js b/test/language/statements/block/tco-stmt.js
new file mode 100644
index 0000000000..2bfdbdd1e2
--- /dev/null
+++ b/test/language/statements/block/tco-stmt.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  { return f(n - 1); }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/do-while/tco-body.js b/test/language/statements/do-while/tco-body.js
new file mode 100644
index 0000000000..5de287bb97
--- /dev/null
+++ b/test/language/statements/do-while/tco-body.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  do {
+    return f(n - 1);
+  } while (false)
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/for/tco-const-body.js b/test/language/statements/for/tco-const-body.js
new file mode 100644
index 0000000000..d9c2c8427e
--- /dev/null
+++ b/test/language/statements/for/tco-const-body.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  for (const x = 0; ;) {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/for/tco-let-body.js b/test/language/statements/for/tco-let-body.js
new file mode 100644
index 0000000000..fb4dd5e5d1
--- /dev/null
+++ b/test/language/statements/for/tco-let-body.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  for (let x = 0; ;) {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/for/tco-lhs-body.js b/test/language/statements/for/tco-lhs-body.js
new file mode 100644
index 0000000000..f6e04dc74a
--- /dev/null
+++ b/test/language/statements/for/tco-lhs-body.js
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  var x;
+  for (x = 0; x < 1; ++x) {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/for/tco-var-body.js b/test/language/statements/for/tco-var-body.js
new file mode 100644
index 0000000000..836b38ac92
--- /dev/null
+++ b/test/language/statements/for/tco-var-body.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  for (var x = 0; ;) {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/if/tco-else-body.js b/test/language/statements/if/tco-else-body.js
new file mode 100644
index 0000000000..52472eed49
--- /dev/null
+++ b/test/language/statements/if/tco-else-body.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  if (false) { } else { return f(n - 1); }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/if/tco-if-body.js b/test/language/statements/if/tco-if-body.js
new file mode 100644
index 0000000000..07178b1fa2
--- /dev/null
+++ b/test/language/statements/if/tco-if-body.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  if (true) { return f(n - 1); }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/labeled/tco.js b/test/language/statements/labeled/tco.js
new file mode 100644
index 0000000000..2935d4c044
--- /dev/null
+++ b/test/language/statements/labeled/tco.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  test262: return f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/return/tco.js b/test/language/statements/return/tco.js
new file mode 100644
index 0000000000..89aa0670f8
--- /dev/null
+++ b/test/language/statements/return/tco.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Expression within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  return f(n - 1);
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/switch/tco-case-body-dflt.js b/test/language/statements/switch/tco-case-body-dflt.js
new file mode 100644
index 0000000000..e4edf2f663
--- /dev/null
+++ b/test/language/statements/switch/tco-case-body-dflt.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  switch(0) { case 0: return f(n - 1); default: }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/switch/tco-case-body.js b/test/language/statements/switch/tco-case-body.js
new file mode 100644
index 0000000000..834bb49ee4
--- /dev/null
+++ b/test/language/statements/switch/tco-case-body.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  switch(0) { case 0: return f(n - 1); }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/switch/tco-dftl-body.js b/test/language/statements/switch/tco-dftl-body.js
new file mode 100644
index 0000000000..edeec48ea9
--- /dev/null
+++ b/test/language/statements/switch/tco-dftl-body.js
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  switch(0) { default: return f(n - 1); }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/try/tco-catch-finally.js b/test/language/statements/try/tco-catch-finally.js
new file mode 100644
index 0000000000..74117563f1
--- /dev/null
+++ b/test/language/statements/try/tco-catch-finally.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  try { } catch (err) { } finally {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/try/tco-catch.js b/test/language/statements/try/tco-catch.js
new file mode 100644
index 0000000000..e653703a9b
--- /dev/null
+++ b/test/language/statements/try/tco-catch.js
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  try {
+    throw null;
+  } catch (err) {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/try/tco-finally.js b/test/language/statements/try/tco-finally.js
new file mode 100644
index 0000000000..95ded7f3ca
--- /dev/null
+++ b/test/language/statements/try/tco-finally.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  try { } finally {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
diff --git a/test/language/statements/while/tco-body.js b/test/language/statements/while/tco-body.js
new file mode 100644
index 0000000000..c2d882bd4c
--- /dev/null
+++ b/test/language/statements/while/tco-body.js
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: Statement within statement is a candidate for tail-call optimization.
+id: static-semantics-hasproductionintailposition
+flags: [onlyStrict]
+features: [tail-call-optimization]
+includes: [tco-helper.js]
+---*/
+
+var callCount = 0;
+(function f(n) {
+  if (n === 0) {
+    callCount += 1
+    return;
+  }
+  while (true) {
+    return f(n - 1);
+  }
+}($MAX_ITERATIONS));
+assert.sameValue(callCount, 1);
-- 
GitLab