1// Copyright 2012 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 "allocation.h"
34#include "ast.h"
35#include "code-stubs.h"
36#include "codegen.h"
37#include "compiler.h"
38
39namespace v8 {
40namespace internal {
41
42// Forward declarations.
43class JumpPatchSite;
44
45// AST node visitor which can tell whether a given statement will be breakable
46// when the code is compiled by the full compiler in the debugger. This means
47// that there will be an IC (load/store/call) in the code generated for the
48// debugger to piggybag on.
49class BreakableStatementChecker: public AstVisitor {
50 public:
51  BreakableStatementChecker() : is_breakable_(false) {}
52
53  void Check(Statement* stmt);
54  void Check(Expression* stmt);
55
56  bool is_breakable() { return is_breakable_; }
57
58 private:
59  // AST node visit functions.
60#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
61  AST_NODE_LIST(DECLARE_VISIT)
62#undef DECLARE_VISIT
63
64  bool is_breakable_;
65
66  DISALLOW_COPY_AND_ASSIGN(BreakableStatementChecker);
67};
68
69
70// -----------------------------------------------------------------------------
71// Full code generator.
72
73class FullCodeGenerator: public AstVisitor {
74 public:
75  enum State {
76    NO_REGISTERS,
77    TOS_REG
78  };
79
80  FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info)
81      : masm_(masm),
82        info_(info),
83        scope_(info->scope()),
84        nesting_stack_(NULL),
85        loop_depth_(0),
86        global_count_(0),
87        context_(NULL),
88        bailout_entries_(info->HasDeoptimizationSupport()
89                         ? info->function()->ast_node_count() : 0),
90        stack_checks_(2),  // There's always at least one.
91        type_feedback_cells_(info->HasDeoptimizationSupport()
92                             ? info->function()->ast_node_count() : 0),
93        ic_total_count_(0),
94        has_self_optimization_header_(false) { }
95
96  static bool MakeCode(CompilationInfo* info);
97
98  // Returns the platform-specific size in bytes of the self-optimization
99  // header.
100  static int self_optimization_header_size();
101
102  // Encode state and pc-offset as a BitField<type, start, size>.
103  // Only use 30 bits because we encode the result as a smi.
104  class StateField : public BitField<State, 0, 1> { };
105  class PcField    : public BitField<unsigned, 1, 30-1> { };
106
107  static const char* State2String(State state) {
108    switch (state) {
109      case NO_REGISTERS: return "NO_REGISTERS";
110      case TOS_REG: return "TOS_REG";
111    }
112    UNREACHABLE();
113    return NULL;
114  }
115
116 private:
117  class Breakable;
118  class Iteration;
119
120  class TestContext;
121
122  class NestedStatement BASE_EMBEDDED {
123   public:
124    explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
125      // Link into codegen's nesting stack.
126      previous_ = codegen->nesting_stack_;
127      codegen->nesting_stack_ = this;
128    }
129    virtual ~NestedStatement() {
130      // Unlink from codegen's nesting stack.
131      ASSERT_EQ(this, codegen_->nesting_stack_);
132      codegen_->nesting_stack_ = previous_;
133    }
134
135    virtual Breakable* AsBreakable() { return NULL; }
136    virtual Iteration* AsIteration() { return NULL; }
137
138    virtual bool IsContinueTarget(Statement* target) { return false; }
139    virtual bool IsBreakTarget(Statement* target) { return false; }
140
141    // Notify the statement that we are exiting it via break, continue, or
142    // return and give it a chance to generate cleanup code.  Return the
143    // next outer statement in the nesting stack.  We accumulate in
144    // *stack_depth the amount to drop the stack and in *context_length the
145    // number of context chain links to unwind as we traverse the nesting
146    // stack from an exit to its target.
147    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
148      return previous_;
149    }
150
151   protected:
152    MacroAssembler* masm() { return codegen_->masm(); }
153
154    FullCodeGenerator* codegen_;
155    NestedStatement* previous_;
156
157   private:
158    DISALLOW_COPY_AND_ASSIGN(NestedStatement);
159  };
160
161  // A breakable statement such as a block.
162  class Breakable : public NestedStatement {
163   public:
164    Breakable(FullCodeGenerator* codegen, BreakableStatement* statement)
165        : NestedStatement(codegen), statement_(statement) {
166    }
167    virtual ~Breakable() {}
168
169    virtual Breakable* AsBreakable() { return this; }
170    virtual bool IsBreakTarget(Statement* target) {
171      return statement() == target;
172    }
173
174    BreakableStatement* statement() { return statement_; }
175    Label* break_label() { return &break_label_; }
176
177   private:
178    BreakableStatement* statement_;
179    Label break_label_;
180  };
181
182  // An iteration statement such as a while, for, or do loop.
183  class Iteration : public Breakable {
184   public:
185    Iteration(FullCodeGenerator* codegen, IterationStatement* statement)
186        : Breakable(codegen, statement) {
187    }
188    virtual ~Iteration() {}
189
190    virtual Iteration* AsIteration() { return this; }
191    virtual bool IsContinueTarget(Statement* target) {
192      return statement() == target;
193    }
194
195    Label* continue_label() { return &continue_label_; }
196
197   private:
198    Label continue_label_;
199  };
200
201  // A nested block statement.
202  class NestedBlock : public Breakable {
203   public:
204    NestedBlock(FullCodeGenerator* codegen, Block* block)
205        : Breakable(codegen, block) {
206    }
207    virtual ~NestedBlock() {}
208
209    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
210      if (statement()->AsBlock()->block_scope() != NULL) {
211        ++(*context_length);
212      }
213      return previous_;
214    };
215  };
216
217  // The try block of a try/catch statement.
218  class TryCatch : public NestedStatement {
219   public:
220    explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {
221    }
222    virtual ~TryCatch() {}
223
224    virtual NestedStatement* Exit(int* stack_depth, int* context_length);
225  };
226
227  // The try block of a try/finally statement.
228  class TryFinally : public NestedStatement {
229   public:
230    TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
231        : NestedStatement(codegen), finally_entry_(finally_entry) {
232    }
233    virtual ~TryFinally() {}
234
235    virtual NestedStatement* Exit(int* stack_depth, int* context_length);
236
237   private:
238    Label* finally_entry_;
239  };
240
241  // The finally block of a try/finally statement.
242  class Finally : public NestedStatement {
243   public:
244    static const int kElementCount = 2;
245
246    explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
247    virtual ~Finally() {}
248
249    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
250      *stack_depth += kElementCount;
251      return previous_;
252    }
253  };
254
255  // The body of a for/in loop.
256  class ForIn : public Iteration {
257   public:
258    static const int kElementCount = 5;
259
260    ForIn(FullCodeGenerator* codegen, ForInStatement* statement)
261        : Iteration(codegen, statement) {
262    }
263    virtual ~ForIn() {}
264
265    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
266      *stack_depth += kElementCount;
267      return previous_;
268    }
269  };
270
271
272  // The body of a with or catch.
273  class WithOrCatch : public NestedStatement {
274   public:
275    explicit WithOrCatch(FullCodeGenerator* codegen)
276        : NestedStatement(codegen) {
277    }
278    virtual ~WithOrCatch() {}
279
280    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
281      ++(*context_length);
282      return previous_;
283    }
284  };
285
286  // Type of a member function that generates inline code for a native function.
287  typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr);
288
289  static const InlineFunctionGenerator kInlineFunctionGenerators[];
290
291  // A platform-specific utility to overwrite the accumulator register
292  // with a GC-safe value.
293  void ClearAccumulator();
294
295  // Determine whether or not to inline the smi case for the given
296  // operation.
297  bool ShouldInlineSmiCase(Token::Value op);
298
299  // Helper function to convert a pure value into a test context.  The value
300  // is expected on the stack or the accumulator, depending on the platform.
301  // See the platform-specific implementation for details.
302  void DoTest(Expression* condition,
303              Label* if_true,
304              Label* if_false,
305              Label* fall_through);
306  void DoTest(const TestContext* context);
307
308  // Helper function to split control flow and avoid a branch to the
309  // fall-through label if it is set up.
310#ifdef V8_TARGET_ARCH_MIPS
311  void Split(Condition cc,
312             Register lhs,
313             const Operand&  rhs,
314             Label* if_true,
315             Label* if_false,
316             Label* fall_through);
317#else  // All non-mips arch.
318  void Split(Condition cc,
319             Label* if_true,
320             Label* if_false,
321             Label* fall_through);
322#endif  // V8_TARGET_ARCH_MIPS
323
324  // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
325  // a register.  Emits a context chain walk if if necessary (so does
326  // SetVar) so avoid calling both on the same variable.
327  void GetVar(Register destination, Variable* var);
328
329  // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable.  If it's in
330  // the context, the write barrier will be emitted and source, scratch0,
331  // scratch1 will be clobbered.  Emits a context chain walk if if necessary
332  // (so does GetVar) so avoid calling both on the same variable.
333  void SetVar(Variable* var,
334              Register source,
335              Register scratch0,
336              Register scratch1);
337
338  // An operand used to read/write a stack-allocated (PARAMETER or LOCAL)
339  // variable.  Writing does not need the write barrier.
340  MemOperand StackOperand(Variable* var);
341
342  // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT)
343  // variable.  May emit code to traverse the context chain, loading the
344  // found context into the scratch register.  Writing to this operand will
345  // need the write barrier if location is CONTEXT.
346  MemOperand VarOperand(Variable* var, Register scratch);
347
348  void VisitForEffect(Expression* expr) {
349    EffectContext context(this);
350    Visit(expr);
351    PrepareForBailout(expr, NO_REGISTERS);
352  }
353
354  void VisitForAccumulatorValue(Expression* expr) {
355    AccumulatorValueContext context(this);
356    Visit(expr);
357    PrepareForBailout(expr, TOS_REG);
358  }
359
360  void VisitForStackValue(Expression* expr) {
361    StackValueContext context(this);
362    Visit(expr);
363    PrepareForBailout(expr, NO_REGISTERS);
364  }
365
366  void VisitForControl(Expression* expr,
367                       Label* if_true,
368                       Label* if_false,
369                       Label* fall_through) {
370    TestContext context(this, expr, if_true, if_false, fall_through);
371    Visit(expr);
372    // For test contexts, we prepare for bailout before branching, not at
373    // the end of the entire expression.  This happens as part of visiting
374    // the expression.
375  }
376
377  void VisitInDuplicateContext(Expression* expr);
378
379  void VisitDeclarations(ZoneList<Declaration*>* declarations);
380  void DeclareGlobals(Handle<FixedArray> pairs);
381  int DeclareGlobalsFlags();
382
383  // Try to perform a comparison as a fast inlined literal compare if
384  // the operands allow it.  Returns true if the compare operations
385  // has been matched and all code generated; false otherwise.
386  bool TryLiteralCompare(CompareOperation* compare);
387
388  // Platform-specific code for comparing the type of a value with
389  // a given literal string.
390  void EmitLiteralCompareTypeof(Expression* expr,
391                                Expression* sub_expr,
392                                Handle<String> check);
393
394  // Platform-specific code for equality comparison with a nil-like value.
395  void EmitLiteralCompareNil(CompareOperation* expr,
396                             Expression* sub_expr,
397                             NilValue nil);
398
399  // Bailout support.
400  void PrepareForBailout(Expression* node, State state);
401  void PrepareForBailoutForId(unsigned id, State state);
402
403  // Cache cell support.  This associates AST ids with global property cells
404  // that will be cleared during GC and collected by the type-feedback oracle.
405  void RecordTypeFeedbackCell(unsigned id, Handle<JSGlobalPropertyCell> cell);
406
407  // Record a call's return site offset, used to rebuild the frame if the
408  // called function was inlined at the site.
409  void RecordJSReturnSite(Call* call);
410
411  // Prepare for bailout before a test (or compare) and branch.  If
412  // should_normalize, then the following comparison will not handle the
413  // canonical JS true value so we will insert a (dead) test against true at
414  // the actual bailout target from the optimized code. If not
415  // should_normalize, the true and false labels are ignored.
416  void PrepareForBailoutBeforeSplit(Expression* expr,
417                                    bool should_normalize,
418                                    Label* if_true,
419                                    Label* if_false);
420
421  // Platform-specific code for a variable, constant, or function
422  // declaration.  Functions have an initial value.
423  // Increments global_count_ for unallocated variables.
424  void EmitDeclaration(VariableProxy* proxy,
425                       VariableMode mode,
426                       FunctionLiteral* function);
427
428  // Platform-specific code for checking the stack limit at the back edge of
429  // a loop.
430  // This is meant to be called at loop back edges, |back_edge_target| is
431  // the jump target of the back edge and is used to approximate the amount
432  // of code inside the loop.
433  void EmitStackCheck(IterationStatement* stmt, Label* back_edge_target);
434  // Record the OSR AST id corresponding to a stack check in the code.
435  void RecordStackCheck(unsigned osr_ast_id);
436  // Emit a table of stack check ids and pcs into the code stream.  Return
437  // the offset of the start of the table.
438  unsigned EmitStackCheckTable();
439
440  void EmitProfilingCounterDecrement(int delta);
441  void EmitProfilingCounterReset();
442
443  // Platform-specific return sequence
444  void EmitReturnSequence();
445
446  // Platform-specific code sequences for calls
447  void EmitCallWithStub(Call* expr, CallFunctionFlags flags);
448  void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
449  void EmitKeyedCallWithIC(Call* expr, Expression* key);
450
451  // Platform-specific code for inline runtime calls.
452  InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
453
454  void EmitInlineRuntimeCall(CallRuntime* expr);
455
456#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
457  void Emit##name(CallRuntime* expr);
458  INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
459  INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
460#undef EMIT_INLINE_RUNTIME_CALL
461
462  // Platform-specific code for loading variables.
463  void EmitLoadGlobalCheckExtensions(Variable* var,
464                                     TypeofState typeof_state,
465                                     Label* slow);
466  MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
467  void EmitDynamicLookupFastCase(Variable* var,
468                                 TypeofState typeof_state,
469                                 Label* slow,
470                                 Label* done);
471  void EmitVariableLoad(VariableProxy* proxy);
472
473  void EmitAccessor(Expression* expression);
474
475  // Expects the arguments and the function already pushed.
476  void EmitResolvePossiblyDirectEval(int arg_count);
477
478  // Platform-specific support for allocating a new closure based on
479  // the given function info.
480  void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
481
482  // Platform-specific support for compiling assignments.
483
484  // Load a value from a named property.
485  // The receiver is left on the stack by the IC.
486  void EmitNamedPropertyLoad(Property* expr);
487
488  // Load a value from a keyed property.
489  // The receiver and the key is left on the stack by the IC.
490  void EmitKeyedPropertyLoad(Property* expr);
491
492  // Apply the compound assignment operator. Expects the left operand on top
493  // of the stack and the right one in the accumulator.
494  void EmitBinaryOp(BinaryOperation* expr,
495                    Token::Value op,
496                    OverwriteMode mode);
497
498  // Helper functions for generating inlined smi code for certain
499  // binary operations.
500  void EmitInlineSmiBinaryOp(BinaryOperation* expr,
501                             Token::Value op,
502                             OverwriteMode mode,
503                             Expression* left,
504                             Expression* right);
505
506  // Assign to the given expression as if via '='. The right-hand-side value
507  // is expected in the accumulator.
508  void EmitAssignment(Expression* expr);
509
510  // Complete a variable assignment.  The right-hand-side value is expected
511  // in the accumulator.
512  void EmitVariableAssignment(Variable* var,
513                              Token::Value op);
514
515  // Complete a named property assignment.  The receiver is expected on top
516  // of the stack and the right-hand-side value in the accumulator.
517  void EmitNamedPropertyAssignment(Assignment* expr);
518
519  // Complete a keyed property assignment.  The receiver and key are
520  // expected on top of the stack and the right-hand-side value in the
521  // accumulator.
522  void EmitKeyedPropertyAssignment(Assignment* expr);
523
524  void CallIC(Handle<Code> code,
525              RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
526              unsigned ast_id = kNoASTId);
527
528  void SetFunctionPosition(FunctionLiteral* fun);
529  void SetReturnPosition(FunctionLiteral* fun);
530  void SetStatementPosition(Statement* stmt);
531  void SetExpressionPosition(Expression* expr, int pos);
532  void SetStatementPosition(int pos);
533  void SetSourcePosition(int pos);
534
535  // Non-local control flow support.
536  void EnterFinallyBlock();
537  void ExitFinallyBlock();
538
539  // Loop nesting counter.
540  int loop_depth() { return loop_depth_; }
541  void increment_loop_depth() { loop_depth_++; }
542  void decrement_loop_depth() {
543    ASSERT(loop_depth_ > 0);
544    loop_depth_--;
545  }
546
547  MacroAssembler* masm() { return masm_; }
548
549  class ExpressionContext;
550  const ExpressionContext* context() { return context_; }
551  void set_new_context(const ExpressionContext* context) { context_ = context; }
552
553  Handle<Script> script() { return info_->script(); }
554  bool is_eval() { return info_->is_eval(); }
555  bool is_native() { return info_->is_native(); }
556  bool is_classic_mode() {
557    return language_mode() == CLASSIC_MODE;
558  }
559  LanguageMode language_mode() {
560    return function()->language_mode();
561  }
562  FunctionLiteral* function() { return info_->function(); }
563  Scope* scope() { return scope_; }
564
565  static Register result_register();
566  static Register context_register();
567
568  // Set fields in the stack frame. Offsets are the frame pointer relative
569  // offsets defined in, e.g., StandardFrameConstants.
570  void StoreToFrameField(int frame_offset, Register value);
571
572  // Load a value from the current context. Indices are defined as an enum
573  // in v8::internal::Context.
574  void LoadContextField(Register dst, int context_index);
575
576  // Push the function argument for the runtime functions PushWithContext
577  // and PushCatchContext.
578  void PushFunctionArgumentForContextAllocation();
579
580  // AST node visit functions.
581#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
582  AST_NODE_LIST(DECLARE_VISIT)
583#undef DECLARE_VISIT
584
585  void EmitUnaryOperation(UnaryOperation* expr, const char* comment);
586
587  void VisitComma(BinaryOperation* expr);
588  void VisitLogicalExpression(BinaryOperation* expr);
589  void VisitArithmeticExpression(BinaryOperation* expr);
590
591  void VisitForTypeofValue(Expression* expr);
592
593  void Generate();
594  void PopulateDeoptimizationData(Handle<Code> code);
595  void PopulateTypeFeedbackInfo(Handle<Code> code);
596  void PopulateTypeFeedbackCells(Handle<Code> code);
597
598  Handle<FixedArray> handler_table() { return handler_table_; }
599
600  struct BailoutEntry {
601    unsigned id;
602    unsigned pc_and_state;
603  };
604
605  struct TypeFeedbackCellEntry {
606    unsigned ast_id;
607    Handle<JSGlobalPropertyCell> cell;
608  };
609
610
611  class ExpressionContext BASE_EMBEDDED {
612   public:
613    explicit ExpressionContext(FullCodeGenerator* codegen)
614        : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
615      codegen->set_new_context(this);
616    }
617
618    virtual ~ExpressionContext() {
619      codegen_->set_new_context(old_);
620    }
621
622    Isolate* isolate() const { return codegen_->isolate(); }
623
624    // Convert constant control flow (true or false) to the result expected for
625    // this expression context.
626    virtual void Plug(bool flag) const = 0;
627
628    // Emit code to convert a pure value (in a register, known variable
629    // location, as a literal, or on top of the stack) into the result
630    // expected according to this expression context.
631    virtual void Plug(Register reg) const = 0;
632    virtual void Plug(Variable* var) const = 0;
633    virtual void Plug(Handle<Object> lit) const = 0;
634    virtual void Plug(Heap::RootListIndex index) const = 0;
635    virtual void PlugTOS() const = 0;
636
637    // Emit code to convert pure control flow to a pair of unbound labels into
638    // the result expected according to this expression context.  The
639    // implementation will bind both labels unless it's a TestContext, which
640    // won't bind them at this point.
641    virtual void Plug(Label* materialize_true,
642                      Label* materialize_false) const = 0;
643
644    // Emit code to discard count elements from the top of stack, then convert
645    // a pure value into the result expected according to this expression
646    // context.
647    virtual void DropAndPlug(int count, Register reg) const = 0;
648
649    // Set up branch labels for a test expression.  The three Label** parameters
650    // are output parameters.
651    virtual void PrepareTest(Label* materialize_true,
652                             Label* materialize_false,
653                             Label** if_true,
654                             Label** if_false,
655                             Label** fall_through) const = 0;
656
657    // Returns true if we are evaluating only for side effects (i.e. if the
658    // result will be discarded).
659    virtual bool IsEffect() const { return false; }
660
661    // Returns true if we are evaluating for the value (in accu/on stack).
662    virtual bool IsAccumulatorValue() const { return false; }
663    virtual bool IsStackValue() const { return false; }
664
665    // Returns true if we are branching on the value rather than materializing
666    // it.  Only used for asserts.
667    virtual bool IsTest() const { return false; }
668
669   protected:
670    FullCodeGenerator* codegen() const { return codegen_; }
671    MacroAssembler* masm() const { return masm_; }
672    MacroAssembler* masm_;
673
674   private:
675    const ExpressionContext* old_;
676    FullCodeGenerator* codegen_;
677  };
678
679  class AccumulatorValueContext : public ExpressionContext {
680   public:
681    explicit AccumulatorValueContext(FullCodeGenerator* codegen)
682        : ExpressionContext(codegen) { }
683
684    virtual void Plug(bool flag) const;
685    virtual void Plug(Register reg) const;
686    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
687    virtual void Plug(Variable* var) const;
688    virtual void Plug(Handle<Object> lit) const;
689    virtual void Plug(Heap::RootListIndex) const;
690    virtual void PlugTOS() const;
691    virtual void DropAndPlug(int count, Register reg) const;
692    virtual void PrepareTest(Label* materialize_true,
693                             Label* materialize_false,
694                             Label** if_true,
695                             Label** if_false,
696                             Label** fall_through) const;
697    virtual bool IsAccumulatorValue() const { return true; }
698  };
699
700  class StackValueContext : public ExpressionContext {
701   public:
702    explicit StackValueContext(FullCodeGenerator* codegen)
703        : ExpressionContext(codegen) { }
704
705    virtual void Plug(bool flag) const;
706    virtual void Plug(Register reg) const;
707    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
708    virtual void Plug(Variable* var) const;
709    virtual void Plug(Handle<Object> lit) const;
710    virtual void Plug(Heap::RootListIndex) const;
711    virtual void PlugTOS() const;
712    virtual void DropAndPlug(int count, Register reg) const;
713    virtual void PrepareTest(Label* materialize_true,
714                             Label* materialize_false,
715                             Label** if_true,
716                             Label** if_false,
717                             Label** fall_through) const;
718    virtual bool IsStackValue() const { return true; }
719  };
720
721  class TestContext : public ExpressionContext {
722   public:
723    TestContext(FullCodeGenerator* codegen,
724                Expression* condition,
725                Label* true_label,
726                Label* false_label,
727                Label* fall_through)
728        : ExpressionContext(codegen),
729          condition_(condition),
730          true_label_(true_label),
731          false_label_(false_label),
732          fall_through_(fall_through) { }
733
734    static const TestContext* cast(const ExpressionContext* context) {
735      ASSERT(context->IsTest());
736      return reinterpret_cast<const TestContext*>(context);
737    }
738
739    Expression* condition() const { return condition_; }
740    Label* true_label() const { return true_label_; }
741    Label* false_label() const { return false_label_; }
742    Label* fall_through() const { return fall_through_; }
743
744    virtual void Plug(bool flag) const;
745    virtual void Plug(Register reg) const;
746    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
747    virtual void Plug(Variable* var) const;
748    virtual void Plug(Handle<Object> lit) const;
749    virtual void Plug(Heap::RootListIndex) const;
750    virtual void PlugTOS() const;
751    virtual void DropAndPlug(int count, Register reg) const;
752    virtual void PrepareTest(Label* materialize_true,
753                             Label* materialize_false,
754                             Label** if_true,
755                             Label** if_false,
756                             Label** fall_through) const;
757    virtual bool IsTest() const { return true; }
758
759   private:
760    Expression* condition_;
761    Label* true_label_;
762    Label* false_label_;
763    Label* fall_through_;
764  };
765
766  class EffectContext : public ExpressionContext {
767   public:
768    explicit EffectContext(FullCodeGenerator* codegen)
769        : ExpressionContext(codegen) { }
770
771    virtual void Plug(bool flag) const;
772    virtual void Plug(Register reg) const;
773    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
774    virtual void Plug(Variable* var) const;
775    virtual void Plug(Handle<Object> lit) const;
776    virtual void Plug(Heap::RootListIndex) const;
777    virtual void PlugTOS() const;
778    virtual void DropAndPlug(int count, Register reg) const;
779    virtual void PrepareTest(Label* materialize_true,
780                             Label* materialize_false,
781                             Label** if_true,
782                             Label** if_false,
783                             Label** fall_through) const;
784    virtual bool IsEffect() const { return true; }
785  };
786
787  MacroAssembler* masm_;
788  CompilationInfo* info_;
789  Scope* scope_;
790  Label return_label_;
791  NestedStatement* nesting_stack_;
792  int loop_depth_;
793  int global_count_;
794  const ExpressionContext* context_;
795  ZoneList<BailoutEntry> bailout_entries_;
796  ZoneList<BailoutEntry> stack_checks_;
797  ZoneList<TypeFeedbackCellEntry> type_feedback_cells_;
798  int ic_total_count_;
799  bool has_self_optimization_header_;
800  Handle<FixedArray> handler_table_;
801  Handle<JSGlobalPropertyCell> profiling_counter_;
802
803  friend class NestedStatement;
804
805  DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
806};
807
808
809// A map from property names to getter/setter pairs allocated in the zone.
810class AccessorTable: public TemplateHashMap<Literal,
811                                            ObjectLiteral::Accessors,
812                                            ZoneListAllocationPolicy> {
813 public:
814  explicit AccessorTable(Zone* zone) :
815      TemplateHashMap<Literal,
816                      ObjectLiteral::Accessors,
817                      ZoneListAllocationPolicy>(Literal::Match),
818      zone_(zone) { }
819
820  Iterator lookup(Literal* literal) {
821    Iterator it = find(literal, true);
822    if (it->second == NULL) it->second = new(zone_) ObjectLiteral::Accessors();
823    return it;
824  }
825
826 private:
827  Zone* zone_;
828};
829
830
831} }  // namespace v8::internal
832
833#endif  // V8_FULL_CODEGEN_H_
834