// Copyright 2017 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. #ifndef V8_COMPILER_ESCAPE_ANALYSIS_REDUCER_H_ #define V8_COMPILER_ESCAPE_ANALYSIS_REDUCER_H_ #include "src/base/compiler-specific.h" #include "src/common/globals.h" #include "src/compiler/access-builder.h" #include "src/compiler/escape-analysis.h" #include "src/compiler/graph-reducer.h" namespace v8 { namespace internal { namespace compiler { class Deduplicator; class JSGraph; // Perform hash-consing when creating or mutating nodes. Used to avoid duplicate // nodes when creating ObjectState, StateValues and FrameState nodes class NodeHashCache { public: NodeHashCache(Graph* graph, Zone* zone) : graph_(graph), cache_(zone), temp_nodes_(zone) {} // Handle to a conceptually new mutable node. Tries to re-use existing nodes // and to recycle memory if possible. class Constructor { public: // Construct a new node as a clone of [from]. Constructor(NodeHashCache* cache, Node* from) : node_cache_(cache), from_(from), tmp_(nullptr) {} // Construct a new node from scratch. Constructor(NodeHashCache* cache, const Operator* op, int input_count, Node** inputs, Type type); // Modify the new node. void ReplaceValueInput(Node* input, int i) { if (!tmp_ && input == NodeProperties::GetValueInput(from_, i)) return; Node* node = MutableNode(); NodeProperties::ReplaceValueInput(node, input, i); } void ReplaceInput(Node* input, int i) { if (!tmp_ && input == from_->InputAt(i)) return; Node* node = MutableNode(); node->ReplaceInput(i, input); } // Obtain the mutated node or a cached copy. Invalidates the [Constructor]. Node* Get(); private: Node* MutableNode(); NodeHashCache* node_cache_; // Original node, copied on write. Node* from_; // Temporary node used for mutations, can be recycled if cache is hit. Node* tmp_; }; private: Node* Query(Node* node); void Insert(Node* node) { cache_.insert(node); } Graph* graph_; struct NodeEquals { bool operator()(Node* a, Node* b) const { return NodeProperties::Equals(a, b); } }; struct NodeHashCode { size_t operator()(Node* n) const { return NodeProperties::HashCode(n); } }; ZoneUnorderedSet cache_; // Unused nodes whose memory can be recycled. ZoneVector temp_nodes_; }; // Modify the graph according to the information computed in the previous phase. class V8_EXPORT_PRIVATE EscapeAnalysisReducer final : public NON_EXPORTED_BASE(AdvancedReducer) { public: EscapeAnalysisReducer(Editor* editor, JSGraph* jsgraph, EscapeAnalysisResult analysis_result, Zone* zone); Reduction Reduce(Node* node) override; const char* reducer_name() const override { return "EscapeAnalysisReducer"; } void Finalize() override; // Verifies that all virtual allocation nodes have been dealt with. Run it // after this reducer has been applied. void VerifyReplacement() const; private: void ReduceFrameStateInputs(Node* node); Node* ReduceDeoptState(Node* node, Node* effect, Deduplicator* deduplicator); Node* ObjectIdNode(const VirtualObject* vobject); Reduction ReplaceNode(Node* original, Node* replacement); JSGraph* jsgraph() const { return jsgraph_; } Isolate* isolate() const { return jsgraph_->isolate(); } EscapeAnalysisResult analysis_result() const { return analysis_result_; } Zone* zone() const { return zone_; } JSGraph* const jsgraph_; EscapeAnalysisResult analysis_result_; ZoneVector object_id_cache_; NodeHashCache node_cache_; ZoneSet arguments_elements_; Zone* const zone_; DISALLOW_COPY_AND_ASSIGN(EscapeAnalysisReducer); }; } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_COMPILER_ESCAPE_ANALYSIS_REDUCER_H_