Commit bdac0ff0 authored by Matthias Liedtke's avatar Matthias Liedtke Committed by V8 LUCI CQ

[turbofan] Avoid deopt loop for GetIterator of null / undefined

GetIterator on object o consists of two steps:
1) iter = load o[#Symbol.Iterator]
2) call iter

For null / undefined step (1) throws an exception, meaning
step (2) is never reached. Up to this change, turbofan
deopts if for either of the two steps there isn't enough
feedback, meaning that we have a deopt loop for null and
undefined.

Change-Id: Ie0eaf8e231a149313e10af9e95fd80bc77dc0beb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3890980Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83159}
parent e28c7178
......@@ -500,11 +500,6 @@ JSTypeHintLowering::ReduceGetIteratorOperation(const Operator* op,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
return LoweringResult::Exit(node);
}
if (Node* node = BuildDeoptIfFeedbackIsInsufficient(
call_slot, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForCall)) {
return LoweringResult::Exit(node);
}
return LoweringResult::NoChange();
}
......
// Copyright 2022 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
function throwsRepeated(fn, ErrorType) {
// Collect type feedback.
%PrepareFunctionForOptimization(fn);
for (let i = 0; i < 5; i++) assertThrows(fn, ErrorType);
// Force compilation and run.
%OptimizeFunctionOnNextCall(fn);
assertThrows(fn, ErrorType);
// If the function isn't optimized / turbofan tier not available,
// a deopt happened on the call above.
assertEquals(%IsTurbofanEnabled(), %ActiveTierIsTurbofan(fn));
}
function repeated(fn) {
// Collect type feedback.
%PrepareFunctionForOptimization(fn);
for (let i = 0; i < 5; i++) fn();
// Force compilation and run.
%OptimizeFunctionOnNextCall(fn);
fn();
// If the function isn't optimized / turbofan tier not available,
// a deopt happened on the call above.
assertEquals(%IsTurbofanEnabled(), %ActiveTierIsTurbofan(fn));
}
repeated(() => { for (let p of "abc") { } });
repeated(() => { for (let p of [1, 2, 3]) { } });
throwsRepeated(() => { for (let p of {a: 1, b: 2}) { } }, TypeError);
let objWithIterator = { [Symbol.iterator]: function* () { yield 1; } };
repeated(() => { for (let p of objWithIterator) { } });
throwsRepeated(() => { for (let p of 5) { } }, TypeError);
throwsRepeated(() => { for (let p of new Number(5)) { } }, TypeError);
throwsRepeated(() => { for (let p of true) { } }, TypeError);
throwsRepeated(() => { for (let p of new BigInt(123)) { } }, TypeError);
throwsRepeated(() => { for (let p of new Symbol("symbol")) { } }, TypeError);
throwsRepeated(function testUndef() { for (let p of undefined) { } }, TypeError);
throwsRepeated(() => { for (let p of null) { } }, TypeError);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment