Add bit_field3 to Map objects
Reuse instance_descriptor field in the map to store additional flags when there are no descriptors. When descriptors get added to the map, move the flags to the DescriptorArray and access through indirection. Review URL: http://codereview.chromium.org/7033024 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8001 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d88dbf27f5
commit
70d5e6d582
@ -924,9 +924,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
// check for an enum cache. Leave the map in r2 for the subsequent
|
||||
// prototype load.
|
||||
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
|
||||
__ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOffset));
|
||||
__ cmp(r3, empty_descriptor_array_value);
|
||||
__ b(eq, &call_runtime);
|
||||
__ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
__ JumpIfSmi(r3, &call_runtime);
|
||||
|
||||
// Check that there is an enum cache in the non-empty instance
|
||||
// descriptors (r3). This is the case if the next enumeration
|
||||
@ -971,7 +970,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
|
||||
// We got a map in register r0. Get the enumeration cache from it.
|
||||
__ bind(&use_cache);
|
||||
__ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset));
|
||||
__ LoadInstanceDescriptors(r0, r1);
|
||||
__ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
|
||||
__ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
||||
|
||||
@ -2544,7 +2543,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
|
||||
// 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
|
||||
// negative.
|
||||
__ ldr(r4, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
|
||||
__ LoadInstanceDescriptors(r1, r4);
|
||||
__ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset));
|
||||
// r4: descriptor array
|
||||
// r3: length of descriptor array
|
||||
|
@ -3083,6 +3083,17 @@ void MacroAssembler::ClampDoubleToUint8(Register result_reg,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
||||
Register descriptors) {
|
||||
ldr(descriptors,
|
||||
FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
Label not_smi;
|
||||
JumpIfNotSmi(descriptors, ¬_smi);
|
||||
mov(descriptors, Operand(FACTORY->empty_descriptor_array()));
|
||||
bind(¬_smi);
|
||||
}
|
||||
|
||||
|
||||
CodePatcher::CodePatcher(byte* address, int instructions)
|
||||
: address_(address),
|
||||
instructions_(instructions),
|
||||
|
@ -1006,6 +1006,8 @@ class MacroAssembler: public Assembler {
|
||||
DoubleRegister temp_double_reg);
|
||||
|
||||
|
||||
void LoadInstanceDescriptors(Register map, Register descriptors);
|
||||
|
||||
private:
|
||||
void CallCFunctionHelper(Register function,
|
||||
ExternalReference function_reference,
|
||||
|
10
src/heap.cc
10
src/heap.cc
@ -1603,7 +1603,7 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
|
||||
map->set_instance_size(instance_size);
|
||||
map->set_inobject_properties(0);
|
||||
map->set_pre_allocated_property_fields(0);
|
||||
map->set_instance_descriptors(empty_descriptor_array());
|
||||
map->init_instance_descriptors();
|
||||
map->set_code_cache(empty_fixed_array());
|
||||
map->set_prototype_transitions(empty_fixed_array());
|
||||
map->set_unused_property_fields(0);
|
||||
@ -1696,15 +1696,15 @@ bool Heap::CreateInitialMaps() {
|
||||
set_empty_descriptor_array(DescriptorArray::cast(obj));
|
||||
|
||||
// Fix the instance_descriptors for the existing maps.
|
||||
meta_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
meta_map()->init_instance_descriptors();
|
||||
meta_map()->set_code_cache(empty_fixed_array());
|
||||
meta_map()->set_prototype_transitions(empty_fixed_array());
|
||||
|
||||
fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
fixed_array_map()->init_instance_descriptors();
|
||||
fixed_array_map()->set_code_cache(empty_fixed_array());
|
||||
fixed_array_map()->set_prototype_transitions(empty_fixed_array());
|
||||
|
||||
oddball_map()->set_instance_descriptors(empty_descriptor_array());
|
||||
oddball_map()->init_instance_descriptors();
|
||||
oddball_map()->set_code_cache(empty_fixed_array());
|
||||
oddball_map()->set_prototype_transitions(empty_fixed_array());
|
||||
|
||||
@ -3307,7 +3307,7 @@ MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
|
||||
|
||||
// Setup the global object as a normalized object.
|
||||
global->set_map(new_map);
|
||||
global->map()->set_instance_descriptors(empty_descriptor_array());
|
||||
global->map()->clear_instance_descriptors();
|
||||
global->set_properties(dictionary);
|
||||
|
||||
// Make sure result is a global object with properties in dictionary.
|
||||
|
@ -887,9 +887,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
// check for an enum cache. Leave the map in ebx for the subsequent
|
||||
// prototype load.
|
||||
__ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset));
|
||||
__ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
|
||||
__ cmp(edx, isolate()->factory()->empty_descriptor_array());
|
||||
__ j(equal, &call_runtime);
|
||||
__ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
__ JumpIfSmi(edx, &call_runtime);
|
||||
|
||||
// Check that there is an enum cache in the non-empty instance
|
||||
// descriptors (edx). This is the case if the next enumeration
|
||||
@ -933,7 +932,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
|
||||
// We got a map in register eax. Get the enumeration cache from it.
|
||||
__ bind(&use_cache);
|
||||
__ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
|
||||
__ LoadInstanceDescriptors(eax, ecx);
|
||||
__ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
|
||||
__ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
||||
|
||||
@ -2472,7 +2471,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
|
||||
// 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
|
||||
// negative.
|
||||
__ mov(ebx, FieldOperand(ebx, Map::kInstanceDescriptorsOffset));
|
||||
__ LoadInstanceDescriptors(ebx, ebx);
|
||||
__ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
|
||||
// ebx: descriptor array
|
||||
// ecx: length of descriptor array
|
||||
|
@ -1974,6 +1974,17 @@ void MacroAssembler::Abort(const char* msg) {
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
||||
Register descriptors) {
|
||||
mov(descriptors,
|
||||
FieldOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
Label not_smi;
|
||||
JumpIfNotSmi(descriptors, ¬_smi);
|
||||
mov(descriptors, isolate()->factory()->empty_descriptor_array());
|
||||
bind(¬_smi);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadPowerOf2(XMMRegister dst,
|
||||
Register scratch,
|
||||
int power) {
|
||||
|
@ -284,6 +284,8 @@ class MacroAssembler: public Assembler {
|
||||
j(not_zero, not_smi_label);
|
||||
}
|
||||
|
||||
void LoadInstanceDescriptors(Register map, Register descriptors);
|
||||
|
||||
void LoadPowerOf2(XMMRegister dst, Register scratch, int power);
|
||||
|
||||
// Abort execution if argument is not a number. Used in debug code.
|
||||
|
@ -1081,8 +1081,13 @@ void MarkCompactCollector::MarkMapContents(Map* map) {
|
||||
FixedArray* prototype_transitions = map->unchecked_prototype_transitions();
|
||||
if (!prototype_transitions->IsMarked()) SetMark(prototype_transitions);
|
||||
|
||||
MarkDescriptorArray(reinterpret_cast<DescriptorArray*>(
|
||||
*HeapObject::RawField(map, Map::kInstanceDescriptorsOffset)));
|
||||
Object* raw_descriptor_array =
|
||||
*HeapObject::RawField(map,
|
||||
Map::kInstanceDescriptorsOrBitField3Offset);
|
||||
if (!raw_descriptor_array->IsSmi()) {
|
||||
MarkDescriptorArray(
|
||||
reinterpret_cast<DescriptorArray*>(raw_descriptor_array));
|
||||
}
|
||||
|
||||
// Mark the Object* fields of the Map.
|
||||
// Since the descriptor array has been marked already, it is fine
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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:
|
||||
@ -272,7 +272,7 @@ void Map::MapVerify() {
|
||||
void Map::SharedMapVerify() {
|
||||
MapVerify();
|
||||
ASSERT(is_shared());
|
||||
ASSERT_EQ(GetHeap()->empty_descriptor_array(), instance_descriptors());
|
||||
ASSERT(instance_descriptors()->IsEmpty());
|
||||
ASSERT_EQ(0, pre_allocated_property_fields());
|
||||
ASSERT_EQ(0, unused_property_fields());
|
||||
ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()),
|
||||
|
@ -1674,9 +1674,21 @@ Object** FixedArray::data_start() {
|
||||
|
||||
|
||||
bool DescriptorArray::IsEmpty() {
|
||||
ASSERT(this->length() > kFirstIndex ||
|
||||
ASSERT(this->IsSmi() ||
|
||||
this->length() > kFirstIndex ||
|
||||
this == HEAP->empty_descriptor_array());
|
||||
return length() <= kFirstIndex;
|
||||
return this->IsSmi() || length() <= kFirstIndex;
|
||||
}
|
||||
|
||||
|
||||
int DescriptorArray::bit_field3_storage() {
|
||||
Object* storage = READ_FIELD(this, kBitField3StorageOffset);
|
||||
return Smi::cast(storage)->value();
|
||||
}
|
||||
|
||||
void DescriptorArray::set_bit_field3_storage(int value) {
|
||||
ASSERT(!IsEmpty());
|
||||
WRITE_FIELD(this, kBitField3StorageOffset, Smi::FromInt(value));
|
||||
}
|
||||
|
||||
|
||||
@ -2967,8 +2979,82 @@ MaybeObject* Map::GetSlowElementsMap() {
|
||||
}
|
||||
|
||||
|
||||
ACCESSORS(Map, instance_descriptors, DescriptorArray,
|
||||
kInstanceDescriptorsOffset)
|
||||
DescriptorArray* Map::instance_descriptors() {
|
||||
Object* object = READ_FIELD(this, kInstanceDescriptorsOrBitField3Offset);
|
||||
if (object->IsSmi()) {
|
||||
return HEAP->empty_descriptor_array();
|
||||
} else {
|
||||
return DescriptorArray::cast(object);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
WriteBarrierMode mode) {
|
||||
Object* object = READ_FIELD(this,
|
||||
kInstanceDescriptorsOrBitField3Offset);
|
||||
if (value == isolate()->heap()->empty_descriptor_array()) {
|
||||
clear_instance_descriptors();
|
||||
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());
|
||||
}
|
||||
}
|
||||
ASSERT(!is_shared());
|
||||
WRITE_FIELD(this, kInstanceDescriptorsOrBitField3Offset, value);
|
||||
CONDITIONAL_WRITE_BARRIER(GetHeap(),
|
||||
this,
|
||||
kInstanceDescriptorsOrBitField3Offset,
|
||||
mode);
|
||||
}
|
||||
|
||||
|
||||
int Map::bit_field3() {
|
||||
Object* object = READ_FIELD(this,
|
||||
kInstanceDescriptorsOrBitField3Offset);
|
||||
if (object->IsSmi()) {
|
||||
return Smi::cast(object)->value();
|
||||
} else {
|
||||
return DescriptorArray::cast(object)->bit_field3_storage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
|
||||
ACCESSORS(Map, prototype_transitions, FixedArray, kPrototypeTransitionsOffset)
|
||||
ACCESSORS(Map, constructor, Object, kConstructorOffset)
|
||||
|
@ -2535,6 +2535,7 @@ bool NormalizedMapCache::CheckHit(Map* slow,
|
||||
fast->inobject_properties()) &&
|
||||
slow->instance_type() == fast->instance_type() &&
|
||||
slow->bit_field() == fast->bit_field() &&
|
||||
slow->bit_field3() == fast->bit_field3() &&
|
||||
(slow->bit_field2() & ~(1<<Map::kIsShared)) == fast->bit_field2();
|
||||
}
|
||||
|
||||
@ -2657,7 +2658,7 @@ MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
|
||||
instance_size_delta);
|
||||
|
||||
set_map(new_map);
|
||||
new_map->set_instance_descriptors(current_heap->empty_descriptor_array());
|
||||
new_map->clear_instance_descriptors();
|
||||
|
||||
set_properties(dictionary);
|
||||
|
||||
@ -3647,8 +3648,7 @@ MaybeObject* Map::CopyDropDescriptors() {
|
||||
// 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)->set_instance_descriptors(
|
||||
heap->empty_descriptor_array());
|
||||
Map::cast(result)->clear_instance_descriptors();
|
||||
// Please note instance_type and instance_size are set when allocated.
|
||||
Map::cast(result)->set_inobject_properties(inobject_properties());
|
||||
Map::cast(result)->set_unused_property_fields(unused_property_fields());
|
||||
@ -3670,6 +3670,7 @@ MaybeObject* Map::CopyDropDescriptors() {
|
||||
}
|
||||
Map::cast(result)->set_bit_field(bit_field());
|
||||
Map::cast(result)->set_bit_field2(bit_field2());
|
||||
Map::cast(result)->set_bit_field3(bit_field3());
|
||||
Map::cast(result)->set_is_shared(false);
|
||||
Map::cast(result)->ClearCodeCache(heap);
|
||||
return result;
|
||||
@ -3698,6 +3699,7 @@ MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
|
||||
|
||||
Map::cast(result)->set_bit_field(bit_field());
|
||||
Map::cast(result)->set_bit_field2(bit_field2());
|
||||
Map::cast(result)->set_bit_field3(bit_field3());
|
||||
|
||||
Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
|
||||
|
||||
@ -3773,8 +3775,8 @@ void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
|
||||
Map* meta_map = heap()->meta_map();
|
||||
while (current != meta_map) {
|
||||
DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
|
||||
*RawField(current, Map::kInstanceDescriptorsOffset));
|
||||
if (d == heap()->empty_descriptor_array()) {
|
||||
*RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
if (d->IsEmpty()) {
|
||||
Map* prev = current->map();
|
||||
current->set_map(meta_map);
|
||||
callback(current, data);
|
||||
@ -4245,6 +4247,7 @@ MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
|
||||
heap->AllocateFixedArray(number_of_descriptors << 1);
|
||||
if (!maybe_array->ToObject(&array)) return maybe_array;
|
||||
}
|
||||
result->set(kBitField3StorageIndex, Smi::FromInt(0));
|
||||
result->set(kContentArrayIndex, array);
|
||||
result->set(kEnumerationIndexIndex,
|
||||
Smi::FromInt(PropertyDetails::kInitialIndex));
|
||||
@ -5701,8 +5704,8 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
|
||||
// Live DescriptorArray objects will be marked, so we must use
|
||||
// low-level accessors to get and modify their data.
|
||||
DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
|
||||
*RawField(this, Map::kInstanceDescriptorsOffset));
|
||||
if (d == heap->raw_unchecked_empty_descriptor_array()) return;
|
||||
*RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
if (d->IsEmpty()) return;
|
||||
Smi* NullDescriptorDetails =
|
||||
PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
|
||||
FixedArray* contents = reinterpret_cast<FixedArray*>(
|
||||
|
@ -2039,16 +2039,22 @@ class FixedArray: public HeapObject {
|
||||
|
||||
// DescriptorArrays are fixed arrays used to hold instance descriptors.
|
||||
// The format of the these objects is:
|
||||
// [0]: point to a fixed array with (value, detail) pairs.
|
||||
// [1]: next enumeration index (Smi), or pointer to small fixed array:
|
||||
// TODO(1399): It should be possible to make room for bit_field3 in the map
|
||||
// without overloading the instance descriptors field in the map
|
||||
// (and storing it in the DescriptorArray when the map has one).
|
||||
// [0]: storage for bit_field3 for Map owning this object (Smi)
|
||||
// [1]: point to a fixed array with (value, detail) pairs.
|
||||
// [2]: next enumeration index (Smi), or pointer to small fixed array:
|
||||
// [0]: next enumeration index (Smi)
|
||||
// [1]: pointer to fixed array with enum cache
|
||||
// [2]: first key
|
||||
// [3]: first key
|
||||
// [length() - 1]: last key
|
||||
//
|
||||
class DescriptorArray: public FixedArray {
|
||||
public:
|
||||
// Is this the singleton empty_descriptor_array?
|
||||
// Returns true for both shared empty_descriptor_array and for smis, which the
|
||||
// map uses to encode additional bit fields when the descriptor array is not
|
||||
// yet used.
|
||||
inline bool IsEmpty();
|
||||
|
||||
// Returns the number of descriptors in the array.
|
||||
@ -2085,6 +2091,12 @@ class DescriptorArray: public FixedArray {
|
||||
return bridge->get(kEnumCacheBridgeCacheIndex);
|
||||
}
|
||||
|
||||
// TODO(1399): It should be possible to make room for bit_field3 in the map
|
||||
// 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,
|
||||
// using the supplied storage for the small "bridge".
|
||||
void SetEnumCache(FixedArray* bridge_storage, FixedArray* new_cache);
|
||||
@ -2163,9 +2175,10 @@ class DescriptorArray: public FixedArray {
|
||||
// Constant for denoting key was not found.
|
||||
static const int kNotFound = -1;
|
||||
|
||||
static const int kContentArrayIndex = 0;
|
||||
static const int kEnumerationIndexIndex = 1;
|
||||
static const int kFirstIndex = 2;
|
||||
static const int kBitField3StorageIndex = 0;
|
||||
static const int kContentArrayIndex = 1;
|
||||
static const int kEnumerationIndexIndex = 2;
|
||||
static const int kFirstIndex = 3;
|
||||
|
||||
// The length of the "bridge" to the enum cache.
|
||||
static const int kEnumCacheBridgeLength = 2;
|
||||
@ -2173,7 +2186,8 @@ class DescriptorArray: public FixedArray {
|
||||
static const int kEnumCacheBridgeCacheIndex = 1;
|
||||
|
||||
// Layout description.
|
||||
static const int kContentArrayOffset = FixedArray::kHeaderSize;
|
||||
static const int kBitField3StorageOffset = FixedArray::kHeaderSize;
|
||||
static const int kContentArrayOffset = kBitField3StorageOffset + kPointerSize;
|
||||
static const int kEnumerationIndexOffset = kContentArrayOffset + kPointerSize;
|
||||
static const int kFirstOffset = kEnumerationIndexOffset + kPointerSize;
|
||||
|
||||
@ -3645,6 +3659,13 @@ class Map: public HeapObject {
|
||||
inline byte bit_field2();
|
||||
inline void set_bit_field2(byte value);
|
||||
|
||||
// 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 void set_bit_field3(int value);
|
||||
|
||||
// Tells whether the object in the prototype property will be used
|
||||
// for instances created from this function. If the prototype
|
||||
// property is set to a value that is not a JSObject, the prototype
|
||||
@ -3766,9 +3787,17 @@ class Map: public HeapObject {
|
||||
|
||||
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.
|
||||
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
|
||||
|
||||
// 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.
|
||||
DECL_ACCESSORS(code_cache, Object)
|
||||
|
||||
@ -3894,9 +3923,19 @@ class Map: public HeapObject {
|
||||
static const int kInstanceAttributesOffset = kInstanceSizesOffset + kIntSize;
|
||||
static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize;
|
||||
static const int kConstructorOffset = kPrototypeOffset + kPointerSize;
|
||||
static const int kInstanceDescriptorsOffset =
|
||||
// Storage for instance descriptors is overloaded to also contain additional
|
||||
// map flags when unused (bit_field3). When the map has instance descriptors,
|
||||
// the flags are transferred to the instance descriptor array and accessed
|
||||
// through an extra indirection.
|
||||
// TODO(1399): It should be possible to make room for bit_field3 in the map
|
||||
// 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;
|
||||
static const int kCodeCacheOffset = kInstanceDescriptorsOffset + kPointerSize;
|
||||
static const int kCodeCacheOffset =
|
||||
kInstanceDescriptorsOrBitField3Offset + kPointerSize;
|
||||
static const int kPrototypeTransitionsOffset =
|
||||
kCodeCacheOffset + kPointerSize;
|
||||
static const int kPadStart = kPrototypeTransitionsOffset + kPointerSize;
|
||||
|
@ -1865,9 +1865,11 @@ void V8HeapExplorer::ExtractReferences(HeapObject* obj) {
|
||||
SetInternalReference(obj, entry,
|
||||
"constructor", map->constructor(),
|
||||
Map::kConstructorOffset);
|
||||
SetInternalReference(obj, entry,
|
||||
"descriptors", map->instance_descriptors(),
|
||||
Map::kInstanceDescriptorsOffset);
|
||||
if (!map->instance_descriptors()->IsEmpty()) {
|
||||
SetInternalReference(obj, entry,
|
||||
"descriptors", map->instance_descriptors(),
|
||||
Map::kInstanceDescriptorsOrBitField3Offset);
|
||||
}
|
||||
SetInternalReference(obj, entry,
|
||||
"code_cache", map->code_cache(),
|
||||
Map::kCodeCacheOffset);
|
||||
|
@ -896,9 +896,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
// check for an enum cache. Leave the map in rbx for the subsequent
|
||||
// prototype load.
|
||||
__ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset));
|
||||
__ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
|
||||
__ cmpq(rdx, empty_descriptor_array_value);
|
||||
__ j(equal, &call_runtime);
|
||||
__ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
__ JumpIfSmi(rdx, &call_runtime);
|
||||
|
||||
// Check that there is an enum cache in the non-empty instance
|
||||
// descriptors (rdx). This is the case if the next enumeration
|
||||
@ -941,7 +940,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
|
||||
|
||||
// We got a map in register rax. Get the enumeration cache from it.
|
||||
__ bind(&use_cache);
|
||||
__ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset));
|
||||
__ LoadInstanceDescriptors(rax, rcx);
|
||||
__ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset));
|
||||
__ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset));
|
||||
|
||||
@ -2442,7 +2441,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
|
||||
// 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
|
||||
// negative.
|
||||
__ movq(rbx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset));
|
||||
__ LoadInstanceDescriptors(rbx, rbx);
|
||||
__ movq(rcx, FieldOperand(rbx, FixedArray::kLengthOffset));
|
||||
// rbx: descriptor array
|
||||
// rcx: length of descriptor array
|
||||
|
@ -2601,6 +2601,17 @@ void MacroAssembler::ClampDoubleToUint8(XMMRegister input_reg,
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::LoadInstanceDescriptors(Register map,
|
||||
Register descriptors) {
|
||||
movq(descriptors, FieldOperand(map,
|
||||
Map::kInstanceDescriptorsOrBitField3Offset));
|
||||
Label not_smi;
|
||||
JumpIfNotSmi(descriptors, ¬_smi, Label::kNear);
|
||||
Move(descriptors, isolate()->factory()->empty_descriptor_array());
|
||||
bind(¬_smi);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::DispatchMap(Register obj,
|
||||
Handle<Map> map,
|
||||
Handle<Code> success,
|
||||
|
@ -782,6 +782,8 @@ class MacroAssembler: public Assembler {
|
||||
Register result_reg,
|
||||
Register temp_reg);
|
||||
|
||||
void LoadInstanceDescriptors(Register map, Register descriptors);
|
||||
|
||||
// Abort execution if argument is not a number. Used in debug code.
|
||||
void AbortIfNotNumber(Register object);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user