Chromium Code Reviews| 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 = TransitionArray::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 | |
| 237 void TransitionArray::PutPrototypeTransition(Handle<Map> map, | 284 void TransitionArray::PutPrototypeTransition(Handle<Map> map, |
| 238 Handle<Object> prototype, | 285 Handle<Object> prototype, |
| 239 Handle<Map> target_map) { | 286 Handle<Map> target_map) { |
| 240 DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); | 287 DCHECK(HeapObject::cast(*prototype)->map()->IsMap()); |
| 241 // Don't cache prototype transition if this map is either shared, or a map of | 288 // Don't cache prototype transition if this map is either shared, or a map of |
| 242 // a prototype. | 289 // a prototype. |
| 243 if (map->is_prototype_map()) return; | 290 if (map->is_prototype_map()) return; |
| 244 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return; | 291 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return; |
| 245 | 292 |
| 246 const int header = kProtoTransitionHeaderSize; | 293 const int header = kProtoTransitionHeaderSize; |
| 247 | 294 |
| 248 Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map); | 295 Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map); |
| 249 | 296 |
| 250 Handle<FixedArray> cache(GetPrototypeTransitions(*map)); | 297 Handle<FixedArray> cache(GetPrototypeTransitions(*map)); |
| 251 int capacity = cache->length() - header; | 298 int capacity = cache->length() - header; |
| 252 int transitions = NumberOfPrototypeTransitions(*cache) + 1; | 299 int transitions = NumberOfPrototypeTransitions(*cache) + 1; |
| 253 | 300 |
| 254 if (transitions > capacity) { | 301 if (transitions > capacity) { |
| 255 // Grow array by factor 2 up to MaxCachedPrototypeTransitions. | 302 // Grow the array if compacting it doesn't free space. |
| 256 int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2); | 303 if (!CompactPrototypeTransitionArray(*cache)) { |
| 257 if (new_capacity == capacity) return; | 304 if (capacity == kMaxCachedPrototypeTransitions) return; |
| 258 int grow_by = new_capacity - capacity; | 305 cache = GrowPrototypeTransitionArray(cache, 2 * transitions, |
| 259 | 306 map->GetIsolate()); |
| 260 Isolate* isolate = map->GetIsolate(); | 307 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 } | 308 } |
| 267 | |
| 268 SetPrototypeTransitions(map, cache); | |
| 269 } | 309 } |
| 270 | 310 |
| 271 // Reload number of transitions as GC might shrink them. | 311 // Reload number of transitions as they might have been compacted. |
| 272 int last = NumberOfPrototypeTransitions(*cache); | 312 int last = NumberOfPrototypeTransitions(*cache); |
| 273 int entry = header + last; | 313 int entry = header + last; |
| 274 | 314 |
| 275 cache->set(entry, *target_cell); | 315 cache->set(entry, *target_cell); |
| 276 SetNumberOfPrototypeTransitions(*cache, last + 1); | 316 SetNumberOfPrototypeTransitions(*cache, last + 1); |
| 277 } | 317 } |
| 278 | 318 |
| 279 | 319 |
| 280 // static | 320 // static |
| 281 Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map, | 321 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 | 420 // Transition arrays are not shared. When one is replaced, it should not |
| 381 // keep referenced objects alive, so we zap it. | 421 // keep referenced objects alive, so we zap it. |
| 382 // When there is another reference to the array somewhere (e.g. a handle), | 422 // 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. | 423 // not zapping turns from a waste of memory into a source of crashes. |
| 384 ZapTransitionArray(old_transitions); | 424 ZapTransitionArray(old_transitions); |
| 385 } | 425 } |
| 386 map->set_raw_transitions(new_transitions); | 426 map->set_raw_transitions(new_transitions); |
| 387 } | 427 } |
| 388 | 428 |
| 389 | 429 |
| 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( | 430 void TransitionArray::SetPrototypeTransitions( |
| 402 Handle<Map> map, Handle<FixedArray> proto_transitions) { | 431 Handle<Map> map, Handle<FixedArray> proto_transitions) { |
| 403 EnsureHasFullTransitionArray(map); | 432 EnsureHasFullTransitionArray(map); |
| 404 if (Heap::ShouldZapGarbage()) { | |
|
ulan
2015/11/24 15:47:04
We do not need to zap prototype transition array b
| |
| 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()); | 433 TransitionArray* transitions = TransitionArray::cast(map->raw_transitions()); |
| 410 transitions->SetPrototypeTransitions(*proto_transitions); | 434 transitions->SetPrototypeTransitions(*proto_transitions); |
| 411 } | 435 } |
| 412 | 436 |
| 413 | 437 |
| 414 void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) { | 438 void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) { |
| 415 Object* raw_transitions = map->raw_transitions(); | 439 Object* raw_transitions = map->raw_transitions(); |
| 416 if (IsFullTransitionArray(raw_transitions)) return; | 440 if (IsFullTransitionArray(raw_transitions)) return; |
| 417 int nof = IsSimpleTransition(raw_transitions) ? 1 : 0; | 441 int nof = IsSimpleTransition(raw_transitions) ? 1 : 0; |
| 418 Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof); | 442 Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 516 PropertyAttributes attributes, | 540 PropertyAttributes attributes, |
| 517 int* out_insertion_index) { | 541 int* out_insertion_index) { |
| 518 int transition = SearchName(name, out_insertion_index); | 542 int transition = SearchName(name, out_insertion_index); |
| 519 if (transition == kNotFound) { | 543 if (transition == kNotFound) { |
| 520 return kNotFound; | 544 return kNotFound; |
| 521 } | 545 } |
| 522 return SearchDetails(transition, kind, attributes, out_insertion_index); | 546 return SearchDetails(transition, kind, attributes, out_insertion_index); |
| 523 } | 547 } |
| 524 } // namespace internal | 548 } // namespace internal |
| 525 } // namespace v8 | 549 } // namespace v8 |
| OLD | NEW |