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/transitions.h" | 5 #include "src/transitions.h" |
6 | 6 |
7 #include "src/objects-inl.h" | 7 #include "src/objects-inl.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 |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 Object* raw_transitions = map->raw_transitions(); | 227 Object* raw_transitions = map->raw_transitions(); |
228 if (IsFullTransitionArray(raw_transitions)) { | 228 if (IsFullTransitionArray(raw_transitions)) { |
229 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | 229 TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
230 return transitions->number_of_transitions() < kMaxNumberOfTransitions; | 230 return transitions->number_of_transitions() < kMaxNumberOfTransitions; |
231 } | 231 } |
232 return true; | 232 return true; |
233 } | 233 } |
234 | 234 |
235 | 235 |
236 // static | 236 // static |
| 237 bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) { |
| 238 const int header = kProtoTransitionHeaderSize; |
| 239 int number_of_transitions = NumberOfPrototypeTransitions(array); |
| 240 if (number_of_transitions == 0) { |
| 241 // Empty array cannot be compacted. |
| 242 return false; |
| 243 } |
| 244 int new_number_of_transitions = 0; |
| 245 for (int i = 0; i < number_of_transitions; i++) { |
| 246 Object* cell = array->get(header + i); |
| 247 if (!WeakCell::cast(cell)->cleared()) { |
| 248 if (new_number_of_transitions != i) { |
| 249 array->set(header + new_number_of_transitions, cell); |
| 250 } |
| 251 new_number_of_transitions++; |
| 252 } |
| 253 } |
| 254 // Fill slots that became free with undefined value. |
| 255 for (int i = new_number_of_transitions; i < number_of_transitions; i++) { |
| 256 array->set_undefined(header + i); |
| 257 } |
| 258 if (number_of_transitions != new_number_of_transitions) { |
| 259 SetNumberOfPrototypeTransitions(array, new_number_of_transitions); |
| 260 } |
| 261 return new_number_of_transitions < number_of_transitions; |
| 262 } |
| 263 |
| 264 |
| 265 // static |
| 266 Handle<FixedArray> TransitionArray::GrowPrototypeTransitionArray( |
| 267 Handle<FixedArray> array, int new_capacity, Isolate* isolate) { |
| 268 // Grow array by factor 2 up to MaxCachedPrototypeTransitions. |
| 269 int capacity = array->length() - kProtoTransitionHeaderSize; |
| 270 new_capacity = Min(kMaxCachedPrototypeTransitions, new_capacity); |
| 271 DCHECK_GT(new_capacity, capacity); |
| 272 int grow_by = new_capacity - capacity; |
| 273 array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by); |
| 274 if (capacity < 0) { |
| 275 // There was no prototype transitions array before, so the size |
| 276 // couldn't be copied. Initialize it explicitly. |
| 277 SetNumberOfPrototypeTransitions(*array, 0); |
| 278 } |
| 279 return array; |
| 280 } |
| 281 |
| 282 |
| 283 // static |
| 284 int TransitionArray::NumberOfPrototypeTransitionsForTest(Map* map) { |
| 285 FixedArray* transitions = GetPrototypeTransitions(map); |
| 286 CompactPrototypeTransitionArray(transitions); |
| 287 return TransitionArray::NumberOfPrototypeTransitions(transitions); |
| 288 } |
| 289 |
| 290 |
| 291 // static |
237 void TransitionArray::PutPrototypeTransition(Handle<Map> map, | 292 void TransitionArray::PutPrototypeTransition(Handle<Map> map, |
238 Handle<Object> prototype, | 293 Handle<Object> prototype, |
239 Handle<Map> target_map) { | 294 Handle<Map> target_map) { |
240 DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); | 295 DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); |
241 // Don't cache prototype transition if this map is either shared, or a map of | 296 // Don't cache prototype transition if this map is either shared, or a map of |
242 // a prototype. | 297 // a prototype. |
243 if (map->is_prototype_map()) return; | 298 if (map->is_prototype_map()) return; |
244 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return; | 299 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return; |
245 | 300 |
246 const int header = kProtoTransitionHeaderSize; | 301 const int header = kProtoTransitionHeaderSize; |
247 | 302 |
248 Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map); | 303 Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map); |
249 | 304 |
250 Handle<FixedArray> cache(GetPrototypeTransitions(*map)); | 305 Handle<FixedArray> cache(GetPrototypeTransitions(*map)); |
251 int capacity = cache->length() - header; | 306 int capacity = cache->length() - header; |
252 int transitions = NumberOfPrototypeTransitions(*cache) + 1; | 307 int transitions = NumberOfPrototypeTransitions(*cache) + 1; |
253 | 308 |
254 if (transitions > capacity) { | 309 if (transitions > capacity) { |
255 // Grow array by factor 2 up to MaxCachedPrototypeTransitions. | 310 // Grow the array if compacting it doesn't free space. |
256 int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2); | 311 if (!CompactPrototypeTransitionArray(*cache)) { |
257 if (new_capacity == capacity) return; | 312 if (capacity == kMaxCachedPrototypeTransitions) return; |
258 int grow_by = new_capacity - capacity; | 313 cache = GrowPrototypeTransitionArray(cache, 2 * transitions, |
259 | 314 map->GetIsolate()); |
260 Isolate* isolate = map->GetIsolate(); | 315 SetPrototypeTransitions(map, cache); |
261 cache = isolate->factory()->CopyFixedArrayAndGrow(cache, grow_by); | |
262 if (capacity < 0) { | |
263 // There was no prototype transitions array before, so the size | |
264 // couldn't be copied. Initialize it explicitly. | |
265 SetNumberOfPrototypeTransitions(*cache, 0); | |
266 } | 316 } |
267 | |
268 SetPrototypeTransitions(map, cache); | |
269 } | 317 } |
270 | 318 |
271 // Reload number of transitions as GC might shrink them. | 319 // Reload number of transitions as they might have been compacted. |
272 int last = NumberOfPrototypeTransitions(*cache); | 320 int last = NumberOfPrototypeTransitions(*cache); |
273 int entry = header + last; | 321 int entry = header + last; |
274 | 322 |
275 cache->set(entry, *target_cell); | 323 cache->set(entry, *target_cell); |
276 SetNumberOfPrototypeTransitions(*cache, last + 1); | 324 SetNumberOfPrototypeTransitions(*cache, last + 1); |
277 } | 325 } |
278 | 326 |
279 | 327 |
280 // static | 328 // static |
281 Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map, | 329 Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map, |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 // Transition arrays are not shared. When one is replaced, it should not | 428 // Transition arrays are not shared. When one is replaced, it should not |
381 // keep referenced objects alive, so we zap it. | 429 // keep referenced objects alive, so we zap it. |
382 // When there is another reference to the array somewhere (e.g. a handle), | 430 // When there is another reference to the array somewhere (e.g. a handle), |
383 // not zapping turns from a waste of memory into a source of crashes. | 431 // not zapping turns from a waste of memory into a source of crashes. |
384 ZapTransitionArray(old_transitions); | 432 ZapTransitionArray(old_transitions); |
385 } | 433 } |
386 map->set_raw_transitions(new_transitions); | 434 map->set_raw_transitions(new_transitions); |
387 } | 435 } |
388 | 436 |
389 | 437 |
390 static void ZapPrototypeTransitions(Object* raw_transitions) { | |
391 DCHECK(TransitionArray::IsFullTransitionArray(raw_transitions)); | |
392 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | |
393 if (!transitions->HasPrototypeTransitions()) return; | |
394 FixedArray* proto_transitions = transitions->GetPrototypeTransitions(); | |
395 MemsetPointer(proto_transitions->data_start(), | |
396 proto_transitions->GetHeap()->the_hole_value(), | |
397 proto_transitions->length()); | |
398 } | |
399 | |
400 | |
401 void TransitionArray::SetPrototypeTransitions( | 438 void TransitionArray::SetPrototypeTransitions( |
402 Handle<Map> map, Handle<FixedArray> proto_transitions) { | 439 Handle<Map> map, Handle<FixedArray> proto_transitions) { |
403 EnsureHasFullTransitionArray(map); | 440 EnsureHasFullTransitionArray(map); |
404 if (Heap::ShouldZapGarbage()) { | |
405 Object* raw_transitions = map->raw_transitions(); | |
406 DCHECK(raw_transitions != *proto_transitions); | |
407 ZapPrototypeTransitions(raw_transitions); | |
408 } | |
409 TransitionArray* transitions = TransitionArray::cast(map->raw_transitions()); | 441 TransitionArray* transitions = TransitionArray::cast(map->raw_transitions()); |
410 transitions->SetPrototypeTransitions(*proto_transitions); | 442 transitions->SetPrototypeTransitions(*proto_transitions); |
411 } | 443 } |
412 | 444 |
413 | 445 |
414 void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) { | 446 void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) { |
415 Object* raw_transitions = map->raw_transitions(); | 447 Object* raw_transitions = map->raw_transitions(); |
416 if (IsFullTransitionArray(raw_transitions)) return; | 448 if (IsFullTransitionArray(raw_transitions)) return; |
417 int nof = IsSimpleTransition(raw_transitions) ? 1 : 0; | 449 int nof = IsSimpleTransition(raw_transitions) ? 1 : 0; |
418 Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof); | 450 Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof); |
(...skipping 18 matching lines...) Expand all Loading... |
437 TraverseCallback callback, | 469 TraverseCallback callback, |
438 void* data) { | 470 void* data) { |
439 Object* raw_transitions = map->raw_transitions(); | 471 Object* raw_transitions = map->raw_transitions(); |
440 if (IsFullTransitionArray(raw_transitions)) { | 472 if (IsFullTransitionArray(raw_transitions)) { |
441 TransitionArray* transitions = TransitionArray::cast(raw_transitions); | 473 TransitionArray* transitions = TransitionArray::cast(raw_transitions); |
442 if (transitions->HasPrototypeTransitions()) { | 474 if (transitions->HasPrototypeTransitions()) { |
443 FixedArray* proto_trans = transitions->GetPrototypeTransitions(); | 475 FixedArray* proto_trans = transitions->GetPrototypeTransitions(); |
444 for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) { | 476 for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) { |
445 int index = TransitionArray::kProtoTransitionHeaderSize + i; | 477 int index = TransitionArray::kProtoTransitionHeaderSize + i; |
446 WeakCell* cell = WeakCell::cast(proto_trans->get(index)); | 478 WeakCell* cell = WeakCell::cast(proto_trans->get(index)); |
447 TraverseTransitionTreeInternal(Map::cast(cell->value()), callback, | 479 if (!cell->cleared()) { |
448 data); | 480 TraverseTransitionTreeInternal(Map::cast(cell->value()), callback, |
| 481 data); |
| 482 } |
449 } | 483 } |
450 } | 484 } |
451 for (int i = 0; i < transitions->number_of_transitions(); ++i) { | 485 for (int i = 0; i < transitions->number_of_transitions(); ++i) { |
452 TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data); | 486 TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data); |
453 } | 487 } |
454 } else if (IsSimpleTransition(raw_transitions)) { | 488 } else if (IsSimpleTransition(raw_transitions)) { |
455 TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions), | 489 TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions), |
456 callback, data); | 490 callback, data); |
457 } | 491 } |
458 callback(map, data); | 492 callback(map, data); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 PropertyAttributes attributes, | 550 PropertyAttributes attributes, |
517 int* out_insertion_index) { | 551 int* out_insertion_index) { |
518 int transition = SearchName(name, out_insertion_index); | 552 int transition = SearchName(name, out_insertion_index); |
519 if (transition == kNotFound) { | 553 if (transition == kNotFound) { |
520 return kNotFound; | 554 return kNotFound; |
521 } | 555 } |
522 return SearchDetails(transition, kind, attributes, out_insertion_index); | 556 return SearchDetails(transition, kind, attributes, out_insertion_index); |
523 } | 557 } |
524 } // namespace internal | 558 } // namespace internal |
525 } // namespace v8 | 559 } // namespace v8 |
OLD | NEW |