v8/test/mjsunit/for-in-opt.js
jkummerow cabeb7db3a Fix deoptimization at ForInStatement::BodyId()
Full-codegen prepared for the bailout in the wrong place, causing side
effects to be replayed when they shouldn't. Crankshaft and Turbofan are
in agreement about where the deopt should jump to.

TEST=mjsunit/for-in-opt
R=jarin@chromium.org
BUG=v8:4381
LOG=y

Review URL: https://codereview.chromium.org/1413923005

Cr-Commit-Position: refs/heads/master@{#31607}
2015-10-27 15:17:24 +00:00

161 lines
3.1 KiB
JavaScript

// 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: --harmony-proxies --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 has_keys = [];
var deopt_has = false;
var deopt_enum = false;
var handler = {
enumerate: function(target) {
if (deopt_enum) {
%DeoptimizeFunction(f2);
deopt_enum = false;
}
return keys;
},
getPropertyDescriptor: function(k) {
if (deopt_has) {
%DeoptimizeFunction(f2);
deopt_has = false;
}
has_keys.push(k);
return {value: 10, configurable: true, writable: false, enumerable: true};
}
};
var proxy = Proxy.create(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, has_keys);
has_keys.length = 0;
}
check_f2();
check_f2();
// Test lazy deopt after GetPropertyNamesFast
%OptimizeFunctionOnNextCall(f2);
deopt_enum = true;
check_f2();
// Test lazy deopt after FILTER_KEY
%OptimizeFunctionOnNextCall(f2);
deopt_has = 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 handler2 = {
getPropertyDescriptor: function(k) {
has_keys.push(k);
return {value: 10, configurable: true, writable: false, enumerable: true};
}
}
var proxy2 = Proxy.create(handler2);
var o2 = {__proto__: proxy2};
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, has_keys);
has_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 = {
enumerate: function(target) {
return ["a", "b"];
},
getPropertyDescriptor: function(k) {
if (k == "a") count++;
if (x) %ScheduleBreak();
return {value: 10, configurable: true, writable: false, enumerable: true};
}
};
var proxy3 = Proxy.create(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);