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
24namespace v8 {
25namespace internal {
26namespace compiler {
27
28class Node;
29class Operator;
30
31class ObservableNodeState {
32 public:
33  ObservableNodeState(const Node* node, Zone* zone);
34
35  uint32_t id() const { return id_; }
36  const Operator* op() const { return op_; }
37  int16_t opcode() const { return op_->opcode(); }
38  Type type() const { return type_; }
39
40 private:
41  uint32_t id_;
42  const Operator* op_;
43  Type type_;
44};
45
46inline 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
52inline bool operator!=(const ObservableNodeState& lhs,
53                       const ObservableNodeState& rhs) {
54  return !operator==(lhs, rhs);
55}
56
57class 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
70  virtual Observation OnNodeCreated(const Node* node) {
71    return Observation::kContinue;
72  }
73
74  virtual Observation OnNodeChanged(const char* reducer_name, const Node* node,
75                                    const ObservableNodeState& old_state) {
76    return Observation::kContinue;
77  }
78
79  void set_has_observed_changes() { has_observed_changes_ = true; }
80  bool has_observed_changes() const { return has_observed_changes_; }
81
82 private:
83  std::atomic<bool> has_observed_changes_{false};
84};
85inline NodeObserver::~NodeObserver() = default;
86
87struct NodeObservation : public ZoneObject {
88  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
97class ObserveNodeManager : public ZoneObject {
98 public:
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
110struct ObserveNodeInfo {
111  ObserveNodeInfo() : observe_node_manager(nullptr), node_observer(nullptr) {}
112  ObserveNodeInfo(ObserveNodeManager* manager, NodeObserver* observer)
113      : observe_node_manager(manager), node_observer(observer) {}
114
115  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