1109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Copyright 2016 the V8 project authors. All rights reserved. 2109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch// found in the LICENSE file. 4109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 5109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#ifndef V8_REMEMBERED_SET_H 6109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#define V8_REMEMBERED_SET_H 7109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch#include "src/assembler.h" 9109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#include "src/heap/heap.h" 10109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#include "src/heap/slot-set.h" 11109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#include "src/heap/spaces.h" 12109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 13109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochnamespace v8 { 14109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochnamespace internal { 15109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 16109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochenum PointerDirection { OLD_TO_OLD, OLD_TO_NEW }; 17109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 1813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch// TODO(ulan): Investigate performance of de-templatizing this class. 19109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdochtemplate <PointerDirection direction> 2062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdochclass RememberedSet : public AllStatic { 21109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch public: 22109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // Given a page and a slot in that page, this function adds the slot to the 23109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // remembered set. 24f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch static void Insert(MemoryChunk* chunk, Address slot_addr) { 25f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch DCHECK(chunk->Contains(slot_addr)); 26f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch SlotSet* slot_set = GetSlotSet(chunk); 27109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch if (slot_set == nullptr) { 28f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch slot_set = AllocateSlotSet(chunk); 29109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 30f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch uintptr_t offset = slot_addr - chunk->address(); 31109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch slot_set[offset / Page::kPageSize].Insert(offset % Page::kPageSize); 32109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 33109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 3462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // Given a page and a slot in that page, this function returns true if 3562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch // the remembered set contains the slot. 3662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch static bool Contains(MemoryChunk* chunk, Address slot_addr) { 3762ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch DCHECK(chunk->Contains(slot_addr)); 3862ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch SlotSet* slot_set = GetSlotSet(chunk); 3962ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch if (slot_set == nullptr) { 4062ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch return false; 4162ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch } 4262ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch uintptr_t offset = slot_addr - chunk->address(); 4362ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch return slot_set[offset / Page::kPageSize].Contains(offset % 4462ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch Page::kPageSize); 4562ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch } 4662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch 47109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // Given a page and a slot in that page, this function removes the slot from 48109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // the remembered set. 49109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // If the slot was never added, then the function does nothing. 50f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch static void Remove(MemoryChunk* chunk, Address slot_addr) { 51f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch DCHECK(chunk->Contains(slot_addr)); 52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch SlotSet* slot_set = GetSlotSet(chunk); 53109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch if (slot_set != nullptr) { 54f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch uintptr_t offset = slot_addr - chunk->address(); 55109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch slot_set[offset / Page::kPageSize].Remove(offset % Page::kPageSize); 56109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 57109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 58109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 59109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // Given a page and a range of slots in that page, this function removes the 60109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // slots from the remembered set. 61c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch static void RemoveRange(MemoryChunk* chunk, Address start, Address end, 62c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch SlotSet::EmptyBucketMode mode) { 63f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch SlotSet* slot_set = GetSlotSet(chunk); 64109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch if (slot_set != nullptr) { 65f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch uintptr_t start_offset = start - chunk->address(); 66f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch uintptr_t end_offset = end - chunk->address(); 67109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch DCHECK_LT(start_offset, end_offset); 68f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (end_offset < static_cast<uintptr_t>(Page::kPageSize)) { 69f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch slot_set->RemoveRange(static_cast<int>(start_offset), 70c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch static_cast<int>(end_offset), mode); 71f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else { 72f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // The large page has multiple slot sets. 73f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // Compute slot set indicies for the range [start_offset, end_offset). 74f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch int start_chunk = static_cast<int>(start_offset / Page::kPageSize); 75f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch int end_chunk = static_cast<int>((end_offset - 1) / Page::kPageSize); 76f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch int offset_in_start_chunk = 77f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch static_cast<int>(start_offset % Page::kPageSize); 78f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // Note that using end_offset % Page::kPageSize would be incorrect 79f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // because end_offset is one beyond the last slot to clear. 80f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch int offset_in_end_chunk = static_cast<int>( 81f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch end_offset - static_cast<uintptr_t>(end_chunk) * Page::kPageSize); 82f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (start_chunk == end_chunk) { 83f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch slot_set[start_chunk].RemoveRange(offset_in_start_chunk, 84c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch offset_in_end_chunk, mode); 85f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else { 86f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // Clear all slots from start_offset to the end of first chunk. 87f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch slot_set[start_chunk].RemoveRange(offset_in_start_chunk, 88c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch Page::kPageSize, mode); 89f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // Clear all slots in intermediate chunks. 90f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for (int i = start_chunk + 1; i < end_chunk; i++) { 91c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch slot_set[i].RemoveRange(0, Page::kPageSize, mode); 92f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 93f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch // Clear slots from the beginning of the last page to end_offset. 94c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch slot_set[end_chunk].RemoveRange(0, offset_in_end_chunk, mode); 95f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 96f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 97109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 98109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 99109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 100109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // Iterates and filters the remembered set with the given callback. 1013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // The callback should take (Address slot) and return SlotCallbackResult. 102109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch template <typename Callback> 103109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch static void Iterate(Heap* heap, Callback callback) { 1043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch IterateMemoryChunks( 1053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch heap, [callback](MemoryChunk* chunk) { Iterate(chunk, callback); }); 1063b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1083b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Iterates over all memory chunks that contains non-empty slot sets. 1093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // The callback should take (MemoryChunk* chunk) and return void. 1103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch template <typename Callback> 1113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch static void IterateMemoryChunks(Heap* heap, Callback callback) { 11213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MemoryChunkIterator it(heap); 113109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch MemoryChunk* chunk; 114109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch while ((chunk = it.next()) != nullptr) { 115109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch SlotSet* slots = GetSlotSet(chunk); 1163b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch TypedSlotSet* typed_slots = GetTypedSlotSet(chunk); 1173b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (slots != nullptr || typed_slots != nullptr) { 1183b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch callback(chunk); 1193b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1203b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1213b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1223b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1233b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Iterates and filters the remembered set in the given memory chunk with 1243b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // the given callback. The callback should take (Address slot) and return 1253b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // SlotCallbackResult. 1263b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch template <typename Callback> 1273b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch static void Iterate(MemoryChunk* chunk, Callback callback) { 1283b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch SlotSet* slots = GetSlotSet(chunk); 1293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (slots != nullptr) { 1303b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch size_t pages = (chunk->size() + Page::kPageSize - 1) / Page::kPageSize; 1313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch int new_count = 0; 1323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch for (size_t page = 0; page < pages; page++) { 133f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch new_count += 134f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch slots[page].Iterate(callback, SlotSet::PREFREE_EMPTY_BUCKETS); 1353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 136f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // Only old-to-old slot sets are released eagerly. Old-new-slot sets are 137f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch // released by the sweeper threads. 138f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch if (direction == OLD_TO_OLD && new_count == 0) { 139f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch chunk->ReleaseOldToOldSlots(); 140109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 141109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 142109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 143109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 1443b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Given a page and a typed slot in that page, this function adds the slot 1453b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // to the remembered set. 14613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static void InsertTyped(Page* page, Address host_addr, SlotType slot_type, 14713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Address slot_addr) { 14813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch TypedSlotSet* slot_set = GetTypedSlotSet(page); 1493b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (slot_set == nullptr) { 15013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch AllocateTypedSlotSet(page); 15113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch slot_set = GetTypedSlotSet(page); 15213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 15313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (host_addr == nullptr) { 15413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch host_addr = page->address(); 1553b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1563b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch uintptr_t offset = slot_addr - page->address(); 15713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch uintptr_t host_offset = host_addr - page->address(); 1583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch DCHECK_LT(offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset)); 15913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DCHECK_LT(host_offset, static_cast<uintptr_t>(TypedSlotSet::kMaxOffset)); 16013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch slot_set->Insert(slot_type, static_cast<uint32_t>(host_offset), 16113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static_cast<uint32_t>(offset)); 1623b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 1643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Given a page and a range of typed slots in that page, this function removes 1653b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // the slots from the remembered set. 166f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch static void RemoveRangeTyped(MemoryChunk* page, Address start, Address end) { 16713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch TypedSlotSet* slots = GetTypedSlotSet(page); 1683b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (slots != nullptr) { 169f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch slots->Iterate( 170f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch [start, end](SlotType slot_type, Address host_addr, 171f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch Address slot_addr) { 172f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch return start <= slot_addr && slot_addr < end ? REMOVE_SLOT 173f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch : KEEP_SLOT; 174f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch }, 175f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch TypedSlotSet::PREFREE_EMPTY_CHUNKS); 1763b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 1783b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 17913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Iterates and filters the remembered set with the given callback. 18013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // The callback should take (SlotType slot_type, SlotAddress slot) and return 18113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // SlotCallbackResult. 18213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch template <typename Callback> 18313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static void IterateTyped(Heap* heap, Callback callback) { 18413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch IterateMemoryChunks(heap, [callback](MemoryChunk* chunk) { 18513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch IterateTyped(chunk, callback); 18613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch }); 18713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 18813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 1893b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Iterates and filters typed old to old pointers in the given memory chunk 1903b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // with the given callback. The callback should take (SlotType slot_type, 1913b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Address slot_addr) and return SlotCallbackResult. 1923b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch template <typename Callback> 1933b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch static void IterateTyped(MemoryChunk* chunk, Callback callback) { 19413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch TypedSlotSet* slots = GetTypedSlotSet(chunk); 1953b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (slots != nullptr) { 196f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch int new_count = slots->Iterate(callback, TypedSlotSet::KEEP_EMPTY_CHUNKS); 1973b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (new_count == 0) { 19813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch ReleaseTypedSlotSet(chunk); 1993b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2003b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2013b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2033b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Clear all old to old slots from the remembered set. 2043b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch static void ClearAll(Heap* heap) { 2053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch STATIC_ASSERT(direction == OLD_TO_OLD); 20613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch MemoryChunkIterator it(heap); 2073b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch MemoryChunk* chunk; 2083b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch while ((chunk = it.next()) != nullptr) { 2093b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch chunk->ReleaseOldToOldSlots(); 2103b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch chunk->ReleaseTypedOldToOldSlots(); 2113b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2123b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2133b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 214109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // Eliminates all stale slots from the remembered set, i.e. 215109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // slots that are not part of live objects anymore. This method must be 216109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // called after marking, when the whole transitive closure is known and 217109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // must be called before sweeping when mark bits are still intact. 218c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch static void ClearInvalidTypedSlots(Heap* heap, MemoryChunk* chunk); 219109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 220109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch private: 221109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch static SlotSet* GetSlotSet(MemoryChunk* chunk) { 222109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch if (direction == OLD_TO_OLD) { 223109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch return chunk->old_to_old_slots(); 224109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } else { 225109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch return chunk->old_to_new_slots(); 226109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 227109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 228109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 2293b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch static TypedSlotSet* GetTypedSlotSet(MemoryChunk* chunk) { 2303b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if (direction == OLD_TO_OLD) { 2313b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch return chunk->typed_old_to_old_slots(); 2323b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } else { 23313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return chunk->typed_old_to_new_slots(); 2343b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2353b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch } 2363b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 23713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static void ReleaseTypedSlotSet(MemoryChunk* chunk) { 23813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (direction == OLD_TO_OLD) { 23913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch chunk->ReleaseTypedOldToOldSlots(); 24013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 24113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 24213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 243109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch static SlotSet* AllocateSlotSet(MemoryChunk* chunk) { 244109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch if (direction == OLD_TO_OLD) { 245109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch chunk->AllocateOldToOldSlots(); 246109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch return chunk->old_to_old_slots(); 247109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } else { 248109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch chunk->AllocateOldToNewSlots(); 249109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch return chunk->old_to_new_slots(); 250109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 251109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 252109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 25313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static TypedSlotSet* AllocateTypedSlotSet(MemoryChunk* chunk) { 25413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (direction == OLD_TO_OLD) { 25513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch chunk->AllocateTypedOldToOldSlots(); 25613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return chunk->typed_old_to_old_slots(); 257109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } else { 25813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch chunk->AllocateTypedOldToNewSlots(); 25913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return chunk->typed_old_to_new_slots(); 260109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 261109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch } 262109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 2633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch static bool IsValidSlot(Heap* heap, MemoryChunk* chunk, Object** slot); 264109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch}; 265109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 26613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochclass UpdateTypedSlotHelper { 26713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch public: 26813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Updates a cell slot using an untyped slot callback. 26913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. 27013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch template <typename Callback> 27113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static SlotCallbackResult UpdateCell(RelocInfo* rinfo, Callback callback) { 27213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DCHECK(rinfo->rmode() == RelocInfo::CELL); 27313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* cell = rinfo->target_cell(); 27413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* old_cell = cell; 27513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch SlotCallbackResult result = callback(&cell); 27613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (cell != old_cell) { 27713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch rinfo->set_target_cell(reinterpret_cast<Cell*>(cell)); 27813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 27913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return result; 28013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 28113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 28213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Updates a code entry slot using an untyped slot callback. 28313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. 28413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch template <typename Callback> 28513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static SlotCallbackResult UpdateCodeEntry(Address entry_address, 28613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Callback callback) { 28713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* code = Code::GetObjectFromEntryAddress(entry_address); 28813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* old_code = code; 28913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch SlotCallbackResult result = callback(&code); 29013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (code != old_code) { 29113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Memory::Address_at(entry_address) = 29213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch reinterpret_cast<Code*>(code)->entry(); 29313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 29413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return result; 29513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 29613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 29713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Updates a code target slot using an untyped slot callback. 29813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. 29913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch template <typename Callback> 30013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static SlotCallbackResult UpdateCodeTarget(RelocInfo* rinfo, 30113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Callback callback) { 30213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); 30313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 30413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* old_target = target; 30513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch SlotCallbackResult result = callback(&target); 30613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (target != old_target) { 30713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch rinfo->set_target_address(Code::cast(target)->instruction_start()); 30813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 30913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return result; 31013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 31113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 31213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Updates an embedded pointer slot using an untyped slot callback. 31313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. 31413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch template <typename Callback> 31513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static SlotCallbackResult UpdateEmbeddedPointer(RelocInfo* rinfo, 31613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Callback callback) { 31713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 31813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* target = rinfo->target_object(); 31913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* old_target = target; 32013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch SlotCallbackResult result = callback(&target); 32113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (target != old_target) { 32213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch rinfo->set_target_object(target); 32313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 32413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return result; 32513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 32613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 32713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Updates a debug target slot using an untyped slot callback. 32813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. 32913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch template <typename Callback> 33013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static SlotCallbackResult UpdateDebugTarget(RelocInfo* rinfo, 33113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Callback callback) { 33213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 33313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch rinfo->IsPatchedDebugBreakSlotSequence()); 33413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Object* target = 33513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); 33613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch SlotCallbackResult result = callback(&target); 33713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch rinfo->set_debug_call_address(Code::cast(target)->instruction_start()); 33813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return result; 33913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 34013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 34113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // Updates a typed slot using an untyped slot callback. 34213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch // The callback accepts (Heap*, Object**) and returns SlotCallbackResult. 34313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch template <typename Callback> 34413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch static SlotCallbackResult UpdateTypedSlot(Isolate* isolate, 34513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch SlotType slot_type, Address addr, 34613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch Callback callback) { 34713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch switch (slot_type) { 34813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch case CODE_TARGET_SLOT: { 34913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch RelocInfo rinfo(isolate, addr, RelocInfo::CODE_TARGET, 0, NULL); 35013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return UpdateCodeTarget(&rinfo, callback); 35113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 35213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch case CELL_TARGET_SLOT: { 35313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch RelocInfo rinfo(isolate, addr, RelocInfo::CELL, 0, NULL); 35413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return UpdateCell(&rinfo, callback); 35513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 35613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch case CODE_ENTRY_SLOT: { 35713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return UpdateCodeEntry(addr, callback); 35813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 35913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch case DEBUG_TARGET_SLOT: { 36013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch RelocInfo rinfo(isolate, addr, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION, 36113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 0, NULL); 36213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch if (rinfo.IsPatchedDebugBreakSlotSequence()) { 36313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return UpdateDebugTarget(&rinfo, callback); 36413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 36513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return REMOVE_SLOT; 36613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 36713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch case EMBEDDED_OBJECT_SLOT: { 36813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch RelocInfo rinfo(isolate, addr, RelocInfo::EMBEDDED_OBJECT, 0, NULL); 36913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return UpdateEmbeddedPointer(&rinfo, callback); 37013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 37113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch case OBJECT_SLOT: { 37213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return callback(reinterpret_cast<Object**>(addr)); 37313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 374f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch case CLEARED_SLOT: 37513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch break; 37613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 37713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch UNREACHABLE(); 37813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch return REMOVE_SLOT; 37913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch } 38013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}; 38113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch 382f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochinline SlotType SlotTypeForRelocInfoMode(RelocInfo::Mode rmode) { 383f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if (RelocInfo::IsCodeTarget(rmode)) { 384f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return CODE_TARGET_SLOT; 385f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else if (RelocInfo::IsCell(rmode)) { 386f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return CELL_TARGET_SLOT; 387f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else if (RelocInfo::IsEmbeddedObject(rmode)) { 388f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return EMBEDDED_OBJECT_SLOT; 389f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } else if (RelocInfo::IsDebugBreakSlot(rmode)) { 390f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return DEBUG_TARGET_SLOT; 391f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch } 392f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch UNREACHABLE(); 393f3b273f5e6ffd2f6ba1c18a27a17db41dfb113c3Ben Murdoch return CLEARED_SLOT; 394f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch} 395f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 396109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch} // namespace internal 397109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch} // namespace v8 398109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 399109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch#endif // V8_REMEMBERED_SET_H 400