1 // Copyright 2021 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 // This file declares the implementation of a new intrinsic %ObserveNode(expr),
6 // which has noop semantics but triggers the invocation of callbacks on a
7 // NodeObserver object. The NodeObserver is set on the OptimizedCompilationInfo
8 // and callbacks are called when the node generated for 'expr' is created or
9 // changed in any phase, until EffectControlLinearization.
10 //
11 // The modifications currently observed are changes to the observed Node
12 // operator and type and its replacement with another Node.
13 //
14 // This provides the infrastructure to write unit tests that check for the
15 // construction of or the lowering to specific nodes in the TurboFan graphs.
16
17 #ifndef V8_COMPILER_NODE_OBSERVER_H_
18 #define V8_COMPILER_NODE_OBSERVER_H_
19
20 #include "src/compiler/node.h"
21 #include "src/compiler/operator.h"
22 #include "src/zone/zone.h"
23
24 namespace v8 {
25 namespace internal {
26 namespace compiler {
27
28 class Node;
29 class Operator;
30
31 class ObservableNodeState {
32 public:
33 ObservableNodeState(const Node* node, Zone* zone);
34
id() const35 uint32_t id() const { return id_; }
op() const36 const Operator* op() const { return op_; }
opcode() const37 int16_t opcode() const { return op_->opcode(); }
type() const38 Type type() const { return type_; }
39
40 private:
41 uint32_t id_;
42 const Operator* op_;
43 Type type_;
44 };
45
operator ==(const ObservableNodeState& lhs, const ObservableNodeState& rhs)46 inline bool operator==(const ObservableNodeState& lhs,
47 const ObservableNodeState& rhs) {
48 return lhs.id() == rhs.id() && lhs.op() == rhs.op() &&
49 lhs.type() == rhs.type();
50 }
51
operator !=(const ObservableNodeState& lhs, const ObservableNodeState& rhs)52 inline bool operator!=(const ObservableNodeState& lhs,
53 const ObservableNodeState& rhs) {
54 return !operator==(lhs, rhs);
55 }
56
57 class NodeObserver : public ZoneObject {
58 public:
59 enum class Observation {
60 kContinue,
61 kStop,
62 };
63
64 NodeObserver() = default;
65 virtual ~NodeObserver() = 0;
66
67 NodeObserver(const NodeObserver&) = delete;
68 NodeObserver& operator=(const NodeObserver&) = delete;
69
OnNodeCreated(const Node* node)70 virtual Observation OnNodeCreated(const Node* node) {
71 return Observation::kContinue;
72 }
73
OnNodeChanged(const char* reducer_name, const Node* node, const ObservableNodeState& old_state)74 virtual Observation OnNodeChanged(const char* reducer_name, const Node* node,
75 const ObservableNodeState& old_state) {
76 return Observation::kContinue;
77 }
78
set_has_observed_changes()79 void set_has_observed_changes() { has_observed_changes_ = true; }
has_observed_changes() const80 bool has_observed_changes() const { return has_observed_changes_; }
81
82 private:
83 std::atomic<bool> has_observed_changes_{false};
84 };
85 inline NodeObserver::~NodeObserver() = default;
86
87 struct NodeObservation : public ZoneObject {
NodeObservationv8::internal::compiler::NodeObservation88 NodeObservation(NodeObserver* node_observer, const Node* node, Zone* zone)
89 : observer(node_observer), state(node, zone) {
90 DCHECK_NOT_NULL(node_observer);
91 }
92
93 NodeObserver* observer;
94 ObservableNodeState state;
95 };
96
97 class ObserveNodeManager : public ZoneObject {
98 public:
ObserveNodeManager(Zone* zone)99 explicit ObserveNodeManager(Zone* zone) : zone_(zone), observations_(zone) {}
100
101 void StartObserving(Node* node, NodeObserver* observer);
102 void OnNodeChanged(const char* reducer_name, const Node* old_node,
103 const Node* new_node);
104
105 private:
106 Zone* zone_;
107 ZoneMap<NodeId, NodeObservation*> observations_;
108 };
109
110 struct ObserveNodeInfo {
ObserveNodeInfov8::internal::compiler::ObserveNodeInfo111 ObserveNodeInfo() : observe_node_manager(nullptr), node_observer(nullptr) {}
ObserveNodeInfov8::internal::compiler::ObserveNodeInfo112 ObserveNodeInfo(ObserveNodeManager* manager, NodeObserver* observer)
113 : observe_node_manager(manager), node_observer(observer) {}
114
StartObservingv8::internal::compiler::ObserveNodeInfo115 void StartObserving(Node* node) const {
116 if (observe_node_manager) {
117 DCHECK_NOT_NULL(node_observer);
118 observe_node_manager->StartObserving(node, node_observer);
119 }
120 }
121
122 ObserveNodeManager* observe_node_manager;
123 NodeObserver* node_observer;
124 };
125
126 } // namespace compiler
127 } // namespace internal
128 } // namespace v8
129
130 #endif // V8_COMPILER_NODE_OBSERVER_H_
131