full-codegen.h 32.3 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 10 11 12 13 14 15 16 17 18
#include "src/v8.h"

#include "src/allocation.h"
#include "src/assert-scope.h"
#include "src/ast.h"
#include "src/code-stubs.h"
#include "src/codegen.h"
#include "src/compiler.h"
#include "src/data-flow.h"
#include "src/globals.h"
#include "src/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
    ASSERT(!info->IsStub());
78 79 80 81
    Initialize();
  }

  void Initialize();
82

83
  static bool MakeCode(CompilationInfo* info);
84

85 86 87 88
  // 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> { };
89 90 91 92 93 94 95 96 97

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

99 100
  static const int kMaxBackEdgeWeight = 127;

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

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

126
  class TestContext;
127 128 129

  class NestedStatement BASE_EMBEDDED {
   public:
130
    explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
      // 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; }

147 148 149 150 151 152 153 154
    // 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_;
155
    }
156

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

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

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

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

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

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

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

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

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

    Label* continue_label() { return &continue_label_; }

203
   private:
204
    Label continue_label_;
205 206
  };

207 208 209 210 211 212 213 214 215
  // 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) {
216
      if (statement()->AsBlock()->scope() != NULL) {
217 218 219
        ++(*context_length);
      }
      return previous_;
220
    }
221 222
  };

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

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

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

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

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

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

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

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

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

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

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

277

278
  // The body of a with or catch.
279 280 281 282 283 284 285 286 287 288 289 290 291
  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_;
    }
  };

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

  static const InlineFunctionGenerator kInlineFunctionGenerators[];

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

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

305 306 307
  // 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.
308 309 310 311 312
  void DoTest(Expression* condition,
              Label* if_true,
              Label* if_false,
              Label* fall_through);
  void DoTest(const TestContext* context);
313 314 315

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

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
  // 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);
353

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

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

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

372 373 374 375
  void VisitForControl(Expression* expr,
                       Label* if_true,
                       Label* if_false,
                       Label* fall_through) {
376
    TestContext context(this, expr, if_true, if_false, fall_through);
377 378 379 380
    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.
381 382
  }

383 384
  void VisitInDuplicateContext(Expression* expr);

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

390 391 392 393 394
  // 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);

395 396 397 398
  // 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);
399

400 401 402
  // 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.
403
  bool TryLiteralCompare(CompareOperation* compare);
404

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

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

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

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

427 428 429 430 431 432 433 434 435
  // 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.
436
  void PrepareForBailoutBeforeSplit(Expression* expr,
437 438 439 440
                                    bool should_normalize,
                                    Label* if_true,
                                    Label* if_false);

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

445 446 447
  // 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.
448 449 450 451
  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);
452 453 454
  // 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();
455

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

459 460 461 462 463
  // 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();

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

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

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

475
  void EmitInlineRuntimeCall(CallRuntime* expr);
476 477

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

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

487
  // Platform-specific code for loading variables.
488 489 490 491 492 493 494 495
  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);
496
  void EmitVariableLoad(VariableProxy* proxy);
497

498 499
  void EmitAccessor(Expression* expression);

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

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

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

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

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

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

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

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

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

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

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

549 550 551
  // 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.
552
  void EmitKeyedPropertyAssignment(Assignment* expr);
553

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

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

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

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

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

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

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

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

593
  static Register result_register();
594 595 596 597 598 599 600 601 602
  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);
603

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

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

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

617
  void VisitForTypeofValue(Expression* expr);
618

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

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

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

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

636
  class ExpressionContext BASE_EMBEDDED {
637 638 639 640 641 642 643 644 645 646
   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_);
    }

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

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

653 654 655
    // 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.
656
    virtual void Plug(Register reg) const = 0;
657
    virtual void Plug(Variable* var) const = 0;
658 659 660 661 662 663
    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
664 665
    // implementation will bind both labels unless it's a TestContext, which
    // won't bind them at this point.
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
    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;

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

686 687 688 689
    // 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; }

690
    // Returns true if we are branching on the value rather than materializing
691
    // it.  Only used for asserts.
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
    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)
707
        : ExpressionContext(codegen) { }
708 709 710 711

    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
712
    virtual void Plug(Variable* var) const;
713 714 715 716 717 718 719 720 721
    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;
722
    virtual bool IsAccumulatorValue() const { return true; }
723 724 725 726 727
  };

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

    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
733
    virtual void Plug(Variable* var) const;
734 735 736 737 738 739 740 741 742
    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;
743
    virtual bool IsStackValue() const { return true; }
744 745 746 747
  };

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

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

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

769 770 771
    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
772
    virtual void Plug(Variable* var) const;
773 774 775 776 777 778 779 780 781 782 783 784
    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:
785
    Expression* condition_;
786 787 788 789 790 791 792 793
    Label* true_label_;
    Label* false_label_;
    Label* fall_through_;
  };

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

    virtual void Plug(bool flag) const;
    virtual void Plug(Register reg) const;
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
799
    virtual void Plug(Variable* var) const;
800 801 802 803 804 805 806 807 808 809 810 811
    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; }
  };

812 813
  MacroAssembler* masm_;
  CompilationInfo* info_;
814
  Scope* scope_;
815 816 817
  Label return_label_;
  NestedStatement* nesting_stack_;
  int loop_depth_;
818
  ZoneList<Handle<Object> >* globals_;
819 820
  Handle<FixedArray> modules_;
  int module_index_;
821
  const ExpressionContext* context_;
822
  ZoneList<BailoutEntry> bailout_entries_;
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_