Commit 4de3bb50 authored by danno@chromium.org's avatar danno@chromium.org

Implement core support for FixedDoubleArrays.

Under a flag without IC or Crankshaft support.

BUG=none
TEST=none

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8229 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 62a65fcc
...@@ -3726,7 +3726,7 @@ class Internals { ...@@ -3726,7 +3726,7 @@ class Internals {
static const int kFullStringRepresentationMask = 0x07; static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02; static const int kExternalTwoByteRepresentationTag = 0x02;
static const int kJSObjectType = 0xa2; static const int kJSObjectType = 0xa3;
static const int kFirstNonstringType = 0x80; static const int kFirstNonstringType = 0x80;
static const int kForeignType = 0x85; static const int kForeignType = 0x85;
......
// 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -58,6 +58,16 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size, ...@@ -58,6 +58,16 @@ Handle<FixedArray> Factory::NewFixedArrayWithHoles(int size,
} }
Handle<FixedArray> Factory::NewFixedDoubleArray(int size,
PretenureFlag pretenure) {
ASSERT(0 <= size);
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateUninitializedFixedDoubleArray(size, pretenure),
FixedArray);
}
Handle<StringDictionary> Factory::NewStringDictionary(int at_least_space_for) { Handle<StringDictionary> Factory::NewStringDictionary(int at_least_space_for) {
ASSERT(0 <= at_least_space_for); ASSERT(0 <= at_least_space_for);
CALL_HEAP_FUNCTION(isolate(), CALL_HEAP_FUNCTION(isolate(),
......
// 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -39,7 +39,7 @@ namespace internal { ...@@ -39,7 +39,7 @@ namespace internal {
class Factory { class Factory {
public: public:
// Allocate a new fixed array with undefined entries. // Allocate a new uninitialized fixed array.
Handle<FixedArray> NewFixedArray( Handle<FixedArray> NewFixedArray(
int size, int size,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
...@@ -49,6 +49,11 @@ class Factory { ...@@ -49,6 +49,11 @@ class Factory {
int size, int size,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
// Allocate a new uninitialized fixed double array.
Handle<FixedArray> NewFixedDoubleArray(
int size,
PretenureFlag pretenure = NOT_TENURED);
Handle<NumberDictionary> NewNumberDictionary(int at_least_space_for); Handle<NumberDictionary> NewNumberDictionary(int at_least_space_for);
Handle<StringDictionary> NewStringDictionary(int at_least_space_for); Handle<StringDictionary> NewStringDictionary(int at_least_space_for);
......
...@@ -99,6 +99,9 @@ private: ...@@ -99,6 +99,9 @@ private:
// Flags for experimental language features. // Flags for experimental language features.
DEFINE_bool(harmony_proxies, false, "enable harmony proxies") DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
// Flags for experimental implementation features.
DEFINE_bool(unbox_double_arrays, false, "automatically unbox arrays of doubles")
// Flags for Crankshaft. // Flags for Crankshaft.
#ifdef V8_TARGET_ARCH_MIPS #ifdef V8_TARGET_ARCH_MIPS
DEFINE_bool(crankshaft, false, "use crankshaft") DEFINE_bool(crankshaft, false, "use crankshaft")
......
...@@ -1286,6 +1286,7 @@ class ScavengingVisitor : public StaticVisitorBase { ...@@ -1286,6 +1286,7 @@ class ScavengingVisitor : public StaticVisitorBase {
table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
table_.Register(kVisitByteArray, &EvacuateByteArray); table_.Register(kVisitByteArray, &EvacuateByteArray);
table_.Register(kVisitFixedArray, &EvacuateFixedArray); table_.Register(kVisitFixedArray, &EvacuateFixedArray);
table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
table_.Register(kVisitGlobalContext, table_.Register(kVisitGlobalContext,
&ObjectEvacuationStrategy<POINTER_OBJECT>:: &ObjectEvacuationStrategy<POINTER_OBJECT>::
...@@ -1433,6 +1434,18 @@ class ScavengingVisitor : public StaticVisitorBase { ...@@ -1433,6 +1434,18 @@ class ScavengingVisitor : public StaticVisitorBase {
} }
static inline void EvacuateFixedDoubleArray(Map* map,
HeapObject** slot,
HeapObject* object) {
int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
int object_size = FixedDoubleArray::SizeFor(length);
EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map,
slot,
object,
object_size);
}
static inline void EvacuateByteArray(Map* map, static inline void EvacuateByteArray(Map* map,
HeapObject** slot, HeapObject** slot,
HeapObject* object) { HeapObject* object) {
...@@ -1771,6 +1784,12 @@ bool Heap::CreateInitialMaps() { ...@@ -1771,6 +1784,12 @@ bool Heap::CreateInitialMaps() {
set_undetectable_ascii_string_map(Map::cast(obj)); set_undetectable_ascii_string_map(Map::cast(obj));
Map::cast(obj)->set_is_undetectable(); Map::cast(obj)->set_is_undetectable();
{ MaybeObject* maybe_obj =
AllocateMap(FIXED_DOUBLE_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_fixed_double_array_map(Map::cast(obj));
{ MaybeObject* maybe_obj = { MaybeObject* maybe_obj =
AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel); AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false; if (!maybe_obj->ToObject(&obj)) return false;
...@@ -3812,6 +3831,62 @@ MaybeObject* Heap::AllocateUninitializedFixedArray(int length) { ...@@ -3812,6 +3831,62 @@ MaybeObject* Heap::AllocateUninitializedFixedArray(int length) {
} }
MaybeObject* Heap::AllocateEmptyFixedDoubleArray() {
int size = FixedDoubleArray::SizeFor(0);
Object* result;
{ MaybeObject* maybe_result =
AllocateRaw(size, OLD_DATA_SPACE, OLD_DATA_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
// Initialize the object.
reinterpret_cast<FixedDoubleArray*>(result)->set_map(
fixed_double_array_map());
reinterpret_cast<FixedDoubleArray*>(result)->set_length(0);
return result;
}
MaybeObject* Heap::AllocateUninitializedFixedDoubleArray(
int length,
PretenureFlag pretenure) {
if (length == 0) return empty_fixed_double_array();
Object* obj;
{ MaybeObject* maybe_obj = AllocateRawFixedDoubleArray(length, pretenure);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
reinterpret_cast<FixedDoubleArray*>(obj)->set_map(fixed_double_array_map());
FixedDoubleArray::cast(obj)->set_length(length);
return obj;
}
MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
PretenureFlag pretenure) {
if (length < 0 || length > FixedDoubleArray::kMaxLength) {
return Failure::OutOfMemoryException();
}
AllocationSpace space =
(pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
int size = FixedDoubleArray::SizeFor(length);
if (space == NEW_SPACE && size > kMaxObjectSizeInNewSpace) {
// Too big for new space.
space = LO_SPACE;
} else if (space == OLD_DATA_SPACE &&
size > MaxObjectSizeInPagedSpace()) {
// Too big for old data space.
space = LO_SPACE;
}
AllocationSpace retry_space =
(size <= MaxObjectSizeInPagedSpace()) ? OLD_DATA_SPACE : LO_SPACE;
return AllocateRaw(size, space, retry_space);
}
MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) { MaybeObject* Heap::AllocateHashTable(int length, PretenureFlag pretenure) {
Object* result; Object* result;
{ MaybeObject* maybe_result = AllocateFixedArray(length, pretenure); { MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
......
...@@ -66,6 +66,7 @@ inline Heap* _inline_get_heap_(); ...@@ -66,6 +66,7 @@ inline Heap* _inline_get_heap_();
V(Map, global_context_map, GlobalContextMap) \ V(Map, global_context_map, GlobalContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \ V(Map, fixed_array_map, FixedArrayMap) \
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \ V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \ V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
V(Map, meta_map, MetaMap) \ V(Map, meta_map, MetaMap) \
V(Map, hash_table_map, HashTableMap) \ V(Map, hash_table_map, HashTableMap) \
...@@ -78,6 +79,7 @@ inline Heap* _inline_get_heap_(); ...@@ -78,6 +79,7 @@ inline Heap* _inline_get_heap_();
V(Object, termination_exception, TerminationException) \ V(Object, termination_exception, TerminationException) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \ V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \ V(ByteArray, empty_byte_array, EmptyByteArray) \
V(FixedDoubleArray, empty_fixed_double_array, EmptyFixedDoubleArray) \
V(String, empty_string, EmptyString) \ V(String, empty_string, EmptyString) \
V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \ V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
V(Map, string_map, StringMap) \ V(Map, string_map, StringMap) \
...@@ -620,6 +622,17 @@ class Heap { ...@@ -620,6 +622,17 @@ class Heap {
int length, int length,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
MUST_USE_RESULT MaybeObject* AllocateRawFixedDoubleArray(
int length,
PretenureFlag pretenure);
// Allocates a fixed double array with uninitialized values. Returns
// Failure::RetryAfterGC(requested_bytes, space) if the allocation failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateUninitializedFixedDoubleArray(
int length,
PretenureFlag pretenure = NOT_TENURED);
// AllocateHashTable is identical to AllocateFixedArray except // AllocateHashTable is identical to AllocateFixedArray except
// that the resulting object has hash_table_map as map. // that the resulting object has hash_table_map as map.
MUST_USE_RESULT MaybeObject* AllocateHashTable( MUST_USE_RESULT MaybeObject* AllocateHashTable(
...@@ -1460,6 +1473,9 @@ class Heap { ...@@ -1460,6 +1473,9 @@ class Heap {
// Allocate empty fixed array. // Allocate empty fixed array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedArray(); MUST_USE_RESULT MaybeObject* AllocateEmptyFixedArray();
// Allocate empty fixed double array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedDoubleArray();
void SwitchScavengingVisitorsTableIfProfilingWasEnabled(); void SwitchScavengingVisitorsTableIfProfilingWasEnabled();
// Performs a minor collection in new generation. // Performs a minor collection in new generation.
......
...@@ -396,6 +396,8 @@ class StaticMarkingVisitor : public StaticVisitorBase { ...@@ -396,6 +396,8 @@ class StaticMarkingVisitor : public StaticVisitorBase {
FixedArray::BodyDescriptor, FixedArray::BodyDescriptor,
void>::Visit); void>::Visit);
table_.Register(kVisitFixedDoubleArray, DataObjectVisitor::Visit);
table_.Register(kVisitGlobalContext, table_.Register(kVisitGlobalContext,
&FixedBodyVisitor<StaticMarkingVisitor, &FixedBodyVisitor<StaticMarkingVisitor,
Context::MarkCompactBodyDescriptor, Context::MarkCompactBodyDescriptor,
......
...@@ -88,6 +88,9 @@ void HeapObject::HeapObjectVerify() { ...@@ -88,6 +88,9 @@ void HeapObject::HeapObjectVerify() {
case FIXED_ARRAY_TYPE: case FIXED_ARRAY_TYPE:
FixedArray::cast(this)->FixedArrayVerify(); FixedArray::cast(this)->FixedArrayVerify();
break; break;
case FIXED_DOUBLE_ARRAY_TYPE:
FixedDoubleArray::cast(this)->FixedDoubleArrayVerify();
break;
case BYTE_ARRAY_TYPE: case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayVerify(); ByteArray::cast(this)->ByteArrayVerify();
break; break;
...@@ -307,6 +310,17 @@ void FixedArray::FixedArrayVerify() { ...@@ -307,6 +310,17 @@ void FixedArray::FixedArrayVerify() {
} }
void FixedDoubleArray::FixedDoubleArrayVerify() {
for (int i = 0; i < length(); i++) {
if (!is_the_hole(i)) {
double value = get(i);
ASSERT(!isnan(value) ||
BitCast<uint64_t>(value) == kCanonicalNonHoleNanInt64);
}
}
}
void JSValue::JSValueVerify() { void JSValue::JSValueVerify() {
Object* v = value(); Object* v = value();
if (v->IsHeapObject()) { if (v->IsHeapObject()) {
...@@ -432,7 +446,9 @@ void Code::CodeVerify() { ...@@ -432,7 +446,9 @@ void Code::CodeVerify() {
void JSArray::JSArrayVerify() { void JSArray::JSArrayVerify() {
JSObjectVerify(); JSObjectVerify();
ASSERT(length()->IsNumber() || length()->IsUndefined()); ASSERT(length()->IsNumber() || length()->IsUndefined());
ASSERT(elements()->IsUndefined() || elements()->IsFixedArray()); ASSERT(elements()->IsUndefined() ||
elements()->IsFixedArray() ||
elements()->IsFixedDoubleArray());
} }
......
...@@ -217,6 +217,10 @@ bool Object::IsExternalTwoByteString() { ...@@ -217,6 +217,10 @@ bool Object::IsExternalTwoByteString() {
String::cast(this)->IsTwoByteRepresentation(); String::cast(this)->IsTwoByteRepresentation();
} }
bool Object::HasValidElements() {
// Dictionary is covered under FixedArray.
return IsFixedArray() || IsFixedDoubleArray() || IsExternalArray();
}
StringShape::StringShape(String* str) StringShape::StringShape(String* str)
: type_(str->map()->instance_type()) { : type_(str->map()->instance_type()) {
...@@ -489,6 +493,13 @@ bool Object::IsFixedArray() { ...@@ -489,6 +493,13 @@ bool Object::IsFixedArray() {
} }
bool Object::IsFixedDoubleArray() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() ==
FIXED_DOUBLE_ARRAY_TYPE;
}
bool Object::IsDescriptorArray() { bool Object::IsDescriptorArray() {
return IsFixedArray(); return IsFixedArray();
} }
...@@ -1318,8 +1329,7 @@ ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset) ...@@ -1318,8 +1329,7 @@ ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
HeapObject* JSObject::elements() { HeapObject* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset); Object* array = READ_FIELD(this, kElementsOffset);
// In the assert below Dictionary is covered under FixedArray. ASSERT(array->HasValidElements());
ASSERT(array->IsFixedArray() || array->IsExternalArray());
return reinterpret_cast<HeapObject*>(array); return reinterpret_cast<HeapObject*>(array);
} }
...@@ -1328,8 +1338,7 @@ void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) { ...@@ -1328,8 +1338,7 @@ void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) {
ASSERT(map()->has_fast_elements() == ASSERT(map()->has_fast_elements() ==
(value->map() == GetHeap()->fixed_array_map() || (value->map() == GetHeap()->fixed_array_map() ||
value->map() == GetHeap()->fixed_cow_array_map())); value->map() == GetHeap()->fixed_cow_array_map()));
// In the assert below Dictionary is covered under FixedArray. ASSERT(value->HasValidElements());
ASSERT(value->IsFixedArray() || value->IsExternalArray());
WRITE_FIELD(this, kElementsOffset, value); WRITE_FIELD(this, kElementsOffset, value);
CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, mode); CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, mode);
} }
...@@ -1577,6 +1586,12 @@ bool Object::IsStringObjectWithCharacterAt(uint32_t index) { ...@@ -1577,6 +1586,12 @@ bool Object::IsStringObjectWithCharacterAt(uint32_t index) {
} }
FixedArrayBase* FixedArrayBase::cast(Object* object) {
ASSERT(object->IsFixedArray() || object->IsFixedDoubleArray());
return reinterpret_cast<FixedArrayBase*>(object);
}
Object* FixedArray::get(int index) { Object* FixedArray::get(int index) {
ASSERT(index >= 0 && index < this->length()); ASSERT(index >= 0 && index < this->length());
return READ_FIELD(this, kHeaderSize + index * kPointerSize); return READ_FIELD(this, kHeaderSize + index * kPointerSize);
...@@ -1600,6 +1615,88 @@ void FixedArray::set(int index, Object* value) { ...@@ -1600,6 +1615,88 @@ void FixedArray::set(int index, Object* value) {
} }
double FixedDoubleArray::get(int index) {
ASSERT(map() != HEAP->fixed_cow_array_map() &&
map() != HEAP->fixed_array_map());
ASSERT(index >= 0 && index < this->length());
double result = READ_DOUBLE_FIELD(this, kHeaderSize + index * kDoubleSize);
ASSERT(!is_the_hole_nan(result));
return result;
}
void FixedDoubleArray::set(int index, double value) {
ASSERT(map() != HEAP->fixed_cow_array_map() &&
map() != HEAP->fixed_array_map());
int offset = kHeaderSize + index * kDoubleSize;
if (isnan(value)) value = canonical_not_the_hole_nan_as_double();
WRITE_DOUBLE_FIELD(this, offset, value);
}
void FixedDoubleArray::set_the_hole(int index) {
ASSERT(map() != HEAP->fixed_cow_array_map() &&
map() != HEAP->fixed_array_map());
int offset = kHeaderSize + index * kDoubleSize;
WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double());
}
bool FixedDoubleArray::is_the_hole(int index) {
int offset = kHeaderSize + index * kDoubleSize;
return is_the_hole_nan(READ_DOUBLE_FIELD(this, offset));
}
void FixedDoubleArray::Initialize(FixedDoubleArray* from) {
int old_length = from->length();
ASSERT(old_length < length());
OS::MemCopy(FIELD_ADDR(this, kHeaderSize),
FIELD_ADDR(from, kHeaderSize),
old_length * kDoubleSize);
int offset = kHeaderSize + old_length * kDoubleSize;
for (int current = from->length(); current < length(); ++current) {
WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double());
offset += kDoubleSize;
}
}
void FixedDoubleArray::Initialize(FixedArray* from) {
int old_length = from->length();
ASSERT(old_length < length());
for (int i = 0; i < old_length; i++) {
Object* hole_or_object = from->get(i);
if (hole_or_object->IsTheHole()) {
set_the_hole(i);
} else {
set(i, hole_or_object->Number());
}
}
int offset = kHeaderSize + old_length * kDoubleSize;
for (int current = from->length(); current < length(); ++current) {
WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double());
offset += kDoubleSize;
}
}
void FixedDoubleArray::Initialize(NumberDictionary* from) {
int offset = kHeaderSize;
for (int current = 0; current < length(); ++current) {
WRITE_DOUBLE_FIELD(this, offset, hole_nan_as_double());
offset += kDoubleSize;
}
for (int i = 0; i < from->Capacity(); i++) {
Object* key = from->KeyAt(i);
if (key->IsNumber()) {
uint32_t entry = static_cast<uint32_t>(key->Number());
set(entry, from->ValueAt(i)->Number());
}
}
}
WriteBarrierMode HeapObject::GetWriteBarrierMode(const AssertNoAllocation&) { WriteBarrierMode HeapObject::GetWriteBarrierMode(const AssertNoAllocation&) {
if (GetHeap()->InNewSpace(this)) return SKIP_WRITE_BARRIER; if (GetHeap()->InNewSpace(this)) return SKIP_WRITE_BARRIER;
return UPDATE_WRITE_BARRIER; return UPDATE_WRITE_BARRIER;
...@@ -1900,6 +1997,7 @@ void NumberDictionary::set_requires_slow_elements() { ...@@ -1900,6 +1997,7 @@ void NumberDictionary::set_requires_slow_elements() {
CAST_ACCESSOR(FixedArray) CAST_ACCESSOR(FixedArray)
CAST_ACCESSOR(FixedDoubleArray)
CAST_ACCESSOR(DescriptorArray) CAST_ACCESSOR(DescriptorArray)
CAST_ACCESSOR(DeoptimizationInputData) CAST_ACCESSOR(DeoptimizationInputData)
CAST_ACCESSOR(DeoptimizationOutputData) CAST_ACCESSOR(DeoptimizationOutputData)
...@@ -1964,7 +2062,7 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) { ...@@ -1964,7 +2062,7 @@ HashTable<Shape, Key>* HashTable<Shape, Key>::cast(Object* obj) {
} }
SMI_ACCESSORS(FixedArray, length, kLengthOffset) SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
SMI_ACCESSORS(ByteArray, length, kLengthOffset) SMI_ACCESSORS(ByteArray, length, kLengthOffset)
INT_ACCESSORS(ExternalArray, length, kLengthOffset) INT_ACCESSORS(ExternalArray, length, kLengthOffset)
...@@ -2423,6 +2521,10 @@ int HeapObject::SizeFromMap(Map* map) { ...@@ -2423,6 +2521,10 @@ int HeapObject::SizeFromMap(Map* map) {
return SeqTwoByteString::SizeFor( return SeqTwoByteString::SizeFor(
reinterpret_cast<SeqTwoByteString*>(this)->length()); reinterpret_cast<SeqTwoByteString*>(this)->length());
} }
if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
return FixedDoubleArray::SizeFor(
reinterpret_cast<FixedDoubleArray*>(this)->length());
}
ASSERT(instance_type == CODE_TYPE); ASSERT(instance_type == CODE_TYPE);
return reinterpret_cast<Code*>(this)->CodeSize(); return reinterpret_cast<Code*>(this)->CodeSize();
} }
...@@ -2981,20 +3083,33 @@ MaybeObject* Map::GetFastElementsMap() { ...@@ -2981,20 +3083,33 @@ MaybeObject* Map::GetFastElementsMap() {
} }
Map* new_map = Map::cast(obj); Map* new_map = Map::cast(obj);
new_map->set_elements_kind(JSObject::FAST_ELEMENTS); new_map->set_elements_kind(JSObject::FAST_ELEMENTS);
isolate()->counters()->map_slow_to_fast_elements()->Increment(); isolate()->counters()->map_to_fast_elements()->Increment();
return new_map;
}
MaybeObject* Map::GetFastDoubleElementsMap() {
if (has_fast_double_elements()) return this;
Object* obj;
{ MaybeObject* maybe_obj = CopyDropTransitions();
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
Map* new_map = Map::cast(obj);
new_map->set_elements_kind(JSObject::FAST_DOUBLE_ELEMENTS);
isolate()->counters()->map_to_fast_double_elements()->Increment();
return new_map; return new_map;
} }
MaybeObject* Map::GetSlowElementsMap() { MaybeObject* Map::GetSlowElementsMap() {
if (!has_fast_elements()) return this; if (!has_fast_elements() && !has_fast_double_elements()) return this;
Object* obj; Object* obj;
{ MaybeObject* maybe_obj = CopyDropTransitions(); { MaybeObject* maybe_obj = CopyDropTransitions();
if (!maybe_obj->ToObject(&obj)) return maybe_obj; if (!maybe_obj->ToObject(&obj)) return maybe_obj;
} }
Map* new_map = Map::cast(obj); Map* new_map = Map::cast(obj);
new_map->set_elements_kind(JSObject::DICTIONARY_ELEMENTS); new_map->set_elements_kind(JSObject::DICTIONARY_ELEMENTS);
isolate()->counters()->map_fast_to_slow_elements()->Increment(); isolate()->counters()->map_to_slow_elements()->Increment();
return new_map; return new_map;
} }
...@@ -3788,6 +3903,8 @@ JSObject::ElementsKind JSObject::GetElementsKind() { ...@@ -3788,6 +3903,8 @@ JSObject::ElementsKind JSObject::GetElementsKind() {
ASSERT((kind == FAST_ELEMENTS && ASSERT((kind == FAST_ELEMENTS &&
(elements()->map() == GetHeap()->fixed_array_map() || (elements()->map() == GetHeap()->fixed_array_map() ||
elements()->map() == GetHeap()->fixed_cow_array_map())) || elements()->map() == GetHeap()->fixed_cow_array_map())) ||
(kind == FAST_DOUBLE_ELEMENTS &&
elements()->IsFixedDoubleArray()) ||
(kind == DICTIONARY_ELEMENTS && (kind == DICTIONARY_ELEMENTS &&
elements()->IsFixedArray() && elements()->IsFixedArray() &&
elements()->IsDictionary()) || elements()->IsDictionary()) ||
...@@ -3801,6 +3918,11 @@ bool JSObject::HasFastElements() { ...@@ -3801,6 +3918,11 @@ bool JSObject::HasFastElements() {
} }
bool JSObject::HasFastDoubleElements() {
return GetElementsKind() == FAST_DOUBLE_ELEMENTS;
}
bool JSObject::HasDictionaryElements() { bool JSObject::HasDictionaryElements() {
return GetElementsKind() == DICTIONARY_ELEMENTS; return GetElementsKind() == DICTIONARY_ELEMENTS;
} }
......
// Copyright 2009 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -73,6 +73,9 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( ...@@ -73,6 +73,9 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case FIXED_ARRAY_TYPE: case FIXED_ARRAY_TYPE:
return kVisitFixedArray; return kVisitFixedArray;
case FIXED_DOUBLE_ARRAY_TYPE:
return kVisitFixedDoubleArray;
case ODDBALL_TYPE: case ODDBALL_TYPE:
return kVisitOddball; return kVisitOddball;
......
// Copyright 2006-2009 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 // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -52,6 +52,7 @@ class StaticVisitorBase : public AllStatic { ...@@ -52,6 +52,7 @@ class StaticVisitorBase : public AllStatic {
kVisitShortcutCandidate, kVisitShortcutCandidate,
kVisitByteArray, kVisitByteArray,
kVisitFixedArray, kVisitFixedArray,
kVisitFixedDoubleArray,
kVisitGlobalContext, kVisitGlobalContext,
// For data objects, JS objects and structs along with generic visitor which // For data objects, JS objects and structs along with generic visitor which
...@@ -285,6 +286,8 @@ class StaticNewSpaceVisitor : public StaticVisitorBase { ...@@ -285,6 +286,8 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
FixedArray::BodyDescriptor, FixedArray::BodyDescriptor,
int>::Visit); int>::Visit);
table_.Register(kVisitFixedDoubleArray, &VisitFixedDoubleArray);
table_.Register(kVisitGlobalContext, table_.Register(kVisitGlobalContext,
&FixedBodyVisitor<StaticVisitor, &FixedBodyVisitor<StaticVisitor,
Context::ScavengeBodyDescriptor, Context::ScavengeBodyDescriptor,
...@@ -329,6 +332,11 @@ class StaticNewSpaceVisitor : public StaticVisitorBase { ...@@ -329,6 +332,11 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
return reinterpret_cast<ByteArray*>(object)->ByteArraySize(); return reinterpret_cast<ByteArray*>(object)->ByteArraySize();
} }
static inline int VisitFixedDoubleArray(Map* map, HeapObject* object) {
int length = reinterpret_cast<FixedDoubleArray*>(object)->length();
return FixedDoubleArray::SizeFor(length);
}
static inline int VisitSeqAsciiString(Map* map, HeapObject* object) { static inline int VisitSeqAsciiString(Map* map, HeapObject* object) {
return SeqAsciiString::cast(object)-> return SeqAsciiString::cast(object)->
SeqAsciiStringSize(map->instance_type()); SeqAsciiStringSize(map->instance_type());
......
This diff is collapsed.
...@@ -533,6 +533,7 @@ enum InstanceType { ...@@ -533,6 +533,7 @@ enum InstanceType {
EXTERNAL_FLOAT_ARRAY_TYPE, EXTERNAL_FLOAT_ARRAY_TYPE,
EXTERNAL_DOUBLE_ARRAY_TYPE, EXTERNAL_DOUBLE_ARRAY_TYPE,
EXTERNAL_PIXEL_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE EXTERNAL_PIXEL_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
FIXED_DOUBLE_ARRAY_TYPE,
FILLER_TYPE, // LAST_DATA_TYPE FILLER_TYPE, // LAST_DATA_TYPE
// Structs. // Structs.
...@@ -732,6 +733,7 @@ class MaybeObject BASE_EMBEDDED { ...@@ -732,6 +733,7 @@ class MaybeObject BASE_EMBEDDED {
V(DeoptimizationInputData) \ V(DeoptimizationInputData) \
V(DeoptimizationOutputData) \ V(DeoptimizationOutputData) \
V(FixedArray) \ V(FixedArray) \
V(FixedDoubleArray) \
V(Context) \ V(Context) \
V(CatchContext) \ V(CatchContext) \
V(GlobalContext) \ V(GlobalContext) \
...@@ -800,6 +802,10 @@ class Object : public MaybeObject { ...@@ -800,6 +802,10 @@ class Object : public MaybeObject {
// Extract the number. // Extract the number.
inline double Number(); inline double Number();
// Returns true if the object is of the correct type to be used as a
// implementation of a JSObject's elements.
inline bool HasValidElements();
inline bool HasSpecificClassOf(String* name); inline bool HasSpecificClassOf(String* name);
MUST_USE_RESULT MaybeObject* ToObject(); // ECMA-262 9.9. MUST_USE_RESULT MaybeObject* ToObject(); // ECMA-262 9.9.
...@@ -1427,6 +1433,10 @@ class JSObject: public JSReceiver { ...@@ -1427,6 +1433,10 @@ class JSObject: public JSReceiver {
// The "fast" kind for tagged values. Must be first to make it possible // The "fast" kind for tagged values. Must be first to make it possible
// to efficiently check maps if they have fast elements. // to efficiently check maps if they have fast elements.
FAST_ELEMENTS, FAST_ELEMENTS,
// The "fast" kind for unwrapped, non-tagged double values.
FAST_DOUBLE_ELEMENTS,
// The "slow" kind. // The "slow" kind.
DICTIONARY_ELEMENTS, DICTIONARY_ELEMENTS,
// The "fast" kind for external arrays // The "fast" kind for external arrays
...@@ -1478,6 +1488,7 @@ class JSObject: public JSReceiver { ...@@ -1478,6 +1488,7 @@ class JSObject: public JSReceiver {
MUST_USE_RESULT inline MaybeObject* ResetElements(); MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind(); inline ElementsKind GetElementsKind();
inline bool HasFastElements(); inline bool HasFastElements();
inline bool HasFastDoubleElements();
inline bool HasDictionaryElements(); inline bool HasDictionaryElements();
inline bool HasExternalPixelElements(); inline bool HasExternalPixelElements();
inline bool HasExternalArrayElements(); inline bool HasExternalArrayElements();
...@@ -1637,6 +1648,9 @@ class JSObject: public JSReceiver { ...@@ -1637,6 +1648,9 @@ class JSObject: public JSReceiver {
// storage would. In that case the JSObject should have fast // storage would. In that case the JSObject should have fast
// elements. // elements.
bool ShouldConvertToFastElements(); bool ShouldConvertToFastElements();
// Returns true if the elements of JSObject contains only values that can be
// represented in a FixedDoubleArray.
bool ShouldConvertToFastDoubleElements();
// Tells whether the index'th element is present. // Tells whether the index'th element is present.
inline bool HasElement(uint32_t index); inline bool HasElement(uint32_t index);
...@@ -1676,6 +1690,12 @@ class JSObject: public JSReceiver { ...@@ -1676,6 +1690,12 @@ class JSObject: public JSReceiver {
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
bool check_prototype = true); bool check_prototype = true);
MUST_USE_RESULT MaybeObject* SetFastDoubleElement(
uint32_t index,
Object* value,
StrictModeFlag strict_mode,
bool check_prototype = true);
// Set the index'th array element. // Set the index'th array element.
// A Failure object is returned if GC is needed. // A Failure object is returned if GC is needed.
MUST_USE_RESULT MaybeObject* SetElement(uint32_t index, MUST_USE_RESULT MaybeObject* SetElement(uint32_t index,
...@@ -1695,6 +1715,9 @@ class JSObject: public JSReceiver { ...@@ -1695,6 +1715,9 @@ class JSObject: public JSReceiver {
MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength(int capacity, MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength(int capacity,
int length); int length);
MUST_USE_RESULT MaybeObject* SetFastDoubleElementsCapacityAndLength(
int capacity,
int length);
MUST_USE_RESULT MaybeObject* SetSlowElements(Object* length); MUST_USE_RESULT MaybeObject* SetSlowElements(Object* length);
// Lookup interceptors are used for handling properties controlled by host // Lookup interceptors are used for handling properties controlled by host
...@@ -1986,13 +2009,26 @@ class JSObject: public JSReceiver { ...@@ -1986,13 +2009,26 @@ class JSObject: public JSReceiver {
}; };
// FixedArray describes fixed-sized arrays with element type Object*. // Common superclass for FixedArrays that allow implementations to share
class FixedArray: public HeapObject { // common accessors and some code paths.
class FixedArrayBase: public HeapObject {
public: public:
// [length]: length of the array. // [length]: length of the array.
inline int length(); inline int length();
inline void set_length(int value); inline void set_length(int value);
inline static FixedArrayBase* cast(Object* object);
// Layout description.
// Length is smi tagged when it is stored.
static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kHeaderSize = kLengthOffset + kPointerSize;
};
// FixedArray describes fixed-sized arrays with element type Object*.
class FixedArray: public FixedArrayBase {
public:
// Setter and getter for elements. // Setter and getter for elements.
inline Object* get(int index); inline Object* get(int index);
// Setter that uses write barrier. // Setter that uses write barrier.
...@@ -2043,11 +2079,6 @@ class FixedArray: public HeapObject { ...@@ -2043,11 +2079,6 @@ class FixedArray: public HeapObject {
// Casting. // Casting.
static inline FixedArray* cast(Object* obj); static inline FixedArray* cast(Object* obj);
// Layout description.
// Length is smi tagged when it is stored.
static const int kLengthOffset = HeapObject::kHeaderSize;
static const int kHeaderSize = kLengthOffset + kPointerSize;
// Maximal allowed size, in bytes, of a single FixedArray. // Maximal allowed size, in bytes, of a single FixedArray.
// Prevents overflowing size computations, as well as extreme memory // Prevents overflowing size computations, as well as extreme memory
// consumption. // consumption.
...@@ -2095,6 +2126,71 @@ class FixedArray: public HeapObject { ...@@ -2095,6 +2126,71 @@ class FixedArray: public HeapObject {
}; };
// FixedDoubleArray describes fixed-sized arrays with element type double.
class FixedDoubleArray: public FixedArrayBase {
public:
inline void Initialize(FixedArray* from);
inline void Initialize(FixedDoubleArray* from);
inline void Initialize(NumberDictionary* from);
// Setter and getter for elements.
inline double get(int index);
inline void set(int index, double value);
inline void set_the_hole(int index);
// Checking for the hole.
inline bool is_the_hole(int index);
// Garbage collection support.
inline static int SizeFor(int length) {
return kHeaderSize + length * kDoubleSize;
}
// The following can't be declared inline as const static
// because they're 64-bit.
static uint64_t kCanonicalNonHoleNanLower32;
static uint64_t kCanonicalNonHoleNanInt64;
static uint64_t kHoleNanInt64;
inline static bool is_the_hole_nan(double value) {
return BitCast<uint64_t, double>(value) == kHoleNanInt64;
}
inline static double hole_nan_as_double() {
return BitCast<double, uint64_t>(kHoleNanInt64);
}
inline static double canonical_not_the_hole_nan_as_double() {
return BitCast<double, uint64_t>(kCanonicalNonHoleNanInt64);
}
// Casting.
static inline FixedDoubleArray* cast(Object* obj);
// Maximal allowed size, in bytes, of a single FixedDoubleArray.
// Prevents overflowing size computations, as well as extreme memory
// consumption.
static const int kMaxSize = 512 * MB;
// Maximally allowed length of a FixedArray.
static const int kMaxLength = (kMaxSize - kHeaderSize) / kDoubleSize;
// Dispatched behavior.
#ifdef OBJECT_PRINT
inline void FixedDoubleArrayPrint() {
FixedDoubleArrayPrint(stdout);
}
void FixedDoubleArrayPrint(FILE* out);
#endif
#ifdef DEBUG
void FixedDoubleArrayVerify();
#endif
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(FixedDoubleArray);
};
// DescriptorArrays are fixed arrays used to hold instance descriptors. // DescriptorArrays are fixed arrays used to hold instance descriptors.
// The format of the these objects is: // The format of the these objects is:
// TODO(1399): It should be possible to make room for bit_field3 in the map // TODO(1399): It should be possible to make room for bit_field3 in the map
...@@ -3809,6 +3905,10 @@ class Map: public HeapObject { ...@@ -3809,6 +3905,10 @@ class Map: public HeapObject {
return elements_kind() == JSObject::FAST_ELEMENTS; return elements_kind() == JSObject::FAST_ELEMENTS;
} }
inline bool has_fast_double_elements() {
return elements_kind() == JSObject::FAST_DOUBLE_ELEMENTS;
}
inline bool has_external_array_elements() { inline bool has_external_array_elements() {
JSObject::ElementsKind kind(elements_kind()); JSObject::ElementsKind kind(elements_kind());
return kind >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && return kind >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
...@@ -3901,18 +4001,23 @@ class Map: public HeapObject { ...@@ -3901,18 +4001,23 @@ class Map: public HeapObject {
// instance descriptors. // instance descriptors.
MUST_USE_RESULT MaybeObject* CopyDropTransitions(); MUST_USE_RESULT MaybeObject* CopyDropTransitions();
// Returns this map if it has the fast elements bit set, otherwise // Returns this map if it already has elements that are fast, otherwise
// returns a copy of the map, with all transitions dropped from the // returns a copy of the map, with all transitions dropped from the
// descriptors and the fast elements bit set. // descriptors and the ElementsKind set to FAST_ELEMENTS.
MUST_USE_RESULT inline MaybeObject* GetFastElementsMap(); MUST_USE_RESULT inline MaybeObject* GetFastElementsMap();
// Returns this map if it has the fast elements bit cleared, // Returns this map if it already has fast elements that are doubles,
// otherwise returns a copy of the map, with all transitions dropped // otherwise returns a copy of the map, with all transitions dropped from the
// from the descriptors and the fast elements bit cleared. // descriptors and the ElementsKind set to FAST_DOUBLE_ELEMENTS.
MUST_USE_RESULT inline MaybeObject* GetFastDoubleElementsMap();
// Returns this map if already has dictionary elements, otherwise returns a
// copy of the map, with all transitions dropped from the descriptors and the
// ElementsKind set to DICTIONARY_ELEMENTS.
MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap(); MUST_USE_RESULT inline MaybeObject* GetSlowElementsMap();
// Returns a new map with all transitions dropped from the descriptors and the // Returns a new map with all transitions dropped from the descriptors and the
// external array elements bit set. // ElementsKind set to one of the value corresponding to array_type.
MUST_USE_RESULT MaybeObject* GetExternalArrayElementsMap( MUST_USE_RESULT MaybeObject* GetExternalArrayElementsMap(
ExternalArrayType array_type, ExternalArrayType array_type,
bool safe_to_add_transition); bool safe_to_add_transition);
......
...@@ -3070,7 +3070,7 @@ void LargeObjectSpace::Verify() { ...@@ -3070,7 +3070,7 @@ void LargeObjectSpace::Verify() {
// strings), fixed arrays, and byte arrays in large object space. // strings), fixed arrays, and byte arrays in large object space.
ASSERT(object->IsCode() || object->IsSeqString() || ASSERT(object->IsCode() || object->IsSeqString() ||
object->IsExternalString() || object->IsFixedArray() || object->IsExternalString() || object->IsFixedArray() ||
object->IsByteArray()); object->IsFixedDoubleArray() || object->IsByteArray());
// The object itself should look OK. // The object itself should look OK.
object->Verify(); object->Verify();
......
...@@ -126,8 +126,9 @@ namespace internal { ...@@ -126,8 +126,9 @@ namespace internal {
V8.GCCompactorCausedByWeakHandles) \ V8.GCCompactorCausedByWeakHandles) \
SC(gc_last_resort_from_js, V8.GCLastResortFromJS) \ SC(gc_last_resort_from_js, V8.GCLastResortFromJS) \
SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \ SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \
SC(map_slow_to_fast_elements, V8.MapSlowToFastElements) \ SC(map_to_fast_elements, V8.MapToFastElements) \
SC(map_fast_to_slow_elements, V8.MapFastToSlowElements) \ SC(map_to_fast_double_elements, V8.MapToFastDoubleElements) \
SC(map_to_slow_elements, V8.MapToSlowElements) \
SC(map_to_external_array_elements, V8.MapToExternalArrayElements) \ SC(map_to_external_array_elements, V8.MapToExternalArrayElements) \
/* How is the generic keyed-load stub used? */ \ /* How is the generic keyed-load stub used? */ \
SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \ SC(keyed_load_generic_smi, V8.KeyedLoadGenericSmi) \
......
// 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:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test dictionary -> double elements -> dictionary elements round trip
var foo = new Array(500000);
function func(a) {
for (var i= 0; i < 100000; ++i ) {
a[i] = i+0.5;
}
}
func(foo);
for (var i= 0; i < 100000; i += 500 ) {
assertEquals(i+0.5, foo[i]);
}
delete foo[5];
// Don't use assertEquals for comparison to undefined due to
assertTrue(undefined === foo[5]);
assertTrue(undefined === foo[500000-1]);
assertTrue(undefined === foo[-1]);
assertEquals(500000, foo.length);
// Cause the array to grow beyond it's JSArray length. This will double the
// size of the capacity and force the array into "slow" dictionary case.
foo[500001] = 50;
assertEquals(50, foo[500001]);
assertEquals(500002, foo.length);
assertTrue(undefined === foo[5])
assertTrue(undefined === foo[500000-1])
assertTrue(undefined === foo[-1])
assertEquals(500002, foo.length);
// Test dictionary -> double elements -> fast elements.
var foo2 = new Array(500000);
func(foo2);
delete foo2[5];
// Convert back to fast elements and make sure the contents of the array are
// unchanged.
foo2[25] = new Object();
for (var i= 0; i < 100000; i += 500 ) {
if (i != 25 && i != 5) {
assertEquals(i+0.5, foo2[i]);
}
}
assertTrue(undefined === foo2[5])
assertTrue(undefined === foo2[500000-1])
assertTrue(undefined === foo2[-1])
assertEquals(500000, foo2.length);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment