Revision: 7433
Author: [email protected]
Date: Wed Mar 30 04:09:54 2011
Log: [Arguments] Support getters and setters on non-strict arguments
objects.
[email protected]
Review URL: http://codereview.chromium.org/6778008
http://code.google.com/p/v8/source/detail?r=7433
Modified:
/branches/experimental/arguments/src/objects.cc
/branches/experimental/arguments/src/runtime.cc
=======================================
--- /branches/experimental/arguments/src/objects.cc Tue Mar 29 03:57:43 2011
+++ /branches/experimental/arguments/src/objects.cc Wed Mar 30 04:09:54 2011
@@ -2571,22 +2571,20 @@
MaybeObject* JSObject::NormalizeElements() {
ASSERT(!HasExternalArrayElements());
- if (HasDictionaryElements() || HasDictionaryArgumentsElements()) {
- return elements();
- }
- ASSERT(HasFastElements() || HasFastArgumentsElements());
// Find the backing store.
- FixedArray* fast_elements = FixedArray::cast(elements());
+ FixedArray* elements = FixedArray::cast(this->elements());
bool is_arguments =
- (fast_elements->map() ==
GetHeap()->non_strict_arguments_elements_map());
+ (elements->map() == GetHeap()->non_strict_arguments_elements_map());
if (is_arguments) {
- fast_elements = FixedArray::cast(fast_elements->get(1));
- }
-
+ elements = FixedArray::cast(elements->get(1));
+ }
+ if (elements->IsDictionary()) return elements;
+
+ ASSERT(HasFastElements() || HasFastArgumentsElements());
// Compute the effective length and allocate a new backing store.
int length = IsJSArray()
? Smi::cast(JSArray::cast(this)->length())->value()
- : fast_elements->length();
+ : elements->length();
NumberDictionary* dictionary = NULL;
{ Object* object;
MaybeObject* maybe = NumberDictionary::Allocate(length);
@@ -2596,20 +2594,20 @@
// Copy the elements to the new backing store.
for (int i = 0; i < length; i++) {
- Object* value = fast_elements->get(i);
+ Object* value = elements->get(i);
if (!value->IsTheHole()) {
PropertyDetails details = PropertyDetails(NONE, NORMAL);
- Object* result;
+ Object* new_dictionary;
MaybeObject* maybe =
- dictionary->AddNumberEntry(i, fast_elements->get(i), details);
- if (!maybe->ToObject(&result)) return maybe;
- dictionary = NumberDictionary::cast(result);
+ dictionary->AddNumberEntry(i, elements->get(i), details);
+ if (!maybe->ToObject(&new_dictionary)) return maybe;
+ dictionary = NumberDictionary::cast(new_dictionary);
}
}
// Switch to using the dictionary as the backing storage for elements.
if (is_arguments) {
- FixedArray::cast(elements())->set(1, dictionary);
+ FixedArray::cast(this->elements())->set(1, dictionary);
} else {
// Set the new map first to satify the elements type assert in
// set_elements().
@@ -3220,6 +3218,24 @@
}
result->NotFound();
}
+
+
+// Search for a getter or setter in an elements dictionary. Returns either
+// undefined if the element is read-only, or the getter/setter pair (fixed
+// array) 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* FindGetterSetterInDictionary(NumberDictionary* dictionary,
+ uint32_t index,
+ Heap* heap) {
+ int entry = dictionary->FindEntry(index);
+ if (entry != NumberDictionary::kNotFound) {
+ Object* result = dictionary->ValueAt(entry);
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ if (details.IsReadOnly()) return heap->undefined_value();
+ if (details.type() == CALLBACKS && result->IsFixedArray()) return
result;
+ }
+ return heap->the_hole_value();
+}
MaybeObject* JSObject::DefineGetterSetter(String* name,
@@ -3255,25 +3271,30 @@
// elements.
return heap->undefined_value();
case DICTIONARY_ELEMENTS: {
- // Lookup the index.
- NumberDictionary* dictionary = element_dictionary();
- int entry = dictionary->FindEntry(index);
- if (entry != NumberDictionary::kNotFound) {
- Object* result = dictionary->ValueAt(entry);
- PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.IsReadOnly()) return heap->undefined_value();
- if (details.type() == CALLBACKS) {
- if (result->IsFixedArray()) {
- return result;
- }
- // Otherwise allow to override it.
+ Object* probe =
+ FindGetterSetterInDictionary(element_dictionary(), index,
heap);
+ if (!probe->IsTheHole()) return probe;
+ // Otherwise allow to override it.
+ 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 + 2) < length ? parameter_map->get(index + 2) : NULL;
+ if (probe == NULL || probe->IsTheHole()) {
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ if (arguments->IsDictionary()) {
+ NumberDictionary* dictionary =
NumberDictionary::cast(arguments);
+ probe = FindGetterSetterInDictionary(dictionary, index, heap);
+ if (!probe->IsTheHole()) return probe;
}
}
break;
}
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
- break;
}
} else {
// Lookup the name.
@@ -3336,24 +3357,38 @@
PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
// Normalize elements to make this operation simple.
- Object* ok;
- { MaybeObject* maybe_ok = NormalizeElements();
- if (!maybe_ok->ToObject(&ok)) return maybe_ok;
- }
- // TODO(kmillikin): Handle arguments object with dictionary elements.
- ASSERT(HasDictionaryElements());
+ NumberDictionary* dictionary = NULL;
+ { Object* result;
+ MaybeObject* maybe = NormalizeElements();
+ if (!maybe->ToObject(&result)) return maybe;
+ dictionary = NumberDictionary::cast(result);
+ }
+ ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
// Update the dictionary with the new CALLBACKS property.
- Object* dict;
- { MaybeObject* maybe_dict =
- element_dictionary()->Set(index, structure, details);
- if (!maybe_dict->ToObject(&dict)) return maybe_dict;
+ { Object* result;
+ MaybeObject* maybe = dictionary->Set(index, structure, details);
+ if (!maybe->ToObject(&result)) return maybe;
+ dictionary = NumberDictionary::cast(result);
}
- NumberDictionary* elements = NumberDictionary::cast(dict);
- elements->set_requires_slow_elements();
- // Set the potential new dictionary on the object.
- set_elements(elements);
+ dictionary->set_requires_slow_elements();
+ // Update the dictionary backing store on the object.
+ if (elements()->map() == GetHeap()->non_strict_arguments_elements_map())
{
+ // Also delete any parameter alias.
+ //
+ // TODO(kmillikin): when deleting the last parameter alias we could
+ // 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 + 2 < length) {
+ parameter_map->set(index + 2, GetHeap()->the_hole_value());
+ }
+ parameter_map->set(1, dictionary);
+ } else {
+ set_elements(dictionary);
+ }
return structure;
}
@@ -7166,14 +7201,34 @@
}
case DICTIONARY_ELEMENTS: {
if (element_dictionary()->FindEntry(index) !=
- NumberDictionary::kNotFound) {
+ NumberDictionary::kNotFound) {
return DICTIONARY_ELEMENT;
}
break;
}
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNIMPLEMENTED();
+ case NON_STRICT_ARGUMENTS_ELEMENTS: {
+ // Aliased parameters and non-aliased elements in a fast backing
store
+ // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
+ // backing store behave as DICTIONARY_ELEMENT.
+ FixedArray* parameter_map = FixedArray::cast(elements());
+ uint32_t length = parameter_map->length();
+ Object* probe =
+ (index + 2) < length ? parameter_map->get(index + 2) : NULL;
+ if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
+ // If not aliased, check the arguments.
+ FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ if (arguments->IsDictionary()) {
+ NumberDictionary* dictionary = NumberDictionary::cast(arguments);
+ if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
+ return DICTIONARY_ELEMENT;
+ }
+ } else {
+ length = arguments->length();
+ probe = (index < length) ? arguments->get(index) : NULL;
+ if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
+ }
break;
+ }
}
return UNDEFINED_ELEMENT;
@@ -7323,7 +7378,7 @@
Handle<JSObject> self(JSObject::cast(receiver));
Handle<JSObject> holder_handle(JSObject::cast(holder));
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
- Handle<String> key(isolate->factory()->NumberToString(number));
+ Handle<String> key = isolate->factory()->NumberToString(number);
LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
CustomArguments args(isolate, data->data(), *self, *holder_handle);
v8::AccessorInfo info(args.end());
@@ -7898,8 +7953,13 @@
if (entry != NumberDictionary::kNotFound) {
Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry);
- if (details.type() != CALLBACKS) return element;
- UNIMPLEMENTED(); // CALLBACKS not yet implemented.
+ if (details.type() == CALLBACKS) {
+ return GetElementWithCallback(receiver,
+ element,
+ index,
+ this);
+ }
+ return element;
}
} else if (index < static_cast<uint32_t>(arguments->length())) {
Object* value = arguments->get(index);
=======================================
--- /branches/experimental/arguments/src/runtime.cc Tue Mar 29 03:57:43 2011
+++ /branches/experimental/arguments/src/runtime.cc Wed Mar 30 04:09:54 2011
@@ -879,7 +879,13 @@
ASSERT(proto->IsJSGlobalObject());
holder = Handle<JSObject>(JSObject::cast(proto));
}
- NumberDictionary* dictionary = holder->element_dictionary();
+ FixedArray* elements = FixedArray::cast(holder->elements());
+ NumberDictionary* dictionary = NULL;
+ if (elements->map() == heap->non_strict_arguments_elements_map()) {
+ dictionary = NumberDictionary::cast(elements->get(1));
+ } else {
+ dictionary = NumberDictionary::cast(elements);
+ }
int entry = dictionary->FindEntry(index);
ASSERT(entry != NumberDictionary::kNotFound);
PropertyDetails details = dictionary->DetailsAt(entry);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev