Index: src/transitions.h |
diff --git a/src/transitions.h b/src/transitions.h |
index 648559ba4cd2652fd836b691e81c9fbb226a48d9..999ad86c558c176f8bb112df840b626f81c36cbb 100644 |
--- a/src/transitions.h |
+++ b/src/transitions.h |
@@ -16,98 +16,47 @@ |
// TransitionArrays are fixed arrays used to hold map transitions for property, |
-// constant, and element changes. "Simple" transitions storing only a single |
-// property transition are stored inline (i.e. the target map is stored |
-// directly); otherwise a full transition array is used that has |
+// constant, and element changes. They can either be simple transition arrays |
+// that store a single property transition, or a full transition array that has |
// 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. |
// |
-// This class provides a static interface that operates directly on maps |
-// and handles the distinction between simple and full transitions storage. |
+// The simple format of the these objects is: |
+// [0] Undefined or back pointer map |
+// [1] Single transition |
// |
// The full format is: |
-// [0] Smi(0) or fixed array of prototype transitions |
-// [1] Number of transitions |
-// [2] First transition |
-// [2 + number of transitions * kTransitionSize]: start of slack |
+// [0] Undefined or back pointer map |
+// [1] Smi(0) or fixed array of prototype transitions |
+// [2] Number of transitions |
+// [3] First transition |
+// [3 + number of transitions * kTransitionSize]: start of slack |
class TransitionArray: public FixedArray { |
public: |
- // Insert a new transition into |map|'s transition array, extending it |
- // as necessary. |
- static void Insert(Handle<Map> map, Handle<Name> name, Handle<Map> target, |
- SimpleTransitionFlag flag); |
- |
- static Map* SearchTransition(Map* map, PropertyKind kind, Name* name, |
- PropertyAttributes attributes); |
- |
- static Map* SearchSpecial(Map* map, Symbol* name); |
- |
- static Handle<Map> FindTransitionToField(Handle<Map> map, Handle<Name> name); |
- |
- static Handle<String> ExpectedTransitionKey(Handle<Map> map); |
- |
- static Handle<Map> ExpectedTransitionTarget(Handle<Map> map) { |
- DCHECK(!ExpectedTransitionKey(map).is_null()); |
- return Handle<Map>(GetSimpleTransition(map->raw_transitions())); |
- } |
- // Returns true if |raw_transition| can be overwritten with a simple |
- // transition (because it's either uninitialized, or has been cleared). |
- static inline bool CanStoreSimpleTransition(Object* raw_transition) { |
- return raw_transition->IsSmi() || |
- (raw_transition->IsWeakCell() && |
- WeakCell::cast(raw_transition)->cleared()); |
- } |
- static inline bool IsSimpleTransition(Object* raw_transition) { |
- DCHECK(!raw_transition->IsWeakCell() || |
- WeakCell::cast(raw_transition)->cleared() || |
- WeakCell::cast(raw_transition)->value()->IsMap()); |
- return raw_transition->IsWeakCell() && |
- !WeakCell::cast(raw_transition)->cleared(); |
- } |
- static inline Map* GetSimpleTransition(Object* raw_transition) { |
- DCHECK(IsSimpleTransition(raw_transition)); |
- return Map::cast(WeakCell::cast(raw_transition)->value()); |
- } |
- static inline bool IsFullTransitionArray(Object* raw_transitions) { |
- return raw_transitions->IsTransitionArray(); |
- } |
- |
- // The size of transition arrays are limited so they do not end up in large |
- // object space. Otherwise ClearNonLiveReferences would leak memory while |
- // applying in-place right trimming. |
- static bool CanHaveMoreTransitions(Handle<Map> map); |
- |
- // ===== PROTOTYPE TRANSITIONS ===== |
- // When you set the prototype of an object using the __proto__ accessor you |
- // need a new map for the object (the prototype is stored in the map). In |
- // order not to multiply maps unnecessarily we store these as transitions in |
- // the original map. That way we can transition to the same map if the same |
- // prototype is set, rather than creating a new map every time. The |
- // transitions are in the form of a map where the keys are prototype objects |
- // and the values are the maps they transition to. |
- // Cache format: |
- // 0: finger - index of the first free cell in the cache |
- // 1 + i: target map |
- static const int kMaxCachedPrototypeTransitions = 256; |
- static Handle<Map> PutPrototypeTransition(Handle<Map> map, |
- Handle<Object> prototype, |
- Handle<Map> target_map); |
- |
- static Handle<Map> GetPrototypeTransition(Handle<Map> map, |
- Handle<Object> prototype); |
- |
- static FixedArray* GetPrototypeTransitions(Map* map); |
- |
- static int NumberOfPrototypeTransitions(FixedArray* proto_transitions) { |
- if (proto_transitions->length() == 0) return 0; |
- Object* raw = proto_transitions->get(kProtoTransitionNumberOfEntriesOffset); |
- return Smi::cast(raw)->value(); |
- } |
- |
- static void SetNumberOfPrototypeTransitions(FixedArray* proto_transitions, |
- int value); |
+ // Accessors for fetching instance transition at transition number. |
+ inline Name* GetKey(int transition_number); |
+ inline void SetKey(int transition_number, Name* value); |
+ inline Object** GetKeySlot(int transition_number); |
+ int GetSortedKeyIndex(int transition_number) { return transition_number; } |
+ |
+ Name* GetSortedKey(int transition_number) { |
+ return GetKey(transition_number); |
+ } |
+ |
+ inline Map* GetTarget(int transition_number); |
+ inline void SetTarget(int transition_number, Map* target); |
+ |
+ inline PropertyDetails GetTargetDetails(int transition_number); |
+ inline Object* GetTargetValue(int transition_number); |
+ |
+ inline bool HasElementsTransition(); |
+ |
+ inline Object* back_pointer_storage(); |
+ inline void set_back_pointer_storage( |
+ Object* back_pointer, |
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
inline FixedArray* GetPrototypeTransitions(); |
inline void SetPrototypeTransitions( |
@@ -116,92 +65,133 @@ |
inline Object** GetPrototypeTransitionsSlot(); |
inline bool HasPrototypeTransitions(); |
- // ===== ITERATION ===== |
- |
- typedef void (*TraverseCallback)(Map* map, void* data); |
- |
- // Traverse the transition tree in postorder. |
- static void TraverseTransitionTree(Map* map, TraverseCallback callback, |
- void* data) { |
- // Make sure that we do not allocate in the callback. |
- DisallowHeapAllocation no_allocation; |
- TraverseTransitionTreeInternal(map, callback, data); |
- } |
- |
- // ===== LOW-LEVEL ACCESSORS ===== |
- |
- // Accessors for fetching instance transition at transition number. |
- static inline Name* GetKey(Object* raw_transitions, int transition_number); |
- inline Name* GetKey(int transition_number); |
- inline void SetKey(int transition_number, Name* value); |
- inline Object** GetKeySlot(int transition_number); |
- int GetSortedKeyIndex(int transition_number) { return transition_number; } |
- |
- Name* GetSortedKey(int transition_number) { |
- return GetKey(transition_number); |
- } |
- |
- static inline Map* GetTarget(Object* raw_transitions, int transition_number); |
- inline Map* GetTarget(int transition_number); |
- inline void SetTarget(int transition_number, Map* target); |
+ // Returns the number of transitions in the array. |
+ int number_of_transitions() { |
+ if (IsSimpleTransition()) return 1; |
+ if (length() <= kFirstIndex) return 0; |
+ return Smi::cast(get(kTransitionLengthIndex))->value(); |
+ } |
+ |
+ int number_of_transitions_storage() { |
+ if (IsSimpleTransition()) return 1; |
+ if (length() <= kFirstIndex) return 0; |
+ return (length() - kFirstIndex) / kTransitionSize; |
+ } |
+ |
+ int NumberOfSlackTransitions() { |
+ return number_of_transitions_storage() - number_of_transitions(); |
+ } |
+ |
+ inline void SetNumberOfTransitions(int number_of_transitions); |
+ inline int number_of_entries() { return number_of_transitions(); } |
+ |
+ // Creates a FullTransitionArray from a SimpleTransitionArray in |
+ // containing_map. |
+ static Handle<TransitionArray> ExtendToFullTransitionArray( |
+ Handle<Map> containing_map); |
+ |
+ // Return a transition array, using the array from the owning map if it |
+ // already has one (copying into a larger array if necessary), otherwise |
+ // creating a new one according to flag. |
+ // TODO(verwaest): This should not cause an existing transition to be |
+ // overwritten. |
+ static Handle<TransitionArray> Insert(Handle<Map> map, Handle<Name> name, |
+ Handle<Map> target, |
+ SimpleTransitionFlag flag); |
+ // Search a transition for a given kind, property name and attributes. |
+ int Search(PropertyKind kind, Name* name, PropertyAttributes attributes, |
+ int* out_insertion_index = NULL); |
+ |
+ // Search a non-property transition (like elements kind, observe or frozen |
+ // transitions). |
+ inline int SearchSpecial(Symbol* symbol, int* out_insertion_index = NULL) { |
+ return SearchName(symbol, out_insertion_index); |
+ } |
static inline PropertyDetails GetTargetDetails(Name* name, Map* target); |
- // Returns the number of transitions in the array. |
- static int NumberOfTransitions(Object* raw_transitions); |
- // Required for templatized Search interface. |
- inline int number_of_entries() { return number_of_transitions(); } |
- |
- inline void SetNumberOfTransitions(int number_of_transitions); |
- |
- static int Capacity(Object* raw_transitions); |
+ // Allocates a TransitionArray. |
+ static Handle<TransitionArray> Allocate(Isolate* isolate, |
+ int number_of_transitions, |
+ int slack = 0); |
+ |
+ bool IsSimpleTransition() { |
+ return length() == kSimpleTransitionSize && |
+ get(kSimpleTransitionTarget)->IsHeapObject() && |
+ // The IntrusivePrototypeTransitionIterator may have set the map of the |
+ // prototype transitions array to a smi. In that case, there are |
+ // prototype transitions, hence this transition array is a full |
+ // transition array. |
+ HeapObject::cast(get(kSimpleTransitionTarget))->map()->IsMap() && |
+ get(kSimpleTransitionTarget)->IsMap(); |
+ } |
+ |
+ bool IsFullTransitionArray() { |
+ return length() > kFirstIndex || |
+ (length() == kFirstIndex && !IsSimpleTransition()); |
+ } |
// Casting. |
static inline TransitionArray* cast(Object* obj); |
+ // Constant for denoting key was not found. |
+ static const int kNotFound = -1; |
+ |
+ static const int kBackPointerStorageIndex = 0; |
+ |
+ // Layout for full transition arrays. |
+ static const int kPrototypeTransitionsIndex = 1; |
+ static const int kTransitionLengthIndex = 2; |
+ static const int kFirstIndex = 3; |
+ |
+ // Layout for simple transition arrays. |
+ static const int kSimpleTransitionTarget = 1; |
+ static const int kSimpleTransitionSize = 2; |
+ static const int kSimpleTransitionIndex = 0; |
+ STATIC_ASSERT(kSimpleTransitionIndex != kNotFound); |
+ |
+ static const int kBackPointerStorageOffset = FixedArray::kHeaderSize; |
+ |
+ // Layout for the full transition array header. |
+ static const int kPrototypeTransitionsOffset = kBackPointerStorageOffset + |
+ kPointerSize; |
+ static const int kTransitionLengthOffset = |
+ kPrototypeTransitionsOffset + kPointerSize; |
+ |
+ // Layout of map transition entries in full transition arrays. |
+ static const int kTransitionKey = 0; |
+ static const int kTransitionTarget = 1; |
static const int kTransitionSize = 2; |
- static const int kProtoTransitionHeaderSize = 1; |
#if defined(DEBUG) || defined(OBJECT_PRINT) |
// For our gdb macros, we should perhaps change these in the future. |
void Print(); |
// Print all the transitions. |
- static void PrintTransitions(std::ostream& os, Object* transitions, |
- bool print_header = true); // NOLINT |
+ void PrintTransitions(std::ostream& os, bool print_header = true); // NOLINT |
#endif |
#ifdef DEBUG |
bool IsSortedNoDuplicates(int valid_entries = -1); |
- static bool IsSortedNoDuplicates(Map* map); |
- static bool IsConsistentWithBackPointers(Map* map); |
+ bool IsConsistentWithBackPointers(Map* current_map); |
+ bool IsEqualTo(TransitionArray* other); |
// Returns true for a non-property transitions like elements kind, observed |
// or frozen transitions. |
static inline bool IsSpecialTransition(Name* name); |
#endif |
- // Constant for denoting key was not found. |
- static const int kNotFound = -1; |
- |
// The maximum number of transitions we want in a transition array (should |
// fit in a page). |
static const int kMaxNumberOfTransitions = 1024 + 512; |
+ // Returns the fixed array length required to hold number_of_transitions |
+ // transitions. |
+ static int LengthFor(int number_of_transitions) { |
+ return ToKeyIndex(number_of_transitions); |
+ } |
+ |
private: |
- // Layout for full transition arrays. |
- static const int kPrototypeTransitionsIndex = 0; |
- static const int kTransitionLengthIndex = 1; |
- static const int kFirstIndex = 2; |
- |
- // Layout of map transition entries in full transition arrays. |
- static const int kTransitionKey = 0; |
- static const int kTransitionTarget = 1; |
- STATIC_ASSERT(kTransitionSize == 2); |
- |
- static const int kProtoTransitionNumberOfEntriesOffset = 0; |
- STATIC_ASSERT(kProtoTransitionHeaderSize == 1); |
- |
// Conversion from transition number to array indices. |
static int ToKeyIndex(int transition_number) { |
return kFirstIndex + |
@@ -215,54 +205,19 @@ |
kTransitionTarget; |
} |
- // Returns the fixed array length required to hold number_of_transitions |
- // transitions. |
- static int LengthFor(int number_of_transitions) { |
- return ToKeyIndex(number_of_transitions); |
- } |
- |
- // Allocates a TransitionArray. |
- static Handle<TransitionArray> Allocate(Isolate* isolate, |
- int number_of_transitions, |
- int slack = 0); |
- |
- static void EnsureHasFullTransitionArray(Handle<Map> map); |
- static void ReplaceTransitions(Handle<Map> map, Object* new_transitions); |
- |
- // Search a transition for a given kind, property name and attributes. |
- int Search(PropertyKind kind, Name* name, PropertyAttributes attributes, |
- int* out_insertion_index = NULL); |
- |
- // Search a non-property transition (like elements kind, observe or frozen |
- // transitions). |
- inline int SearchSpecial(Symbol* symbol, int* out_insertion_index = NULL) { |
- return SearchName(symbol, out_insertion_index); |
- } |
+ static Handle<TransitionArray> AllocateSimple( |
+ Isolate* isolate, Handle<Map> target); |
+ |
+ // Allocate a new transition array with a single entry. |
+ static Handle<TransitionArray> NewWith(Handle<Map> map, |
+ Handle<Name> name, |
+ Handle<Map> target, |
+ SimpleTransitionFlag flag); |
+ |
// Search a first transition for a given property name. |
inline int SearchName(Name* name, int* out_insertion_index = NULL); |
int SearchDetails(int transition, PropertyKind kind, |
PropertyAttributes attributes, int* out_insertion_index); |
- |
- int number_of_transitions() { |
- if (length() < kFirstIndex) return 0; |
- return Smi::cast(get(kTransitionLengthIndex))->value(); |
- } |
- |
- static inline PropertyDetails GetSimpleTargetDetails(Map* transition) { |
- return transition->GetLastDescriptorDetails(); |
- } |
- |
- static inline Name* GetSimpleTransitionKey(Map* transition) { |
- int descriptor = transition->LastAdded(); |
- return transition->instance_descriptors()->GetKey(descriptor); |
- } |
- |
- static void TraverseTransitionTreeInternal(Map* map, |
- TraverseCallback callback, |
- void* data); |
- |
- static void SetPrototypeTransitions(Handle<Map> map, |
- Handle<FixedArray> proto_transitions); |
// Compares two tuples <key, kind, attributes>, returns -1 if |
// tuple1 is "less" than tuple2, 0 if tuple1 equal to tuple2 and 1 otherwise. |
@@ -292,12 +247,6 @@ |
int origin_transition, |
int target_transition); |
-#ifdef DEBUG |
- static void CheckNewTransitionsAreConsistent(Handle<Map> map, |
- TransitionArray* old_transitions, |
- Object* transitions); |
-#endif |
- |
DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionArray); |
}; |