full-codegen.h 32.2 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_FULL_CODEGEN_H_
#define V8_FULL_CODEGEN_H_
7 8 9

#include "v8.h"

10
#include "allocation.h"
11
#include "assert-scope.h"
12
#include "ast.h"
13 14
#include "code-stubs.h"
#include "codegen.h"
15
#include "compiler.h"
16
#include "data-flow.h"
17 18
#include "globals.h"
#include "objects.h"
19 20 21 22

namespace v8 {
namespace internal {

23 24 25
// Forward declarations.
class JumpPatchSite;

26 27 28 29 30 31
// AST node visitor which can tell whether a given statement will be breakable
// when the code is compiled by the full compiler in the debugger. This means
// that there will be an IC (load/store/call) in the code generated for the
// debugger to piggybag on.
class BreakableStatementChecker: public AstVisitor {
 public:
32 33
  explicit BreakableStatementChecker(Zone* zone) : is_breakable_(false) {
    InitializeAstVisitor(zone);
34
  }
35 36 37 38 39 40 41 42 43 44 45 46 47 48

  void Check(Statement* stmt);
  void Check(Expression* stmt);

  bool is_breakable() { return is_breakable_; }

 private:
  // AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
  AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT

  bool is_breakable_;

49
  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
50 51 52 53
  DISALLOW_COPY_AND_ASSIGN(BreakableStatementChecker);
};


54
// -----------------------------------------------------------------------------
55
// Full code generator.
56

57
class FullCodeGenerator: public AstVisitor {
58
 public:
59 60 61 62 63
  enum State {
    NO_REGISTERS,
    TOS_REG
  };

64
  FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info)
65
      : masm_(masm),
66 67
        info_(info),
        scope_(info->scope()),
68
        nesting_stack_(NULL),
69
        loop_depth_(0),
70
        globals_(NULL),
71
        context_(NULL),
72
        bailout_entries_(info->HasDeoptimizationSupport()
73 74
                         ? info->function()->ast_node_count() : 0,
                         info->zone()),
75
        back_edges_(2, info->zone()),
76
        ic_total_count_(0) {
77 78 79 80
    Initialize();
  }

  void Initialize();
81

82
  static bool MakeCode(CompilationInfo* info);
83

84 85 86 87
  // Encode state and pc-offset as a BitField<type, start, size>.
  // Only use 30 bits because we encode the result as a smi.
  class StateField : public BitField<State, 0, 1> { };
  class PcField    : public BitField<unsigned, 1, 30-1> { };
88 89 90 91 92 93 94 95 96

  static const char* State2String(State state) {
    switch (state) {
      case NO_REGISTERS: return "NO_REGISTERS";
      case TOS_REG: return "TOS_REG";
    }
    UNREACHABLE();
    return NULL;
  }
97

98 99
  static const int kMaxBackEdgeWeight = 127;

100
  // Platform-specific code size multiplier.
101
#if V8_TARGET_ARCH_IA32
102
  static const int kCodeSizeMultiplier = 105;
103
  static const int kBootCodeSizeMultiplier = 100;
104
#elif V8_TARGET_ARCH_X64
105
  static const int kCodeSizeMultiplier = 170;
106
  static const int kBootCodeSizeMultiplier = 140;
107
#elif V8_TARGET_ARCH_ARM
108
  static const int kCodeSizeMultiplier = 149;
109
  static const int kBootCodeSizeMultiplier = 110;
110 111
#elif V8_TARGET_ARCH_ARM64
// TODO(all): Copied ARM value. Check this is sensible for ARM64.
112
  static const int kCodeSizeMultiplier = 149;
113
  static const int kBootCodeSizeMultiplier = 110;
114
#elif V8_TARGET_ARCH_MIPS
115
  static const int kCodeSizeMultiplier = 149;
116
  static const int kBootCodeSizeMultiplier = 120;
117 118 119 120
#else
#error Unsupported target architecture.
#endif

121
 private:
122 123
  class Breakable;
  class Iteration;
124

125
  class TestContext;
126 127 128

  class NestedStatement BASE_EMBEDDED {
   public:
129
    explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
      // Link into codegen's nesting stack.
      previous_ = codegen->nesting_stack_;
      codegen->nesting_stack_ = this;
    }
    virtual ~NestedStatement() {
      // Unlink from codegen's nesting stack.
      ASSERT_EQ(this, codegen_->nesting_stack_);
      codegen_->nesting_stack_ = previous_;
    }

    virtual Breakable* AsBreakable() { return NULL; }
    virtual Iteration* AsIteration() { return NULL; }

    virtual bool IsContinueTarget(Statement* target) { return false; }
    virtual bool IsBreakTarget(Statement* target) { return false; }

146 147 148 149 150 151 152 153
    // Notify the statement that we are exiting it via break, continue, or
    // return and give it a chance to generate cleanup code.  Return the
    // next outer statement in the nesting stack.  We accumulate in
    // *stack_depth the amount to drop the stack and in *context_length the
    // number of context chain links to unwind as we traverse the nesting
    // stack from an exit to its target.
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
      return previous_;
154
    }
155

156
   protected:
157
    MacroAssembler* masm() { return codegen_->masm(); }
158

159
    FullCodeGenerator* codegen_;
160
    NestedStatement* previous_;
161 162

   private:
163 164 165
    DISALLOW_COPY_AND_ASSIGN(NestedStatement);
  };

166
  // A breakable statement such as a block.
167 168
  class Breakable : public NestedStatement {
   public:
169 170 171
    Breakable(FullCodeGenerator* codegen, BreakableStatement* statement)
        : NestedStatement(codegen), statement_(statement) {
    }
172
    virtual ~Breakable() {}
173

174
    virtual Breakable* AsBreakable() { return this; }
175 176
    virtual bool IsBreakTarget(Statement* target) {
      return statement() == target;
177
    }
178 179 180 181

    BreakableStatement* statement() { return statement_; }
    Label* break_label() { return &break_label_; }

182
   private:
183 184
    BreakableStatement* statement_;
    Label break_label_;
185 186
  };

187
  // An iteration statement such as a while, for, or do loop.
188 189
  class Iteration : public Breakable {
   public:
190 191 192
    Iteration(FullCodeGenerator* codegen, IterationStatement* statement)
        : Breakable(codegen, statement) {
    }
193
    virtual ~Iteration() {}
194

195
    virtual Iteration* AsIteration() { return this; }
196 197
    virtual bool IsContinueTarget(Statement* target) {
      return statement() == target;
198
    }
199 200 201

    Label* continue_label() { return &continue_label_; }

202
   private:
203
    Label continue_label_;
204 205
  };

206 207 208 209 210 211 212 213 214
  // A nested block statement.
  class NestedBlock : public Breakable {
   public:
    NestedBlock(FullCodeGenerator* codegen, Block* block)
        : Breakable(codegen, block) {
    }
    virtual ~NestedBlock() {}

    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
215
      if (statement()->AsBlock()->scope() != NULL) {
216 217 218
        ++(*context_length);
      }
      return previous_;
219
    }
220 221
  };

222
  // The try block of a try/catch statement.
223 224
  class TryCatch : public NestedStatement {
   public:
225 226
    explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {
    }
227
    virtual ~TryCatch() {}
228

229
    virtual NestedStatement* Exit(int* stack_depth, int* context_length);
230 231
  };

232
  // The try block of a try/finally statement.
233 234
  class TryFinally : public NestedStatement {
   public:
235 236 237
    TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
        : NestedStatement(codegen), finally_entry_(finally_entry) {
    }
238
    virtual ~TryFinally() {}
239

240
    virtual NestedStatement* Exit(int* stack_depth, int* context_length);
241

242 243 244 245
   private:
    Label* finally_entry_;
  };

246
  // The finally block of a try/finally statement.
247 248
  class Finally : public NestedStatement {
   public:
249
    static const int kElementCount = 5;
250

251
    explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
252
    virtual ~Finally() {}
253

254
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
255
      *stack_depth += kElementCount;
256
      return previous_;
257 258 259
    }
  };

260
  // The body of a for/in loop.
261 262
  class ForIn : public Iteration {
   public:
263 264 265 266 267
    static const int kElementCount = 5;

    ForIn(FullCodeGenerator* codegen, ForInStatement* statement)
        : Iteration(codegen, statement) {
    }
268
    virtual ~ForIn() {}
269

270
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
271
      *stack_depth += kElementCount;
272
      return previous_;
273 274 275
    }
  };

