OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 2292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2303 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue; | 2303 if (map->instance_type() < FIRST_JS_OBJECT_TYPE) continue; |
2304 | 2304 |
2305 if (map_mark.Get() && | 2305 if (map_mark.Get() && |
2306 map->attached_to_shared_function_info()) { | 2306 map->attached_to_shared_function_info()) { |
2307 // This map is used for inobject slack tracking and has been detached | 2307 // This map is used for inobject slack tracking and has been detached |
2308 // from SharedFunctionInfo during the mark phase. | 2308 // from SharedFunctionInfo during the mark phase. |
2309 // Since it survived the GC, reattach it now. | 2309 // Since it survived the GC, reattach it now. |
2310 map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); | 2310 map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); |
2311 } | 2311 } |
2312 | 2312 |
2313 // Clear dead prototype transitions. | 2313 ClearNonLivePrototypeTransitions(map); |
2314 int number_of_transitions = map->NumberOfProtoTransitions(); | 2314 ClearNonLiveMapTransitions(map, map_mark); |
2315 FixedArray* prototype_transitions = map->prototype_transitions(); | |
2316 | |
2317 int new_number_of_transitions = 0; | |
2318 const int header = Map::kProtoTransitionHeaderSize; | |
2319 const int proto_offset = | |
2320 header + Map::kProtoTransitionPrototypeOffset; | |
2321 const int map_offset = header + Map::kProtoTransitionMapOffset; | |
2322 const int step = Map::kProtoTransitionElementsPerEntry; | |
2323 for (int i = 0; i < number_of_transitions; i++) { | |
2324 Object* prototype = prototype_transitions->get(proto_offset + i * step); | |
2325 Object* cached_map = prototype_transitions->get(map_offset + i * step); | |
2326 if (IsMarked(prototype) && IsMarked(cached_map)) { | |
2327 int proto_index = proto_offset + new_number_of_transitions * step; | |
2328 int map_index = map_offset + new_number_of_transitions * step; | |
2329 if (new_number_of_transitions != i) { | |
2330 prototype_transitions->set_unchecked( | |
2331 heap_, | |
2332 proto_index, | |
2333 prototype, | |
2334 UPDATE_WRITE_BARRIER); | |
2335 prototype_transitions->set_unchecked( | |
2336 heap_, | |
2337 map_index, | |
2338 cached_map, | |
2339 SKIP_WRITE_BARRIER); | |
2340 } | |
2341 Object** slot = | |
2342 HeapObject::RawField(prototype_transitions, | |
2343 FixedArray::OffsetOfElementAt(proto_index)); | |
2344 RecordSlot(slot, slot, prototype); | |
2345 new_number_of_transitions++; | |
2346 } | |
2347 } | |
2348 | |
2349 if (new_number_of_transitions != number_of_transitions) { | |
2350 map->SetNumberOfProtoTransitions(new_number_of_transitions); | |
2351 } | |
2352 | |
2353 // Fill slots that became free with undefined value. | |
2354 for (int i = new_number_of_transitions * step; | |
2355 i < number_of_transitions * step; | |
2356 i++) { | |
2357 prototype_transitions->set_undefined(heap_, header + i); | |
2358 } | |
2359 | |
2360 // Follow the chain of back pointers to find the prototype. | |
2361 Map* current = map; | |
2362 while (current->IsMap()) { | |
2363 current = reinterpret_cast<Map*>(current->prototype()); | |
2364 ASSERT(current->IsHeapObject()); | |
2365 } | |
2366 Object* real_prototype = current; | |
2367 | |
2368 // Follow back pointers, setting them to prototype, | |
2369 // clearing map transitions when necessary. | |
2370 current = map; | |
2371 bool on_dead_path = !map_mark.Get(); | |
2372 Object* next; | |
2373 while (current->IsMap()) { | |
2374 next = current->prototype(); | |
2375 // There should never be a dead map above a live map. | |
2376 MarkBit current_mark = Marking::MarkBitFrom(current); | |
2377 bool is_alive = current_mark.Get(); | |
2378 ASSERT(on_dead_path || is_alive); | |
2379 | |
2380 // A live map above a dead map indicates a dead transition. | |
2381 // This test will always be false on the first iteration. | |
2382 if (on_dead_path && is_alive) { | |
2383 on_dead_path = false; | |
2384 current->ClearNonLiveTransitions(heap(), real_prototype); | |
2385 } | |
2386 *HeapObject::RawField(current, Map::kPrototypeOffset) = | |
2387 real_prototype; | |
2388 | |
2389 if (is_alive) { | |
2390 Object** slot = HeapObject::RawField(current, Map::kPrototypeOffset); | |
2391 RecordSlot(slot, slot, real_prototype); | |
2392 } | |
2393 current = reinterpret_cast<Map*>(next); | |
2394 } | |
2395 } | 2315 } |
2396 } | 2316 } |
2397 | 2317 |
| 2318 |
| 2319 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) { |
| 2320 int number_of_transitions = map->NumberOfProtoTransitions(); |
| 2321 FixedArray* prototype_transitions = map->prototype_transitions(); |
| 2322 |
| 2323 int new_number_of_transitions = 0; |
| 2324 const int header = Map::kProtoTransitionHeaderSize; |
| 2325 const int proto_offset = header + Map::kProtoTransitionPrototypeOffset; |
| 2326 const int map_offset = header + Map::kProtoTransitionMapOffset; |
| 2327 const int step = Map::kProtoTransitionElementsPerEntry; |
| 2328 for (int i = 0; i < number_of_transitions; i++) { |
| 2329 Object* prototype = prototype_transitions->get(proto_offset + i * step); |
| 2330 Object* cached_map = prototype_transitions->get(map_offset + i * step); |
| 2331 if (IsMarked(prototype) && IsMarked(cached_map)) { |
| 2332 int proto_index = proto_offset + new_number_of_transitions * step; |
| 2333 int map_index = map_offset + new_number_of_transitions * step; |
| 2334 if (new_number_of_transitions != i) { |
| 2335 prototype_transitions->set_unchecked( |
| 2336 heap_, |
| 2337 proto_index, |
| 2338 prototype, |
| 2339 UPDATE_WRITE_BARRIER); |
| 2340 prototype_transitions->set_unchecked( |
| 2341 heap_, |
| 2342 map_index, |
| 2343 cached_map, |
| 2344 SKIP_WRITE_BARRIER); |
| 2345 } |
| 2346 Object** slot = |
| 2347 HeapObject::RawField(prototype_transitions, |
| 2348 FixedArray::OffsetOfElementAt(proto_index)); |
| 2349 RecordSlot(slot, slot, prototype); |
| 2350 new_number_of_transitions++; |
| 2351 } |
| 2352 } |
| 2353 |
| 2354 if (new_number_of_transitions != number_of_transitions) { |
| 2355 map->SetNumberOfProtoTransitions(new_number_of_transitions); |
| 2356 } |
| 2357 |
| 2358 // Fill slots that became free with undefined value. |
| 2359 for (int i = new_number_of_transitions * step; |
| 2360 i < number_of_transitions * step; |
| 2361 i++) { |
| 2362 prototype_transitions->set_undefined(heap_, header + i); |
| 2363 } |
| 2364 } |
| 2365 |
| 2366 |
| 2367 void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map, |
| 2368 MarkBit map_mark) { |
| 2369 // Follow the chain of back pointers to find the prototype. |
| 2370 Map* real_prototype = map; |
| 2371 while (real_prototype->IsMap()) { |
| 2372 real_prototype = reinterpret_cast<Map*>(real_prototype->prototype()); |
| 2373 ASSERT(real_prototype->IsHeapObject()); |
| 2374 } |
| 2375 |
| 2376 // Follow back pointers, setting them to prototype, clearing map transitions |
| 2377 // when necessary. |
| 2378 Map* current = map; |
| 2379 bool current_is_alive = map_mark.Get(); |
| 2380 bool on_dead_path = !current_is_alive; |
| 2381 while (current->IsMap()) { |
| 2382 Object* next = current->prototype(); |
| 2383 // There should never be a dead map above a live map. |
| 2384 ASSERT(on_dead_path || current_is_alive); |
| 2385 |
| 2386 // A live map above a dead map indicates a dead transition. This test will |
| 2387 // always be false on the first iteration. |
| 2388 if (on_dead_path && current_is_alive) { |
| 2389 on_dead_path = false; |
| 2390 current->ClearNonLiveTransitions(heap(), real_prototype); |
| 2391 } |
| 2392 |
| 2393 Object** slot = HeapObject::RawField(current, Map::kPrototypeOffset); |
| 2394 *slot = real_prototype; |
| 2395 if (current_is_alive) RecordSlot(slot, slot, real_prototype); |
| 2396 |
| 2397 current = reinterpret_cast<Map*>(next); |
| 2398 current_is_alive = Marking::MarkBitFrom(current).Get(); |
| 2399 } |
| 2400 } |
| 2401 |
2398 | 2402 |
2399 void MarkCompactCollector::ProcessWeakMaps() { | 2403 void MarkCompactCollector::ProcessWeakMaps() { |
2400 Object* weak_map_obj = encountered_weak_maps(); | 2404 Object* weak_map_obj = encountered_weak_maps(); |
2401 while (weak_map_obj != Smi::FromInt(0)) { | 2405 while (weak_map_obj != Smi::FromInt(0)) { |
2402 ASSERT(MarkCompactCollector::IsMarked(HeapObject::cast(weak_map_obj))); | 2406 ASSERT(MarkCompactCollector::IsMarked(HeapObject::cast(weak_map_obj))); |
2403 JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(weak_map_obj); | 2407 JSWeakMap* weak_map = reinterpret_cast<JSWeakMap*>(weak_map_obj); |
2404 ObjectHashTable* table = ObjectHashTable::cast(weak_map->table()); | 2408 ObjectHashTable* table = ObjectHashTable::cast(weak_map->table()); |
2405 for (int i = 0; i < table->Capacity(); i++) { | 2409 for (int i = 0; i < table->Capacity(); i++) { |
2406 if (MarkCompactCollector::IsMarked(HeapObject::cast(table->KeyAt(i)))) { | 2410 if (MarkCompactCollector::IsMarked(HeapObject::cast(table->KeyAt(i)))) { |
2407 Object* value = table->get(table->EntryToValueIndex(i)); | 2411 Object* value = table->get(table->EntryToValueIndex(i)); |
(...skipping 1525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3933 while (buffer != NULL) { | 3937 while (buffer != NULL) { |
3934 SlotsBuffer* next_buffer = buffer->next(); | 3938 SlotsBuffer* next_buffer = buffer->next(); |
3935 DeallocateBuffer(buffer); | 3939 DeallocateBuffer(buffer); |
3936 buffer = next_buffer; | 3940 buffer = next_buffer; |
3937 } | 3941 } |
3938 *buffer_address = NULL; | 3942 *buffer_address = NULL; |
3939 } | 3943 } |
3940 | 3944 |
3941 | 3945 |
3942 } } // namespace v8::internal | 3946 } } // namespace v8::internal |
OLD | NEW |