void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors,
Register scratch) {
- Register temp = descriptors;
- ldr(temp, FieldMemOperand(map, Map::kTransitionsOrBackPointerOffset));
-
- Label ok, fail, load_from_back_pointer;
- CheckMap(temp,
- scratch,
- isolate()->factory()->fixed_array_map(),
- &fail,
- DONT_DO_SMI_CHECK);
- ldr(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset));
- jmp(&ok);
-
- bind(&fail);
- CompareRoot(temp, Heap::kUndefinedValueRootIndex);
- b(ne, &load_from_back_pointer);
- mov(descriptors, Operand(FACTORY->empty_descriptor_array()));
- jmp(&ok);
-
- bind(&load_from_back_pointer);
- ldr(temp, FieldMemOperand(temp, Map::kTransitionsOrBackPointerOffset));
- ldr(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset));
-
- bind(&ok);
+ ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
}
}
PropertyAttributes attribs = static_cast<PropertyAttributes>(
DONT_ENUM | DONT_DELETE | READ_ONLY);
- Map::SetDescriptors(map, descriptors);
+ map->set_instance_descriptors(*descriptors);
{ // Add length.
CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
}
PropertyAttributes attribs = static_cast<PropertyAttributes>(
DONT_ENUM | DONT_DELETE);
- Map::SetDescriptors(map, descriptors);
+ map->set_instance_descriptors(*descriptors);
{ // Add length.
CallbacksDescriptor d(*factory()->length_symbol(), *length, attribs);
Handle<Foreign> array_length(factory->NewForeign(&Accessors::ArrayLength));
PropertyAttributes attribs = static_cast<PropertyAttributes>(
DONT_ENUM | DONT_DELETE);
- Map::SetDescriptors(initial_map, array_descriptors);
+ initial_map->set_instance_descriptors(*array_descriptors);
{ // Add length.
CallbacksDescriptor d(*factory->length_symbol(), *array_length, attribs);
factory->NewForeign(&Accessors::StringLength));
PropertyAttributes attribs = static_cast<PropertyAttributes>(
DONT_ENUM | DONT_DELETE | READ_ONLY);
- Map::SetDescriptors(string_map, string_descriptors);
+ string_map->set_instance_descriptors(*string_descriptors);
{ // Add length.
CallbacksDescriptor d(*factory->length_symbol(), *string_length, attribs);
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 5);
DescriptorArray::WhitenessWitness witness(*descriptors);
- Map::SetDescriptors(initial_map, descriptors);
+ initial_map->set_instance_descriptors(*descriptors);
{
// ECMA-262, section 15.10.7.1.
// Create the descriptor array for the arguments object.
Handle<DescriptorArray> descriptors = factory->NewDescriptorArray(0, 3);
DescriptorArray::WhitenessWitness witness(*descriptors);
- Map::SetDescriptors(map, descriptors);
+ map->set_instance_descriptors(*descriptors);
{ // length
FieldDescriptor d(*factory->length_symbol(), 0, DONT_ENUM);
factory()->NewForeign(&Accessors::ScriptEvalFromFunctionName));
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- Map::SetDescriptors(script_map, script_descriptors);
+ script_map->set_instance_descriptors(*script_descriptors);
{
CallbacksDescriptor d(
&Accessors::ArrayLength));
PropertyAttributes attribs = static_cast<PropertyAttributes>(
DONT_ENUM | DONT_DELETE);
- Map::SetDescriptors(initial_map, array_descriptors);
+ initial_map->set_instance_descriptors(*array_descriptors);
{ // Add length.
CallbacksDescriptor d(
Handle<DescriptorArray> reresult_descriptors =
factory()->NewDescriptorArray(0, 3);
DescriptorArray::WhitenessWitness witness(*reresult_descriptors);
- Map::SetDescriptors(initial_map, reresult_descriptors);
+ initial_map->set_instance_descriptors(*reresult_descriptors);
{
JSFunction* array_function = native_context()->array_function();
#endif
MaybeObject* result = map_space_->AllocateRaw(Map::kSize);
if (result->IsFailure()) old_gen_exhausted_ = true;
-#ifdef DEBUG
- if (!result->IsFailure()) {
- // Maps have their own alignment.
- CHECK((reinterpret_cast<intptr_t>(result) & kMapAlignmentMask) ==
- static_cast<intptr_t>(kHeapObjectTag));
- }
-#endif
return result;
}
map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
map->init_back_pointer(undefined_value());
map->set_unused_property_fields(0);
+ map->set_instance_descriptors(empty_descriptor_array());
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
int bit_field3 = Map::EnumLengthBits::encode(Map::kInvalidEnumCache) |
map->set_bit_field3(bit_field3);
map->set_elements_kind(elements_kind);
- // If the map object is aligned fill the padding area with Smi 0 objects.
- if (Map::kPadStart < Map::kSize) {
- memset(reinterpret_cast<byte*>(map) + Map::kPadStart - kHeapObjectTag,
- 0,
- Map::kSize - Map::kPadStart);
- }
return map;
}
// Fix the instance_descriptors for the existing maps.
meta_map()->set_code_cache(empty_fixed_array());
meta_map()->init_back_pointer(undefined_value());
+ meta_map()->set_instance_descriptors(empty_descriptor_array());
fixed_array_map()->set_code_cache(empty_fixed_array());
fixed_array_map()->init_back_pointer(undefined_value());
+ fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
oddball_map()->set_code_cache(empty_fixed_array());
oddball_map()->init_back_pointer(undefined_value());
+ oddball_map()->set_instance_descriptors(empty_descriptor_array());
// Fix prototype object for existing maps.
meta_map()->set_prototype(null_value());
if (HasDuplicates(descriptors)) {
fun->shared()->ForbidInlineConstructor();
} else {
- MaybeObject* maybe_failure = map->InitializeDescriptors(descriptors);
- if (maybe_failure->IsFailure()) return maybe_failure;
+ map->InitializeDescriptors(descriptors);
map->set_pre_allocated_property_fields(count);
map->set_unused_property_fields(in_object_properties - count);
}
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors) {
- Register temp = descriptors;
- mov(temp, FieldOperand(map, Map::kTransitionsOrBackPointerOffset));
-
- Label ok, fail, load_from_back_pointer;
- CheckMap(temp,
- isolate()->factory()->fixed_array_map(),
- &fail,
- DONT_DO_SMI_CHECK);
- mov(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset));
- jmp(&ok);
-
- bind(&fail);
- cmp(temp, isolate()->factory()->undefined_value());
- j(not_equal, &load_from_back_pointer, Label::kNear);
- mov(descriptors, isolate()->factory()->empty_descriptor_array());
- jmp(&ok);
-
- bind(&load_from_back_pointer);
- mov(temp, FieldOperand(temp, Map::kTransitionsOrBackPointerOffset));
- mov(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset));
-
- bind(&ok);
+ mov(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
}
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors,
Register scratch) {
- Register temp = descriptors;
- lw(temp, FieldMemOperand(map, Map::kTransitionsOrBackPointerOffset));
-
- Label ok, fail, load_from_back_pointer;
- CheckMap(temp,
- scratch,
- isolate()->factory()->fixed_array_map(),
- &fail,
- DONT_DO_SMI_CHECK);
- lw(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset));
- jmp(&ok);
-
- bind(&fail);
- LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
- Branch(&load_from_back_pointer, ne, temp, Operand(scratch));
- LoadRoot(descriptors, Heap::kEmptyDescriptorArrayRootIndex);
- jmp(&ok);
-
- bind(&load_from_back_pointer);
- lw(temp, FieldMemOperand(temp, Map::kTransitionsOrBackPointerOffset));
- lw(descriptors, FieldMemOperand(temp, TransitionArray::kDescriptorsOffset));
-
- bind(&ok);
+ lw(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
}
}
-DescriptorArray* Map::instance_descriptors() {
- if (HasTransitionArray()) return transitions()->descriptors();
- Object* back_pointer = GetBackPointer();
- if (!back_pointer->IsMap()) return GetHeap()->empty_descriptor_array();
- return Map::cast(back_pointer)->instance_descriptors();
-}
-
-
-enum TransitionsKind { DESCRIPTORS_HOLDER, FULL_TRANSITION_ARRAY };
-
-
// If the descriptor is using the empty transition array, install a new empty
// transition array that will have place for an element transition.
-static MaybeObject* EnsureHasTransitionArray(Map* map, TransitionsKind kind) {
+static MaybeObject* EnsureHasTransitionArray(Map* map) {
TransitionArray* transitions;
MaybeObject* maybe_transitions;
if (!map->HasTransitionArray()) {
- if (kind == FULL_TRANSITION_ARRAY) {
- maybe_transitions = TransitionArray::Allocate(0);
- } else {
- maybe_transitions = TransitionArray::AllocateDescriptorsHolder();
- }
+ maybe_transitions = TransitionArray::Allocate(0);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
transitions->set_back_pointer_storage(map->GetBackPointer());
- } else if (kind == FULL_TRANSITION_ARRAY &&
- !map->transitions()->IsFullTransitionArray()) {
+ } else if (!map->transitions()->IsFullTransitionArray()) {
maybe_transitions = map->transitions()->ExtendToFullTransitionArray();
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
} else {
}
-MaybeObject* Map::SetDescriptors(DescriptorArray* value) {
- ASSERT(!is_shared());
- MaybeObject* maybe_failure =
- EnsureHasTransitionArray(this, DESCRIPTORS_HOLDER);
- if (maybe_failure->IsFailure()) return maybe_failure;
-
- ASSERT(NumberOfOwnDescriptors() <= value->number_of_descriptors());
- transitions()->set_descriptors(value);
- return this;
-}
-
-
-MaybeObject* Map::InitializeDescriptors(DescriptorArray* descriptors) {
+void Map::InitializeDescriptors(DescriptorArray* descriptors) {
int len = descriptors->number_of_descriptors();
#ifdef DEBUG
ASSERT(len <= DescriptorArray::kMaxNumberOfDescriptors);
}
#endif
- MaybeObject* maybe_failure = SetDescriptors(descriptors);
- if (maybe_failure->IsFailure()) return maybe_failure;
-
+ set_instance_descriptors(descriptors);
SetNumberOfOwnDescriptors(len);
- return this;
}
+ACCESSORS(Map, instance_descriptors, DescriptorArray, kDescriptorsOffset)
SMI_ACCESSORS(Map, bit_field3, kBitField3Offset)
Map* target,
SimpleTransitionFlag flag) {
if (HasTransitionArray()) return transitions()->CopyInsert(key, target);
- return TransitionArray::NewWith(
- flag, key, target, instance_descriptors(), GetBackPointer());
+ return TransitionArray::NewWith(flag, key, target, GetBackPointer());
}
MaybeObject* Map::set_elements_transition_map(Map* transitioned_map) {
- DescriptorArray* descriptors = instance_descriptors();
- MaybeObject* allow_elements =
- EnsureHasTransitionArray(this, FULL_TRANSITION_ARRAY);
+ MaybeObject* allow_elements = EnsureHasTransitionArray(this);
if (allow_elements->IsFailure()) return allow_elements;
- transitions()->set_descriptors(descriptors);
transitions()->set_elements_transition(transitioned_map);
return this;
}
MaybeObject* Map::SetPrototypeTransitions(FixedArray* proto_transitions) {
- DescriptorArray* descriptors = instance_descriptors();
- MaybeObject* allow_prototype =
- EnsureHasTransitionArray(this, FULL_TRANSITION_ARRAY);
+ MaybeObject* allow_prototype = EnsureHasTransitionArray(this);
if (allow_prototype->IsFailure()) return allow_prototype;
#ifdef DEBUG
if (HasPrototypeTransitions()) {
ZapPrototypeTransitions();
}
#endif
- transitions()->set_descriptors(descriptors);
transitions()->SetPrototypeTransitions(proto_transitions);
return this;
}
}
PrintF(out, " - back pointer: ");
GetBackPointer()->ShortPrint(out);
- PrintF(out, "\n - instance descriptors %i #%i %i: ",
+ PrintF(out, "\n - instance descriptors %i #%i: ",
owns_descriptors(),
- NumberOfOwnDescriptors(),
- StoresOwnDescriptors());
+ NumberOfOwnDescriptors());
instance_descriptors()->ShortPrint(out);
if (HasTransitionArray()) {
PrintF(out, "\n - transitions: ");
Heap* heap, TransitionArray* transitions) {
if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return;
- // Skip recording the descriptors_pointer slot since the cell space
- // is not compacted and descriptors are referenced through a cell.
- Object** descriptors_slot = transitions->GetDescriptorsSlot();
- HeapObject* descriptors = HeapObject::cast(*descriptors_slot);
- StaticVisitor::MarkObject(heap, descriptors);
- heap->mark_compact_collector()->RecordSlot(
- descriptors_slot, descriptors_slot, descriptors);
-
// Simple transitions do not have keys nor prototype transitions.
if (transitions->IsSimpleTransition()) return;
Map* old_target = old_map->GetTransition(transition_index);
Object* result;
- // To sever a transition to a map with which the descriptors are shared, the
- // larger map (more descriptors) needs to store its own descriptors array.
- // Both sides of the severed chain need to have their own descriptors pointer
- // to store distinct descriptor arrays.
-
- // If the old_target did not yet store its own descriptors, the new
- // descriptors pointer is created for the old_target by temporarily clearing
- // the back pointer and setting its descriptor array.
-
- // This phase is executed before creating the new map since it requires
- // allocation that may fail.
- if (!old_target->StoresOwnDescriptors()) {
- DescriptorArray* old_descriptors = old_map->instance_descriptors();
- MaybeObject* maybe_failure = old_target->SetDescriptors(old_descriptors);
- if (maybe_failure->IsFailure()) return maybe_failure;
- }
-
MaybeObject* maybe_result =
ConvertDescriptorToField(name, new_value, attributes);
if (!maybe_result->To(&result)) return maybe_result;
old_target->instance_descriptors() == old_map->instance_descriptors()) {
// Since the conversion above generated a new fast map with an additional
// property which can be shared as well, install this descriptor pointer
- // along the entire chain of smaller maps; and remove the transition array
- // that is only in place to hold the descriptor array in the new map.
+ // along the entire chain of smaller maps.
Map* map;
DescriptorArray* new_descriptors = new_map->instance_descriptors();
DescriptorArray* old_descriptors = old_map->instance_descriptors();
!current->IsUndefined();
current = map->GetBackPointer()) {
map = Map::cast(current);
- if (!map->HasTransitionArray()) break;
- TransitionArray* transitions = map->transitions();
- if (transitions->descriptors() != old_descriptors) break;
+ if (map->instance_descriptors() != old_descriptors) break;
map->SetEnumLength(Map::kInvalidEnumCache);
- transitions->set_descriptors(new_descriptors);
+ map->set_instance_descriptors(new_descriptors);
}
old_map->set_owns_descriptors(false);
- new_map->ClearTransitions(GetHeap());
}
old_map->SetTransition(transition_index, new_map);
new_descriptors->CopyFrom(i, *descriptors, i, witness);
}
- Map::SetDescriptors(map, new_descriptors);
+ map->set_instance_descriptors(*new_descriptors);
}
}
-void Map::SetDescriptors(Handle<Map> map,
- Handle<DescriptorArray> descriptors) {
- Isolate* isolate = map->GetIsolate();
- CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors));
-}
-
-
int Map::NumberOfDescribedProperties(DescriptorFlag which,
PropertyAttributes filter) {
int result = 0;
new_descriptors->Append(descriptor, witness);
- // If the source descriptors had an enum cache we copy it. This ensures that
- // the maps to which we push the new descriptor array back can rely on a
- // cache always being available once it is set. If the map has more
- // enumerated descriptors than available in the original cache, the cache
- // will be lazily replaced by the extended cache when needed.
- if (descriptors->HasEnumCache()) {
- new_descriptors->CopyEnumCacheFrom(descriptors);
- }
+ if (old_size > 0) {
+ // If the source descriptors had an enum cache we copy it. This ensures
+ // that the maps to which we push the new descriptor array back can rely
+ // on a cache always being available once it is set. If the map has more
+ // enumerated descriptors than available in the original cache, the cache
+ // will be lazily replaced by the extended cache when needed.
+ if (descriptors->HasEnumCache()) {
+ new_descriptors->CopyEnumCacheFrom(descriptors);
+ }
- Map* map;
- // Replace descriptors by new_descriptors in all maps that share it.
- for (Object* current = GetBackPointer();
- !current->IsUndefined();
- current = map->GetBackPointer()) {
- map = Map::cast(current);
- if (!map->HasTransitionArray()) break;
- TransitionArray* transitions = map->transitions();
- if (transitions->descriptors() != descriptors) break;
- transitions->set_descriptors(new_descriptors);
- }
+ Map* map;
+ // Replace descriptors by new_descriptors in all maps that share it.
+ for (Object* current = GetBackPointer();
+ !current->IsUndefined();
+ current = map->GetBackPointer()) {
+ map = Map::cast(current);
+ if (map->instance_descriptors() != descriptors) break;
+ map->set_instance_descriptors(new_descriptors);
+ }
- transitions->set_descriptors(new_descriptors);
+ set_instance_descriptors(new_descriptors);
+ }
}
- set_transitions(transitions);
result->SetBackPointer(this);
- set_owns_descriptors(false);
-
- result->SetNumberOfOwnDescriptors(new_descriptors->number_of_descriptors());
+ result->InitializeDescriptors(new_descriptors);
ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1);
+ set_transitions(transitions);
+ set_owns_descriptors(false);
+
return result;
}
MaybeObject* maybe_result = CopyDropDescriptors();
if (!maybe_result->To(&result)) return maybe_result;
- // Unless we are creating a map with no descriptors and no back pointer, we
- // insert the descriptor array locally.
- if (!descriptors->IsEmpty()) {
- MaybeObject* maybe_failure = result->SetDescriptors(descriptors);
- if (maybe_failure->IsFailure()) return maybe_failure;
- result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors());
- }
+ result->InitializeDescriptors(descriptors);
if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) {
TransitionArray* transitions;
MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag);
if (!maybe_transitions->To(&transitions)) return maybe_transitions;
- if (descriptors->IsEmpty()) {
- if (owns_descriptors()) {
- // If the copied map has no added fields, and the parent map owns its
- // descriptors, those descriptors have to be empty. In that case,
- // transfer ownership of the descriptors to the new child.
- ASSERT(instance_descriptors()->IsEmpty());
- set_owns_descriptors(false);
- } else {
- // If the parent did not own its own descriptors, it may share a larger
- // descriptors array already. In that case, force a split by setting
- // the descriptor array of the new map to the empty descriptor array.
- MaybeObject* maybe_failure =
- result->SetDescriptors(GetHeap()->empty_descriptor_array());
- if (maybe_failure->IsFailure()) return maybe_failure;
- }
- }
-
set_transitions(transitions);
result->SetBackPointer(this);
}
ASSERT(kind != elements_kind());
}
- if (flag == INSERT_TRANSITION && owns_descriptors()) {
+ bool insert_transition =
+ flag == INSERT_TRANSITION && !HasElementsTransition();
+
+ if (insert_transition && owns_descriptors()) {
// In case the map owned its own descriptors, share the descriptors and
// transfer ownership to the new map.
Map* new_map;
if (added_elements->IsFailure()) return added_elements;
new_map->set_elements_kind(kind);
+ new_map->InitializeDescriptors(instance_descriptors());
new_map->SetBackPointer(this);
- new_map->SetNumberOfOwnDescriptors(NumberOfOwnDescriptors());
set_owns_descriptors(false);
return new_map;
}
Map* new_map;
MaybeObject* maybe_new_map = Copy();
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
- ASSERT(new_map->NumberOfOwnDescriptors() == NumberOfOwnDescriptors());
+
new_map->set_elements_kind(kind);
- if (flag == INSERT_TRANSITION && !HasElementsTransition()) {
- // Map::Copy does not store the descriptor array in case it is empty, since
- // it does not insert a back pointer; implicitly indicating that its
- // descriptor array is empty. Since in this case we do want to insert a back
- // pointer, we have to manually set the empty descriptor array to force a
- // split.
- if (!new_map->StoresOwnDescriptors()) {
- ASSERT(new_map->NumberOfOwnDescriptors() == 0);
- MaybeObject* maybe_failure =
- new_map->SetDescriptors(GetHeap()->empty_descriptor_array());
- if (maybe_failure->IsFailure()) return maybe_failure;
- }
+ if (insert_transition) {
MaybeObject* added_elements = set_elements_transition_map(new_map);
if (added_elements->IsFailure()) return added_elements;
-
new_map->SetBackPointer(this);
}
// Clear a possible back pointer in case the transition leads to a dead map.
// Return true in case a back pointer has been cleared and false otherwise.
-static bool ClearBackPointer(Heap* heap,
- Map* target,
- DescriptorArray* descriptors,
- bool* descriptors_owner_died) {
+static bool ClearBackPointer(Heap* heap, Map* target) {
if (Marking::MarkBitFrom(target).Get()) return false;
- if (target->instance_descriptors() == descriptors) {
- *descriptors_owner_died = true;
- }
target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
return true;
}
int transition_index = 0;
- DescriptorArray* descriptors = t->descriptors();
+ DescriptorArray* descriptors = instance_descriptors();
bool descriptors_owner_died = false;
// Compact all live descriptors to the left.
for (int i = 0; i < t->number_of_transitions(); ++i) {
Map* target = t->GetTarget(i);
- if (!ClearBackPointer(heap, target, descriptors, &descriptors_owner_died)) {
+ if (ClearBackPointer(heap, target)) {
+ if (target->instance_descriptors() == descriptors) {
+ descriptors_owner_died = true;
+ descriptors_owner_died = true;
+ }
+ } else {
if (i != transition_index) {
String* key = t->GetKey(i);
t->SetKey(transition_index, key);
}
if (t->HasElementsTransition() &&
- ClearBackPointer(heap,
- t->elements_transition(),
- descriptors,
- &descriptors_owner_died)) {
+ ClearBackPointer(heap, t->elements_transition())) {
+ if (t->elements_transition()->instance_descriptors() == descriptors) {
+ descriptors_owner_died = true;
+ }
t->ClearElementsTransition();
} else {
// If there are no transitions to be cleared, return.
TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
} else {
- t->set_descriptors(heap->empty_descriptor_array());
+ ASSERT(descriptors == GetHeap()->empty_descriptor_array());
}
}
descriptors->Sort();
- MaybeObject* maybe_failure = new_map->InitializeDescriptors(descriptors);
- if (maybe_failure->IsFailure()) return maybe_failure;
+ new_map->InitializeDescriptors(descriptors);
new_map->set_unused_property_fields(unused_property_fields);
// Transform the object.
// DescriptorArrays are fixed arrays used to hold instance descriptors.
// The format of the these objects is:
-// [0]: Either Smi(0) if uninitialized, or a pointer to small fixed array:
+// [0]: Number of descriptors
+// [1]: Either Smi(0) if uninitialized, or a pointer to small fixed array:
// [0]: pointer to fixed array with enum cache
// [1]: either Smi(0) or pointer to fixed array with indices
-// [1]: first key
-// [length() - kDescriptorSize]: last key
+// [2]: first key
+// [2 + number of descriptors * kDescriptorSize]: start of slack
class DescriptorArray: public FixedArray {
public:
// WhitenessWitness is used to prove that a descriptor array is white
static bool IsValidElementsTransition(ElementsKind from_kind,
ElementsKind to_kind);
- bool StoresOwnDescriptors() { return HasTransitionArray(); }
inline bool HasTransitionArray();
inline bool HasElementsTransition();
inline Map* elements_transition_map();
inline JSFunction* unchecked_constructor();
// [instance descriptors]: describes the object.
- inline DescriptorArray* instance_descriptors();
- MUST_USE_RESULT inline MaybeObject* SetDescriptors(
- DescriptorArray* descriptors);
- static void SetDescriptors(Handle<Map> map,
- Handle<DescriptorArray> descriptors);
- MUST_USE_RESULT inline MaybeObject* InitializeDescriptors(
- DescriptorArray* descriptors);
+ DECL_ACCESSORS(instance_descriptors, DescriptorArray)
+ inline void InitializeDescriptors(DescriptorArray* descriptors);
// [stub cache]: contains stubs compiled for this map.
DECL_ACCESSORS(code_cache, Object)
// indirection.
static const int kTransitionsOrBackPointerOffset =
kConstructorOffset + kPointerSize;
- static const int kCodeCacheOffset =
+ static const int kDescriptorsOffset =
kTransitionsOrBackPointerOffset + kPointerSize;
+ static const int kCodeCacheOffset =
+ kDescriptorsOffset + kPointerSize;
static const int kBitField3Offset = kCodeCacheOffset + kPointerSize;
- static const int kPadStart = kBitField3Offset + kPointerSize;
- static const int kSize = MAP_POINTER_ALIGN(kPadStart);
+ static const int kSize = kBitField3Offset + kPointerSize;
// Layout of pointer fields. Heap iteration code relies on them
// being continuously allocated.
Map::kConstructorOffset);
if (map->HasTransitionArray()) {
TransitionArray* transitions = map->transitions();
- DescriptorArray* descriptors = transitions->descriptors();
- TagObject(descriptors, "(map descriptors)");
- SetInternalReference(transitions, entry,
- "descriptors", descriptors,
- TransitionArray::kDescriptorsOffset);
Object* back_pointer = transitions->back_pointer_storage();
TagObject(transitions->back_pointer_storage(), "(back pointer)");
"backpointer", back_pointer,
Map::kTransitionsOrBackPointerOffset);
}
+ DescriptorArray* descriptors = map->instance_descriptors();
+ TagObject(descriptors, "(map descriptors)");
+ SetInternalReference(map, entry,
+ "descriptors", descriptors,
+ Map::kDescriptorsOffset);
+
SetInternalReference(map, entry,
"code_cache", map->code_cache(),
Map::kCodeCacheOffset);
#define ASSERT_OBJECT_ALIGNED(address) \
ASSERT((OffsetFrom(address) & kObjectAlignmentMask) == 0)
-#define ASSERT_MAP_ALIGNED(address) \
- ASSERT((OffsetFrom(address) & kMapAlignmentMask) == 0)
-
#define ASSERT_OBJECT_SIZE(size) \
ASSERT((0 < size) && (size <= Page::kMaxNonCodeHeapObjectSize))
static const size_t kHeaderSize = kWriteBarrierCounterOffset + kPointerSize;
static const int kBodyOffset =
- CODE_POINTER_ALIGN(MAP_POINTER_ALIGN(kHeaderSize + Bitmap::kSize));
+ CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
// The start offset of the object area in a page. Aligned to both maps and
// code alignment to be suitable for both. Also aligned to 32 words because
}
-Object** TransitionArray::GetDescriptorsSlot() {
- return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
- kDescriptorsOffset);
-}
-
-
-DescriptorArray* TransitionArray::descriptors() {
- return DescriptorArray::cast(get(kDescriptorsIndex));
-}
-
-
-void TransitionArray::set_descriptors(DescriptorArray* descriptors) {
- ASSERT(descriptors->IsDescriptorArray());
- set(kDescriptorsIndex, descriptors);
-}
-
-
Object* TransitionArray::back_pointer_storage() {
return get(kBackPointerStorageIndex);
}
MaybeObject* TransitionArray::NewWith(SimpleTransitionFlag flag,
String* key,
Map* target,
- DescriptorArray* descriptors,
Object* back_pointer) {
TransitionArray* result;
MaybeObject* maybe_result;
result->NoIncrementalWriteBarrierSet(0, key, target);
}
result->set_back_pointer_storage(back_pointer);
- result->set_descriptors(descriptors);
return result;
}
-MaybeObject* TransitionArray::AllocateDescriptorsHolder() {
- return AllocateRaw(kDescriptorsHolderSize);
-}
-
-
MaybeObject* TransitionArray::ExtendToFullTransitionArray() {
ASSERT(!IsFullTransitionArray());
int nof = number_of_transitions();
result->NoIncrementalWriteBarrierCopyFrom(this, kSimpleTransitionIndex, 0);
}
- result->set_descriptors(descriptors());
result->set_back_pointer_storage(back_pointer_storage());
return result;
}
maybe_array = TransitionArray::Allocate(new_size);
if (!maybe_array->To(&result)) return maybe_array;
- result->set_descriptors(descriptors());
-
if (HasElementsTransition()) {
result->set_elements_transition(elements_transition());
}
// TransitionArrays are fixed arrays used to hold map transitions for property,
-// constant, and element changes.
-// The format of the these objects is:
-// [0] Descriptor array
-// [1] Undefined or back pointer map
-// [2] Smi(0) or elements transition map
-// [3] Smi(0) or fixed array of prototype transitions
-// [4] First transition
+// constant, and element changes. They can either be simple transition arrays
+// that store a single property transition, or a full transition array that has
+// space for elements transitions, prototype transitions and multiple property
+// transitons. The details related to property transitions are accessed in the
+// descriptor array of the target map. In the case of a simple transition, the
+// key is also read from the descriptor array of the target map.
+//
+// The simple format of the these objects is:
+// [0] Undefined or back pointer map
+// [1] Single transition
+//
+// The full format is:
+// [0] Undefined or back pointer map
+// [1] Smi(0) or elements transition map
+// [2] Smi(0) or fixed array of prototype transitions
+// [3] First transition
// [length() - kTransitionSize] Last transition
class TransitionArray: public FixedArray {
public:
inline bool HasElementsTransition();
inline void ClearElementsTransition();
- inline Object** GetDescriptorsSlot();
- inline DescriptorArray* descriptors();
- inline void set_descriptors(DescriptorArray* descriptors);
-
inline Object* back_pointer_storage();
inline void set_back_pointer_storage(
Object* back_pointer,
SimpleTransitionFlag flag,
String* key,
Map* target,
- DescriptorArray* descriptors,
Object* back_pointer);
- static MUST_USE_RESULT MaybeObject* AllocateDescriptorsHolder();
-
MUST_USE_RESULT MaybeObject* ExtendToFullTransitionArray();
// Copy the transition array, inserting a new transition.
// Allocates a TransitionArray.
MUST_USE_RESULT static MaybeObject* Allocate(int number_of_transitions);
- bool IsDescriptorsHolder() { return length() == kDescriptorsHolderSize; }
bool IsSimpleTransition() { return length() == kSimpleTransitionSize; }
bool IsFullTransitionArray() { return length() >= kFirstIndex; }
// Constant for denoting key was not found.
static const int kNotFound = -1;
- static const int kDescriptorsIndex = 0;
- static const int kBackPointerStorageIndex = 1;
- static const int kDescriptorsHolderSize = 2;
+ static const int kBackPointerStorageIndex = 0;
// Layout for full transition arrays.
- static const int kElementsTransitionIndex = 2;
- static const int kPrototypeTransitionsIndex = 3;
- static const int kFirstIndex = 4;
+ static const int kElementsTransitionIndex = 1;
+ static const int kPrototypeTransitionsIndex = 2;
+ static const int kFirstIndex = 3;
// Layout for simple transition arrays.
- static const int kSimpleTransitionTarget = 2;
- static const int kSimpleTransitionSize = 3;
+ static const int kSimpleTransitionTarget = 1;
+ static const int kSimpleTransitionSize = 2;
static const int kSimpleTransitionIndex = 0;
STATIC_ASSERT(kSimpleTransitionIndex != kNotFound);
- static const int kDescriptorsOffset = FixedArray::kHeaderSize;
- static const int kBackPointerStorageOffset = kDescriptorsOffset +
- kPointerSize;
+ static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
// Layout for the full transition array header.
static const int kElementsTransitionOffset = kBackPointerStorageOffset +
const intptr_t kDoubleAlignment = 8;
const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1;
-// Desired alignment for maps.
-#if V8_HOST_ARCH_64_BIT
-const intptr_t kMapAlignmentBits = kObjectAlignmentBits;
-#else
-const intptr_t kMapAlignmentBits = kObjectAlignmentBits + 3;
-#endif
-const intptr_t kMapAlignment = (1 << kMapAlignmentBits);
-const intptr_t kMapAlignmentMask = kMapAlignment - 1;
-
// Desired alignment for generated code is 32 bytes (to improve cache line
// utilization).
const int kCodeAlignmentBits = 5;
#define POINTER_SIZE_ALIGN(value) \
(((value) + kPointerAlignmentMask) & ~kPointerAlignmentMask)
-// MAP_POINTER_ALIGN returns the value aligned as a map pointer.
-#define MAP_POINTER_ALIGN(value) \
- (((value) + kMapAlignmentMask) & ~kMapAlignmentMask)
-
// CODE_POINTER_ALIGN returns the value aligned as a generated code segment.
#define CODE_POINTER_ALIGN(value) \
(((value) + kCodeAlignmentMask) & ~kCodeAlignmentMask)
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors) {
- Register temp = descriptors;
- movq(temp, FieldOperand(map, Map::kTransitionsOrBackPointerOffset));
-
- Label ok, fail, load_from_back_pointer;
- CheckMap(temp,
- isolate()->factory()->fixed_array_map(),
- &fail,
- DONT_DO_SMI_CHECK);
- movq(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset));
- jmp(&ok);
-
- bind(&fail);
- CompareRoot(temp, Heap::kUndefinedValueRootIndex);
- j(not_equal, &load_from_back_pointer, Label::kNear);
- Move(descriptors, isolate()->factory()->empty_descriptor_array());
- jmp(&ok);
-
- bind(&load_from_back_pointer);
- movq(temp, FieldOperand(temp, Map::kTransitionsOrBackPointerOffset));
- movq(descriptors, FieldOperand(temp, TransitionArray::kDescriptorsOffset));
-
- bind(&ok);
+ movq(descriptors, FieldOperand(map, Map::kDescriptorsOffset));
}
Handle<DescriptorArray> new_descriptors = FACTORY->NewDescriptorArray(0, 1);
v8::internal::DescriptorArray::WhitenessWitness witness(*new_descriptors);
- v8::internal::Map::SetDescriptors(map, new_descriptors);
+ map->set_instance_descriptors(*new_descriptors);
CallbacksDescriptor d(*name,
*foreign,
CHECK_NE(NULL, map);
const v8::HeapGraphNode* own_descriptors = GetProperty(
map, v8::HeapGraphEdge::kInternal, "descriptors");
- CHECK_EQ(NULL, own_descriptors);
+ CHECK_NE(NULL, own_descriptors);
const v8::HeapGraphNode* own_transitions = GetProperty(
map, v8::HeapGraphEdge::kInternal, "transitions");
CHECK_EQ(NULL, own_transitions);
-
- const v8::HeapGraphNode* back_pointer_map =
- GetProperty(map, v8::HeapGraphEdge::kInternal, "backpointer");
- CHECK_NE(NULL, back_pointer_map);
- const v8::HeapGraphNode* descriptors = GetProperty(
- back_pointer_map, v8::HeapGraphEdge::kInternal, "descriptors");
- CHECK_NE(NULL, descriptors);
- const v8::HeapGraphNode* transitions = GetProperty(
- back_pointer_map, v8::HeapGraphEdge::kInternal, "transitions");
- CHECK_NE(NULL, transitions);
}