276

277
  // The body of a with or catch.
278 279 280 281 282 283 284 285 286 287 288 289 290
  class WithOrCatch : public NestedStatement {
   public:
    explicit WithOrCatch(FullCodeGenerator* codegen)
        : NestedStatement(codegen) {
    }
    virtual ~WithOrCatch() {}

    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
      ++(*context_length);
      return previous_;
    }
  };

291
  // Type of a member function that generates inline code for a native function.
292
  typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr);
293 294 295

  static const InlineFunctionGenerator kInlineFunctionGenerators[];

kmillikin@chromium.org's avatar
kmillikin@chromium.org committed
296 297 298 299
  // A platform-specific utility to overwrite the accumulator register
  // with a GC-safe value.
  void ClearAccumulator();

300 301 302 303
  // Determine whether or not to inline the smi case for the given
  // operation.
  bool ShouldInlineSmiCase(Token::Value op);

304 305 306
  // Helper function to convert a pure value into a test context.  The value
  // is expected on the stack or the accumulator, depending on the platform.
  // See the platform-specific implementation for details.
307 308 309 310 311
  void DoTest(Expression* condition,
              Label* if_true,
              Label* if_false,
              Label* fall_through);
  void DoTest(const TestContext* context);
312 313 314

  // Helper function to split control flow and avoid a branch to the
  // fall-through label if it is set up.
315
#if V8_TARGET_ARCH_MIPS
316
  void Split(Condition cc,
317 318
             Register lhs,
             const Operand&  rhs,
319 320 321
             Label* if_true,
             Label* if_false,
             Label* fall_through);
322 323 324 325 326 327
#else  // All non-mips arch.
  void Split(Condition cc,
             Label* if_true,
             Label* if_false,
             Label* fall_through);
#endif  // V8_TARGET_ARCH_MIPS
328

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
  // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
  // a register.  Emits a context chain walk if if necessary (so does
  // SetVar) so avoid calling both on the same variable.
  void GetVar(Register destination, Variable* var);

  // Assign to a known (PARAMETER, LOCAL, or CONTEXT) variable.  If it's in
  // the context, the write barrier will be emitted and source, scratch0,
  // scratch1 will be clobbered.  Emits a context chain walk if if necessary
  // (so does GetVar) so avoid calling both on the same variable.
  void SetVar(Variable* var,
              Register source,
              Register scratch0,
              Register scratch1);

  // An operand used to read/write a stack-allocated (PARAMETER or LOCAL)
  // variable.  Writing does not need the write barrier.
  MemOperand StackOperand(Variable* var);

  // An operand used to read/write a known (PARAMETER, LOCAL, or CONTEXT)
  // variable.  May emit code to traverse the context chain, loading the
  // found context into the scratch register.  Writing to this operand will
  // need the write barrier if location is CONTEXT.
  MemOperand VarOperand(Variable* var, Register scratch);
352

353
  void VisitForEffect(Expression* expr) {
354
    EffectContext context(this);
355 356
    Visit(expr);
    PrepareForBailout(expr, NO_REGISTERS);
357 358 359 360
  }

  void VisitForAccumulatorValue(Expression* expr) {
    AccumulatorValueContext context(this);
361 362
    Visit(expr);
    PrepareForBailout(expr, TOS_REG);
363 364
  }

365 366
  void VisitForStackValue(Expression* expr) {
    StackValueContext context(this);
367 368
    Visit(expr);
    PrepareForBailout(expr, NO_REGISTERS);
369
  }
370

371 372 373 374
  void VisitForControl(Expression* expr,
                       Label* if_true,
                       Label* if_false,
                       Label* fall_through) {
375
    TestContext context(this, expr, if_true, if_false, fall_through);
376 377 378 379
    Visit(expr);
    // For test contexts, we prepare for bailout before branching, not at
    // the end of the entire expression.  This happens as part of visiting
    // the expression.
380 381
  }

382 383
  void VisitInDuplicateContext(Expression* expr);

384
  void VisitDeclarations(ZoneList<Declaration*>* declarations);
385
  void DeclareModules(Handle<FixedArray> descriptions);
386
  void DeclareGlobals(Handle<FixedArray> pairs);
