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