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