8428feeddc
Soft-deopt for mono/polymorphic property accesses that don't have any maps, and only allow zero-map feedback to be monomorphic. This makes sure we only emit a megamorphic LoadIC builtin call if the IC was actually megamorphic. JSGenericLowering assumed that zero maps meant that a load site is megamorphic. However, it can be the case that the call-site is monomorphic or polymorphic, and the maps had died. In this case we don't want to call the megamorphic IC builtin, as on a stub cache miss we fallback to a normal LoadIC miss, which can record mono/polymorphic feedback in the IC. After this, we'll enter a miss loop in the megamorphic load builtin, and worse the LoadIC assumes that there's something "wrong" with the feedback, so it'll keep trying to reconfigure the handler (possibly allocating new load handlers if this is a prototype field access). As a drive-by, rewrite GetRelevantReceiverMaps to be an in-place filtering of the maps rather than copying them. Change-Id: I0c25bfa606367fa81c43223bbd56cdadb5e789ef Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2150586 Reviewed-by: Georg Neis <neis@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Georg Neis <neis@chromium.org> Auto-Submit: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#67152}
54 lines
1.7 KiB
JavaScript
54 lines
1.7 KiB
JavaScript
// Copyright 2020 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 --harmony-weak-refs --expose-gc
|
|
|
|
// Helper to convert setTimeout into an awaitable promise.
|
|
function asyncTimeout(timeout) {
|
|
return new Promise((resolve, reject)=>{
|
|
setTimeout(resolve, timeout);
|
|
})
|
|
}
|
|
|
|
function Foo() {}
|
|
|
|
function getX(o) { return o.x; }
|
|
|
|
(async function() {
|
|
let o = new Foo();
|
|
// Transition o:Foo to o:Foo{x}. This transition is important, as the o:Foo
|
|
// map is the initial map for the Foo constructor, and so is strongly held by
|
|
// it. We want o to be the only strong holder of its map.
|
|
o.x = 42;
|
|
%CompleteInobjectSlackTracking(new Foo());
|
|
|
|
// Warm up 'getX' with 'Foo{x}' feedback for its o.x access.
|
|
%PrepareFunctionForOptimization(getX);
|
|
assertEquals(getX(o), 42);
|
|
assertEquals(getX(o), 42);
|
|
|
|
// Clear out 'o', which is the only strong holder of the Foo{x} map.
|
|
let weak_o = new WeakRef(o);
|
|
o = null;
|
|
|
|
// Tick the message loop so that the weak ref can be collected.
|
|
await asyncTimeout(0);
|
|
|
|
// Collect the old 'o', which will also collect the 'Foo{x}' map.
|
|
gc();
|
|
|
|
// Make sure the old 'o' was collected.
|
|
assertEquals(undefined, weak_o.deref());
|
|
|
|
// Optimize the function with the current monomorphic 'Foo{x}' map o.x access,
|
|
// where the 'Foo{x}' map is dead and therefore the map set is empty. Then,
|
|
// create a new 'Foo{x}' object and pass that through. This compilation and
|
|
// o.x access should still succeed despite the dead map.
|
|
%OptimizeFunctionOnNextCall(getX);
|
|
o = new Foo();
|
|
o.x = 42;
|
|
assertEquals(getX(o), 42);
|
|
|
|
})();
|