Home | History | Annotate | Download | only in src
      1 // Copyright 2009 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_FULL_CODEGEN_H_
     29 #define V8_FULL_CODEGEN_H_
     30 
     31 #include "v8.h"
     32 
     33 #include "ast.h"
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 class FullCodeGenSyntaxChecker: public AstVisitor {
     39  public:
     40   FullCodeGenSyntaxChecker() : has_supported_syntax_(true) {}
     41 
     42   void Check(FunctionLiteral* fun);
     43 
     44   bool has_supported_syntax() { return has_supported_syntax_; }
     45 
     46  private:
     47   void VisitDeclarations(ZoneList<Declaration*>* decls);
     48   void VisitStatements(ZoneList<Statement*>* stmts);
     49 
     50   // AST node visit functions.
     51 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
     52   AST_NODE_LIST(DECLARE_VISIT)
     53 #undef DECLARE_VISIT
     54 
     55   bool has_supported_syntax_;
     56 
     57   DISALLOW_COPY_AND_ASSIGN(FullCodeGenSyntaxChecker);
     58 };
     59 
     60 
     61 // -----------------------------------------------------------------------------
     62 // Full code generator.
     63 
     64 class FullCodeGenerator: public AstVisitor {
     65  public:
     66   enum Mode {
     67     PRIMARY,
     68     SECONDARY
     69   };
     70 
     71   explicit FullCodeGenerator(MacroAssembler* masm)
     72       : masm_(masm),
     73         info_(NULL),
     74         nesting_stack_(NULL),
     75         loop_depth_(0),
     76         location_(kStack),
     77         true_label_(NULL),
     78         false_label_(NULL) {
     79   }
     80 
     81   static Handle<Code> MakeCode(CompilationInfo* info);
     82 
     83   void Generate(CompilationInfo* info, Mode mode);
     84 
     85  private:
     86   class Breakable;
     87   class Iteration;
     88   class TryCatch;
     89   class TryFinally;
     90   class Finally;
     91   class ForIn;
     92 
     93   class NestedStatement BASE_EMBEDDED {
     94    public:
     95     explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
     96       // Link into codegen's nesting stack.
     97       previous_ = codegen->nesting_stack_;
     98       codegen->nesting_stack_ = this;
     99     }
    100     virtual ~NestedStatement() {
    101       // Unlink from codegen's nesting stack.
    102       ASSERT_EQ(this, codegen_->nesting_stack_);
    103       codegen_->nesting_stack_ = previous_;
    104     }
    105 
    106     virtual Breakable* AsBreakable() { return NULL; }
    107     virtual Iteration* AsIteration() { return NULL; }
    108     virtual TryCatch* AsTryCatch() { return NULL; }
    109     virtual TryFinally* AsTryFinally() { return NULL; }
    110     virtual Finally* AsFinally() { return NULL; }
    111     virtual ForIn* AsForIn() { return NULL; }
    112 
    113     virtual bool IsContinueTarget(Statement* target) { return false; }
    114     virtual bool IsBreakTarget(Statement* target) { return false; }
    115 
    116     // Generate code to leave the nested statement. This includes
    117     // cleaning up any stack elements in use and restoring the
    118     // stack to the expectations of the surrounding statements.
    119     // Takes a number of stack elements currently on top of the
    120     // nested statement's stack, and returns a number of stack
    121     // elements left on top of the surrounding statement's stack.
    122     // The generated code must preserve the result register (which
    123     // contains the value in case of a return).
    124     virtual int Exit(int stack_depth) {
    125       // Default implementation for the case where there is
    126       // nothing to clean up.
    127       return stack_depth;
    128     }
    129     NestedStatement* outer() { return previous_; }
    130    protected:
    131     MacroAssembler* masm() { return codegen_->masm(); }
    132    private:
    133     FullCodeGenerator* codegen_;
    134     NestedStatement* previous_;
    135     DISALLOW_COPY_AND_ASSIGN(NestedStatement);
    136   };
    137 
    138   class Breakable : public NestedStatement {
    139    public:
    140     Breakable(FullCodeGenerator* codegen,
    141               BreakableStatement* break_target)
    142         : NestedStatement(codegen),
    143           target_(break_target) {}
    144     virtual ~Breakable() {}
    145     virtual Breakable* AsBreakable() { return this; }
    146     virtual bool IsBreakTarget(Statement* statement) {
    147       return target_ == statement;
    148     }
    149     BreakableStatement* statement() { return target_; }
    150     Label* break_target() { return &break_target_label_; }
    151    private:
    152     BreakableStatement* target_;
    153     Label break_target_label_;
    154     DISALLOW_COPY_AND_ASSIGN(Breakable);
    155   };
    156 
    157   class Iteration : public Breakable {
    158    public:
    159     Iteration(FullCodeGenerator* codegen,
    160               IterationStatement* iteration_statement)
    161         : Breakable(codegen, iteration_statement) {}
    162     virtual ~Iteration() {}
    163     virtual Iteration* AsIteration() { return this; }
    164     virtual bool IsContinueTarget(Statement* statement) {
    165       return this->statement() == statement;
    166     }
    167     Label* continue_target() { return &continue_target_label_; }
    168    private:
    169     Label continue_target_label_;
    170     DISALLOW_COPY_AND_ASSIGN(Iteration);
    171   };
    172 
    173   // The environment inside the try block of a try/catch statement.
    174   class TryCatch : public NestedStatement {
    175    public:
    176     explicit TryCatch(FullCodeGenerator* codegen, Label* catch_entry)
    177         : NestedStatement(codegen), catch_entry_(catch_entry) { }
    178     virtual ~TryCatch() {}
    179     virtual TryCatch* AsTryCatch() { return this; }
    180     Label* catch_entry() { return catch_entry_; }
    181     virtual int Exit(int stack_depth);
    182    private:
    183     Label* catch_entry_;
    184     DISALLOW_COPY_AND_ASSIGN(TryCatch);
    185   };
    186 
    187   // The environment inside the try block of a try/finally statement.
    188   class TryFinally : public NestedStatement {
    189    public:
    190     explicit TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
    191         : NestedStatement(codegen), finally_entry_(finally_entry) { }
    192     virtual ~TryFinally() {}
    193     virtual TryFinally* AsTryFinally() { return this; }
    194     Label* finally_entry() { return finally_entry_; }
    195     virtual int Exit(int stack_depth);
    196    private:
    197     Label* finally_entry_;
    198     DISALLOW_COPY_AND_ASSIGN(TryFinally);
    199   };
    200 
    201   // A FinallyEnvironment represents being inside a finally block.
    202   // Abnormal termination of the finally block needs to clean up
    203   // the block's parameters from the stack.
    204   class Finally : public NestedStatement {
    205    public:
    206     explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
    207     virtual ~Finally() {}
    208     virtual Finally* AsFinally() { return this; }
    209     virtual int Exit(int stack_depth) {
    210       return stack_depth + kFinallyStackElementCount;
    211     }
    212    private:
    213     // Number of extra stack slots occupied during a finally block.
    214     static const int kFinallyStackElementCount = 2;
    215     DISALLOW_COPY_AND_ASSIGN(Finally);
    216   };
    217 
    218   // A ForInEnvironment represents being inside a for-in loop.
    219   // Abnormal termination of the for-in block needs to clean up
    220   // the block's temporary storage from the stack.
    221   class ForIn : public Iteration {
    222    public:
    223     ForIn(FullCodeGenerator* codegen,
    224           ForInStatement* statement)
    225         : Iteration(codegen, statement) { }
    226     virtual ~ForIn() {}
    227     virtual ForIn* AsForIn() { return this; }
    228     virtual int Exit(int stack_depth) {
    229       return stack_depth + kForInStackElementCount;
    230     }
    231    private:
    232     // TODO(lrn): Check that this value is correct when implementing
    233     // for-in.
    234     static const int kForInStackElementCount = 5;
    235     DISALLOW_COPY_AND_ASSIGN(ForIn);
    236   };
    237 
    238   enum Location {
    239     kAccumulator,
    240     kStack
    241   };
    242 
    243   int SlotOffset(Slot* slot);
    244 
    245   // Emit code to convert a pure value (in a register, slot, as a literal,
    246   // or on top of the stack) into the result expected according to an
    247   // expression context.
    248   void Apply(Expression::Context context, Register reg);
    249 
    250   // Slot cannot have type Slot::LOOKUP.
    251   void Apply(Expression::Context context, Slot* slot);
    252 
    253   void Apply(Expression::Context context, Literal* lit);
    254   void ApplyTOS(Expression::Context context);
    255 
    256   // Emit code to discard count elements from the top of stack, then convert
    257   // a pure value into the result expected according to an expression
    258   // context.
    259   void DropAndApply(int count, Expression::Context context, Register reg);
    260 
    261   // Emit code to convert pure control flow to a pair of labels into the
    262   // result expected according to an expression context.
    263   void Apply(Expression::Context context,
    264              Label* materialize_true,
    265              Label* materialize_false);
    266 
    267   // Helper function to convert a pure value into a test context.  The value
    268   // is expected on the stack or the accumulator, depending on the platform.
    269   // See the platform-specific implementation for details.
    270   void DoTest(Expression::Context context);
    271 
    272   void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
    273   void Move(Register dst, Slot* source);
    274 
    275   // Return an operand used to read/write to a known (ie, non-LOOKUP) slot.
    276   // May emit code to traverse the context chain, destroying the scratch
    277   // register.
    278   MemOperand EmitSlotSearch(Slot* slot, Register scratch);
    279 
    280   void VisitForEffect(Expression* expr) {
    281     Expression::Context saved_context = context_;
    282     context_ = Expression::kEffect;
    283     Visit(expr);
    284     context_ = saved_context;
    285   }
    286 
    287   void VisitForValue(Expression* expr, Location where) {
    288     Expression::Context saved_context = context_;
    289     Location saved_location = location_;
    290     context_ = Expression::kValue;
    291     location_ = where;
    292     Visit(expr);
    293     context_ = saved_context;
    294     location_ = saved_location;
    295   }
    296 
    297   void VisitForControl(Expression* expr, Label* if_true, Label* if_false) {
    298     Expression::Context saved_context = context_;
    299     Label* saved_true = true_label_;
    300     Label* saved_false = false_label_;
    301     context_ = Expression::kTest;
    302     true_label_ = if_true;
    303     false_label_ = if_false;
    304     Visit(expr);
    305     context_ = saved_context;
    306     true_label_ = saved_true;
    307     false_label_ = saved_false;
    308   }
    309 
    310   void VisitForValueControl(Expression* expr,
    311                             Location where,
    312                             Label* if_true,
    313                             Label* if_false) {
    314     Expression::Context saved_context = context_;
    315     Location saved_location = location_;
    316     Label* saved_true = true_label_;
    317     Label* saved_false = false_label_;
    318     context_ = Expression::kValueTest;
    319     location_ = where;
    320     true_label_ = if_true;
    321     false_label_ = if_false;
    322     Visit(expr);
    323     context_ = saved_context;
    324     location_ = saved_location;
    325     true_label_ = saved_true;
    326     false_label_ = saved_false;
    327   }
    328 
    329   void VisitForControlValue(Expression* expr,
    330                             Location where,
    331                             Label* if_true,
    332                             Label* if_false) {
    333     Expression::Context saved_context = context_;
    334     Location saved_location = location_;
    335     Label* saved_true = true_label_;
    336     Label* saved_false = false_label_;
    337     context_ = Expression::kTestValue;
    338     location_ = where;
    339     true_label_ = if_true;
    340     false_label_ = if_false;
    341     Visit(expr);
    342     context_ = saved_context;
    343     location_ = saved_location;
    344     true_label_ = saved_true;
    345     false_label_ = saved_false;
    346   }
    347 
    348   void VisitDeclarations(ZoneList<Declaration*>* declarations);
    349   void DeclareGlobals(Handle<FixedArray> pairs);
    350 
    351   // Platform-specific return sequence
    352   void EmitReturnSequence(int position);
    353 
    354   // Platform-specific code sequences for calls
    355   void EmitCallWithStub(Call* expr);
    356   void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
    357 
    358   // Platform-specific code for loading variables.
    359   void EmitVariableLoad(Variable* expr, Expression::Context context);
    360 
    361   // Platform-specific support for compiling assignments.
    362 
    363   // Load a value from a named property.
    364   // The receiver is left on the stack by the IC.
    365   void EmitNamedPropertyLoad(Property* expr);
    366 
    367   // Load a value from a keyed property.
    368   // The receiver and the key is left on the stack by the IC.
    369   void EmitKeyedPropertyLoad(Property* expr);
    370 
    371   // Apply the compound assignment operator. Expects the left operand on top
    372   // of the stack and the right one in the accumulator.
    373   void EmitBinaryOp(Token::Value op, Expression::Context context);
    374 
    375   // Complete a variable assignment.  The right-hand-side value is expected
    376   // in the accumulator.
    377   void EmitVariableAssignment(Variable* var, Expression::Context context);
    378 
    379   // Complete a named property assignment.  The receiver is expected on top
    380   // of the stack and the right-hand-side value in the accumulator.
    381   void EmitNamedPropertyAssignment(Assignment* expr);
    382 
    383   // Complete a keyed property assignment.  The receiver and key are
    384   // expected on top of the stack and the right-hand-side value in the
    385   // accumulator.
    386   void EmitKeyedPropertyAssignment(Assignment* expr);
    387 
    388   void SetFunctionPosition(FunctionLiteral* fun);
    389   void SetReturnPosition(FunctionLiteral* fun);
    390   void SetStatementPosition(Statement* stmt);
    391   void SetStatementPosition(int pos);
    392   void SetSourcePosition(int pos);
    393 
    394   // Non-local control flow support.
    395   void EnterFinallyBlock();
    396   void ExitFinallyBlock();
    397 
    398   // Loop nesting counter.
    399   int loop_depth() { return loop_depth_; }
    400   void increment_loop_depth() { loop_depth_++; }
    401   void decrement_loop_depth() {
    402     ASSERT(loop_depth_ > 0);
    403     loop_depth_--;
    404   }
    405 
    406   MacroAssembler* masm() { return masm_; }
    407 
    408   Handle<Script> script() { return info_->script(); }
    409   bool is_eval() { return info_->is_eval(); }
    410   FunctionLiteral* function() { return info_->function(); }
    411   Scope* scope() { return info_->scope(); }
    412 
    413   static Register result_register();
    414   static Register context_register();
    415 
    416   // Set fields in the stack frame. Offsets are the frame pointer relative
    417   // offsets defined in, e.g., StandardFrameConstants.
    418   void StoreToFrameField(int frame_offset, Register value);
    419 
    420   // Load a value from the current context. Indices are defined as an enum
    421   // in v8::internal::Context.
    422   void LoadContextField(Register dst, int context_index);
    423 
    424   // AST node visit functions.
    425 #define DECLARE_VISIT(type) virtual void Visit##type(type* node);
    426   AST_NODE_LIST(DECLARE_VISIT)
    427 #undef DECLARE_VISIT
    428   // Handles the shortcutted logical binary operations in VisitBinaryOperation.
    429   void EmitLogicalOperation(BinaryOperation* expr);
    430 
    431   MacroAssembler* masm_;
    432   CompilationInfo* info_;
    433 
    434   Label return_label_;
    435   NestedStatement* nesting_stack_;
    436   int loop_depth_;
    437 
    438   Expression::Context context_;
    439   Location location_;
    440   Label* true_label_;
    441   Label* false_label_;
    442 
    443   friend class NestedStatement;
    444 
    445   DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
    446 };
    447 
    448 
    449 } }  // namespace v8::internal
    450 
    451 #endif  // V8_FULL_CODEGEN_H_
    452