The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / full-codegen.h @ f230a1cf

History | View | Annotate | Download (33.7 KB)

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 "assert-scope.h"
35
#include "ast.h"
36
#include "code-stubs.h"
37
#include "codegen.h"
38
#include "compiler.h"
39
#include "data-flow.h"
40
#include "globals.h"
41
#include "objects.h"
42

    
43
namespace v8 {
44
namespace internal {
45

    
46
// Forward declarations.
47
class JumpPatchSite;
48

    
49
// AST node visitor which can tell whether a given statement will be breakable
50
// when the code is compiled by the full compiler in the debugger. This means
51
// that there will be an IC (load/store/call) in the code generated for the
52
// debugger to piggybag on.
53
class BreakableStatementChecker: public AstVisitor {
54
 public:
55
  explicit BreakableStatementChecker(Isolate* isolate) : is_breakable_(false) {
56
    InitializeAstVisitor(isolate);
57
  }
58

    
59
  void Check(Statement* stmt);
60
  void Check(Expression* stmt);
61

    
62
  bool is_breakable() { return is_breakable_; }
63

    
64
 private:
65
  // AST node visit functions.
66
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
67
  AST_NODE_LIST(DECLARE_VISIT)
68
#undef DECLARE_VISIT
69

    
70
  bool is_breakable_;
71

    
72
  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
73
  DISALLOW_COPY_AND_ASSIGN(BreakableStatementChecker);
74
};
75

    
76

    
77
// -----------------------------------------------------------------------------
78
// Full code generator.
79

    
80
class FullCodeGenerator: public AstVisitor {
81
 public:
82
  enum State {
83
    NO_REGISTERS,
84
    TOS_REG
85
  };
86

    
87
  FullCodeGenerator(MacroAssembler* masm, CompilationInfo* info)
88
      : masm_(masm),
89
        info_(info),
90
        scope_(info->scope()),
91
        nesting_stack_(NULL),
92
        loop_depth_(0),
93
        globals_(NULL),
94
        context_(NULL),
95
        bailout_entries_(info->HasDeoptimizationSupport()
96
                         ? info->function()->ast_node_count() : 0,
97
                         info->zone()),
98
        back_edges_(2, info->zone()),
99
        type_feedback_cells_(info->HasDeoptimizationSupport()
100
                             ? info->function()->ast_node_count() : 0,
101
                             info->zone()),
102
        ic_total_count_(0),
103
        zone_(info->zone()) {
104
    Initialize();
105
  }
106

    
107
  void Initialize();
108

    
109
  static bool MakeCode(CompilationInfo* info);
110

    
111
  // Encode state and pc-offset as a BitField<type, start, size>.
112
  // Only use 30 bits because we encode the result as a smi.
113
  class StateField : public BitField<State, 0, 1> { };
114
  class PcField    : public BitField<unsigned, 1, 30-1> { };
115

    
116
  static const char* State2String(State state) {
117
    switch (state) {
118
      case NO_REGISTERS: return "NO_REGISTERS";
119
      case TOS_REG: return "TOS_REG";
120
    }
121
    UNREACHABLE();
122
    return NULL;
123
  }
124

    
125
  Zone* zone() const { return zone_; }
126

    
127
  static const int kMaxBackEdgeWeight = 127;
128

    
129
  // Platform-specific code size multiplier.
130
#if V8_TARGET_ARCH_IA32
131
  static const int kCodeSizeMultiplier = 100;
132
#elif V8_TARGET_ARCH_X64
133
  static const int kCodeSizeMultiplier = 162;
134
#elif V8_TARGET_ARCH_ARM
135
  static const int kCodeSizeMultiplier = 142;
136
#elif V8_TARGET_ARCH_MIPS
137
  static const int kCodeSizeMultiplier = 142;
138
#else
139
#error Unsupported target architecture.
140
#endif
141

    
142
 private:
143
  class Breakable;
144
  class Iteration;
145

    
146
  class TestContext;
147

    
148
  class NestedStatement BASE_EMBEDDED {
149
   public:
150
    explicit NestedStatement(FullCodeGenerator* codegen) : codegen_(codegen) {
151
      // Link into codegen's nesting stack.
152
      previous_ = codegen->nesting_stack_;
153
      codegen->nesting_stack_ = this;
154
    }
155
    virtual ~NestedStatement() {
156
      // Unlink from codegen's nesting stack.
157
      ASSERT_EQ(this, codegen_->nesting_stack_);
158
      codegen_->nesting_stack_ = previous_;
159
    }
160

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

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

    
167
    // Notify the statement that we are exiting it via break, continue, or
168
    // return and give it a chance to generate cleanup code.  Return the
169
    // next outer statement in the nesting stack.  We accumulate in
170
    // *stack_depth the amount to drop the stack and in *context_length the
171
    // number of context chain links to unwind as we traverse the nesting
172
    // stack from an exit to its target.
173
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
174
      return previous_;
175
    }
176

    
177
   protected:
178
    MacroAssembler* masm() { return codegen_->masm(); }
179

    
180
    FullCodeGenerator* codegen_;
181
    NestedStatement* previous_;
182

    
183
   private:
184
    DISALLOW_COPY_AND_ASSIGN(NestedStatement);
185
  };
186

    
187
  // A breakable statement such as a block.
188
  class Breakable : public NestedStatement {
189
   public:
190
    Breakable(FullCodeGenerator* codegen, BreakableStatement* statement)
191
        : NestedStatement(codegen), statement_(statement) {
192
    }
193
    virtual ~Breakable() {}
194

    
195
    virtual Breakable* AsBreakable() { return this; }
196
    virtual bool IsBreakTarget(Statement* target) {
197
      return statement() == target;
198
    }
199

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

    
203
   private:
204
    BreakableStatement* statement_;
205
    Label break_label_;
206
  };
207

    
208
  // An iteration statement such as a while, for, or do loop.
209
  class Iteration : public Breakable {
210
   public:
211
    Iteration(FullCodeGenerator* codegen, IterationStatement* statement)
212
        : Breakable(codegen, statement) {
213
    }
214
    virtual ~Iteration() {}
215

    
216
    virtual Iteration* AsIteration() { return this; }
217
    virtual bool IsContinueTarget(Statement* target) {
218
      return statement() == target;
219
    }
220

    
221
    Label* continue_label() { return &continue_label_; }
222

    
223
   private:
224
    Label continue_label_;
225
  };
226

    
227
  // A nested block statement.
228
  class NestedBlock : public Breakable {
229
   public:
230
    NestedBlock(FullCodeGenerator* codegen, Block* block)
231
        : Breakable(codegen, block) {
232
    }
233
    virtual ~NestedBlock() {}
234

    
235
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
236
      if (statement()->AsBlock()->scope() != NULL) {
237
        ++(*context_length);
238
      }
239
      return previous_;
240
    };
241
  };
242

    
243
  // The try block of a try/catch statement.
244
  class TryCatch : public NestedStatement {
245
   public:
246
    explicit TryCatch(FullCodeGenerator* codegen) : NestedStatement(codegen) {
247
    }
248
    virtual ~TryCatch() {}
249

    
250
    virtual NestedStatement* Exit(int* stack_depth, int* context_length);
251
  };
252

    
253
  // The try block of a try/finally statement.
254
  class TryFinally : public NestedStatement {
255
   public:
256
    TryFinally(FullCodeGenerator* codegen, Label* finally_entry)
257
        : NestedStatement(codegen), finally_entry_(finally_entry) {
258
    }
259
    virtual ~TryFinally() {}
260

    
261
    virtual NestedStatement* Exit(int* stack_depth, int* context_length);
262

    
263
   private:
264
    Label* finally_entry_;
265
  };
266

    
267
  // The finally block of a try/finally statement.
268
  class Finally : public NestedStatement {
269
   public:
270
    static const int kElementCount = 5;
271

    
272
    explicit Finally(FullCodeGenerator* codegen) : NestedStatement(codegen) { }
273
    virtual ~Finally() {}
274

    
275
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
276
      *stack_depth += kElementCount;
277
      return previous_;
278
    }
279
  };
