Index: src/objects-inl.h |
=================================================================== |
--- src/objects-inl.h (revision 9531) |
+++ src/objects-inl.h (working copy) |
@@ -43,8 +43,11 @@ |
#include "isolate.h" |
#include "property.h" |
#include "spaces.h" |
+#include "store-buffer.h" |
#include "v8memory.h" |
+#include "incremental-marking.h" |
+ |
namespace v8 { |
namespace internal { |
@@ -80,19 +83,10 @@ |
type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \ |
void holder::set_##name(type* value, WriteBarrierMode mode) { \ |
WRITE_FIELD(this, offset, value); \ |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, mode); \ |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, value, mode); \ |
} |
-// GC-safe accessors do not use HeapObject::GetHeap(), but access TLS instead. |
-#define ACCESSORS_GCSAFE(holder, name, type, offset) \ |
- type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \ |
- void holder::set_##name(type* value, WriteBarrierMode mode) { \ |
- WRITE_FIELD(this, offset, value); \ |
- CONDITIONAL_WRITE_BARRIER(HEAP, this, offset, mode); \ |
- } |
- |
- |
#define SMI_ACCESSORS(holder, name, offset) \ |
int holder::name() { \ |
Object* value = READ_FIELD(this, offset); \ |
@@ -147,6 +141,12 @@ |
} |
+bool Object::NonFailureIsHeapObject() { |
+ ASSERT(!this->IsFailure()); |
+ return (reinterpret_cast<intptr_t>(this) & kSmiTagMask) != 0; |
+} |
+ |
+ |
bool Object::IsHeapNumber() { |
return Object::IsHeapObject() |
&& HeapObject::cast(this)->map()->instance_type() == HEAP_NUMBER_TYPE; |
@@ -165,6 +165,13 @@ |
} |
+bool Object::IsSpecFunction() { |
+ if (!Object::IsHeapObject()) return false; |
+ InstanceType type = HeapObject::cast(this)->map()->instance_type(); |
+ return type == JS_FUNCTION_TYPE || type == JS_FUNCTION_PROXY_TYPE; |
+} |
+ |
+ |
bool Object::IsSymbol() { |
if (!this->IsHeapObject()) return false; |
uint32_t type = HeapObject::cast(this)->map()->instance_type(); |
@@ -402,6 +409,19 @@ |
} |
+bool Object::IsFreeSpace() { |
+ return Object::IsHeapObject() |
+ && HeapObject::cast(this)->map()->instance_type() == FREE_SPACE_TYPE; |
+} |
+ |
+ |
+bool Object::IsFiller() { |
+ if (!Object::IsHeapObject()) return false; |
+ InstanceType instance_type = HeapObject::cast(this)->map()->instance_type(); |
+ return instance_type == FREE_SPACE_TYPE || instance_type == FILLER_TYPE; |
+} |
+ |
+ |
bool Object::IsExternalPixelArray() { |
return Object::IsHeapObject() && |
HeapObject::cast(this)->map()->instance_type() == |
@@ -509,20 +529,23 @@ |
bool Object::IsJSReceiver() { |
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
return IsHeapObject() && |
HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_RECEIVER_TYPE; |
} |
bool Object::IsJSObject() { |
- return IsJSReceiver() && !IsJSProxy(); |
+ STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); |
+ return IsHeapObject() && |
+ HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE; |
} |
bool Object::IsJSProxy() { |
- return Object::IsHeapObject() && |
- (HeapObject::cast(this)->map()->instance_type() == JS_PROXY_TYPE || |
- HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_PROXY_TYPE); |
+ if (!Object::IsHeapObject()) return false; |
+ InstanceType type = HeapObject::cast(this)->map()->instance_type(); |
+ return FIRST_JS_PROXY_TYPE <= type && type <= LAST_JS_PROXY_TYPE; |
} |
@@ -642,7 +665,6 @@ |
bool Object::IsOddball() { |
- ASSERT(HEAP->is_safe_to_read_maps()); |
return Object::IsHeapObject() |
&& HeapObject::cast(this)->map()->instance_type() == ODDBALL_TYPE; |
} |
@@ -939,21 +961,20 @@ |
#define WRITE_FIELD(p, offset, value) \ |
(*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value) |
-// TODO(isolates): Pass heap in to these macros. |
-#define WRITE_BARRIER(object, offset) \ |
- object->GetHeap()->RecordWrite(object->address(), offset); |
+#define WRITE_BARRIER(heap, object, offset, value) \ |
+ heap->incremental_marking()->RecordWrite( \ |
+ object, HeapObject::RawField(object, offset), value); \ |
+ if (heap->InNewSpace(value)) { \ |
+ heap->RecordWrite(object->address(), offset); \ |
+ } |
-// CONDITIONAL_WRITE_BARRIER must be issued after the actual |
-// write due to the assert validating the written value. |
-#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, mode) \ |
- if (mode == UPDATE_WRITE_BARRIER) { \ |
- heap->RecordWrite(object->address(), offset); \ |
- } else { \ |
- ASSERT(mode == SKIP_WRITE_BARRIER); \ |
- ASSERT(heap->InNewSpace(object) || \ |
- !heap->InNewSpace(READ_FIELD(object, offset)) || \ |
- Page::FromAddress(object->address())-> \ |
- IsRegionDirty(object->address() + offset)); \ |
+#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, value, mode) \ |
+ if (mode == UPDATE_WRITE_BARRIER) { \ |
+ heap->incremental_marking()->RecordWrite( \ |
+ object, HeapObject::RawField(object, offset), value); \ |
+ if (heap->InNewSpace(value)) { \ |
+ heap->RecordWrite(object->address(), offset); \ |
+ } \ |
} |
#ifndef V8_TARGET_ARCH_MIPS |
@@ -974,7 +995,6 @@ |
#define READ_DOUBLE_FIELD(p, offset) read_double_field(p, offset) |
#endif // V8_TARGET_ARCH_MIPS |
- |
#ifndef V8_TARGET_ARCH_MIPS |
#define WRITE_DOUBLE_FIELD(p, offset, value) \ |
(*reinterpret_cast<double*>(FIELD_ADDR(p, offset)) = value) |
@@ -1169,91 +1189,6 @@ |
} |
-bool MapWord::IsMarked() { |
- return (value_ & kMarkingMask) == 0; |
-} |
- |
- |
-void MapWord::SetMark() { |
- value_ &= ~kMarkingMask; |
-} |
- |
- |
-void MapWord::ClearMark() { |
- value_ |= kMarkingMask; |
-} |
- |
- |
-bool MapWord::IsOverflowed() { |
- return (value_ & kOverflowMask) != 0; |
-} |
- |
- |
-void MapWord::SetOverflow() { |
- value_ |= kOverflowMask; |
-} |
- |
- |
-void MapWord::ClearOverflow() { |
- value_ &= ~kOverflowMask; |
-} |
- |
- |
-MapWord MapWord::EncodeAddress(Address map_address, int offset) { |
- // Offset is the distance in live bytes from the first live object in the |
- // same page. The offset between two objects in the same page should not |
- // exceed the object area size of a page. |
- ASSERT(0 <= offset && offset < Page::kObjectAreaSize); |
- |
- uintptr_t compact_offset = offset >> kObjectAlignmentBits; |
- ASSERT(compact_offset < (1 << kForwardingOffsetBits)); |
- |
- Page* map_page = Page::FromAddress(map_address); |
- ASSERT_MAP_PAGE_INDEX(map_page->mc_page_index); |
- |
- uintptr_t map_page_offset = |
- map_page->Offset(map_address) >> kMapAlignmentBits; |
- |
- uintptr_t encoding = |
- (compact_offset << kForwardingOffsetShift) | |
- (map_page_offset << kMapPageOffsetShift) | |
- (map_page->mc_page_index << kMapPageIndexShift); |
- return MapWord(encoding); |
-} |
- |
- |
-Address MapWord::DecodeMapAddress(MapSpace* map_space) { |
- int map_page_index = |
- static_cast<int>((value_ & kMapPageIndexMask) >> kMapPageIndexShift); |
- ASSERT_MAP_PAGE_INDEX(map_page_index); |
- |
- int map_page_offset = static_cast<int>( |
- ((value_ & kMapPageOffsetMask) >> kMapPageOffsetShift) << |
- kMapAlignmentBits); |
- |
- return (map_space->PageAddress(map_page_index) + map_page_offset); |
-} |
- |
- |
-int MapWord::DecodeOffset() { |
- // The offset field is represented in the kForwardingOffsetBits |
- // most-significant bits. |
- uintptr_t offset = (value_ >> kForwardingOffsetShift) << kObjectAlignmentBits; |
- ASSERT(offset < static_cast<uintptr_t>(Page::kObjectAreaSize)); |
- return static_cast<int>(offset); |
-} |
- |
- |
-MapWord MapWord::FromEncodedAddress(Address address) { |
- return MapWord(reinterpret_cast<uintptr_t>(address)); |
-} |
- |
- |
-Address MapWord::ToEncodedAddress() { |
- return reinterpret_cast<Address>(value_); |
-} |
- |
- |
#ifdef DEBUG |
void HeapObject::VerifyObjectField(int offset) { |
VerifyPointer(READ_FIELD(this, offset)); |
@@ -1266,12 +1201,11 @@ |
Heap* HeapObject::GetHeap() { |
- // During GC, the map pointer in HeapObject is used in various ways that |
- // prevent us from retrieving Heap from the map. |
- // Assert that we are not in GC, implement GC code in a way that it doesn't |
- // pull heap from the map. |
- ASSERT(HEAP->is_safe_to_read_maps()); |
- return map()->heap(); |
+ Heap* heap = |
+ MemoryChunk::FromAddress(reinterpret_cast<Address>(this))->heap(); |
+ ASSERT(heap != NULL); |
+ ASSERT(heap->isolate() == Isolate::Current()); |
+ return heap; |
} |
@@ -1287,9 +1221,20 @@ |
void HeapObject::set_map(Map* value) { |
set_map_word(MapWord::FromMap(value)); |
+ if (value != NULL) { |
+ // TODO(1600) We are passing NULL as a slot because maps can never be on |
+ // evacuation candidate. |
+ value->GetHeap()->incremental_marking()->RecordWrite(this, NULL, value); |
+ } |
} |
+// Unsafe accessor omitting write barrier. |
+void HeapObject::set_map_unsafe(Map* value) { |
+ set_map_word(MapWord::FromMap(value)); |
+} |
+ |
+ |
MapWord HeapObject::map_word() { |
return MapWord(reinterpret_cast<uintptr_t>(READ_FIELD(this, kMapOffset))); |
} |
@@ -1329,47 +1274,6 @@ |
} |
-bool HeapObject::IsMarked() { |
- return map_word().IsMarked(); |
-} |
- |
- |
-void HeapObject::SetMark() { |
- ASSERT(!IsMarked()); |
- MapWord first_word = map_word(); |
- first_word.SetMark(); |
- set_map_word(first_word); |
-} |
- |
- |
-void HeapObject::ClearMark() { |
- ASSERT(IsMarked()); |
- MapWord first_word = map_word(); |
- first_word.ClearMark(); |
- set_map_word(first_word); |
-} |
- |
- |
-bool HeapObject::IsOverflowed() { |
- return map_word().IsOverflowed(); |
-} |
- |
- |
-void HeapObject::SetOverflow() { |
- MapWord first_word = map_word(); |
- first_word.SetOverflow(); |
- set_map_word(first_word); |
-} |
- |
- |
-void HeapObject::ClearOverflow() { |
- ASSERT(IsOverflowed()); |
- MapWord first_word = map_word(); |
- first_word.ClearOverflow(); |
- set_map_word(first_word); |
-} |
- |
- |
double HeapNumber::value() { |
return READ_DOUBLE_FIELD(this, kValueOffset); |
} |
@@ -1400,16 +1304,84 @@ |
return static_cast<FixedArrayBase*>(array); |
} |
+void JSObject::ValidateSmiOnlyElements() { |
+#if DEBUG |
+ if (FLAG_smi_only_arrays && |
+ map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS) { |
+ Heap* heap = GetHeap(); |
+ // Don't use elements, since integrity checks will fail if there |
+ // are filler pointers in the array. |
+ FixedArray* fixed_array = |
+ reinterpret_cast<FixedArray*>(READ_FIELD(this, kElementsOffset)); |
+ Map* map = fixed_array->map(); |
+ // Arrays that have been shifted in place can't be verified. |
+ if (map != heap->raw_unchecked_one_pointer_filler_map() && |
+ map != heap->raw_unchecked_two_pointer_filler_map() && |
+ map != heap->free_space_map()) { |
+ for (int i = 0; i < fixed_array->length(); i++) { |
+ Object* current = fixed_array->get(i); |
+ ASSERT(current->IsSmi() || current == heap->the_hole_value()); |
+ } |
+ } |
+ } |
+#endif |
+} |
+ |
+MaybeObject* JSObject::EnsureCanContainNonSmiElements() { |
+#if DEBUG |
+ ValidateSmiOnlyElements(); |
+#endif |
+ if (FLAG_smi_only_arrays && |
+ (map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS)) { |
+ Object* obj; |
+ MaybeObject* maybe_obj = GetElementsTransitionMap(FAST_ELEMENTS); |
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
+ set_map(Map::cast(obj)); |
+ } |
+ return this; |
+} |
+ |
+ |
+MaybeObject* JSObject::EnsureCanContainElements(Object** objects, |
+ uint32_t count) { |
+ if (FLAG_smi_only_arrays && |
+ map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS) { |
+ for (uint32_t i = 0; i < count; ++i) { |
+ Object* current = *objects++; |
+ if (!current->IsSmi() && current != GetHeap()->the_hole_value()) { |
+ return EnsureCanContainNonSmiElements(); |
+ } |
+ } |
+ } |
+ return this; |
+} |
+ |
+ |
+MaybeObject* JSObject::EnsureCanContainElements(FixedArray* elements) { |
+ if (FLAG_smi_only_arrays) { |
+ Object** objects = reinterpret_cast<Object**>( |
+ FIELD_ADDR(elements, elements->OffsetOfElementAt(0))); |
+ return EnsureCanContainElements(objects, elements->length()); |
+ } else { |
+ return this; |
+ } |
+} |
+ |
+ |
void JSObject::set_elements(FixedArrayBase* value, WriteBarrierMode mode) { |
- ASSERT(map()->has_fast_elements() == |
+ ASSERT((map()->has_fast_elements() || |
+ map()->has_fast_smi_only_elements()) == |
(value->map() == GetHeap()->fixed_array_map() || |
value->map() == GetHeap()->fixed_cow_array_map())); |
ASSERT(map()->has_fast_double_elements() == |
value->IsFixedDoubleArray()); |
ASSERT(value->HasValidElements()); |
+#ifdef DEBUG |
+ ValidateSmiOnlyElements(); |
+#endif |
WRITE_FIELD(this, kElementsOffset, value); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, mode); |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kElementsOffset, value, mode); |
} |
@@ -1420,7 +1392,7 @@ |
void JSObject::initialize_elements() { |
- ASSERT(map()->has_fast_elements()); |
+ ASSERT(map()->has_fast_elements() || map()->has_fast_smi_only_elements()); |
ASSERT(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array())); |
WRITE_FIELD(this, kElementsOffset, GetHeap()->empty_fixed_array()); |
} |
@@ -1428,9 +1400,11 @@ |
MaybeObject* JSObject::ResetElements() { |
Object* obj; |
- { MaybeObject* maybe_obj = map()->GetFastElementsMap(); |
- if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
- } |
+ ElementsKind elements_kind = FLAG_smi_only_arrays |
+ ? FAST_SMI_ONLY_ELEMENTS |
+ : FAST_ELEMENTS; |
+ MaybeObject* maybe_obj = GetElementsTransitionMap(elements_kind); |
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
set_map(Map::cast(obj)); |
initialize_elements(); |
return this; |
@@ -1442,12 +1416,12 @@ |
byte Oddball::kind() { |
- return READ_BYTE_FIELD(this, kKindOffset); |
+ return Smi::cast(READ_FIELD(this, kKindOffset))->value(); |
} |
void Oddball::set_kind(byte value) { |
- WRITE_BYTE_FIELD(this, kKindOffset, value); |
+ WRITE_FIELD(this, kKindOffset, Smi::FromInt(value)); |
} |
@@ -1460,6 +1434,8 @@ |
// The write barrier is not used for global property cells. |
ASSERT(!val->IsJSGlobalPropertyCell()); |
WRITE_FIELD(this, kValueOffset, val); |
+ GetHeap()->incremental_marking()->RecordWrite( |
+ this, HeapObject::RawField(this, kValueOffset), val); |
} |
@@ -1528,7 +1504,7 @@ |
// to adjust the index here. |
int offset = GetHeaderSize() + (kPointerSize * index); |
WRITE_FIELD(this, offset, value); |
- WRITE_BARRIER(this, offset); |
+ WRITE_BARRIER(GetHeap(), this, offset, value); |
} |
@@ -1554,7 +1530,7 @@ |
if (index < 0) { |
int offset = map()->instance_size() + (index * kPointerSize); |
WRITE_FIELD(this, offset, value); |
- WRITE_BARRIER(this, offset); |
+ WRITE_BARRIER(GetHeap(), this, offset, value); |
} else { |
ASSERT(index < properties()->length()); |
properties()->set(index, value); |
@@ -1588,17 +1564,33 @@ |
ASSERT(index < 0); |
int offset = map()->instance_size() + (index * kPointerSize); |
WRITE_FIELD(this, offset, value); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, mode); |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, value, mode); |
return value; |
} |
-void JSObject::InitializeBody(int object_size, Object* value) { |
- ASSERT(!value->IsHeapObject() || !GetHeap()->InNewSpace(value)); |
- for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) { |
- WRITE_FIELD(this, offset, value); |
+void JSObject::InitializeBody(Map* map, |
+ Object* pre_allocated_value, |
+ Object* filler_value) { |
+ ASSERT(!filler_value->IsHeapObject() || |
+ !GetHeap()->InNewSpace(filler_value)); |
+ ASSERT(!pre_allocated_value->IsHeapObject() || |
+ !GetHeap()->InNewSpace(pre_allocated_value)); |
+ int size = map->instance_size(); |
+ int offset = kHeaderSize; |
+ if (filler_value != pre_allocated_value) { |
+ int pre_allocated = map->pre_allocated_property_fields(); |
+ ASSERT(pre_allocated * kPointerSize + kHeaderSize <= size); |
+ for (int i = 0; i < pre_allocated; i++) { |
+ WRITE_FIELD(this, offset, pre_allocated_value); |
+ offset += kPointerSize; |
+ } |
} |
+ while (offset < size) { |
+ WRITE_FIELD(this, offset, filler_value); |
+ offset += kPointerSize; |
+ } |
} |
@@ -1683,7 +1675,7 @@ |
ASSERT(index >= 0 && index < this->length()); |
int offset = kHeaderSize + index * kPointerSize; |
WRITE_FIELD(this, offset, value); |
- WRITE_BARRIER(this, offset); |
+ WRITE_BARRIER(GetHeap(), this, offset, value); |
} |
@@ -1768,7 +1760,7 @@ |
void FixedDoubleArray::Initialize(FixedArray* from) { |
int old_length = from->length(); |
- ASSERT(old_length < 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()) { |
@@ -1802,7 +1794,9 @@ |
WriteBarrierMode HeapObject::GetWriteBarrierMode(const AssertNoAllocation&) { |
- if (GetHeap()->InNewSpace(this)) return SKIP_WRITE_BARRIER; |
+ Heap* heap = GetHeap(); |
+ if (heap->incremental_marking()->IsMarking()) return UPDATE_WRITE_BARRIER; |
+ if (heap->InNewSpace(this)) return SKIP_WRITE_BARRIER; |
return UPDATE_WRITE_BARRIER; |
} |
@@ -1814,7 +1808,7 @@ |
ASSERT(index >= 0 && index < this->length()); |
int offset = kHeaderSize + index * kPointerSize; |
WRITE_FIELD(this, offset, value); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, mode); |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, value, mode); |
} |
@@ -1823,6 +1817,10 @@ |
ASSERT(index >= 0 && index < array->length()); |
ASSERT(!HEAP->InNewSpace(value)); |
WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value); |
+ array->GetHeap()->incremental_marking()->RecordWrite( |
+ array, |
+ HeapObject::RawField(array, kHeaderSize + index * kPointerSize), |
+ value); |
} |
@@ -1875,7 +1873,7 @@ |
WriteBarrierMode mode) { |
int offset = kHeaderSize + index * kPointerSize; |
WRITE_FIELD(this, offset, value); |
- CONDITIONAL_WRITE_BARRIER(heap, this, offset, mode); |
+ CONDITIONAL_WRITE_BARRIER(heap, this, offset, value, mode); |
} |
@@ -2154,6 +2152,7 @@ |
CAST_ACCESSOR(JSWeakMap) |
CAST_ACCESSOR(Foreign) |
CAST_ACCESSOR(ByteArray) |
+CAST_ACCESSOR(FreeSpace) |
CAST_ACCESSOR(ExternalArray) |
CAST_ACCESSOR(ExternalByteArray) |
CAST_ACCESSOR(ExternalUnsignedByteArray) |
@@ -2180,6 +2179,7 @@ |
SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) |
+SMI_ACCESSORS(FreeSpace, size, kSizeOffset) |
SMI_ACCESSORS(String, length, kLengthOffset) |
@@ -2336,7 +2336,7 @@ |
void SlicedString::set_parent(String* parent) { |
- ASSERT(parent->IsSeqString()); |
+ ASSERT(parent->IsSeqString() || parent->IsExternalString()); |
WRITE_FIELD(this, kParentOffset, parent); |
} |
@@ -2356,7 +2356,7 @@ |
void ConsString::set_first(String* value, WriteBarrierMode mode) { |
WRITE_FIELD(this, kFirstOffset, value); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kFirstOffset, mode); |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kFirstOffset, value, mode); |
} |
@@ -2372,29 +2372,31 @@ |
void ConsString::set_second(String* value, WriteBarrierMode mode) { |
WRITE_FIELD(this, kSecondOffset, value); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kSecondOffset, mode); |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kSecondOffset, value, mode); |
} |
-ExternalAsciiString::Resource* ExternalAsciiString::resource() { |
+const ExternalAsciiString::Resource* ExternalAsciiString::resource() { |
return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)); |
} |
void ExternalAsciiString::set_resource( |
- ExternalAsciiString::Resource* resource) { |
- *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource; |
+ const ExternalAsciiString::Resource* resource) { |
+ *reinterpret_cast<const Resource**>( |
+ FIELD_ADDR(this, kResourceOffset)) = resource; |
} |
-ExternalTwoByteString::Resource* ExternalTwoByteString::resource() { |
+const ExternalTwoByteString::Resource* ExternalTwoByteString::resource() { |
return *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)); |
} |
void ExternalTwoByteString::set_resource( |
- ExternalTwoByteString::Resource* resource) { |
- *reinterpret_cast<Resource**>(FIELD_ADDR(this, kResourceOffset)) = resource; |
+ const ExternalTwoByteString::Resource* resource) { |
+ *reinterpret_cast<const Resource**>( |
+ FIELD_ADDR(this, kResourceOffset)) = resource; |
} |
@@ -2694,6 +2696,9 @@ |
if (instance_type == BYTE_ARRAY_TYPE) { |
return reinterpret_cast<ByteArray*>(this)->ByteArraySize(); |
} |
+ if (instance_type == FREE_SPACE_TYPE) { |
+ return reinterpret_cast<FreeSpace*>(this)->size(); |
+ } |
if (instance_type == STRING_TYPE) { |
return SeqTwoByteString::SizeFor( |
reinterpret_cast<SeqTwoByteString*>(this)->length()); |
@@ -2855,12 +2860,6 @@ |
} |
-FixedArray* Map::unchecked_prototype_transitions() { |
- return reinterpret_cast<FixedArray*>( |
- READ_FIELD(this, kPrototypeTransitionsOffset)); |
-} |
- |
- |
Code::Flags Code::flags() { |
return static_cast<Flags>(READ_INT_FIELD(this, kFlagsOffset)); |
} |
@@ -2932,6 +2931,19 @@ |
} |
+bool Code::is_pregenerated() { |
+ return kind() == STUB && IsPregeneratedField::decode(flags()); |
+} |
+ |
+ |
+void Code::set_is_pregenerated(bool value) { |
+ ASSERT(kind() == STUB); |
+ Flags f = flags(); |
+ f = static_cast<Flags>(IsPregeneratedField::update(f, value)); |
+ set_flags(f); |
+} |
+ |
+ |
bool Code::optimizable() { |
ASSERT(kind() == FUNCTION); |
return READ_BYTE_FIELD(this, kOptimizableOffset) == 1; |
@@ -3097,6 +3109,19 @@ |
WRITE_BYTE_FIELD(this, kToBooleanTypeOffset, value); |
} |
+ |
+bool Code::has_function_cache() { |
+ ASSERT(kind() == STUB); |
+ return READ_BYTE_FIELD(this, kHasFunctionCacheOffset) != 0; |
+} |
+ |
+ |
+void Code::set_has_function_cache(bool flag) { |
+ ASSERT(kind() == STUB); |
+ WRITE_BYTE_FIELD(this, kHasFunctionCacheOffset, flag); |
+} |
+ |
+ |
bool Code::is_inline_cache_stub() { |
Kind kind = this->kind(); |
return kind >= FIRST_IC_KIND && kind <= LAST_IC_KIND; |
@@ -3182,48 +3207,6 @@ |
} |
-Isolate* Map::isolate() { |
- return heap()->isolate(); |
-} |
- |
- |
-Heap* Map::heap() { |
- // NOTE: address() helper is not used to save one instruction. |
- Heap* heap = Page::FromAddress(reinterpret_cast<Address>(this))->heap_; |
- ASSERT(heap != NULL); |
- ASSERT(heap->isolate() == Isolate::Current()); |
- return heap; |
-} |
- |
- |
-Heap* Code::heap() { |
- // NOTE: address() helper is not used to save one instruction. |
- Heap* heap = Page::FromAddress(reinterpret_cast<Address>(this))->heap_; |
- ASSERT(heap != NULL); |
- ASSERT(heap->isolate() == Isolate::Current()); |
- return heap; |
-} |
- |
- |
-Isolate* Code::isolate() { |
- return heap()->isolate(); |
-} |
- |
- |
-Heap* JSGlobalPropertyCell::heap() { |
- // NOTE: address() helper is not used to save one instruction. |
- Heap* heap = Page::FromAddress(reinterpret_cast<Address>(this))->heap_; |
- ASSERT(heap != NULL); |
- ASSERT(heap->isolate() == Isolate::Current()); |
- return heap; |
-} |
- |
- |
-Isolate* JSGlobalPropertyCell::isolate() { |
- return heap()->isolate(); |
-} |
- |
- |
Object* Code::GetObjectFromEntryAddress(Address location_of_address) { |
return HeapObject:: |
FromAddress(Memory::Address_at(location_of_address) - Code::kHeaderSize); |
@@ -3238,49 +3221,10 @@ |
void Map::set_prototype(Object* value, WriteBarrierMode mode) { |
ASSERT(value->IsNull() || value->IsJSReceiver()); |
WRITE_FIELD(this, kPrototypeOffset, value); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kPrototypeOffset, mode); |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kPrototypeOffset, value, mode); |
} |
-MaybeObject* Map::GetFastElementsMap() { |
- if (has_fast_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(FAST_ELEMENTS); |
- 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(FAST_DOUBLE_ELEMENTS); |
- isolate()->counters()->map_to_fast_double_elements()->Increment(); |
- return new_map; |
-} |
- |
- |
-MaybeObject* Map::GetSlowElementsMap() { |
- 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(DICTIONARY_ELEMENTS); |
- isolate()->counters()->map_to_slow_elements()->Increment(); |
- return new_map; |
-} |
- |
- |
DescriptorArray* Map::instance_descriptors() { |
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset); |
if (object->IsSmi()) { |
@@ -3312,7 +3256,8 @@ |
WriteBarrierMode mode) { |
Object* object = READ_FIELD(this, |
kInstanceDescriptorsOrBitField3Offset); |
- if (value == isolate()->heap()->empty_descriptor_array()) { |
+ Heap* heap = GetHeap(); |
+ if (value == heap->empty_descriptor_array()) { |
clear_instance_descriptors(); |
return; |
} else { |
@@ -3325,10 +3270,8 @@ |
} |
ASSERT(!is_shared()); |
WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, value); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), |
- this, |
- kInstanceDescriptorsOrBitField3Offset, |
- mode); |
+ CONDITIONAL_WRITE_BARRIER( |
+ heap, this, kInstanceDescriptorsOrBitField3Offset, value, mode); |
} |
@@ -3357,14 +3300,22 @@ |
} |
+FixedArray* Map::unchecked_prototype_transitions() { |
+ return reinterpret_cast<FixedArray*>( |
+ READ_FIELD(this, kPrototypeTransitionsOffset)); |
+} |
+ |
+ |
ACCESSORS(Map, code_cache, Object, kCodeCacheOffset) |
ACCESSORS(Map, prototype_transitions, FixedArray, kPrototypeTransitionsOffset) |
ACCESSORS(Map, constructor, Object, kConstructorOffset) |
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset) |
ACCESSORS(JSFunction, literals, FixedArray, kLiteralsOffset) |
-ACCESSORS_GCSAFE(JSFunction, next_function_link, Object, |
- kNextFunctionLinkOffset) |
+ACCESSORS(JSFunction, |
+ next_function_link, |
+ Object, |
+ kNextFunctionLinkOffset) |
ACCESSORS(GlobalObject, builtins, JSBuiltinsObject, kBuiltinsOffset) |
ACCESSORS(GlobalObject, global_context, Context, kGlobalContextOffset) |
@@ -3453,8 +3404,8 @@ |
#endif |
ACCESSORS(SharedFunctionInfo, name, Object, kNameOffset) |
-ACCESSORS_GCSAFE(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset) |
-ACCESSORS_GCSAFE(SharedFunctionInfo, initial_map, Object, kInitialMapOffset) |
+ACCESSORS(SharedFunctionInfo, construct_stub, Code, kConstructStubOffset) |
+ACCESSORS(SharedFunctionInfo, initial_map, Object, kInitialMapOffset) |
ACCESSORS(SharedFunctionInfo, instance_class_name, Object, |
kInstanceClassNameOffset) |
ACCESSORS(SharedFunctionInfo, function_data, Object, kFunctionDataOffset) |
@@ -3660,7 +3611,7 @@ |
void SharedFunctionInfo::set_code(Code* value, WriteBarrierMode mode) { |
WRITE_FIELD(this, kCodeOffset, value); |
- ASSERT(!Isolate::Current()->heap()->InNewSpace(value)); |
+ CONDITIONAL_WRITE_BARRIER(value->GetHeap(), this, kCodeOffset, value, mode); |
} |
@@ -3673,7 +3624,11 @@ |
void SharedFunctionInfo::set_scope_info(SerializedScopeInfo* value, |
WriteBarrierMode mode) { |
WRITE_FIELD(this, kScopeInfoOffset, reinterpret_cast<Object*>(value)); |
- CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kScopeInfoOffset, mode); |
+ CONDITIONAL_WRITE_BARRIER(GetHeap(), |
+ this, |
+ kScopeInfoOffset, |
+ reinterpret_cast<Object*>(value), |
+ mode); |
} |
@@ -3770,10 +3725,13 @@ |
void JSFunction::set_code(Code* value) { |
- // Skip the write barrier because code is never in new space. |
ASSERT(!HEAP->InNewSpace(value)); |
Address entry = value->entry(); |
WRITE_INTPTR_FIELD(this, kCodeEntryOffset, reinterpret_cast<intptr_t>(entry)); |
+ GetHeap()->incremental_marking()->RecordWriteOfCodeEntry( |
+ this, |
+ HeapObject::RawField(this, kCodeEntryOffset), |
+ value); |
} |
@@ -3813,7 +3771,7 @@ |
void JSFunction::set_context(Object* value) { |
ASSERT(value->IsUndefined() || value->IsContext()); |
WRITE_FIELD(this, kContextOffset, value); |
- WRITE_BARRIER(this, kContextOffset); |
+ WRITE_BARRIER(GetHeap(), this, kContextOffset, value); |
} |
ACCESSORS(JSFunction, prototype_or_initial_map, Object, |
@@ -3887,7 +3845,7 @@ |
Object* value) { |
ASSERT(id < kJSBuiltinsCount); // id is unsigned. |
WRITE_FIELD(this, OffsetOfFunctionWithId(id), value); |
- WRITE_BARRIER(this, OffsetOfFunctionWithId(id)); |
+ WRITE_BARRIER(GetHeap(), this, OffsetOfFunctionWithId(id), value); |
} |
@@ -3906,6 +3864,7 @@ |
ACCESSORS(JSProxy, handler, Object, kHandlerOffset) |
+ACCESSORS(JSProxy, hash, Object, kHashOffset) |
ACCESSORS(JSFunctionProxy, call_trap, Object, kCallTrapOffset) |
ACCESSORS(JSFunctionProxy, construct_trap, Object, kConstructTrapOffset) |
@@ -3918,8 +3877,8 @@ |
} |
-ACCESSORS(JSWeakMap, table, ObjectHashTable, kTableOffset) |
-ACCESSORS_GCSAFE(JSWeakMap, next, Object, kNextOffset) |
+ACCESSORS(JSWeakMap, table, Object, kTableOffset) |
+ACCESSORS(JSWeakMap, next, Object, kNextOffset) |
ObjectHashTable* JSWeakMap::unchecked_table() { |
@@ -4011,9 +3970,8 @@ |
} |
-bool Code::contains(byte* pc) { |
- return (instruction_start() <= pc) && |
- (pc <= instruction_start() + instruction_size()); |
+bool Code::contains(byte* inner_pointer) { |
+ return (address() <= inner_pointer) && (inner_pointer <= address() + Size()); |
} |
@@ -4092,6 +4050,7 @@ |
if (value->IsSmi()) { |
fa->set_unchecked(index, Smi::cast(value)); |
} else { |
+ // We only do this during GC, so we don't need to notify the write barrier. |
fa->set_unchecked(heap, index, value, SKIP_WRITE_BARRIER); |
} |
} |
@@ -4099,15 +4058,20 @@ |
ElementsKind JSObject::GetElementsKind() { |
ElementsKind kind = map()->elements_kind(); |
- ASSERT((kind == FAST_ELEMENTS && |
- (elements()->map() == GetHeap()->fixed_array_map() || |
- elements()->map() == GetHeap()->fixed_cow_array_map())) || |
+#if DEBUG |
+ FixedArrayBase* fixed_array = |
+ reinterpret_cast<FixedArrayBase*>(READ_FIELD(this, kElementsOffset)); |
+ Map* map = fixed_array->map(); |
+ ASSERT(((kind == FAST_ELEMENTS || kind == FAST_SMI_ONLY_ELEMENTS) && |
+ (map == GetHeap()->fixed_array_map() || |
+ map == GetHeap()->fixed_cow_array_map())) || |
(kind == FAST_DOUBLE_ELEMENTS && |
- elements()->IsFixedDoubleArray()) || |
+ fixed_array->IsFixedDoubleArray()) || |
(kind == DICTIONARY_ELEMENTS && |
- elements()->IsFixedArray() && |
- elements()->IsDictionary()) || |
+ fixed_array->IsFixedArray() && |
+ fixed_array->IsDictionary()) || |
(kind > DICTIONARY_ELEMENTS)); |
+#endif |
return kind; |
} |
@@ -4122,6 +4086,18 @@ |
} |
+bool JSObject::HasFastSmiOnlyElements() { |
+ return GetElementsKind() == FAST_SMI_ONLY_ELEMENTS; |
+} |
+ |
+ |
+bool JSObject::HasFastTypeElements() { |
+ ElementsKind elements_kind = GetElementsKind(); |
+ return elements_kind == FAST_SMI_ONLY_ELEMENTS || |
+ elements_kind == FAST_ELEMENTS; |
+} |
+ |
+ |
bool JSObject::HasFastDoubleElements() { |
return GetElementsKind() == FAST_DOUBLE_ELEMENTS; |
} |
@@ -4132,6 +4108,11 @@ |
} |
+bool JSObject::HasNonStrictArgumentsElements() { |
+ return GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS; |
+} |
+ |
+ |
bool JSObject::HasExternalArrayElements() { |
HeapObject* array = elements(); |
ASSERT(array != NULL); |
@@ -4183,7 +4164,7 @@ |
MaybeObject* JSObject::EnsureWritableFastElements() { |
- ASSERT(HasFastElements()); |
+ ASSERT(HasFastTypeElements()); |
FixedArray* elems = FixedArray::cast(elements()); |
Isolate* isolate = GetIsolate(); |
if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems; |
@@ -4359,47 +4340,21 @@ |
} |
-bool JSObject::HasHiddenPropertiesObject() { |
- ASSERT(!IsJSGlobalProxy()); |
- return GetPropertyAttributePostInterceptor(this, |
- GetHeap()->hidden_symbol(), |
- false) != ABSENT; |
+MaybeObject* JSReceiver::GetIdentityHash(CreationFlag flag) { |
+ return IsJSProxy() |
+ ? JSProxy::cast(this)->GetIdentityHash(flag) |
+ : JSObject::cast(this)->GetIdentityHash(flag); |
} |
-Object* JSObject::GetHiddenPropertiesObject() { |
- ASSERT(!IsJSGlobalProxy()); |
- PropertyAttributes attributes; |
- // You can't install a getter on a property indexed by the hidden symbol, |
- // so we can be sure that GetLocalPropertyPostInterceptor returns a real |
- // object. |
- Object* result = |
- GetLocalPropertyPostInterceptor(this, |
- GetHeap()->hidden_symbol(), |
- &attributes)->ToObjectUnchecked(); |
- return result; |
+bool JSReceiver::HasElement(uint32_t index) { |
+ if (IsJSProxy()) { |
+ return JSProxy::cast(this)->HasElementWithHandler(index); |
+ } |
+ return JSObject::cast(this)->HasElementWithReceiver(this, index); |
} |
-MaybeObject* JSObject::SetHiddenPropertiesObject(Object* hidden_obj) { |
- ASSERT(!IsJSGlobalProxy()); |
- return SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), |
- hidden_obj, |
- DONT_ENUM, |
- kNonStrictMode); |
-} |
- |
- |
-bool JSObject::HasHiddenProperties() { |
- return !GetHiddenProperties(OMIT_CREATION)->ToObjectChecked()->IsUndefined(); |
-} |
- |
- |
-bool JSObject::HasElement(uint32_t index) { |
- return HasElementWithReceiver(this, index); |
-} |
- |
- |
bool AccessorInfo::all_can_read() { |
return BooleanBit::get(flag(), kAllCanReadBit); |
} |
@@ -4508,27 +4463,27 @@ |
} |
-bool ObjectHashTableShape::IsMatch(JSObject* key, Object* other) { |
- return key == JSObject::cast(other); |
+bool ObjectHashTableShape::IsMatch(JSReceiver* key, Object* other) { |
+ return key == JSReceiver::cast(other); |
} |
-uint32_t ObjectHashTableShape::Hash(JSObject* key) { |
- MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION); |
+uint32_t ObjectHashTableShape::Hash(JSReceiver* key) { |
+ MaybeObject* maybe_hash = key->GetIdentityHash(OMIT_CREATION); |
ASSERT(!maybe_hash->IsFailure()); |
return Smi::cast(maybe_hash->ToObjectUnchecked())->value(); |
} |
-uint32_t ObjectHashTableShape::HashForObject(JSObject* key, Object* other) { |
- MaybeObject* maybe_hash = JSObject::cast(other)->GetIdentityHash( |
- JSObject::OMIT_CREATION); |
+uint32_t ObjectHashTableShape::HashForObject(JSReceiver* key, Object* other) { |
+ MaybeObject* maybe_hash = |
+ JSReceiver::cast(other)->GetIdentityHash(OMIT_CREATION); |
ASSERT(!maybe_hash->IsFailure()); |
return Smi::cast(maybe_hash->ToObjectUnchecked())->value(); |
} |
-MaybeObject* ObjectHashTableShape::AsObject(JSObject* key) { |
+MaybeObject* ObjectHashTableShape::AsObject(JSReceiver* key) { |
return key; |
} |
@@ -4548,7 +4503,7 @@ |
void JSArray::EnsureSize(int required_size) { |
- ASSERT(HasFastElements()); |
+ ASSERT(HasFastTypeElements()); |
FixedArray* elts = FixedArray::cast(elements()); |
const int kArraySizeThatFitsComfortablyInNewSpace = 128; |
if (elts->length() < required_size) { |
@@ -4566,13 +4521,17 @@ |
void JSArray::set_length(Smi* length) { |
+ // Don't need a write barrier for a Smi. |
set_length(static_cast<Object*>(length), SKIP_WRITE_BARRIER); |
} |
-void JSArray::SetContent(FixedArray* storage) { |
+MaybeObject* JSArray::SetContent(FixedArray* storage) { |
+ MaybeObject* maybe_object = EnsureCanContainElements(storage); |
+ if (maybe_object->IsFailure()) return maybe_object; |
set_length(Smi::FromInt(storage->length())); |
set_elements(storage); |
+ return this; |
} |