diff --git a/harness/tco-helper.js b/harness/tco-helper.js
new file mode 100644
index 0000000000000000000000000000000000000000..5e9bee2257713180fc18d827c4f4d14e9d50e800
--- /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 0000000000000000000000000000000000000000..586c06ddac3b52b1717511f27e25feb57ae41de0
--- /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 0000000000000000000000000000000000000000..4db0c9d180c182216eab4d2f12b806dcd2064b1d
--- /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 0000000000000000000000000000000000000000..a47bebbe2bc630223e92d70faa64dc3067bf21f3
--- /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 0000000000000000000000000000000000000000..910746f002c8453e88f0292f88c53c017495a751
--- /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 0000000000000000000000000000000000000000..55cd30016a5dc4e6623510d470bd8c89b1f3cbb1
--- /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 0000000000000000000000000000000000000000..f4c34e71b800270e774c2684c785b0555736a7d4
--- /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 0000000000000000000000000000000000000000..035218ffe37f92b67143d1be32fe8a255e53f029
--- /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 0000000000000000000000000000000000000000..bcd50bcbf83e22a5886bbbb3ad7c62cf2e586a14
--- /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 0000000000000000000000000000000000000000..c1148b9ff7682df0c3c82a0d043f62e188296f3d
--- /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 0000000000000000000000000000000000000000..652c1b54bc001b26994dee10a1a045c22a999b56
--- /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 0000000000000000000000000000000000000000..f60ac5fb0a1cea237db6f0abd43ae98c6bd95dbc
--- /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 0000000000000000000000000000000000000000..2bfdbdd1e2e36863637d136833d9dd5ec093e081
--- /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 0000000000000000000000000000000000000000..5de287bb9792dbbb5e5f131f711dc89f05ce52dd
--- /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 0000000000000000000000000000000000000000..d9c2c8427e7e65325bfe691f006f3dc4781fb0ae
--- /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 0000000000000000000000000000000000000000..fb4dd5e5d193860c3ec13977d67d785bc79c6239
--- /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 0000000000000000000000000000000000000000..f6e04dc74a7e2fdb79a9ba423a03f8e175551421
--- /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 0000000000000000000000000000000000000000..836b38ac9213396d18949b9538634f4d22e97c80
--- /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 0000000000000000000000000000000000000000..52472eed49e59f95cb5f78b8c163f86ef79be5f7
--- /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 0000000000000000000000000000000000000000..07178b1fa29eb4712dfd4f7a6b59958e29154bad
--- /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 0000000000000000000000000000000000000000..2935d4c044d0ec0600c49f255aff18fe35638d1f
--- /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 0000000000000000000000000000000000000000..89aa0670f88dec36ddae89380caf6d0fed1a6a9a
--- /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 0000000000000000000000000000000000000000..e4edf2f663688b1db49b44b9b7592b305bcdb68a
--- /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 0000000000000000000000000000000000000000..834bb49ee4b357569dab682e76b00b58dbb5c9f3
--- /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 0000000000000000000000000000000000000000..edeec48ea92530285f4a45c52d39a53264acb0e9
--- /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 0000000000000000000000000000000000000000..74117563f111d92a54d8a97cb3ef0d5acabbabf9
--- /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 0000000000000000000000000000000000000000..e653703a9b08f93161e30335521f879a7293d2df
--- /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 0000000000000000000000000000000000000000..95ded7f3ca2ec42f7483d763bd7e3de5e56fb506
--- /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 0000000000000000000000000000000000000000..c2d882bd4ce42aa6d9cad931f5eb22fd0633f2d5
--- /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);