280

    
281
  // The body of a for/in loop.
282
  class ForIn : public Iteration {
283
   public:
284
    static const int kElementCount = 5;
285

    
286
    ForIn(FullCodeGenerator* codegen, ForInStatement* statement)
287
        : Iteration(codegen, statement) {
288
    }
289
    virtual ~ForIn() {}
290

    
291
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
292
      *stack_depth += kElementCount;
293
      return previous_;
294
    }
295
  };
296

    
297

    
298
  // The body of a with or catch.
299
  class WithOrCatch : public NestedStatement {
300
   public:
301
    explicit WithOrCatch(FullCodeGenerator* codegen)
302
        : NestedStatement(codegen) {
303
    }
304
    virtual ~WithOrCatch() {}
305

    
306
    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
307
      ++(*context_length);
308
      return previous_;
309
    }
310
  };
311

    
312
  // Type of a member function that generates inline code for a native function.
313
  typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr);
314

    
315
  static const InlineFunctionGenerator kInlineFunctionGenerators[];
316

    
317
  // A platform-specific utility to overwrite the accumulator register
318
  // with a GC-safe value.
319
  void ClearAccumulator();
320

    
321
  // Determine whether or not to inline the smi case for the given
322
  // operation.
323
  bool ShouldInlineSmiCase(Token::Value op);
