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