387
  int DeclareGlobalsFlags();
388

389 390 391 392 393
  // Generate code to allocate all (including nested) modules and contexts.
  // Because of recursive linking and the presence of module alias declarations,
  // this has to be a separate pass _before_ populating or executing any module.
  void AllocateModules(ZoneList<Declaration*>* declarations);

394 395 396 397
  // Generate code to create an iterator result object.  The "value" property is
  // set to a value popped from the stack, and "done" is set according to the
  // argument.  The result object is left in the result register.
  void EmitCreateIteratorResult(bool done);
398

399 400 401
  // Try to perform a comparison as a fast inlined literal compare if
  // the operands allow it.  Returns true if the compare operations
  // has been matched and all code generated; false otherwise.
402
  bool TryLiteralCompare(CompareOperation* compare);
403

404 405
  // Platform-specific code for comparing the type of a value with
  // a given literal string.
406 407 408
  void EmitLiteralCompareTypeof(Expression* expr,
                                Expression* sub_expr,
                                Handle<String> check);
409 410 411 412 413 414

  // Platform-specific code for equality comparison with a nil-like value.
  void EmitLiteralCompareNil(CompareOperation* expr,
                             Expression* sub_expr,
                             NilValue nil);

415
  // Bailout support.
416
  void PrepareForBailout(Expression* node, State state);
417
  void PrepareForBailoutForId(BailoutId id, State state);
418

419 420 421
  // Feedback slot support. The feedback vector will be cleared during gc and
  // collected by the type-feedback oracle.
  Handle<FixedArray> FeedbackVector() {
422
    return info_->feedback_vector();
423
  }
424
  void EnsureSlotContainsAllocationSite(int slot);
425

426 427 428 429 430 431 432 433 434
  // Record a call's return site offset, used to rebuild the frame if the
  // called function was inlined at the site.
  void RecordJSReturnSite(Call* call);

  // Prepare for bailout before a test (or compare) and branch.  If
  // should_normalize, then the following comparison will not handle the
  // canonical JS true value so we will insert a (dead) test against true at
  // the actual bailout target from the optimized code. If not
  // should_normalize, the true and false labels are ignored.
435
  void PrepareForBailoutBeforeSplit(Expression* expr,
436 437 438 439
                                    bool should_normalize,
                                    Label* if_true,
                                    Label* if_false);

440 441 442
  // If enabled, emit debug code for checking that the current context is
  // neither a with nor a catch context.
  void EmitDebugCheckDeclarationContext(Variable* variable);
443

444 445 446
  // This is meant to be called at loop back edges, |back_edge_target| is
  // the jump target of the back edge and is used to approximate the amount
  // of code inside the loop.
447 448 449 450
  void EmitBackEdgeBookkeeping(IterationStatement* stmt,
                               Label* back_edge_target);
  // Record the OSR AST id corresponding to a back edge in the code.
  void RecordBackEdge(BailoutId osr_ast_id);
451 452 453
  // Emit a table of back edge ids, pcs and loop depths into the code stream.
  // Return the offset of the start of the table.
  unsigned EmitBackEdgeTable();
454

455 456 457
  void EmitProfilingCounterDecrement(int delta);
  void EmitProfilingCounterReset();

458 459 460 461 462
  // Emit code to pop values from the stack associated with nested statements
  // like try/catch, try/finally, etc, running the finallies and unwinding the
  // handlers as needed.
  void EmitUnwindBeforeReturn();

463
  // Platform-specific return sequence
464
  void EmitReturnSequence();
465 466

  // Platform-specific code sequences for calls
467 468 469
  void EmitCall(Call* expr, CallIC::CallType = CallIC::FUNCTION);
  void EmitCallWithLoadIC(Call* expr);
  void EmitKeyedCallWithLoadIC(Call* expr, Expression* key);
470

471
  // Platform-specific code for inline runtime calls.
472 473
  InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);

474
  void EmitInlineRuntimeCall(CallRuntime* expr);
475 476

#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
477
  void Emit##name(CallRuntime* expr);
478
  INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
479
#undef EMIT_INLINE_RUNTIME_CALL
480

481 482 483 484 485
  // Platform-specific code for resuming generators.
  void EmitGeneratorResume(Expression *generator,
                           Expression *value,
                           JSGeneratorObject::ResumeMode resume_mode);