324

    
325
  // Helper function to convert a pure value into a test context.  The value
326
  // is expected on the stack or the accumulator, depending on the platform.
327
  // See the platform-specific implementation for details.
328
  void DoTest(Expression* condition,
329
              Label* if_true,
330
              Label* if_false,
331
              Label* fall_through);
332
  void DoTest(const TestContext* context);
333

    
334
  // Helper function to split control flow and avoid a branch to the
335
  // fall-through label if it is set up.
336
#if V8_TARGET_ARCH_MIPS
337
  void Split(Condition cc,
338
             Register lhs,
339
             const Operand&  rhs,
340
             Label* if_true,
341
             Label* if_false,
342
             Label* fall_through);
343
#else  // All non-mips arch.
344
  void Split(Condition cc,
345
             Label* if_true,
346
             Label* if_false,
347
             Label* fall_through);
348
#endif  // V8_TARGET_ARCH_MIPS
349

    
350
  // Load the value of a known (PARAMETER, LOCAL, or CONTEXT) variable into
351
  // a register.  Emits a context chain walk if if necessary (so does
352
  // SetVar) so avoid calling both on the same variable.
353
  void GetVar(Register destination, Variable* var);
354

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

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

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

    
374
  void VisitForEffect(Expression* expr) {
375
    EffectContext context(this);
376
    Visit(expr);
377
    PrepareForBailout(expr, NO_REGISTERS);
378
  }
379

    
380
  void VisitForAccumulatorValue(Expression* expr) {
381
    AccumulatorValueContext context(this);
382
    Visit(expr);
383
    PrepareForBailout(expr, TOS_REG);
384
  }
385

    
386
  void VisitForStackValue(Expression* expr) {
387
    StackValueContext context(this);
388
    Visit(expr);
389
    PrepareForBailout(expr, NO_REGISTERS);
390
  }
391

    
392
  void VisitForControl(Expression* expr,
393
                       Label* if_true,
394
                       Label* if_false,
395
                       Label* fall_through) {
396
    TestContext context(this, expr, if_true, if_false, fall_through);
397
    Visit(expr);
398
    // For test contexts, we prepare for bailout before branching, not at
399
    // the end of the entire expression.  This happens as part of visiting
400
    // the expression.
401
  }
402

    
403
  void VisitInDuplicateContext(Expression* expr);
404

    
405
  void VisitDeclarations(ZoneList<Declaration*>* declarations);
406
  void DeclareModules(Handle<FixedArray> descriptions);
407
  void DeclareGlobals(Handle<FixedArray> pairs);
408
  int DeclareGlobalsFlags();
