// Copyright 2013 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_GRAPH_BUILDER_H_ #define V8_COMPILER_GRAPH_BUILDER_H_ #include "src/v8.h" #include "src/allocation.h" #include "src/compiler/common-operator.h" #include "src/compiler/graph.h" #include "src/unique.h" namespace v8 { namespace internal { class BitVector; namespace compiler { class Node; // A common base class for anything that creates nodes in a graph. class GraphBuilder { public: explicit GraphBuilder(Graph* graph) : graph_(graph) {} virtual ~GraphBuilder() {} Node* NewNode(const Operator* op, bool incomplete = false) { return MakeNode(op, 0, static_cast(NULL), incomplete); } Node* NewNode(const Operator* op, Node* n1) { return MakeNode(op, 1, &n1, false); } Node* NewNode(const Operator* op, Node* n1, Node* n2) { Node* buffer[] = {n1, n2}; return MakeNode(op, arraysize(buffer), buffer, false); } Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) { Node* buffer[] = {n1, n2, n3}; return MakeNode(op, arraysize(buffer), buffer, false); } Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) { Node* buffer[] = {n1, n2, n3, n4}; return MakeNode(op, arraysize(buffer), buffer, false); } Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4, Node* n5) { Node* buffer[] = {n1, n2, n3, n4, n5}; return MakeNode(op, arraysize(buffer), buffer, false); } Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4, Node* n5, Node* n6) { Node* nodes[] = {n1, n2, n3, n4, n5, n6}; return MakeNode(op, arraysize(nodes), nodes, false); } Node* NewNode(const Operator* op, int value_input_count, Node** value_inputs, bool incomplete = false) { return MakeNode(op, value_input_count, value_inputs, incomplete); } Graph* graph() const { return graph_; } protected: // Base implementation used by all factory methods. virtual Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs, bool incomplete) = 0; private: Graph* graph_; }; // The StructuredGraphBuilder produces a high-level IR graph. It is used as the // base class for concrete implementations (e.g the AstGraphBuilder or the // StubGraphBuilder). class StructuredGraphBuilder : public GraphBuilder { public: StructuredGraphBuilder(Zone* zone, Graph* graph, CommonOperatorBuilder* common); virtual ~StructuredGraphBuilder() {} // Creates a new Phi node having {count} input values. Node* NewPhi(int count, Node* input, Node* control); Node* NewEffectPhi(int count, Node* input, Node* control); // Helpers for merging control, effect or value dependencies. Node* MergeControl(Node* control, Node* other); Node* MergeEffect(Node* value, Node* other, Node* control); Node* MergeValue(Node* value, Node* other, Node* control); // Helpers to create new control nodes. Node* NewIfTrue() { return NewNode(common()->IfTrue()); } Node* NewIfFalse() { return NewNode(common()->IfFalse()); } Node* NewMerge() { return NewNode(common()->Merge(1), true); } Node* NewLoop() { return NewNode(common()->Loop(1), true); } Node* NewBranch(Node* condition, BranchHint hint = BranchHint::kNone) { return NewNode(common()->Branch(hint), condition); } protected: class Environment; friend class Environment; friend class ControlBuilder; // The following method creates a new node having the specified operator and // ensures effect and control dependencies are wired up. The dependencies // tracked by the environment might be mutated. virtual Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs, bool incomplete) FINAL; Environment* environment() const { return environment_; } void set_environment(Environment* env) { environment_ = env; } Node* current_context() const { return current_context_; } void set_current_context(Node* context) { current_context_ = context; } Node* exit_control() const { return exit_control_; } void set_exit_control(Node* node) { exit_control_ = node; } Node* dead_control(); Zone* graph_zone() const { return graph()->zone(); } Zone* local_zone() const { return local_zone_; } Isolate* isolate() const { return graph_zone()->isolate(); } CommonOperatorBuilder* common() const { return common_; } // Helper to wrap a Handle into a Unique. template Unique MakeUnique(Handle object) { return Unique::CreateUninitialized(object); } // Support for control flow builders. The concrete type of the environment // depends on the graph builder, but environments themselves are not virtual. virtual Environment* CopyEnvironment(Environment* env); // Helper to indicate a node exits the function body. void UpdateControlDependencyToLeaveFunction(Node* exit); private: CommonOperatorBuilder* common_; Environment* environment_; // Zone local to the builder for data not leaking into the graph. Zone* local_zone_; // Temporary storage for building node input lists. int input_buffer_size_; Node** input_buffer_; // Node representing the control dependency for dead code. SetOncePointer dead_control_; // Node representing the current context within the function body. Node* current_context_; // Merge of all control nodes that exit the function body. Node* exit_control_; // Growth increment for the temporary buffer used to construct input lists to // new nodes. static const int kInputBufferSizeIncrement = 64; Node** EnsureInputBufferSize(int size); DISALLOW_COPY_AND_ASSIGN(StructuredGraphBuilder); }; // The abstract execution environment contains static knowledge about // execution state at arbitrary control-flow points. It allows for // simulation of the control-flow at compile time. class StructuredGraphBuilder::Environment : public ZoneObject { public: Environment(StructuredGraphBuilder* builder, Node* control_dependency); Environment(const Environment& copy); // Control dependency tracked by this environment. Node* GetControlDependency() { return control_dependency_; } void UpdateControlDependency(Node* dependency) { control_dependency_ = dependency; } // Effect dependency tracked by this environment. Node* GetEffectDependency() { return effect_dependency_; } void UpdateEffectDependency(Node* dependency) { effect_dependency_ = dependency; } // Mark this environment as being unreachable. void MarkAsUnreachable() { UpdateControlDependency(builder()->dead_control()); } bool IsMarkedAsUnreachable() { return GetControlDependency()->opcode() == IrOpcode::kDead; } // Merge another environment into this one. void Merge(Environment* other); // Copies this environment at a control-flow split point. Environment* CopyForConditional() { return builder()->CopyEnvironment(this); } // Copies this environment to a potentially unreachable control-flow point. Environment* CopyAsUnreachable() { Environment* env = builder()->CopyEnvironment(this); env->MarkAsUnreachable(); return env; } // Copies this environment at a loop header control-flow point. Environment* CopyForLoop(BitVector* assigned) { PrepareForLoop(assigned); return builder()->CopyEnvironment(this); } Node* GetContext() { return builder_->current_context(); } protected: Zone* zone() const { return builder_->local_zone(); } Graph* graph() const { return builder_->graph(); } StructuredGraphBuilder* builder() const { return builder_; } CommonOperatorBuilder* common() { return builder_->common(); } NodeVector* values() { return &values_; } // Prepare environment to be used as loop header. void PrepareForLoop(BitVector* assigned); private: StructuredGraphBuilder* builder_; Node* control_dependency_; Node* effect_dependency_; NodeVector values_; }; } } } // namespace v8::internal::compiler #endif // V8_COMPILER_GRAPH_BUILDER_H__