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/heap-write-barrier.h"
6
7 #include "src/heap/embedder-tracing.h"
8 #include "src/heap/heap-write-barrier-inl.h"
9 #include "src/heap/marking-barrier.h"
10 #include "src/objects/code-inl.h"
11 #include "src/objects/descriptor-array.h"
12 #include "src/objects/js-objects.h"
13 #include "src/objects/maybe-object.h"
14 #include "src/objects/slots-inl.h"
15
16 namespace v8 {
17 namespace internal {
18
19 namespace {
20 thread_local MarkingBarrier* current_marking_barrier = nullptr;
21 } // namespace
22
CurrentMarkingBarrier(Heap * heap)23 MarkingBarrier* WriteBarrier::CurrentMarkingBarrier(Heap* heap) {
24 return current_marking_barrier ? current_marking_barrier
25 : heap->marking_barrier();
26 }
27
SetForThread(MarkingBarrier * marking_barrier)28 void WriteBarrier::SetForThread(MarkingBarrier* marking_barrier) {
29 DCHECK_NULL(current_marking_barrier);
30 current_marking_barrier = marking_barrier;
31 }
32
ClearForThread(MarkingBarrier * marking_barrier)33 void WriteBarrier::ClearForThread(MarkingBarrier* marking_barrier) {
34 DCHECK_EQ(current_marking_barrier, marking_barrier);
35 current_marking_barrier = nullptr;
36 }
37
MarkingSlow(Heap * heap,HeapObject host,HeapObjectSlot slot,HeapObject value)38 void WriteBarrier::MarkingSlow(Heap* heap, HeapObject host, HeapObjectSlot slot,
39 HeapObject value) {
40 MarkingBarrier* marking_barrier = current_marking_barrier
41 ? current_marking_barrier
42 : heap->marking_barrier();
43 marking_barrier->Write(host, slot, value);
44 }
45
46 // static
MarkingSlowFromGlobalHandle(Heap * heap,HeapObject value)47 void WriteBarrier::MarkingSlowFromGlobalHandle(Heap* heap, HeapObject value) {
48 heap->marking_barrier()->WriteWithoutHost(value);
49 }
50
51 // static
MarkingSlowFromInternalFields(Heap * heap,JSObject host)52 void WriteBarrier::MarkingSlowFromInternalFields(Heap* heap, JSObject host) {
53 auto* local_embedder_heap_tracer = heap->local_embedder_heap_tracer();
54 if (!local_embedder_heap_tracer->InUse()) return;
55
56 local_embedder_heap_tracer->EmbedderWriteBarrier(heap, host);
57 }
58
MarkingSlow(Heap * heap,Code host,RelocInfo * reloc_info,HeapObject value)59 void WriteBarrier::MarkingSlow(Heap* heap, Code host, RelocInfo* reloc_info,
60 HeapObject value) {
61 MarkingBarrier* marking_barrier = current_marking_barrier
62 ? current_marking_barrier
63 : heap->marking_barrier();
64 marking_barrier->Write(host, reloc_info, value);
65 }
66
MarkingSlow(Heap * heap,JSArrayBuffer host,ArrayBufferExtension * extension)67 void WriteBarrier::MarkingSlow(Heap* heap, JSArrayBuffer host,
68 ArrayBufferExtension* extension) {
69 MarkingBarrier* marking_barrier = current_marking_barrier
70 ? current_marking_barrier
71 : heap->marking_barrier();
72 marking_barrier->Write(host, extension);
73 }
74
MarkingSlow(Heap * heap,DescriptorArray descriptor_array,int number_of_own_descriptors)75 void WriteBarrier::MarkingSlow(Heap* heap, DescriptorArray descriptor_array,
76 int number_of_own_descriptors) {
77 MarkingBarrier* marking_barrier = current_marking_barrier
78 ? current_marking_barrier
79 : heap->marking_barrier();
80 marking_barrier->Write(descriptor_array, number_of_own_descriptors);
81 }
82
MarkingFromCode(Address raw_host,Address raw_slot)83 int WriteBarrier::MarkingFromCode(Address raw_host, Address raw_slot) {
84 HeapObject host = HeapObject::cast(Object(raw_host));
85 MaybeObjectSlot slot(raw_slot);
86 Address value = (*slot).ptr();
87 #ifdef V8_MAP_PACKING
88 if (slot.address() == host.address()) {
89 // Clear metadata bits and fix object tag.
90 value = (value & ~Internals::kMapWordMetadataMask &
91 ~Internals::kMapWordXorMask) |
92 (uint64_t)kHeapObjectTag;
93 }
94 #endif
95 WriteBarrier::Marking(host, slot, MaybeObject(value));
96 // Called by WriteBarrierCodeStubAssembler, which doesnt accept void type
97 return 0;
98 }
99
100 #ifdef ENABLE_SLOW_DCHECKS
IsImmortalImmovableHeapObject(HeapObject object)101 bool WriteBarrier::IsImmortalImmovableHeapObject(HeapObject object) {
102 BasicMemoryChunk* basic_chunk = BasicMemoryChunk::FromHeapObject(object);
103 // All objects in readonly space are immortal and immovable.
104 if (basic_chunk->InReadOnlySpace()) return true;
105 MemoryChunk* chunk = MemoryChunk::FromHeapObject(object);
106 // There are also objects in "regular" spaces which are immortal and
107 // immovable. Objects on a page that can get compacted are movable and can be
108 // filtered out.
109 if (!chunk->IsFlagSet(MemoryChunk::NEVER_EVACUATE)) return false;
110 // Now we know the object is immovable, check whether it is also immortal.
111 // Builtins are roots and therefore always kept alive by the GC.
112 return object.IsCode() && Code::cast(object).is_builtin();
113 }
114 #endif
115
116 } // namespace internal
117 } // namespace v8
118