486
  // Platform-specific code for loading variables.
487 488 489 490 491 492 493 494
  void EmitLoadGlobalCheckExtensions(Variable* var,
                                     TypeofState typeof_state,
                                     Label* slow);
  MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
  void EmitDynamicLookupFastCase(Variable* var,
                                 TypeofState typeof_state,
                                 Label* slow,
                                 Label* done);
495
  void EmitVariableLoad(VariableProxy* proxy);
496

497 498
  void EmitAccessor(Expression* expression);

499
  // Expects the arguments and the function already pushed.
500
  void EmitResolvePossiblyDirectEval(int arg_count);
501

502 503
  // Platform-specific support for allocating a new closure based on
  // the given function info.
504
  void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
505

506 507
  // Platform-specific support for compiling assignments.

508
  // Load a value from a named property.
509
  // The receiver is left on the stack by the IC.
510
  void EmitNamedPropertyLoad(Property* expr);
511

512
  // Load a value from a keyed property.
513
  // The receiver and the key is left on the stack by the IC.
514
  void EmitKeyedPropertyLoad(Property* expr);
515

516 517
  // Apply the compound assignment operator. Expects the left operand on top
  // of the stack and the right one in the accumulator.
518 519
  void EmitBinaryOp(BinaryOperation* expr,
                    Token::Value op,
520
                    OverwriteMode mode);
521

522 523
  // Helper functions for generating inlined smi code for certain
  // binary operations.
524
  void EmitInlineSmiBinaryOp(BinaryOperation* expr,
525 526 527
                             Token::Value op,
                             OverwriteMode mode,
                             Expression* left,
528
                             Expression* right);
529

530 531
  // Assign to the given expression as if via '='. The right-hand-side value
  // is expected in the accumulator.
532
  void EmitAssignment(Expression* expr);
533

534
  // Complete a variable assignment.  The right-hand-side value is expected
535
  // in the accumulator.
536
  void EmitVariableAssignment(Variable* var,
537
                              Token::Value op);
538

539 540 541
  // Helper functions to EmitVariableAssignment
  void EmitStoreToStackLocalOrContextSlot(Variable* var,
                                          MemOperand location);
542
  void EmitCallStoreContextSlot(Handle<String> name, StrictMode strict_mode);
543

544 545
  // Complete a named property assignment.  The receiver is expected on top
  // of the stack and the right-hand-side value in the accumulator.
546
  void EmitNamedPropertyAssignment(Assignment* expr);
547

548 549 550
  // Complete a keyed property assignment.  The receiver and key are
  // expected on top of the stack and the right-hand-side value in the
  // accumulator.
551
  void EmitKeyedPropertyAssignment(Assignment* expr);
552

553
  void CallIC(Handle<Code> code,
554
              TypeFeedbackId id = TypeFeedbackId::None());
555

556 557
  void CallLoadIC(ContextualMode mode,
                  TypeFeedbackId id = TypeFeedbackId::None());
558
  void CallStoreIC(TypeFeedbackId id = TypeFeedbackId::None());
559

560 561 562
  void SetFunctionPosition(FunctionLiteral* fun);
  void SetReturnPosition(FunctionLiteral* fun);
  void SetStatementPosition(Statement* stmt);
563
  void SetExpressionPosition(Expression* expr);
564
  void SetStatementPosition(int pos);
565
  void SetSourcePosition(int pos);
566

567 568 569 570 571
  // Non-local control flow support.
  void EnterFinallyBlock();
  void ExitFinallyBlock();

  // Loop nesting counter.
572 573 574 575 576 577 578
  int loop_depth() { return loop_depth_; }
  void increment_loop_depth() { loop_depth_++; }
  void decrement_loop_depth() {
    ASSERT(loop_depth_ > 0);
    loop_depth_--;
  }

579
  MacroAssembler* masm() { return masm_; }
580

581 582 583 584
  class ExpressionContext;
  const ExpressionContext* context() { return context_; }
  void set_new_context(const ExpressionContext* context) { context_ = context; }

585 586
  Handle<Script> script() { return info_->script(); }
  bool is_eval() { return info_->is_eval(); }
587
  bool is_native() { return info_->is_native(); }
