| Index: src/runtime/runtime-object.cc
|
| diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc
|
| index 55154fa504b1c13b5e3c89fad52f140644e89837..7183b55439f3eba5d57f40dffb9cc50af0dbed04 100644
|
| --- a/src/runtime/runtime-object.cc
|
| +++ b/src/runtime/runtime-object.cc
|
| @@ -126,11 +126,70 @@ static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate,
|
| return Runtime::GetObjectProperty(isolate, receiver_obj, key_obj);
|
| }
|
|
|
| +namespace {
|
| +
|
| +bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
|
| + Handle<Object> raw_key) {
|
| + // This implements a special case for fast property deletion: when the
|
| + // last property in an object is deleted, then instead of normalizing
|
| + // the properties, we can undo the last map transition, with a few
|
| + // prerequisites:
|
| + // (1) The receiver must be a regular object and the key a unique name.
|
| + Map* map = receiver->map();
|
| + if (map->IsSpecialReceiverMap()) return false;
|
| + if (!raw_key->IsUniqueName()) return false;
|
| + Handle<Name> key = Handle<Name>::cast(raw_key);
|
| + // (2) The property to be deleted must be the last property.
|
| + int nof = map->NumberOfOwnDescriptors();
|
| + if (nof == 0) return false;
|
| + int descriptor = nof - 1;
|
| + DescriptorArray* descriptors = map->instance_descriptors();
|
| + if (descriptors->GetKey(descriptor) != *key) return false;
|
| + // (3) The property to be deleted must be deletable.
|
| + PropertyDetails details = descriptors->GetDetails(descriptor);
|
| + if (!details.IsConfigurable()) return false;
|
| + // (4) The map must have a back pointer.
|
| + Object* backpointer = map->GetBackPointer();
|
| + if (!backpointer->IsMap()) return false;
|
| + // (5) The last transition must have been caused by adding a property
|
| + // (and not any kind of special transition).
|
| + if (Map::cast(backpointer)->NumberOfOwnDescriptors() != nof - 1) return false;
|
| +
|
| + // Preconditions successful. No more bailouts after this point.
|
| +
|
| + // Zap the property to avoid keeping objects alive. Zapping is not necessary
|
| + // for properties stored in the descriptor array.
|
| + if (details.location() == kField) {
|
| + Object* filler = isolate->heap()->one_pointer_filler_map();
|
| + FieldIndex index = FieldIndex::ForPropertyIndex(map, details.field_index());
|
| + JSObject::cast(*receiver)->RawFastPropertyAtPut(index, filler);
|
| + // We must clear any recorded slot for the deleted property, because
|
| + // subsequent object modifications might put a raw double there.
|
| + // Slot clearing is the reason why this entire function cannot currently
|
| + // be implemented in the DeleteProperty stub.
|
| + if (index.is_inobject() && !map->IsUnboxedDoubleField(index)) {
|
| + isolate->heap()->ClearRecordedSlot(
|
| + *receiver, HeapObject::RawField(*receiver, index.offset()));
|
| + }
|
| + }
|
| + // If the map was marked stable before, then there could be optimized code
|
| + // that depends on the assumption that no object that reached this map
|
| + // transitions away from it without triggering the "deoptimize dependent
|
| + // code" mechanism.
|
| + map->NotifyLeafMapLayoutChange();
|
| + // Finally, perform the map rollback.
|
| + receiver->synchronized_set_map(Map::cast(backpointer));
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
|
|
| Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
|
| Handle<JSReceiver> receiver,
|
| Handle<Object> key,
|
| LanguageMode language_mode) {
|
| + if (DeleteObjectPropertyFast(isolate, receiver, key)) return Just(true);
|
| +
|
| bool success = false;
|
| LookupIterator it = LookupIterator::PropertyOrElement(
|
| isolate, receiver, key, &success, LookupIterator::OWN);
|
|
|