Index: src/transitions.cc |
diff --git a/src/transitions.cc b/src/transitions.cc |
index 43fc90b1b51796ddd8c96fd478f902ea822c8a3a..6154b4c1e10db478fc58186d4a396f2e4c5038c3 100644 |
--- a/src/transitions.cc |
+++ b/src/transitions.cc |
@@ -12,141 +12,110 @@ namespace v8 { |
namespace internal { |
-Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate, |
- int number_of_transitions, |
- int slack) { |
- Handle<FixedArray> array = isolate->factory()->NewFixedArray( |
- LengthFor(number_of_transitions + slack)); |
- array->set(kPrototypeTransitionsIndex, Smi::FromInt(0)); |
- array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions)); |
- return Handle<TransitionArray>::cast(array); |
-} |
- |
- |
-Handle<TransitionArray> TransitionArray::AllocateSimple(Isolate* isolate, |
- Handle<Map> target) { |
- Handle<FixedArray> array = |
- isolate->factory()->NewFixedArray(kSimpleTransitionSize); |
- array->set(kSimpleTransitionTarget, *target); |
- return Handle<TransitionArray>::cast(array); |
-} |
- |
- |
-void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin, |
- int origin_transition, |
- int target_transition) { |
- NoIncrementalWriteBarrierSet(target_transition, |
- origin->GetKey(origin_transition), |
- origin->GetTarget(origin_transition)); |
-} |
- |
- |
-Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map, |
- Handle<Name> name, |
- Handle<Map> target, |
- SimpleTransitionFlag flag) { |
- Handle<TransitionArray> result; |
- Isolate* isolate = name->GetIsolate(); |
- |
- if (flag == SIMPLE_PROPERTY_TRANSITION) { |
- result = AllocateSimple(isolate, target); |
- } else { |
- result = Allocate(isolate, 1); |
- result->NoIncrementalWriteBarrierSet(0, *name, *target); |
- } |
- result->set_back_pointer_storage(map->GetBackPointer()); |
- return result; |
-} |
- |
- |
-Handle<TransitionArray> TransitionArray::ExtendToFullTransitionArray( |
- Handle<Map> containing_map) { |
- DCHECK(!containing_map->transitions()->IsFullTransitionArray()); |
- int nof = containing_map->transitions()->number_of_transitions(); |
- |
- // A transition array may shrink during GC. |
- Handle<TransitionArray> result = Allocate(containing_map->GetIsolate(), nof); |
- DisallowHeapAllocation no_gc; |
- int new_nof = containing_map->transitions()->number_of_transitions(); |
- if (new_nof != nof) { |
- DCHECK(new_nof == 0); |
- result->Shrink(ToKeyIndex(0)); |
- result->SetNumberOfTransitions(0); |
- } else if (nof == 1) { |
- result->NoIncrementalWriteBarrierCopyFrom( |
- containing_map->transitions(), kSimpleTransitionIndex, 0); |
+// static |
+void TransitionArray::Insert(Handle<Map> map, Handle<Name> name, |
+ Handle<Map> target, SimpleTransitionFlag flag) { |
+ Isolate* isolate = map->GetIsolate(); |
+ target->SetBackPointer(*map); |
+ |
+ // If the map doesn't have any transitions at all yet, install the new one. |
+ if (CanStoreSimpleTransition(map->raw_transitions())) { |
+ if (flag == SIMPLE_PROPERTY_TRANSITION) { |
+ Handle<WeakCell> cell = Map::WeakCellForMap(target); |
+ map->set_raw_transitions(*cell); |
+ return; |
+ } |
+ // If the flag requires a full TransitionArray, allocate one. |
+ Handle<TransitionArray> result = Allocate(isolate, 0, 1); |
+ map->set_raw_transitions(*result); |
} |
- result->set_back_pointer_storage( |
- containing_map->transitions()->back_pointer_storage()); |
- return result; |
-} |
- |
- |
-Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map, |
- Handle<Name> name, |
- Handle<Map> target, |
- SimpleTransitionFlag flag) { |
- if (!map->HasTransitionArray()) { |
- return TransitionArray::NewWith(map, name, target, flag); |
+ bool is_special_transition = flag == SPECIAL_TRANSITION; |
+ // If the map has a simple transition, check if it should be overwritten. |
+ if (IsSimpleTransition(map->raw_transitions())) { |
+ Map* old_target = GetSimpleTransition(map->raw_transitions()); |
+ Name* key = GetSimpleTransitionKey(old_target); |
+ PropertyDetails old_details = GetSimpleTargetDetails(old_target); |
+ PropertyDetails new_details = is_special_transition |
+ ? PropertyDetails(NONE, DATA, 0) |
+ : GetTargetDetails(*name, *target); |
+ if (flag == SIMPLE_PROPERTY_TRANSITION && key->Equals(*name) && |
+ old_details.kind() == new_details.kind() && |
+ old_details.attributes() == new_details.attributes()) { |
+ Handle<WeakCell> cell = Map::WeakCellForMap(target); |
+ map->set_raw_transitions(*cell); |
+ return; |
+ } |
+ // Otherwise allocate a full TransitionArray with slack for a new entry. |
+ Handle<TransitionArray> result = Allocate(isolate, 1, 1); |
+ // Re-read existing data; the allocation might have caused it to be cleared. |
+ if (IsSimpleTransition(map->raw_transitions())) { |
+ old_target = GetSimpleTransition(map->raw_transitions()); |
+ result->NoIncrementalWriteBarrierSet( |
+ 0, GetSimpleTransitionKey(old_target), old_target); |
+ } else { |
+ result->SetNumberOfTransitions(0); |
+ } |
+ map->set_raw_transitions(*result); |
} |
- int number_of_transitions = map->transitions()->number_of_transitions(); |
- int new_nof = number_of_transitions; |
+ // At this point, we know that the map has a full TransitionArray. |
+ DCHECK(IsFullTransitionArray(map->raw_transitions())); |
- bool is_special_transition = flag == SPECIAL_TRANSITION; |
+ int number_of_transitions = 0; |
+ int new_nof = 0; |
+ int insertion_index = kNotFound; |
DCHECK_EQ(is_special_transition, IsSpecialTransition(*name)); |
PropertyDetails details = is_special_transition |
? PropertyDetails(NONE, DATA, 0) |
: GetTargetDetails(*name, *target); |
- int insertion_index = kNotFound; |
- int index = |
- is_special_transition |
- ? map->transitions()->SearchSpecial(Symbol::cast(*name), |
- &insertion_index) |
- : map->transitions()->Search(details.kind(), *name, |
- details.attributes(), &insertion_index); |
- if (index == kNotFound) { |
- ++new_nof; |
- } else { |
- insertion_index = index; |
- } |
- DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions); |
- |
- CHECK(new_nof <= kMaxNumberOfTransitions); |
- |
- if (new_nof <= map->transitions()->number_of_transitions_storage()) { |
+ { |
DisallowHeapAllocation no_gc; |
- TransitionArray* array = map->transitions(); |
+ TransitionArray* array = TransitionArray::cast(map->raw_transitions()); |
+ number_of_transitions = array->number_of_transitions(); |
+ new_nof = number_of_transitions; |
+ int index = |
+ is_special_transition |
+ ? array->SearchSpecial(Symbol::cast(*name), &insertion_index) |
+ : array->Search(details.kind(), *name, details.attributes(), |
+ &insertion_index); |
+ // If an existing entry was found, overwrite it and return. |
if (index != kNotFound) { |
array->SetTarget(index, *target); |
- return handle(array); |
+ return; |
} |
- array->SetNumberOfTransitions(new_nof); |
- for (index = number_of_transitions; index > insertion_index; --index) { |
- Name* key = array->GetKey(index - 1); |
- array->SetKey(index, key); |
- array->SetTarget(index, array->GetTarget(index - 1)); |
+ ++new_nof; |
+ CHECK(new_nof <= kMaxNumberOfTransitions); |
+ DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions); |
+ |
+ // If there is enough capacity, insert new entry into the existing array. |
+ if (new_nof <= Capacity(array)) { |
+ array->SetNumberOfTransitions(new_nof); |
+ for (index = number_of_transitions; index > insertion_index; --index) { |
+ array->SetKey(index, array->GetKey(index - 1)); |
+ array->SetTarget(index, array->GetTarget(index - 1)); |
+ } |
+ array->SetKey(index, *name); |
+ array->SetTarget(index, *target); |
+ SLOW_DCHECK(array->IsSortedNoDuplicates()); |
+ return; |
} |
- array->SetKey(index, *name); |
- array->SetTarget(index, *target); |
- SLOW_DCHECK(array->IsSortedNoDuplicates()); |
- return handle(array); |
} |
+ // We're gonna need a bigger TransitionArray. |
Handle<TransitionArray> result = Allocate( |
map->GetIsolate(), new_nof, |
Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions)); |
- // The map's transition array may grown smaller during the allocation above as |
+ // The map's transition array may have shrunk during the allocation above as |
// it was weakly traversed, though it is guaranteed not to disappear. Trim the |
// result copy if needed, and recompute variables. |
- DCHECK(map->HasTransitionArray()); |
+ DCHECK(IsFullTransitionArray(map->raw_transitions())); |
DisallowHeapAllocation no_gc; |
- TransitionArray* array = map->transitions(); |
+ TransitionArray* array = TransitionArray::cast(map->raw_transitions()); |
if (array->number_of_transitions() != number_of_transitions) { |
DCHECK(array->number_of_transitions() < number_of_transitions); |
@@ -154,11 +123,11 @@ Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map, |
new_nof = number_of_transitions; |
insertion_index = kNotFound; |
- index = is_special_transition ? map->transitions()->SearchSpecial( |
- Symbol::cast(*name), &insertion_index) |
- : map->transitions()->Search( |
- details.kind(), *name, |
- details.attributes(), &insertion_index); |
+ int index = |
+ is_special_transition |
+ ? array->SearchSpecial(Symbol::cast(*name), &insertion_index) |
+ : array->Search(details.kind(), *name, details.attributes(), |
+ &insertion_index); |
if (index == kNotFound) { |
++new_nof; |
} else { |
@@ -183,12 +152,332 @@ Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map, |
result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1); |
} |
- result->set_back_pointer_storage(array->back_pointer_storage()); |
SLOW_DCHECK(result->IsSortedNoDuplicates()); |
- return result; |
+ map->set_raw_transitions(*result); |
+} |
+ |
+ |
+// static |
+Map* TransitionArray::SearchTransition(Map* map, PropertyKind kind, Name* name, |
+ PropertyAttributes attributes) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ if (IsSimpleTransition(raw_transitions)) { |
+ Map* target = GetSimpleTransition(raw_transitions); |
+ Name* key = GetSimpleTransitionKey(target); |
+ if (!key->Equals(name)) return NULL; |
+ PropertyDetails details = GetSimpleTargetDetails(target); |
+ if (details.attributes() != attributes) return NULL; |
+ if (details.kind() != kind) return NULL; |
+ return target; |
+ } |
+ if (IsFullTransitionArray(raw_transitions)) { |
+ TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
+ int transition = transitions->Search(kind, name, attributes); |
+ if (transition == kNotFound) return NULL; |
+ return transitions->GetTarget(transition); |
+ } |
+ return NULL; |
} |
+// static |
+Map* TransitionArray::SearchSpecial(Map* map, Symbol* name) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ if (IsFullTransitionArray(raw_transitions)) { |
+ TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
+ int transition = transitions->SearchSpecial(name); |
+ if (transition == kNotFound) return NULL; |
+ return transitions->GetTarget(transition); |
+ } |
+ return NULL; |
+} |
+ |
+ |
+// static |
+Handle<Map> TransitionArray::FindTransitionToField(Handle<Map> map, |
+ Handle<Name> name) { |
+ DisallowHeapAllocation no_gc; |
+ Map* target = SearchTransition(*map, kData, *name, NONE); |
+ if (target == NULL) return Handle<Map>::null(); |
+ PropertyDetails details = target->GetLastDescriptorDetails(); |
+ DCHECK_EQ(NONE, details.attributes()); |
+ if (details.type() != DATA) return Handle<Map>::null(); |
+ return Handle<Map>(target); |
+} |
+ |
+ |
+// static |
+Handle<String> TransitionArray::ExpectedTransitionKey(Handle<Map> map) { |
+ DisallowHeapAllocation no_gc; |
+ Object* raw_transition = map->raw_transitions(); |
+ if (!IsSimpleTransition(raw_transition)) return Handle<String>::null(); |
+ Map* target = GetSimpleTransition(raw_transition); |
+ PropertyDetails details = GetSimpleTargetDetails(target); |
+ if (details.type() != DATA) return Handle<String>::null(); |
+ if (details.attributes() != NONE) return Handle<String>::null(); |
+ Name* name = GetSimpleTransitionKey(target); |
+ if (!name->IsString()) return Handle<String>::null(); |
+ return Handle<String>(String::cast(name)); |
+} |
+ |
+ |
+// static |
+bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ if (IsFullTransitionArray(raw_transitions)) { |
+ TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
+ return transitions->number_of_transitions() < kMaxNumberOfTransitions; |
+ } |
+ return true; |
+} |
+ |
+ |
+// static |
+Handle<Map> TransitionArray::PutPrototypeTransition(Handle<Map> map, |
+ Handle<Object> prototype, |
+ Handle<Map> target_map) { |
+ DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); |
+ // Don't cache prototype transition if this map is either shared, or a map of |
+ // a prototype. |
+ if (map->is_prototype_map()) return map; |
+ if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map; |
+ |
+ const int header = kProtoTransitionHeaderSize; |
+ |
+ Handle<FixedArray> cache(GetPrototypeTransitions(*map)); |
+ int capacity = cache->length() - header; |
+ int transitions = NumberOfPrototypeTransitions(*cache) + 1; |
+ |
+ if (transitions > capacity) { |
+ // Grow array by factor 2 up to MaxCachedPrototypeTransitions. |
+ int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2); |
+ if (new_capacity == capacity) return map; |
+ |
+ cache = FixedArray::CopySize(cache, header + new_capacity); |
+ if (capacity < 0) { |
+ // There was no prototype transitions array before, so the size |
+ // couldn't be copied. Initialize it explicitly. |
+ SetNumberOfPrototypeTransitions(*cache, 0); |
+ } |
+ |
+ SetPrototypeTransitions(map, cache); |
+ } |
+ |
+ // Reload number of transitions as GC might shrink them. |
+ int last = NumberOfPrototypeTransitions(*cache); |
+ int entry = header + last; |
+ |
+ cache->set(entry, *target_map); |
+ SetNumberOfPrototypeTransitions(*cache, last + 1); |
+ |
+ return map; |
+} |
+ |
+ |
+// static |
+Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map, |
+ Handle<Object> prototype) { |
+ DisallowHeapAllocation no_gc; |
+ FixedArray* cache = GetPrototypeTransitions(*map); |
+ int number_of_transitions = NumberOfPrototypeTransitions(cache); |
+ for (int i = 0; i < number_of_transitions; i++) { |
+ Map* target = Map::cast(cache->get(kProtoTransitionHeaderSize + i)); |
+ if (target->prototype() == *prototype) return handle(target); |
+ } |
+ return Handle<Map>(); |
+} |
+ |
+ |
+// static |
+FixedArray* TransitionArray::GetPrototypeTransitions(Map* map) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ Heap* heap = map->GetHeap(); |
+ if (!IsFullTransitionArray(raw_transitions)) { |
+ return heap->empty_fixed_array(); |
+ } |
+ TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
+ if (!transitions->HasPrototypeTransitions()) { |
+ return heap->empty_fixed_array(); |
+ } |
+ return transitions->GetPrototypeTransitions(); |
+} |
+ |
+ |
+// static |
+void TransitionArray::SetNumberOfPrototypeTransitions( |
+ FixedArray* proto_transitions, int value) { |
+ DCHECK(proto_transitions->length() != 0); |
+ proto_transitions->set(kProtoTransitionNumberOfEntriesOffset, |
+ Smi::FromInt(value)); |
+} |
+ |
+ |
+// static |
+int TransitionArray::NumberOfTransitions(Object* raw_transitions) { |
+ if (CanStoreSimpleTransition(raw_transitions)) return 0; |
+ if (IsSimpleTransition(raw_transitions)) return 1; |
+ DCHECK(IsFullTransitionArray(raw_transitions)); |
+ return TransitionArray::cast(raw_transitions)->number_of_transitions(); |
+} |
+ |
+ |
+// static |
+int TransitionArray::Capacity(Object* raw_transitions) { |
+ if (!IsFullTransitionArray(raw_transitions)) return 1; |
+ TransitionArray* t = TransitionArray::cast(raw_transitions); |
+ if (t->length() <= kFirstIndex) return 0; |
+ return (t->length() - kFirstIndex) / kTransitionSize; |
+} |
+ |
+ |
+// Private static helper functions. |
+ |
+Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate, |
+ int number_of_transitions, |
+ int slack) { |
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray( |
+ LengthFor(number_of_transitions + slack)); |
+ array->set(kPrototypeTransitionsIndex, Smi::FromInt(0)); |
+ array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions)); |
+ return Handle<TransitionArray>::cast(array); |
+} |
+ |
+ |
+void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin, |
+ int origin_transition, |
+ int target_transition) { |
+ NoIncrementalWriteBarrierSet(target_transition, |
+ origin->GetKey(origin_transition), |
+ origin->GetTarget(origin_transition)); |
+} |
+ |
+ |
+static void ZapTransitionArray(TransitionArray* transitions) { |
+ MemsetPointer(transitions->data_start(), |
+ transitions->GetHeap()->the_hole_value(), |
+ transitions->length()); |
+} |
+ |
+ |
+void TransitionArray::ReplaceTransitions(Handle<Map> map, |
+ Object* new_transitions) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ if (IsFullTransitionArray(raw_transitions)) { |
+ TransitionArray* old_transitions = TransitionArray::cast(raw_transitions); |
+#ifdef DEBUG |
+ CheckNewTransitionsAreConsistent(map, old_transitions, new_transitions); |
+ DCHECK(old_transitions != new_transitions); |
+#endif |
+ // Transition arrays are not shared. When one is replaced, it should not |
+ // keep referenced objects alive, so we zap it. |
+ // When there is another reference to the array somewhere (e.g. a handle), |
+ // not zapping turns from a waste of memory into a source of crashes. |
+ ZapTransitionArray(old_transitions); |
+ } |
+ map->set_raw_transitions(new_transitions); |
+} |
+ |
+ |
+static void ZapPrototypeTransitions(Object* raw_transitions) { |
+ DCHECK(TransitionArray::IsFullTransitionArray(raw_transitions)); |
+ TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
+ if (!transitions->HasPrototypeTransitions()) return; |
+ FixedArray* proto_transitions = transitions->GetPrototypeTransitions(); |
+ MemsetPointer(proto_transitions->data_start(), |
+ proto_transitions->GetHeap()->the_hole_value(), |
+ proto_transitions->length()); |
+} |
+ |
+ |
+void TransitionArray::SetPrototypeTransitions( |
+ Handle<Map> map, Handle<FixedArray> proto_transitions) { |
+ EnsureHasFullTransitionArray(map); |
+ if (Heap::ShouldZapGarbage()) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ DCHECK(raw_transitions != *proto_transitions); |
+ ZapPrototypeTransitions(raw_transitions); |
+ } |
+ TransitionArray* transitions = TransitionArray::cast(map->raw_transitions()); |
+ transitions->SetPrototypeTransitions(*proto_transitions); |
+} |
+ |
+ |
+void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ if (IsFullTransitionArray(raw_transitions)) return; |
+ int nof = IsSimpleTransition(raw_transitions) ? 1 : 0; |
+ Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof); |
+ DisallowHeapAllocation no_gc; |
+ // Reload pointer after the allocation that just happened. |
+ raw_transitions = map->raw_transitions(); |
+ int new_nof = IsSimpleTransition(raw_transitions) ? 1 : 0; |
+ if (new_nof != nof) { |
+ DCHECK(new_nof == 0); |
+ result->Shrink(ToKeyIndex(0)); |
+ result->SetNumberOfTransitions(0); |
+ } else if (nof == 1) { |
+ Map* target = GetSimpleTransition(raw_transitions); |
+ Name* key = GetSimpleTransitionKey(target); |
+ result->NoIncrementalWriteBarrierSet(0, key, target); |
+ } |
+ ReplaceTransitions(map, *result); |
+} |
+ |
+ |
+void TransitionArray::TraverseTransitionTreeInternal(Map* map, |
+ TraverseCallback callback, |
+ void* data) { |
+ Object* raw_transitions = map->raw_transitions(); |
+ if (IsFullTransitionArray(raw_transitions)) { |
+ TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
+ if (transitions->HasPrototypeTransitions()) { |
+ FixedArray* proto_trans = transitions->GetPrototypeTransitions(); |
+ for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) { |
+ int index = TransitionArray::kProtoTransitionHeaderSize + i; |
+ TraverseTransitionTreeInternal(Map::cast(proto_trans->get(index)), |
+ callback, data); |
+ } |
+ } |
+ for (int i = 0; i < transitions->number_of_transitions(); ++i) { |
+ TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data); |
+ } |
+ } else if (IsSimpleTransition(raw_transitions)) { |
+ TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions), |
+ callback, data); |
+ } |
+ callback(map, data); |
+} |
+ |
+ |
+#ifdef DEBUG |
+void TransitionArray::CheckNewTransitionsAreConsistent( |
+ Handle<Map> map, TransitionArray* old_transitions, Object* transitions) { |
+ // This function only handles full transition arrays. |
+ DCHECK(IsFullTransitionArray(transitions)); |
+ TransitionArray* new_transitions = TransitionArray::cast(transitions); |
+ for (int i = 0; i < old_transitions->number_of_transitions(); i++) { |
+ Map* target = old_transitions->GetTarget(i); |
+ if (target->instance_descriptors() == map->instance_descriptors()) { |
+ Name* key = old_transitions->GetKey(i); |
+ int new_target_index; |
+ if (TransitionArray::IsSpecialTransition(key)) { |
+ new_target_index = new_transitions->SearchSpecial(Symbol::cast(key)); |
+ } else { |
+ PropertyDetails details = |
+ TransitionArray::GetTargetDetails(key, target); |
+ new_target_index = |
+ new_transitions->Search(details.kind(), key, details.attributes()); |
+ } |
+ DCHECK_NE(TransitionArray::kNotFound, new_target_index); |
+ DCHECK_EQ(target, new_transitions->GetTarget(new_target_index)); |
+ } |
+ } |
+} |
+#endif |
+ |
+ |
+// Private non-static helper functions (operating on full transition arrays). |
+ |
int TransitionArray::SearchDetails(int transition, PropertyKind kind, |
PropertyAttributes attributes, |
int* out_insertion_index) { |