static FixedArrayBase* LeftTrimFixedArray(Heap* heap,
FixedArrayBase* elms,
int to_trim) {
+ ASSERT(heap->CanMoveObjectStart(elms));
+
Map* map = elms->map();
int entry_size;
if (elms->IsFixedArray()) {
// Technically in new space this write might be omitted (except for
// debug mode which iterates through the heap), but to play safer
// we still do it.
+ // Since left trimming is only performed on pages which are not concurrently
+ // swept creating a filler object does not require synchronization.
heap->CreateFillerObjectAt(elms->address(), to_trim * entry_size);
int new_start_index = to_trim * (entry_size / kPointerSize);
if (length == 0) {
array->initialize_elements();
} else {
- backing_store->set_length(length);
+ int filler_size = (old_capacity - length) * ElementSize;
Address filler_start = backing_store->address() +
BackingStore::OffsetOfElementAt(length);
- int filler_size = (old_capacity - length) * ElementSize;
array->GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
+
+ // We are storing the new length using release store after creating a
+ // filler for the left-over space to avoid races with the sweeper
+ // thread.
+ backing_store->synchronized_set_length(length);
}
} else {
// Otherwise, fill the unused tail with holes.
WRITE_FIELD(this, offset, Smi::FromInt(value)); \
}
+#define SYNCHRONIZED_SMI_ACCESSORS(holder, name, offset) \
+ int holder::synchronized_##name() { \
+ Object* value = ACQUIRE_READ_FIELD(this, offset); \
+ return Smi::cast(value)->value(); \
+ } \
+ void holder::synchronized_set_##name(int value) { \
+ RELEASE_WRITE_FIELD(this, offset, Smi::FromInt(value)); \
+ }
+
#define BOOL_GETTER(holder, field, name, offset) \
bool holder::name() { \
#define READ_FIELD(p, offset) \
(*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)))
+#define ACQUIRE_READ_FIELD(p, offset) \
+ reinterpret_cast<Object*>( \
+ Acquire_Load(reinterpret_cast<AtomicWord*>(FIELD_ADDR(p, offset))))
+
+#define NO_BARRIER_READ_FIELD(p, offset) \
+ reinterpret_cast<Object*>( \
+ NoBarrier_Load(reinterpret_cast<AtomicWord*>(FIELD_ADDR(p, offset))))
+
#define WRITE_FIELD(p, offset, value) \
(*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)
+#define RELEASE_WRITE_FIELD(p, offset, value) \
+ Release_Store(reinterpret_cast<AtomicWord*>(FIELD_ADDR(p, offset)), \
+ reinterpret_cast<AtomicWord>(value));
+
+#define NO_BARRIER_WRITE_FIELD(p, offset, value) \
+ NoBarrier_Store(reinterpret_cast<AtomicWord*>(FIELD_ADDR(p, offset)), \
+ reinterpret_cast<AtomicWord>(value));
+
#define WRITE_BARRIER(heap, object, offset, value) \
heap->incremental_marking()->RecordWrite( \
object, HeapObject::RawField(object, offset), value); \
}
+Map* HeapObject::synchronized_map() {
+ return synchronized_map_word().ToMap();
+}
+
+
+void HeapObject::synchronized_set_map(Map* value) {
+ synchronized_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_no_write_barrier(Map* value) {
set_map_word(MapWord::FromMap(value));
MapWord HeapObject::map_word() {
- return MapWord(reinterpret_cast<uintptr_t>(READ_FIELD(this, kMapOffset)));
+ return MapWord(
+ reinterpret_cast<uintptr_t>(NO_BARRIER_READ_FIELD(this, kMapOffset)));
}
void HeapObject::set_map_word(MapWord map_word) {
- // WRITE_FIELD does not invoke write barrier, but there is no need
- // here.
- WRITE_FIELD(this, kMapOffset, reinterpret_cast<Object*>(map_word.value_));
+ NO_BARRIER_WRITE_FIELD(
+ this, kMapOffset, reinterpret_cast<Object*>(map_word.value_));
+}
+
+
+MapWord HeapObject::synchronized_map_word() {
+ return MapWord(
+ reinterpret_cast<uintptr_t>(ACQUIRE_READ_FIELD(this, kMapOffset)));
+}
+
+
+void HeapObject::synchronized_set_map_word(MapWord map_word) {
+ RELEASE_WRITE_FIELD(
+ this, kMapOffset, reinterpret_cast<Object*>(map_word.value_));
}
SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
+SYNCHRONIZED_SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
+
SMI_ACCESSORS(FreeSpace, size, kSizeOffset)
SMI_ACCESSORS(String, length, kLengthOffset)
+SYNCHRONIZED_SMI_ACCESSORS(String, length, kLengthOffset)
uint32_t Name::hash_field() {
// In either case we resort to a short external string instead, omitting
// the field caching the address of the backing store. When we encounter
// short external strings in generated code, we need to bailout to runtime.
+ Map* new_map;
if (size < ExternalString::kSize ||
heap->old_pointer_space()->Contains(this)) {
- this->set_map_no_write_barrier(
- is_internalized
- ? (is_ascii
- ? heap->
- short_external_internalized_string_with_one_byte_data_map()
- : heap->short_external_internalized_string_map())
- : (is_ascii
- ? heap->short_external_string_with_one_byte_data_map()
- : heap->short_external_string_map()));
+ new_map = is_internalized
+ ? (is_ascii
+ ? heap->
+ short_external_internalized_string_with_one_byte_data_map()
+ : heap->short_external_internalized_string_map())
+ : (is_ascii
+ ? heap->short_external_string_with_one_byte_data_map()
+ : heap->short_external_string_map());
} else {
- this->set_map_no_write_barrier(
- is_internalized
- ? (is_ascii
- ? heap->external_internalized_string_with_one_byte_data_map()
- : heap->external_internalized_string_map())
- : (is_ascii
- ? heap->external_string_with_one_byte_data_map()
- : heap->external_string_map()));
+ new_map = is_internalized
+ ? (is_ascii
+ ? heap->external_internalized_string_with_one_byte_data_map()
+ : heap->external_internalized_string_map())
+ : (is_ascii
+ ? heap->external_string_with_one_byte_data_map()
+ : heap->external_string_map());
}
+
+ // Byte size of the external String object.
+ int new_size = this->SizeFromMap(new_map);
+ heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
+
+ // We are storing the new map using release store after creating a filler for
+ // the left-over space to avoid races with the sweeper thread.
+ this->synchronized_set_map(new_map);
+
ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
self->set_resource(resource);
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
- // Fill the remainder of the string with dead wood.
- int new_size = this->Size(); // Byte size of the external String object.
- heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
return true;
}
// In either case we resort to a short external string instead, omitting
// the field caching the address of the backing store. When we encounter
// short external strings in generated code, we need to bailout to runtime.
+ Map* new_map;
if (size < ExternalString::kSize ||
heap->old_pointer_space()->Contains(this)) {
- this->set_map_no_write_barrier(
- is_internalized ? heap->short_external_ascii_internalized_string_map()
- : heap->short_external_ascii_string_map());
+ new_map = is_internalized
+ ? heap->short_external_ascii_internalized_string_map()
+ : heap->short_external_ascii_string_map();
} else {
- this->set_map_no_write_barrier(
- is_internalized ? heap->external_ascii_internalized_string_map()
- : heap->external_ascii_string_map());
+ new_map = is_internalized
+ ? heap->external_ascii_internalized_string_map()
+ : heap->external_ascii_string_map();
}
+
+ // Byte size of the external String object.
+ int new_size = this->SizeFromMap(new_map);
+ heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
+
+ // We are storing the new map using release store after creating a filler for
+ // the left-over space to avoid races with the sweeper thread.
+ this->synchronized_set_map(new_map);
+
ExternalAsciiString* self = ExternalAsciiString::cast(this);
self->set_resource(resource);
if (is_internalized) self->Hash(); // Force regeneration of the hash value.
- // Fill the remainder of the string with dead wood.
- int new_size = this->Size(); // Byte size of the external String object.
- heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
return true;
}
// we still do it.
heap->CreateFillerObjectAt(new_end, size_delta);
- elms->set_length(len - to_trim);
+ // We are storing the new length using release store after creating a filler
+ // for the left-over space to avoid races with the sweeper thread.
+ elms->synchronized_set_length(len - to_trim);
heap->AdjustLiveBytes(elms->address(), -size_delta, mode);
// converted to doubles.
if (!old_map->InstancesNeedRewriting(
*new_map, number_of_fields, inobject, unused)) {
- object->set_map(*new_map);
+ // Writing the new map here does not require synchronization since it does
+ // not change the actual object size.
+ object->synchronized_set_map(*new_map);
return;
}
int instance_size_delta = old_map->instance_size() - new_instance_size;
ASSERT(instance_size_delta >= 0);
Address address = object->address() + new_instance_size;
+
+ // The trimming is performed on a newly allocated object, which is on a
+ // fresly allocated page or on an already swept page. Hence, the sweeper
+ // thread can not get confused with the filler creation. No synchronization
+ // needed.
isolate->heap()->CreateFillerObjectAt(address, instance_size_delta);
// If there are properties in the new backing store, trim it to the correct
object->set_properties(*array);
}
+ // The trimming is performed on a newly allocated object, which is on a
+ // fresly allocated page or on an already swept page. Hence, the sweeper
+ // thread can not get confused with the filler creation. No synchronization
+ // needed.
object->set_map(*new_map);
}
-instance_size_delta,
Heap::FROM_MUTATOR);
- object->set_map(*new_map);
+ // We are storing the new map using release store after creating a filler for
+ // the left-over space to avoid races with the sweeper thread.
+ object->synchronized_set_map(*new_map);
+
map->NotifyLeafMapLayoutChange();
object->set_properties(*dictionary);
}
int delta = old_size - new_size;
- string->set_length(new_length);
Address start_of_string = string->address();
ASSERT_OBJECT_ALIGNED(start_of_string);
}
heap->AdjustLiveBytes(start_of_string, -delta, Heap::FROM_MUTATOR);
+ // We are storing the new length using release store after creating a filler
+ // for the left-over space to avoid races with the sweeper thread.
+ string->synchronized_set_length(new_length);
+
if (new_length == 0) return heap->isolate()->factory()->empty_string();
return string;
}
// of primitive (non-JS) objects like strings, heap numbers etc.
inline void set_map_no_write_barrier(Map* value);
+ // Get the map using acquire load.
+ inline Map* synchronized_map();
+ inline MapWord synchronized_map_word();
+
+ // Set the map using release store
+ inline void synchronized_set_map(Map* value);
+ inline void synchronized_set_map_word(MapWord map_word);
+
// During garbage collection, the map word of a heap object does not
// necessarily contain a map pointer.
inline MapWord map_word();
inline int length();
inline void set_length(int value);
+ // Get and set the length using acquire loads and release stores.
+ inline int synchronized_length();
+ inline void synchronized_set_length(int value);
+
inline static FixedArrayBase* cast(Object* object);
// Layout description.
inline int length();
inline void set_length(int value);
+ // Get and set the length of the string using acquire loads and release
+ // stores.
+ inline int synchronized_length();
+ inline void synchronized_set_length(int value);
+
// Returns whether this string has only ASCII chars, i.e. all of them can
// be ASCII encoded. This might be the case even if the string is
// two-byte. Such strings may appear when the embedder prefers
Address end_of_string = answer->address() + string_size;
Heap* heap = isolate->heap();
+
+ // The trimming is performed on a newly allocated object, which is on a
+ // fresly allocated page or on an already swept page. Hence, the sweeper
+ // thread can not get confused with the filler creation. No synchronization
+ // needed.
heap->CreateFillerObjectAt(end_of_string, delta);
heap->AdjustLiveBytes(answer->address(), -delta, Heap::FROM_MUTATOR);
return *answer;