blob: 082ebc16b015df44d1586fbaa355d6f6604ce65c [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/transitions.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/objects-inl.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/transitions-inl.h"
9#include "src/utils.h"
10
11namespace v8 {
12namespace internal {
13
14
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015// static
16void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
17 Handle<Map> target, SimpleTransitionFlag flag) {
18 Isolate* isolate = map->GetIsolate();
19 target->SetBackPointer(*map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021 // If the map doesn't have any transitions at all yet, install the new one.
22 if (CanStoreSimpleTransition(map->raw_transitions())) {
23 if (flag == SIMPLE_PROPERTY_TRANSITION) {
24 Handle<WeakCell> cell = Map::WeakCellForMap(target);
25 ReplaceTransitions(map, *cell);
26 return;
27 }
28 // If the flag requires a full TransitionArray, allocate one.
29 Handle<TransitionArray> result = Allocate(isolate, 0, 1);
30 ReplaceTransitions(map, *result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032
Emily Bernierd0a1eb72015-03-24 16:35:39 -040033 bool is_special_transition = flag == SPECIAL_TRANSITION;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 // If the map has a simple transition, check if it should be overwritten.
35 if (IsSimpleTransition(map->raw_transitions())) {
36 Map* old_target = GetSimpleTransition(map->raw_transitions());
37 Name* key = GetSimpleTransitionKey(old_target);
38 PropertyDetails old_details = GetSimpleTargetDetails(old_target);
39 PropertyDetails new_details = is_special_transition
40 ? PropertyDetails::Empty()
41 : GetTargetDetails(*name, *target);
42 if (flag == SIMPLE_PROPERTY_TRANSITION && key->Equals(*name) &&
43 old_details.kind() == new_details.kind() &&
44 old_details.attributes() == new_details.attributes()) {
45 Handle<WeakCell> cell = Map::WeakCellForMap(target);
46 ReplaceTransitions(map, *cell);
47 return;
48 }
49 // Otherwise allocate a full TransitionArray with slack for a new entry.
50 Handle<TransitionArray> result = Allocate(isolate, 1, 1);
51 // Re-read existing data; the allocation might have caused it to be cleared.
52 if (IsSimpleTransition(map->raw_transitions())) {
53 old_target = GetSimpleTransition(map->raw_transitions());
54 result->Set(0, GetSimpleTransitionKey(old_target), old_target);
55 } else {
56 result->SetNumberOfTransitions(0);
57 }
58 ReplaceTransitions(map, *result);
59 }
60
61 // At this point, we know that the map has a full TransitionArray.
62 DCHECK(IsFullTransitionArray(map->raw_transitions()));
63
64 int number_of_transitions = 0;
65 int new_nof = 0;
66 int insertion_index = kNotFound;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040067 DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
68 PropertyDetails details = is_special_transition
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069 ? PropertyDetails::Empty()
Emily Bernierd0a1eb72015-03-24 16:35:39 -040070 : GetTargetDetails(*name, *target);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040073 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 TransitionArray* array = TransitionArray::cast(map->raw_transitions());
75 number_of_transitions = array->number_of_transitions();
76 new_nof = number_of_transitions;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040077
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000078 int index =
79 is_special_transition
80 ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
81 : array->Search(details.kind(), *name, details.attributes(),
82 &insertion_index);
83 // If an existing entry was found, overwrite it and return.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040084 if (index != kNotFound) {
85 array->SetTarget(index, *target);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040087 }
88
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 ++new_nof;
90 CHECK(new_nof <= kMaxNumberOfTransitions);
91 DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
92
93 // If there is enough capacity, insert new entry into the existing array.
94 if (new_nof <= Capacity(array)) {
95 array->SetNumberOfTransitions(new_nof);
96 for (index = number_of_transitions; index > insertion_index; --index) {
97 array->SetKey(index, array->GetKey(index - 1));
98 array->SetTarget(index, array->GetTarget(index - 1));
99 }
100 array->SetKey(index, *name);
101 array->SetTarget(index, *target);
102 SLOW_DCHECK(array->IsSortedNoDuplicates());
103 return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400104 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400105 }
106
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 // We're gonna need a bigger TransitionArray.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400108 Handle<TransitionArray> result = Allocate(
109 map->GetIsolate(), new_nof,
110 Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 // The map's transition array may have shrunk during the allocation above as
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 // it was weakly traversed, though it is guaranteed not to disappear. Trim the
114 // result copy if needed, and recompute variables.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 DCHECK(IsFullTransitionArray(map->raw_transitions()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 DisallowHeapAllocation no_gc;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000117 TransitionArray* array = TransitionArray::cast(map->raw_transitions());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118 if (array->number_of_transitions() != number_of_transitions) {
119 DCHECK(array->number_of_transitions() < number_of_transitions);
120
121 number_of_transitions = array->number_of_transitions();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400122 new_nof = number_of_transitions;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000123
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124 insertion_index = kNotFound;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000125 int index =
126 is_special_transition
127 ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
128 : array->Search(details.kind(), *name, details.attributes(),
129 &insertion_index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400130 if (index == kNotFound) {
131 ++new_nof;
132 } else {
133 insertion_index = index;
134 }
135 DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400137 result->Shrink(ToKeyIndex(new_nof));
138 result->SetNumberOfTransitions(new_nof);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 }
140
141 if (array->HasPrototypeTransitions()) {
142 result->SetPrototypeTransitions(array->GetPrototypeTransitions());
143 }
144
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400145 DCHECK_NE(kNotFound, insertion_index);
146 for (int i = 0; i < insertion_index; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147 result->Set(i, array->GetKey(i), array->GetTarget(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 result->Set(insertion_index, *name, *target);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150 for (int i = insertion_index; i < number_of_transitions; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 result->Set(i + 1, array->GetKey(i), array->GetTarget(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 }
153
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 SLOW_DCHECK(result->IsSortedNoDuplicates());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 ReplaceTransitions(map, *result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156}
157
158
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000159// static
160Map* TransitionArray::SearchTransition(Map* map, PropertyKind kind, Name* name,
161 PropertyAttributes attributes) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100162 DCHECK(name->IsUniqueName());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 Object* raw_transitions = map->raw_transitions();
164 if (IsSimpleTransition(raw_transitions)) {
165 Map* target = GetSimpleTransition(raw_transitions);
166 Name* key = GetSimpleTransitionKey(target);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100167 if (key != name) return nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168 PropertyDetails details = GetSimpleTargetDetails(target);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100169 if (details.attributes() != attributes) return nullptr;
170 if (details.kind() != kind) return nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 return target;
172 }
173 if (IsFullTransitionArray(raw_transitions)) {
174 TransitionArray* transitions = TransitionArray::cast(raw_transitions);
175 int transition = transitions->Search(kind, name, attributes);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100176 if (transition == kNotFound) return nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177 return transitions->GetTarget(transition);
178 }
179 return NULL;
180}
181
182
183// static
184Map* TransitionArray::SearchSpecial(Map* map, Symbol* name) {
185 Object* raw_transitions = map->raw_transitions();
186 if (IsFullTransitionArray(raw_transitions)) {
187 TransitionArray* transitions = TransitionArray::cast(raw_transitions);
188 int transition = transitions->SearchSpecial(name);
189 if (transition == kNotFound) return NULL;
190 return transitions->GetTarget(transition);
191 }
192 return NULL;
193}
194
195
196// static
197Handle<Map> TransitionArray::FindTransitionToField(Handle<Map> map,
198 Handle<Name> name) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100199 DCHECK(name->IsUniqueName());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 DisallowHeapAllocation no_gc;
201 Map* target = SearchTransition(*map, kData, *name, NONE);
202 if (target == NULL) return Handle<Map>::null();
203 PropertyDetails details = target->GetLastDescriptorDetails();
204 DCHECK_EQ(NONE, details.attributes());
205 if (details.type() != DATA) return Handle<Map>::null();
206 return Handle<Map>(target);
207}
208
209
210// static
211Handle<String> TransitionArray::ExpectedTransitionKey(Handle<Map> map) {
212 DisallowHeapAllocation no_gc;
213 Object* raw_transition = map->raw_transitions();
214 if (!IsSimpleTransition(raw_transition)) return Handle<String>::null();
215 Map* target = GetSimpleTransition(raw_transition);
216 PropertyDetails details = GetSimpleTargetDetails(target);
217 if (details.type() != DATA) return Handle<String>::null();
218 if (details.attributes() != NONE) return Handle<String>::null();
219 Name* name = GetSimpleTransitionKey(target);
220 if (!name->IsString()) return Handle<String>::null();
221 return Handle<String>(String::cast(name));
222}
223
224
225// static
226bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) {
227 if (map->is_dictionary_map()) return false;
228 Object* raw_transitions = map->raw_transitions();
229 if (IsFullTransitionArray(raw_transitions)) {
230 TransitionArray* transitions = TransitionArray::cast(raw_transitions);
231 return transitions->number_of_transitions() < kMaxNumberOfTransitions;
232 }
233 return true;
234}
235
236
237// static
238bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
239 const int header = kProtoTransitionHeaderSize;
240 int number_of_transitions = NumberOfPrototypeTransitions(array);
241 if (number_of_transitions == 0) {
242 // Empty array cannot be compacted.
243 return false;
244 }
245 int new_number_of_transitions = 0;
246 for (int i = 0; i < number_of_transitions; i++) {
247 Object* cell = array->get(header + i);
248 if (!WeakCell::cast(cell)->cleared()) {
249 if (new_number_of_transitions != i) {
250 array->set(header + new_number_of_transitions, cell);
251 }
252 new_number_of_transitions++;
253 }
254 }
255 // Fill slots that became free with undefined value.
256 for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
257 array->set_undefined(header + i);
258 }
259 if (number_of_transitions != new_number_of_transitions) {
260 SetNumberOfPrototypeTransitions(array, new_number_of_transitions);
261 }
262 return new_number_of_transitions < number_of_transitions;
263}
264
265
266// static
267Handle<FixedArray> TransitionArray::GrowPrototypeTransitionArray(
268 Handle<FixedArray> array, int new_capacity, Isolate* isolate) {
269 // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
270 int capacity = array->length() - kProtoTransitionHeaderSize;
271 new_capacity = Min(kMaxCachedPrototypeTransitions, new_capacity);
272 DCHECK_GT(new_capacity, capacity);
273 int grow_by = new_capacity - capacity;
274 array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by, TENURED);
275 if (capacity < 0) {
276 // There was no prototype transitions array before, so the size
277 // couldn't be copied. Initialize it explicitly.
278 SetNumberOfPrototypeTransitions(*array, 0);
279 }
280 return array;
281}
282
283
284// static
285int TransitionArray::NumberOfPrototypeTransitionsForTest(Map* map) {
286 FixedArray* transitions = GetPrototypeTransitions(map);
287 CompactPrototypeTransitionArray(transitions);
288 return TransitionArray::NumberOfPrototypeTransitions(transitions);
289}
290
291
292// static
293void TransitionArray::PutPrototypeTransition(Handle<Map> map,
294 Handle<Object> prototype,
295 Handle<Map> target_map) {
296 DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
297 // Don't cache prototype transition if this map is either shared, or a map of
298 // a prototype.
299 if (map->is_prototype_map()) return;
300 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return;
301
302 const int header = kProtoTransitionHeaderSize;
303
304 Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map);
305
306 Handle<FixedArray> cache(GetPrototypeTransitions(*map));
307 int capacity = cache->length() - header;
308 int transitions = NumberOfPrototypeTransitions(*cache) + 1;
309
310 if (transitions > capacity) {
311 // Grow the array if compacting it doesn't free space.
312 if (!CompactPrototypeTransitionArray(*cache)) {
313 if (capacity == kMaxCachedPrototypeTransitions) return;
314 cache = GrowPrototypeTransitionArray(cache, 2 * transitions,
315 map->GetIsolate());
316 SetPrototypeTransitions(map, cache);
317 }
318 }
319
320 // Reload number of transitions as they might have been compacted.
321 int last = NumberOfPrototypeTransitions(*cache);
322 int entry = header + last;
323
324 cache->set(entry, *target_cell);
325 SetNumberOfPrototypeTransitions(*cache, last + 1);
326}
327
328
329// static
330Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map,
331 Handle<Object> prototype) {
332 DisallowHeapAllocation no_gc;
333 FixedArray* cache = GetPrototypeTransitions(*map);
334 int number_of_transitions = NumberOfPrototypeTransitions(cache);
335 for (int i = 0; i < number_of_transitions; i++) {
336 WeakCell* target_cell =
337 WeakCell::cast(cache->get(kProtoTransitionHeaderSize + i));
338 if (!target_cell->cleared() &&
339 Map::cast(target_cell->value())->prototype() == *prototype) {
340 return handle(Map::cast(target_cell->value()));
341 }
342 }
343 return Handle<Map>();
344}
345
346
347// static
348FixedArray* TransitionArray::GetPrototypeTransitions(Map* map) {
349 Object* raw_transitions = map->raw_transitions();
350 Heap* heap = map->GetHeap();
351 if (!IsFullTransitionArray(raw_transitions)) {
352 return heap->empty_fixed_array();
353 }
354 TransitionArray* transitions = TransitionArray::cast(raw_transitions);
355 if (!transitions->HasPrototypeTransitions()) {
356 return heap->empty_fixed_array();
357 }
358 return transitions->GetPrototypeTransitions();
359}
360
361
362// static
363void TransitionArray::SetNumberOfPrototypeTransitions(
364 FixedArray* proto_transitions, int value) {
365 DCHECK(proto_transitions->length() != 0);
366 proto_transitions->set(kProtoTransitionNumberOfEntriesOffset,
367 Smi::FromInt(value));
368}
369
370
371// static
372int TransitionArray::NumberOfTransitions(Object* raw_transitions) {
373 if (CanStoreSimpleTransition(raw_transitions)) return 0;
374 if (IsSimpleTransition(raw_transitions)) return 1;
375 // Prototype maps don't have transitions.
376 if (raw_transitions->IsPrototypeInfo()) return 0;
377 DCHECK(IsFullTransitionArray(raw_transitions));
378 return TransitionArray::cast(raw_transitions)->number_of_transitions();
379}
380
381
382// static
383int TransitionArray::Capacity(Object* raw_transitions) {
384 if (!IsFullTransitionArray(raw_transitions)) return 1;
385 TransitionArray* t = TransitionArray::cast(raw_transitions);
386 if (t->length() <= kFirstIndex) return 0;
387 return (t->length() - kFirstIndex) / kTransitionSize;
388}
389
390
391// Private static helper functions.
392
393Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
394 int number_of_transitions,
395 int slack) {
396 Handle<FixedArray> array = isolate->factory()->NewTransitionArray(
397 LengthFor(number_of_transitions + slack));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000398 array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
399 array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
400 return Handle<TransitionArray>::cast(array);
401}
402
403
404// static
405void TransitionArray::ZapTransitionArray(TransitionArray* transitions) {
406 // Do not zap the next link that is used by GC.
407 STATIC_ASSERT(kNextLinkIndex + 1 == kPrototypeTransitionsIndex);
408 MemsetPointer(transitions->data_start() + kPrototypeTransitionsIndex,
409 transitions->GetHeap()->the_hole_value(),
410 transitions->length() - kPrototypeTransitionsIndex);
411 transitions->SetNumberOfTransitions(0);
412}
413
414
415void TransitionArray::ReplaceTransitions(Handle<Map> map,
416 Object* new_transitions) {
417 Object* raw_transitions = map->raw_transitions();
418 if (IsFullTransitionArray(raw_transitions)) {
419 TransitionArray* old_transitions = TransitionArray::cast(raw_transitions);
420#ifdef DEBUG
421 CheckNewTransitionsAreConsistent(map, old_transitions, new_transitions);
422 DCHECK(old_transitions != new_transitions);
423#endif
424 // Transition arrays are not shared. When one is replaced, it should not
425 // keep referenced objects alive, so we zap it.
426 // When there is another reference to the array somewhere (e.g. a handle),
427 // not zapping turns from a waste of memory into a source of crashes.
428 ZapTransitionArray(old_transitions);
429 }
430 map->set_raw_transitions(new_transitions);
431}
432
433
434void TransitionArray::SetPrototypeTransitions(
435 Handle<Map> map, Handle<FixedArray> proto_transitions) {
436 EnsureHasFullTransitionArray(map);
437 TransitionArray* transitions = TransitionArray::cast(map->raw_transitions());
438 transitions->SetPrototypeTransitions(*proto_transitions);
439}
440
441
442void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) {
443 Object* raw_transitions = map->raw_transitions();
444 if (IsFullTransitionArray(raw_transitions)) return;
445 int nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
446 Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof);
447 DisallowHeapAllocation no_gc;
448 // Reload pointer after the allocation that just happened.
449 raw_transitions = map->raw_transitions();
450 int new_nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
451 if (new_nof != nof) {
452 DCHECK(new_nof == 0);
453 result->Shrink(ToKeyIndex(0));
454 result->SetNumberOfTransitions(0);
455 } else if (nof == 1) {
456 Map* target = GetSimpleTransition(raw_transitions);
457 Name* key = GetSimpleTransitionKey(target);
458 result->Set(0, key, target);
459 }
460 ReplaceTransitions(map, *result);
461}
462
463
464void TransitionArray::TraverseTransitionTreeInternal(Map* map,
465 TraverseCallback callback,
466 void* data) {
467 Object* raw_transitions = map->raw_transitions();
468 if (IsFullTransitionArray(raw_transitions)) {
469 TransitionArray* transitions = TransitionArray::cast(raw_transitions);
470 if (transitions->HasPrototypeTransitions()) {
471 FixedArray* proto_trans = transitions->GetPrototypeTransitions();
472 for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) {
473 int index = TransitionArray::kProtoTransitionHeaderSize + i;
474 WeakCell* cell = WeakCell::cast(proto_trans->get(index));
475 if (!cell->cleared()) {
476 TraverseTransitionTreeInternal(Map::cast(cell->value()), callback,
477 data);
478 }
479 }
480 }
481 for (int i = 0; i < transitions->number_of_transitions(); ++i) {
482 TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data);
483 }
484 } else if (IsSimpleTransition(raw_transitions)) {
485 TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions),
486 callback, data);
487 }
488 callback(map, data);
489}
490
491
492#ifdef DEBUG
493void TransitionArray::CheckNewTransitionsAreConsistent(
494 Handle<Map> map, TransitionArray* old_transitions, Object* transitions) {
495 // This function only handles full transition arrays.
496 DCHECK(IsFullTransitionArray(transitions));
497 TransitionArray* new_transitions = TransitionArray::cast(transitions);
498 for (int i = 0; i < old_transitions->number_of_transitions(); i++) {
499 Map* target = old_transitions->GetTarget(i);
500 if (target->instance_descriptors() == map->instance_descriptors()) {
501 Name* key = old_transitions->GetKey(i);
502 int new_target_index;
503 if (TransitionArray::IsSpecialTransition(key)) {
504 new_target_index = new_transitions->SearchSpecial(Symbol::cast(key));
505 } else {
506 PropertyDetails details =
507 TransitionArray::GetTargetDetails(key, target);
508 new_target_index =
509 new_transitions->Search(details.kind(), key, details.attributes());
510 }
511 DCHECK_NE(TransitionArray::kNotFound, new_target_index);
512 DCHECK_EQ(target, new_transitions->GetTarget(new_target_index));
513 }
514 }
515}
516#endif
517
518
519// Private non-static helper functions (operating on full transition arrays).
520
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400521int TransitionArray::SearchDetails(int transition, PropertyKind kind,
522 PropertyAttributes attributes,
523 int* out_insertion_index) {
524 int nof_transitions = number_of_transitions();
525 DCHECK(transition < nof_transitions);
526 Name* key = GetKey(transition);
527 for (; transition < nof_transitions && GetKey(transition) == key;
528 transition++) {
529 Map* target = GetTarget(transition);
530 PropertyDetails target_details = GetTargetDetails(key, target);
531
532 int cmp = CompareDetails(kind, attributes, target_details.kind(),
533 target_details.attributes());
534 if (cmp == 0) {
535 return transition;
536 } else if (cmp < 0) {
537 break;
538 }
539 }
540 if (out_insertion_index != NULL) *out_insertion_index = transition;
541 return kNotFound;
542}
543
544
545int TransitionArray::Search(PropertyKind kind, Name* name,
546 PropertyAttributes attributes,
547 int* out_insertion_index) {
548 int transition = SearchName(name, out_insertion_index);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100549 if (transition == kNotFound) return kNotFound;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400550 return SearchDetails(transition, kind, attributes, out_insertion_index);
551}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552} // namespace internal
553} // namespace v8