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:
parent
8d47a6f625
commit
3e7d642d0a
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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]);
|
||||
|
Loading…
Reference in New Issue
Block a user