588
  StrictMode strict_mode() { return function()->strict_mode(); }
589
  FunctionLiteral* function() { return info_->function(); }
590
  Scope* scope() { return scope_; }
591

592
  static Register result_register();
593 594 595 596 597 598 599 600 601
  static Register context_register();

  // Set fields in the stack frame. Offsets are the frame pointer relative
  // offsets defined in, e.g., StandardFrameConstants.
  void StoreToFrameField(int frame_offset, Register value);

  // Load a value from the current context. Indices are defined as an enum
  // in v8::internal::Context.
  void LoadContextField(Register dst, int context_index);
602

603 604 605 606
  // Push the function argument for the runtime functions PushWithContext
  // and PushCatchContext.
  void PushFunctionArgumentForContextAllocation();

607 608 609 610
  // AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
  AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
611

612 613 614
  void VisitComma(BinaryOperation* expr);
  void VisitLogicalExpression(BinaryOperation* expr);
  void VisitArithmeticExpression(BinaryOperation* expr);
615

616
  void VisitForTypeofValue(Expression* expr);
617

618 619 620 621 622 623
  void Generate();
  void PopulateDeoptimizationData(Handle<Code> code);
  void PopulateTypeFeedbackInfo(Handle<Code> code);

  Handle<FixedArray> handler_table() { return handler_table_; }

624
  struct BailoutEntry {
625
    BailoutId id;
626 627
    unsigned pc_and_state;
  };
628

629 630 631
  struct BackEdgeEntry {
    BailoutId id;
    unsigned pc;
632
    uint32_t loop_depth;
633 634
  };

635
  class ExpressionContext BASE_EMBEDDED {
636 637 638 639 640 641 642 643 644 645
   public:
    explicit ExpressionContext(FullCodeGenerator* codegen)
        : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
      codegen->set_new_context(this);
    }

    virtual ~ExpressionContext() {
      codegen_->set_new_context(old_);
    }

646 647
    Isolate* isolate() const { return codegen_->isolate(); }

648 649 650 651
    // Convert constant control flow (true or false) to the result expected for
    // this expression context.
    virtual void Plug(bool flag) const = 0;

652 653 654
    // Emit code to convert a pure value (in a register, known variable
    // location, as a literal, or on top of the stack) into the result
    // expected according to this expression context.
655
    virtual void Plug(Register reg) const = 0;
656
    virtual void Plug(Variable* var) const = 0;
657 658 659 660 661 662
    virtual void Plug(Handle<Object> lit) const = 0;
    virtual void Plug(Heap::RootListIndex index) const = 0;
    virtual void PlugTOS() const = 0;

    // Emit code to convert pure control flow to a pair of unbound labels into
    // the result expected according to this expression context.  The
663 664
    // implementation will bind both labels unless it's a TestContext, which
    // won't bind them at this point.
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
    virtual void Plug(Label* materialize_true,
                      Label* materialize_false) const = 0;

    // Emit code to discard count elements from the top of stack, then convert
    // a pure value into the result expected according to this expression
    // context.
    virtual void DropAndPlug(int count, Register reg) const = 0;

    // Set up branch labels for a test expression.  The three Label** parameters
    // are output parameters.
    virtual void PrepareTest(Label* materialize_true,
                             Label* materialize_false,
                             Label** if_true,
                             Label** if_false,
                             Label** fall_through) const = 0;

681 682
    // Returns true if we are evaluating only for side effects (i.e. if the
    // result will be discarded).
683 684
    virtual bool IsEffect() const { return false; }

685 686 687 688
    // Returns true if we are evaluating for the value (in accu/on stack).
    virtual bool IsAccumulatorValue() const { return false; }
    virtual bool IsStackValue() const { return false; }

689
    // Returns true if we are branching on the value rather than materializing
