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

Reply via email to