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 {
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
static const int kJSObjectType = 0xa2;
static const int kJSObjectType = 0xa3;
static const int kFirstNonstringType = 0x80;
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
// modification, are permitted provided that the following conditions are
// met:
......@@ -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) {
ASSERT(0 <= at_least_space_for);
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
// modification, are permitted provided that the following conditions are
// met:
......@@ -39,7 +39,7 @@ namespace internal {
class Factory {
public:
// Allocate a new fixed array with undefined entries.
// Allocate a new uninitialized fixed array.
Handle<FixedArray> NewFixedArray(
int size,
PretenureFlag pretenure = NOT_TENURED);
......@@ -49,6 +49,11 @@ class Factory {
int size,
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<StringDictionary> NewStringDictionary(int at_least_space_for);
......
......@@ -99,6 +99,9 @@ private:
// Flags for experimental language features.
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.
#ifdef V8_TARGET_ARCH_MIPS
DEFINE_bool(crankshaft, false, "use crankshaft")
......
......@@ -1286,6 +1286,7 @@ class ScavengingVisitor : public StaticVisitorBase {
table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate);
table_.Register(kVisitByteArray, &EvacuateByteArray);
table_.Register(kVisitFixedArray, &EvacuateFixedArray);
table_.Register(kVisitFixedDoubleArray, &EvacuateFixedDoubleArray);
table_.Register(kVisitGlobalContext,
&ObjectEvacuationStrategy<POINTER_OBJECT>::
......@@ -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,
HeapObject** slot,
HeapObject* object) {
......@@ -1771,6 +1784,12 @@ bool Heap::CreateInitialMaps() {
set_undetectable_ascii_string_map(Map::cast(obj));
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 =
AllocateMap(BYTE_ARRAY_TYPE, kVariableSizeSentinel);
if (!maybe_obj->ToObject(&obj)) return false;
......@@ -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) {
Object* result;
{ MaybeObject* maybe_result = AllocateFixedArray(length, pretenure);
......
......@@ -66,6 +66,7 @@ inline Heap* _inline_get_heap_();
V(Map, global_context_map, GlobalContextMap) \
V(Map, fixed_array_map, FixedArrayMap) \
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
V(Map, meta_map, MetaMap) \
V(Map, hash_table_map, HashTableMap) \
......@@ -78,6 +79,7 @@ inline Heap* _inline_get_heap_();
V(Object, termination_exception, TerminationException) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ByteArray, empty_byte_array, EmptyByteArray) \
V(FixedDoubleArray, empty_fixed_double_array, EmptyFixedDoubleArray) \
V(String, empty_string, EmptyString) \
V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
V(Map, string_map, StringMap) \
......@@ -620,6 +622,17 @@ class Heap {
int length,
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
// that the resulting object has hash_table_map as map.
MUST_USE_RESULT MaybeObject* AllocateHashTable(
......@@ -1460,6 +1473,9 @@ class Heap {
// Allocate empty fixed array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedArray();
// Allocate empty fixed double array.
MUST_USE_RESULT MaybeObject* AllocateEmptyFixedDoubleArray();
void SwitchScavengingVisitorsTableIfProfilingWasEnabled();
// Performs a minor collection in new generation.
......
......@@ -396,6 +396,8 @@ class StaticMarkingVisitor : public StaticVisitorBase {
FixedArray::BodyDescriptor,
void>::Visit);
table_.Register(kVisitFixedDoubleArray, DataObjectVisitor::Visit);
table_.Register(kVisitGlobalContext,
&FixedBodyVisitor<StaticMarkingVisitor,
Context::MarkCompactBodyDescriptor,
......
......@@ -88,6 +88,9 @@ void HeapObject::HeapObjectVerify() {
case FIXED_ARRAY_TYPE:
FixedArray::cast(this)->FixedArrayVerify();
break;
case FIXED_DOUBLE_ARRAY_TYPE:
FixedDoubleArray::cast(this)->FixedDoubleArrayVerify();
break;
case BYTE_ARRAY_TYPE:
ByteArray::cast(this)->ByteArrayVerify();
break;
......@@ -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() {
Object* v = value();
if (v->IsHeapObject()) {
......@@ -432,7 +446,9 @@ void Code::CodeVerify() {
void JSArray::JSArrayVerify() {
JSObjectVerify();
ASSERT(length()->IsNumber() || length()->IsUndefined());
ASSERT(elements()->IsUndefined() || elements()->IsFixedArray());
ASSERT(elements()->IsUndefined() ||
elements()->IsFixedArray() ||
elements()->IsFixedDoubleArray());
}
......
......@@ -217,6 +217,10 @@ bool Object::IsExternalTwoByteString() {
String::cast(this)->IsTwoByteRepresentation();
}
bool Object::HasValidElements() {
// Dictionary is covered under FixedArray.
return IsFixedArray() || IsFixedDoubleArray() || IsExternalArray();
}
StringShape::StringShape(String* str)
: type_(str->map()->instance_type()) {
......@@ -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() {
return IsFixedArray();
}
......@@ -1318,8 +1329,7 @@ ACCESSORS(JSObject, properties, FixedArray, kPropertiesOffset)
HeapObject* JSObject::elements() {
Object* array = READ_FIELD(this, kElementsOffset);
// In the assert below Dictionary is covered under FixedArray.
ASSERT(array->IsFixedArray() || array->IsExternalArray());
ASSERT(array->HasValidElements());
return reinterpret_cast<HeapObject*>(array);
}
......@@ -1328,8 +1338,7 @@ void JSObject::set_elements(HeapObject* value, WriteBarrierMode mode) {
ASSERT(map()->has_fast_elements() ==
(value->map() == GetHeap()->fixed_array_map() ||
value->map() == GetHeap()->fixed_cow_array_map()));
// In the assert below Dictionary is covered under FixedArray.
ASSERT(value->IsFixedArray() || value->IsExternalArray());
ASSERT(value->HasValidElements());
WRITE_FIELD(this, kElementsOffset, value);
CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, mode);
}
......@@ -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) {
ASSERT(index >= 0 && index < this->length());
return READ_FIELD(this, kHeaderSize + index * kPointerSize);
......@@ -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&) {
if (GetHeap()->InNewSpace(this)) return SKIP_WRITE_BARRIER;
return UPDATE_WRITE_BARRIER;
......@@ -1900,6 +1997,7 @@ void NumberDictionary::set_requires_slow_elements() {
CAST_ACCESSOR(FixedArray)
CAST_ACCESSOR(FixedDoubleArray)
CAST_ACCESSOR(DescriptorArray)
CAST_ACCESSOR(DeoptimizationInputData)
CAST_ACCESSOR(DeoptimizationOutputData)
......@@ -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)
INT_ACCESSORS(ExternalArray, length, kLengthOffset)
......@@ -2423,6 +2521,10 @@ int HeapObject::SizeFromMap(Map* map) {
return SeqTwoByteString::SizeFor(
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);
return reinterpret_cast<Code*>(this)->CodeSize();
}
......@@ -2981,20 +3083,33 @@ MaybeObject* Map::GetFastElementsMap() {
}
Map* new_map = Map::cast(obj);
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;
}
MaybeObject* Map::GetSlowElementsMap() {
if (!has_fast_elements()) return this;
if (!has_fast_elements() && !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::DICTIONARY_ELEMENTS);
isolate()->counters()->map_fast_to_slow_elements()->Increment();
isolate()->counters()->map_to_slow_elements()->Increment();
return new_map;
}
......@@ -3788,6 +3903,8 @@ JSObject::ElementsKind JSObject::GetElementsKind() {
ASSERT((kind == FAST_ELEMENTS &&
(elements()->map() == GetHeap()->fixed_array_map() ||
elements()->map() == GetHeap()->fixed_cow_array_map())) ||
(kind == FAST_DOUBLE_ELEMENTS &&
elements()->IsFixedDoubleArray()) ||
(kind == DICTIONARY_ELEMENTS &&
elements()->IsFixedArray() &&
elements()->IsDictionary()) ||
......@@ -3801,6 +3918,11 @@ bool JSObject::HasFastElements() {
}
bool JSObject::HasFastDoubleElements() {
return GetElementsKind() == FAST_DOUBLE_ELEMENTS;
}
bool JSObject::HasDictionaryElements() {
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
// modification, are permitted provided that the following conditions are
// met:
......@@ -73,6 +73,9 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case FIXED_ARRAY_TYPE:
return kVisitFixedArray;
case FIXED_DOUBLE_ARRAY_TYPE:
return kVisitFixedDoubleArray;
case ODDBALL_TYPE:
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
// modification, are permitted provided that the following conditions are
// met:
......@@ -52,6 +52,7 @@ class StaticVisitorBase : public AllStatic {
kVisitShortcutCandidate,
kVisitByteArray,
kVisitFixedArray,
kVisitFixedDoubleArray,
kVisitGlobalContext,
// For data objects, JS objects and structs along with generic visitor which
......@@ -285,6 +286,8 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
FixedArray::BodyDescriptor,
int>::Visit);
table_.Register(kVisitFixedDoubleArray, &VisitFixedDoubleArray);
table_.Register(kVisitGlobalContext,
&FixedBodyVisitor<StaticVisitor,
Context::ScavengeBodyDescriptor,
......@@ -329,6 +332,11 @@ class StaticNewSpaceVisitor : public StaticVisitorBase {
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) {
return SeqAsciiString::cast(object)->
SeqAsciiStringSize(map->instance_type());
......
This diff is collapsed.
......@@ -533,6 +533,7 @@ enum InstanceType {
EXTERNAL_FLOAT_ARRAY_TYPE,
EXTERNAL_DOUBLE_ARRAY_TYPE,
EXTERNAL_PIXEL_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE
FIXED_DOUBLE_ARRAY_TYPE,
FILLER_TYPE, // LAST_DATA_TYPE
// Structs.
......@@ -732,6 +733,7 @@ class MaybeObject BASE_EMBEDDED {
V(DeoptimizationInputData) \
V(DeoptimizationOutputData) \
V(FixedArray) \
V(FixedDoubleArray) \
V(Context) \
V(CatchContext) \
V(GlobalContext) \
......@@ -800,6 +802,10 @@ class Object : public MaybeObject {
// Extract the 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);
MUST_USE_RESULT MaybeObject* ToObject(); // ECMA-262 9.9.
......@@ -1427,6 +1433,10 @@ class JSObject: public JSReceiver {
// The "fast" kind for tagged values. Must be first to make it possible
// to efficiently check maps if they have fast elements.
FAST_ELEMENTS,
// The "fast" kind for unwrapped, non-tagged double values.
FAST_DOUBLE_ELEMENTS,
// The "slow" kind.
DICTIONARY_ELEMENTS,
// The "fast" kind for external arrays
......@@ -1478,6 +1488,7 @@ class JSObject: public JSReceiver {
MUST_USE_RESULT inline MaybeObject* ResetElements();
inline ElementsKind GetElementsKind();
inline bool HasFastElements();
inline bool HasFastDoubleElements();
inline bool HasDictionaryElements();
inline bool HasExternalPixelElements();
inline bool HasExternalArrayElements();
......@@ -1637,6 +1648,9 @@ class JSObject: public JSReceiver {
// storage would. In that case the JSObject should have fast
// elements.
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.
inline bool HasElement(uint32_t index);
......@@ -1676,6 +1690,12 @@ class JSObject: public JSReceiver {
StrictModeFlag strict_mode,
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.
// A Failure object is returned if GC is needed.
MUST_USE_RESULT MaybeObject* SetElement(uint32_t index,
......@@ -1695,6 +1715,9 @@ class JSObject: public JSReceiver {
MUST_USE_RESULT MaybeObject* SetFastElementsCapacityAndLength(int capacity,
int length);
MUST_USE_RESULT MaybeObject* SetFastDoubleElementsCapacityAndLength(
int capacity,
int length);
MUST_USE_RESULT MaybeObject* SetSlowElements(Object* length);
// Lookup interceptors are used for handling properties controlled by host
......@@ -1986,13 +2009,26 @@ class JSObject: public JSReceiver {
};
// FixedArray describes fixed-sized arrays with element type Object*.
class FixedArray: public HeapObject {
// Common superclass for FixedArrays that allow implementations to share
// common accessors and some code paths.
class FixedArrayBase: public HeapObject {
public:
// [length]: length of the array.
inline int length();
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.
inline Object* get(int index);
// Setter that uses write barrier.
......@@ -2043,11 +2079,6 @@ class FixedArray: public HeapObject {
// Casting.
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.
// Prevents overflowing size computations, as well as extreme memory
// consumption.
......@@ -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.
// The format of the these objects is:
// TODO(1399): It should be possible to make room for bit_field3 in the map
......@@ -3809,6 +3905,10 @@ class Map: public HeapObject {
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() {
JSObject::ElementsKind kind(elements_kind());
return kind >= JSObject::FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
......@@ -3901,18 +4001,23 @@ class Map: public HeapObject {
// instance descriptors.
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
// descriptors and the fast elements bit set.
// descriptors and the ElementsKind set to FAST_ELEMENTS.
MUST_USE_RESULT inline MaybeObject* GetFastElementsMap();
// Returns this map if it has the fast elements bit cleared,
// otherwise returns a copy of the map, with all transitions dropped
// from the descriptors and 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 from the
// 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();
// 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(
ExternalArrayType array_type,
bool safe_to_add_transition);
......
......@@ -3070,7 +3070,7 @@ void LargeObjectSpace::Verify() {
// strings), fixed arrays, and byte arrays in large object space.
ASSERT(object->IsCode() || object->IsSeqString() ||
object->IsExternalString() || object->IsFixedArray() ||
object->IsByteArray());
object->IsFixedDoubleArray() || object->IsByteArray());
// The object itself should look OK.
object->Verify();
......
......@@ -126,8 +126,9 @@ namespace internal {
V8.GCCompactorCausedByWeakHandles) \
SC(gc_last_resort_from_js, V8.GCLastResortFromJS) \
SC(gc_last_resort_from_handles, V8.GCLastResortFromHandles) \
SC(map_slow_to_fast_elements, V8.MapSlowToFastElements) \
SC(map_fast_to_slow_elements, V8.MapFastToSlowElements) \
SC(map_to_fast_elements, V8.MapToFastElements) \
SC(map_to_fast_double_elements, V8.MapToFastDoubleElements) \
SC(map_to_slow_elements, V8.MapToSlowElements) \
SC(map_to_external_array_elements, V8.MapToExternalArrayElements) \
/* How is the generic keyed-load stub used? */ \
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