1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/heap/conservative-stack-visitor.h"
6
7#include "src/execution/isolate-utils-inl.h"
8#include "src/heap/large-spaces.h"
9#include "src/heap/paged-spaces-inl.h"
10
11namespace v8 {
12namespace internal {
13
14ConservativeStackVisitor::ConservativeStackVisitor(Isolate* isolate,
15                                                   RootVisitor* delegate)
16    : isolate_(isolate), delegate_(delegate) {}
17
18void ConservativeStackVisitor::VisitPointer(const void* pointer) {
19  VisitConservativelyIfPointer(pointer);
20}
21
22bool ConservativeStackVisitor::CheckPage(Address address, MemoryChunk* page) {
23  if (address < page->area_start() || address >= page->area_end()) return false;
24
25  auto base_ptr = page->object_start_bitmap()->FindBasePtr(address);
26  if (base_ptr == kNullAddress) {
27    return false;
28  }
29
30  // At this point, base_ptr *must* refer to the valid object. We check if
31  // |address| resides inside the object or beyond it in unused memory.
32  HeapObject obj = HeapObject::FromAddress(base_ptr);
33  Address obj_end = obj.address() + obj.Size();
34
35  if (address >= obj_end) {
36    // |address| points to unused memory.
37    return false;
38  }
39
40  // TODO(jakehughes) Pinning is only required for the marking visitor. Other
41  // visitors (such as verify visitor) could work without pining. This should
42  // be moved to delegate_
43  page->SetFlag(BasicMemoryChunk::Flag::PINNED);
44
45  Object ptr = HeapObject::FromAddress(base_ptr);
46  FullObjectSlot root = FullObjectSlot(&ptr);
47  delegate_->VisitRootPointer(Root::kHandleScope, nullptr, root);
48  DCHECK(root == FullObjectSlot(reinterpret_cast<Address>(&base_ptr)));
49  return true;
50}
51
52void ConservativeStackVisitor::VisitConservativelyIfPointer(
53    const void* pointer) {
54  auto address = reinterpret_cast<Address>(pointer);
55  if (address > isolate_->heap()->old_space()->top() ||
56      address < isolate_->heap()->old_space()->limit()) {
57    return;
58  }
59
60  for (Page* page : *isolate_->heap()->old_space()) {
61    if (CheckPage(address, page)) {
62      return;
63    }
64  }
65
66  for (LargePage* page : *isolate_->heap()->lo_space()) {
67    if (address >= page->area_start() && address < page->area_end()) {
68      Object ptr = page->GetObject();
69      FullObjectSlot root = FullObjectSlot(&ptr);
70      delegate_->VisitRootPointer(Root::kHandleScope, nullptr, root);
71      DCHECK(root == FullObjectSlot(&ptr));
72      return;
73    }
74  }
75}
76
77}  // namespace internal
78}  // namespace v8
79