Home | History | Annotate | Download | only in x64
      1 // Copyright 2010 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 #include "v8.h"
     29 
     30 #include "codegen-inl.h"
     31 #include "compiler.h"
     32 #include "debug.h"
     33 #include "full-codegen.h"
     34 #include "parser.h"
     35 
     36 namespace v8 {
     37 namespace internal {
     38 
     39 #define __ ACCESS_MASM(masm_)
     40 
     41 // Generate code for a JS function.  On entry to the function the receiver
     42 // and arguments have been pushed on the stack left to right, with the
     43 // return address on top of them.  The actual argument count matches the
     44 // formal parameter count expected by the function.
     45 //
     46 // The live registers are:
     47 //   o rdi: the JS function object being called (ie, ourselves)
     48 //   o rsi: our context
     49 //   o rbp: our caller's frame pointer
     50 //   o rsp: stack pointer (pointing to return address)
     51 //
     52 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
     53 // frames-x64.h for its layout.
     54 void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) {
     55   ASSERT(info_ == NULL);
     56   info_ = info;
     57   SetFunctionPosition(function());
     58 
     59   if (mode == PRIMARY) {
     60     __ push(rbp);  // Caller's frame pointer.
     61     __ movq(rbp, rsp);
     62     __ push(rsi);  // Callee's context.
     63     __ push(rdi);  // Callee's JS Function.
     64 
     65     { Comment cmnt(masm_, "[ Allocate locals");
     66       int locals_count = scope()->num_stack_slots();
     67       if (locals_count == 1) {
     68         __ PushRoot(Heap::kUndefinedValueRootIndex);
     69       } else if (locals_count > 1) {
     70         __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
     71         for (int i = 0; i < locals_count; i++) {
     72           __ push(rdx);
     73         }
     74       }
     75     }
     76 
     77     bool function_in_register = true;
     78 
     79     // Possibly allocate a local context.
     80     if (scope()->num_heap_slots() > 0) {
     81       Comment cmnt(masm_, "[ Allocate local context");
     82       // Argument to NewContext is the function, which is still in rdi.
     83       __ push(rdi);
     84       __ CallRuntime(Runtime::kNewContext, 1);
     85       function_in_register = false;
     86       // Context is returned in both rax and rsi.  It replaces the context
     87       // passed to us.  It's saved in the stack and kept live in rsi.
     88       __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
     89 
     90       // Copy any necessary parameters into the context.
     91       int num_parameters = scope()->num_parameters();
     92       for (int i = 0; i < num_parameters; i++) {
     93         Slot* slot = scope()->parameter(i)->slot();
     94         if (slot != NULL && slot->type() == Slot::CONTEXT) {
     95           int parameter_offset = StandardFrameConstants::kCallerSPOffset +
     96                                      (num_parameters - 1 - i) * kPointerSize;
     97           // Load parameter from stack.
     98           __ movq(rax, Operand(rbp, parameter_offset));
     99           // Store it in the context.
    100           int context_offset = Context::SlotOffset(slot->index());
    101           __ movq(Operand(rsi, context_offset), rax);
    102           // Update the write barrier. This clobbers all involved
    103           // registers, so we have use a third register to avoid
    104           // clobbering rsi.
    105           __ movq(rcx, rsi);
    106           __ RecordWrite(rcx, context_offset, rax, rbx);
    107         }
    108       }
    109     }
    110 
    111     // Possibly allocate an arguments object.
    112     Variable* arguments = scope()->arguments()->AsVariable();
    113     if (arguments != NULL) {
    114       // Arguments object must be allocated after the context object, in
    115       // case the "arguments" or ".arguments" variables are in the context.
    116       Comment cmnt(masm_, "[ Allocate arguments object");
    117       if (function_in_register) {
    118         __ push(rdi);
    119       } else {
    120         __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
    121       }
    122       // The receiver is just before the parameters on the caller's stack.
    123       int offset = scope()->num_parameters() * kPointerSize;
    124       __ lea(rdx,
    125              Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset));
    126       __ push(rdx);
    127       __ Push(Smi::FromInt(scope()->num_parameters()));
    128       // Arguments to ArgumentsAccessStub:
    129       //   function, receiver address, parameter count.
    130       // The stub will rewrite receiver and parameter count if the previous
    131       // stack frame was an arguments adapter frame.
    132       ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
    133       __ CallStub(&stub);
    134       // Store new arguments object in both "arguments" and ".arguments" slots.
    135       __ movq(rcx, rax);
    136       Move(arguments->slot(), rax, rbx, rdx);
    137       Slot* dot_arguments_slot =
    138           scope()->arguments_shadow()->AsVariable()->slot();
    139       Move(dot_arguments_slot, rcx, rbx, rdx);
    140     }
    141   }
    142 
    143   { Comment cmnt(masm_, "[ Declarations");
    144     VisitDeclarations(scope()->declarations());
    145   }
    146 
    147   { Comment cmnt(masm_, "[ Stack check");
    148     Label ok;
    149     __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
    150     __ j(above_equal, &ok);
    151     StackCheckStub stub;
    152     __ CallStub(&stub);
    153     __ bind(&ok);
    154   }
    155 
    156   if (FLAG_trace) {
    157     __ CallRuntime(Runtime::kTraceEnter, 0);
    158   }
    159 
    160   { Comment cmnt(masm_, "[ Body");
    161     ASSERT(loop_depth() == 0);
    162     VisitStatements(function()->body());
    163     ASSERT(loop_depth() == 0);
    164   }
    165 
    166   { Comment cmnt(masm_, "[ return <undefined>;");
    167     // Emit a 'return undefined' in case control fell off the end of the body.
    168     __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
    169     EmitReturnSequence(function()->end_position());
    170   }
    171 }
    172 
    173 
    174 void FullCodeGenerator::EmitReturnSequence(int position) {
    175   Comment cmnt(masm_, "[ Return sequence");
    176   if (return_label_.is_bound()) {
    177     __ jmp(&return_label_);
    178   } else {
    179     __ bind(&return_label_);
    180     if (FLAG_trace) {
    181       __ push(rax);
    182       __ CallRuntime(Runtime::kTraceExit, 1);
    183     }
    184 #ifdef DEBUG
    185     // Add a label for checking the size of the code used for returning.
    186     Label check_exit_codesize;
    187     masm_->bind(&check_exit_codesize);
    188 #endif
    189     CodeGenerator::RecordPositions(masm_, position);
    190     __ RecordJSReturn();
    191     // Do not use the leave instruction here because it is too short to
    192     // patch with the code required by the debugger.
    193     __ movq(rsp, rbp);
    194     __ pop(rbp);
    195     __ ret((scope()->num_parameters() + 1) * kPointerSize);
    196 #ifdef ENABLE_DEBUGGER_SUPPORT
    197     // Add padding that will be overwritten by a debugger breakpoint.  We
    198     // have just generated "movq rsp, rbp; pop rbp; ret k" with length 7
    199     // (3 + 1 + 3).
    200     const int kPadding = Assembler::kJSReturnSequenceLength - 7;
    201     for (int i = 0; i < kPadding; ++i) {
    202       masm_->int3();
    203     }
    204     // Check that the size of the code used for returning matches what is
    205     // expected by the debugger.
    206     ASSERT_EQ(Assembler::kJSReturnSequenceLength,
    207             masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
    208 #endif
    209   }
    210 }
    211 
    212 
    213 void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
    214   switch (context) {
    215     case Expression::kUninitialized:
    216       UNREACHABLE();
    217 
    218     case Expression::kEffect:
    219       // Nothing to do.
    220       break;
    221 
    222     case Expression::kValue:
    223       // Move value into place.
    224       switch (location_) {
    225         case kAccumulator:
    226           if (!reg.is(result_register())) __ movq(result_register(), reg);
    227           break;
    228         case kStack:
    229           __ push(reg);
    230           break;
    231       }
    232       break;
    233 
    234     case Expression::kTest:
    235       // For simplicity we always test the accumulator register.
    236       if (!reg.is(result_register())) __ movq(result_register(), reg);
    237       DoTest(context);
    238       break;
    239 
    240     case Expression::kValueTest:
    241     case Expression::kTestValue:
    242       if (!reg.is(result_register())) __ movq(result_register(), reg);
    243       switch (location_) {
    244         case kAccumulator:
    245           break;
    246         case kStack:
    247           __ push(result_register());
    248           break;
    249       }
    250       DoTest(context);
    251       break;
    252   }
    253 }
    254 
    255 
    256 void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
    257   switch (context) {
    258     case Expression::kUninitialized:
    259       UNREACHABLE();
    260     case Expression::kEffect:
    261       // Nothing to do.
    262       break;
    263     case Expression::kValue: {
    264       MemOperand slot_operand = EmitSlotSearch(slot, result_register());
    265       switch (location_) {
    266         case kAccumulator:
    267           __ movq(result_register(), slot_operand);
    268           break;
    269         case kStack:
    270           // Memory operands can be pushed directly.
    271           __ push(slot_operand);
    272           break;
    273       }
    274       break;
    275     }
    276 
    277     case Expression::kTest:
    278       Move(result_register(), slot);
    279       DoTest(context);
    280       break;
    281 
    282     case Expression::kValueTest:
    283     case Expression::kTestValue:
    284       Move(result_register(), slot);
    285       switch (location_) {
    286         case kAccumulator:
    287           break;
    288         case kStack:
    289           __ push(result_register());
    290           break;
    291       }
    292       DoTest(context);
    293       break;
    294   }
    295 }
    296 
    297 
    298 void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
    299   switch (context) {
    300     case Expression::kUninitialized:
    301       UNREACHABLE();
    302     case Expression::kEffect:
    303       // Nothing to do.
    304       break;
    305     case Expression::kValue:
    306       switch (location_) {
    307         case kAccumulator:
    308           __ Move(result_register(), lit->handle());
    309           break;
    310         case kStack:
    311           __ Push(lit->handle());
    312           break;
    313       }
    314       break;
    315 
    316     case Expression::kTest:
    317       __ Move(result_register(), lit->handle());
    318       DoTest(context);
    319       break;
    320 
    321     case Expression::kValueTest:
    322     case Expression::kTestValue:
    323       __ Move(result_register(), lit->handle());
    324       switch (location_) {
    325         case kAccumulator:
    326           break;
    327         case kStack:
    328           __ push(result_register());
    329           break;
    330       }
    331       DoTest(context);
    332       break;
    333   }
    334 }
    335 
    336 
    337 void FullCodeGenerator::ApplyTOS(Expression::Context context) {
    338   switch (context) {
    339     case Expression::kUninitialized:
    340       UNREACHABLE();
    341 
    342     case Expression::kEffect:
    343       __ Drop(1);
    344       break;
    345 
    346     case Expression::kValue:
    347       switch (location_) {
    348         case kAccumulator:
    349           __ pop(result_register());
    350           break;
    351         case kStack:
    352           break;
    353       }
    354       break;
    355 
    356     case Expression::kTest:
    357       __ pop(result_register());
    358       DoTest(context);
    359       break;
    360 
    361     case Expression::kValueTest:
    362     case Expression::kTestValue:
    363       switch (location_) {
    364         case kAccumulator:
    365           __ pop(result_register());
    366           break;
    367         case kStack:
    368           __ movq(result_register(), Operand(rsp, 0));
    369           break;
    370       }
    371       DoTest(context);
    372       break;
    373   }
    374 }
    375 
    376 
    377 void FullCodeGenerator::DropAndApply(int count,
    378                                      Expression::Context context,
    379                                      Register reg) {
    380   ASSERT(count > 0);
    381   ASSERT(!reg.is(rsp));
    382   switch (context) {
    383     case Expression::kUninitialized:
    384       UNREACHABLE();
    385 
    386     case Expression::kEffect:
    387       __ Drop(count);
    388       break;
    389 
    390     case Expression::kValue:
    391       switch (location_) {
    392         case kAccumulator:
    393           __ Drop(count);
    394           if (!reg.is(result_register())) __ movq(result_register(), reg);
    395           break;
    396         case kStack:
    397           if (count > 1) __ Drop(count - 1);
    398           __ movq(Operand(rsp, 0), reg);
    399           break;
    400       }
    401       break;
    402 
    403     case Expression::kTest:
    404       __ Drop(count);
    405       if (!reg.is(result_register())) __ movq(result_register(), reg);
    406       DoTest(context);
    407       break;
    408 
    409     case Expression::kValueTest:
    410     case Expression::kTestValue:
    411       switch (location_) {
    412         case kAccumulator:
    413           __ Drop(count);
    414           if (!reg.is(result_register())) __ movq(result_register(), reg);
    415           break;
    416         case kStack:
    417           if (count > 1) __ Drop(count - 1);
    418           __ movq(result_register(), reg);
    419           __ movq(Operand(rsp, 0), result_register());
    420           break;
    421       }
    422       DoTest(context);
    423       break;
    424   }
    425 }
    426 
    427 
    428 void FullCodeGenerator::Apply(Expression::Context context,
    429                               Label* materialize_true,
    430                               Label* materialize_false) {
    431   switch (context) {
    432     case Expression::kUninitialized:
    433 
    434     case Expression::kEffect:
    435       ASSERT_EQ(materialize_true, materialize_false);
    436       __ bind(materialize_true);
    437       break;
    438 
    439     case Expression::kValue: {
    440       Label done;
    441       switch (location_) {
    442         case kAccumulator:
    443           __ bind(materialize_true);
    444           __ Move(result_register(), Factory::true_value());
    445           __ jmp(&done);
    446           __ bind(materialize_false);
    447           __ Move(result_register(), Factory::false_value());
    448           break;
    449         case kStack:
    450           __ bind(materialize_true);
    451           __ Push(Factory::true_value());
    452           __ jmp(&done);
    453           __ bind(materialize_false);
    454           __ Push(Factory::false_value());
    455           break;
    456       }
    457       __ bind(&done);
    458       break;
    459     }
    460 
    461     case Expression::kTest:
    462       break;
    463 
    464     case Expression::kValueTest:
    465       __ bind(materialize_true);
    466       switch (location_) {
    467         case kAccumulator:
    468           __ Move(result_register(), Factory::true_value());
    469           break;
    470         case kStack:
    471           __ Push(Factory::true_value());
    472           break;
    473       }
    474       __ jmp(true_label_);
    475       break;
    476 
    477     case Expression::kTestValue:
    478       __ bind(materialize_false);
    479       switch (location_) {
    480         case kAccumulator:
    481           __ Move(result_register(), Factory::false_value());
    482           break;
    483         case kStack:
    484           __ Push(Factory::false_value());
    485           break;
    486       }
    487       __ jmp(false_label_);
    488       break;
    489   }
    490 }
    491 
    492 
    493 void FullCodeGenerator::DoTest(Expression::Context context) {
    494   // The value to test is in the accumulator.  If the value might be needed
    495   // on the stack (value/test and test/value contexts with a stack location
    496   // desired), then the value is already duplicated on the stack.
    497   ASSERT_NE(NULL, true_label_);
    498   ASSERT_NE(NULL, false_label_);
    499 
    500   // In value/test and test/value expression contexts with stack as the
    501   // desired location, there is already an extra value on the stack.  Use a
    502   // label to discard it if unneeded.
    503   Label discard;
    504   Label* if_true = true_label_;
    505   Label* if_false = false_label_;
    506   switch (context) {
    507     case Expression::kUninitialized:
    508     case Expression::kEffect:
    509     case Expression::kValue:
    510       UNREACHABLE();
    511     case Expression::kTest:
    512       break;
    513     case Expression::kValueTest:
    514       switch (location_) {
    515         case kAccumulator:
    516           break;
    517         case kStack:
    518           if_false = &discard;
    519           break;
    520       }
    521       break;
    522     case Expression::kTestValue:
    523       switch (location_) {
    524         case kAccumulator:
    525           break;
    526         case kStack:
    527           if_true = &discard;
    528           break;
    529       }
    530       break;
    531   }
    532 
    533   // Emit the inlined tests assumed by the stub.
    534   __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
    535   __ j(equal, if_false);
    536   __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
    537   __ j(equal, if_true);
    538   __ CompareRoot(result_register(), Heap::kFalseValueRootIndex);
    539   __ j(equal, if_false);
    540   ASSERT_EQ(0, kSmiTag);
    541   __ SmiCompare(result_register(), Smi::FromInt(0));
    542   __ j(equal, if_false);
    543   Condition is_smi = masm_->CheckSmi(result_register());
    544   __ j(is_smi, if_true);
    545 
    546   // Save a copy of the value if it may be needed and isn't already saved.
    547   switch (context) {
    548     case Expression::kUninitialized:
    549     case Expression::kEffect:
    550     case Expression::kValue:
    551       UNREACHABLE();
    552     case Expression::kTest:
    553       break;
    554     case Expression::kValueTest:
    555       switch (location_) {
    556         case kAccumulator:
    557           __ push(result_register());
    558           break;
    559         case kStack:
    560           break;
    561       }
    562       break;
    563     case Expression::kTestValue:
    564       switch (location_) {
    565         case kAccumulator:
    566           __ push(result_register());
    567           break;
    568         case kStack:
    569           break;
    570       }
    571       break;
    572   }
    573 
    574   // Call the ToBoolean stub for all other cases.
    575   ToBooleanStub stub;
    576   __ push(result_register());
    577   __ CallStub(&stub);
    578   __ testq(rax, rax);
    579 
    580   // The stub returns nonzero for true.  Complete based on the context.
    581   switch (context) {
    582     case Expression::kUninitialized:
    583     case Expression::kEffect:
    584     case Expression::kValue:
    585       UNREACHABLE();
    586 
    587     case Expression::kTest:
    588       __ j(not_zero, true_label_);
    589       __ jmp(false_label_);
    590       break;
    591 
    592     case Expression::kValueTest:
    593       switch (location_) {
    594         case kAccumulator:
    595           __ j(zero, &discard);
    596           __ pop(result_register());
    597           __ jmp(true_label_);
    598           break;
    599         case kStack:
    600           __ j(not_zero, true_label_);
    601           break;
    602       }
    603       __ bind(&discard);
    604       __ Drop(1);
    605       __ jmp(false_label_);
    606       break;
    607 
    608     case Expression::kTestValue:
    609       switch (location_) {
    610         case kAccumulator:
    611           __ j(not_zero, &discard);
    612           __ pop(result_register());
    613           __ jmp(false_label_);
    614           break;
    615         case kStack:
    616           __ j(zero, false_label_);
    617           break;
    618       }
    619       __ bind(&discard);
    620       __ Drop(1);
    621       __ jmp(true_label_);
    622       break;
    623   }
    624 }
    625 
    626 
    627 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
    628   switch (slot->type()) {
    629     case Slot::PARAMETER:
    630     case Slot::LOCAL:
    631       return Operand(rbp, SlotOffset(slot));
    632     case Slot::CONTEXT: {
    633       int context_chain_length =
    634           scope()->ContextChainLength(slot->var()->scope());
    635       __ LoadContext(scratch, context_chain_length);
    636       return CodeGenerator::ContextOperand(scratch, slot->index());
    637     }
    638     case Slot::LOOKUP:
    639       UNREACHABLE();
    640   }
    641   UNREACHABLE();
    642   return Operand(rax, 0);
    643 }
    644 
    645 
    646 void FullCodeGenerator::Move(Register destination, Slot* source) {
    647   MemOperand location = EmitSlotSearch(source, destination);
    648   __ movq(destination, location);
    649 }
    650 
    651 
    652 void FullCodeGenerator::Move(Slot* dst,
    653                              Register src,
    654                              Register scratch1,
    655                              Register scratch2) {
    656   ASSERT(dst->type() != Slot::LOOKUP);  // Not yet implemented.
    657   ASSERT(!scratch1.is(src) && !scratch2.is(src));
    658   MemOperand location = EmitSlotSearch(dst, scratch1);
    659   __ movq(location, src);
    660   // Emit the write barrier code if the location is in the heap.
    661   if (dst->type() == Slot::CONTEXT) {
    662     int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
    663     __ RecordWrite(scratch1, offset, src, scratch2);
    664   }
    665 }
    666 
    667 
    668 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
    669   Comment cmnt(masm_, "[ Declaration");
    670   Variable* var = decl->proxy()->var();
    671   ASSERT(var != NULL);  // Must have been resolved.
    672   Slot* slot = var->slot();
    673   Property* prop = var->AsProperty();
    674 
    675   if (slot != NULL) {
    676     switch (slot->type()) {
    677       case Slot::PARAMETER:
    678       case Slot::LOCAL:
    679         if (decl->mode() == Variable::CONST) {
    680           __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
    681           __ movq(Operand(rbp, SlotOffset(slot)), kScratchRegister);
    682         } else if (decl->fun() != NULL) {
    683           VisitForValue(decl->fun(), kAccumulator);
    684           __ movq(Operand(rbp, SlotOffset(slot)), result_register());
    685         }
    686         break;
    687 
    688       case Slot::CONTEXT:
    689         // We bypass the general EmitSlotSearch because we know more about
    690         // this specific context.
    691 
    692         // The variable in the decl always resides in the current context.
    693         ASSERT_EQ(0, scope()->ContextChainLength(var->scope()));
    694         if (FLAG_debug_code) {
    695           // Check if we have the correct context pointer.
    696           __ movq(rbx,
    697                   CodeGenerator::ContextOperand(rsi, Context::FCONTEXT_INDEX));
    698           __ cmpq(rbx, rsi);
    699           __ Check(equal, "Unexpected declaration in current context.");
    700         }
    701         if (decl->mode() == Variable::CONST) {
    702           __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
    703           __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
    704                   kScratchRegister);
    705           // No write barrier since the hole value is in old space.
    706         } else if (decl->fun() != NULL) {
    707           VisitForValue(decl->fun(), kAccumulator);
    708           __ movq(CodeGenerator::ContextOperand(rsi, slot->index()),
    709                   result_register());
    710           int offset = Context::SlotOffset(slot->index());
    711           __ movq(rbx, rsi);
    712           __ RecordWrite(rbx, offset, result_register(), rcx);
    713         }
    714         break;
    715 
    716       case Slot::LOOKUP: {
    717         __ push(rsi);
    718         __ Push(var->name());
    719         // Declaration nodes are always introduced in one of two modes.
    720         ASSERT(decl->mode() == Variable::VAR ||
    721                decl->mode() == Variable::CONST);
    722         PropertyAttributes attr =
    723             (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
    724         __ Push(Smi::FromInt(attr));
    725         // Push initial value, if any.
    726         // Note: For variables we must not push an initial value (such as
    727         // 'undefined') because we may have a (legal) redeclaration and we
    728         // must not destroy the current value.
    729         if (decl->mode() == Variable::CONST) {
    730           __ PushRoot(Heap::kTheHoleValueRootIndex);
    731         } else if (decl->fun() != NULL) {
    732           VisitForValue(decl->fun(), kStack);
    733         } else {
    734           __ Push(Smi::FromInt(0));  // no initial value!
    735         }
    736         __ CallRuntime(Runtime::kDeclareContextSlot, 4);
    737         break;
    738       }
    739     }
    740 
    741   } else if (prop != NULL) {
    742     if (decl->fun() != NULL || decl->mode() == Variable::CONST) {
    743       // We are declaring a function or constant that rewrites to a
    744       // property.  Use (keyed) IC to set the initial value.
    745       VisitForValue(prop->obj(), kStack);
    746       VisitForValue(prop->key(), kStack);
    747 
    748       if (decl->fun() != NULL) {
    749         VisitForValue(decl->fun(), kAccumulator);
    750       } else {
    751         __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
    752       }
    753 
    754       Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
    755       __ call(ic, RelocInfo::CODE_TARGET);
    756       // Absence of a test rax instruction following the call
    757       // indicates that none of the load was inlined.
    758       __ nop();
    759 
    760       // Value in rax is ignored (declarations are statements).  Receiver
    761       // and key on stack are discarded.
    762       __ Drop(2);
    763     }
    764   }
    765 }
    766 
    767 
    768 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
    769   // Call the runtime to declare the globals.
    770   __ push(rsi);  // The context is the first argument.
    771   __ Push(pairs);
    772   __ Push(Smi::FromInt(is_eval() ? 1 : 0));
    773   __ CallRuntime(Runtime::kDeclareGlobals, 3);
    774   // Return value is ignored.
    775 }
    776 
    777 
    778 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
    779   Comment cmnt(masm_, "[ FunctionLiteral");
    780 
    781   // Build the function boilerplate and instantiate it.
    782   Handle<JSFunction> boilerplate =
    783       Compiler::BuildBoilerplate(expr, script(), this);
    784   if (HasStackOverflow()) return;
    785 
    786   ASSERT(boilerplate->IsBoilerplate());
    787 
    788   // Create a new closure.
    789   __ push(rsi);
    790   __ Push(boilerplate);
    791   __ CallRuntime(Runtime::kNewClosure, 2);
    792   Apply(context_, rax);
    793 }
    794 
    795 
    796 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
    797   Comment cmnt(masm_, "[ VariableProxy");
    798   EmitVariableLoad(expr->var(), context_);
    799 }
    800 
    801 
    802 void FullCodeGenerator::EmitVariableLoad(Variable* var,
    803                                          Expression::Context context) {
    804   // Four cases: non-this global variables, lookup slots, all other
    805   // types of slots, and parameters that rewrite to explicit property
    806   // accesses on the arguments object.
    807   Slot* slot = var->slot();
    808   Property* property = var->AsProperty();
    809 
    810   if (var->is_global() && !var->is_this()) {
    811     Comment cmnt(masm_, "Global variable");
    812     // Use inline caching. Variable name is passed in rcx and the global
    813     // object on the stack.
    814     __ push(CodeGenerator::GlobalObject());
    815     __ Move(rcx, var->name());
    816     Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
    817     __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
    818     // A test rax instruction following the call is used by the IC to
    819     // indicate that the inobject property case was inlined.  Ensure there
    820     // is no test rax instruction here.
    821     __ nop();
    822     DropAndApply(1, context, rax);
    823 
    824   } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
    825     Comment cmnt(masm_, "Lookup slot");
    826     __ push(rsi);  // Context.
    827     __ Push(var->name());
    828     __ CallRuntime(Runtime::kLoadContextSlot, 2);
    829     Apply(context, rax);
    830 
    831   } else if (slot != NULL) {
    832     Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
    833                             ? "Context slot"
    834                             : "Stack slot");
    835     Apply(context, slot);
    836 
    837   } else {
    838     Comment cmnt(masm_, "Rewritten parameter");
    839     ASSERT_NOT_NULL(property);
    840     // Rewritten parameter accesses are of the form "slot[literal]".
    841 
    842     // Assert that the object is in a slot.
    843     Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
    844     ASSERT_NOT_NULL(object_var);
    845     Slot* object_slot = object_var->slot();
    846     ASSERT_NOT_NULL(object_slot);
    847 
    848     // Load the object.
    849     MemOperand object_loc = EmitSlotSearch(object_slot, rax);
    850     __ push(object_loc);
    851 
    852     // Assert that the key is a smi.
    853     Literal* key_literal = property->key()->AsLiteral();
    854     ASSERT_NOT_NULL(key_literal);
    855     ASSERT(key_literal->handle()->IsSmi());
    856 
    857     // Load the key.
    858     __ Push(key_literal->handle());
    859 
    860     // Do a keyed property load.
    861     Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
    862     __ call(ic, RelocInfo::CODE_TARGET);
    863     // Notice: We must not have a "test rax, ..." instruction after the
    864     // call. It is treated specially by the LoadIC code.
    865     __ nop();
    866     // Drop key and object left on the stack by IC, and push the result.
    867     DropAndApply(2, context, rax);
    868   }
    869 }
    870 
    871 
    872 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
    873   Comment cmnt(masm_, "[ RegExpLiteral");
    874   Label done;
    875   // Registers will be used as follows:
    876   // rdi = JS function.
    877   // rbx = literals array.
    878   // rax = regexp literal.
    879   __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
    880   __ movq(rbx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
    881   int literal_offset =
    882     FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
    883   __ movq(rax, FieldOperand(rbx, literal_offset));
    884   __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
    885   __ j(not_equal, &done);
    886   // Create regexp literal using runtime function
    887   // Result will be in rax.
    888   __ push(rbx);
    889   __ Push(Smi::FromInt(expr->literal_index()));
    890   __ Push(expr->pattern());
    891   __ Push(expr->flags());
    892   __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
    893   __ bind(&done);
    894   Apply(context_, rax);
    895 }
    896 
    897 
    898 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
    899   Comment cmnt(masm_, "[ ObjectLiteral");
    900   __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
    901   __ push(FieldOperand(rdi, JSFunction::kLiteralsOffset));
    902   __ Push(Smi::FromInt(expr->literal_index()));
    903   __ Push(expr->constant_properties());
    904   if (expr->depth() > 1) {
    905     __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
    906   } else {
    907     __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
    908   }
    909 
    910   // If result_saved is true the result is on top of the stack.  If
    911   // result_saved is false the result is in rax.
    912   bool result_saved = false;
    913 
    914   for (int i = 0; i < expr->properties()->length(); i++) {
    915     ObjectLiteral::Property* property = expr->properties()->at(i);
    916     if (property->IsCompileTimeValue()) continue;
    917 
    918     Literal* key = property->key();
    919     Expression* value = property->value();
    920     if (!result_saved) {
    921       __ push(rax);  // Save result on the stack
    922       result_saved = true;
    923     }
    924     switch (property->kind()) {
    925       case ObjectLiteral::Property::CONSTANT:
    926         UNREACHABLE();
    927       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
    928         ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
    929         // Fall through.
    930       case ObjectLiteral::Property::COMPUTED:
    931         if (key->handle()->IsSymbol()) {
    932           VisitForValue(value, kAccumulator);
    933           __ Move(rcx, key->handle());
    934           __ movq(rdx, Operand(rsp, 0));
    935           Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
    936           __ call(ic, RelocInfo::CODE_TARGET);
    937           __ nop();
    938           break;
    939         }
    940         // Fall through.
    941       case ObjectLiteral::Property::PROTOTYPE:
    942         __ push(Operand(rsp, 0));  // Duplicate receiver.
    943         VisitForValue(key, kStack);
    944         VisitForValue(value, kStack);
    945         __ CallRuntime(Runtime::kSetProperty, 3);
    946         break;
    947       case ObjectLiteral::Property::SETTER:
    948       case ObjectLiteral::Property::GETTER:
    949         __ push(Operand(rsp, 0));  // Duplicate receiver.
    950         VisitForValue(key, kStack);
    951         __ Push(property->kind() == ObjectLiteral::Property::SETTER ?
    952                 Smi::FromInt(1) :
    953                 Smi::FromInt(0));
    954         VisitForValue(value, kStack);
    955         __ CallRuntime(Runtime::kDefineAccessor, 4);
    956         break;
    957     }
    958   }
    959 
    960   if (result_saved) {
    961     ApplyTOS(context_);
    962   } else {
    963     Apply(context_, rax);
    964   }
    965 }
    966 
    967 
    968 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
    969   Comment cmnt(masm_, "[ ArrayLiteral");
    970   __ movq(rbx, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
    971   __ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
    972   __ Push(Smi::FromInt(expr->literal_index()));
    973   __ Push(expr->constant_elements());
    974   if (expr->depth() > 1) {
    975     __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
    976   } else {
    977     __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
    978   }
    979 
    980   bool result_saved = false;  // Is the result saved to the stack?
    981 
    982   // Emit code to evaluate all the non-constant subexpressions and to store
    983   // them into the newly cloned array.
    984   ZoneList<Expression*>* subexprs = expr->values();
    985   for (int i = 0, len = subexprs->length(); i < len; i++) {
    986     Expression* subexpr = subexprs->at(i);
    987     // If the subexpression is a literal or a simple materialized literal it
    988     // is already set in the cloned array.
    989     if (subexpr->AsLiteral() != NULL ||
    990         CompileTimeValue::IsCompileTimeValue(subexpr)) {
    991       continue;
    992     }
    993 
    994     if (!result_saved) {
    995       __ push(rax);
    996       result_saved = true;
    997     }
    998     VisitForValue(subexpr, kAccumulator);
    999 
   1000     // Store the subexpression value in the array's elements.
   1001     __ movq(rbx, Operand(rsp, 0));  // Copy of array literal.
   1002     __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset));
   1003     int offset = FixedArray::kHeaderSize + (i * kPointerSize);
   1004     __ movq(FieldOperand(rbx, offset), result_register());
   1005 
   1006     // Update the write barrier for the array store.
   1007     __ RecordWrite(rbx, offset, result_register(), rcx);
   1008   }
   1009 
   1010   if (result_saved) {
   1011     ApplyTOS(context_);
   1012   } else {
   1013     Apply(context_, rax);
   1014   }
   1015 }
   1016 
   1017 
   1018 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
   1019   Comment cmnt(masm_, "[ Assignment");
   1020   ASSERT(expr->op() != Token::INIT_CONST);
   1021   // Left-hand side can only be a property, a global or a (parameter or local)
   1022   // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
   1023   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
   1024   LhsKind assign_type = VARIABLE;
   1025   Property* prop = expr->target()->AsProperty();
   1026   if (prop != NULL) {
   1027     assign_type =
   1028         (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
   1029   }
   1030 
   1031   // Evaluate LHS expression.
   1032   switch (assign_type) {
   1033     case VARIABLE:
   1034       // Nothing to do here.
   1035       break;
   1036     case NAMED_PROPERTY:
   1037       if (expr->is_compound()) {
   1038         // We need the receiver both on the stack and in the accumulator.
   1039         VisitForValue(prop->obj(), kAccumulator);
   1040         __ push(result_register());
   1041       } else {
   1042         VisitForValue(prop->obj(), kStack);
   1043       }
   1044       break;
   1045     case KEYED_PROPERTY:
   1046       VisitForValue(prop->obj(), kStack);
   1047       VisitForValue(prop->key(), kStack);
   1048       break;
   1049   }
   1050 
   1051   // If we have a compound assignment: Get value of LHS expression and
   1052   // store in on top of the stack.
   1053   if (expr->is_compound()) {
   1054     Location saved_location = location_;
   1055     location_ = kStack;
   1056     switch (assign_type) {
   1057       case VARIABLE:
   1058         EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
   1059                          Expression::kValue);
   1060         break;
   1061       case NAMED_PROPERTY:
   1062         EmitNamedPropertyLoad(prop);
   1063         __ push(result_register());
   1064         break;
   1065       case KEYED_PROPERTY:
   1066         EmitKeyedPropertyLoad(prop);
   1067         __ push(result_register());
   1068         break;
   1069     }
   1070     location_ = saved_location;
   1071   }
   1072 
   1073   // Evaluate RHS expression.
   1074   Expression* rhs = expr->value();
   1075   VisitForValue(rhs, kAccumulator);
   1076 
   1077   // If we have a compound assignment: Apply operator.
   1078   if (expr->is_compound()) {
   1079     Location saved_location = location_;
   1080     location_ = kAccumulator;
   1081     EmitBinaryOp(expr->binary_op(), Expression::kValue);
   1082     location_ = saved_location;
   1083   }
   1084 
   1085   // Record source position before possible IC call.
   1086   SetSourcePosition(expr->position());
   1087 
   1088   // Store the value.
   1089   switch (assign_type) {
   1090     case VARIABLE:
   1091       EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
   1092                              context_);
   1093       break;
   1094     case NAMED_PROPERTY:
   1095       EmitNamedPropertyAssignment(expr);
   1096       break;
   1097     case KEYED_PROPERTY:
   1098       EmitKeyedPropertyAssignment(expr);
   1099       break;
   1100   }
   1101 }
   1102 
   1103 
   1104 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
   1105   SetSourcePosition(prop->position());
   1106   Literal* key = prop->key()->AsLiteral();
   1107   __ Move(rcx, key->handle());
   1108   Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   1109   __ Call(ic, RelocInfo::CODE_TARGET);
   1110   __ nop();
   1111 }
   1112 
   1113 
   1114 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
   1115   SetSourcePosition(prop->position());
   1116   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
   1117   __ Call(ic, RelocInfo::CODE_TARGET);
   1118   __ nop();
   1119 }
   1120 
   1121 
   1122 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
   1123                                      Expression::Context context) {
   1124   __ push(result_register());
   1125   GenericBinaryOpStub stub(op,
   1126                            NO_OVERWRITE,
   1127                            NO_GENERIC_BINARY_FLAGS);
   1128   __ CallStub(&stub);
   1129   Apply(context, rax);
   1130 }
   1131 
   1132 
   1133 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
   1134                                                Expression::Context context) {
   1135   // Three main cases: non-this global variables, lookup slots, and
   1136   // all other types of slots.  Left-hand-side parameters that rewrite
   1137   // to explicit property accesses do not reach here.
   1138   ASSERT(var != NULL);
   1139   ASSERT(var->is_global() || var->slot() != NULL);
   1140   Slot* slot = var->slot();
   1141   if (var->is_global()) {
   1142     ASSERT(!var->is_this());
   1143     // Assignment to a global variable.  Use inline caching for the
   1144     // assignment.  Right-hand-side value is passed in rax, variable name in
   1145     // rcx, and the global object in rdx.
   1146     __ Move(rcx, var->name());
   1147     __ movq(rdx, CodeGenerator::GlobalObject());
   1148     Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
   1149     __ Call(ic, RelocInfo::CODE_TARGET);
   1150     Apply(context, rax);
   1151 
   1152   } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
   1153     __ push(result_register());  // Value.
   1154     __ push(rsi);  // Context.
   1155     __ Push(var->name());
   1156     __ CallRuntime(Runtime::kStoreContextSlot, 3);
   1157     Apply(context, rax);
   1158 
   1159   } else if (var->slot() != NULL) {
   1160     switch (slot->type()) {
   1161       case Slot::LOCAL:
   1162       case Slot::PARAMETER:
   1163         __ movq(Operand(rbp, SlotOffset(slot)), result_register());
   1164         break;
   1165 
   1166       case Slot::CONTEXT: {
   1167         MemOperand target = EmitSlotSearch(slot, rcx);
   1168         __ movq(target, result_register());
   1169 
   1170         // RecordWrite may destroy all its register arguments.
   1171         __ movq(rdx, result_register());
   1172         int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
   1173         __ RecordWrite(rcx, offset, rdx, rbx);
   1174         break;
   1175       }
   1176 
   1177       case Slot::LOOKUP:
   1178         UNREACHABLE();
   1179         break;
   1180     }
   1181     Apply(context, result_register());
   1182 
   1183   } else {
   1184     // Variables rewritten as properties are not treated as variables in
   1185     // assignments.
   1186     UNREACHABLE();
   1187   }
   1188 }
   1189 
   1190 
   1191 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
   1192   // Assignment to a property, using a named store IC.
   1193   Property* prop = expr->target()->AsProperty();
   1194   ASSERT(prop != NULL);
   1195   ASSERT(prop->key()->AsLiteral() != NULL);
   1196 
   1197   // If the assignment starts a block of assignments to the same object,
   1198   // change to slow case to avoid the quadratic behavior of repeatedly
   1199   // adding fast properties.
   1200   if (expr->starts_initialization_block()) {
   1201     __ push(result_register());
   1202     __ push(Operand(rsp, kPointerSize));  // Receiver is now under value.
   1203     __ CallRuntime(Runtime::kToSlowProperties, 1);
   1204     __ pop(result_register());
   1205   }
   1206 
   1207   // Record source code position before IC call.
   1208   SetSourcePosition(expr->position());
   1209   __ Move(rcx, prop->key()->AsLiteral()->handle());
   1210   if (expr->ends_initialization_block()) {
   1211     __ movq(rdx, Operand(rsp, 0));
   1212   } else {
   1213     __ pop(rdx);
   1214   }
   1215   Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
   1216   __ Call(ic, RelocInfo::CODE_TARGET);
   1217   __ nop();
   1218 
   1219   // If the assignment ends an initialization block, revert to fast case.
   1220   if (expr->ends_initialization_block()) {
   1221     __ push(rax);  // Result of assignment, saved even if not needed.
   1222     __ push(Operand(rsp, kPointerSize));  // Receiver is under value.
   1223     __ CallRuntime(Runtime::kToFastProperties, 1);
   1224     __ pop(rax);
   1225     DropAndApply(1, context_, rax);
   1226   } else {
   1227     Apply(context_, rax);
   1228   }
   1229 }
   1230 
   1231 
   1232 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   1233   // Assignment to a property, using a keyed store IC.
   1234 
   1235   // If the assignment starts a block of assignments to the same object,
   1236   // change to slow case to avoid the quadratic behavior of repeatedly
   1237   // adding fast properties.
   1238   if (expr->starts_initialization_block()) {
   1239     __ push(result_register());
   1240     // Receiver is now under the key and value.
   1241     __ push(Operand(rsp, 2 * kPointerSize));
   1242     __ CallRuntime(Runtime::kToSlowProperties, 1);
   1243     __ pop(result_register());
   1244   }
   1245 
   1246   // Record source code position before IC call.
   1247   SetSourcePosition(expr->position());
   1248   Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
   1249   __ Call(ic, RelocInfo::CODE_TARGET);
   1250   // This nop signals to the IC that there is no inlined code at the call
   1251   // site for it to patch.
   1252   __ nop();
   1253 
   1254   // If the assignment ends an initialization block, revert to fast case.
   1255   if (expr->ends_initialization_block()) {
   1256     __ push(rax);  // Result of assignment, saved even if not needed.
   1257     // Receiver is under the key and value.
   1258     __ push(Operand(rsp, 2 * kPointerSize));
   1259     __ CallRuntime(Runtime::kToFastProperties, 1);
   1260     __ pop(rax);
   1261   }
   1262 
   1263   // Receiver and key are still on stack.
   1264   DropAndApply(2, context_, rax);
   1265 }
   1266 
   1267 
   1268 void FullCodeGenerator::VisitProperty(Property* expr) {
   1269   Comment cmnt(masm_, "[ Property");
   1270   Expression* key = expr->key();
   1271 
   1272   // Evaluate receiver.
   1273   VisitForValue(expr->obj(), kStack);
   1274 
   1275   if (key->IsPropertyName()) {
   1276     EmitNamedPropertyLoad(expr);
   1277     // Drop receiver left on the stack by IC.
   1278     DropAndApply(1, context_, rax);
   1279   } else {
   1280     VisitForValue(expr->key(), kStack);
   1281     EmitKeyedPropertyLoad(expr);
   1282     // Drop key and receiver left on the stack by IC.
   1283     DropAndApply(2, context_, rax);
   1284   }
   1285 }
   1286 
   1287 
   1288 void FullCodeGenerator::EmitCallWithIC(Call* expr,
   1289                                        Handle<Object> name,
   1290                                        RelocInfo::Mode mode) {
   1291   // Code common for calls using the IC.
   1292   ZoneList<Expression*>* args = expr->arguments();
   1293   int arg_count = args->length();
   1294   for (int i = 0; i < arg_count; i++) {
   1295     VisitForValue(args->at(i), kStack);
   1296   }
   1297   __ Move(rcx, name);
   1298   // Record source position for debugger.
   1299   SetSourcePosition(expr->position());
   1300   // Call the IC initialization code.
   1301   InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
   1302   Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
   1303                                                          in_loop);
   1304   __ Call(ic, mode);
   1305   // Restore context register.
   1306   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
   1307   Apply(context_, rax);
   1308 }
   1309 
   1310 
   1311 void FullCodeGenerator::EmitCallWithStub(Call* expr) {
   1312   // Code common for calls using the call stub.
   1313   ZoneList<Expression*>* args = expr->arguments();
   1314   int arg_count = args->length();
   1315   for (int i = 0; i < arg_count; i++) {
   1316     VisitForValue(args->at(i), kStack);
   1317   }
   1318   // Record source position for debugger.
   1319   SetSourcePosition(expr->position());
   1320   CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
   1321   __ CallStub(&stub);
   1322   // Restore context register.
   1323   __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
   1324   // Discard the function left on TOS.
   1325   DropAndApply(1, context_, rax);
   1326 }
   1327 
   1328 
   1329 void FullCodeGenerator::VisitCall(Call* expr) {
   1330   Comment cmnt(masm_, "[ Call");
   1331   Expression* fun = expr->expression();
   1332   Variable* var = fun->AsVariableProxy()->AsVariable();
   1333 
   1334   if (var != NULL && var->is_possibly_eval()) {
   1335     // Call to the identifier 'eval'.
   1336     UNREACHABLE();
   1337   } else if (var != NULL && !var->is_this() && var->is_global()) {
   1338     // Call to a global variable.
   1339     // Push global object as receiver for the call IC lookup.
   1340     __ push(CodeGenerator::GlobalObject());
   1341     EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
   1342   } else if (var != NULL && var->slot() != NULL &&
   1343              var->slot()->type() == Slot::LOOKUP) {
   1344     // Call to a lookup slot.
   1345     UNREACHABLE();
   1346   } else if (fun->AsProperty() != NULL) {
   1347     // Call to an object property.
   1348     Property* prop = fun->AsProperty();
   1349     Literal* key = prop->key()->AsLiteral();
   1350     if (key != NULL && key->handle()->IsSymbol()) {
   1351       // Call to a named property, use call IC.
   1352       VisitForValue(prop->obj(), kStack);
   1353       EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
   1354     } else {
   1355       // Call to a keyed property, use keyed load IC followed by function
   1356       // call.
   1357       VisitForValue(prop->obj(), kStack);
   1358       VisitForValue(prop->key(), kStack);
   1359       // Record source code position for IC call.
   1360       SetSourcePosition(prop->position());
   1361       Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
   1362       __ call(ic, RelocInfo::CODE_TARGET);
   1363       // By emitting a nop we make sure that we do not have a "test rax,..."
   1364       // instruction after the call it is treated specially by the LoadIC code.
   1365       __ nop();
   1366       // Drop key left on the stack by IC.
   1367       __ Drop(1);
   1368       // Pop receiver.
   1369       __ pop(rbx);
   1370       // Push result (function).
   1371       __ push(rax);
   1372       // Push receiver object on stack.
   1373       if (prop->is_synthetic()) {
   1374         __ movq(rcx, CodeGenerator::GlobalObject());
   1375         __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
   1376       } else {
   1377         __ push(rbx);
   1378       }
   1379       EmitCallWithStub(expr);
   1380     }
   1381   } else {
   1382     // Call to some other expression.  If the expression is an anonymous
   1383     // function literal not called in a loop, mark it as one that should
   1384     // also use the fast code generator.
   1385     FunctionLiteral* lit = fun->AsFunctionLiteral();
   1386     if (lit != NULL &&
   1387         lit->name()->Equals(Heap::empty_string()) &&
   1388         loop_depth() == 0) {
   1389       lit->set_try_full_codegen(true);
   1390     }
   1391     VisitForValue(fun, kStack);
   1392     // Load global receiver object.
   1393     __ movq(rbx, CodeGenerator::GlobalObject());
   1394     __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
   1395     // Emit function call.
   1396     EmitCallWithStub(expr);
   1397   }
   1398 }
   1399 
   1400 
   1401 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   1402   Comment cmnt(masm_, "[ CallNew");
   1403   // According to ECMA-262, section 11.2.2, page 44, the function
   1404   // expression in new calls must be evaluated before the
   1405   // arguments.
   1406   // Push function on the stack.
   1407   VisitForValue(expr->expression(), kStack);
   1408 
   1409   // Push global object (receiver).
   1410   __ push(CodeGenerator::GlobalObject());
   1411 
   1412   // Push the arguments ("left-to-right") on the stack.
   1413   ZoneList<Expression*>* args = expr->arguments();
   1414   int arg_count = args->length();
   1415   for (int i = 0; i < arg_count; i++) {
   1416     VisitForValue(args->at(i), kStack);
   1417   }
   1418 
   1419   // Call the construct call builtin that handles allocation and
   1420   // constructor invocation.
   1421   SetSourcePosition(expr->position());
   1422 
   1423   // Load function, arg_count into rdi and rax.
   1424   __ Set(rax, arg_count);
   1425   // Function is in rsp[arg_count + 1].
   1426   __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
   1427 
   1428   Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
   1429   __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
   1430 
   1431   // Replace function on TOS with result in rax, or pop it.
   1432   DropAndApply(1, context_, rax);
   1433 }
   1434 
   1435 
   1436 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
   1437   Comment cmnt(masm_, "[ CallRuntime");
   1438   ZoneList<Expression*>* args = expr->arguments();
   1439 
   1440   if (expr->is_jsruntime()) {
   1441     // Prepare for calling JS runtime function.
   1442     __ movq(rax, CodeGenerator::GlobalObject());
   1443     __ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
   1444   }
   1445 
   1446   // Push the arguments ("left-to-right").
   1447   int arg_count = args->length();
   1448   for (int i = 0; i < arg_count; i++) {
   1449     VisitForValue(args->at(i), kStack);
   1450   }
   1451 
   1452   if (expr->is_jsruntime()) {
   1453     // Call the JS runtime function using a call IC.
   1454     __ Move(rcx, expr->name());
   1455     InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
   1456     Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
   1457     __ call(ic, RelocInfo::CODE_TARGET);
   1458     // Restore context register.
   1459     __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
   1460   } else {
   1461     __ CallRuntime(expr->function(), arg_count);
   1462   }
   1463   Apply(context_, rax);
   1464 }
   1465 
   1466 
   1467 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
   1468   switch (expr->op()) {
   1469     case Token::VOID: {
   1470       Comment cmnt(masm_, "[ UnaryOperation (VOID)");
   1471       VisitForEffect(expr->expression());
   1472       switch (context_) {
   1473         case Expression::kUninitialized:
   1474           UNREACHABLE();
   1475           break;
   1476         case Expression::kEffect:
   1477           break;
   1478         case Expression::kValue:
   1479           switch (location_) {
   1480             case kAccumulator:
   1481               __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
   1482               break;
   1483             case kStack:
   1484               __ PushRoot(Heap::kUndefinedValueRootIndex);
   1485               break;
   1486           }
   1487           break;
   1488         case Expression::kTestValue:
   1489           // Value is false so it's needed.
   1490           switch (location_) {
   1491             case kAccumulator:
   1492               __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
   1493               break;
   1494             case kStack:
   1495               __ PushRoot(Heap::kUndefinedValueRootIndex);
   1496               break;
   1497           }
   1498           // Fall through.
   1499         case Expression::kTest:
   1500         case Expression::kValueTest:
   1501           __ jmp(false_label_);
   1502           break;
   1503       }
   1504       break;
   1505     }
   1506 
   1507     case Token::NOT: {
   1508       Comment cmnt(masm_, "[ UnaryOperation (NOT)");
   1509       Label materialize_true, materialize_false, done;
   1510       // Initially assume a pure test context.  Notice that the labels are
   1511       // swapped.
   1512       Label* if_true = false_label_;
   1513       Label* if_false = true_label_;
   1514       switch (context_) {
   1515         case Expression::kUninitialized:
   1516           UNREACHABLE();
   1517           break;
   1518         case Expression::kEffect:
   1519           if_true = &done;
   1520           if_false = &done;
   1521           break;
   1522         case Expression::kValue:
   1523           if_true = &materialize_false;
   1524           if_false = &materialize_true;
   1525           break;
   1526         case Expression::kTest:
   1527           break;
   1528         case Expression::kValueTest:
   1529           if_false = &materialize_true;
   1530           break;
   1531         case Expression::kTestValue:
   1532           if_true = &materialize_false;
   1533           break;
   1534       }
   1535       VisitForControl(expr->expression(), if_true, if_false);
   1536       Apply(context_, if_false, if_true);  // Labels swapped.
   1537       break;
   1538     }
   1539 
   1540     case Token::TYPEOF: {
   1541       Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
   1542       VariableProxy* proxy = expr->expression()->AsVariableProxy();
   1543       if (proxy != NULL &&
   1544           !proxy->var()->is_this() &&
   1545           proxy->var()->is_global()) {
   1546         Comment cmnt(masm_, "Global variable");
   1547         __ push(CodeGenerator::GlobalObject());
   1548         __ Move(rcx, proxy->name());
   1549         Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   1550         // Use a regular load, not a contextual load, to avoid a reference
   1551         // error.
   1552         __ Call(ic, RelocInfo::CODE_TARGET);
   1553         __ movq(Operand(rsp, 0), rax);
   1554       } else if (proxy != NULL &&
   1555                  proxy->var()->slot() != NULL &&
   1556                  proxy->var()->slot()->type() == Slot::LOOKUP) {
   1557         __ push(rsi);
   1558         __ Push(proxy->name());
   1559         __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
   1560         __ push(rax);
   1561       } else {
   1562         // This expression cannot throw a reference error at the top level.
   1563         VisitForValue(expr->expression(), kStack);
   1564       }
   1565 
   1566       __ CallRuntime(Runtime::kTypeof, 1);
   1567       Apply(context_, rax);
   1568       break;
   1569     }
   1570 
   1571     case Token::ADD: {
   1572       Comment cmt(masm_, "[ UnaryOperation (ADD)");
   1573       VisitForValue(expr->expression(), kAccumulator);
   1574       Label no_conversion;
   1575       Condition is_smi = masm_->CheckSmi(result_register());
   1576       __ j(is_smi, &no_conversion);
   1577       __ push(result_register());
   1578       __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
   1579       __ bind(&no_conversion);
   1580       Apply(context_, result_register());
   1581       break;
   1582     }
   1583 
   1584     case Token::SUB: {
   1585       Comment cmt(masm_, "[ UnaryOperation (SUB)");
   1586       bool overwrite =
   1587           (expr->expression()->AsBinaryOperation() != NULL &&
   1588            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
   1589       GenericUnaryOpStub stub(Token::SUB, overwrite);
   1590       // GenericUnaryOpStub expects the argument to be in the
   1591       // accumulator register rax.
   1592       VisitForValue(expr->expression(), kAccumulator);
   1593       __ CallStub(&stub);
   1594       Apply(context_, rax);
   1595       break;
   1596     }
   1597 
   1598     case Token::BIT_NOT: {
   1599       Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
   1600       bool overwrite =
   1601           (expr->expression()->AsBinaryOperation() != NULL &&
   1602            expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
   1603       GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
   1604       // GenericUnaryOpStub expects the argument to be in the
   1605       // accumulator register rax.
   1606       VisitForValue(expr->expression(), kAccumulator);
   1607       // Avoid calling the stub for Smis.
   1608       Label smi, done;
   1609       Condition is_smi = masm_->CheckSmi(result_register());
   1610       __ j(is_smi, &smi);
   1611       // Non-smi: call stub leaving result in accumulator register.
   1612       __ CallStub(&stub);
   1613       __ jmp(&done);
   1614       // Perform operation directly on Smis.
   1615       __ bind(&smi);
   1616       __ SmiNot(result_register(), result_register());
   1617       __ bind(&done);
   1618       Apply(context_, result_register());
   1619       break;
   1620     }
   1621 
   1622     default:
   1623       UNREACHABLE();
   1624   }
   1625 }
   1626 
   1627 
   1628 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   1629   Comment cmnt(masm_, "[ CountOperation");
   1630 
   1631   // Expression can only be a property, a global or a (parameter or local)
   1632   // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
   1633   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
   1634   LhsKind assign_type = VARIABLE;
   1635   Property* prop = expr->expression()->AsProperty();
   1636   // In case of a property we use the uninitialized expression context
   1637   // of the key to detect a named property.
   1638   if (prop != NULL) {
   1639     assign_type =
   1640         (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
   1641   }
   1642 
   1643   // Evaluate expression and get value.
   1644   if (assign_type == VARIABLE) {
   1645     ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
   1646     Location saved_location = location_;
   1647     location_ = kAccumulator;
   1648     EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
   1649                      Expression::kValue);
   1650     location_ = saved_location;
   1651   } else  {
   1652     // Reserve space for result of postfix operation.
   1653     if (expr->is_postfix() && context_ != Expression::kEffect) {
   1654       __ Push(Smi::FromInt(0));
   1655     }
   1656     VisitForValue(prop->obj(), kStack);
   1657     if (assign_type == NAMED_PROPERTY) {
   1658       EmitNamedPropertyLoad(prop);
   1659     } else {
   1660       VisitForValue(prop->key(), kStack);
   1661       EmitKeyedPropertyLoad(prop);
   1662     }
   1663   }
   1664 
   1665   // Call ToNumber only if operand is not a smi.
   1666   Label no_conversion;
   1667   Condition is_smi;
   1668   is_smi = masm_->CheckSmi(rax);
   1669   __ j(is_smi, &no_conversion);
   1670   __ push(rax);
   1671   __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
   1672   __ bind(&no_conversion);
   1673 
   1674   // Save result for postfix expressions.
   1675   if (expr->is_postfix()) {
   1676     switch (context_) {
   1677       case Expression::kUninitialized:
   1678         UNREACHABLE();
   1679       case Expression::kEffect:
   1680         // Do not save result.
   1681         break;
   1682       case Expression::kValue:
   1683       case Expression::kTest:
   1684       case Expression::kValueTest:
   1685       case Expression::kTestValue:
   1686         // Save the result on the stack. If we have a named or keyed property
   1687         // we store the result under the receiver that is currently on top
   1688         // of the stack.
   1689         switch (assign_type) {
   1690           case VARIABLE:
   1691             __ push(rax);
   1692             break;
   1693           case NAMED_PROPERTY:
   1694             __ movq(Operand(rsp, kPointerSize), rax);
   1695             break;
   1696           case KEYED_PROPERTY:
   1697             __ movq(Operand(rsp, 2 * kPointerSize), rax);
   1698             break;
   1699         }
   1700         break;
   1701     }
   1702   }
   1703 
   1704   // Inline smi case if we are in a loop.
   1705   Label stub_call, done;
   1706   if (loop_depth() > 0) {
   1707     if (expr->op() == Token::INC) {
   1708       __ SmiAddConstant(rax, rax, Smi::FromInt(1));
   1709     } else {
   1710       __ SmiSubConstant(rax, rax, Smi::FromInt(1));
   1711     }
   1712     __ j(overflow, &stub_call);
   1713     // We could eliminate this smi check if we split the code at
   1714     // the first smi check before calling ToNumber.
   1715     is_smi = masm_->CheckSmi(rax);
   1716     __ j(is_smi, &done);
   1717     __ bind(&stub_call);
   1718     // Call stub. Undo operation first.
   1719     if (expr->op() == Token::INC) {
   1720       __ SmiSubConstant(rax, rax, Smi::FromInt(1));
   1721     } else {
   1722       __ SmiAddConstant(rax, rax, Smi::FromInt(1));
   1723     }
   1724   }
   1725   // Call stub for +1/-1.
   1726   GenericBinaryOpStub stub(expr->binary_op(),
   1727                            NO_OVERWRITE,
   1728                            NO_GENERIC_BINARY_FLAGS);
   1729   stub.GenerateCall(masm_, rax, Smi::FromInt(1));
   1730   __ bind(&done);
   1731 
   1732   // Store the value returned in rax.
   1733   switch (assign_type) {
   1734     case VARIABLE:
   1735       if (expr->is_postfix()) {
   1736         EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
   1737                                Expression::kEffect);
   1738         // For all contexts except kEffect: We have the result on
   1739         // top of the stack.
   1740         if (context_ != Expression::kEffect) {
   1741           ApplyTOS(context_);
   1742         }
   1743       } else {
   1744         EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
   1745                                context_);
   1746       }
   1747       break;
   1748     case NAMED_PROPERTY: {
   1749       __ Move(rcx, prop->key()->AsLiteral()->handle());
   1750       __ pop(rdx);
   1751       Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
   1752       __ call(ic, RelocInfo::CODE_TARGET);
   1753       // This nop signals to the IC that there is no inlined code at the call
   1754       // site for it to patch.
   1755       __ nop();
   1756       if (expr->is_postfix()) {
   1757         if (context_ != Expression::kEffect) {
   1758           ApplyTOS(context_);
   1759         }
   1760       } else {
   1761         Apply(context_, rax);
   1762       }
   1763       break;
   1764     }
   1765     case KEYED_PROPERTY: {
   1766       Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
   1767       __ call(ic, RelocInfo::CODE_TARGET);
   1768       // This nop signals to the IC that there is no inlined code at the call
   1769       // site for it to patch.
   1770       __ nop();
   1771       if (expr->is_postfix()) {
   1772         __ Drop(2);  // Result is on the stack under the key and the receiver.
   1773         if (context_ != Expression::kEffect) {
   1774           ApplyTOS(context_);
   1775         }
   1776       } else {
   1777         DropAndApply(2, context_, rax);
   1778       }
   1779       break;
   1780     }
   1781   }
   1782 }
   1783 
   1784 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
   1785   Comment cmnt(masm_, "[ BinaryOperation");
   1786   switch (expr->op()) {
   1787     case Token::COMMA:
   1788       VisitForEffect(expr->left());
   1789       Visit(expr->right());
   1790       break;
   1791 
   1792     case Token::OR:
   1793     case Token::AND:
   1794       EmitLogicalOperation(expr);
   1795       break;
   1796 
   1797     case Token::ADD:
   1798     case Token::SUB:
   1799     case Token::DIV:
   1800     case Token::MOD:
   1801     case Token::MUL:
   1802     case Token::BIT_OR:
   1803     case Token::BIT_AND:
   1804     case Token::BIT_XOR:
   1805     case Token::SHL:
   1806     case Token::SHR:
   1807     case Token::SAR:
   1808       VisitForValue(expr->left(), kStack);
   1809       VisitForValue(expr->right(), kAccumulator);
   1810       EmitBinaryOp(expr->op(), context_);
   1811       break;
   1812 
   1813     default:
   1814       UNREACHABLE();
   1815   }
   1816 }
   1817 
   1818 
   1819 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
   1820   Comment cmnt(masm_, "[ CompareOperation");
   1821 
   1822   // Always perform the comparison for its control flow.  Pack the result
   1823   // into the expression's context after the comparison is performed.
   1824   Label materialize_true, materialize_false, done;
   1825   // Initially assume we are in a test context.
   1826   Label* if_true = true_label_;
   1827   Label* if_false = false_label_;
   1828   switch (context_) {
   1829     case Expression::kUninitialized:
   1830       UNREACHABLE();
   1831       break;
   1832     case Expression::kEffect:
   1833       if_true = &done;
   1834       if_false = &done;
   1835       break;
   1836     case Expression::kValue:
   1837       if_true = &materialize_true;
   1838       if_false = &materialize_false;
   1839       break;
   1840     case Expression::kTest:
   1841       break;
   1842     case Expression::kValueTest:
   1843       if_true = &materialize_true;
   1844       break;
   1845     case Expression::kTestValue:
   1846       if_false = &materialize_false;
   1847       break;
   1848   }
   1849 
   1850   VisitForValue(expr->left(), kStack);
   1851   switch (expr->op()) {
   1852     case Token::IN:
   1853       VisitForValue(expr->right(), kStack);
   1854       __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
   1855       __ CompareRoot(rax, Heap::kTrueValueRootIndex);
   1856       __ j(equal, if_true);
   1857       __ jmp(if_false);
   1858       break;
   1859 
   1860     case Token::INSTANCEOF: {
   1861       VisitForValue(expr->right(), kStack);
   1862       InstanceofStub stub;
   1863       __ CallStub(&stub);
   1864       __ testq(rax, rax);
   1865       __ j(zero, if_true);  // The stub returns 0 for true.
   1866       __ jmp(if_false);
   1867       break;
   1868     }
   1869 
   1870     default: {
   1871       VisitForValue(expr->right(), kAccumulator);
   1872       Condition cc = no_condition;
   1873       bool strict = false;
   1874       switch (expr->op()) {
   1875         case Token::EQ_STRICT:
   1876           strict = true;
   1877           // Fall through.
   1878         case Token::EQ:
   1879           cc = equal;
   1880           __ pop(rdx);
   1881           break;
   1882         case Token::LT:
   1883           cc = less;
   1884           __ pop(rdx);
   1885           break;
   1886         case Token::GT:
   1887           // Reverse left and right sizes to obtain ECMA-262 conversion order.
   1888           cc = less;
   1889           __ movq(rdx, result_register());
   1890           __ pop(rax);
   1891          break;
   1892         case Token::LTE:
   1893           // Reverse left and right sizes to obtain ECMA-262 conversion order.
   1894           cc = greater_equal;
   1895           __ movq(rdx, result_register());
   1896           __ pop(rax);
   1897           break;
   1898         case Token::GTE:
   1899           cc = greater_equal;
   1900           __ pop(rdx);
   1901           break;
   1902         case Token::IN:
   1903         case Token::INSTANCEOF:
   1904         default:
   1905           UNREACHABLE();
   1906       }
   1907 
   1908       // The comparison stub expects the smi vs. smi case to be handled
   1909       // before it is called.
   1910       Label slow_case;
   1911       __ JumpIfNotBothSmi(rax, rdx, &slow_case);
   1912       __ SmiCompare(rdx, rax);
   1913       __ j(cc, if_true);
   1914       __ jmp(if_false);
   1915 
   1916       __ bind(&slow_case);
   1917       CompareStub stub(cc, strict);
   1918       __ CallStub(&stub);
   1919       __ testq(rax, rax);
   1920       __ j(cc, if_true);
   1921       __ jmp(if_false);
   1922     }
   1923   }
   1924 
   1925   // Convert the result of the comparison into one expected for this
   1926   // expression's context.
   1927   Apply(context_, if_true, if_false);
   1928 }
   1929 
   1930 
   1931 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
   1932   __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
   1933   Apply(context_, rax);
   1934 }
   1935 
   1936 
   1937 Register FullCodeGenerator::result_register() { return rax; }
   1938 
   1939 
   1940 Register FullCodeGenerator::context_register() { return rsi; }
   1941 
   1942 
   1943 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
   1944   ASSERT(IsAligned(frame_offset, kPointerSize));
   1945   __ movq(Operand(rbp, frame_offset), value);
   1946 }
   1947 
   1948 
   1949 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
   1950   __ movq(dst, CodeGenerator::ContextOperand(rsi, context_index));
   1951 }
   1952 
   1953 
   1954 // ----------------------------------------------------------------------------
   1955 // Non-local control flow support.
   1956 
   1957 
   1958 void FullCodeGenerator::EnterFinallyBlock() {
   1959   ASSERT(!result_register().is(rdx));
   1960   ASSERT(!result_register().is(rcx));
   1961   // Cook return address on top of stack (smi encoded Code* delta)
   1962   __ movq(rdx, Operand(rsp, 0));
   1963   __ Move(rcx, masm_->CodeObject());
   1964   __ subq(rdx, rcx);
   1965   __ Integer32ToSmi(rdx, rdx);
   1966   __ movq(Operand(rsp, 0), rdx);
   1967   // Store result register while executing finally block.
   1968   __ push(result_register());
   1969 }
   1970 
   1971 
   1972 void FullCodeGenerator::ExitFinallyBlock() {
   1973   ASSERT(!result_register().is(rdx));
   1974   ASSERT(!result_register().is(rcx));
   1975   // Restore result register from stack.
   1976   __ pop(result_register());
   1977   // Uncook return address.
   1978   __ movq(rdx, Operand(rsp, 0));
   1979   __ SmiToInteger32(rdx, rdx);
   1980   __ Move(rcx, masm_->CodeObject());
   1981   __ addq(rdx, rcx);
   1982   __ movq(Operand(rsp, 0), rdx);
   1983   // And return.
   1984   __ ret(0);
   1985 }
   1986 
   1987 
   1988 #undef __
   1989 
   1990 
   1991 } }  // namespace v8::internal
   1992