diff options
Diffstat (limited to 'deps/v8/src/compiler/ast-graph-builder.h')
-rw-r--r-- | deps/v8/src/compiler/ast-graph-builder.h | 437 |
1 files changed, 231 insertions, 206 deletions
diff --git a/deps/v8/src/compiler/ast-graph-builder.h b/deps/v8/src/compiler/ast-graph-builder.h index 0337c813b9..ebeb6c613c 100644 --- a/deps/v8/src/compiler/ast-graph-builder.h +++ b/deps/v8/src/compiler/ast-graph-builder.h @@ -5,63 +5,191 @@ #ifndef V8_COMPILER_AST_GRAPH_BUILDER_H_ #define V8_COMPILER_AST_GRAPH_BUILDER_H_ -#include "src/v8.h" - #include "src/ast.h" -#include "src/compiler/graph-builder.h" #include "src/compiler/js-graph.h" namespace v8 { namespace internal { + +class BitVector; + namespace compiler { class ControlBuilder; class Graph; class LoopAssignmentAnalysis; class LoopBuilder; +class Node; // The AstGraphBuilder produces a high-level IR graph, based on an // underlying AST. The produced graph can either be compiled into a // stand-alone function or be wired into another graph for the purposes // of function inlining. -class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { +class AstGraphBuilder : public AstVisitor { public: AstGraphBuilder(Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph, LoopAssignmentAnalysis* loop_assignment = NULL); // Creates a graph by visiting the entire AST. - bool CreateGraph(); + bool CreateGraph(bool constant_context); + + // 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: +#define DECLARE_VISIT(type) void Visit##type(type* node) OVERRIDE; + // Visiting functions for AST nodes make this an AstVisitor. + AST_NODE_LIST(DECLARE_VISIT) +#undef DECLARE_VISIT + + // Visiting function for declarations list is overridden. + void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE; + + private: class AstContext; class AstEffectContext; class AstValueContext; class AstTestContext; - class BreakableScope; class ContextScope; + class ControlScope; + class ControlScopeForBreakable; + class ControlScopeForIteration; + class ControlScopeForCatch; + class ControlScopeForFinally; class Environment; + friend class ControlBuilder; - Environment* environment() { - return reinterpret_cast<Environment*>( - StructuredGraphBuilder::environment()); - } + Zone* local_zone_; + CompilationInfo* info_; + JSGraph* jsgraph_; + Environment* environment_; + AstContext* ast_context_; + // List of global declarations for functions and variables. + ZoneVector<Handle<Object>> globals_; + + // Stack of control scopes currently entered by the visitor. + ControlScope* execution_control_; + + // Stack of context objects pushed onto the chain by the visitor. + ContextScope* execution_context_; + + // Nodes representing values in the activation record. + SetOncePointer<Node> function_closure_; + SetOncePointer<Node> function_context_; + + // Temporary storage for building node input lists. + int input_buffer_size_; + Node** input_buffer_; + + // Merge of all control nodes that exit the function body. + Node* exit_control_; + + // Result of loop assignment analysis performed before graph creation. + LoopAssignmentAnalysis* loop_assignment_analysis_; + + // Growth increment for the temporary buffer used to construct input lists to + // new nodes. + static const int kInputBufferSizeIncrement = 64; + + Zone* local_zone() const { return local_zone_; } + Environment* environment() const { return environment_; } AstContext* ast_context() const { return ast_context_; } - BreakableScope* breakable() const { return breakable_; } + ControlScope* execution_control() const { return execution_control_; } ContextScope* execution_context() const { return execution_context_; } + CommonOperatorBuilder* common() const { return jsgraph_->common(); } + CompilationInfo* info() const { return info_; } + LanguageMode language_mode() const; + JSGraph* jsgraph() { return jsgraph_; } + Graph* graph() { return jsgraph_->graph(); } + Zone* graph_zone() { return graph()->zone(); } + JSOperatorBuilder* javascript() { return jsgraph_->javascript(); } + ZoneVector<Handle<Object>>* globals() { return &globals_; } + Scope* current_scope() const; + Node* current_context() const; + Node* exit_control() const { return exit_control_; } + void set_environment(Environment* env) { environment_ = env; } void set_ast_context(AstContext* ctx) { ast_context_ = ctx; } - void set_breakable(BreakableScope* brk) { breakable_ = brk; } + void set_execution_control(ControlScope* ctrl) { execution_control_ = ctrl; } void set_execution_context(ContextScope* ctx) { execution_context_ = ctx; } + void set_exit_control(Node* exit) { exit_control_ = exit; } + + // Create the main graph body by visiting the AST. + void CreateGraphBody(); - // Support for control flow builders. The concrete type of the environment - // depends on the graph builder, but environments themselves are not virtual. - typedef StructuredGraphBuilder::Environment BaseEnvironment; - BaseEnvironment* CopyEnvironment(BaseEnvironment* env) OVERRIDE; + // Create the node that represents the outer context of the function. + void CreateFunctionContext(bool constant_context); - // Getters for values in the activation record. + // Get or create the node that represents the outer function closure. Node* GetFunctionClosure(); - Node* GetFunctionContext(); + + // Node creation helpers. + Node* NewNode(const Operator* op, bool incomplete = false) { + return MakeNode(op, 0, static_cast<Node**>(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); + } + + // 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); + + Node* NewOuterContextParam(); + Node* NewCurrentContextOsrValue(); + + // 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); + + // The main node creation chokepoint. Adds context, frame state, effect, + // and control dependencies depending on the operator. + Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs, + bool incomplete); + + // Helper to indicate a node exits the function body. + void UpdateControlDependencyToLeaveFunction(Node* exit); // // The following build methods all generate graph fragments and return one @@ -72,12 +200,16 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { // Builder to create a receiver check for sloppy mode. Node* BuildPatchReceiverToGlobalProxy(Node* receiver); - // Builder to create a local function context. + // Builders to create local function and block contexts. Node* BuildLocalFunctionContext(Node* context, Node* closure); + Node* BuildLocalBlockContext(Scope* scope); // Builder to create an arguments object if it is used. Node* BuildArgumentsObject(Variable* arguments); + // Builder to create an array of rest parameters if used + Node* BuildRestArgumentsArray(Variable* rest, int index); + // Builders for variable load and assignment. Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op, BailoutId bailout_id, @@ -98,6 +230,11 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { // Builders for automatic type conversion. Node* BuildToBoolean(Node* value); + Node* BuildToName(Node* value, BailoutId bailout_id); + + // Builder for adding the [[HomeObject]] to a value if the value came from a + // function literal and needs a home object. Do nothing otherwise. + Node* BuildSetHomeObject(Node* value, Node* home_object, Expression* expr); // Builders for error reporting at runtime. Node* BuildThrowReferenceError(Variable* var, BailoutId bailout_id); @@ -108,49 +245,27 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole, BailoutId bailout_id); + // Builders for non-local control flow. + Node* BuildReturn(Node* return_value); + Node* BuildThrow(Node* exception_value); + // Builders for binary operations. Node* BuildBinaryOp(Node* left, Node* right, Token::Value op); // Builder for stack-check guards. Node* BuildStackCheck(); -#define DECLARE_VISIT(type) void Visit##type(type* node) OVERRIDE; - // Visiting functions for AST nodes make this an AstVisitor. - AST_NODE_LIST(DECLARE_VISIT) -#undef DECLARE_VISIT - - // Visiting function for declarations list is overridden. - void VisitDeclarations(ZoneList<Declaration*>* declarations) OVERRIDE; + // Check if the given statement is an OSR entry. + // If so, record the stack height into the compilation and return {true}. + bool CheckOsrEntry(IterationStatement* stmt); - private: - CompilationInfo* info_; - AstContext* ast_context_; - JSGraph* jsgraph_; - - // List of global declarations for functions and variables. - ZoneVector<Handle<Object>> globals_; - - // Stack of breakable statements entered by the visitor. - BreakableScope* breakable_; - - // Stack of context objects pushed onto the chain by the visitor. - ContextScope* execution_context_; - - // Nodes representing values in the activation record. - SetOncePointer<Node> function_closure_; - SetOncePointer<Node> function_context_; - - // Result of loop assignment analysis performed before graph creation. - LoopAssignmentAnalysis* loop_assignment_analysis_; - - CompilationInfo* info() const { return info_; } - inline StrictMode strict_mode() const; - JSGraph* jsgraph() { return jsgraph_; } - JSOperatorBuilder* javascript() { return jsgraph_->javascript(); } - ZoneVector<Handle<Object>>* globals() { return &globals_; } + // Helper to wrap a Handle<T> into a Unique<T>. + template <class T> + Unique<T> MakeUnique(Handle<T> object) { + return Unique<T>::CreateUninitialized(object); + } - // Current scope during visitation. - inline Scope* current_scope() const; + Node** EnsureInputBufferSize(int size); // Named and keyed loads require a VectorSlotPair for successful lowering. VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const; @@ -168,6 +283,7 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { void VisitForEffect(Expression* expr); void VisitForValue(Expression* expr); void VisitForValueOrNull(Expression* expr); + void VisitForValueOrTheHole(Expression* expr); void VisitForValues(ZoneList<Expression*>* exprs); // Common for all IterationStatement bodies. @@ -188,7 +304,12 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { void VisitArithmeticExpression(BinaryOperation* expr); // Dispatched from VisitForInStatement. - void VisitForInAssignment(Expression* expr, Node* value); + void VisitForInAssignment(Expression* expr, Node* value, + BailoutId bailout_id); + void VisitForInBody(ForInStatement* stmt); + + // Dispatched from VisitClassLiteral. + void VisitClassLiteralContents(ClassLiteral* expr); // Builds deoptimization for a given node. void PrepareFrameState( @@ -210,11 +331,9 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor { // // [parameters (+receiver)] [locals] [operand stack] // -class AstGraphBuilder::Environment - : public StructuredGraphBuilder::Environment { +class AstGraphBuilder::Environment : public ZoneObject { public: Environment(AstGraphBuilder* builder, Scope* scope, Node* control_dependency); - Environment(const Environment& copy); int parameters_count() const { return parameters_count_; } int locals_count() const { return locals_count_; } @@ -244,6 +363,10 @@ class AstGraphBuilder::Environment } } + Node* Context() const { return contexts_.back(); } + void PushContext(Node* context) { contexts()->push_back(context); } + void PopContext() { contexts()->pop_back(); } + // Operations on the operand stack. void Push(Node* node) { values()->push_back(node); @@ -279,170 +402,72 @@ class AstGraphBuilder::Environment // further mutation of the environment will not affect checkpoints. Node* Checkpoint(BailoutId ast_id, OutputFrameStateCombine combine); - protected: - AstGraphBuilder* builder() const { - return reinterpret_cast<AstGraphBuilder*>( - StructuredGraphBuilder::Environment::builder()); + // Control dependency tracked by this environment. + Node* GetControlDependency() { return control_dependency_; } + void UpdateControlDependency(Node* dependency) { + control_dependency_ = dependency; } - private: - void UpdateStateValues(Node** state_values, int offset, int count); - - int parameters_count_; - int locals_count_; - Node* parameters_node_; - Node* locals_node_; - Node* stack_node_; -}; - - -// Each expression in the AST is evaluated in a specific context. This context -// decides how the evaluation result is passed up the visitor. -class AstGraphBuilder::AstContext BASE_EMBEDDED { - public: - bool IsEffect() const { return kind_ == Expression::kEffect; } - bool IsValue() const { return kind_ == Expression::kValue; } - bool IsTest() const { return kind_ == Expression::kTest; } - - // Determines how to combine the frame state with the value - // that is about to be plugged into this AstContext. - OutputFrameStateCombine GetStateCombine() { - return IsEffect() ? OutputFrameStateCombine::Ignore() - : OutputFrameStateCombine::Push(); + // Effect dependency tracked by this environment. + Node* GetEffectDependency() { return effect_dependency_; } + void UpdateEffectDependency(Node* dependency) { + effect_dependency_ = dependency; } - // Plug a node into this expression context. Call this function in tail - // position in the Visit functions for expressions. - virtual void ProduceValue(Node* value) = 0; - - // Unplugs a node from this expression context. Call this to retrieve the - // result of another Visit function that already plugged the context. - virtual Node* ConsumeValue() = 0; - - // Shortcut for "context->ProduceValue(context->ConsumeValue())". - void ReplaceValue() { ProduceValue(ConsumeValue()); } - - protected: - AstContext(AstGraphBuilder* owner, Expression::Context kind); - virtual ~AstContext(); - - AstGraphBuilder* owner() const { return owner_; } - Environment* environment() const { return owner_->environment(); } - -// We want to be able to assert, in a context-specific way, that the stack -// height makes sense when the context is filled. -#ifdef DEBUG - int original_height_; -#endif - - private: - Expression::Context kind_; - AstGraphBuilder* owner_; - AstContext* outer_; -}; - - -// Context to evaluate expression for its side effects only. -class AstGraphBuilder::AstEffectContext FINAL : public AstContext { - public: - explicit AstEffectContext(AstGraphBuilder* owner) - : AstContext(owner, Expression::kEffect) {} - ~AstEffectContext() FINAL; - void ProduceValue(Node* value) FINAL; - Node* ConsumeValue() FINAL; -}; - - -// Context to evaluate expression for its value (and side effects). -class AstGraphBuilder::AstValueContext FINAL : public AstContext { - public: - explicit AstValueContext(AstGraphBuilder* owner) - : AstContext(owner, Expression::kValue) {} - ~AstValueContext() FINAL; - void ProduceValue(Node* value) FINAL; - Node* ConsumeValue() FINAL; -}; - - -// Context to evaluate expression for a condition value (and side effects). -class AstGraphBuilder::AstTestContext FINAL : public AstContext { - public: - explicit AstTestContext(AstGraphBuilder* owner) - : AstContext(owner, Expression::kTest) {} - ~AstTestContext() FINAL; - void ProduceValue(Node* value) FINAL; - Node* ConsumeValue() FINAL; -}; - - -// Scoped class tracking breakable statements entered by the visitor. Allows to -// properly 'break' and 'continue' iteration statements as well as to 'break' -// from blocks within switch statements. -class AstGraphBuilder::BreakableScope BASE_EMBEDDED { - public: - BreakableScope(AstGraphBuilder* owner, BreakableStatement* target, - ControlBuilder* control, int drop_extra) - : owner_(owner), - target_(target), - next_(owner->breakable()), - control_(control), - drop_extra_(drop_extra) { - owner_->set_breakable(this); // Push. + // Mark this environment as being unreachable. + void MarkAsUnreachable() { + UpdateControlDependency(builder()->jsgraph()->DeadControl()); } - - ~BreakableScope() { - owner_->set_breakable(next_); // Pop. + bool IsMarkedAsUnreachable() { + return GetControlDependency()->opcode() == IrOpcode::kDead; } - // Either 'break' or 'continue' the target statement. - void BreakTarget(BreakableStatement* target); - void ContinueTarget(BreakableStatement* target); - - private: - AstGraphBuilder* owner_; - BreakableStatement* target_; - BreakableScope* next_; - ControlBuilder* control_; - int drop_extra_; - - // Find the correct scope for the target statement. Note that this also drops - // extra operands from the environment for each scope skipped along the way. - BreakableScope* FindBreakable(BreakableStatement* target); -}; + // Merge another environment into this one. + void Merge(Environment* other); + // Copies this environment at a control-flow split point. + Environment* CopyForConditional() { return Copy(); } -// Scoped class tracking context objects created by the visitor. Represents -// mutations of the context chain within the function body and allows to -// change the current {scope} and {context} during visitation. -class AstGraphBuilder::ContextScope BASE_EMBEDDED { - public: - ContextScope(AstGraphBuilder* owner, Scope* scope, Node* context) - : owner_(owner), - next_(owner->execution_context()), - outer_(owner->current_context()), - scope_(scope) { - owner_->set_execution_context(this); // Push. - owner_->set_current_context(context); + // Copies this environment to a potentially unreachable control-flow point. + Environment* CopyAsUnreachable() { + Environment* env = Copy(); + env->MarkAsUnreachable(); + return env; } - ~ContextScope() { - owner_->set_execution_context(next_); // Pop. - owner_->set_current_context(outer_); + // Copies this environment at a loop header control-flow point. + Environment* CopyForLoop(BitVector* assigned, bool is_osr = false) { + PrepareForLoop(assigned, is_osr); + return Copy(); } - // Current scope during visitation. - Scope* scope() const { return scope_; } + int ContextStackDepth() { return static_cast<int>(contexts_.size()); } private: - AstGraphBuilder* owner_; - ContextScope* next_; - Node* outer_; - Scope* scope_; -}; + AstGraphBuilder* builder_; + int parameters_count_; + int locals_count_; + NodeVector values_; + NodeVector contexts_; + Node* control_dependency_; + Node* effect_dependency_; + Node* parameters_node_; + Node* locals_node_; + Node* stack_node_; -Scope* AstGraphBuilder::current_scope() const { - return execution_context_->scope(); -} + explicit Environment(const Environment* copy); + Environment* Copy() { return new (zone()) Environment(this); } + void UpdateStateValues(Node** state_values, int offset, int count); + Zone* zone() const { return builder_->local_zone(); } + Graph* graph() const { return builder_->graph(); } + AstGraphBuilder* builder() const { return builder_; } + CommonOperatorBuilder* common() { return builder_->common(); } + NodeVector* values() { return &values_; } + NodeVector* contexts() { return &contexts_; } + + // Prepare environment to be used as loop header. + void PrepareForLoop(BitVector* assigned, bool is_osr = false); +}; } // namespace compiler } // namespace internal |