v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
store-buffer.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "store-buffer.h"
31 #include "store-buffer-inl.h"
32 #include "v8-counters.h"
33 
34 namespace v8 {
35 namespace internal {
36 
38  : heap_(heap),
39  start_(NULL),
40  limit_(NULL),
41  old_start_(NULL),
42  old_limit_(NULL),
43  old_top_(NULL),
44  old_reserved_limit_(NULL),
45  old_buffer_is_sorted_(false),
46  old_buffer_is_filtered_(false),
47  during_gc_(false),
48  store_buffer_rebuilding_enabled_(false),
49  callback_(NULL),
50  may_move_store_buffer_entries_(true),
51  virtual_memory_(NULL),
52  hash_set_1_(NULL),
53  hash_set_2_(NULL),
54  hash_sets_are_empty_(true) {
55 }
56 
57 
59  virtual_memory_ = new VirtualMemory(kStoreBufferSize * 3);
60  uintptr_t start_as_int =
61  reinterpret_cast<uintptr_t>(virtual_memory_->address());
62  start_ =
63  reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2));
64  limit_ = start_ + (kStoreBufferSize / kPointerSize);
65 
66  old_virtual_memory_ =
68  old_top_ = old_start_ =
69  reinterpret_cast<Address*>(old_virtual_memory_->address());
70  // Don't know the alignment requirements of the OS, but it is certainly not
71  // less than 0xfff.
72  ASSERT((reinterpret_cast<uintptr_t>(old_start_) & 0xfff) == 0);
73  int initial_length = static_cast<int>(OS::CommitPageSize() / kPointerSize);
74  ASSERT(initial_length > 0);
75  ASSERT(initial_length <= kOldStoreBufferLength);
76  old_limit_ = old_start_ + initial_length;
77  old_reserved_limit_ = old_start_ + kOldStoreBufferLength;
78 
79  CHECK(old_virtual_memory_->Commit(
80  reinterpret_cast<void*>(old_start_),
81  (old_limit_ - old_start_) * kPointerSize,
82  false));
83 
84  ASSERT(reinterpret_cast<Address>(start_) >= virtual_memory_->address());
85  ASSERT(reinterpret_cast<Address>(limit_) >= virtual_memory_->address());
86  Address* vm_limit = reinterpret_cast<Address*>(
87  reinterpret_cast<char*>(virtual_memory_->address()) +
88  virtual_memory_->size());
89  ASSERT(start_ <= vm_limit);
90  ASSERT(limit_ <= vm_limit);
91  USE(vm_limit);
92  ASSERT((reinterpret_cast<uintptr_t>(limit_) & kStoreBufferOverflowBit) != 0);
93  ASSERT((reinterpret_cast<uintptr_t>(limit_ - 1) & kStoreBufferOverflowBit) ==
94  0);
95 
96  CHECK(virtual_memory_->Commit(reinterpret_cast<Address>(start_),
98  false)); // Not executable.
99  heap_->public_set_store_buffer_top(start_);
100 
101  hash_set_1_ = new uintptr_t[kHashSetLength];
102  hash_set_2_ = new uintptr_t[kHashSetLength];
103  hash_sets_are_empty_ = false;
104 
105  ClearFilteringHashSets();
106 }
107 
108 
110  delete virtual_memory_;
111  delete old_virtual_memory_;
112  delete[] hash_set_1_;
113  delete[] hash_set_2_;
114  old_start_ = old_top_ = old_limit_ = old_reserved_limit_ = NULL;
115  start_ = limit_ = NULL;
116  heap_->public_set_store_buffer_top(start_);
117 }
118 
119 
121  isolate->heap()->store_buffer()->Compact();
122 }
123 
124 
125 #if V8_TARGET_ARCH_X64
126 static int CompareAddresses(const void* void_a, const void* void_b) {
127  intptr_t a =
128  reinterpret_cast<intptr_t>(*reinterpret_cast<const Address*>(void_a));
129  intptr_t b =
130  reinterpret_cast<intptr_t>(*reinterpret_cast<const Address*>(void_b));
131  // Unfortunately if int is smaller than intptr_t there is no branch-free
132  // way to return a number with the same sign as the difference between the
133  // pointers.
134  if (a == b) return 0;
135  if (a < b) return -1;
136  ASSERT(a > b);
137  return 1;
138 }
139 #else
140 static int CompareAddresses(const void* void_a, const void* void_b) {
141  intptr_t a =
142  reinterpret_cast<intptr_t>(*reinterpret_cast<const Address*>(void_a));
143  intptr_t b =
144  reinterpret_cast<intptr_t>(*reinterpret_cast<const Address*>(void_b));
145  ASSERT(sizeof(1) == sizeof(a));
146  // Shift down to avoid wraparound.
147  return (a >> kPointerSizeLog2) - (b >> kPointerSizeLog2);
148 }
149 #endif
150 
151 
152 void StoreBuffer::Uniq() {
153  // Remove adjacent duplicates and cells that do not point at new space.
154  Address previous = NULL;
155  Address* write = old_start_;
156  ASSERT(may_move_store_buffer_entries_);
157  for (Address* read = old_start_; read < old_top_; read++) {
158  Address current = *read;
159  if (current != previous) {
160  if (heap_->InNewSpace(*reinterpret_cast<Object**>(current))) {
161  *write++ = current;
162  }
163  }
164  previous = current;
165  }
166  old_top_ = write;
167 }
168 
169 
170 void StoreBuffer::EnsureSpace(intptr_t space_needed) {
171  while (old_limit_ - old_top_ < space_needed &&
172  old_limit_ < old_reserved_limit_) {
173  size_t grow = old_limit_ - old_start_; // Double size.
174  CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_limit_),
175  grow * kPointerSize,
176  false));
177  old_limit_ += grow;
178  }
179 
180  if (old_limit_ - old_top_ >= space_needed) return;
181 
182  if (old_buffer_is_filtered_) return;
183  ASSERT(may_move_store_buffer_entries_);
184  Compact();
185 
186  old_buffer_is_filtered_ = true;
187  bool page_has_scan_on_scavenge_flag = false;
188 
189  PointerChunkIterator it(heap_);
190  MemoryChunk* chunk;
191  while ((chunk = it.next()) != NULL) {
192  if (chunk->scan_on_scavenge()) page_has_scan_on_scavenge_flag = true;
193  }
194 
195  if (page_has_scan_on_scavenge_flag) {
197  }
198 
199  // If filtering out the entries from scan_on_scavenge pages got us down to
200  // less than half full, then we are satisfied with that.
201  if (old_limit_ - old_top_ > old_top_ - old_start_) return;
202 
203  // Sample 1 entry in 97 and filter out the pages where we estimate that more
204  // than 1 in 8 pointers are to new space.
205  static const int kSampleFinenesses = 5;
206  static const struct Samples {
207  int prime_sample_step;
208  int threshold;
209  } samples[kSampleFinenesses] = {
210  { 97, ((Page::kPageSize / kPointerSize) / 97) / 8 },
211  { 23, ((Page::kPageSize / kPointerSize) / 23) / 16 },
212  { 7, ((Page::kPageSize / kPointerSize) / 7) / 32 },
213  { 3, ((Page::kPageSize / kPointerSize) / 3) / 256 },
214  { 1, 0}
215  };
216  for (int i = kSampleFinenesses - 1; i >= 0; i--) {
217  ExemptPopularPages(samples[i].prime_sample_step, samples[i].threshold);
218  // As a last resort we mark all pages as being exempt from the store buffer.
219  ASSERT(i != 0 || old_top_ == old_start_);
220  if (old_limit_ - old_top_ > old_top_ - old_start_) return;
221  }
222  UNREACHABLE();
223 }
224 
225 
226 // Sample the store buffer to see if some pages are taking up a lot of space
227 // in the store buffer.
228 void StoreBuffer::ExemptPopularPages(int prime_sample_step, int threshold) {
229  PointerChunkIterator it(heap_);
230  MemoryChunk* chunk;
231  while ((chunk = it.next()) != NULL) {
232  chunk->set_store_buffer_counter(0);
233  }
234  bool created_new_scan_on_scavenge_pages = false;
235  MemoryChunk* previous_chunk = NULL;
236  for (Address* p = old_start_; p < old_top_; p += prime_sample_step) {
237  Address addr = *p;
238  MemoryChunk* containing_chunk = NULL;
239  if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
240  containing_chunk = previous_chunk;
241  } else {
242  containing_chunk = MemoryChunk::FromAnyPointerAddress(addr);
243  }
244  int old_counter = containing_chunk->store_buffer_counter();
245  if (old_counter == threshold) {
246  containing_chunk->set_scan_on_scavenge(true);
247  created_new_scan_on_scavenge_pages = true;
248  }
249  containing_chunk->set_store_buffer_counter(old_counter + 1);
250  previous_chunk = containing_chunk;
251  }
252  if (created_new_scan_on_scavenge_pages) {
254  }
255  old_buffer_is_filtered_ = true;
256 }
257 
258 
260  Address* new_top = old_start_;
261  MemoryChunk* previous_chunk = NULL;
262  for (Address* p = old_start_; p < old_top_; p++) {
263  Address addr = *p;
264  MemoryChunk* containing_chunk = NULL;
265  if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
266  containing_chunk = previous_chunk;
267  } else {
268  containing_chunk = MemoryChunk::FromAnyPointerAddress(addr);
269  previous_chunk = containing_chunk;
270  }
271  if (!containing_chunk->IsFlagSet(flag)) {
272  *new_top++ = addr;
273  }
274  }
275  old_top_ = new_top;
276 
277  // Filtering hash sets are inconsistent with the store buffer after this
278  // operation.
279  ClearFilteringHashSets();
280 }
281 
282 
284  Compact();
285  if (old_buffer_is_sorted_) return;
286  qsort(reinterpret_cast<void*>(old_start_),
287  old_top_ - old_start_,
288  sizeof(*old_top_),
289  &CompareAddresses);
290  Uniq();
291 
292  old_buffer_is_sorted_ = true;
293 
294  // Filtering hash sets are inconsistent with the store buffer after this
295  // operation.
296  ClearFilteringHashSets();
297 }
298 
299 
301  Compact();
302  PointerChunkIterator it(heap_);
303  MemoryChunk* chunk;
304  bool page_has_scan_on_scavenge_flag = false;
305  while ((chunk = it.next()) != NULL) {
306  if (chunk->scan_on_scavenge()) page_has_scan_on_scavenge_flag = true;
307  }
308 
309  if (page_has_scan_on_scavenge_flag) {
311  }
312 
313  // Filtering hash sets are inconsistent with the store buffer after
314  // iteration.
315  ClearFilteringHashSets();
316 
317  return page_has_scan_on_scavenge_flag;
318 }
319 
320 
321 #ifdef DEBUG
322 void StoreBuffer::Clean() {
323  ClearFilteringHashSets();
324  Uniq(); // Also removes things that no longer point to new space.
325  CheckForFullBuffer();
326 }
327 
328 
329 static Address* in_store_buffer_1_element_cache = NULL;
330 
331 
332 bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) {
333  if (!FLAG_enable_slow_asserts) return true;
334  if (in_store_buffer_1_element_cache != NULL &&
335  *in_store_buffer_1_element_cache == cell_address) {
336  return true;
337  }
338  Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
339  for (Address* current = top - 1; current >= start_; current--) {
340  if (*current == cell_address) {
341  in_store_buffer_1_element_cache = current;
342  return true;
343  }
344  }
345  for (Address* current = old_top_ - 1; current >= old_start_; current--) {
346  if (*current == cell_address) {
347  in_store_buffer_1_element_cache = current;
348  return true;
349  }
350  }
351  return false;
352 }
353 #endif
354 
355 
356 void StoreBuffer::ClearFilteringHashSets() {
357  if (!hash_sets_are_empty_) {
358  memset(reinterpret_cast<void*>(hash_set_1_),
359  0,
360  sizeof(uintptr_t) * kHashSetLength);
361  memset(reinterpret_cast<void*>(hash_set_2_),
362  0,
363  sizeof(uintptr_t) * kHashSetLength);
364  hash_sets_are_empty_ = true;
365  }
366 }
367 
368 
370  ClearFilteringHashSets();
371  during_gc_ = true;
372 }
373 
374 
375 #ifdef DEBUG
376 static void DummyScavengePointer(HeapObject** p, HeapObject* o) {
377  // Do nothing.
378 }
379 
380 
381 void StoreBuffer::VerifyPointers(PagedSpace* space,
382  RegionCallback region_callback) {
383  PageIterator it(space);
384 
385  while (it.has_next()) {
386  Page* page = it.next();
387  FindPointersToNewSpaceOnPage(
388  reinterpret_cast<PagedSpace*>(page->owner()),
389  page,
390  region_callback,
391  &DummyScavengePointer);
392  }
393 }
394 
395 
396 void StoreBuffer::VerifyPointers(LargeObjectSpace* space) {
397  LargeObjectIterator it(space);
398  for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
399  if (object->IsFixedArray()) {
400  Address slot_address = object->address();
401  Address end = object->address() + object->Size();
402 
403  while (slot_address < end) {
404  HeapObject** slot = reinterpret_cast<HeapObject**>(slot_address);
405  // When we are not in GC the Heap::InNewSpace() predicate
406  // checks that pointers which satisfy predicate point into
407  // the active semispace.
408  heap_->InNewSpace(*slot);
409  slot_address += kPointerSize;
410  }
411  }
412  }
413 }
414 #endif
415 
416 
418 #ifdef DEBUG
419  VerifyPointers(heap_->old_pointer_space(),
420  &StoreBuffer::FindPointersToNewSpaceInRegion);
421  VerifyPointers(heap_->map_space(),
422  &StoreBuffer::FindPointersToNewSpaceInMapsRegion);
423  VerifyPointers(heap_->lo_space());
424 #endif
425 }
426 
427 
429  during_gc_ = false;
430  if (FLAG_verify_heap) {
431  Verify();
432  }
433 }
434 
435 
436 void StoreBuffer::FindPointersToNewSpaceInRegion(
437  Address start, Address end, ObjectSlotCallback slot_callback) {
438  for (Address slot_address = start;
439  slot_address < end;
440  slot_address += kPointerSize) {
441  Object** slot = reinterpret_cast<Object**>(slot_address);
442  if (heap_->InNewSpace(*slot)) {
443  HeapObject* object = reinterpret_cast<HeapObject*>(*slot);
444  ASSERT(object->IsHeapObject());
445  slot_callback(reinterpret_cast<HeapObject**>(slot), object);
446  if (heap_->InNewSpace(*slot)) {
447  EnterDirectlyIntoStoreBuffer(slot_address);
448  }
449  }
450  }
451 }
452 
453 
454 // Compute start address of the first map following given addr.
455 static inline Address MapStartAlign(Address addr) {
456  Address page = Page::FromAddress(addr)->area_start();
457  return page + (((addr - page) + (Map::kSize - 1)) / Map::kSize * Map::kSize);
458 }
459 
460 
461 // Compute end address of the first map preceding given addr.
462 static inline Address MapEndAlign(Address addr) {
463  Address page = Page::FromAllocationTop(addr)->area_start();
464  return page + ((addr - page) / Map::kSize * Map::kSize);
465 }
466 
467 
468 void StoreBuffer::FindPointersToNewSpaceInMaps(
469  Address start,
470  Address end,
471  ObjectSlotCallback slot_callback) {
472  ASSERT(MapStartAlign(start) == start);
473  ASSERT(MapEndAlign(end) == end);
474 
475  Address map_address = start;
476  while (map_address < end) {
477  ASSERT(!heap_->InNewSpace(Memory::Object_at(map_address)));
478  ASSERT(Memory::Object_at(map_address)->IsMap());
479 
480  Address pointer_fields_start = map_address + Map::kPointerFieldsBeginOffset;
481  Address pointer_fields_end = map_address + Map::kPointerFieldsEndOffset;
482 
483  FindPointersToNewSpaceInRegion(pointer_fields_start,
484  pointer_fields_end,
485  slot_callback);
486  map_address += Map::kSize;
487  }
488 }
489 
490 
491 void StoreBuffer::FindPointersToNewSpaceInMapsRegion(
492  Address start,
493  Address end,
494  ObjectSlotCallback slot_callback) {
495  Address map_aligned_start = MapStartAlign(start);
496  Address map_aligned_end = MapEndAlign(end);
497 
498  ASSERT(map_aligned_start == start);
499  ASSERT(map_aligned_end == end);
500 
501  FindPointersToNewSpaceInMaps(map_aligned_start,
502  map_aligned_end,
503  slot_callback);
504 }
505 
506 
507 // This function iterates over all the pointers in a paged space in the heap,
508 // looking for pointers into new space. Within the pages there may be dead
509 // objects that have not been overwritten by free spaces or fillers because of
510 // lazy sweeping. These dead objects may not contain pointers to new space.
511 // The garbage areas that have been swept properly (these will normally be the
512 // large ones) will be marked with free space and filler map words. In
513 // addition any area that has never been used at all for object allocation must
514 // be marked with a free space or filler. Because the free space and filler
515 // maps do not move we can always recognize these even after a compaction.
516 // Normal objects like FixedArrays and JSObjects should not contain references
517 // to these maps. The special garbage section (see comment in spaces.h) is
518 // skipped since it can contain absolutely anything. Any objects that are
519 // allocated during iteration may or may not be visited by the iteration, but
520 // they will not be partially visited.
521 void StoreBuffer::FindPointersToNewSpaceOnPage(
522  PagedSpace* space,
523  Page* page,
524  RegionCallback region_callback,
525  ObjectSlotCallback slot_callback) {
526  Address visitable_start = page->area_start();
527  Address end_of_page = page->area_end();
528 
529  Address visitable_end = visitable_start;
530 
531  Object* free_space_map = heap_->free_space_map();
532  Object* two_pointer_filler_map = heap_->two_pointer_filler_map();
533 
534  while (visitable_end < end_of_page) {
535  Object* o = *reinterpret_cast<Object**>(visitable_end);
536  // Skip fillers but not things that look like fillers in the special
537  // garbage section which can contain anything.
538  if (o == free_space_map ||
539  o == two_pointer_filler_map ||
540  (visitable_end == space->top() && visitable_end != space->limit())) {
541  if (visitable_start != visitable_end) {
542  // After calling this the special garbage section may have moved.
543  (this->*region_callback)(visitable_start,
544  visitable_end,
545  slot_callback);
546  if (visitable_end >= space->top() && visitable_end < space->limit()) {
547  visitable_end = space->limit();
548  visitable_start = visitable_end;
549  continue;
550  }
551  }
552  if (visitable_end == space->top() && visitable_end != space->limit()) {
553  visitable_start = visitable_end = space->limit();
554  } else {
555  // At this point we are either at the start of a filler or we are at
556  // the point where the space->top() used to be before the
557  // visit_pointer_region call above. Either way we can skip the
558  // object at the current spot: We don't promise to visit objects
559  // allocated during heap traversal, and if space->top() moved then it
560  // must be because an object was allocated at this point.
561  visitable_start =
562  visitable_end + HeapObject::FromAddress(visitable_end)->Size();
563  visitable_end = visitable_start;
564  }
565  } else {
566  ASSERT(o != free_space_map);
567  ASSERT(o != two_pointer_filler_map);
568  ASSERT(visitable_end < space->top() || visitable_end >= space->limit());
569  visitable_end += kPointerSize;
570  }
571  }
572  ASSERT(visitable_end == end_of_page);
573  if (visitable_start != visitable_end) {
574  (this->*region_callback)(visitable_start,
575  visitable_end,
576  slot_callback);
577  }
578 }
579 
580 
581 void StoreBuffer::IteratePointersInStoreBuffer(
582  ObjectSlotCallback slot_callback) {
583  Address* limit = old_top_;
584  old_top_ = old_start_;
585  {
587  for (Address* current = old_start_; current < limit; current++) {
588 #ifdef DEBUG
589  Address* saved_top = old_top_;
590 #endif
591  Object** slot = reinterpret_cast<Object**>(*current);
592  Object* object = *slot;
593  if (heap_->InFromSpace(object)) {
594  HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
595  slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object);
596  if (heap_->InNewSpace(*slot)) {
597  EnterDirectlyIntoStoreBuffer(reinterpret_cast<Address>(slot));
598  }
599  }
600  ASSERT(old_top_ == saved_top + 1 || old_top_ == saved_top);
601  }
602  }
603 }
604 
605 
607  // We do not sort or remove duplicated entries from the store buffer because
608  // we expect that callback will rebuild the store buffer thus removing
609  // all duplicates and pointers to old space.
610  bool some_pages_to_scan = PrepareForIteration();
611 
612  // TODO(gc): we want to skip slots on evacuation candidates
613  // but we can't simply figure that out from slot address
614  // because slot can belong to a large object.
615  IteratePointersInStoreBuffer(slot_callback);
616 
617  // We are done scanning all the pointers that were in the store buffer, but
618  // there may be some pages marked scan_on_scavenge that have pointers to new
619  // space that are not in the store buffer. We must scan them now. As we
620  // scan, the surviving pointers to new space will be added to the store
621  // buffer. If there are still a lot of pointers to new space then we will
622  // keep the scan_on_scavenge flag on the page and discard the pointers that
623  // were added to the store buffer. If there are not many pointers to new
624  // space left on the page we will keep the pointers in the store buffer and
625  // remove the flag from the page.
626  if (some_pages_to_scan) {
627  if (callback_ != NULL) {
628  (*callback_)(heap_, NULL, kStoreBufferStartScanningPagesEvent);
629  }
630  PointerChunkIterator it(heap_);
631  MemoryChunk* chunk;
632  while ((chunk = it.next()) != NULL) {
633  if (chunk->scan_on_scavenge()) {
634  chunk->set_scan_on_scavenge(false);
635  if (callback_ != NULL) {
636  (*callback_)(heap_, chunk, kStoreBufferScanningPageEvent);
637  }
638  if (chunk->owner() == heap_->lo_space()) {
639  LargePage* large_page = reinterpret_cast<LargePage*>(chunk);
640  HeapObject* array = large_page->GetObject();
641  ASSERT(array->IsFixedArray());
642  Address start = array->address();
643  Address end = start + array->Size();
644  FindPointersToNewSpaceInRegion(start, end, slot_callback);
645  } else {
646  Page* page = reinterpret_cast<Page*>(chunk);
647  PagedSpace* owner = reinterpret_cast<PagedSpace*>(page->owner());
648  FindPointersToNewSpaceOnPage(
649  owner,
650  page,
651  (owner == heap_->map_space() ?
652  &StoreBuffer::FindPointersToNewSpaceInMapsRegion :
653  &StoreBuffer::FindPointersToNewSpaceInRegion),
654  slot_callback);
655  }
656  }
657  }
658  if (callback_ != NULL) {
659  (*callback_)(heap_, NULL, kStoreBufferScanningPageEvent);
660  }
661  }
662 }
663 
664 
666  Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top());
667 
668  if (top == start_) return;
669 
670  // There's no check of the limit in the loop below so we check here for
671  // the worst case (compaction doesn't eliminate any pointers).
672  ASSERT(top <= limit_);
673  heap_->public_set_store_buffer_top(start_);
674  EnsureSpace(top - start_);
675  ASSERT(may_move_store_buffer_entries_);
676  // Goes through the addresses in the store buffer attempting to remove
677  // duplicates. In the interest of speed this is a lossy operation. Some
678  // duplicates will remain. We have two hash sets with different hash
679  // functions to reduce the number of unnecessary clashes.
680  hash_sets_are_empty_ = false; // Hash sets are in use.
681  for (Address* current = start_; current < top; current++) {
682  ASSERT(!heap_->cell_space()->Contains(*current));
683  ASSERT(!heap_->code_space()->Contains(*current));
684  ASSERT(!heap_->old_data_space()->Contains(*current));
685  uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current);
686  // Shift out the last bits including any tags.
687  int_addr >>= kPointerSizeLog2;
688  int hash1 =
689  ((int_addr ^ (int_addr >> kHashSetLengthLog2)) & (kHashSetLength - 1));
690  if (hash_set_1_[hash1] == int_addr) continue;
691  uintptr_t hash2 = (int_addr - (int_addr >> kHashSetLengthLog2));
692  hash2 ^= hash2 >> (kHashSetLengthLog2 * 2);
693  hash2 &= (kHashSetLength - 1);
694  if (hash_set_2_[hash2] == int_addr) continue;
695  if (hash_set_1_[hash1] == 0) {
696  hash_set_1_[hash1] = int_addr;
697  } else if (hash_set_2_[hash2] == 0) {
698  hash_set_2_[hash2] = int_addr;
699  } else {
700  // Rather than slowing down we just throw away some entries. This will
701  // cause some duplicates to remain undetected.
702  hash_set_1_[hash1] = int_addr;
703  hash_set_2_[hash2] = 0;
704  }
705  old_buffer_is_sorted_ = false;
706  old_buffer_is_filtered_ = false;
707  *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2);
708  ASSERT(old_top_ <= old_limit_);
709  }
710  heap_->isolate()->counters()->store_buffer_compactions()->Increment();
711  CheckForFullBuffer();
712 }
713 
714 
715 void StoreBuffer::CheckForFullBuffer() {
717 }
718 
719 } } // namespace v8::internal
byte * Address
Definition: globals.h:172
bool FLAG_enable_slow_asserts
static const int kPointerFieldsEndOffset
Definition: objects.h:4977
static const int kHashSetLength
Definition: store-buffer.h:89
static Object *& Object_at(Address addr)
Definition: v8memory.h:75
bool Contains(Address addr)
Definition: spaces.h:365
bool InNewSpace(Object *object)
Definition: heap-inl.h:292
void(* ObjectSlotCallback)(HeapObject **from, HeapObject *to)
Definition: store-buffer.h:42
Isolate * isolate()
Definition: heap-inl.h:494
void set_scan_on_scavenge(bool scan)
Definition: spaces-inl.h:185
static MemoryChunk * FromAddress(Address a)
Definition: spaces.h:304
bool InFromSpace(Object *object)
Definition: heap-inl.h:306
#define ASSERT(condition)
Definition: checks.h:270
friend class DontMoveStoreBufferEntriesScope
Definition: store-buffer.h:204
static void StoreBufferOverflow(Isolate *isolate)
const int kPointerSizeLog2
Definition: globals.h:246
#define CHECK(condition)
Definition: checks.h:56
static const int kPageSize
Definition: spaces.h:695
StoreBuffer * store_buffer()
Definition: heap.h:1516
#define UNREACHABLE()
Definition: checks.h:50
bool Contains(Address a)
Definition: spaces-inl.h:178
void IteratePointersToNewSpace(ObjectSlotCallback callback)
static const int kStoreBufferOverflowBit
Definition: store-buffer.h:84
static const int kStoreBufferSize
Definition: store-buffer.h:85
const int kPointerSize
Definition: globals.h:234
bool IsFlagSet(int flag)
Definition: spaces.h:433
bool Commit(void *address, size_t size, bool is_executable)
OldSpace * old_pointer_space()
Definition: heap.h:500
T RoundUp(T x, intptr_t m)
Definition: utils.h:150
static const int kSize
Definition: objects.h:4972
OldSpace * code_space()
Definition: heap.h:502
void public_set_store_buffer_top(Address *top)
Definition: heap.h:1214
void EnsureSpace(intptr_t space_needed)
LargeObjectSpace * lo_space()
Definition: heap.h:505
HeapObject * GetObject()
Definition: spaces.h:738
void(StoreBuffer::* RegionCallback)(Address start, Address end, ObjectSlotCallback slot_callback)
Definition: store-buffer.h:44
CellSpace * cell_space()
Definition: heap.h:504
Space * owner() const
Definition: spaces.h:321
kPropertyAccessorsOffset kNamedPropertyHandlerOffset kInstanceTemplateOffset kAccessCheckInfoOffset kEvalFrominstructionsOffsetOffset kThisPropertyAssignmentsOffset flag
Definition: objects-inl.h:3682
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
Definition: flags.cc:274
static HeapObject * FromAddress(Address address)
Definition: objects-inl.h:1163
void USE(T)
Definition: globals.h:303
Counters * counters()
Definition: isolate.h:804
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping true
Definition: flags.cc:157
MapSpace * map_space()
Definition: heap.h:503
void set_store_buffer_counter(int counter)
Definition: spaces.h:361
static const int kOldStoreBufferLength
Definition: store-buffer.h:87
static const int kHashSetLengthLog2
Definition: store-buffer.h:88
void EnterDirectlyIntoStoreBuffer(Address addr)
static intptr_t CommitPageSize()
OldSpace * old_data_space()
Definition: heap.h:501
static MemoryChunk * FromAnyPointerAddress(Address addr)
Definition: spaces-inl.h:197
static const int kPointerFieldsBeginOffset
Definition: objects.h:4976