summaryrefslogtreecommitdiff
path: root/deps/v8/test/mjsunit/es6/iterator-eager-deopt.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/mjsunit/es6/iterator-eager-deopt.js')
-rw-r--r--deps/v8/test/mjsunit/es6/iterator-eager-deopt.js69
1 files changed, 69 insertions, 0 deletions
diff --git a/deps/v8/test/mjsunit/es6/iterator-eager-deopt.js b/deps/v8/test/mjsunit/es6/iterator-eager-deopt.js
new file mode 100644
index 0000000000..fe004c8c6d
--- /dev/null
+++ b/deps/v8/test/mjsunit/es6/iterator-eager-deopt.js
@@ -0,0 +1,69 @@
+// Copyright 2019 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.
+
+// The GetIterator bytecode is used to implement a part of the iterator
+// protocol (https://tc39.es/ecma262/#sec-getiterator). Here, the
+// bytecode performs multiple operations including some that have side-effects
+// and may deoptimize eagerly or lazily.
+// This test ensures the eager deoptimization is handled correctly.
+
+// Flags: --allow-natives-syntax --no-always-opt
+
+var getIteratorCount = 0;
+var iteratorCount = 0;
+var iteratorAfterEagerDeoptCount = 0;
+
+function foo(obj) {
+ // The following for-of loop uses the iterator protocol to iterate
+ // over the 'obj'.
+ // The GetIterator bytecode invovlves 3 steps:
+ // 1. method = GetMethod(obj, @@iterator)
+ // 2. iterator = Call(method, obj)
+ // 3. if(!IsJSReceiver(iterator)) throw SymbolIteratorInvalid.
+ for(var x of obj){}
+}
+
+// This iterator gets inlined when the 'foo' function is JIT compiled for
+// the first time.
+var iterator = function() {
+ iteratorCount++;
+ return {
+ next: function() {
+ return { done: true };
+ }
+ }
+}
+
+var iteratorAfterEagerDeopt = function() {
+ iteratorAfterEagerDeoptCount++;
+ return {
+ next: function() {
+ return { done: true };
+ }
+ }
+}
+
+// Here, retrieval of function at @@iterator has side effect (increments the
+// 'getIteratorCount'). Changing the value of 'iterator' in the JIT compiled
+// 'foo' causes deoptimization after the count is incremented. Now the deopt
+// cannot resume at the beginning of the bytecode because it would end up in
+// incrementing the count again.
+let y = { get [Symbol.iterator] () {
+ getIteratorCount++;
+ return iterator;
+ }
+ };
+
+%PrepareFunctionForOptimization(foo);
+foo(y);
+foo(y);
+%OptimizeFunctionOnNextCall(foo);
+
+// Change the value of 'iterator' to trigger eager deoptimization of 'foo'.
+iterator = iteratorAfterEagerDeopt
+foo(y);
+assertUnoptimized(foo);
+assertEquals(getIteratorCount, 3);
+assertEquals(iteratorCount, 2);
+assertEquals(iteratorAfterEagerDeoptCount, 1);