v8/test/mjsunit/compiler/monomorphic-named-load-with-no-map.js
Leszek Swirski 8428feeddc [turbofan] Avoid megamorphic loads for zero-map mono/polymorphic sites
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}
2020-04-15 15:07:20 +00:00

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);
})();