690
    // it.  Only used for asserts.
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
    virtual bool IsTest() const { return false; }

   protected:
    FullCodeGenerator* codegen() const { return codegen_; }
    MacroAssembler* masm() const { return masm_; }
    MacroAssembler* masm_;

   private:
    const ExpressionContext* old_;
    FullCodeGenerator* codegen_;
  };

  class AccumulatorValueContext : public ExpressionContext {
   public:
    explicit AccumulatorValueContext(FullCodeGenerator* codegen)
706
        : ExpressionContext(codegen) { }
707 708 709 710

    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
711
    virtual void Plug(Variable* var) const;
712 713 714 715 716 717 718 719 720
    virtual void Plug(Handle<Object> lit) const;
    virtual void Plug(Heap::RootListIndex) const;
    virtual void PlugTOS() const;
    virtual void DropAndPlug(int count, Register reg) const;
    virtual void PrepareTest(Label* materialize_true,
                             Label* materialize_false,
                             Label** if_true,
                             Label** if_false,
                             Label** fall_through) const;
721
    virtual bool IsAccumulatorValue() const { return true; }
722 723 724 725 726
  };

  class StackValueContext : public ExpressionContext {
   public:
    explicit StackValueContext(FullCodeGenerator* codegen)
727
        : ExpressionContext(codegen) { }
728 729 730 731

    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
732
    virtual void Plug(Variable* var) const;
733 734 735 736 737 738 739 740 741
    virtual void Plug(Handle<Object> lit) const;
    virtual void Plug(Heap::RootListIndex) const;
    virtual void PlugTOS() const;
    virtual void DropAndPlug(int count, Register reg) const;
    virtual void PrepareTest(Label* materialize_true,
                             Label* materialize_false,
                             Label** if_true,
                             Label** if_false,
                             Label** fall_through) const;
742
    virtual bool IsStackValue() const { return true; }
743 744 745 746
  };

  class TestContext : public ExpressionContext {
   public:
747 748 749 750 751
    TestContext(FullCodeGenerator* codegen,
                Expression* condition,
                Label* true_label,
                Label* false_label,
                Label* fall_through)
752
        : ExpressionContext(codegen),
753
          condition_(condition),
754 755
          true_label_(true_label),
          false_label_(false_label),
756
          fall_through_(fall_through) { }
757

758 759 760 761 762
    static const TestContext* cast(const ExpressionContext* context) {
      ASSERT(context->IsTest());
      return reinterpret_cast<const TestContext*>(context);
    }

763
    Expression* condition() const { return condition_; }
764 765 766 767
    Label* true_label() const { return true_label_; }
    Label* false_label() const { return false_label_; }
    Label* fall_through() const { return fall_through_; }

768 769 770
    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
771
    virtual void Plug(Variable* var) const;
772 773 774 775 776 777 778 779 780 781 782 783
    virtual void Plug(Handle<Object> lit) const;
    virtual void Plug(Heap::RootListIndex) const;
    virtual void PlugTOS() const;
    virtual void DropAndPlug(int count, Register reg) const;
    virtual void PrepareTest(Label* materialize_true,
                             Label* materialize_false,
                             Label** if_true,
                             Label** if_false,
                             Label** fall_through) const;
    virtual bool IsTest() const { return true; }

   private:
784
    Expression* condition_;
785 786 787 788 789 790 791 792
    Label* true_label_;
    Label* false_label_;
    Label* fall_through_;
  };

  class EffectContext : public ExpressionContext {
   public:
    explicit EffectContext(FullCodeGenerator* codegen)
793
        : ExpressionContext(codegen) { }
794 795 796 797

    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
798
    virtual void Plug(Variable* var) const;
799 800 801 802 803 804 805 806 807 808 809 810
    virtual void Plug(Handle<Object> lit) const;
    virtual void Plug(Heap::RootListIndex) const;
    virtual void PlugTOS() const;
    virtual void DropAndPlug(int count, Register reg) const;
    virtual void PrepareTest(Label* materialize_true,
                             Label* materialize_false,
                             Label** if_true,
                             Label** if_false,
                             Label** fall_through) const;
    virtual bool IsEffect() const { return true; }
  };

811 812
  MacroAssembler* masm_;
  CompilationInfo* info_;
813
  Scope* scope_;
814 815 816
  Label return_label_;
  NestedStatement* nesting_stack_;
  int loop_depth_;
817
  ZoneList<Handle<Object> >* globals_;
818 819
  Handle<FixedArray> modules_;
  int module_index_;
820
  const ExpressionContext* context_;
821
  ZoneList<BailoutEntry> bailout_entries_;
822
  GrowableBitVector prepared_bailout_ids_;
823
  ZoneList<BackEdgeEntry> back_edges_;
