Index: test/mjsunit/for-in-opt.js |
diff --git a/test/mjsunit/for-in-opt.js b/test/mjsunit/for-in-opt.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bc59a1b0877e0ebd687d4698ac4b32ab724d7869 |
--- /dev/null |
+++ b/test/mjsunit/for-in-opt.js |
@@ -0,0 +1,157 @@ |
+// Copyright 2015 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. |
+ |
+// Flags: --allow-natives-syntax --expose-debug-as debug |
+ |
+"use strict"; |
+ |
+// Test non-JSObject receiver. |
+function f(o) { |
+ var result = []; |
+ for (var i in o) { |
+ result.push(i); |
+ } |
+ return result; |
+} |
+ |
+assertEquals(["0"], f("a")); |
+assertEquals(["0"], f("a")); |
+ |
+%OptimizeFunctionOnNextCall(f); |
+assertEquals(["0","1","2"], f("bla")); |
+ |
+// Test the lazy deopt points. |
+var keys = ["a", "b", "c", "d"]; |
+var property_descriptor_keys = []; |
+var deopt_enum = false; |
+var deopt_property_descriptor = false; |
+ |
+var handler = { |
+ ownKeys() { |
+ if (deopt_enum) { |
+ %DeoptimizeFunction(f2); |
+ deopt_enum = false; |
+ } |
+ return keys; |
+ }, |
+ getOwnPropertyDescriptor(target, k) { |
+ if (deopt_property_descriptor) { |
+ %DeoptimizeFunction(f2); |
+ deopt_property_descriptor = false; |
+ } |
+ property_descriptor_keys.push(k); |
+ return { enumerable: true, configurable: true } |
+ }, |
+}; |
+ |
+ |
+var proxy = new Proxy({}, handler); |
+var o = {__proto__: proxy}; |
+ |
+function f2(o) { |
+ var result = []; |
+ for (var i in o) { |
+ result.push(i); |
+ } |
+ return result; |
+} |
+ |
+function check_f2() { |
+ assertEquals(keys, f2(o)); |
+ assertEquals(keys, property_descriptor_keys); |
+ property_descriptor_keys.length = 0; |
+} |
+ |
+check_f2(); |
+check_f2(); |
+ |
+// Test lazy deopt after ForInEnumerate |
+%OptimizeFunctionOnNextCall(f2); |
+deopt_enum = true; |
+check_f2(); |
+ |
+// Test lazy deopt after FILTER_KEY |
+%OptimizeFunctionOnNextCall(f2); |
+deopt_property_descriptor = true; |
+check_f2(); |
+ |
+ |
+function f3(o) { |
+ for (var i in o) { |
+ } |
+} |
+ |
+f3({__proto__:{x:1}}); |
+f3({__proto__:{x:1}}); |
+ |
+%OptimizeFunctionOnNextCall(f3); |
+f3(undefined); |
+f3(null); |
+ |
+// Reliable repro for an issue previously flushed out by GC stress. |
+var p = {x: "x"} |
+ |
+function f4(o, p) { |
+ var result = []; |
+ for (var i in o) { |
+ var j = p.x + "str"; |
+ result.push(i); |
+ } |
+ return result; |
+} |
+ |
+function check_f4() { |
+ assertEquals(keys, f4(o, p)); |
+ assertEquals(keys, property_descriptor_keys); |
+ property_descriptor_keys.length = 0; |
+} |
+ |
+check_f4(); |
+check_f4(); |
+ |
+%OptimizeFunctionOnNextCall(f4); |
+ |
+p.y = "y"; // Change map, cause eager deopt. |
+check_f4(); |
+ |
+// Repro for Turbofan equivalent. |
+var x; |
+var count = 0; |
+ |
+var Debug = debug.Debug; |
+ |
+function listener(event, exec_state, event_data, data) { |
+ if (event == Debug.DebugEvent.Break) { |
+ %DeoptimizeFunction(f5); |
+ } |
+} |
+ |
+var handler3 = { |
+ ownKeys() { return ["a", "b"] }, |
+ getOwnPropertyDescriptor(target, k) { |
+ if (k == "a") count++; |
+ if (x) %ScheduleBreak() |
+ return { enumerable: true, configurable: true } |
+ } |
+}; |
+ |
+var proxy3 = new Proxy({}, handler3); |
+var o3 = {__proto__: proxy3}; |
+ |
+function f5() { |
+ for (var p in o3) { |
+ print(p); |
+ } |
+} |
+ |
+x = false; |
+ |
+f5(); f5(); f5(); |
+%OptimizeFunctionOnNextCall(f5); |
+x = true; |
+count = 0; |
+Debug.setListener(listener); |
+f5(); |
+Debug.setListener(null); |
+assertEquals(1, count); |