OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/objects.h" | 7 #include "src/objects.h" |
8 #include "src/transitions-inl.h" | 8 #include "src/transitions-inl.h" |
9 #include "src/utils.h" | 9 #include "src/utils.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 | 13 |
14 | 14 |
15 // static | |
16 void TransitionArray::Insert(Handle<Map> map, Handle<Name> name, | |
17 Handle<Map> target, SimpleTransitionFlag flag) { | |
18 Isolate* isolate = map->GetIsolate(); | |
19 target->SetBackPointer(*map); | |
20 | |
21 // 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 map->set_raw_transitions(*cell); | |
26 return; | |
27 } | |
28 // If the flag requires a full TransitionArray, allocate one. | |
29 Handle<TransitionArray> result = Allocate(isolate, 0, 1); | |
30 map->set_raw_transitions(*result); | |
31 } | |
32 | |
33 bool is_special_transition = flag == SPECIAL_TRANSITION; | |
34 // 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(NONE, DATA, 0) | |
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 map->set_raw_transitions(*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->NoIncrementalWriteBarrierSet( | |
55 0, GetSimpleTransitionKey(old_target), old_target); | |
56 } else { | |
57 result->SetNumberOfTransitions(0); | |
58 } | |
59 map->set_raw_transitions(*result); | |
60 } | |
61 | |
62 // At this point, we know that the map has a full TransitionArray. | |
63 DCHECK(IsFullTransitionArray(map->raw_transitions())); | |
64 | |
65 int number_of_transitions = 0; | |
66 int new_nof = 0; | |
67 int insertion_index = kNotFound; | |
68 DCHECK_EQ(is_special_transition, IsSpecialTransition(*name)); | |
69 PropertyDetails details = is_special_transition | |
70 ? PropertyDetails(NONE, DATA, 0) | |
71 : GetTargetDetails(*name, *target); | |
72 | |
73 { | |
74 DisallowHeapAllocation no_gc; | |
75 TransitionArray* array = TransitionArray::cast(map->raw_transitions()); | |
76 number_of_transitions = array->number_of_transitions(); | |
77 new_nof = number_of_transitions; | |
78 | |
79 int index = | |
80 is_special_transition | |
81 ? array->SearchSpecial(Symbol::cast(*name), &insertion_index) | |
82 : array->Search(details.kind(), *name, details.attributes(), | |
83 &insertion_index); | |
84 // If an existing entry was found, overwrite it and return. | |
85 if (index != kNotFound) { | |
86 array->SetTarget(index, *target); | |
87 return; | |
88 } | |
89 | |
90 ++new_nof; | |
91 CHECK(new_nof <= kMaxNumberOfTransitions); | |
92 DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions); | |
93 | |
94 // If there is enough capacity, insert new entry into the existing array. | |
95 if (new_nof <= Capacity(array)) { | |
96 array->SetNumberOfTransitions(new_nof); | |
97 for (index = number_of_transitions; index > insertion_index; --index) { | |
98 array->SetKey(index, array->GetKey(index - 1)); | |
99 array->SetTarget(index, array->GetTarget(index - 1)); | |
100 } | |
101 array->SetKey(index, *name); | |
102 array->SetTarget(index, *target); | |
103 SLOW_DCHECK(array->IsSortedNoDuplicates()); | |
104 return; | |
105 } | |
106 } | |
107 | |
108 // We're gonna need a bigger TransitionArray. | |
109 Handle<TransitionArray> result = Allocate( | |
110 map->GetIsolate(), new_nof, | |
111 Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions)); | |
112 | |
113 // The map's transition array may have shrunk during the allocation above as | |
114 // it was weakly traversed, though it is guaranteed not to disappear. Trim the | |
115 // result copy if needed, and recompute variables. | |
116 DCHECK(IsFullTransitionArray(map->raw_transitions())); | |
117 DisallowHeapAllocation no_gc; | |
118 TransitionArray* array = TransitionArray::cast(map->raw_transitions()); | |
119 if (array->number_of_transitions() != number_of_transitions) { | |
120 DCHECK(array->number_of_transitions() < number_of_transitions); | |
121 | |
122 number_of_transitions = array->number_of_transitions(); | |
123 new_nof = number_of_transitions; | |
124 | |
125 insertion_index = kNotFound; | |
126 int index = | |
127 is_special_transition | |
128 ? array->SearchSpecial(Symbol::cast(*name), &insertion_index) | |
129 : array->Search(details.kind(), *name, details.attributes(), | |
130 &insertion_index); | |
131 if (index == kNotFound) { | |
132 ++new_nof; | |
133 } else { | |
134 insertion_index = index; | |
135 } | |
136 DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions); | |
137 | |
138 result->Shrink(ToKeyIndex(new_nof)); | |
139 result->SetNumberOfTransitions(new_nof); | |
140 } | |
141 | |
142 if (array->HasPrototypeTransitions()) { | |
143 result->SetPrototypeTransitions(array->GetPrototypeTransitions()); | |
144 } | |
145 | |
146 DCHECK_NE(kNotFound, insertion_index); | |
147 for (int i = 0; i < insertion_index; ++i) { | |
148 result->NoIncrementalWriteBarrierCopyFrom(array, i, i); | |
149 } | |
150 result->NoIncrementalWriteBarrierSet(insertion_index, *name, *target); | |
151 for (int i = insertion_index; i < number_of_transitions; ++i) { | |
152 result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1); | |
153 } | |
154 | |
155 SLOW_DCHECK(result->IsSortedNoDuplicates()); | |
156 map->set_raw_transitions(*result); | |
157 } | |
158 | |
159 | |
160 // static | |
161 Map* TransitionArray::SearchTransition(Map* map, PropertyKind kind, Name* name, | |
162 PropertyAttributes attributes) { | |
163 Object* raw_transitions = map->raw_transitions(); | |
164 if (IsSimpleTransition(raw_transitions)) { | |
165 Map* target = GetSimpleTransition(raw_transitions); | |
166 Name* key = GetSimpleTransitionKey(target); | |
167 if (!key->Equals(name)) return NULL; | |
168 PropertyDetails details = GetSimpleTargetDetails(target); | |
169 if (details.attributes() != attributes) return NULL; | |
170 if (details.kind() != kind) return NULL; | |
171 return target; | |
172 } | |
173 if (IsFullTransitionArray(raw_transitions)) { | |
174 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | |
175 int transition = transitions->Search(kind, name, attributes); | |
176 if (transition == kNotFound) return NULL; | |
177 return transitions->GetTarget(transition); | |
178 } | |
179 return NULL; | |
180 } | |
181 | |
182 | |
183 // static | |
184 Map* 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 | |
197 Handle<Map> TransitionArray::FindTransitionToField(Handle<Map> map, | |
198 Handle<Name> name) { | |
199 DisallowHeapAllocation no_gc; | |
200 Map* target = SearchTransition(*map, kData, *name, NONE); | |
201 if (target == NULL) return Handle<Map>::null(); | |
202 PropertyDetails details = target->GetLastDescriptorDetails(); | |
203 DCHECK_EQ(NONE, details.attributes()); | |
204 if (details.type() != DATA) return Handle<Map>::null(); | |
205 return Handle<Map>(target); | |
206 } | |
207 | |
208 | |
209 // static | |
210 Handle<String> TransitionArray::ExpectedTransitionKey(Handle<Map> map) { | |
211 DisallowHeapAllocation no_gc; | |
212 Object* raw_transition = map->raw_transitions(); | |
213 if (!IsSimpleTransition(raw_transition)) return Handle<String>::null(); | |
214 Map* target = GetSimpleTransition(raw_transition); | |
215 PropertyDetails details = GetSimpleTargetDetails(target); | |
216 if (details.type() != DATA) return Handle<String>::null(); | |
217 if (details.attributes() != NONE) return Handle<String>::null(); | |
218 Name* name = GetSimpleTransitionKey(target); | |
219 if (!name->IsString()) return Handle<String>::null(); | |
220 return Handle<String>(String::cast(name)); | |
221 } | |
222 | |
223 | |
224 // static | |
225 bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) { | |
226 Object* raw_transitions = map->raw_transitions(); | |
227 if (IsFullTransitionArray(raw_transitions)) { | |
228 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | |
229 return transitions->number_of_transitions() < kMaxNumberOfTransitions; | |
230 } | |
231 return true; | |
232 } | |
233 | |
234 | |
235 // static | |
236 Handle<Map> TransitionArray::PutPrototypeTransition(Handle<Map> map, | |
237 Handle<Object> prototype, | |
238 Handle<Map> target_map) { | |
239 DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); | |
240 // Don't cache prototype transition if this map is either shared, or a map of | |
241 // a prototype. | |
242 if (map->is_prototype_map()) return map; | |
243 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map; | |
244 | |
245 const int header = kProtoTransitionHeaderSize; | |
246 | |
247 Handle<FixedArray> cache(GetPrototypeTransitions(*map)); | |
248 int capacity = cache->length() - header; | |
249 int transitions = NumberOfPrototypeTransitions(*cache) + 1; | |
250 | |
251 if (transitions > capacity) { | |
252 // Grow array by factor 2 up to MaxCachedPrototypeTransitions. | |
253 int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2); | |
254 if (new_capacity == capacity) return map; | |
255 | |
256 cache = FixedArray::CopySize(cache, header + new_capacity); | |
257 if (capacity < 0) { | |
258 // There was no prototype transitions array before, so the size | |
259 // couldn't be copied. Initialize it explicitly. | |
260 SetNumberOfPrototypeTransitions(*cache, 0); | |
261 } | |
262 | |
263 SetPrototypeTransitions(map, cache); | |
264 } | |
265 | |
266 // Reload number of transitions as GC might shrink them. | |
267 int last = NumberOfPrototypeTransitions(*cache); | |
268 int entry = header + last; | |
269 | |
270 cache->set(entry, *target_map); | |
271 SetNumberOfPrototypeTransitions(*cache, last + 1); | |
272 | |
273 return map; | |
274 } | |
275 | |
276 | |
277 // static | |
278 Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map, | |
279 Handle<Object> prototype) { | |
280 DisallowHeapAllocation no_gc; | |
281 FixedArray* cache = GetPrototypeTransitions(*map); | |
282 int number_of_transitions = NumberOfPrototypeTransitions(cache); | |
283 for (int i = 0; i < number_of_transitions; i++) { | |
284 Map* target = Map::cast(cache->get(kProtoTransitionHeaderSize + i)); | |
285 if (target->prototype() == *prototype) return handle(target); | |
286 } | |
287 return Handle<Map>(); | |
288 } | |
289 | |
290 | |
291 // static | |
292 FixedArray* TransitionArray::GetPrototypeTransitions(Map* map) { | |
293 Object* raw_transitions = map->raw_transitions(); | |
294 Heap* heap = map->GetHeap(); | |
295 if (!IsFullTransitionArray(raw_transitions)) { | |
296 return heap->empty_fixed_array(); | |
297 } | |
298 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | |
299 if (!transitions->HasPrototypeTransitions()) { | |
300 return heap->empty_fixed_array(); | |
301 } | |
302 return transitions->GetPrototypeTransitions(); | |
303 } | |
304 | |
305 | |
306 // static | |
307 void TransitionArray::SetNumberOfPrototypeTransitions( | |
308 FixedArray* proto_transitions, int value) { | |
309 DCHECK(proto_transitions->length() != 0); | |
310 proto_transitions->set(kProtoTransitionNumberOfEntriesOffset, | |
311 Smi::FromInt(value)); | |
312 } | |
313 | |
314 | |
315 // static | |
316 int TransitionArray::NumberOfTransitions(Object* raw_transitions) { | |
317 if (CanStoreSimpleTransition(raw_transitions)) return 0; | |
318 if (IsSimpleTransition(raw_transitions)) return 1; | |
319 DCHECK(IsFullTransitionArray(raw_transitions)); | |
320 return TransitionArray::cast(raw_transitions)->number_of_transitions(); | |
321 } | |
322 | |
323 | |
324 // static | |
325 int TransitionArray::Capacity(Object* raw_transitions) { | |
326 if (!IsFullTransitionArray(raw_transitions)) return 1; | |
327 TransitionArray* t = TransitionArray::cast(raw_transitions); | |
328 if (t->length() <= kFirstIndex) return 0; | |
329 return (t->length() - kFirstIndex) / kTransitionSize; | |
330 } | |
331 | |
332 | |
333 // Private static helper functions. | |
334 | |
335 Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate, | 15 Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate, |
336 int number_of_transitions, | 16 int number_of_transitions, |
337 int slack) { | 17 int slack) { |
338 Handle<FixedArray> array = isolate->factory()->NewFixedArray( | 18 Handle<FixedArray> array = isolate->factory()->NewFixedArray( |
339 LengthFor(number_of_transitions + slack)); | 19 LengthFor(number_of_transitions + slack)); |
340 array->set(kPrototypeTransitionsIndex, Smi::FromInt(0)); | 20 array->set(kPrototypeTransitionsIndex, Smi::FromInt(0)); |
341 array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions)); | 21 array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions)); |
342 return Handle<TransitionArray>::cast(array); | 22 return Handle<TransitionArray>::cast(array); |
343 } | 23 } |
344 | 24 |
345 | 25 |
| 26 Handle<TransitionArray> TransitionArray::AllocateSimple(Isolate* isolate, |
| 27 Handle<Map> target) { |
| 28 Handle<FixedArray> array = |
| 29 isolate->factory()->NewFixedArray(kSimpleTransitionSize); |
| 30 array->set(kSimpleTransitionTarget, *target); |
| 31 return Handle<TransitionArray>::cast(array); |
| 32 } |
| 33 |
| 34 |
346 void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin, | 35 void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin, |
347 int origin_transition, | 36 int origin_transition, |
348 int target_transition) { | 37 int target_transition) { |
349 NoIncrementalWriteBarrierSet(target_transition, | 38 NoIncrementalWriteBarrierSet(target_transition, |
350 origin->GetKey(origin_transition), | 39 origin->GetKey(origin_transition), |
351 origin->GetTarget(origin_transition)); | 40 origin->GetTarget(origin_transition)); |
352 } | 41 } |
353 | 42 |
354 | 43 |
355 static void ZapTransitionArray(TransitionArray* transitions) { | 44 Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map, |
356 MemsetPointer(transitions->data_start(), | 45 Handle<Name> name, |
357 transitions->GetHeap()->the_hole_value(), | 46 Handle<Map> target, |
358 transitions->length()); | 47 SimpleTransitionFlag flag) { |
| 48 Handle<TransitionArray> result; |
| 49 Isolate* isolate = name->GetIsolate(); |
| 50 |
| 51 if (flag == SIMPLE_PROPERTY_TRANSITION) { |
| 52 result = AllocateSimple(isolate, target); |
| 53 } else { |
| 54 result = Allocate(isolate, 1); |
| 55 result->NoIncrementalWriteBarrierSet(0, *name, *target); |
| 56 } |
| 57 result->set_back_pointer_storage(map->GetBackPointer()); |
| 58 return result; |
359 } | 59 } |
360 | 60 |
361 | 61 |
362 void TransitionArray::ReplaceTransitions(Handle<Map> map, | 62 Handle<TransitionArray> TransitionArray::ExtendToFullTransitionArray( |
363 Object* new_transitions) { | 63 Handle<Map> containing_map) { |
364 Object* raw_transitions = map->raw_transitions(); | 64 DCHECK(!containing_map->transitions()->IsFullTransitionArray()); |
365 if (IsFullTransitionArray(raw_transitions)) { | 65 int nof = containing_map->transitions()->number_of_transitions(); |
366 TransitionArray* old_transitions = TransitionArray::cast(raw_transitions); | |
367 #ifdef DEBUG | |
368 CheckNewTransitionsAreConsistent(map, old_transitions, new_transitions); | |
369 DCHECK(old_transitions != new_transitions); | |
370 #endif | |
371 // Transition arrays are not shared. When one is replaced, it should not | |
372 // keep referenced objects alive, so we zap it. | |
373 // When there is another reference to the array somewhere (e.g. a handle), | |
374 // not zapping turns from a waste of memory into a source of crashes. | |
375 ZapTransitionArray(old_transitions); | |
376 } | |
377 map->set_raw_transitions(new_transitions); | |
378 } | |
379 | 66 |
380 | 67 // A transition array may shrink during GC. |
381 static void ZapPrototypeTransitions(Object* raw_transitions) { | 68 Handle<TransitionArray> result = Allocate(containing_map->GetIsolate(), nof); |
382 DCHECK(TransitionArray::IsFullTransitionArray(raw_transitions)); | |
383 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | |
384 if (!transitions->HasPrototypeTransitions()) return; | |
385 FixedArray* proto_transitions = transitions->GetPrototypeTransitions(); | |
386 MemsetPointer(proto_transitions->data_start(), | |
387 proto_transitions->GetHeap()->the_hole_value(), | |
388 proto_transitions->length()); | |
389 } | |
390 | |
391 | |
392 void TransitionArray::SetPrototypeTransitions( | |
393 Handle<Map> map, Handle<FixedArray> proto_transitions) { | |
394 EnsureHasFullTransitionArray(map); | |
395 if (Heap::ShouldZapGarbage()) { | |
396 Object* raw_transitions = map->raw_transitions(); | |
397 DCHECK(raw_transitions != *proto_transitions); | |
398 ZapPrototypeTransitions(raw_transitions); | |
399 } | |
400 TransitionArray* transitions = TransitionArray::cast(map->raw_transitions()); | |
401 transitions->SetPrototypeTransitions(*proto_transitions); | |
402 } | |
403 | |
404 | |
405 void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) { | |
406 Object* raw_transitions = map->raw_transitions(); | |
407 if (IsFullTransitionArray(raw_transitions)) return; | |
408 int nof = IsSimpleTransition(raw_transitions) ? 1 : 0; | |
409 Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof); | |
410 DisallowHeapAllocation no_gc; | 69 DisallowHeapAllocation no_gc; |
411 // Reload pointer after the allocation that just happened. | 70 int new_nof = containing_map->transitions()->number_of_transitions(); |
412 raw_transitions = map->raw_transitions(); | |
413 int new_nof = IsSimpleTransition(raw_transitions) ? 1 : 0; | |
414 if (new_nof != nof) { | 71 if (new_nof != nof) { |
415 DCHECK(new_nof == 0); | 72 DCHECK(new_nof == 0); |
416 result->Shrink(ToKeyIndex(0)); | 73 result->Shrink(ToKeyIndex(0)); |
417 result->SetNumberOfTransitions(0); | 74 result->SetNumberOfTransitions(0); |
418 } else if (nof == 1) { | 75 } else if (nof == 1) { |
419 Map* target = GetSimpleTransition(raw_transitions); | 76 result->NoIncrementalWriteBarrierCopyFrom( |
420 Name* key = GetSimpleTransitionKey(target); | 77 containing_map->transitions(), kSimpleTransitionIndex, 0); |
421 result->NoIncrementalWriteBarrierSet(0, key, target); | |
422 } | 78 } |
423 ReplaceTransitions(map, *result); | 79 |
| 80 result->set_back_pointer_storage( |
| 81 containing_map->transitions()->back_pointer_storage()); |
| 82 return result; |
424 } | 83 } |
425 | 84 |
426 | 85 |
427 void TransitionArray::TraverseTransitionTreeInternal(Map* map, | 86 Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map, |
428 TraverseCallback callback, | 87 Handle<Name> name, |
429 void* data) { | 88 Handle<Map> target, |
430 Object* raw_transitions = map->raw_transitions(); | 89 SimpleTransitionFlag flag) { |
431 if (IsFullTransitionArray(raw_transitions)) { | 90 if (!map->HasTransitionArray()) { |
432 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | 91 return TransitionArray::NewWith(map, name, target, flag); |
433 if (transitions->HasPrototypeTransitions()) { | 92 } |
434 FixedArray* proto_trans = transitions->GetPrototypeTransitions(); | 93 |
435 for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) { | 94 int number_of_transitions = map->transitions()->number_of_transitions(); |
436 int index = TransitionArray::kProtoTransitionHeaderSize + i; | 95 int new_nof = number_of_transitions; |
437 TraverseTransitionTreeInternal(Map::cast(proto_trans->get(index)), | 96 |
438 callback, data); | 97 bool is_special_transition = flag == SPECIAL_TRANSITION; |
439 } | 98 DCHECK_EQ(is_special_transition, IsSpecialTransition(*name)); |
| 99 PropertyDetails details = is_special_transition |
| 100 ? PropertyDetails(NONE, DATA, 0) |
| 101 : GetTargetDetails(*name, *target); |
| 102 |
| 103 int insertion_index = kNotFound; |
| 104 int index = |
| 105 is_special_transition |
| 106 ? map->transitions()->SearchSpecial(Symbol::cast(*name), |
| 107 &insertion_index) |
| 108 : map->transitions()->Search(details.kind(), *name, |
| 109 details.attributes(), &insertion_index); |
| 110 if (index == kNotFound) { |
| 111 ++new_nof; |
| 112 } else { |
| 113 insertion_index = index; |
| 114 } |
| 115 DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions); |
| 116 |
| 117 CHECK(new_nof <= kMaxNumberOfTransitions); |
| 118 |
| 119 if (new_nof <= map->transitions()->number_of_transitions_storage()) { |
| 120 DisallowHeapAllocation no_gc; |
| 121 TransitionArray* array = map->transitions(); |
| 122 |
| 123 if (index != kNotFound) { |
| 124 array->SetTarget(index, *target); |
| 125 return handle(array); |
440 } | 126 } |
441 for (int i = 0; i < transitions->number_of_transitions(); ++i) { | 127 |
442 TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data); | 128 array->SetNumberOfTransitions(new_nof); |
| 129 for (index = number_of_transitions; index > insertion_index; --index) { |
| 130 Name* key = array->GetKey(index - 1); |
| 131 array->SetKey(index, key); |
| 132 array->SetTarget(index, array->GetTarget(index - 1)); |
443 } | 133 } |
444 } else if (IsSimpleTransition(raw_transitions)) { | 134 array->SetKey(index, *name); |
445 TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions), | 135 array->SetTarget(index, *target); |
446 callback, data); | 136 SLOW_DCHECK(array->IsSortedNoDuplicates()); |
| 137 return handle(array); |
447 } | 138 } |
448 callback(map, data); | 139 |
| 140 Handle<TransitionArray> result = Allocate( |
| 141 map->GetIsolate(), new_nof, |
| 142 Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions)); |
| 143 |
| 144 // The map's transition array may grown smaller during the allocation above as |
| 145 // it was weakly traversed, though it is guaranteed not to disappear. Trim the |
| 146 // result copy if needed, and recompute variables. |
| 147 DCHECK(map->HasTransitionArray()); |
| 148 DisallowHeapAllocation no_gc; |
| 149 TransitionArray* array = map->transitions(); |
| 150 if (array->number_of_transitions() != number_of_transitions) { |
| 151 DCHECK(array->number_of_transitions() < number_of_transitions); |
| 152 |
| 153 number_of_transitions = array->number_of_transitions(); |
| 154 new_nof = number_of_transitions; |
| 155 |
| 156 insertion_index = kNotFound; |
| 157 index = is_special_transition ? map->transitions()->SearchSpecial( |
| 158 Symbol::cast(*name), &insertion_index) |
| 159 : map->transitions()->Search( |
| 160 details.kind(), *name, |
| 161 details.attributes(), &insertion_index); |
| 162 if (index == kNotFound) { |
| 163 ++new_nof; |
| 164 } else { |
| 165 insertion_index = index; |
| 166 } |
| 167 DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions); |
| 168 |
| 169 result->Shrink(ToKeyIndex(new_nof)); |
| 170 result->SetNumberOfTransitions(new_nof); |
| 171 } |
| 172 |
| 173 if (array->HasPrototypeTransitions()) { |
| 174 result->SetPrototypeTransitions(array->GetPrototypeTransitions()); |
| 175 } |
| 176 |
| 177 DCHECK_NE(kNotFound, insertion_index); |
| 178 for (int i = 0; i < insertion_index; ++i) { |
| 179 result->NoIncrementalWriteBarrierCopyFrom(array, i, i); |
| 180 } |
| 181 result->NoIncrementalWriteBarrierSet(insertion_index, *name, *target); |
| 182 for (int i = insertion_index; i < number_of_transitions; ++i) { |
| 183 result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1); |
| 184 } |
| 185 |
| 186 result->set_back_pointer_storage(array->back_pointer_storage()); |
| 187 SLOW_DCHECK(result->IsSortedNoDuplicates()); |
| 188 return result; |
449 } | 189 } |
450 | 190 |
451 | 191 |
452 #ifdef DEBUG | |
453 void TransitionArray::CheckNewTransitionsAreConsistent( | |
454 Handle<Map> map, TransitionArray* old_transitions, Object* transitions) { | |
455 // This function only handles full transition arrays. | |
456 DCHECK(IsFullTransitionArray(transitions)); | |
457 TransitionArray* new_transitions = TransitionArray::cast(transitions); | |
458 for (int i = 0; i < old_transitions->number_of_transitions(); i++) { | |
459 Map* target = old_transitions->GetTarget(i); | |
460 if (target->instance_descriptors() == map->instance_descriptors()) { | |
461 Name* key = old_transitions->GetKey(i); | |
462 int new_target_index; | |
463 if (TransitionArray::IsSpecialTransition(key)) { | |
464 new_target_index = new_transitions->SearchSpecial(Symbol::cast(key)); | |
465 } else { | |
466 PropertyDetails details = | |
467 TransitionArray::GetTargetDetails(key, target); | |
468 new_target_index = | |
469 new_transitions->Search(details.kind(), key, details.attributes()); | |
470 } | |
471 DCHECK_NE(TransitionArray::kNotFound, new_target_index); | |
472 DCHECK_EQ(target, new_transitions->GetTarget(new_target_index)); | |
473 } | |
474 } | |
475 } | |
476 #endif | |
477 | |
478 | |
479 // Private non-static helper functions (operating on full transition arrays). | |
480 | |
481 int TransitionArray::SearchDetails(int transition, PropertyKind kind, | 192 int TransitionArray::SearchDetails(int transition, PropertyKind kind, |
482 PropertyAttributes attributes, | 193 PropertyAttributes attributes, |
483 int* out_insertion_index) { | 194 int* out_insertion_index) { |
484 int nof_transitions = number_of_transitions(); | 195 int nof_transitions = number_of_transitions(); |
485 DCHECK(transition < nof_transitions); | 196 DCHECK(transition < nof_transitions); |
486 Name* key = GetKey(transition); | 197 Name* key = GetKey(transition); |
487 for (; transition < nof_transitions && GetKey(transition) == key; | 198 for (; transition < nof_transitions && GetKey(transition) == key; |
488 transition++) { | 199 transition++) { |
489 Map* target = GetTarget(transition); | 200 Map* target = GetTarget(transition); |
490 PropertyDetails target_details = GetTargetDetails(key, target); | 201 PropertyDetails target_details = GetTargetDetails(key, target); |
(...skipping 14 matching lines...) Expand all Loading... |
505 int TransitionArray::Search(PropertyKind kind, Name* name, | 216 int TransitionArray::Search(PropertyKind kind, Name* name, |
506 PropertyAttributes attributes, | 217 PropertyAttributes attributes, |
507 int* out_insertion_index) { | 218 int* out_insertion_index) { |
508 int transition = SearchName(name, out_insertion_index); | 219 int transition = SearchName(name, out_insertion_index); |
509 if (transition == kNotFound) { | 220 if (transition == kNotFound) { |
510 return kNotFound; | 221 return kNotFound; |
511 } | 222 } |
512 return SearchDetails(transition, kind, attributes, out_insertion_index); | 223 return SearchDetails(transition, kind, attributes, out_insertion_index); |
513 } | 224 } |
514 } } // namespace v8::internal | 225 } } // namespace v8::internal |
OLD | NEW |