824
  int ic_total_count_;
825
  Handle<FixedArray> handler_table_;
826
  Handle<Cell> profiling_counter_;
827
  bool generate_debug_code_;
828

829 830
  friend class NestedStatement;

831
  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
832
  DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
833 834
};

835

836 837 838
// A map from property names to getter/setter pairs allocated in the zone.
class AccessorTable: public TemplateHashMap<Literal,
                                            ObjectLiteral::Accessors,
839
                                            ZoneAllocationPolicy> {
840 841
 public:
  explicit AccessorTable(Zone* zone) :
842
      TemplateHashMap<Literal, ObjectLiteral::Accessors,
843 844
                      ZoneAllocationPolicy>(Literal::Match,
                                            ZoneAllocationPolicy(zone)),
845 846 847
      zone_(zone) { }

  Iterator lookup(Literal* literal) {
848
    Iterator it = find(literal, true, ZoneAllocationPolicy(zone_));
849 850 851 852 853 854 855 856 857
    if (it->second == NULL) it->second = new(zone_) ObjectLiteral::Accessors();
    return it;
  }

 private:
  Zone* zone_;
};


858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
class BackEdgeTable {
 public:
  BackEdgeTable(Code* code, DisallowHeapAllocation* required) {
    ASSERT(code->kind() == Code::FUNCTION);
    instruction_start_ = code->instruction_start();
    Address table_address = instruction_start_ + code->back_edge_table_offset();
    length_ = Memory::uint32_at(table_address);
    start_ = table_address + kTableLengthSize;
  }

  uint32_t length() { return length_; }

  BailoutId ast_id(uint32_t index) {
    return BailoutId(static_cast<int>(
        Memory::uint32_at(entry_at(index) + kAstIdOffset)));
  }

  uint32_t loop_depth(uint32_t index) {
    return Memory::uint32_at(entry_at(index) + kLoopDepthOffset);
  }

  uint32_t pc_offset(uint32_t index) {
    return Memory::uint32_at(entry_at(index) + kPcOffsetOffset);
  }

  Address pc(uint32_t index) {
    return instruction_start_ + pc_offset(index);
  }

  enum BackEdgeState {
    INTERRUPT,
889 890
    ON_STACK_REPLACEMENT,
    OSR_AFTER_STACK_CHECK
891 892 893 894 895 896 897
  };

  // Patch all interrupts with allowed loop depth in the unoptimized code to
  // unconditionally call replacement_code.
  static void Patch(Isolate* isolate,
                    Code* unoptimized_code);

898
  // Patch the back edge to the target state, provided the correct callee.
899
  static void PatchAt(Code* unoptimized_code,
900 901
                      Address pc,
                      BackEdgeState target_state,
902 903
                      Code* replacement_code);

904
  // Change all patched back edges back to normal interrupts.
905 906 907
  static void Revert(Isolate* isolate,
                     Code* unoptimized_code);

908 909
  // Change a back edge patched for on-stack replacement to perform a
  // stack check first.
910
  static void AddStackCheck(Handle<Code> code, uint32_t pc_offset);
911

912 913
  // Revert the patch by AddStackCheck.
  static void RemoveStackCheck(Handle<Code> code, uint32_t pc_offset);
914 915

  // Return the current patch state of the back edge.
916 917 918 919
  static BackEdgeState GetBackEdgeState(Isolate* isolate,
                                        Code* unoptimized_code,
                                        Address pc_after);

920
#ifdef DEBUG
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
  // Verify that all back edges of a certain loop depth are patched.
  static bool Verify(Isolate* isolate,
                     Code* unoptimized_code,
                     int loop_nesting_level);
#endif  // DEBUG

 private:
  Address entry_at(uint32_t index) {
    ASSERT(index < length_);
    return start_ + index * kEntrySize;
  }

  static const int kTableLengthSize = kIntSize;
  static const int kAstIdOffset = 0 * kIntSize;
  static const int kPcOffsetOffset = 1 * kIntSize;
  static const int kLoopDepthOffset = 2 * kIntSize;
  static const int kEntrySize = 3 * kIntSize;

  Address start_;
  Address instruction_start_;
  uint32_t length_;
};


945 946
} }  // namespace v8::internal

947
#endif  // V8_FULL_CODEGEN_H_