2efc138131
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}
158 lines
2.9 KiB
JavaScript
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);
|