v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
block-instrumentation-reducer.h
Go to the documentation of this file.
1// Copyright 2024 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#ifndef V8_COMPILER_TURBOSHAFT_BLOCK_INSTRUMENTATION_REDUCER_H_
6#define V8_COMPILER_TURBOSHAFT_BLOCK_INSTRUMENTATION_REDUCER_H_
7
13
15
17
18namespace detail {
19Handle<HeapObject> CreateCountersArray(Isolate* isolate);
20} // namespace detail
21
22template <typename Next>
24 : public UniformReducerAdapter<BlockInstrumentationReducer, Next> {
25 public:
26 TURBOSHAFT_REDUCER_BOILERPLATE(BlockInstrumentation)
28
35
36 void Bind(Block* new_block) {
37 Next::Bind(new_block);
38
39 const int block_number = new_block->index().id();
40 data_->SetBlockId(block_number, block_number);
41
42 // Reset counter.
44 }
45
46 template <Opcode opcode, typename Continuation, typename... Args>
48 // Those operations must be skipped here because we want to keep them at the
49 // beginning of their blocks.
50 static_assert(opcode != Opcode::kCatchBlockBegin);
51 static_assert(opcode != Opcode::kDidntThrow);
52 static_assert(opcode != Opcode::kParameter);
53
55 // If this is the first (non-skipped) operation in this block, emit
56 // instrumentation.
57 const int block_number = __ current_block() -> index().id();
58 EmitBlockInstrumentation(block_number);
59 }
60 return Continuation{this}.Reduce(args...);
61 }
62
63 V<Object> REDUCE(Parameter)(int32_t parameter_index,
65 const char* debug_name) {
66 // Skip generic callback as we don't want to emit instrumentation BEFORE
67 // this operation.
68 return Next::ReduceParameter(parameter_index, rep, debug_name);
69 }
70
72 // Skip generic callback as we don't want to emit instrumentation BEFORE
73 // this operation.
74 return Next::ReduceCatchBlockBegin();
75 }
76
78 V<Any> throwing_operation, bool has_catch_block,
80 OpEffects throwing_op_effects) {
81 // Skip generic callback as we don't want to emit instrumentation BEFORE
82 // this operation.
83 return Next::ReduceDidntThrow(throwing_operation, has_catch_block,
84 results_rep, throwing_op_effects);
85 }
86
87 V<Word32> LoadCounterValue(int block_number) {
88 int offset_to_counter_value = block_number * kInt32Size;
90 offset_to_counter_value += sizeof(ByteArray::Header);
91 // Allocation is disallowed here, so rather than referring to an actual
92 // counters array, create a reference to a special marker object. This
93 // object will get fixed up later in the constants table (see
94 // PatchBasicBlockCountersReference). An important and subtle point: we
95 // cannot use the root handle basic_block_counters_marker_handle() and
96 // must create a new separate handle. Otherwise
97 // MacroAssemblerBase::IndirectLoadConstant would helpfully emit a
98 // root-relative load rather than putting this value in the constants
99 // table where we expect it to be for patching.
100 V<HeapObject> counter_array = __ HeapConstant(counters_array_handle_);
101 return __ Load(counter_array, LoadOp::Kind::TaggedBase(),
102 MemoryRepresentation::Uint32(), offset_to_counter_value);
103 } else {
104 V<WordPtr> counter_array =
105 __ WordPtrConstant(reinterpret_cast<uintptr_t>(data_->counts()));
106 return __ LoadOffHeap(counter_array, offset_to_counter_value,
108 }
109 }
110
111 void StoreCounterValue(int block_number, V<Word32> value) {
112 int offset_to_counter_value = block_number * kInt32Size;
113 if (on_heap_counters_) {
114 offset_to_counter_value += sizeof(ByteArray::Header);
115 // Allocation is disallowed here, so rather than referring to an actual
116 // counters array, create a reference to a special marker object. This
117 // object will get fixed up later in the constants table (see
118 // PatchBasicBlockCountersReference). An important and subtle point: we
119 // cannot use the root handle basic_block_counters_marker_handle() and
120 // must create a new separate handle. Otherwise
121 // MacroAssemblerBase::IndirectLoadConstant would helpfully emit a
122 // root-relative load rather than putting this value in the constants
123 // table where we expect it to be for patching.
124 V<HeapObject> counter_array = __ HeapConstant(counters_array_handle_);
125 __ Store(counter_array, value, StoreOp::Kind::TaggedBase(),
127 WriteBarrierKind::kNoWriteBarrier, offset_to_counter_value);
128 } else {
129 V<WordPtr> counter_array =
130 __ WordPtrConstant(reinterpret_cast<uintptr_t>(data_->counts()));
131 __ StoreOffHeap(counter_array, value, MemoryRepresentation::Uint32(),
132 offset_to_counter_value);
133 }
134 }
135
136 void EmitBlockInstrumentation(int block_number) {
137 // Load the current counter value from the array.
138 V<Word32> value = LoadCounterValue(block_number);
139
140 // Increment the counter value.
141 V<Word32> incremented_value = __ Word32Add(value, 1);
142
143 // Branchless saturation, because we don't want to introduce additional
144 // control flow here.
145 V<Word32> overflow = __ Uint32LessThan(incremented_value, value);
146 V<Word32> overflow_mask = __ Word32Sub(0, overflow);
147 V<Word32> saturated_value =
148 __ Word32BitwiseOr(incremented_value, overflow_mask);
149
150 // Store the incremented counter value back into the array.
151 StoreCounterValue(block_number, saturated_value);
152 }
153
155 const int true_id = branch.if_true->index().id();
156 const int false_id = branch.if_false->index().id();
157 data_->AddBranch(true_id, false_id);
158 return Next::ReduceInputGraphBranch(ig_index, branch);
159 }
160
161 private:
163 BasicBlockProfilerData* data_ = __ data() -> info()->profiler_data();
164 const bool on_heap_counters_ =
168};
169
171
172} // namespace v8::internal::compiler::turboshaft
173
174#endif // V8_COMPILER_TURBOSHAFT_BLOCK_INSTRUMENTATION_REDUCER_H_
#define REDUCE(operation)
#define REDUCE_INPUT_GRAPH(operation)
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
void SetBlockId(size_t offset, int32_t id)
void AddBranch(int32_t true_block_id, int32_t false_block_id)
bool IsGeneratingEmbeddedBuiltins() const
Definition isolate.h:1897
detail::ArrayHeaderBase< HeapObjectLayout, true > Header
V< None > REDUCE_INPUT_GRAPH Branch(V< None > ig_index, const BranchOp &branch)
V< Object > REDUCE Parameter(int32_t parameter_index, RegisterRepresentation rep, const char *debug_name)
V< Any > REDUCE DidntThrow(V< Any > throwing_operation, bool has_catch_block, const base::Vector< const RegisterRepresentation > *results_rep, OpEffects throwing_op_effects)
static constexpr MemoryRepresentation Uint32()
#define TURBOSHAFT_REDUCER_BOILERPLATE(Name)
Definition assembler.h:823
Handle< SharedFunctionInfo > info
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
Isolate * isolate
Handle< HeapObject > CreateCountersArray(Isolate *isolate)
constexpr int kInt32Size
Definition globals.h:401
i::Address Load(i::Address address)
Definition unwinder.cc:19
#define DCHECK_NOT_NULL(val)
Definition logging.h:492