// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // This file declares the implementation of a new intrinsic %ObserveNode(expr), // which has noop semantics but triggers the invocation of callbacks on a // NodeObserver object. The NodeObserver is set on the OptimizedCompilationInfo // and callbacks are called when the node generated for 'expr' is created or // changed in any phase, until EffectControlLinearization. // // The modifications currently observed are changes to the observed Node // operator and type and its replacement with another Node. // // This provides the infrastructure to write unit tests that check for the // construction of or the lowering to specific nodes in the TurboFan graphs. #ifndef V8_COMPILER_NODE_OBSERVER_H_ #define V8_COMPILER_NODE_OBSERVER_H_ #include "src/compiler/node.h" #include "src/compiler/operator.h" #include "src/zone/zone.h" namespace v8 { namespace internal { namespace compiler { class Node; class Operator; class ObservableNodeState { public: ObservableNodeState(const Node* node, Zone* zone); uint32_t id() const { return id_; } const Operator* op() const { return op_; } int16_t opcode() const { return op_->opcode(); } Type type() const { return type_; } private: uint32_t id_; const Operator* op_; Type type_; }; inline bool operator==(const ObservableNodeState& lhs, const ObservableNodeState& rhs) { return lhs.id() == rhs.id() && lhs.op() == rhs.op() && lhs.type() == rhs.type(); } inline bool operator!=(const ObservableNodeState& lhs, const ObservableNodeState& rhs) { return !operator==(lhs, rhs); } class NodeObserver : public ZoneObject { public: enum class Observation { kContinue, kStop, }; NodeObserver() = default; virtual ~NodeObserver() = 0; NodeObserver(const NodeObserver&) = delete; NodeObserver& operator=(const NodeObserver&) = delete; virtual Observation OnNodeCreated(const Node* node) { return Observation::kContinue; } virtual Observation OnNodeChanged(const char* reducer_name, const Node* node, const ObservableNodeState& old_state) { return Observation::kContinue; } void set_has_observed_changes() { has_observed_changes_ = true; } bool has_observed_changes() const { return has_observed_changes_; } private: bool has_observed_changes_ = false; }; inline NodeObserver::~NodeObserver() = default; struct NodeObservation : public ZoneObject { NodeObservation(NodeObserver* node_observer, const Node* node, Zone* zone) : observer(node_observer), state(node, zone) { DCHECK_NOT_NULL(node_observer); } NodeObserver* observer; ObservableNodeState state; }; class ObserveNodeManager : public ZoneObject { public: explicit ObserveNodeManager(Zone* zone) : zone_(zone), observations_(zone) {} void StartObserving(Node* node, NodeObserver* observer); void OnNodeChanged(const char* reducer_name, const Node* old_node, const Node* new_node); private: Zone* zone_; ZoneMap observations_; }; struct ObserveNodeInfo { ObserveNodeInfo() : observe_node_manager(nullptr), node_observer(nullptr) {} ObserveNodeInfo(ObserveNodeManager* manager, NodeObserver* observer) : observe_node_manager(manager), node_observer(observer) {} void StartObserving(Node* node) const { if (observe_node_manager) { DCHECK_NOT_NULL(node_observer); observe_node_manager->StartObserving(node, node_observer); } } ObserveNodeManager* observe_node_manager; NodeObserver* node_observer; }; } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_COMPILER_NODE_OBSERVER_H_