| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index ebf184408fac1df1164193813ea7fd7e314ecb14..592955d2a8b80c221d533b65656ab5d336705fcf 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -4067,10 +4067,13 @@ void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup,
|
| Handle<JSObject> object(lookup->holder());
|
| if (object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) {
|
| JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
| + } else if (object->map()->is_prototype_map()) {
|
| + JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
|
| }
|
|
|
| if (!object->HasFastProperties()) {
|
| ReplaceSlowProperty(object, name, value, attributes);
|
| + ReoptimizeIfPrototype(object);
|
| return;
|
| }
|
|
|
| @@ -5151,17 +5154,22 @@ Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
|
|
|
| Handle<Object> JSObject::DeletePropertyPostInterceptor(Handle<JSObject> object,
|
| Handle<Name> name,
|
| - DeleteMode mode) {
|
| + DeleteMode delete_mode) {
|
| // Check own property, ignore interceptor.
|
| Isolate* isolate = object->GetIsolate();
|
| - LookupResult result(isolate);
|
| - object->LookupOwnRealNamedProperty(name, &result);
|
| - if (!result.IsFound()) return isolate->factory()->true_value();
|
| + LookupResult lookup(isolate);
|
| + object->LookupOwnRealNamedProperty(name, &lookup);
|
| + if (!lookup.IsFound()) return isolate->factory()->true_value();
|
|
|
| + PropertyNormalizationMode mode = object->map()->is_prototype_map()
|
| + ? KEEP_INOBJECT_PROPERTIES
|
| + : CLEAR_INOBJECT_PROPERTIES;
|
| // Normalize object if needed.
|
| - NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
| + NormalizeProperties(object, mode, 0);
|
|
|
| - return DeleteNormalizedProperty(object, name, mode);
|
| + Handle<Object> result = DeleteNormalizedProperty(object, name, delete_mode);
|
| + ReoptimizeIfPrototype(object);
|
| + return result;
|
| }
|
|
|
|
|
| @@ -5308,7 +5316,7 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
|
|
|
| MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
| Handle<Name> name,
|
| - DeleteMode mode) {
|
| + DeleteMode delete_mode) {
|
| Isolate* isolate = object->GetIsolate();
|
| // ECMA-262, 3rd, 8.6.2.5
|
| DCHECK(name->IsName());
|
| @@ -5327,20 +5335,20 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
| DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
|
| return JSGlobalObject::DeleteProperty(
|
| Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)), name,
|
| - mode);
|
| + delete_mode);
|
| }
|
|
|
| uint32_t index = 0;
|
| if (name->AsArrayIndex(&index)) {
|
| - return DeleteElement(object, index, mode);
|
| + return DeleteElement(object, index, delete_mode);
|
| }
|
|
|
| LookupResult lookup(isolate);
|
| object->LookupOwn(name, &lookup, true);
|
| if (!lookup.IsFound()) return isolate->factory()->true_value();
|
| // Ignore attributes if forcing a deletion.
|
| - if (lookup.IsDontDelete() && mode != FORCE_DELETION) {
|
| - if (mode == STRICT_DELETION) {
|
| + if (lookup.IsDontDelete() && delete_mode != FORCE_DELETION) {
|
| + if (delete_mode == STRICT_DELETION) {
|
| // Deleting a non-configurable property in strict mode.
|
| Handle<Object> args[2] = { name, object };
|
| Handle<Object> error = isolate->factory()->NewTypeError(
|
| @@ -5362,8 +5370,8 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
| // Check for interceptor.
|
| if (lookup.IsInterceptor()) {
|
| // Skip interceptor if forcing a deletion.
|
| - if (mode == FORCE_DELETION) {
|
| - result = DeletePropertyPostInterceptor(object, name, mode);
|
| + if (delete_mode == FORCE_DELETION) {
|
| + result = DeletePropertyPostInterceptor(object, name, delete_mode);
|
| } else {
|
| ASSIGN_RETURN_ON_EXCEPTION(
|
| isolate, result,
|
| @@ -5371,10 +5379,14 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
|
| Object);
|
| }
|
| } else {
|
| + PropertyNormalizationMode mode = object->map()->is_prototype_map()
|
| + ? KEEP_INOBJECT_PROPERTIES
|
| + : CLEAR_INOBJECT_PROPERTIES;
|
| // Normalize object if needed.
|
| - NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
| + NormalizeProperties(object, mode, 0);
|
| // Make sure the properties are normalized before removing the entry.
|
| - result = DeleteNormalizedProperty(object, name, mode);
|
| + result = DeleteNormalizedProperty(object, name, delete_mode);
|
| + ReoptimizeIfPrototype(object);
|
| }
|
|
|
| if (is_observed) {
|
| @@ -5696,6 +5708,7 @@ MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
|
| Handle<Map> new_map = Map::CopyForFreeze(old_map);
|
| JSObject::MigrateToMap(object, new_map);
|
| } else {
|
| + DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
|
| // Slow path: need to normalize properties for safety
|
| NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
|
|
| @@ -6594,8 +6607,11 @@ void JSObject::SetPropertyCallback(Handle<JSObject> object,
|
| Handle<Name> name,
|
| Handle<Object> structure,
|
| PropertyAttributes attributes) {
|
| + PropertyNormalizationMode mode = object->map()->is_prototype_map()
|
| + ? KEEP_INOBJECT_PROPERTIES
|
| + : CLEAR_INOBJECT_PROPERTIES;
|
| // Normalize object to make this operation simple.
|
| - NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
|
| + NormalizeProperties(object, mode, 0);
|
|
|
| // For the global object allocate a new map to invalidate the global inline
|
| // caches which have a global property cell reference directly in the code.
|
| @@ -6613,6 +6629,8 @@ void JSObject::SetPropertyCallback(Handle<JSObject> object,
|
| // Update the dictionary with the new CALLBACKS property.
|
| PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
|
| SetNormalizedProperty(object, name, structure, details);
|
| +
|
| + ReoptimizeIfPrototype(object);
|
| }
|
|
|
|
|
| @@ -9970,6 +9988,12 @@ void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
|
| }
|
|
|
|
|
| +void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
|
| + if (!object->map()->is_prototype_map()) return;
|
| + OptimizeAsPrototype(object);
|
| +}
|
| +
|
| +
|
| Handle<Object> CacheInitialJSArrayMaps(
|
| Handle<Context> native_context, Handle<Map> initial_map) {
|
| // Replace all of the cached initial array maps in the native context with
|
| @@ -10132,9 +10156,6 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
| Handle<Object> prototype;
|
| if (function->has_instance_prototype()) {
|
| prototype = handle(function->instance_prototype(), isolate);
|
| - // TODO(verwaest): Remove once "delete" keeps objects marked as prototypes
|
| - // fast as well.
|
| - JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(prototype));
|
| } else {
|
| prototype = isolate->factory()->NewFunctionPrototype(function);
|
| }
|
|
|