Revision: 8718
Author:   [email protected]
Date:     Fri Jul 22 02:04:16 2011
Log:      Remaining changes to fully support FastDoubleArray.

[email protected]
BUG=none
TEST=cctests, unboxed-double-array.js

Review URL: http://codereview.chromium.org/7473031
http://code.google.com/p/v8/source/detail?r=8718

Modified:
 /branches/bleeding_edge/src/objects-printer.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/test/cctest/test-api.cc
 /branches/bleeding_edge/test/mjsunit/unbox-double-arrays.js

=======================================
--- /branches/bleeding_edge/src/objects-printer.cc      Thu Jun 16 07:12:58 2011
+++ /branches/bleeding_edge/src/objects-printer.cc      Fri Jul 22 02:04:16 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -282,6 +282,19 @@
       }
       break;
     }
+    case FAST_DOUBLE_ELEMENTS: {
+      // Print in array notation for non-sparse arrays.
+      FixedDoubleArray* p = FixedDoubleArray::cast(elements());
+      for (int i = 0; i < p->length(); i++) {
+        if (p->is_the_hole(i)) {
+          PrintF(out, "   %d: <the hole>", i);
+        } else {
+          PrintF(out, "   %d: %g", i, p->get(i));
+        }
+        PrintF(out, "\n");
+      }
+      break;
+    }
     case EXTERNAL_PIXEL_ELEMENTS: {
       ExternalPixelArray* p = ExternalPixelArray::cast(elements());
       for (int i = 0; i < p->length(); i++) {
@@ -360,9 +373,6 @@
       }
       break;
     }
-    default:
-      UNREACHABLE();
-      break;
   }
 }

=======================================
--- /branches/bleeding_edge/src/objects.cc      Thu Jul 21 06:51:04 2011
+++ /branches/bleeding_edge/src/objects.cc      Fri Jul 22 02:04:16 2011
@@ -4689,7 +4689,7 @@
     case JSObject::FAST_ELEMENTS:
       return UnionOfKeys(FixedArray::cast(array->elements()));
     case JSObject::FAST_DOUBLE_ELEMENTS:
-      UNIMPLEMENTED();
+      return UnionOfDoubleKeys(FixedDoubleArray::cast(array->elements()));
       break;
     case JSObject::DICTIONARY_ELEMENTS: {
       NumberDictionary* dict = array->element_dictionary();
@@ -4784,6 +4784,69 @@
   ASSERT(extra == index);
   return result;
 }
+
+
+MaybeObject* FixedArray::UnionOfDoubleKeys(FixedDoubleArray* other) {
+  int len0 = length();
+#ifdef DEBUG
+  if (FLAG_enable_slow_asserts) {
+    for (int i = 0; i < len0; i++) {
+      ASSERT(get(i)->IsString() || get(i)->IsNumber());
+    }
+  }
+#endif
+  int len1 = other->length();
+  // Optimize if 'other' is empty.
+  // We cannot optimize if 'this' is empty, as other may have holes
+  // or non keys.
+  if (len1 == 0) return this;
+
+  // Compute how many elements are not in this.
+  int extra = 0;
+  Heap* heap = GetHeap();
+  Object* obj;
+  for (int y = 0; y < len1; y++) {
+    if (!other->is_the_hole(y)) {
+      MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y));
+      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+      if (!HasKey(this, obj)) extra++;
+    }
+  }
+
+  if (extra == 0) return this;
+
+  // Allocate the result
+  { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
+    if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+  }
+  // Fill in the content
+  FixedArray* result = FixedArray::cast(obj);
+  {
+    // Limit the scope of the AssertNoAllocation
+    AssertNoAllocation no_gc;
+    WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
+    for (int i = 0; i < len0; i++) {
+      Object* e = get(i);
+      ASSERT(e->IsString() || e->IsNumber());
+      result->set(i, e, mode);
+    }
+  }
+
+  // Fill in the extra keys.
+  int index = 0;
+  for (int y = 0; y < len1; y++) {
+    if (!other->is_the_hole(y)) {
+      MaybeObject* maybe_obj = heap->NumberFromDouble(other->get(y));
+      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+      if (!HasKey(this, obj)) {
+        result->set(len0 + index, obj);
+        index++;
+      }
+    }
+  }
+  ASSERT(extra == index);
+  return result;
+}


 MaybeObject* FixedArray::CopySize(int new_length) {
@@ -7542,9 +7605,10 @@

   switch (GetElementsKind()) {
     case FAST_ELEMENTS: {
+    case FAST_DOUBLE_ELEMENTS:
       // Make sure we never try to shrink dense arrays into sparse arrays.
- ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
-                                   new_length);
+      ASSERT(static_cast<uint32_t>(
+          FixedArrayBase::cast(elements())->length()) <= new_length);
       MaybeObject* result = NormalizeElements();
       if (result->IsFailure()) return result;

@@ -7573,7 +7637,6 @@
     case EXTERNAL_FLOAT_ELEMENTS:
     case EXTERNAL_DOUBLE_ELEMENTS:
     case EXTERNAL_PIXEL_ELEMENTS:
-    case FAST_DOUBLE_ELEMENTS:
       UNREACHABLE();
       break;
   }
@@ -7914,6 +7977,17 @@
       }
       break;
     }
