blob: 8978156464e677268c293e5193cc9288ff83ca81 [file] [log] [blame]
// 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<NodeId, NodeObservation*> 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_