[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:
parent
57cd8c8582
commit
97077520b0
@ -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
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user