+    case FAST_DOUBLE_ELEMENTS: {
+      uint32_t length = IsJSArray() ?
+          static_cast<uint32_t>
+              (Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+      if ((index < length) &&
+          !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
+        return true;
+      }
+      break;
+    }
     case EXTERNAL_PIXEL_ELEMENTS: {
       ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
       if (index < static_cast<uint32_t>(pixels->length())) {
@@ -7928,8 +8002,7 @@
     case EXTERNAL_INT_ELEMENTS:
     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
     case EXTERNAL_FLOAT_ELEMENTS:
-    case EXTERNAL_DOUBLE_ELEMENTS:
-    case FAST_DOUBLE_ELEMENTS: {
+    case EXTERNAL_DOUBLE_ELEMENTS: {
       ExternalArray* array = ExternalArray::cast(elements());
       if (index < static_cast<uint32_t>(array->length())) {
         return true;
@@ -9380,6 +9453,15 @@
       return (index < length) &&
           !FixedArray::cast(elements())->get(index)->IsTheHole();
     }
+    case FAST_DOUBLE_ELEMENTS: {
+      uint32_t length = IsJSArray() ?
+          static_cast<uint32_t>(
+              Smi::cast(JSArray::cast(this)->length())->value()) :
+ static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
+      return (index < length) &&
+          !FixedDoubleArray::cast(elements())->is_the_hole(index);
+      break;
+    }
     case EXTERNAL_PIXEL_ELEMENTS: {
       ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
       return index < static_cast<uint32_t>(pixels->length());
@@ -9395,9 +9477,6 @@
       ExternalArray* array = ExternalArray::cast(elements());
       return index < static_cast<uint32_t>(array->length());
     }
-    case FAST_DOUBLE_ELEMENTS:
-      UNREACHABLE();
-      break;
     case DICTIONARY_ELEMENTS: {
       return element_dictionary()->FindEntry(index)
           != NumberDictionary::kNotFound;
=======================================
--- /branches/bleeding_edge/src/objects.h       Thu Jul 21 06:51:04 2011
+++ /branches/bleeding_edge/src/objects.h       Fri Jul 22 02:04:16 2011
@@ -2050,6 +2050,7 @@
   static const int kHeaderSize = kLengthOffset + kPointerSize;
 };

+class FixedDoubleArray;

 // FixedArray describes fixed-sized arrays with element type Object*.
 class FixedArray: public FixedArrayBase {
@@ -2092,6 +2093,10 @@
   // Compute the union of this and other.
   MUST_USE_RESULT MaybeObject* UnionOfKeys(FixedArray* other);

+  // Compute the union of this and other.
+  MUST_USE_RESULT MaybeObject* UnionOfDoubleKeys(
+      FixedDoubleArray* other);
+
   // Copy a sub array from the receiver to dest.
   void CopyTo(int pos, FixedArray* dest, int dest_pos, int len);

=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc     Mon Jul 18 10:44:57 2011
+++ /branches/bleeding_edge/test/cctest/test-api.cc     Fri Jul 22 02:04:16 2011
@@ -3558,6 +3558,68 @@
   result = interceptor_getter_script->Run();
   CHECK_EQ(v8_num(625), result);
 }
+
+
+static v8::Handle<Value> UnboxedDoubleIndexedPropertyGetter(
+    uint32_t index,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  if (index < 25) {
+    return v8::Handle<Value>(v8_num(index));
+  }
+  return v8::Handle<Value>();
+}
+
+
+static v8::Handle<Value> UnboxedDoubleIndexedPropertySetter(
+    uint32_t index,
+    Local<Value> value,
+    const AccessorInfo& info) {
+  ApiTestFuzzer::Fuzz();
+  if (index < 25) {
+    return v8::Handle<Value>(v8_num(index));
+  }
+  return v8::Handle<Value>();
+}
+
+
+Handle<v8::Array> UnboxedDoubleIndexedPropertyEnumerator(
+    const AccessorInfo& info) {
+  // Force the list of returned keys to be stored in a FastDoubleArray.
+  Local<Script> indexed_property_names_script = Script::Compile(v8_str(
+      "keys = new Array(); keys[125000] = 1;"
+      "for(i = 0; i < 80000; i++) { keys[i] = i; };"
+      "keys.length = 25; keys;"));
+  Local<Value> result = indexed_property_names_script->Run();
+  return Local<v8::Array>(::v8::Array::Cast(*result));
+}
+
+
+// Make sure that the the interceptor code in the runtime properly handles
+// merging property name lists for double-array-backed arrays.
+THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
+  v8::HandleScope scope;
+  Local<ObjectTemplate> templ = ObjectTemplate::New();
+  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
+                                   UnboxedDoubleIndexedPropertySetter,
+                                   0,
+                                   0,
+                                   UnboxedDoubleIndexedPropertyEnumerator);
+  LocalContext context;
+  context->Global()->Set(v8_str("obj"), templ->NewInstance());
+  // When obj is created, force it to be Stored in a FastDoubleArray.
+  Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
+      "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
+      "key_count = 0; "
+      "for (x in obj) {key_count++;};"
+      "obj;"));
+  Local<Value> result = create_unboxed_double_script->Run();
+  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
+  Local<Script> key_count_check = Script::Compile(v8_str(
+      "key_count;"));
+  result = key_count_check->Run();
+  CHECK_EQ(v8_num(40013), result);
+}


 static v8::Handle<Value> IdentityIndexedPropertyGetter(
=======================================
--- /branches/bleeding_edge/test/mjsunit/unbox-double-arrays.js Wed Jul 20 06:41:50 2011 +++ /branches/bleeding_edge/test/mjsunit/unbox-double-arrays.js Fri Jul 22 02:04:16 2011
@@ -29,12 +29,12 @@

 // Flags: --allow-natives-syntax --unbox-double-arrays --expose-gc
 var large_array_size = 100000;
-var approx_dict_to_elements_threshold = 75000;
+var approx_dict_to_elements_threshold = 70000;

 var name = 0;

 function expected_array_value(i) {
-  if ((i % 2) == 0) {
+  if ((i % 50) != 0) {
     return i;
   } else {
     return i + 0.5;
@@ -467,6 +467,17 @@
 test_for_in();
 test_for_in();

+function test_get_property_names() {
+  names = %GetPropertyNames(large_array3);
+  property_name_count = 0;
+  for (x in names) { property_name_count++; };
+  assertEquals(26, property_name_count);
+}
+
+test_get_property_names();
+test_get_property_names();
+test_get_property_names();
+
 // Test elements getters.
 assertEquals(expected_array_value(10), large_array3[10]);
 assertEquals(expected_array_value(-NaN), large_array3[2]);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to