409

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

    
415
  // Generate code to create an iterator result object.  The "value" property is
416
  // set to a value popped from the stack, and "done" is set according to the
417
  // argument.  The result object is left in the result register.
418
  void EmitCreateIteratorResult(bool done);
419

    
420
  // Try to perform a comparison as a fast inlined literal compare if
421
  // the operands allow it.  Returns true if the compare operations
422
  // has been matched and all code generated; false otherwise.
423
  bool TryLiteralCompare(CompareOperation* compare);
424

    
425
  // Platform-specific code for comparing the type of a value with
426
  // a given literal string.
427
  void EmitLiteralCompareTypeof(Expression* expr,
428
                                Expression* sub_expr,
429
                                Handle<String> check);
430

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

    
436
  // Bailout support.
437
  void PrepareForBailout(Expression* node, State state);
438
  void PrepareForBailoutForId(BailoutId id, State state);
439

    
440
  // Cache cell support.  This associates AST ids with global property cells
441
  // that will be cleared during GC and collected by the type-feedback oracle.
442
  void RecordTypeFeedbackCell(TypeFeedbackId id, Handle<Cell> cell);
443

    
444
  // Record a call's return site offset, used to rebuild the frame if the
445
  // called function was inlined at the site.
446
  void RecordJSReturnSite(Call* call);
447

    
448
  // Prepare for bailout before a test (or compare) and branch.  If
449
  // should_normalize, then the following comparison will not handle the
450
  // canonical JS true value so we will insert a (dead) test against true at
451
  // the actual bailout target from the optimized code. If not
452
  // should_normalize, the true and false labels are ignored.
453
  void PrepareForBailoutBeforeSplit(Expression* expr,
454
                                    bool should_normalize,
455
                                    Label* if_true,
456
                                    Label* if_false);
457

    
458
  // If enabled, emit debug code for checking that the current context is
459
  // neither a with nor a catch context.
460
  void EmitDebugCheckDeclarationContext(Variable* variable);
461

    
462
  // This is meant to be called at loop back edges, |back_edge_target| is
463
  // the jump target of the back edge and is used to approximate the amount
464
  // of code inside the loop.
465
  void EmitBackEdgeBookkeeping(IterationStatement* stmt,
466
                               Label* back_edge_target);
467
  // Record the OSR AST id corresponding to a back edge in the code.
468
  void RecordBackEdge(BailoutId osr_ast_id);
469
  // Emit a table of back edge ids, pcs and loop depths into the code stream.
470
  // Return the offset of the start of the table.
471
  unsigned EmitBackEdgeTable();
472

    
473
  void EmitProfilingCounterDecrement(int delta);
474
  void EmitProfilingCounterReset();
475

    
476
  // Emit code to pop values from the stack associated with nested statements
477
  // like try/catch, try/finally, etc, running the finallies and unwinding the
478
  // handlers as needed.
479
  void EmitUnwindBeforeReturn();
480

    
481
  // Platform-specific return sequence
482
  void EmitReturnSequence();
483

    
484
  // Platform-specific code sequences for calls
485
  void EmitCallWithStub(Call* expr, CallFunctionFlags flags);
486
  void EmitCallWithIC(Call* expr, Handle<Object> name, RelocInfo::Mode mode);
487
  void EmitKeyedCallWithIC(Call* expr, Expression* key);
488

    
489
  // Platform-specific code for inline runtime calls.
490
  InlineFunctionGenerator FindInlineFunctionGenerator(Runtime::FunctionId id);
491

    
492
  void EmitInlineRuntimeCall(CallRuntime* expr);
493

    
494
#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
495
  void Emit##name(CallRuntime* expr);
496
  INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
497
  INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
498
#undef EMIT_INLINE_RUNTIME_CALL
499

    
500
  void EmitSeqStringSetCharCheck(Register string,
501
                                 Register index,
502
                                 Register value,
503
                                 uint32_t encoding_mask);
504

    
505
  // Platform-specific code for resuming generators.
506
  void EmitGeneratorResume(Expression *generator,
507
                           Expression *value,
508
                           JSGeneratorObject::ResumeMode resume_mode);
