| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 645bb4a74e39f81272c0c9e3c4c4d913976224fc..90220f0f31137fc67c106db8bb0d1a898ffb86d6 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -3470,7 +3470,7 @@ Handle<Map> Map::TransitionElementsToSlow(Handle<Map> map,
|
| bool allow_store_transition =
|
| // Only remember the map transition if there is not an already existing
|
| // non-matching element transition.
|
| - !map->IsUndefined() && !map->is_shared() &&
|
| + !map->IsUndefined() && !map->is_dictionary_map() &&
|
| IsTransitionElementsKind(from_kind);
|
|
|
| // Only store fast element maps in ascending generality.
|
| @@ -4440,6 +4440,8 @@ Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
|
|
|
| MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
|
| PropertyNormalizationMode mode) {
|
| + // Only use the cache once it is initialized.
|
| + if (!IsNormalizedMapCache(this)) return MaybeHandle<Map>();
|
| DisallowHeapAllocation no_gc;
|
| Object* value = FixedArray::get(GetIndex(fast_map));
|
| if (!value->IsMap() ||
|
| @@ -4452,6 +4454,8 @@ MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
|
|
|
| void NormalizedMapCache::Set(Handle<Map> fast_map,
|
| Handle<Map> normalized_map) {
|
| + // Only use the cache once it is initialized.
|
| + if (!IsNormalizedMapCache(this)) return;
|
| DisallowHeapAllocation no_gc;
|
| DCHECK(normalized_map->is_dictionary_map());
|
| FixedArray::set(GetIndex(fast_map), *normalized_map);
|
| @@ -6981,17 +6985,14 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map,
|
| Handle<Map> new_map;
|
| if (cache->Get(fast_map, mode).ToHandle(&new_map)) {
|
| #ifdef VERIFY_HEAP
|
| - if (FLAG_verify_heap) {
|
| - new_map->SharedMapVerify();
|
| - }
|
| + if (FLAG_verify_heap) new_map->DictionaryMapVerify();
|
| #endif
|
| #ifdef ENABLE_SLOW_DCHECKS
|
| if (FLAG_enable_slow_asserts) {
|
| // The cached map should match newly created normalized map bit-by-bit,
|
| // except for the code cache, which can contain some ics which can be
|
| // applied to the shared map.
|
| - Handle<Map> fresh = Map::CopyNormalized(
|
| - fast_map, mode, SHARED_NORMALIZED_MAP);
|
| + Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
|
|
|
| DCHECK(memcmp(fresh->address(),
|
| new_map->address(),
|
| @@ -7005,7 +7006,7 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map,
|
| }
|
| #endif
|
| } else {
|
| - new_map = Map::CopyNormalized(fast_map, mode, SHARED_NORMALIZED_MAP);
|
| + new_map = Map::CopyNormalized(fast_map, mode);
|
| cache->Set(fast_map, new_map);
|
| isolate->counters()->normalized_maps()->Increment();
|
| }
|
| @@ -7015,8 +7016,7 @@ Handle<Map> Map::Normalize(Handle<Map> fast_map,
|
|
|
|
|
| Handle<Map> Map::CopyNormalized(Handle<Map> map,
|
| - PropertyNormalizationMode mode,
|
| - NormalizedMapSharingMode sharing) {
|
| + PropertyNormalizationMode mode) {
|
| int new_instance_size = map->instance_size();
|
| if (mode == CLEAR_INOBJECT_PROPERTIES) {
|
| new_instance_size -= map->inobject_properties() * kPointerSize;
|
| @@ -7028,14 +7028,11 @@ Handle<Map> Map::CopyNormalized(Handle<Map> map,
|
| result->set_inobject_properties(map->inobject_properties());
|
| }
|
|
|
| - result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
|
| result->set_dictionary_map(true);
|
| result->set_migration_target(false);
|
|
|
| #ifdef VERIFY_HEAP
|
| - if (FLAG_verify_heap && result->is_shared()) {
|
| - result->SharedMapVerify();
|
| - }
|
| + if (FLAG_verify_heap) result->DictionaryMapVerify();
|
| #endif
|
|
|
| return result;
|
| @@ -7051,7 +7048,6 @@ Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
|
|
|
| result->set_pre_allocated_property_fields(
|
| map->pre_allocated_property_fields());
|
| - result->set_is_shared(false);
|
| result->ClearCodeCache(map->GetHeap());
|
| map->NotifyLeafMapLayoutChange();
|
| return result;
|
| @@ -9812,20 +9808,29 @@ void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
|
| }
|
|
|
|
|
| -void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
|
| +void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
|
| + PrototypeOptimizationMode mode) {
|
| if (object->IsGlobalObject()) return;
|
| -
|
| - // Make sure prototypes are fast objects and their maps have the bit set
|
| - // so they remain fast.
|
| + if (object->IsJSGlobalProxy()) return;
|
| + if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) {
|
| + // First normalize to ensure all JSFunctions are CONSTANT.
|
| + JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
|
| + }
|
| if (!object->HasFastProperties()) {
|
| - MigrateSlowToFast(object, 0);
|
| + JSObject::MigrateSlowToFast(object, 0);
|
| + }
|
| + if (mode == FAST_PROTOTYPE && object->HasFastProperties() &&
|
| + !object->map()->is_prototype_map()) {
|
| + Handle<Map> new_map = Map::Copy(handle(object->map()));
|
| + JSObject::MigrateToMap(object, new_map);
|
| + object->map()->set_is_prototype_map(true);
|
| }
|
| }
|
|
|
|
|
| void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
|
| if (!object->map()->is_prototype_map()) return;
|
| - OptimizeAsPrototype(object);
|
| + OptimizeAsPrototype(object, FAST_PROTOTYPE);
|
| }
|
|
|
|
|
| @@ -9876,21 +9881,30 @@ void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
|
| if (function->IsInobjectSlackTrackingInProgress()) {
|
| function->CompleteInobjectSlackTracking();
|
| }
|
| +
|
| Handle<Map> initial_map(function->initial_map(), isolate);
|
| - Handle<Map> new_map = Map::Copy(initial_map);
|
| - new_map->set_prototype(*value);
|
|
|
| - // If the function is used as the global Array function, cache the
|
| - // initial map (and transitioned versions) in the native context.
|
| - Context* native_context = function->context()->native_context();
|
| - Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX);
|
| - if (array_function->IsJSFunction() &&
|
| - *function == JSFunction::cast(array_function)) {
|
| - CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
|
| + if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
|
| + initial_map->instance_type() == JS_OBJECT_TYPE) {
|
| + // Put the value in the initial map field until an initial map is needed.
|
| + // At that point, a new initial map is created and the prototype is put
|
| + // into the initial map where it belongs.
|
| + function->set_prototype_or_initial_map(*value);
|
| + } else {
|
| + Handle<Map> new_map = Map::Copy(initial_map);
|
| + JSFunction::SetInitialMap(function, new_map, value);
|
| +
|
| + // If the function is used as the global Array function, cache the
|
| + // initial map (and transitioned versions) in the native context.
|
| + Context* native_context = function->context()->native_context();
|
| + Object* array_function =
|
| + native_context->get(Context::ARRAY_FUNCTION_INDEX);
|
| + if (array_function->IsJSFunction() &&
|
| + *function == JSFunction::cast(array_function)) {
|
| + CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
|
| + }
|
| }
|
|
|
| - JSFunction::SetInitialMap(function, new_map);
|
| -
|
| // Deoptimize all code that embeds the previous initial map.
|
| initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
|
| isolate, DependentCode::kInitialMapChangedGroup);
|
| @@ -9956,27 +9970,13 @@ bool JSFunction::RemovePrototype() {
|
| }
|
|
|
|
|
| -void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map) {
|
| - if (map->prototype()->IsJSObject()) {
|
| - Handle<JSObject> js_proto = handle(JSObject::cast(map->prototype()));
|
| - if (!js_proto->map()->is_prototype_map() &&
|
| - !js_proto->map()->IsGlobalObjectMap() &&
|
| - !js_proto->map()->IsJSGlobalProxyMap()) {
|
| - // Normalize and turn fast again to make all functions CONSTANT
|
| - // properties.
|
| - if (!js_proto->GetIsolate()->bootstrapper()->IsActive()) {
|
| - JSObject::NormalizeProperties(js_proto, KEEP_INOBJECT_PROPERTIES, 0);
|
| - }
|
| - if (!js_proto->HasFastProperties()) {
|
| - JSObject::MigrateSlowToFast(js_proto, 0);
|
| - }
|
| - if (js_proto->HasFastProperties()) {
|
| - Handle<Map> new_map = Map::Copy(handle(js_proto->map()));
|
| - JSObject::MigrateToMap(js_proto, new_map);
|
| - js_proto->map()->set_is_prototype_map(true);
|
| - }
|
| - }
|
| +void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
|
| + Handle<Object> prototype) {
|
| + if (prototype->IsJSObject()) {
|
| + Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype);
|
| + JSObject::OptimizeAsPrototype(js_proto, FAST_PROTOTYPE);
|
| }
|
| + map->set_prototype(*prototype);
|
| function->set_prototype_or_initial_map(*map);
|
| map->set_constructor(*function);
|
| }
|
| @@ -10011,11 +10011,10 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
| }
|
| map->set_inobject_properties(in_object_properties);
|
| map->set_unused_property_fields(in_object_properties);
|
| - map->set_prototype(*prototype);
|
| DCHECK(map->has_fast_object_elements());
|
|
|
| // Finally link initial map and constructor function.
|
| - JSFunction::SetInitialMap(function, map);
|
| + JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype));
|
|
|
| if (!function->shared()->is_generator()) {
|
| function->StartInobjectSlackTracking();
|
| @@ -11777,7 +11776,7 @@ Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
|
| // Don't cache prototype transition if this map is either shared, or a map of
|
| // a prototype.
|
| if (map->is_prototype_map()) return map;
|
| - if (map->is_shared() || !FLAG_cache_prototype_transitions) return map;
|
| + if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
|
|
|
| const int step = kProtoTransitionElementsPerEntry;
|
| const int header = kProtoTransitionHeaderSize;
|
| @@ -12100,7 +12099,7 @@ Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
|
|
|
| MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
|
| Handle<Object> value,
|
| - bool skip_hidden_prototypes) {
|
| + bool from_javascript) {
|
| #ifdef DEBUG
|
| int size = object->Size();
|
| #endif
|
| @@ -12145,7 +12144,7 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
|
| object->map()->DictionaryElementsInPrototypeChainOnly();
|
| Handle<JSObject> real_receiver = object;
|
|
|
| - if (skip_hidden_prototypes) {
|
| + if (from_javascript) {
|
| // Find the first object in the chain whose prototype object is not
|
| // hidden and set the new prototype on that object.
|
| PrototypeIterator iter(isolate, real_receiver);
|
| @@ -12163,7 +12162,9 @@ MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
|
| if (map->prototype() == *value) return value;
|
|
|
| if (value->IsJSObject()) {
|
| - JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
|
| + PrototypeOptimizationMode mode =
|
| + from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
|
| + JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), mode);
|
| }
|
|
|
| Handle<Map> new_map = Map::TransitionToPrototype(map, value);
|
|
|