[runtime] Prepopulate map cache with initial Object map

Use the map for both objects with 0 requested properties and the number
of inobject properties it has (4 currently) to share maptrees.

Change-Id: Ie4859d44bed39effff864d54e7d416b13898c7d9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3035081
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75757}
This commit is contained in:
Toon Verwaest 2021-07-16 14:10:29 +02:00 committed by V8 LUCI CQ
parent 84d5b027a7
commit e5c2e17de0
3 changed files with 33 additions and 31 deletions

View File

@ -3323,41 +3323,27 @@ Handle<JSObject> Factory::NewArgumentsObject(Handle<JSFunction> callee,
Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<NativeContext> context,
int number_of_properties) {
if (number_of_properties == 0) {
// Reuse the initial map of the Object function if the literal has no
// predeclared properties.
return handle(context->object_function().initial_map(), isolate());
}
// Use initial slow object proto map for too many properties.
const int kMapCacheSize = 128;
if (number_of_properties > kMapCacheSize) {
if (number_of_properties >= JSObject::kMapCacheSize) {
return handle(context->slow_object_with_object_prototype_map(), isolate());
}
int cache_index = number_of_properties - 1;
Handle<Object> maybe_cache(context->map_cache(), isolate());
if (maybe_cache->IsUndefined(isolate())) {
// Allocate the new map cache for the native context.
maybe_cache = NewWeakFixedArray(kMapCacheSize, AllocationType::kOld);
context->set_map_cache(*maybe_cache);
} else {
// Check to see whether there is a matching element in the cache.
Handle<WeakFixedArray> cache = Handle<WeakFixedArray>::cast(maybe_cache);
MaybeObject result = cache->Get(cache_index);
HeapObject heap_object;
if (result->GetHeapObjectIfWeak(&heap_object)) {
Map map = Map::cast(heap_object);
DCHECK(!map.is_dictionary_map());
return handle(map, isolate());
}
Handle<WeakFixedArray> cache(WeakFixedArray::cast(context->map_cache()),
isolate());
// Check to see whether there is a matching element in the cache.
MaybeObject result = cache->Get(number_of_properties);
HeapObject heap_object;
if (result->GetHeapObjectIfWeak(&heap_object)) {
Map map = Map::cast(heap_object);
DCHECK(!map.is_dictionary_map());
return handle(map, isolate());
}
// Create a new map and add it to the cache.
Handle<WeakFixedArray> cache = Handle<WeakFixedArray>::cast(maybe_cache);
Handle<Map> map = Map::Create(isolate(), number_of_properties);
DCHECK(!map->is_dictionary_map());
cache->Set(cache_index, HeapObjectReference::Weak(*map));
cache->Set(number_of_properties, HeapObjectReference::Weak(*map));
return map;
}

View File

@ -249,7 +249,7 @@ class Genesis {
ElementsKind elements_kind,
InstanceType type,
int rab_gsab_initial_map_index);
void InitializeNormalizedMapCaches();
void InitializeMapCaches();
enum ExtensionTraversalState { UNVISITED, VISITED, INSTALLED };
@ -5009,9 +5009,23 @@ bool Genesis::InstallExtrasBindings() {
return true;
}
void Genesis::InitializeNormalizedMapCaches() {
Handle<NormalizedMapCache> cache = NormalizedMapCache::New(isolate());
native_context()->set_normalized_map_cache(*cache);
void Genesis::InitializeMapCaches() {
{
Handle<NormalizedMapCache> cache = NormalizedMapCache::New(isolate());
native_context()->set_normalized_map_cache(*cache);
}
{
Handle<WeakFixedArray> cache = factory()->NewWeakFixedArray(
JSObject::kMapCacheSize, AllocationType::kOld);
DisallowGarbageCollection no_gc;
native_context()->set_map_cache(*cache);
Map initial = native_context()->object_function().initial_map();
cache->Set(0, HeapObjectReference::Weak(initial), SKIP_WRITE_BARRIER);
cache->Set(initial.GetInObjectProperties(),
HeapObjectReference::Weak(initial), SKIP_WRITE_BARRIER);
}
}
bool Bootstrapper::InstallExtensions(Handle<Context> native_context,
@ -5489,8 +5503,8 @@ Genesis::Genesis(
CreateAsyncFunctionMaps(empty_function);
Handle<JSGlobalObject> global_object =
CreateNewGlobals(global_proxy_template, global_proxy);
InitializeMapCaches();
InitializeGlobal(global_object, empty_function);
InitializeNormalizedMapCaches();
InitializeIteratorFunctions();
InitializeCallSiteBuiltins();

View File

@ -793,6 +793,8 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
static const int kMaxInstanceSize = 255 * kTaggedSize;
static const int kMapCacheSize = 128;
// When extending the backing storage for property values, we increase
// its size by more than the 1 entry necessary, so sequentially adding fields
// to the same object requires fewer allocations and copies.