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(), |