| Index: src/compiler/ast-graph-builder.h
|
| diff --git a/src/compiler/ast-graph-builder.h b/src/compiler/ast-graph-builder.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..4ab792e14bb66995fb02142c96fe973cfa470704
|
| --- /dev/null
|
| +++ b/src/compiler/ast-graph-builder.h
|
| @@ -0,0 +1,417 @@
|
| +// Copyright 2014 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_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 {
|
| +namespace compiler {
|
| +
|
| +class ControlBuilder;
|
| +class LoopBuilder;
|
| +class Graph;
|
| +
|
| +// 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 {
|
| + public:
|
| + AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph,
|
| + SourcePositionTable* source_positions_);
|
| +
|
| + // Creates a graph by visiting the entire AST.
|
| + bool CreateGraph();
|
| +
|
| + protected:
|
| + class AstContext;
|
| + class AstEffectContext;
|
| + class AstValueContext;
|
| + class AstTestContext;
|
| + class BreakableScope;
|
| + class ContextScope;
|
| + class Environment;
|
| +
|
| + Environment* environment() {
|
| + return reinterpret_cast<Environment*>(environment_internal());
|
| + }
|
| +
|
| + AstContext* ast_context() const { return ast_context_; }
|
| + BreakableScope* breakable() const { return breakable_; }
|
| + ContextScope* execution_context() const { return execution_context_; }
|
| +
|
| + void set_ast_context(AstContext* ctx) { ast_context_ = ctx; }
|
| + void set_breakable(BreakableScope* brk) { breakable_ = brk; }
|
| + void set_execution_context(ContextScope* ctx) { execution_context_ = ctx; }
|
| +
|
| + // 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;
|
| + virtual BaseEnvironment* CopyEnvironment(BaseEnvironment* env);
|
| +
|
| + SourcePositionTable* source_positions() { return source_positions_; }
|
| +
|
| + // TODO(mstarzinger): The pipeline only needs to be a friend to access the
|
| + // function context. Remove as soon as the context is a parameter.
|
| + friend class Pipeline;
|
| +
|
| + // Getters for values in the activation record.
|
| + Node* GetFunctionClosure();
|
| + Node* GetFunctionContext();
|
| +
|
| + //
|
| + // The following build methods all generate graph fragments and return one
|
| + // resulting node. The operand stack height remains the same, variables and
|
| + // other dependencies tracked by the environment might be mutated though.
|
| + //
|
| +
|
| + // Builder to create a local function context.
|
| + Node* BuildLocalFunctionContext(Node* context, Node* closure);
|
| +
|
| + // Builder to create an arguments object if it is used.
|
| + Node* BuildArgumentsObject(Variable* arguments);
|
| +
|
| + // Builders for variable load and assignment.
|
| + Node* BuildVariableAssignment(Variable* var, Node* value, Token::Value op);
|
| + Node* BuildVariableDelete(Variable* var);
|
| + Node* BuildVariableLoad(Variable* var, ContextualMode mode = CONTEXTUAL);
|
| +
|
| + // Builders for accessing the function context.
|
| + Node* BuildLoadBuiltinsObject();
|
| + Node* BuildLoadGlobalObject();
|
| + Node* BuildLoadClosure();
|
| +
|
| + // Builders for automatic type conversion.
|
| + Node* BuildToBoolean(Node* value);
|
| +
|
| + // Builders for error reporting at runtime.
|
| + Node* BuildThrowReferenceError(Variable* var);
|
| +
|
| + // Builders for dynamic hole-checks at runtime.
|
| + Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole);
|
| + Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole);
|
| +
|
| + // Builders for binary operations.
|
| + Node* BuildBinaryOp(Node* left, Node* right, Token::Value op);
|
| +
|
| +#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
|
| + // Visiting functions for AST nodes make this an AstVisitor.
|
| + AST_NODE_LIST(DECLARE_VISIT)
|
| +#undef DECLARE_VISIT
|
| +
|
| + // Visiting function for declarations list is overridden.
|
| + virtual void VisitDeclarations(ZoneList<Declaration*>* declarations);
|
| +
|
| + private:
|
| + CompilationInfo* info_;
|
| + AstContext* ast_context_;
|
| + JSGraph* jsgraph_;
|
| + SourcePositionTable* source_positions_;
|
| +
|
| + // List of global declarations for functions and variables.
|
| + ZoneList<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_;
|
| +
|
| + CompilationInfo* info() { return info_; }
|
| + StrictMode strict_mode() { return info()->strict_mode(); }
|
| + JSGraph* jsgraph() { return jsgraph_; }
|
| + JSOperatorBuilder* javascript() { return jsgraph_->javascript(); }
|
| + ZoneList<Handle<Object> >* globals() { return &globals_; }
|
| +
|
| + // Current scope during visitation.
|
| + inline Scope* current_scope() const;
|
| +
|
| + // Process arguments to a call by popping {arity} elements off the operand
|
| + // stack and build a call node using the given call operator.
|
| + Node* ProcessArguments(Operator* op, int arity);
|
| +
|
| + // Visit statements.
|
| + void VisitIfNotNull(Statement* stmt);
|
| +
|
| + // Visit expressions.
|
| + void VisitForTest(Expression* expr);
|
| + void VisitForEffect(Expression* expr);
|
| + void VisitForValue(Expression* expr);
|
| + void VisitForValueOrNull(Expression* expr);
|
| + void VisitForValues(ZoneList<Expression*>* exprs);
|
| +
|
| + // Common for all IterationStatement bodies.
|
| + void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop, int);
|
| +
|
| + // Dispatched from VisitCallRuntime.
|
| + void VisitCallJSRuntime(CallRuntime* expr);
|
| +
|
| + // Dispatched from VisitUnaryOperation.
|
| + void VisitDelete(UnaryOperation* expr);
|
| + void VisitVoid(UnaryOperation* expr);
|
| + void VisitTypeof(UnaryOperation* expr);
|
| + void VisitNot(UnaryOperation* expr);
|
| +
|
| + // Dispatched from VisitBinaryOperation.
|
| + void VisitComma(BinaryOperation* expr);
|
| + void VisitLogicalExpression(BinaryOperation* expr);
|
| + void VisitArithmeticExpression(BinaryOperation* expr);
|
| +
|
| + // Dispatched from VisitForInStatement.
|
| + void VisitForInAssignment(Expression* expr, Node* value);
|
| +
|
| + void BuildLazyBailout(Node* node, BailoutId ast_id);
|
| +
|
| + DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
|
| + DISALLOW_COPY_AND_ASSIGN(AstGraphBuilder);
|
| +};
|
| +
|
| +
|
| +// The abstract execution environment for generated code consists of
|
| +// parameter variables, local variables and the operand stack. The
|
| +// environment will perform proper SSA-renaming of all tracked nodes
|
| +// at split and merge points in the control flow. Internally all the
|
| +// values are stored in one list using the following layout:
|
| +//
|
| +// [parameters (+receiver)] [locals] [operand stack]
|
| +//
|
| +class AstGraphBuilder::Environment
|
| + : public StructuredGraphBuilder::Environment {
|
| + 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_; }
|
| + int stack_height() {
|
| + return values()->size() - parameters_count_ - locals_count_;
|
| + }
|
| +
|
| + // Operations on parameter or local variables. The parameter indices are
|
| + // shifted by 1 (receiver is parameter index -1 but environment index 0).
|
| + void Bind(Variable* variable, Node* node) {
|
| + ASSERT(variable->IsStackAllocated());
|
| + if (variable->IsParameter()) {
|
| + values()->at(variable->index() + 1) = node;
|
| + parameters_dirty_ = true;
|
| + } else {
|
| + ASSERT(variable->IsStackLocal());
|
| + values()->at(variable->index() + parameters_count_) = node;
|
| + locals_dirty_ = true;
|
| + }
|
| + }
|
| + Node* Lookup(Variable* variable) {
|
| + ASSERT(variable->IsStackAllocated());
|
| + if (variable->IsParameter()) {
|
| + return values()->at(variable->index() + 1);
|
| + } else {
|
| + ASSERT(variable->IsStackLocal());
|
| + return values()->at(variable->index() + parameters_count_);
|
| + }
|
| + }
|
| +
|
| + // Operations on the operand stack.
|
| + void Push(Node* node) {
|
| + values()->push_back(node);
|
| + stack_dirty_ = true;
|
| + }
|
| + Node* Top() {
|
| + ASSERT(stack_height() > 0);
|
| + return values()->back();
|
| + }
|
| + Node* Pop() {
|
| + ASSERT(stack_height() > 0);
|
| + Node* back = values()->back();
|
| + values()->pop_back();
|
| + return back;
|
| + }
|
| +
|
| + // Direct mutations of the operand stack.
|
| + void Poke(int depth, Node* node) {
|
| + ASSERT(depth >= 0 && depth < stack_height());
|
| + int index = values()->size() - depth - 1;
|
| + values()->at(index) = node;
|
| + }
|
| + Node* Peek(int depth) {
|
| + ASSERT(depth >= 0 && depth < stack_height());
|
| + int index = values()->size() - depth - 1;
|
| + return values()->at(index);
|
| + }
|
| + void Drop(int depth) {
|
| + ASSERT(depth >= 0 && depth <= stack_height());
|
| + values()->erase(values()->end() - depth, values()->end());
|
| + }
|
| +
|
| + // Preserve a checkpoint of the environment for the IR graph. Any
|
| + // further mutation of the environment will not affect checkpoints.
|
| + Node* Checkpoint(BailoutId ast_id);
|
| +
|
| + private:
|
| + int parameters_count_;
|
| + int locals_count_;
|
| + Node* parameters_node_;
|
| + Node* locals_node_;
|
| + Node* stack_node_;
|
| + bool parameters_dirty_;
|
| + bool locals_dirty_;
|
| + bool stack_dirty_;
|
| +};
|
| +
|
| +
|
| +// 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; }
|
| +
|
| + // 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 V8_FINAL : public AstContext {
|
| + public:
|
| + explicit AstEffectContext(AstGraphBuilder* owner)
|
| + : AstContext(owner, Expression::kEffect) {}
|
| + virtual ~AstEffectContext();
|
| + virtual void ProduceValue(Node* value) V8_OVERRIDE;
|
| + virtual Node* ConsumeValue() V8_OVERRIDE;
|
| +};
|
| +
|
| +
|
| +// Context to evaluate expression for its value (and side effects).
|
| +class AstGraphBuilder::AstValueContext V8_FINAL : public AstContext {
|
| + public:
|
| + explicit AstValueContext(AstGraphBuilder* owner)
|
| + : AstContext(owner, Expression::kValue) {}
|
| + virtual ~AstValueContext();
|
| + virtual void ProduceValue(Node* value) V8_OVERRIDE;
|
| + virtual Node* ConsumeValue() V8_OVERRIDE;
|
| +};
|
| +
|
| +
|
| +// Context to evaluate expression for a condition value (and side effects).
|
| +class AstGraphBuilder::AstTestContext V8_FINAL : public AstContext {
|
| + public:
|
| + explicit AstTestContext(AstGraphBuilder* owner)
|
| + : AstContext(owner, Expression::kTest) {}
|
| + virtual ~AstTestContext();
|
| + virtual void ProduceValue(Node* value) V8_OVERRIDE;
|
| + virtual Node* ConsumeValue() V8_OVERRIDE;
|
| +};
|
| +
|
| +
|
| +// 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.
|
| + }
|
| +
|
| + ~BreakableScope() {
|
| + owner_->set_breakable(next_); // Pop.
|
| + }
|
| +
|
| + // 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);
|
| +};
|
| +
|
| +
|
| +// 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);
|
| + }
|
| +
|
| + ~ContextScope() {
|
| + owner_->set_execution_context(next_); // Pop.
|
| + owner_->set_current_context(outer_);
|
| + }
|
| +
|
| + // Current scope during visitation.
|
| + Scope* scope() const { return scope_; }
|
| +
|
| + private:
|
| + AstGraphBuilder* owner_;
|
| + ContextScope* next_;
|
| + Node* outer_;
|
| + Scope* scope_;
|
| +};
|
| +
|
| +Scope* AstGraphBuilder::current_scope() const {
|
| + return execution_context_->scope();
|
| +}
|
| +}
|
| +}
|
| +} // namespace v8::internal::compiler
|
| +
|
| +#endif // V8_COMPILER_AST_GRAPH_BUILDER_H_
|
|
|