[maps] Avoid creating 2 maps by normalizing and then copying

Instead, create only 1 normalized map.

This will benefit ES5-style classes.

Bug: v8:13091
Change-Id: I495ea4a69aedef01b97f4b0d5aad19bb355ce004
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3776692
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82099}
This commit is contained in:
Marja Hölttä 2022-07-21 12:52:39 +02:00 committed by V8 LUCI CQ
parent 57cd8c8582
commit 97077520b0
5 changed files with 60 additions and 20 deletions

View File

@ -3690,12 +3690,12 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
void JSObject::NormalizeProperties(Isolate* isolate, Handle<JSObject> object,
PropertyNormalizationMode mode,
int expected_additional_properties,
const char* reason) {
bool use_cache, const char* reason) {
if (!object->HasFastProperties()) return;
Handle<Map> map(object->map(), isolate);
Handle<Map> new_map =
Map::Normalize(isolate, map, map->elements_kind(), mode, reason);
Handle<Map> new_map = Map::Normalize(isolate, map, map->elements_kind(), mode,
use_cache, reason);
JSObject::MigrateToMap(isolate, object, new_map,
expected_additional_properties);
@ -4756,20 +4756,41 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
bool enable_setup_mode) {
Isolate* isolate = object->GetIsolate();
if (object->IsJSGlobalObject()) return;
if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
// First normalize to ensure all JSFunctions are DATA_CONSTANT.
JSObject::NormalizeProperties(isolate, object, KEEP_INOBJECT_PROPERTIES, 0,
"NormalizeAsPrototype");
}
if (object->map().is_prototype_map()) {
if (object->map(isolate).is_prototype_map()) {
if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
// This is the only way PrototypeBenefitsFromNormalization can be true:
DCHECK(!object->map(isolate).should_be_fast_prototype_map());
// First normalize to ensure all JSFunctions are DATA_CONSTANT.
constexpr bool kUseCache = true;
JSObject::NormalizeProperties(isolate, object, KEEP_INOBJECT_PROPERTIES,
0, kUseCache, "NormalizeAsPrototype");
}
if (!V8_DICT_PROPERTY_CONST_TRACKING_BOOL &&
object->map().should_be_fast_prototype_map() &&
object->map(isolate).should_be_fast_prototype_map() &&
!object->HasFastProperties()) {
JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
}
} else {
Handle<Map> new_map =
Map::Copy(isolate, handle(object->map(), isolate), "CopyAsPrototype");
Handle<Map> new_map;
if (enable_setup_mode && PrototypeBenefitsFromNormalization(object)) {
#if DEBUG
Handle<Map> old_map = handle(object->map(isolate), isolate);
#endif // DEBUG
// First normalize to ensure all JSFunctions are DATA_CONSTANT. Don't use
// the cache, since we're going to use the normalized version directly,
// without making a copy.
constexpr bool kUseCache = false;
JSObject::NormalizeProperties(isolate, object, KEEP_INOBJECT_PROPERTIES,
0, kUseCache,
"NormalizeAndCopyAsPrototype");
// A new map was created.
DCHECK_NE(*old_map, object->map(isolate));
new_map = handle(object->map(isolate), isolate);
} else {
new_map =
Map::Copy(isolate, handle(object->map(), isolate), "CopyAsPrototype");
}
new_map->set_is_prototype_map(true);
// Replace the pointer to the exact constructor with the Object function
@ -4810,8 +4831,9 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
#ifdef DEBUG
bool should_be_dictionary = V8_DICT_PROPERTY_CONST_TRACKING_BOOL &&
enable_setup_mode && !object->IsJSGlobalProxy() &&
!object->GetIsolate()->bootstrapper()->IsActive();
DCHECK_IMPLIES(should_be_dictionary, object->map().is_dictionary_map());
!isolate->bootstrapper()->IsActive();
DCHECK_IMPLIES(should_be_dictionary,
object->map(isolate).is_dictionary_map());
#endif
}

View File

@ -651,7 +651,15 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
// an initial capacity for holding these properties.
V8_EXPORT_PRIVATE static void NormalizeProperties(
Isolate* isolate, Handle<JSObject> object, PropertyNormalizationMode mode,
int expected_additional_properties, const char* reason);
int expected_additional_properties, bool use_cache, const char* reason);
V8_EXPORT_PRIVATE static void NormalizeProperties(
Isolate* isolate, Handle<JSObject> object, PropertyNormalizationMode mode,
int expected_additional_properties, const char* reason) {
const bool kUseCache = true;
NormalizeProperties(isolate, object, mode, expected_additional_properties,
kUseCache, reason);
}
// Convert and update the elements backing store to be a
// NumberDictionary dictionary. Returns the backing after conversion.

View File

@ -171,7 +171,9 @@ void Map::GeneralizeIfCanHaveTransitionableFastElementsKind(
Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
PropertyNormalizationMode mode, const char* reason) {
return Normalize(isolate, fast_map, fast_map->elements_kind(), mode, reason);
const bool kUseCache = true;
return Normalize(isolate, fast_map, fast_map->elements_kind(), mode,
kUseCache, reason);
}
bool Map::EquivalentToForNormalization(const Map other,

View File

@ -1182,13 +1182,15 @@ Handle<Map> Map::RawCopy(Isolate* isolate, Handle<Map> src_handle,
Handle<Map> Map::Normalize(Isolate* isolate, Handle<Map> fast_map,
ElementsKind new_elements_kind,
PropertyNormalizationMode mode, const char* reason) {
PropertyNormalizationMode mode, bool use_cache,
const char* reason) {
DCHECK(!fast_map->is_dictionary_map());
Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
isolate);
bool use_cache =
!fast_map->is_prototype_map() && !maybe_cache->IsUndefined(isolate);
if (fast_map->is_prototype_map() || maybe_cache->IsUndefined(isolate)) {
use_cache = false;
}
Handle<NormalizedMapCache> cache;
if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);

View File

@ -534,11 +534,17 @@ class Map : public TorqueGeneratedMap<Map, HeapObject> {
Isolate* isolate, Handle<Map> old_map, InternalIndex descriptor_number,
PropertyConstness constness, Handle<Object> value);
V8_EXPORT_PRIVATE static Handle<Map> Normalize(
Isolate* isolate, Handle<Map> map, ElementsKind new_elements_kind,
PropertyNormalizationMode mode, bool use_cache, const char* reason);
V8_EXPORT_PRIVATE static Handle<Map> Normalize(Isolate* isolate,
Handle<Map> map,
ElementsKind new_elements_kind,
PropertyNormalizationMode mode,
const char* reason);
const char* reason) {
const bool kUseCache = true;
return Normalize(isolate, map, new_elements_kind, mode, kUseCache, reason);
}
inline static Handle<Map> Normalize(Isolate* isolate, Handle<Map> fast_map,
PropertyNormalizationMode mode,