v8/test/mjsunit/for-in-opt.js
cbruni 2efc138131 [proxies] use [[GetPrototypeOf]] trap in for-in key accumulation
With the recent spec change removing the [[Enumerate]] internal method, we now
have to walk the complete prototype chain. This implies that we call the
[[GetPrototypeOf]] trap on proxies.

As a secondary change we now trigger the [[GetOwnProperty]] trap for the for-in
filter step to see whether the properties are still enumerable. Before we did this
in the key-accumulation phase. This way we slightly reduce the number of traps
invoked. Whilst this is not ideal, it comes closer to the Spec's example
implementation.

BUG=v8:1543, v8:4768
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#35017}
2016-03-23 08:36:59 +00:00

158 lines
2.9 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: --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);