| // Copyright 2009 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #ifndef V8_CFG_H_ |
| #define V8_CFG_H_ |
| |
| #include "ast.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class ExitNode; |
| class Location; |
| |
| // Translate a source AST into a control-flow graph (CFG). The CFG contains |
| // single-entry, single-exit blocks of straight-line instructions and |
| // administrative nodes. |
| // |
| // Instructions are described by the following grammar. |
| // |
| // <Instruction> ::= |
| // Move <Location> <Value> |
| // | PropLoad <Location> <Value> <Value> |
| // | BinaryOp <Location> Token::Value <Value> <Value> |
| // | Return Nowhere <Value> |
| // | Position <Int> |
| // |
| // Values are trivial expressions: |
| // |
| // <Value> ::= Constant | <Location> |
| // |
| // Locations are storable values ('lvalues'). They can be slots, |
| // compiler-generated temporaries, or the special location 'Nowhere' |
| // indicating that no value is needed. |
| // |
| // <Location> ::= |
| // SlotLocation Slot::Type <Index> |
| // | TempLocation |
| // | Nowhere |
| |
| |
| // Administrative nodes: There are several types of 'administrative' nodes |
| // that do not contain instructions and do not necessarily have a single |
| // predecessor and a single successor. |
| // |
| // EntryNode: there is a distinguished entry node that has no predecessors |
| // and a single successor. |
| // |
| // ExitNode: there is a distinguished exit node that has arbitrarily many |
| // predecessors and no successor. |
| // |
| // JoinNode: join nodes have multiple predecessors and a single successor. |
| // |
| // BranchNode: branch nodes have a single predecessor and multiple |
| // successors. |
| |
| |
| // A convenient class to keep 'global' values when building a CFG. Since |
| // CFG construction can be invoked recursively, CFG globals are stacked. |
| class CfgGlobals BASE_EMBEDDED { |
| public: |
| explicit CfgGlobals(FunctionLiteral* fun); |
| |
| ~CfgGlobals() { top_ = previous_; } |
| |
| static CfgGlobals* current() { |
| ASSERT(top_ != NULL); |
| return top_; |
| } |
| |
| // The function currently being compiled. |
| FunctionLiteral* fun() { return global_fun_; } |
| |
| // The shared global exit node for all exits from the function. |
| ExitNode* exit() { return global_exit_; } |
| |
| // A singleton. |
| Location* nowhere() { return nowhere_; } |
| |
| #ifdef DEBUG |
| int next_node_number() { return node_counter_++; } |
| int next_temp_number() { return temp_counter_++; } |
| #endif |
| |
| private: |
| static CfgGlobals* top_; |
| FunctionLiteral* global_fun_; |
| ExitNode* global_exit_; |
| Location* nowhere_; |
| |
| #ifdef DEBUG |
| // Used to number nodes and temporaries when printing. |
| int node_counter_; |
| int temp_counter_; |
| #endif |
| |
| CfgGlobals* previous_; |
| }; |
| |
| |
| class SlotLocation; |
| |
| // Values represent trivial source expressions: ones with no side effects |
| // and that do not require code to be generated. |
| class Value : public ZoneObject { |
| public: |
| virtual ~Value() {} |
| |
| // Predicates: |
| |
| virtual bool is_temporary() { return false; } |
| virtual bool is_slot() { return false; } |
| virtual bool is_constant() { return false; } |
| |
| // True if the value is a temporary allocated to the stack in |
| // fast-compilation mode. |
| virtual bool is_on_stack() { return false; } |
| |
| // Support for fast-compilation mode: |
| |
| // Move the value into a register. |
| virtual void Get(MacroAssembler* masm, Register reg) = 0; |
| |
| // Push the value on the stack. |
| virtual void Push(MacroAssembler* masm) = 0; |
| |
| // Move the value into a slot location. |
| virtual void MoveToSlot(MacroAssembler* masm, SlotLocation* loc) = 0; |
| |
| #ifdef DEBUG |
| virtual void Print() = 0; |
| #endif |
| }; |
| |
| |
| // A compile-time constant that appeared as a literal in the source AST. |
| class Constant : public Value { |
| public: |
| explicit Constant(Handle<Object> handle) : handle_(handle) {} |
| |
| // Cast accessor. |
| static Constant* cast(Value* value) { |
| ASSERT(value->is_constant()); |
| return reinterpret_cast<Constant*>(value); |
| } |
| |
| // Accessors. |
| Handle<Object> handle() { return handle_; } |
| |
| // Predicates. |
| bool is_constant() { return true; } |
| |
| // Support for fast-compilation mode. |
| void Get(MacroAssembler* masm, Register reg); |
| void Push(MacroAssembler* masm); |
| void MoveToSlot(MacroAssembler* masm, SlotLocation* loc); |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| |
| private: |
| Handle<Object> handle_; |
| }; |
| |
| |
| // Locations are values that can be stored into ('lvalues'). |
| class Location : public Value { |
| public: |
| virtual ~Location() {} |
| |
| // Static factory function returning the singleton nowhere location. |
| static Location* Nowhere() { |
| return CfgGlobals::current()->nowhere(); |
| } |
| |
| // Support for fast-compilation mode: |
| |
| // Assumes temporaries have been allocated. |
| virtual void Get(MacroAssembler* masm, Register reg) = 0; |
| |
| // Store the value in a register to the location. Assumes temporaries |
| // have been allocated. |
| virtual void Set(MacroAssembler* masm, Register reg) = 0; |
| |
| // Assumes temporaries have been allocated, and if the value is a |
| // temporary it was not allocated to the stack. |
| virtual void Push(MacroAssembler* masm) = 0; |
| |
| // Emit code to move a value into this location. |
| virtual void Move(MacroAssembler* masm, Value* value) = 0; |
| |
| #ifdef DEBUG |
| virtual void Print() = 0; |
| #endif |
| }; |
| |
| |
| // Nowhere is a special (singleton) location that indicates the value of a |
| // computation is not needed (though its side effects are). |
| class Nowhere : public Location { |
| public: |
| // We should not try to emit code to read Nowhere. |
| void Get(MacroAssembler* masm, Register reg) { UNREACHABLE(); } |
| void Push(MacroAssembler* masm) { UNREACHABLE(); } |
| void MoveToSlot(MacroAssembler* masm, SlotLocation* loc) { UNREACHABLE(); } |
| |
| // Setting Nowhere is ignored. |
| void Set(MacroAssembler* masm, Register reg) {} |
| void Move(MacroAssembler* masm, Value* value) {} |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| |
| private: |
| Nowhere() {} |
| |
| friend class CfgGlobals; |
| }; |
| |
| |
| // SlotLocations represent parameters and stack-allocated (i.e., |
| // non-context) local variables. |
| class SlotLocation : public Location { |
| public: |
| SlotLocation(Slot::Type type, int index) : type_(type), index_(index) {} |
| |
| // Cast accessor. |
| static SlotLocation* cast(Value* value) { |
| ASSERT(value->is_slot()); |
| return reinterpret_cast<SlotLocation*>(value); |
| } |
| |
| // Accessors. |
| Slot::Type type() { return type_; } |
| int index() { return index_; } |
| |
| // Predicates. |
| bool is_slot() { return true; } |
| |
| // Support for fast-compilation mode. |
| void Get(MacroAssembler* masm, Register reg); |
| void Set(MacroAssembler* masm, Register reg); |
| void Push(MacroAssembler* masm); |
| void Move(MacroAssembler* masm, Value* value); |
| void MoveToSlot(MacroAssembler* masm, SlotLocation* loc); |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| |
| private: |
| Slot::Type type_; |
| int index_; |
| }; |
| |
| |
| // TempLocations represent compiler generated temporaries. They are |
| // allocated to registers or memory either before code generation (in the |
| // optimized-for-speed compiler) or on the fly during code generation (in |
| // the optimized-for-space compiler). |
| class TempLocation : public Location { |
| public: |
| // Fast-compilation mode allocation decisions. |
| enum Where { |
| NOT_ALLOCATED, // Not yet allocated. |
| ACCUMULATOR, // Allocated to the dedicated accumulator register. |
| STACK // " " " " stack. |
| }; |
| |
| TempLocation() : where_(NOT_ALLOCATED) { |
| #ifdef DEBUG |
| number_ = -1; |
| #endif |
| } |
| |
| // Cast accessor. |
| static TempLocation* cast(Value* value) { |
| ASSERT(value->is_temporary()); |
| return reinterpret_cast<TempLocation*>(value); |
| } |
| |
| // Accessors. |
| Where where() { return where_; } |
| void set_where(Where where) { |
| ASSERT(where_ == TempLocation::NOT_ALLOCATED); |
| where_ = where; |
| } |
| |
| // Predicates. |
| bool is_on_stack() { return where_ == STACK; } |
| bool is_temporary() { return true; } |
| |
| // Support for fast-compilation mode. Assume the temp has been allocated. |
| void Get(MacroAssembler* masm, Register reg); |
| void Set(MacroAssembler* masm, Register reg); |
| void Push(MacroAssembler* masm); |
| void Move(MacroAssembler* masm, Value* value); |
| void MoveToSlot(MacroAssembler* masm, SlotLocation* loc); |
| |
| #ifdef DEBUG |
| int number() { |
| if (number_ == -1) number_ = CfgGlobals::current()->next_temp_number(); |
| return number_; |
| } |
| |
| void Print(); |
| #endif |
| |
| private: |
| Where where_; |
| |
| #ifdef DEBUG |
| int number_; |
| #endif |
| }; |
| |
| |
| // Instructions are computations. The represent non-trivial source |
| // expressions: typically ones that have side effects and require code to |
| // be generated. |
| class Instruction : public ZoneObject { |
| public: |
| // Accessors. |
| Location* location() { return location_; } |
| void set_location(Location* location) { location_ = location; } |
| |
| // Support for fast-compilation mode: |
| |
| // Emit code to perform the instruction. |
| virtual void Compile(MacroAssembler* masm) = 0; |
| |
| // Allocate a temporary which is the result of the immediate predecessor |
| // instruction. It is allocated to the accumulator register if it is used |
| // as an operand to this instruction, otherwise to the stack. |
| virtual void FastAllocate(TempLocation* temp) = 0; |
| |
| #ifdef DEBUG |
| virtual void Print() = 0; |
| #endif |
| |
| protected: |
| // Every instruction has a location where its result is stored (which may |
| // be Nowhere). |
| explicit Instruction(Location* location) : location_(location) {} |
| |
| virtual ~Instruction() {} |
| |
| Location* location_; |
| }; |
| |
| |
| // Base class of instructions that have no input operands. |
| class ZeroOperandInstruction : public Instruction { |
| public: |
| // Support for fast-compilation mode: |
| virtual void Compile(MacroAssembler* masm) = 0; |
| void FastAllocate(TempLocation* temp); |
| |
| #ifdef DEBUG |
| // Printing support: print the operands (nothing). |
| virtual void Print() {} |
| #endif |
| |
| protected: |
| explicit ZeroOperandInstruction(Location* loc) : Instruction(loc) {} |
| }; |
| |
| |
| // Base class of instructions that have a single input operand. |
| class OneOperandInstruction : public Instruction { |
| public: |
| // Support for fast-compilation mode: |
| virtual void Compile(MacroAssembler* masm) = 0; |
| void FastAllocate(TempLocation* temp); |
| |
| #ifdef DEBUG |
| // Printing support: print the operands. |
| virtual void Print(); |
| #endif |
| |
| protected: |
| OneOperandInstruction(Location* loc, Value* value) |
| : Instruction(loc), value_(value) { |
| } |
| |
| Value* value_; |
| }; |
| |
| |
| // Base class of instructions that have two input operands. |
| class TwoOperandInstruction : public Instruction { |
| public: |
| // Support for fast-compilation mode: |
| virtual void Compile(MacroAssembler* masm) = 0; |
| void FastAllocate(TempLocation* temp); |
| |
| #ifdef DEBUG |
| // Printing support: print the operands. |
| virtual void Print(); |
| #endif |
| |
| protected: |
| TwoOperandInstruction(Location* loc, Value* value0, Value* value1) |
| : Instruction(loc), value0_(value0), value1_(value1) { |
| } |
| |
| Value* value0_; |
| Value* value1_; |
| }; |
| |
| |
| // A phantom instruction that indicates the start of a statement. It |
| // causes the statement position to be recorded in the relocation |
| // information but generates no code. |
| class PositionInstr : public ZeroOperandInstruction { |
| public: |
| explicit PositionInstr(int pos) |
| : ZeroOperandInstruction(CfgGlobals::current()->nowhere()), pos_(pos) { |
| } |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| // This should not be called. The last instruction of the previous |
| // statement should not have a temporary as its location. |
| void FastAllocate(TempLocation* temp) { UNREACHABLE(); } |
| |
| #ifdef DEBUG |
| // Printing support. Print nothing. |
| void Print() {} |
| #endif |
| |
| private: |
| int pos_; |
| }; |
| |
| |
| // Move a value to a location. |
| class MoveInstr : public OneOperandInstruction { |
| public: |
| MoveInstr(Location* loc, Value* value) |
| : OneOperandInstruction(loc, value) { |
| } |
| |
| // Accessors. |
| Value* value() { return value_; } |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| #ifdef DEBUG |
| // Printing support. |
| void Print(); |
| #endif |
| }; |
| |
| |
| // Load a property from a receiver, leaving the result in a location. |
| class PropLoadInstr : public TwoOperandInstruction { |
| public: |
| PropLoadInstr(Location* loc, Value* object, Value* key) |
| : TwoOperandInstruction(loc, object, key) { |
| } |
| |
| // Accessors. |
| Value* object() { return value0_; } |
| Value* key() { return value1_; } |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| }; |
| |
| |
| // Perform a (non-short-circuited) binary operation on a pair of values, |
| // leaving the result in a location. |
| class BinaryOpInstr : public TwoOperandInstruction { |
| public: |
| BinaryOpInstr(Location* loc, Token::Value op, Value* left, Value* right) |
| : TwoOperandInstruction(loc, left, right), op_(op) { |
| } |
| |
| // Accessors. |
| Value* left() { return value0_; } |
| Value* right() { return value1_; } |
| Token::Value op() { return op_; } |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| |
| private: |
| Token::Value op_; |
| }; |
| |
| |
| // Return a value. Has the side effect of moving its value into the return |
| // value register. Can only occur as the last instruction in an instruction |
| // block, and implies that the block is closed (cannot have instructions |
| // appended or graph fragments concatenated to the end) and that the block's |
| // successor is the global exit node for the current function. |
| class ReturnInstr : public OneOperandInstruction { |
| public: |
| explicit ReturnInstr(Value* value) |
| : OneOperandInstruction(CfgGlobals::current()->nowhere(), value) { |
| } |
| |
| virtual ~ReturnInstr() {} |
| |
| // Accessors. |
| Value* value() { return value_; } |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| }; |
| |
| |
| // Nodes make up control-flow graphs. |
| class CfgNode : public ZoneObject { |
| public: |
| CfgNode() : is_marked_(false) { |
| #ifdef DEBUG |
| number_ = -1; |
| #endif |
| } |
| |
| virtual ~CfgNode() {} |
| |
| // Because CFGs contain cycles, nodes support marking during traversal |
| // (e.g., for printing or compilation). The traversal functions will mark |
| // unmarked nodes and backtrack if they encounter a marked one. After a |
| // traversal, the graph should be explicitly unmarked by calling Unmark on |
| // the entry node. |
| bool is_marked() { return is_marked_; } |
| virtual void Unmark() = 0; |
| |
| // Predicates: |
| |
| // True if the node is an instruction block. |
| virtual bool is_block() { return false; } |
| |
| // Support for fast-compilation mode. Emit the instructions or control |
| // flow represented by the node. |
| virtual void Compile(MacroAssembler* masm) = 0; |
| |
| #ifdef DEBUG |
| int number() { |
| if (number_ == -1) number_ = CfgGlobals::current()->next_node_number(); |
| return number_; |
| } |
| |
| virtual void Print() = 0; |
| #endif |
| |
| protected: |
| bool is_marked_; |
| |
| #ifdef DEBUG |
| int number_; |
| #endif |
| }; |
| |
| |
| // A block is a single-entry, single-exit block of instructions. |
| class InstructionBlock : public CfgNode { |
| public: |
| InstructionBlock() : successor_(NULL), instructions_(4) {} |
| |
| virtual ~InstructionBlock() {} |
| |
| void Unmark(); |
| |
| // Cast accessor. |
| static InstructionBlock* cast(CfgNode* node) { |
| ASSERT(node->is_block()); |
| return reinterpret_cast<InstructionBlock*>(node); |
| } |
| |
| bool is_block() { return true; } |
| |
| // Accessors. |
| CfgNode* successor() { return successor_; } |
| |
| void set_successor(CfgNode* succ) { |
| ASSERT(successor_ == NULL); |
| successor_ = succ; |
| } |
| |
| ZoneList<Instruction*>* instructions() { return &instructions_; } |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| // Add an instruction to the end of the block. |
| void Append(Instruction* instr) { instructions_.Add(instr); } |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| |
| private: |
| CfgNode* successor_; |
| ZoneList<Instruction*> instructions_; |
| }; |
| |
| |
| // An entry node (one per function). |
| class EntryNode : public CfgNode { |
| public: |
| explicit EntryNode(InstructionBlock* succ) : successor_(succ) {} |
| |
| virtual ~EntryNode() {} |
| |
| void Unmark(); |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| |
| private: |
| InstructionBlock* successor_; |
| }; |
| |
| |
| // An exit node (one per function). |
| class ExitNode : public CfgNode { |
| public: |
| ExitNode() {} |
| |
| virtual ~ExitNode() {} |
| |
| void Unmark(); |
| |
| // Support for fast-compilation mode. |
| void Compile(MacroAssembler* masm); |
| |
| #ifdef DEBUG |
| void Print(); |
| #endif |
| }; |
| |
| |
| // A CFG consists of a linked structure of nodes. Nodes are linked by |
| // pointing to their successors, always beginning with a (single) entry node |
| // (not necessarily of type EntryNode). If it is still possible to add |
| // nodes to the end of the graph (i.e., there is a (single) path that does |
| // not end with the global exit node), then the CFG has an exit node as |
| // well. |
| // |
| // The empty CFG is represented by a NULL entry and a NULL exit. |
| // |
| // We use the term 'open fragment' to mean a CFG whose entry and exits are |
| // both instruction blocks. It is always possible to add instructions and |
| // nodes to the beginning or end of an open fragment. |
| // |
| // We use the term 'closed fragment' to mean a CFG whose entry is an |
| // instruction block and whose exit is NULL (all paths go to the global |
| // exit). |
| // |
| // We use the term 'fragment' to refer to a CFG that is known to be an open |
| // or closed fragment. |
| class Cfg : public ZoneObject { |
| public: |
| // Create an empty CFG fragment. |
| Cfg() : entry_(NULL), exit_(NULL) {} |
| |
| // Build the CFG for a function. The returned CFG begins with an |
| // EntryNode and all paths end with the ExitNode. |
| static Cfg* Build(); |
| |
| // The entry and exit nodes of the CFG (not necessarily EntryNode and |
| // ExitNode). |
| CfgNode* entry() { return entry_; } |
| CfgNode* exit() { return exit_; } |
| |
| // True if the CFG has no nodes. |
| bool is_empty() { return entry_ == NULL; } |
| |
| // True if the CFG has an available exit node (i.e., it can be appended or |
| // concatenated to). |
| bool has_exit() { return exit_ != NULL; } |
| |
| // Add an EntryNode to a CFG fragment. It is no longer a fragment |
| // (instructions can no longer be prepended). |
| void PrependEntryNode(); |
| |
| // Append an instruction to the end of an open fragment. |
| void Append(Instruction* instr); |
| |
| // Appends a return instruction to the end of an open fragment and make |
| // it a closed fragment (the exit's successor becomes global exit node). |
| void AppendReturnInstruction(Value* value); |
| |
| // Glue an other CFG fragment to the end of this (open) fragment. |
| void Concatenate(Cfg* other); |
| |
| // Support for compilation. Compile the entire CFG. |
| Handle<Code> Compile(Handle<Script> script); |
| |
| #ifdef DEBUG |
| // Support for printing. |
| void Print(); |
| #endif |
| |
| private: |
| // Entry and exit nodes. |
| CfgNode* entry_; |
| CfgNode* exit_; |
| }; |
| |
| |
| // An implementation of a set of locations (currently slot locations), most |
| // of the operations are destructive. |
| class LocationSet BASE_EMBEDDED { |
| public: |
| // Construct an empty location set. |
| LocationSet() : parameters_(0), locals_(0) {} |
| |
| // Raw accessors. |
| uintptr_t parameters() { return parameters_; } |
| uintptr_t locals() { return locals_; } |
| |
| // Make this the empty set. |
| void Empty() { |
| parameters_ = locals_ = 0; |
| } |
| |
| // Insert an element. |
| void AddElement(SlotLocation* location) { |
| if (location->type() == Slot::PARAMETER) { |
| // Parameter indexes begin with -1 ('this'). |
| ASSERT(location->index() < kBitsPerPointer - 1); |
| parameters_ |= (1 << (location->index() + 1)); |
| } else { |
| ASSERT(location->type() == Slot::LOCAL); |
| ASSERT(location->index() < kBitsPerPointer); |
| locals_ |= (1 << location->index()); |
| } |
| } |
| |
| // (Destructively) compute the union with another set. |
| void Union(LocationSet* other) { |
| parameters_ |= other->parameters(); |
| locals_ |= other->locals(); |
| } |
| |
| bool Contains(SlotLocation* location) { |
| if (location->type() == Slot::PARAMETER) { |
| ASSERT(location->index() < kBitsPerPointer - 1); |
| return (parameters_ & (1 << (location->index() + 1))); |
| } else { |
| ASSERT(location->type() == Slot::LOCAL); |
| ASSERT(location->index() < kBitsPerPointer); |
| return (locals_ & (1 << location->index())); |
| } |
| } |
| |
| private: |
| uintptr_t parameters_; |
| uintptr_t locals_; |
| }; |
| |
| |
| // An ExpressionCfgBuilder traverses an expression and returns an open CFG |
| // fragment (currently a possibly empty list of instructions represented by |
| // a singleton instruction block) and the expression's value. |
| // |
| // Failure to build the CFG is indicated by a NULL CFG. |
| class ExpressionCfgBuilder : public AstVisitor { |
| public: |
| ExpressionCfgBuilder() : destination_(NULL), value_(NULL), graph_(NULL) {} |
| |
| // Result accessors. |
| Value* value() { return value_; } |
| Cfg* graph() { return graph_; } |
| LocationSet* assigned_vars() { return &assigned_vars_; } |
| |
| // Build the cfg for an expression and remember its value. The |
| // destination is a 'hint' where the value should go which may be ignored. |
| // NULL is used to indicate no preference. |
| // |
| // Concretely, if the expression needs to generate a temporary for its |
| // value, it should use the passed destination or generate one if NULL. |
| void Build(Expression* expr, Location* destination) { |
| value_ = NULL; |
| graph_ = new Cfg(); |
| assigned_vars_.Empty(); |
| destination_ = destination; |
| Visit(expr); |
| } |
| |
| // AST node visitors. |
| #define DECLARE_VISIT(type) void Visit##type(type* node); |
| AST_NODE_LIST(DECLARE_VISIT) |
| #undef DECLARE_VISIT |
| |
| private: |
| // State for the visitor. Input parameter: |
| Location* destination_; |
| |
| // Output parameters: |
| Value* value_; |
| Cfg* graph_; |
| LocationSet assigned_vars_; |
| }; |
| |
| |
| // A StatementCfgBuilder maintains a CFG fragment accumulator. When it |
| // visits a statement, it concatenates the CFG for the statement to the end |
| // of the accumulator. |
| class StatementCfgBuilder : public AstVisitor { |
| public: |
| StatementCfgBuilder() : graph_(new Cfg()) {} |
| |
| Cfg* graph() { return graph_; } |
| |
| void VisitStatements(ZoneList<Statement*>* stmts); |
| |
| // AST node visitors. |
| #define DECLARE_VISIT(type) void Visit##type(type* node); |
| AST_NODE_LIST(DECLARE_VISIT) |
| #undef DECLARE_VISIT |
| |
| private: |
| // State for the visitor. Input/output parameter: |
| Cfg* graph_; |
| }; |
| |
| |
| } } // namespace v8::internal |
| |
| #endif // V8_CFG_H_ |