509

    
510
  // Platform-specific code for loading variables.
511
  void EmitLoadGlobalCheckExtensions(Variable* var,
512
                                     TypeofState typeof_state,
513
                                     Label* slow);
514
  MemOperand ContextSlotOperandCheckExtensions(Variable* var, Label* slow);
515
  void EmitDynamicLookupFastCase(Variable* var,
516
                                 TypeofState typeof_state,
517
                                 Label* slow,
518
                                 Label* done);
519
  void EmitVariableLoad(VariableProxy* proxy);
520

    
521
  void EmitAccessor(Expression* expression);
522

    
523
  // Expects the arguments and the function already pushed.
524
  void EmitResolvePossiblyDirectEval(int arg_count);
525

    
526
  // Platform-specific support for allocating a new closure based on
527
  // the given function info.
528
  void EmitNewClosure(Handle<SharedFunctionInfo> info, bool pretenure);
529

    
530
  // Platform-specific support for compiling assignments.
531

    
532
  // Load a value from a named property.
533
  // The receiver is left on the stack by the IC.
534
  void EmitNamedPropertyLoad(Property* expr);
535

    
536
  // Load a value from a keyed property.
537
  // The receiver and the key is left on the stack by the IC.
538
  void EmitKeyedPropertyLoad(Property* expr);
539

    
540
  // Apply the compound assignment operator. Expects the left operand on top
541
  // of the stack and the right one in the accumulator.
542
  void EmitBinaryOp(BinaryOperation* expr,
543
                    Token::Value op,
544
                    OverwriteMode mode);
545

    
546
  // Helper functions for generating inlined smi code for certain
547
  // binary operations.
548
  void EmitInlineSmiBinaryOp(BinaryOperation* expr,
549
                             Token::Value op,
550
                             OverwriteMode mode,
551
                             Expression* left,
552
                             Expression* right);
553

    
554
  // Assign to the given expression as if via '='. The right-hand-side value
555
  // is expected in the accumulator.
556
  void EmitAssignment(Expression* expr);
557

    
558
  // Complete a variable assignment.  The right-hand-side value is expected
559
  // in the accumulator.
560
  void EmitVariableAssignment(Variable* var,
561
                              Token::Value op);
562

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

    
567
  // Complete a keyed property assignment.  The receiver and key are
568
  // expected on top of the stack and the right-hand-side value in the
569
  // accumulator.
570
  void EmitKeyedPropertyAssignment(Assignment* expr);
571

    
572
  void CallIC(Handle<Code> code,
573
              RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
574
              TypeFeedbackId id = TypeFeedbackId::None());
575

    
576
  void SetFunctionPosition(FunctionLiteral* fun);
577
  void SetReturnPosition(FunctionLiteral* fun);
578
  void SetStatementPosition(Statement* stmt);
579
  void SetExpressionPosition(Expression* expr);
580
  void SetStatementPosition(int pos);
581
  void SetSourcePosition(int pos);
582

    
583
  // Non-local control flow support.
584
  void EnterFinallyBlock();
585
  void ExitFinallyBlock();
586

    
587
  // Loop nesting counter.
588
  int loop_depth() { return loop_depth_; }
589
  void increment_loop_depth() { loop_depth_++; }
590
  void decrement_loop_depth() {
591
    ASSERT(loop_depth_ > 0);
592
    loop_depth_--;
593
  }
594

    
595
  MacroAssembler* masm() { return masm_; }
596

    
597
  class ExpressionContext;
598
  const ExpressionContext* context() { return context_; }
599
  void set_new_context(const ExpressionContext* context) { context_ = context; }
600

    
601
  Handle<Script> script() { return info_->script(); }
602
  bool is_eval() { return info_->is_eval(); }
603
  bool is_native() { return info_->is_native(); }
604
  bool is_classic_mode() { return language_mode() == CLASSIC_MODE; }
605
  LanguageMode language_mode() { return function()->language_mode(); }
606
  FunctionLiteral* function() { return info_->function(); }
