Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 2b21278b240373ff48639a50b7d2520933ae7a08..c317f0abf70eaacf1aaf3c7820a5affc3e86d17e 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -4362,15 +4362,14 @@ void JSObject::LookupCallback(String* name, LookupResult* result) { |
| } |
| -// Search for a getter or setter in an elements dictionary and update its |
| -// attributes. Returns either undefined if the element is non-deletable, or the |
| -// getter/setter pair if there is an existing one, or the hole value if the |
| -// element does not exist or is a normal non-getter/setter data element. |
| -static Object* UpdateGetterSetterInDictionary( |
| +// Try to update an accessor in an elements dictionary. Return true if the |
| +// update succeeded, and false otherwise. |
| +static bool UpdateGetterSetterInDictionary( |
| SeededNumberDictionary* dictionary, |
| uint32_t index, |
| - PropertyAttributes attributes, |
| - Heap* heap) { |
| + bool is_getter, |
| + Object* fun, |
| + PropertyAttributes attributes) { |
| int entry = dictionary->FindEntry(index); |
| if (entry != SeededNumberDictionary::kNotFound) { |
| Object* result = dictionary->ValueAt(entry); |
| @@ -4382,108 +4381,116 @@ static Object* UpdateGetterSetterInDictionary( |
| dictionary->DetailsAtPut(entry, |
| PropertyDetails(attributes, CALLBACKS, index)); |
| } |
| - return result; |
| + AccessorPair::cast(result)->set(is_getter, fun); |
| + return true; |
| } |
| } |
| - return heap->the_hole_value(); |
| + return false; |
| } |
| -MaybeObject* JSObject::DefineGetterSetter(String* name, |
| - PropertyAttributes attributes) { |
| - Heap* heap = GetHeap(); |
| - // Make sure that the top context does not change when doing callbacks or |
| - // interceptor calls. |
| - AssertNoContextChange ncc; |
| - |
| - // Try to flatten before operating on the string. |
| - name->TryFlatten(); |
| - |
| - if (!CanSetCallback(name)) { |
| - return heap->undefined_value(); |
| - } |
| - |
| - uint32_t index = 0; |
| - bool is_element = name->AsArrayIndex(&index); |
| - |
| - if (is_element) { |
| - switch (GetElementsKind()) { |
| - case FAST_SMI_ONLY_ELEMENTS: |
| - case FAST_ELEMENTS: |
| - case FAST_DOUBLE_ELEMENTS: |
| - break; |
| - case EXTERNAL_PIXEL_ELEMENTS: |
| - case EXTERNAL_BYTE_ELEMENTS: |
| - case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| - case EXTERNAL_SHORT_ELEMENTS: |
| - case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| - case EXTERNAL_INT_ELEMENTS: |
| - case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| - case EXTERNAL_FLOAT_ELEMENTS: |
| - case EXTERNAL_DOUBLE_ELEMENTS: |
| - // Ignore getters and setters on pixel and external array |
| - // elements. |
| - return heap->undefined_value(); |
| - case DICTIONARY_ELEMENTS: { |
| - Object* probe = UpdateGetterSetterInDictionary(element_dictionary(), |
| - index, |
| - attributes, |
| - heap); |
| - if (!probe->IsTheHole()) return probe; |
| - // Otherwise allow to override it. |
| - break; |
| +MaybeObject* JSObject::DefineElementAccessor(uint32_t index, |
| + bool is_getter, |
| + Object* fun, |
| + PropertyAttributes attributes) { |
| + switch (GetElementsKind()) { |
| + case FAST_SMI_ONLY_ELEMENTS: |
| + case FAST_ELEMENTS: |
| + case FAST_DOUBLE_ELEMENTS: |
| + break; |
| + case EXTERNAL_PIXEL_ELEMENTS: |
| + case EXTERNAL_BYTE_ELEMENTS: |
| + case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| + case EXTERNAL_SHORT_ELEMENTS: |
| + case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| + case EXTERNAL_INT_ELEMENTS: |
| + case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| + case EXTERNAL_FLOAT_ELEMENTS: |
| + case EXTERNAL_DOUBLE_ELEMENTS: |
| + // Ignore getters and setters on pixel and external array elements. |
| + return GetHeap()->undefined_value(); |
| + case DICTIONARY_ELEMENTS: |
| + if (UpdateGetterSetterInDictionary(element_dictionary(), |
| + index, |
| + is_getter, |
| + fun, |
| + attributes)) { |
| + return GetHeap()->undefined_value(); |
|
Michael Starzinger
2012/02/22 10:24:38
I prefer having the result of GetHeap() in a local
Sven Panne
2012/02/22 10:52:18
I don't think that one possible additional memory
fschneider
2012/02/24 10:33:17
I don't buy the conciseness argument. heap->undefi
Sven Panne
2012/02/24 11:47:17
It's not about shorter lines, it's all about havin
Michael Starzinger
2012/02/24 12:44:09
Knowing that "heap" refers to the one and only hea
|
| } |
| - case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| - // Ascertain whether we have read-only properties or an existing |
| - // getter/setter pair in an arguments elements dictionary backing |
| - // store. |
| - FixedArray* parameter_map = FixedArray::cast(elements()); |
| - uint32_t length = parameter_map->length(); |
| - Object* probe = |
| - index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
| - if (probe == NULL || probe->IsTheHole()) { |
| - FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| - if (arguments->IsDictionary()) { |
| - SeededNumberDictionary* dictionary = |
| - SeededNumberDictionary::cast(arguments); |
| - probe = UpdateGetterSetterInDictionary(dictionary, |
| - index, |
| - attributes, |
| - heap); |
| - if (!probe->IsTheHole()) return probe; |
| + break; |
| + case NON_STRICT_ARGUMENTS_ELEMENTS: { |
| + // Ascertain whether we have read-only properties or an existing |
| + // getter/setter pair in an arguments elements dictionary backing |
| + // store. |
| + FixedArray* parameter_map = FixedArray::cast(elements()); |
| + uint32_t length = parameter_map->length(); |
| + Object* probe = |
| + index < (length - 2) ? parameter_map->get(index + 2) : NULL; |
| + if (probe == NULL || probe->IsTheHole()) { |
| + FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); |
| + if (arguments->IsDictionary()) { |
| + SeededNumberDictionary* dictionary = |
| + SeededNumberDictionary::cast(arguments); |
| + if (UpdateGetterSetterInDictionary(dictionary, |
| + index, |
| + is_getter, |
| + fun, |
| + attributes)) { |
| + return GetHeap()->undefined_value(); |
| } |
| } |
| - break; |
| } |
| + break; |
| } |
| - } else { |
| - // Lookup the name. |
| - LookupResult result(heap->isolate()); |
| - LocalLookupRealNamedProperty(name, &result); |
| - if (result.IsFound()) { |
| - // TODO(mstarzinger): We should check for result.IsDontDelete() here once |
| - // we only call into the runtime once to set both getter and setter. |
| - if (result.type() == CALLBACKS) { |
| - Object* obj = result.GetCallbackObject(); |
| - // Need to preserve old getters/setters. |
| - if (obj->IsAccessorPair()) { |
| - // Use set to update attributes. |
| - return SetPropertyCallback(name, obj, attributes); |
| + } |
| + |
| + AccessorPair* accessors; |
| + { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair(); |
| + if (!maybe_accessors->To(&accessors)) return maybe_accessors; |
| + } |
| + accessors->set(is_getter, fun); |
| + |
| + { MaybeObject* maybe_ok = SetElementCallback(index, accessors, attributes); |
|
Sven Panne
2012/02/24 11:47:17
I'll apply the same simplification here...
|
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| + } |
| + return GetHeap()->undefined_value(); |
| +} |
| + |
| + |
| +MaybeObject* JSObject::DefinePropertyAccessor(String* name, |
| + bool is_getter, |
| + Object* fun, |
| + PropertyAttributes attributes) { |
| + // Lookup the name. |
| + LookupResult result(GetHeap()->isolate()); |
| + LocalLookupRealNamedProperty(name, &result); |
| + if (result.IsFound()) { |
| + // TODO(mstarzinger): We should check for result.IsDontDelete() here once |
| + // we only call into the runtime once to set both getter and setter. |
| + if (result.type() == CALLBACKS) { |
| + Object* obj = result.GetCallbackObject(); |
| + // Need to preserve old getters/setters. |
| + if (obj->IsAccessorPair()) { |
| + AccessorPair::cast(obj)->set(is_getter, fun); |
| + // Use set to update attributes. |
| + { MaybeObject* maybe_ok = SetPropertyCallback(name, obj, attributes); |
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| } |
| + return GetHeap()->undefined_value(); |
|
fschneider
2012/02/24 10:33:17
return SetPropertyCallback(name, obj, attributes);
Sven Panne
2012/02/24 11:47:17
See remark below.
|
| } |
| } |
| } |
| AccessorPair* accessors; |
| - { MaybeObject* maybe_accessors = heap->AllocateAccessorPair(); |
| - if (!maybe_accessors->To<AccessorPair>(&accessors)) return maybe_accessors; |
| + { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair(); |
| + if (!maybe_accessors->To(&accessors)) return maybe_accessors; |
| } |
| + accessors->set(is_getter, fun); |
| - if (is_element) { |
| - return SetElementCallback(index, accessors, attributes); |
| - } else { |
| - return SetPropertyCallback(name, accessors, attributes); |
| + { MaybeObject* maybe_ok = SetPropertyCallback(name, accessors, attributes); |
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| } |
| + return GetHeap()->undefined_value(); |
|
fschneider
2012/02/24 10:33:17
return SetPropertyCallback(name, accessors, attrib
Sven Panne
2012/02/24 11:47:17
Good point, I'll submit a separate CL for this min
|
| } |
| @@ -4517,19 +4524,15 @@ MaybeObject* JSObject::SetElementCallback(uint32_t index, |
| PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
| // Normalize elements to make this operation simple. |
| - SeededNumberDictionary* dictionary = NULL; |
| - { Object* result; |
| - MaybeObject* maybe = NormalizeElements(); |
| - if (!maybe->ToObject(&result)) return maybe; |
| - dictionary = SeededNumberDictionary::cast(result); |
| + SeededNumberDictionary* dictionary; |
| + { MaybeObject* maybe_dictionary = NormalizeElements(); |
| + if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
| } |
| ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
| // Update the dictionary with the new CALLBACKS property. |
| - { Object* result; |
| - MaybeObject* maybe = dictionary->Set(index, structure, details); |
| - if (!maybe->ToObject(&result)) return maybe; |
| - dictionary = SeededNumberDictionary::cast(result); |
| + { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details); |
| + if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
| } |
| dictionary->set_requires_slow_elements(); |
| @@ -4541,8 +4544,7 @@ MaybeObject* JSObject::SetElementCallback(uint32_t index, |
| // switch to a direct backing store without the parameter map. This |
| // would allow GC of the context. |
| FixedArray* parameter_map = FixedArray::cast(elements()); |
| - uint32_t length = parameter_map->length(); |
| - if (index < length - 2) { |
| + if (index < static_cast<uint32_t>(parameter_map->length()) - 2) { |
| parameter_map->set(index + 2, GetHeap()->the_hole_value()); |
| } |
| parameter_map->set(1, dictionary); |
| @@ -4550,7 +4552,7 @@ MaybeObject* JSObject::SetElementCallback(uint32_t index, |
| set_elements(dictionary); |
| } |
| - return structure; |
| + return GetHeap()->undefined_value(); |
| } |
| @@ -4564,19 +4566,18 @@ MaybeObject* JSObject::SetPropertyCallback(String* name, |
| < DescriptorArray::kMaxNumberOfDescriptors); |
| // Normalize object to make this operation simple. |
| - Object* ok; |
| { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| - if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| } |
| // 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. |
| if (IsGlobalObject()) { |
| - Object* new_map; |
| + Map* new_map; |
| { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); |
| - if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
| + if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
| } |
| - set_map(Map::cast(new_map)); |
| + set_map(new_map); |
| // When running crankshaft, changing the map is not enough. We |
| // need to deoptimize all functions that rely on this global |
| // object. |
| @@ -4584,17 +4585,15 @@ MaybeObject* JSObject::SetPropertyCallback(String* name, |
| } |
| // Update the dictionary with the new CALLBACKS property. |
| - Object* result; |
| - { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details); |
| - if (!maybe_result->ToObject(&result)) return maybe_result; |
| + { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details); |
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| } |
| if (convert_back_to_fast) { |
| - { MaybeObject* maybe_ok = TransformToFastProperties(0); |
| - if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| - } |
| + MaybeObject* maybe_ok = TransformToFastProperties(0); |
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| } |
| - return result; |
| + return GetHeap()->undefined_value(); |
| } |
| MaybeObject* JSObject::DefineAccessor(String* name, |
| @@ -4618,17 +4617,19 @@ MaybeObject* JSObject::DefineAccessor(String* name, |
| fun, attributes); |
| } |
| - Object* accessors; |
| - { MaybeObject* maybe_accessors = DefineGetterSetter(name, attributes); |
| - if (!maybe_accessors->To<Object>(&accessors)) return maybe_accessors; |
| - } |
| - if (accessors->IsUndefined()) return accessors; |
| - if (is_getter) { |
| - AccessorPair::cast(accessors)->set_getter(fun); |
| - } else { |
| - AccessorPair::cast(accessors)->set_setter(fun); |
| - } |
| - return this; |
| + // Make sure that the top context does not change when doing callbacks or |
| + // interceptor calls. |
| + AssertNoContextChange ncc; |
| + |
| + // Try to flatten before operating on the string. |
| + name->TryFlatten(); |
| + |
| + if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); |
| + |
| + uint32_t index = 0; |
| + return name->AsArrayIndex(&index) ? |
| + DefineElementAccessor(index, is_getter, fun, attributes) : |
| + DefinePropertyAccessor(name, is_getter, fun, attributes); |
| } |
| @@ -4691,10 +4692,9 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { |
| break; |
| } |
| - Object* ok; |
| { MaybeObject* maybe_ok = |
| SetElementCallback(index, info, info->property_attributes()); |
| - if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| } |
| } else { |
| // Lookup the name. |
| @@ -4705,10 +4705,9 @@ MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { |
| if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) { |
| return isolate->heap()->undefined_value(); |
| } |
| - Object* ok; |
| { MaybeObject* maybe_ok = |
| SetPropertyCallback(name, info, info->property_attributes()); |
| - if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| + if (maybe_ok->IsFailure()) return maybe_ok; |
| } |
| } |
| @@ -12672,6 +12671,11 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( |
| details.index()); |
| descriptors->Set(next_descriptor++, &d, witness); |
| } else if (type == CALLBACKS) { |
| + if (value->IsAccessorPair()) { |
| + MaybeObject* maybe_copy = |
| + AccessorPair::cast(value)->CopyWithoutTransitions(); |
| + if (!maybe_copy->To(&value)) return maybe_copy; |
| + } |
| CallbacksDescriptor d(String::cast(key), |
| value, |
| details.attributes(), |