Remaining changes to fully support FastDoubleArray.

R=ager@chromium.org
BUG=none
TEST=cctests, unboxed-double-array.js

Review URL: http://codereview.chromium.org/7473031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8718 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
danno@chromium.org 2011-07-22 09:04:16 +00:00
parent 8d47a6f625
commit 3e7d642d0a
5 changed files with 182 additions and 15 deletions

View File

@ -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 @@ void JSObject::PrintElements(FILE* out) {
}
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 @@ void JSObject::PrintElements(FILE* out) {
}
break;
}
default:
UNREACHABLE();
break;
}
}

View File

@ -4689,7 +4689,7 @@ MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
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();
@ -4786,6 +4786,69 @@ MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
}
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) {
Heap* heap = GetHeap();
if (new_length == 0) return heap->empty_fixed_array();
@ -7542,9 +7605,10 @@ MaybeObject* JSObject::SetSlowElements(Object* len) {
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 @@ MaybeObject* JSObject::SetSlowElements(Object* len) {
case EXTERNAL_FLOAT_ELEMENTS:
case EXTERNAL_DOUBLE_ELEMENTS:
case EXTERNAL_PIXEL_ELEMENTS:
case FAST_DOUBLE_ELEMENTS:
UNREACHABLE();
break;
}
@ -7914,6 +7977,17 @@ bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
}
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 @@ bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
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 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
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 @@ bool JSObject::HasRealElementProperty(uint32_t index) {
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;

View File

@ -2050,6 +2050,7 @@ class FixedArrayBase: public HeapObject {
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 @@ class FixedArray: public FixedArrayBase {
// 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);

View File

@ -3560,6 +3560,68 @@ THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
}
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(
uint32_t index,
const AccessorInfo& info) {

View File

@ -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();
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]);