607
  Scope* scope() { return scope_; }
608

    
609
  static Register result_register();
610
  static Register context_register();
611

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

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

    
620
  // Push the function argument for the runtime functions PushWithContext
621
  // and PushCatchContext.
622
  void PushFunctionArgumentForContextAllocation();
623

    
624
  // AST node visit functions.
625
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
626
  AST_NODE_LIST(DECLARE_VISIT)
627
#undef DECLARE_VISIT
628

    
629
  void VisitComma(BinaryOperation* expr);
630
  void VisitLogicalExpression(BinaryOperation* expr);
631
  void VisitArithmeticExpression(BinaryOperation* expr);
632

    
633
  void VisitForTypeofValue(Expression* expr);
634

    
635
  void Generate();
636
  void PopulateDeoptimizationData(Handle<Code> code);
637
  void PopulateTypeFeedbackInfo(Handle<Code> code);
638
  void PopulateTypeFeedbackCells(Handle<Code> code);
639

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

    
642
  struct BailoutEntry {
643
    BailoutId id;
644
    unsigned pc_and_state;
645
  };
646

    
647
  struct BackEdgeEntry {
648
    BailoutId id;
649
    unsigned pc;
650
    uint32_t loop_depth;
651
  };
652

    
653
  struct TypeFeedbackCellEntry {
654
    TypeFeedbackId ast_id;
655
    Handle<Cell> cell;
656
  };
657

    
658

    
659
  class ExpressionContext BASE_EMBEDDED {
660
   public:
661
    explicit ExpressionContext(FullCodeGenerator* codegen)
662
        : masm_(codegen->masm()), old_(codegen->context()), codegen_(codegen) {
663
      codegen->set_new_context(this);
664
    }
665

    
666
    virtual ~ExpressionContext() {
667
      codegen_->set_new_context(old_);
668
    }
669

    
670
    Isolate* isolate() const { return codegen_->isolate(); }
671

    
672
    // Convert constant control flow (true or false) to the result expected for
673
    // this expression context.
674
    virtual void Plug(bool flag) const = 0;
675

    
676
    // Emit code to convert a pure value (in a register, known variable
677
    // location, as a literal, or on top of the stack) into the result
678
    // expected according to this expression context.
679
    virtual void Plug(Register reg) const = 0;
680
    virtual void Plug(Variable* var) const = 0;
681
    virtual void Plug(Handle<Object> lit) const = 0;
682
    virtual void Plug(Heap::RootListIndex index) const = 0;
683
    virtual void PlugTOS() const = 0;
684

    
685
    // Emit code to convert pure control flow to a pair of unbound labels into
686
    // the result expected according to this expression context.  The
687
    // implementation will bind both labels unless it's a TestContext, which
688
    // won't bind them at this point.
689
    virtual void Plug(Label* materialize_true,
690
                      Label* materialize_false) const = 0;
691

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

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

    
705
    // Returns true if we are evaluating only for side effects (i.e. if the
706
    // result will be discarded).
707
    virtual bool IsEffect() const { return false; }
708

    
709
    // Returns true if we are evaluating for the value (in accu/on stack).
710
    virtual bool IsAccumulatorValue() const { return false; }
711
    virtual bool IsStackValue() const { return false; }
712

    
713
    // Returns true if we are branching on the value rather than materializing
714
    // it.  Only used for asserts.
715
    virtual bool IsTest() const { return false; }
716

    
717
   protected:
718
    FullCodeGenerator* codegen() const { return codegen_; }
719
    MacroAssembler* masm() const { return masm_; }
720
    MacroAssembler* masm_;
721

    
722
   private:
723
    const ExpressionContext* old_;
724
    FullCodeGenerator* codegen_;
725
  };
