Version 2.2.13.

Implement Object.getOwnPropertyDescriptor for element indices and strings (issue 599).

Fix bug for windows 64 bit C calls from generated code.

Add new scons flag unalignedaccesses for arm builds.

Performance improvements on all platforms.


git-svn-id: http://v8.googlecode.com/svn/trunk@4756 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime.cc b/src/runtime.cc
index b421ac7..d53b13d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -291,7 +291,7 @@
         Handle<String> name(String::cast(*key));
         ASSERT(!name->AsArrayIndex(&element_index));
         result = SetProperty(boilerplate, name, value, NONE);
-      } else if (Array::IndexFromObject(*key, &element_index)) {
+      } else if (key->ToArrayIndex(&element_index)) {
         // Array index (uint32).
         result = SetElement(boilerplate, element_index, value);
       } else {
@@ -569,6 +569,18 @@
 }
 
 
+// Enumerator used as indices into the array returned from GetOwnProperty
+enum PropertyDescriptorIndices {
+  IS_ACCESSOR_INDEX,
+  VALUE_INDEX,
+  GETTER_INDEX,
+  SETTER_INDEX,
+  WRITABLE_INDEX,
+  ENUMERABLE_INDEX,
+  CONFIGURABLE_INDEX,
+  DESCRIPTOR_SIZE
+};
+
 // Returns an array with the property description:
 //  if args[1] is not a property on args[0]
 //          returns undefined
@@ -579,18 +591,63 @@
 static Object* Runtime_GetOwnProperty(Arguments args) {
   ASSERT(args.length() == 2);
   HandleScope scope;
-  Handle<FixedArray> elms = Factory::NewFixedArray(5);
+  Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
   Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
   LookupResult result;
   CONVERT_CHECKED(JSObject, obj, args[0]);
   CONVERT_CHECKED(String, name, args[1]);
 
+  // This could be an element.
+  uint32_t index;
+  if (name->AsArrayIndex(&index)) {
+    if (!obj->HasLocalElement(index)) {
+      return Heap::undefined_value();
+    }
+
+    // Special handling of string objects according to ECMAScript 5 15.5.5.2.
+    // Note that this might be a string object with elements other than the
+    // actual string value. This is covered by the subsequent cases.
+    if (obj->IsStringObjectWithCharacterAt(index)) {
+      JSValue* js_value = JSValue::cast(obj);
+      String* str = String::cast(js_value->value());
+      elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+      elms->set(VALUE_INDEX, str->SubString(index, index+1));
+      elms->set(WRITABLE_INDEX, Heap::false_value());
+      elms->set(ENUMERABLE_INDEX,  Heap::false_value());
+      elms->set(CONFIGURABLE_INDEX, Heap::false_value());
+      return *desc;
+    }
+
+    // This can potentially be an element in the elements dictionary or
+    // a fast element.
+    if (obj->HasDictionaryElements()) {
+      NumberDictionary* dictionary = obj->element_dictionary();
+      int entry = dictionary->FindEntry(index);
+      PropertyDetails details = dictionary->DetailsAt(entry);
+      elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+      elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
+      elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
+      elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
+      elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
+      return *desc;
+    } else {
+      // Elements that are stored as array elements always has:
+      // writable: true, configurable: true, enumerable: true.
+      elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+      elms->set(VALUE_INDEX, obj->GetElement(index));
+      elms->set(WRITABLE_INDEX, Heap::true_value());
+      elms->set(ENUMERABLE_INDEX,  Heap::true_value());
+      elms->set(CONFIGURABLE_INDEX, Heap::true_value());
+      return *desc;
+    }
+  }
+
   // Use recursive implementation to also traverse hidden prototypes
   GetOwnPropertyImplementation(obj, name, &result);
 
-  if (!result.IsProperty())
+  if (!result.IsProperty()) {
     return Heap::undefined_value();
-
+  }
   if (result.type() == CALLBACKS) {
     Object* structure = result.GetCallbackObject();
     if (structure->IsProxy() || structure->IsAccessorInfo()) {
@@ -598,25 +655,25 @@
       // an API defined callback.
       Object* value = obj->GetPropertyWithCallback(
           obj, structure, name, result.holder());
-      elms->set(0, Heap::false_value());
-      elms->set(1, value);
-      elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
+      elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+      elms->set(VALUE_INDEX, value);
+      elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
     } else if (structure->IsFixedArray()) {
       // __defineGetter__/__defineSetter__ callback.
-      elms->set(0, Heap::true_value());
-      elms->set(1, FixedArray::cast(structure)->get(0));
-      elms->set(2, FixedArray::cast(structure)->get(1));
+      elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
+      elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
+      elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
     } else {
       return Heap::undefined_value();
     }
   } else {
-    elms->set(0, Heap::false_value());
-    elms->set(1, result.GetLazyValue());
-    elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
+    elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+    elms->set(VALUE_INDEX, result.GetLazyValue());
+    elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
   }
 
-  elms->set(3, Heap::ToBoolean(!result.IsDontEnum()));
-  elms->set(4, Heap::ToBoolean(!result.IsDontDelete()));
+  elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
+  elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
   return *desc;
 }
 
