Use map of prototype in Map::Hash.

Instead of using addresses of prototype and constructor (which can be
movedby GC) when computing the hash of a Map, we use the addresses of the
prototype map (which won't be compacted).
The prototype map is in a 1:1 relation with the prototype.
In addition the prototype points to the constructor in most cases.

Bug: v8:11519
Change-Id: Ibc47e5870955d7721509be07fae7719a93da9a26
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2739646
Commit-Queue: Patrick Thier <pthier@chromium.org>
Auto-Submit: Patrick Thier <pthier@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73286}
This commit is contained in:
pthier 2021-03-09 08:04:42 +00:00 committed by Commit Bot
parent 03a73545af
commit ae8823217d
2 changed files with 34 additions and 12 deletions

View File

@ -2372,20 +2372,17 @@ Handle<Map> Map::CopyReplaceDescriptor(Isolate* isolate, Handle<Map> map,
}
int Map::Hash() {
// For performance reasons we only hash the 3 most variable fields of a map:
// constructor, prototype and bit_field2. For predictability reasons we
// use objects' offsets in respective pages for hashing instead of raw
// addresses.
// For performance reasons we only hash the 2 most variable fields of a map:
// prototype map and bit_field2. For predictability reasons we use objects'
// offsets in respective pages for hashing instead of raw addresses. We use
// the map of the prototype because the prototype itself could be compacted,
// whereas the map will not be moved.
// NOTE: If we want to compact maps, this hash function won't work as intended
// anymore.
// Shift away the tag.
int hash = ObjectAddressForHashing(GetConstructor().ptr()) >> 2;
// XOR-ing the prototype and constructor directly yields too many zero bits
// when the two pointers are close (which is fairly common).
// To avoid this we shift the prototype bits relatively to the constructor.
hash ^= ObjectAddressForHashing(prototype().ptr()) << (32 - kPageSizeBits);
return hash ^ (hash >> 16) ^ bit_field2();
int hash = ObjectAddressForHashing(prototype().map().ptr()) >> 2;
return hash ^ bit_field2();
}
namespace {

View File

@ -0,0 +1,25 @@
// Copyright 2021 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 --gc-interval=500 --stress-compaction
function bar(a) {
return Object.defineProperty(a, 'x', {get() { return 1; }});
}
function foo() {
return {};
}
%NeverOptimizeFunction(bar);
%PrepareFunctionForOptimization(foo);
const o = foo(); // Keep a reference so the GC doesn't kill the map.
%SimulateNewspaceFull();
bar(o);
const a = bar(foo());
%SimulateNewspaceFull();
%OptimizeFunctionOnNextCall(foo);
const b = bar(foo());
assertTrue(%HaveSameMap(a, b));