726

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

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

    
748
  class StackValueContext : public ExpressionContext {
749
   public:
750
    explicit StackValueContext(FullCodeGenerator* codegen)
751
        : ExpressionContext(codegen) { }
752

    
753
    virtual void Plug(bool flag) const;
754
    virtual void Plug(Register reg) const;
755
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
756
    virtual void Plug(Variable* var) const;
757
    virtual void Plug(Handle<Object> lit) const;
758
    virtual void Plug(Heap::RootListIndex) const;
759
    virtual void PlugTOS() const;
760
    virtual void DropAndPlug(int count, Register reg) const;
761
    virtual void PrepareTest(Label* materialize_true,
762
                             Label* materialize_false,
763
                             Label** if_true,
764
                             Label** if_false,
765
                             Label** fall_through) const;
766
    virtual bool IsStackValue() const { return true; }
767
  };
768

    
769
  class TestContext : public ExpressionContext {
770
   public:
771
    TestContext(FullCodeGenerator* codegen,
772
                Expression* condition,
773
                Label* true_label,
774
                Label* false_label,
775
                Label* fall_through)
776
        : ExpressionContext(codegen),
777
          condition_(condition),
778
          true_label_(true_label),
779
          false_label_(false_label),
780
          fall_through_(fall_through) { }
781

    
782
    static const TestContext* cast(const ExpressionContext* context) {
783
      ASSERT(context->IsTest());
784
      return reinterpret_cast<const TestContext*>(context);
785
    }
786

    
787
    Expression* condition() const { return condition_; }
788
    Label* true_label() const { return true_label_; }
789
    Label* false_label() const { return false_label_; }
790
    Label* fall_through() const { return fall_through_; }
791

    
792
    virtual void Plug(bool flag) const;
793
    virtual void Plug(Register reg) const;
794
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
795
    virtual void Plug(Variable* var) const;
796
    virtual void Plug(Handle<Object> lit) const;
797
    virtual void Plug(Heap::RootListIndex) const;
798
    virtual void PlugTOS() const;
799
    virtual void DropAndPlug(int count, Register reg) const;
800
    virtual void PrepareTest(Label* materialize_true,
801
                             Label* materialize_false,
802
                             Label** if_true,
803
                             Label** if_false,
804
                             Label** fall_through) const;
805
    virtual bool IsTest() const { return true; }
806

    
807
   private:
808
    Expression* condition_;
809
    Label* true_label_;
810
    Label* false_label_;
811
    Label* fall_through_;
812
  };
813

    
814
  class EffectContext : public ExpressionContext {
815
   public:
816
    explicit EffectContext(FullCodeGenerator* codegen)
817
        : ExpressionContext(codegen) { }
818

    
819
    virtual void Plug(bool flag) const;
820
    virtual void Plug(Register reg) const;
821
    virtual void Plug(Label* materialize_true, Label* materialize_false) const;
822
    virtual void Plug(Variable* var) const;
823
    virtual void Plug(Handle<Object> lit) const;
824
    virtual void Plug(Heap::RootListIndex) const;
825
    virtual void PlugTOS() const;
826
    virtual void DropAndPlug(int count, Register reg) const;
827
    virtual void PrepareTest(Label* materialize_true,
828
                             Label* materialize_false,
829
                             Label** if_true,
830
                             Label** if_false,
831
                             Label** fall_through) const;
832
    virtual bool IsEffect() const { return true; }
833
  };
834

    
835
  MacroAssembler* masm_;
836
  CompilationInfo* info_;
837
  Scope* scope_;
838
  Label return_label_;
839
  NestedStatement* nesting_stack_;
840
  int loop_depth_;
841
  ZoneList<Handle<Object> >* globals_;
842
  Handle<FixedArray> modules_;
843
  int module_index_;
844
  const ExpressionContext* context_;
845
  ZoneList<BailoutEntry> bailout_entries_;
846
  GrowableBitVector prepared_bailout_ids_;
847
  ZoneList<BackEdgeEntry> back_edges_;
848
  ZoneList<TypeFeedbackCellEntry> type_feedback_cells_;
849
  int ic_total_count_;
850
  Handle<FixedArray> handler_table_;
851
  Handle<Cell> profiling_counter_;
852
  bool generate_debug_code_;
853
  Zone* zone_;
854

    
855
  friend class NestedStatement;
856

    
857
  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
