Swap bitfield3 and backpointer.
Bitfield3 now has its own field, while the backpointer shares the field with the descriptor array; which will become the transition array. BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/10692130 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12034 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
1c62d72a3c
commit
45419ee145
@ -1141,7 +1141,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
|||||||
|
|
||||||
// We got a map in register r0. Get the enumeration cache from it.
|
// We got a map in register r0. Get the enumeration cache from it.
|
||||||
__ bind(&use_cache);
|
__ bind(&use_cache);
|
||||||
__ LoadInstanceDescriptors(r0, r1);
|
__ LoadInstanceDescriptors(r0, r1, r2);
|
||||||
__ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
|
__ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
|
||||||
__ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
__ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
||||||
|
|
||||||
@ -2737,7 +2737,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
|
|||||||
// Look for valueOf symbol in the descriptor array, and indicate false if
|
// Look for valueOf symbol in the descriptor array, and indicate false if
|
||||||
// found. The type is not checked, so if it is a transition it is a false
|
// found. The type is not checked, so if it is a transition it is a false
|
||||||
// negative.
|
// negative.
|
||||||
__ LoadInstanceDescriptors(r1, r4);
|
__ LoadInstanceDescriptors(r1, r4, r3);
|
||||||
__ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset));
|
__ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset));
|
||||||
// r4: descriptor array
|
// r4: descriptor array
|
||||||
// r3: length of descriptor array
|
// r3: length of descriptor array
|
||||||
|
@ -2381,8 +2381,9 @@ LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
|
|||||||
|
|
||||||
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
|
LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
|
||||||
LOperand* map = UseRegister(instr->map());
|
LOperand* map = UseRegister(instr->map());
|
||||||
|
LOperand* scratch = TempRegister();
|
||||||
return AssignEnvironment(DefineAsRegister(
|
return AssignEnvironment(DefineAsRegister(
|
||||||
new(zone()) LForInCacheArray(map)));
|
new(zone()) LForInCacheArray(map, scratch)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2177,13 +2177,15 @@ class LForInPrepareMap: public LTemplateInstruction<1, 1, 0> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LForInCacheArray: public LTemplateInstruction<1, 1, 0> {
|
class LForInCacheArray: public LTemplateInstruction<1, 1, 1> {
|
||||||
public:
|
public:
|
||||||
explicit LForInCacheArray(LOperand* map) {
|
explicit LForInCacheArray(LOperand* map, LOperand* scratch) {
|
||||||
inputs_[0] = map;
|
inputs_[0] = map;
|
||||||
|
temps_[0] = scratch;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOperand* map() { return inputs_[0]; }
|
LOperand* map() { return inputs_[0]; }
|
||||||
|
LOperand* scratch() { return temps_[0]; }
|
||||||
|
|
||||||
DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray, "for-in-cache-array")
|
DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray, "for-in-cache-array")
|
||||||
|
|
||||||
|
@ -5357,7 +5357,8 @@ void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
|
|||||||
void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
|
void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
|
||||||
Register map = ToRegister(instr->map());
|
Register map = ToRegister(instr->map());
|
||||||
Register result = ToRegister(instr->result());
|
Register result = ToRegister(instr->result());
|
||||||
__ LoadInstanceDescriptors(map, result);
|
Register scratch = ToRegister(instr->scratch());
|
||||||
|
__ LoadInstanceDescriptors(map, result, scratch);
|
||||||
__ ldr(result,
|
__ ldr(result,
|
||||||
FieldMemOperand(result, DescriptorArray::kEnumerationIndexOffset));
|
FieldMemOperand(result, DescriptorArray::kEnumerationIndexOffset));
|
||||||
__ ldr(result,
|
__ ldr(result,
|
||||||
|
@ -3673,13 +3673,21 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
||||||
Register descriptors) {
|
Register descriptors,
|
||||||
|
Register scratch) {
|
||||||
ldr(descriptors,
|
ldr(descriptors,
|
||||||
FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
|
FieldMemOperand(map, Map::kInstanceDescriptorsOrBackPointerOffset));
|
||||||
Label not_smi;
|
|
||||||
JumpIfNotSmi(descriptors, ¬_smi);
|
Label ok, fail;
|
||||||
|
CheckMap(descriptors,
|
||||||
|
scratch,
|
||||||
|
isolate()->factory()->fixed_array_map(),
|
||||||
|
&fail,
|
||||||
|
DONT_DO_SMI_CHECK);
|
||||||
|
jmp(&ok);
|
||||||
|
bind(&fail);
|
||||||
mov(descriptors, Operand(FACTORY->empty_descriptor_array()));
|
mov(descriptors, Operand(FACTORY->empty_descriptor_array()));
|
||||||
bind(¬_smi);
|
bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3704,8 +3712,13 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
|
|||||||
// check for an enum cache. Leave the map in r2 for the subsequent
|
// check for an enum cache. Leave the map in r2 for the subsequent
|
||||||
// prototype load.
|
// prototype load.
|
||||||
ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
|
ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
|
||||||
ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOrBitField3Offset));
|
ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOrBackPointerOffset));
|
||||||
JumpIfSmi(r3, call_runtime);
|
|
||||||
|
CheckMap(r3,
|
||||||
|
r7,
|
||||||
|
isolate()->factory()->fixed_array_map(),
|
||||||
|
call_runtime,
|
||||||
|
DONT_DO_SMI_CHECK);
|
||||||
|
|
||||||
// Check that there is an enum cache in the non-empty instance
|
// Check that there is an enum cache in the non-empty instance
|
||||||
// descriptors (r3). This is the case if the next enumeration
|
// descriptors (r3). This is the case if the next enumeration
|
||||||
|
@ -1268,7 +1268,9 @@ class MacroAssembler: public Assembler {
|
|||||||
DoubleRegister temp_double_reg);
|
DoubleRegister temp_double_reg);
|
||||||
|
|
||||||
|
|
||||||
void LoadInstanceDescriptors(Register map, Register descriptors);
|
void LoadInstanceDescriptors(Register map,
|
||||||
|
Register descriptors,
|
||||||
|
Register scratch);
|
||||||
|
|
||||||
// Activation support.
|
// Activation support.
|
||||||
void EnterFrame(StackFrame::Type type);
|
void EnterFrame(StackFrame::Type type);
|
||||||
|
@ -2058,6 +2058,7 @@ MaybeObject* Heap::AllocatePartialMap(InstanceType instance_type,
|
|||||||
reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
|
reinterpret_cast<Map*>(result)->set_unused_property_fields(0);
|
||||||
reinterpret_cast<Map*>(result)->set_bit_field(0);
|
reinterpret_cast<Map*>(result)->set_bit_field(0);
|
||||||
reinterpret_cast<Map*>(result)->set_bit_field2(0);
|
reinterpret_cast<Map*>(result)->set_bit_field2(0);
|
||||||
|
reinterpret_cast<Map*>(result)->set_bit_field3(0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2080,12 +2081,12 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type,
|
|||||||
map->set_instance_size(instance_size);
|
map->set_instance_size(instance_size);
|
||||||
map->set_inobject_properties(0);
|
map->set_inobject_properties(0);
|
||||||
map->set_pre_allocated_property_fields(0);
|
map->set_pre_allocated_property_fields(0);
|
||||||
map->init_instance_descriptors();
|
|
||||||
map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
|
map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
|
||||||
map->init_back_pointer(undefined_value());
|
map->init_back_pointer(undefined_value());
|
||||||
map->set_unused_property_fields(0);
|
map->set_unused_property_fields(0);
|
||||||
map->set_bit_field(0);
|
map->set_bit_field(0);
|
||||||
map->set_bit_field2(1 << Map::kIsExtensible);
|
map->set_bit_field2(1 << Map::kIsExtensible);
|
||||||
|
map->set_bit_field3(0);
|
||||||
map->set_elements_kind(elements_kind);
|
map->set_elements_kind(elements_kind);
|
||||||
|
|
||||||
// If the map object is aligned fill the padding area with Smi 0 objects.
|
// If the map object is aligned fill the padding area with Smi 0 objects.
|
||||||
@ -2219,15 +2220,12 @@ bool Heap::CreateInitialMaps() {
|
|||||||
set_empty_descriptor_array(DescriptorArray::cast(obj));
|
set_empty_descriptor_array(DescriptorArray::cast(obj));
|
||||||
|
|
||||||
// Fix the instance_descriptors for the existing maps.
|
// Fix the instance_descriptors for the existing maps.
|
||||||
meta_map()->init_instance_descriptors();
|
|
||||||
meta_map()->set_code_cache(empty_fixed_array());
|
meta_map()->set_code_cache(empty_fixed_array());
|
||||||
meta_map()->init_back_pointer(undefined_value());
|
meta_map()->init_back_pointer(undefined_value());
|
||||||
|
|
||||||
fixed_array_map()->init_instance_descriptors();
|
|
||||||
fixed_array_map()->set_code_cache(empty_fixed_array());
|
fixed_array_map()->set_code_cache(empty_fixed_array());
|
||||||
fixed_array_map()->init_back_pointer(undefined_value());
|
fixed_array_map()->init_back_pointer(undefined_value());
|
||||||
|
|
||||||
oddball_map()->init_instance_descriptors();
|
|
||||||
oddball_map()->set_code_cache(empty_fixed_array());
|
oddball_map()->set_code_cache(empty_fixed_array());
|
||||||
oddball_map()->init_back_pointer(undefined_value());
|
oddball_map()->init_back_pointer(undefined_value());
|
||||||
|
|
||||||
@ -4191,7 +4189,6 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
|
|||||||
|
|
||||||
// Set up the global object as a normalized object.
|
// Set up the global object as a normalized object.
|
||||||
global->set_map(new_map);
|
global->set_map(new_map);
|
||||||
global->map()->clear_instance_descriptors();
|
|
||||||
global->set_properties(dictionary);
|
global->set_properties(dictionary);
|
||||||
|
|
||||||
// Make sure result is a global object with properties in dictionary.
|
// Make sure result is a global object with properties in dictionary.
|
||||||
|
@ -2518,12 +2518,18 @@ void MacroAssembler::Abort(const char* msg) {
|
|||||||
|
|
||||||
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
||||||
Register descriptors) {
|
Register descriptors) {
|
||||||
mov(descriptors,
|
mov(descriptors, FieldOperand(map,
|
||||||
FieldOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
|
Map::kInstanceDescriptorsOrBackPointerOffset));
|
||||||
Label not_smi;
|
|
||||||
JumpIfNotSmi(descriptors, ¬_smi);
|
Label ok, fail;
|
||||||
|
CheckMap(descriptors,
|
||||||
|
isolate()->factory()->fixed_array_map(),
|
||||||
|
&fail,
|
||||||
|
DONT_DO_SMI_CHECK);
|
||||||
|
jmp(&ok);
|
||||||
|
bind(&fail);
|
||||||
mov(descriptors, isolate()->factory()->empty_descriptor_array());
|
mov(descriptors, isolate()->factory()->empty_descriptor_array());
|
||||||
bind(¬_smi);
|
bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2886,8 +2892,11 @@ void MacroAssembler::CheckEnumCache(Label* call_runtime) {
|
|||||||
// check for an enum cache. Leave the map in ebx for the subsequent
|
// check for an enum cache. Leave the map in ebx for the subsequent
|
||||||
// prototype load.
|
// prototype load.
|
||||||
mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
|
mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
|
||||||
mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset));
|
mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBackPointerOffset));
|
||||||
JumpIfSmi(edx, call_runtime);
|
CheckMap(edx,
|
||||||
|
isolate()->factory()->fixed_array_map(),
|
||||||
|
call_runtime,
|
||||||
|
DONT_DO_SMI_CHECK);
|
||||||
|
|
||||||
// Check that there is an enum cache in the non-empty instance
|
// Check that there is an enum cache in the non-empty instance
|
||||||
// descriptors (edx). This is the case if the next enumeration
|
// descriptors (edx). This is the case if the next enumeration
|
||||||
|
@ -1829,20 +1829,23 @@ void Marker<T>::MarkMapContents(Map* map) {
|
|||||||
base_marker()->MarkObjectAndPush(HeapObject::cast(map->GetBackPointer()));
|
base_marker()->MarkObjectAndPush(HeapObject::cast(map->GetBackPointer()));
|
||||||
|
|
||||||
Object** descriptor_array_slot =
|
Object** descriptor_array_slot =
|
||||||
HeapObject::RawField(map, Map::kInstanceDescriptorsOrBitField3Offset);
|
HeapObject::RawField(map, Map::kInstanceDescriptorsOrBackPointerOffset);
|
||||||
Object* descriptor_array = *descriptor_array_slot;
|
Object* descriptor_array = *descriptor_array_slot;
|
||||||
if (!descriptor_array->IsSmi()) {
|
if (descriptor_array->IsDescriptorArray()) {
|
||||||
MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(descriptor_array));
|
MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(descriptor_array));
|
||||||
|
} else {
|
||||||
|
// Already marked by marking map->GetBackPointer().
|
||||||
|
ASSERT(descriptor_array->IsMap() || descriptor_array->IsUndefined());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the Object* fields of the Map. Since the descriptor array has been
|
// Mark the Object* fields of the Map. Since the descriptor array has been
|
||||||
// marked already, it is fine that one of these fields contains a pointer
|
// marked already, it is fine that one of these fields contains a pointer
|
||||||
// to it. But make sure to skip back pointer.
|
// to it. But make sure to skip back pointer.
|
||||||
STATIC_ASSERT(Map::kPointerFieldsEndOffset ==
|
STATIC_ASSERT(Map::kPointerFieldsEndOffset ==
|
||||||
Map::kBackPointerOffset + kPointerSize);
|
Map::kBitField3Offset + kPointerSize);
|
||||||
Object** start_slot =
|
Object** start_slot =
|
||||||
HeapObject::RawField(map, Map::kPointerFieldsBeginOffset);
|
HeapObject::RawField(map, Map::kPointerFieldsBeginOffset);
|
||||||
Object** end_slot = HeapObject::RawField(map, Map::kBackPointerOffset);
|
Object** end_slot = HeapObject::RawField(map, Map::kBitField3Offset);
|
||||||
for (Object** slot = start_slot; slot < end_slot; slot++) {
|
for (Object** slot = start_slot; slot < end_slot; slot++) {
|
||||||
Object* obj = *slot;
|
Object* obj = *slot;
|
||||||
if (!obj->NonFailureIsHeapObject()) continue;
|
if (!obj->NonFailureIsHeapObject()) continue;
|
||||||
|
@ -1896,14 +1896,17 @@ bool DescriptorArray::HasTransitionArray() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int DescriptorArray::bit_field3_storage() {
|
Object* DescriptorArray::back_pointer_storage() {
|
||||||
Object* storage = READ_FIELD(this, kBitField3StorageOffset);
|
return READ_FIELD(this, kBackPointerStorageOffset);
|
||||||
return Smi::cast(storage)->value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorArray::set_bit_field3_storage(int value) {
|
|
||||||
ASSERT(length() > kBitField3StorageIndex);
|
void DescriptorArray::set_back_pointer_storage(Object* value,
|
||||||
WRITE_FIELD(this, kBitField3StorageOffset, Smi::FromInt(value));
|
WriteBarrierMode mode) {
|
||||||
|
ASSERT(length() > kBackPointerStorageIndex);
|
||||||
|
Heap* heap = GetHeap();
|
||||||
|
WRITE_FIELD(this, kBackPointerStorageOffset, value);
|
||||||
|
CONDITIONAL_WRITE_BARRIER(heap, this, kBackPointerStorageOffset, value, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3437,8 +3440,9 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
|
|||||||
|
|
||||||
|
|
||||||
DescriptorArray* Map::instance_descriptors() {
|
DescriptorArray* Map::instance_descriptors() {
|
||||||
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset);
|
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
|
||||||
if (object->IsSmi()) {
|
if (!object->IsDescriptorArray()) {
|
||||||
|
ASSERT(object->IsMap() || object->IsUndefined());
|
||||||
return GetHeap()->empty_descriptor_array();
|
return GetHeap()->empty_descriptor_array();
|
||||||
} else {
|
} else {
|
||||||
return DescriptorArray::cast(object);
|
return DescriptorArray::cast(object);
|
||||||
@ -3446,85 +3450,60 @@ DescriptorArray* Map::instance_descriptors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Map::init_instance_descriptors() {
|
|
||||||
WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, Smi::FromInt(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Map::clear_instance_descriptors() {
|
|
||||||
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset);
|
|
||||||
if (!object->IsSmi()) {
|
|
||||||
WRITE_FIELD(
|
|
||||||
this,
|
|
||||||
kInstanceDescriptorsOrBitField3Offset,
|
|
||||||
Smi::FromInt(DescriptorArray::cast(object)->bit_field3_storage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Map::set_instance_descriptors(DescriptorArray* value,
|
void Map::set_instance_descriptors(DescriptorArray* value,
|
||||||
WriteBarrierMode mode) {
|
WriteBarrierMode mode) {
|
||||||
Object* object = READ_FIELD(this,
|
|
||||||
kInstanceDescriptorsOrBitField3Offset);
|
|
||||||
Heap* heap = GetHeap();
|
Heap* heap = GetHeap();
|
||||||
|
|
||||||
if (value == heap->empty_descriptor_array()) {
|
if (value == heap->empty_descriptor_array()) {
|
||||||
clear_instance_descriptors();
|
ClearDescriptorArray(heap, mode);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
if (object->IsSmi()) {
|
|
||||||
value->set_bit_field3_storage(Smi::cast(object)->value());
|
|
||||||
} else {
|
|
||||||
value->set_bit_field3_storage(
|
|
||||||
DescriptorArray::cast(object)->bit_field3_storage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
|
||||||
|
|
||||||
|
if (object->IsDescriptorArray()) {
|
||||||
|
value->set_back_pointer_storage(
|
||||||
|
DescriptorArray::cast(object)->back_pointer_storage());
|
||||||
|
} else {
|
||||||
|
ASSERT(object->IsMap() || object->IsUndefined());
|
||||||
|
value->set_back_pointer_storage(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(!is_shared());
|
ASSERT(!is_shared());
|
||||||
WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, value);
|
WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value);
|
||||||
CONDITIONAL_WRITE_BARRIER(
|
CONDITIONAL_WRITE_BARRIER(
|
||||||
heap, this, kInstanceDescriptorsOrBitField3Offset, value, mode);
|
heap, this, kInstanceDescriptorsOrBackPointerOffset, value, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int Map::bit_field3() {
|
SMI_ACCESSORS(Map, bit_field3, kBitField3Offset)
|
||||||
Object* object = READ_FIELD(this,
|
|
||||||
kInstanceDescriptorsOrBitField3Offset);
|
|
||||||
if (object->IsSmi()) {
|
|
||||||
return Smi::cast(object)->value();
|
|
||||||
} else {
|
|
||||||
return DescriptorArray::cast(object)->bit_field3_storage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Map::ClearDescriptorArray() {
|
void Map::ClearDescriptorArray(Heap* heap, WriteBarrierMode mode) {
|
||||||
int bitfield3 = bit_field3();
|
Object* back_pointer = GetBackPointer();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset);
|
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
|
||||||
if (!object->IsSmi()) {
|
if (object->IsDescriptorArray()) {
|
||||||
ZapTransitions();
|
ZapTransitions();
|
||||||
|
} else {
|
||||||
|
ASSERT(object->IsMap() || object->IsUndefined());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
WRITE_FIELD(this,
|
WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, back_pointer);
|
||||||
kInstanceDescriptorsOrBitField3Offset,
|
CONDITIONAL_WRITE_BARRIER(
|
||||||
Smi::FromInt(bitfield3));
|
heap, this, kInstanceDescriptorsOrBackPointerOffset, back_pointer, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Map::set_bit_field3(int value) {
|
|
||||||
ASSERT(Smi::IsValid(value));
|
|
||||||
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset);
|
|
||||||
if (object->IsSmi()) {
|
|
||||||
WRITE_FIELD(this,
|
|
||||||
kInstanceDescriptorsOrBitField3Offset,
|
|
||||||
Smi::FromInt(value));
|
|
||||||
} else {
|
|
||||||
DescriptorArray::cast(object)->set_bit_field3_storage(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Object* Map::GetBackPointer() {
|
Object* Map::GetBackPointer() {
|
||||||
return READ_FIELD(this, kBackPointerOffset);
|
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
|
||||||
|
if (object->IsDescriptorArray()) {
|
||||||
|
return DescriptorArray::cast(object)->back_pointer_storage();
|
||||||
|
} else {
|
||||||
|
ASSERT(object->IsMap() || object->IsUndefined());
|
||||||
|
return object;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3549,8 +3528,8 @@ MaybeObject* Map::AddTransition(String* key, Object* value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If the map does not have a descriptor array, install a new empty
|
// If the map is using the empty descriptor array, install a new empty
|
||||||
// descriptor array that has room for a transition array.
|
// descriptor array that will contain an elements transition.
|
||||||
static MaybeObject* AllowTransitions(Map* map) {
|
static MaybeObject* AllowTransitions(Map* map) {
|
||||||
if (map->instance_descriptors()->MayContainTransitions()) return map;
|
if (map->instance_descriptors()->MayContainTransitions()) return map;
|
||||||
DescriptorArray* descriptors;
|
DescriptorArray* descriptors;
|
||||||
@ -3619,13 +3598,13 @@ TransitionArray* Map::transitions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Map::ClearTransitions() {
|
void Map::ClearTransitions(Heap* heap, WriteBarrierMode mode) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
ZapTransitions();
|
ZapTransitions();
|
||||||
#endif
|
#endif
|
||||||
DescriptorArray* descriptors = instance_descriptors();
|
DescriptorArray* descriptors = instance_descriptors();
|
||||||
if (descriptors->number_of_descriptors() == 0) {
|
if (descriptors->number_of_descriptors() == 0) {
|
||||||
ClearDescriptorArray();
|
ClearDescriptorArray(heap, mode);
|
||||||
} else {
|
} else {
|
||||||
descriptors->ClearTransitions();
|
descriptors->ClearTransitions();
|
||||||
}
|
}
|
||||||
@ -3648,17 +3627,22 @@ MaybeObject* Map::set_transitions(TransitionArray* transitions_array) {
|
|||||||
|
|
||||||
void Map::init_back_pointer(Object* undefined) {
|
void Map::init_back_pointer(Object* undefined) {
|
||||||
ASSERT(undefined->IsUndefined());
|
ASSERT(undefined->IsUndefined());
|
||||||
WRITE_FIELD(this, kBackPointerOffset, undefined);
|
WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
|
void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
|
||||||
Heap* heap = GetHeap();
|
|
||||||
ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE);
|
ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE);
|
||||||
ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
|
ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
|
||||||
(value->IsMap() && GetBackPointer()->IsUndefined()));
|
(value->IsMap() && GetBackPointer()->IsUndefined()));
|
||||||
WRITE_FIELD(this, kBackPointerOffset, value);
|
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBackPointerOffset);
|
||||||
CONDITIONAL_WRITE_BARRIER(heap, this, kBackPointerOffset, value, mode);
|
if (object->IsMap()) {
|
||||||
|
WRITE_FIELD(this, kInstanceDescriptorsOrBackPointerOffset, value);
|
||||||
|
CONDITIONAL_WRITE_BARRIER(
|
||||||
|
GetHeap(), this, kInstanceDescriptorsOrBackPointerOffset, value, mode);
|
||||||
|
} else {
|
||||||
|
DescriptorArray::cast(object)->set_back_pointer_storage(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3411,9 +3411,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
|
|||||||
-instance_size_delta);
|
-instance_size_delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
set_map(new_map);
|
set_map(new_map);
|
||||||
new_map->clear_instance_descriptors();
|
|
||||||
|
|
||||||
set_properties(dictionary);
|
set_properties(dictionary);
|
||||||
|
|
||||||
@ -4927,12 +4925,7 @@ MaybeObject* Map::CopyDropDescriptors() {
|
|||||||
}
|
}
|
||||||
Map::cast(result)->set_prototype(prototype());
|
Map::cast(result)->set_prototype(prototype());
|
||||||
Map::cast(result)->set_constructor(constructor());
|
Map::cast(result)->set_constructor(constructor());
|
||||||
// Don't copy descriptors, so map transitions always remain a forest.
|
|
||||||
// If we retained the same descriptors we would have two maps
|
|
||||||
// pointing to the same transition which is bad because the garbage
|
|
||||||
// collector relies on being able to reverse pointers from transitions
|
|
||||||
// to maps. If properties need to be retained use CopyDropTransitions.
|
|
||||||
Map::cast(result)->clear_instance_descriptors();
|
|
||||||
// Please note instance_type and instance_size are set when allocated.
|
// Please note instance_type and instance_size are set when allocated.
|
||||||
Map::cast(result)->set_inobject_properties(inobject_properties());
|
Map::cast(result)->set_inobject_properties(inobject_properties());
|
||||||
Map::cast(result)->set_unused_property_fields(unused_property_fields());
|
Map::cast(result)->set_unused_property_fields(unused_property_fields());
|
||||||
@ -5824,7 +5817,6 @@ MaybeObject* DescriptorArray::Allocate(int number_of_descriptors,
|
|||||||
if (!maybe_array->To(&result)) return maybe_array;
|
if (!maybe_array->To(&result)) return maybe_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->set(kBitField3StorageIndex, Smi::FromInt(0));
|
|
||||||
result->set(kEnumerationIndexIndex,
|
result->set(kEnumerationIndexIndex,
|
||||||
Smi::FromInt(PropertyDetails::kInitialIndex));
|
Smi::FromInt(PropertyDetails::kInitialIndex));
|
||||||
result->set(kTransitionsIndex, Smi::FromInt(0));
|
result->set(kTransitionsIndex, Smi::FromInt(0));
|
||||||
@ -7413,7 +7405,7 @@ void Map::ClearNonLiveTransitions(Heap* heap) {
|
|||||||
if (transition_index == 0 &&
|
if (transition_index == 0 &&
|
||||||
!t->HasElementsTransition() &&
|
!t->HasElementsTransition() &&
|
||||||
!t->HasPrototypeTransitions()) {
|
!t->HasPrototypeTransitions()) {
|
||||||
return ClearTransitions();
|
return ClearTransitions(heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
int trim = t->number_of_transitions() - transition_index;
|
int trim = t->number_of_transitions() - transition_index;
|
||||||
|
@ -2514,11 +2514,7 @@ class DescriptorArray: public FixedArray {
|
|||||||
kTransitionsOffset);
|
kTransitionsOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(1399): It should be possible to make room for bit_field3 in the map
|
DECL_ACCESSORS(back_pointer_storage, Object)
|
||||||
// without overloading the instance descriptors field in the map
|
|
||||||
// (and storing it in the DescriptorArray when the map has one).
|
|
||||||
inline int bit_field3_storage();
|
|
||||||
inline void set_bit_field3_storage(int value);
|
|
||||||
|
|
||||||
// Initialize or change the enum cache,
|
// Initialize or change the enum cache,
|
||||||
// using the supplied storage for the small "bridge".
|
// using the supplied storage for the small "bridge".
|
||||||
@ -2607,7 +2603,7 @@ class DescriptorArray: public FixedArray {
|
|||||||
// Constant for denoting key was not found.
|
// Constant for denoting key was not found.
|
||||||
static const int kNotFound = -1;
|
static const int kNotFound = -1;
|
||||||
|
|
||||||
static const int kBitField3StorageIndex = 0;
|
static const int kBackPointerStorageIndex = 0;
|
||||||
static const int kEnumerationIndexIndex = 1;
|
static const int kEnumerationIndexIndex = 1;
|
||||||
static const int kTransitionsIndex = 2;
|
static const int kTransitionsIndex = 2;
|
||||||
static const int kFirstIndex = 3;
|
static const int kFirstIndex = 3;
|
||||||
@ -2619,8 +2615,8 @@ class DescriptorArray: public FixedArray {
|
|||||||
static const int kEnumCacheBridgeIndicesCacheIndex = 2;
|
static const int kEnumCacheBridgeIndicesCacheIndex = 2;
|
||||||
|
|
||||||
// Layout description.
|
// Layout description.
|
||||||
static const int kBitField3StorageOffset = FixedArray::kHeaderSize;
|
static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
|
||||||
static const int kEnumerationIndexOffset = kBitField3StorageOffset +
|
static const int kEnumerationIndexOffset = kBackPointerStorageOffset +
|
||||||
kPointerSize;
|
kPointerSize;
|
||||||
static const int kTransitionsOffset = kEnumerationIndexOffset + kPointerSize;
|
static const int kTransitionsOffset = kEnumerationIndexOffset + kPointerSize;
|
||||||
static const int kFirstOffset = kTransitionsOffset + kPointerSize;
|
static const int kFirstOffset = kTransitionsOffset + kPointerSize;
|
||||||
@ -4676,12 +4672,8 @@ class Map: public HeapObject {
|
|||||||
inline void set_bit_field2(byte value);
|
inline void set_bit_field2(byte value);
|
||||||
|
|
||||||
// Bit field 3.
|
// Bit field 3.
|
||||||
// TODO(1399): It should be possible to make room for bit_field3 in the map
|
|
||||||
// without overloading the instance descriptors field (and storing it in the
|
|
||||||
// DescriptorArray when the map has one).
|
|
||||||
inline int bit_field3();
|
inline int bit_field3();
|
||||||
inline void set_bit_field3(int value);
|
inline void set_bit_field3(int value);
|
||||||
inline void SetOwnBitField3(int value);
|
|
||||||
|
|
||||||
// Tells whether the object in the prototype property will be used
|
// Tells whether the object in the prototype property will be used
|
||||||
// for instances created from this function. If the prototype
|
// for instances created from this function. If the prototype
|
||||||
@ -4812,7 +4804,8 @@ class Map: public HeapObject {
|
|||||||
Object* value);
|
Object* value);
|
||||||
MUST_USE_RESULT inline MaybeObject* set_transitions(
|
MUST_USE_RESULT inline MaybeObject* set_transitions(
|
||||||
TransitionArray* transitions);
|
TransitionArray* transitions);
|
||||||
inline void ClearTransitions();
|
inline void ClearTransitions(Heap* heap,
|
||||||
|
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
|
||||||
|
|
||||||
// Tells whether the map is attached to SharedFunctionInfo
|
// Tells whether the map is attached to SharedFunctionInfo
|
||||||
// (for inobject slack tracking).
|
// (for inobject slack tracking).
|
||||||
@ -4839,20 +4832,12 @@ class Map: public HeapObject {
|
|||||||
|
|
||||||
inline JSFunction* unchecked_constructor();
|
inline JSFunction* unchecked_constructor();
|
||||||
|
|
||||||
// Should only be called by the code that initializes map to set initial valid
|
|
||||||
// value of the instance descriptor member.
|
|
||||||
inline void init_instance_descriptors();
|
|
||||||
|
|
||||||
// [instance descriptors]: describes the object.
|
// [instance descriptors]: describes the object.
|
||||||
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
|
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
|
||||||
|
|
||||||
// Should only be called to clear a descriptor array that was only used to
|
// Should only be called to clear a descriptor array that was only used to
|
||||||
// store transitions and does not contain any live transitions anymore.
|
// store transitions and does not contain any live transitions anymore.
|
||||||
inline void ClearDescriptorArray();
|
inline void ClearDescriptorArray(Heap* heap, WriteBarrierMode mode);
|
||||||
|
|
||||||
// Sets the instance descriptor array for the map to be an empty descriptor
|
|
||||||
// array.
|
|
||||||
inline void clear_instance_descriptors();
|
|
||||||
|
|
||||||
// [stub cache]: contains stubs compiled for this map.
|
// [stub cache]: contains stubs compiled for this map.
|
||||||
DECL_ACCESSORS(code_cache, Object)
|
DECL_ACCESSORS(code_cache, Object)
|
||||||
@ -5047,23 +5032,18 @@ class Map: public HeapObject {
|
|||||||
// map flags when unused (bit_field3). When the map has instance descriptors,
|
// map flags when unused (bit_field3). When the map has instance descriptors,
|
||||||
// the flags are transferred to the instance descriptor array and accessed
|
// the flags are transferred to the instance descriptor array and accessed
|
||||||
// through an extra indirection.
|
// through an extra indirection.
|
||||||
// TODO(1399): It should be possible to make room for bit_field3 in the map
|
static const int kInstanceDescriptorsOrBackPointerOffset =
|
||||||
// without overloading the instance descriptors field, but the map is
|
|
||||||
// currently perfectly aligned to 32 bytes and extending it at all would
|
|
||||||
// double its size. After the increment GC work lands, this size restriction
|
|
||||||
// could be loosened and bit_field3 moved directly back in the map.
|
|
||||||
static const int kInstanceDescriptorsOrBitField3Offset =
|
|
||||||
kConstructorOffset + kPointerSize;
|
kConstructorOffset + kPointerSize;
|
||||||
static const int kCodeCacheOffset =
|
static const int kCodeCacheOffset =
|
||||||
kInstanceDescriptorsOrBitField3Offset + kPointerSize;
|
kInstanceDescriptorsOrBackPointerOffset + kPointerSize;
|
||||||
static const int kBackPointerOffset = kCodeCacheOffset + kPointerSize;
|
static const int kBitField3Offset = kCodeCacheOffset + kPointerSize;
|
||||||
static const int kPadStart = kBackPointerOffset + kPointerSize;
|
static const int kPadStart = kBitField3Offset + kPointerSize;
|
||||||
static const int kSize = MAP_POINTER_ALIGN(kPadStart);
|
static const int kSize = MAP_POINTER_ALIGN(kPadStart);
|
||||||
|
|
||||||
// Layout of pointer fields. Heap iteration code relies on them
|
// Layout of pointer fields. Heap iteration code relies on them
|
||||||
// being continuously allocated.
|
// being continuously allocated.
|
||||||
static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset;
|
static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset;
|
||||||
static const int kPointerFieldsEndOffset = kBackPointerOffset + kPointerSize;
|
static const int kPointerFieldsEndOffset = kBitField3Offset + kPointerSize;
|
||||||
|
|
||||||
// Byte offsets within kInstanceSizesOffset.
|
// Byte offsets within kInstanceSizesOffset.
|
||||||
static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
|
static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
|
||||||
|
@ -2011,7 +2011,7 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
|
|||||||
TagObject(map->instance_descriptors(), "(map descriptors)");
|
TagObject(map->instance_descriptors(), "(map descriptors)");
|
||||||
SetInternalReference(map, entry,
|
SetInternalReference(map, entry,
|
||||||
"descriptors", map->instance_descriptors(),
|
"descriptors", map->instance_descriptors(),
|
||||||
Map::kInstanceDescriptorsOrBitField3Offset);
|
Map::kInstanceDescriptorsOrBackPointerOffset);
|
||||||
}
|
}
|
||||||
SetInternalReference(map, entry,
|
SetInternalReference(map, entry,
|
||||||
"code_cache", map->code_cache(),
|
"code_cache", map->code_cache(),
|
||||||
|
@ -2190,13 +2190,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
|
|||||||
DescriptorArray* new_descriptors =
|
DescriptorArray* new_descriptors =
|
||||||
DescriptorArray::cast(descriptors_unchecked);
|
DescriptorArray::cast(descriptors_unchecked);
|
||||||
// Create a new map featuring the new field descriptors array.
|
// Create a new map featuring the new field descriptors array.
|
||||||
Object* map_unchecked;
|
Map* new_map;
|
||||||
{ MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
|
{ MaybeObject* maybe_map_unchecked =
|
||||||
if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
|
function->map()->CopyDropDescriptors();
|
||||||
|
if (!maybe_map_unchecked->To(&new_map)) {
|
||||||
return maybe_map_unchecked;
|
return maybe_map_unchecked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map* new_map = Map::cast(map_unchecked);
|
|
||||||
new_map->set_instance_descriptors(new_descriptors);
|
new_map->set_instance_descriptors(new_descriptors);
|
||||||
function->set_map(new_map);
|
function->set_map(new_map);
|
||||||
} else { // Dictionary properties.
|
} else { // Dictionary properties.
|
||||||
|
@ -2853,11 +2853,17 @@ void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
|
|||||||
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
||||||
Register descriptors) {
|
Register descriptors) {
|
||||||
movq(descriptors, FieldOperand(map,
|
movq(descriptors, FieldOperand(map,
|
||||||
Map::kInstanceDescriptorsOrBitField3Offset));
|
Map::kInstanceDescriptorsOrBackPointerOffset));
|
||||||
Label not_smi;
|
|
||||||
JumpIfNotSmi(descriptors, ¬_smi, Label::kNear);
|
Label ok, fail;
|
||||||
|
CheckMap(descriptors,
|
||||||
|
isolate()->factory()->fixed_array_map(),
|
||||||
|
&fail,
|
||||||
|
DONT_DO_SMI_CHECK);
|
||||||
|
jmp(&ok);
|
||||||
|
bind(&fail);
|
||||||
Move(descriptors, isolate()->factory()->empty_descriptor_array());
|
Move(descriptors, isolate()->factory()->empty_descriptor_array());
|
||||||
bind(¬_smi);
|
bind(&ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4457,8 +4463,12 @@ void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
|
|||||||
// check for an enum cache. Leave the map in rbx for the subsequent
|
// check for an enum cache. Leave the map in rbx for the subsequent
|
||||||
// prototype load.
|
// prototype load.
|
||||||
movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
|
movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
|
||||||
movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBitField3Offset));
|
movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBackPointerOffset));
|
||||||
JumpIfSmi(rdx, call_runtime);
|
|
||||||
|
CheckMap(rdx,
|
||||||
|
isolate()->factory()->fixed_array_map(),
|
||||||
|
call_runtime,
|
||||||
|
DONT_DO_SMI_CHECK);
|
||||||
|
|
||||||
// Check that there is an enum cache in the non-empty instance
|
// Check that there is an enum cache in the non-empty instance
|
||||||
// descriptors (rdx). This is the case if the next enumeration
|
// descriptors (rdx). This is the case if the next enumeration
|
||||||
|
Loading…
Reference in New Issue
Block a user