@@ -1583,7 +1640,7 @@
 
 static Object* CharCodeAt(String* subject, Object* index) {
   uint32_t i = 0;
-  if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
+  if (!index->ToArrayIndex(&i)) return Heap::nan_value();
   // Flatten the string.  If someone wants to get a char at an index
   // in a cons string, it is likely that more indices will be
   // accessed.
@@ -1599,7 +1656,7 @@
 
 static Object* CharFromCode(Object* char_code) {
   uint32_t code;
-  if (Array::IndexFromObject(char_code, &code)) {
+  if (char_code->ToArrayIndex(&code)) {
     if (code <= 0xffff) {
       return Heap::LookupSingleCharacterStringFromCode(code);
     }
@@ -2780,7 +2837,7 @@
 
   Object* index = args[2];
   uint32_t start_index;
-  if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
+  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
 
   RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
   int position = Runtime::StringMatch(sub, pat, start_index);
@@ -2830,7 +2887,7 @@
 
   Object* index = args[2];
   uint32_t start_index;
-  if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
+  if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
 
   uint32_t pat_length = pat->length();
   uint32_t sub_length = sub->length();
@@ -3657,7 +3714,7 @@
 
   // Check if the given key is an array index.
   uint32_t index;
-  if (Array::IndexFromObject(*key, &index)) {
+  if (key->ToArrayIndex(&index)) {
     return GetElementOrCharAt(object, index);
   }
 
@@ -3843,7 +3900,7 @@
 
   // Check if the given key is an array index.
   uint32_t index;
-  if (Array::IndexFromObject(*key, &index)) {
+  if (key->ToArrayIndex(&index)) {
     // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
     // of a string using [] notation.  We need to support this too in
     // JavaScript.
@@ -3895,7 +3952,7 @@
 
   // Check if the given key is an array index.
   uint32_t index;
-  if (Array::IndexFromObject(*key, &index)) {
+  if (key->ToArrayIndex(&index)) {
     // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
     // of a string using [] notation.  We need to support this too in
     // JavaScript.
@@ -3942,7 +3999,7 @@
 
   // Check if the given key is an array index.
   uint32_t index;
-  if (Array::IndexFromObject(*key, &index)) {
+  if (key->ToArrayIndex(&index)) {
     // In Firefox/SpiderMonkey, Safari and Opera you can access the
     // characters of a string using [] notation.  In the case of a
     // String object we just need to redirect the deletion to the
@@ -4355,7 +4412,7 @@
   // Try to convert the key to an index. If successful and within
   // index return the the argument from the frame.
   uint32_t index;
-  if (Array::IndexFromObject(args[0], &index) && index < n) {
+  if (args[0]->ToArrayIndex(&index) && index < n) {
     return frame->GetParameter(index);
   }
 
@@ -5287,6 +5344,25 @@
 }
 
 
+static Object* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
+  NoHandleAllocation ha;
+  ASSERT(args.length() == 1);
+
+  CONVERT_DOUBLE_CHECKED(number, args[0]);
+
+  // We do not include 0 so that we don't have to treat +0 / -0 cases.
+  if (number > 0 && number <= Smi::kMaxValue) {
+    return Smi::FromInt(static_cast<int>(number));
+  }
+
+  double double_value = DoubleToInteger(number);
+  // Map both -0 and +0 to +0.
+  if (double_value == 0) double_value = 0;
+
+  return Heap::NumberFromDouble(double_value);
+}
+
+
 static Object* Runtime_NumberToJSUint32(Arguments args) {
   NoHandleAllocation ha;
   ASSERT(args.length() == 1);
@@ -6457,8 +6533,8 @@
     if (obj->IsFailure()) return obj;
 
     AssertNoAllocation no_gc;
-    reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
-    FixedArray* array = FixedArray::cast(obj);
+    FixedArray* array = reinterpret_cast<FixedArray*>(obj);
+    array->set_map(Heap::fixed_array_map());
     array->set_length(length);
 
     WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
@@ -7747,8 +7823,8 @@
   Handle<Object> key2 = args.at<Object>(2);
 
   uint32_t index1, index2;
-  if (!Array::IndexFromObject(*key1, &index1)
-      || !Array::IndexFromObject(*key2, &index2)) {
+  if (!key1->ToArrayIndex(&index1)
+      || !key2->ToArrayIndex(&index2)) {
     return Top::ThrowIllegalOperation();
   }
 
@@ -7779,17 +7855,19 @@
     for (int i = 0; i < keys_length; i++) {
       Object* key = keys->get(i);
       uint32_t index;
-      if (!Array::IndexFromObject(key, &index) || index >= length) {
+      if (!key->ToArrayIndex(&index) || index >= length) {
         // Zap invalid keys.
         keys->set_undefined(i);
       }
     }
     return *Factory::NewJSArrayWithElements(keys);
   } else {
+    ASSERT(array->HasFastElements());
     Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
     // -1 means start of array.
     single_interval->set(0, Smi::FromInt(-1));
-    uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
+    uint32_t actual_length =
+        static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
     uint32_t min_length = actual_length < length ? actual_length : length;
     Handle<Object> length_object =
         Factory::NewNumber(static_cast<double>(min_length));