858
  DISALLOW_COPY_AND_ASSIGN(FullCodeGenerator);
859
};
860

    
861

    
862
// A map from property names to getter/setter pairs allocated in the zone.
863
class AccessorTable: public TemplateHashMap<Literal,
864
                                            ObjectLiteral::Accessors,
865
                                            ZoneAllocationPolicy> {
866
 public:
867
  explicit AccessorTable(Zone* zone) :
868
      TemplateHashMap<Literal, ObjectLiteral::Accessors,
869
                      ZoneAllocationPolicy>(Literal::Match,
870
                                            ZoneAllocationPolicy(zone)),
871
      zone_(zone) { }
872

    
873
  Iterator lookup(Literal* literal) {
874
    Iterator it = find(literal, true, ZoneAllocationPolicy(zone_));
875
    if (it->second == NULL) it->second = new(zone_) ObjectLiteral::Accessors();
876
    return it;
877
  }
878

    
879
 private:
880
  Zone* zone_;
881
};
882

    
883

    
884
class BackEdgeTable {
885
 public:
886
  BackEdgeTable(Code* code, DisallowHeapAllocation* required) {
887
    ASSERT(code->kind() == Code::FUNCTION);
888
    instruction_start_ = code->instruction_start();
889
    Address table_address = instruction_start_ + code->back_edge_table_offset();
890
    length_ = Memory::uint32_at(table_address);
891
    start_ = table_address + kTableLengthSize;
892
  }
893

    
894
  uint32_t length() { return length_; }
895

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

    
901
  uint32_t loop_depth(uint32_t index) {
902
    return Memory::uint32_at(entry_at(index) + kLoopDepthOffset);
903
  }
904

    
905
  uint32_t pc_offset(uint32_t index) {
906
    return Memory::uint32_at(entry_at(index) + kPcOffsetOffset);
907
  }
908

    
909
  Address pc(uint32_t index) {
910
    return instruction_start_ + pc_offset(index);
911
  }
912

    
913
  enum BackEdgeState {
914
    INTERRUPT,
915
    ON_STACK_REPLACEMENT,
916
    OSR_AFTER_STACK_CHECK
917
  };
918

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

    
924
  // Patch the back edge to the target state, provided the correct callee.
925
  static void PatchAt(Code* unoptimized_code,
926
                      Address pc,
927
                      BackEdgeState target_state,
928
                      Code* replacement_code);
929

    
930
  // Change all patched back edges back to normal interrupts.
931
  static void Revert(Isolate* isolate,
932
                     Code* unoptimized_code);
933

    
934
  // Change a back edge patched for on-stack replacement to perform a
935
  // stack check first.
936
  static void AddStackCheck(CompilationInfo* info);
937

    
938
  // Remove the stack check, if available, and replace by on-stack replacement.
939
  static void RemoveStackCheck(CompilationInfo* info);
940

    
941
  // Return the current patch state of the back edge.
942
  static BackEdgeState GetBackEdgeState(Isolate* isolate,
943
                                        Code* unoptimized_code,
944
                                        Address pc_after);
945

    
946
#ifdef DEBUG
947
  // Verify that all back edges of a certain loop depth are patched.
948
  static bool Verify(Isolate* isolate,
949
                     Code* unoptimized_code,
950
                     int loop_nesting_level);
951
#endif  // DEBUG
952

    
953
 private:
954
  Address entry_at(uint32_t index) {
955
    ASSERT(index < length_);
956
    return start_ + index * kEntrySize;
957
  }
958

    
959
  static const int kTableLengthSize = kIntSize;
960
  static const int kAstIdOffset = 0 * kIntSize;
961
  static const int kPcOffsetOffset = 1 * kIntSize;
962
  static const int kLoopDepthOffset = 2 * kIntSize;
963
  static const int kEntrySize = 3 * kIntSize;
964

    
965
  Address start_;
966
  Address instruction_start_;
967
  uint32_t length_;
968
};
969

    
970

    
971
} }  // namespace v8::internal
972

    
973
#endif  // V8_FULL_CODEGEN_H_