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 "register-allocator-inl.h"
     32 #include "scopes.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 #define __ ACCESS_MASM(masm())
     38 
     39 // -------------------------------------------------------------------------
     40 // VirtualFrame implementation.
     41 
     42 // On entry to a function, the virtual frame already contains the receiver,
     43 // the parameters, and a return address.  All frame elements are in memory.
     44 VirtualFrame::VirtualFrame()
     45     : elements_(parameter_count() + local_count() + kPreallocatedElements),
     46       stack_pointer_(parameter_count() + 1) {  // 0-based index of TOS.
     47   for (int i = 0; i <= stack_pointer_; i++) {
     48     elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
     49   }
     50   for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
     51     register_locations_[i] = kIllegalIndex;
     52   }
     53 }
     54 
     55 
     56 void VirtualFrame::SyncElementBelowStackPointer(int index) {
     57   // Emit code to write elements below the stack pointer to their
     58   // (already allocated) stack address.
     59   ASSERT(index <= stack_pointer_);
     60   FrameElement element = elements_[index];
     61   ASSERT(!element.is_synced());
     62   switch (element.type()) {
     63     case FrameElement::INVALID:
     64       break;
     65 
     66     case FrameElement::MEMORY:
     67       // This function should not be called with synced elements.
     68       // (memory elements are always synced).
     69       UNREACHABLE();
     70       break;
     71 
     72     case FrameElement::REGISTER:
     73       __ mov(Operand(ebp, fp_relative(index)), element.reg());
     74       break;
     75 
     76     case FrameElement::CONSTANT:
     77       if (cgen()->IsUnsafeSmi(element.handle())) {
     78         cgen()->StoreUnsafeSmiToLocal(fp_relative(index), element.handle());
     79       } else {
     80         __ Set(Operand(ebp, fp_relative(index)),
     81                Immediate(element.handle()));
     82       }
     83       break;
     84 
     85     case FrameElement::COPY: {
     86       int backing_index = element.index();
     87       FrameElement backing_element = elements_[backing_index];
     88       if (backing_element.is_memory()) {
     89         Result temp = cgen()->allocator()->Allocate();
     90         ASSERT(temp.is_valid());
     91         __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index)));
     92         __ mov(Operand(ebp, fp_relative(index)), temp.reg());
     93       } else {
     94         ASSERT(backing_element.is_register());
     95         __ mov(Operand(ebp, fp_relative(index)), backing_element.reg());
     96       }
     97       break;
     98     }
     99   }
    100   elements_[index].set_sync();
    101 }
    102 
    103 
    104 void VirtualFrame::SyncElementByPushing(int index) {
    105   // Sync an element of the frame that is just above the stack pointer
    106   // by pushing it.
    107   ASSERT(index == stack_pointer_ + 1);
    108   stack_pointer_++;
    109   FrameElement element = elements_[index];
    110 
    111   switch (element.type()) {
    112     case FrameElement::INVALID:
    113       __ push(Immediate(Smi::FromInt(0)));
    114       break;
    115 
    116     case FrameElement::MEMORY:
    117       // No memory elements exist above the stack pointer.
    118       UNREACHABLE();
    119       break;
    120 
    121     case FrameElement::REGISTER:
    122       __ push(element.reg());
    123       break;
    124 
    125     case FrameElement::CONSTANT:
    126       if (cgen()->IsUnsafeSmi(element.handle())) {
    127        cgen()->PushUnsafeSmi(element.handle());
    128       } else {
    129         __ push(Immediate(element.handle()));
    130       }
    131       break;
    132 
    133     case FrameElement::COPY: {
    134       int backing_index = element.index();
    135       FrameElement backing = elements_[backing_index];
    136       ASSERT(backing.is_memory() || backing.is_register());
    137       if (backing.is_memory()) {
    138         __ push(Operand(ebp, fp_relative(backing_index)));
    139       } else {
    140         __ push(backing.reg());
    141       }
    142       break;
    143     }
    144   }
    145   elements_[index].set_sync();
    146 }
    147 
    148 
    149 // Clear the dirty bits for the range of elements in
    150 // [min(stack_pointer_ + 1,begin), end].
    151 void VirtualFrame::SyncRange(int begin, int end) {
    152   ASSERT(begin >= 0);
    153   ASSERT(end < element_count());
    154   // Sync elements below the range if they have not been materialized
    155   // on the stack.
    156   int start = Min(begin, stack_pointer_ + 1);
    157 
    158   // Emit normal push instructions for elements above stack pointer
    159   // and use mov instructions if we are below stack pointer.
    160   for (int i = start; i <= end; i++) {
    161     if (!elements_[i].is_synced()) {
    162       if (i <= stack_pointer_) {
    163         SyncElementBelowStackPointer(i);
    164       } else {
    165         SyncElementByPushing(i);
    166       }
    167     }
    168   }
    169 }
    170 
    171 
    172 void VirtualFrame::MakeMergable() {
    173   for (int i = 0; i < element_count(); i++) {
    174     FrameElement element = elements_[i];
    175 
    176     // All number type information is reset to unknown for a mergable frame
    177     // because of incoming back edges.
    178     if (element.is_constant() || element.is_copy()) {
    179       if (element.is_synced()) {
    180         // Just spill.
    181         elements_[i] = FrameElement::MemoryElement(NumberInfo::kUnknown);
    182       } else {
    183         // Allocate to a register.
    184         FrameElement backing_element;  // Invalid if not a copy.
    185         if (element.is_copy()) {
    186           backing_element = elements_[element.index()];
    187         }
    188         Result fresh = cgen()->allocator()->Allocate();
    189         ASSERT(fresh.is_valid());  // A register was spilled if all were in use.
    190         elements_[i] =
    191             FrameElement::RegisterElement(fresh.reg(),
    192                                           FrameElement::NOT_SYNCED,
    193                                           NumberInfo::kUnknown);
    194         Use(fresh.reg(), i);
    195 
    196         // Emit a move.
    197         if (element.is_constant()) {
    198           if (cgen()->IsUnsafeSmi(element.handle())) {
    199             cgen()->MoveUnsafeSmi(fresh.reg(), element.handle());
    200           } else {
    201             __ Set(fresh.reg(), Immediate(element.handle()));
    202           }
    203         } else {
    204           ASSERT(element.is_copy());
    205           // Copies are only backed by register or memory locations.
    206           if (backing_element.is_register()) {
    207             // The backing store may have been spilled by allocating,
    208             // but that's OK.  If it was, the value is right where we
    209             // want it.
    210             if (!fresh.reg().is(backing_element.reg())) {
    211               __ mov(fresh.reg(), backing_element.reg());
    212             }
    213           } else {
    214             ASSERT(backing_element.is_memory());
    215             __ mov(fresh.reg(), Operand(ebp, fp_relative(element.index())));
    216           }
    217         }
    218       }
    219       // No need to set the copied flag --- there are no copies.
    220     } else {
    221       // Clear the copy flag of non-constant, non-copy elements.
    222       // They cannot be copied because copies are not allowed.
    223       // The copy flag is not relied on before the end of this loop,
    224       // including when registers are spilled.
    225       elements_[i].clear_copied();
    226       elements_[i].set_number_info(NumberInfo::kUnknown);
    227     }
    228   }
    229 }
    230 
    231 
    232 void VirtualFrame::MergeTo(VirtualFrame* expected) {
    233   Comment cmnt(masm(), "[ Merge frame");
    234   // We should always be merging the code generator's current frame to an
    235   // expected frame.
    236   ASSERT(cgen()->frame() == this);
    237 
    238   // Adjust the stack pointer upward (toward the top of the virtual
    239   // frame) if necessary.
    240   if (stack_pointer_ < expected->stack_pointer_) {
    241     int difference = expected->stack_pointer_ - stack_pointer_;
    242     stack_pointer_ = expected->stack_pointer_;
    243     __ sub(Operand(esp), Immediate(difference * kPointerSize));
    244   }
    245 
    246   MergeMoveRegistersToMemory(expected);
    247   MergeMoveRegistersToRegisters(expected);
    248   MergeMoveMemoryToRegisters(expected);
    249 
    250   // Adjust the stack pointer downward if necessary.
    251   if (stack_pointer_ > expected->stack_pointer_) {
    252     int difference = stack_pointer_ - expected->stack_pointer_;
    253     stack_pointer_ = expected->stack_pointer_;
    254     __ add(Operand(esp), Immediate(difference * kPointerSize));
    255   }
    256 
    257   // At this point, the frames should be identical.
    258   ASSERT(Equals(expected));
    259 }
    260 
    261 
    262 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) {
    263   ASSERT(stack_pointer_ >= expected->stack_pointer_);
    264 
    265   // Move registers, constants, and copies to memory.  Perform moves
    266   // from the top downward in the frame in order to leave the backing
    267   // stores of copies in registers.
    268   //
    269   // Moving memory-backed copies to memory requires a spare register
    270   // for the memory-to-memory moves.  Since we are performing a merge,
    271   // we use esi (which is already saved in the frame).  We keep track
    272   // of the index of the frame element esi is caching or kIllegalIndex
    273   // if esi has not been disturbed.
    274   int esi_caches = kIllegalIndex;
    275   for (int i = element_count() - 1; i >= 0; i--) {
    276     FrameElement target = expected->elements_[i];
    277     if (target.is_register()) continue;  // Handle registers later.
    278     if (target.is_memory()) {
    279       FrameElement source = elements_[i];
    280       switch (source.type()) {
    281         case FrameElement::INVALID:
    282           // Not a legal merge move.
    283           UNREACHABLE();
    284           break;
    285 
    286         case FrameElement::MEMORY:
    287           // Already in place.
    288           break;
    289 
    290         case FrameElement::REGISTER:
    291           Unuse(source.reg());
    292           if (!source.is_synced()) {
    293             __ mov(Operand(ebp, fp_relative(i)), source.reg());
    294           }
    295           break;
    296 
    297         case FrameElement::CONSTANT:
    298           if (!source.is_synced()) {
    299             if (cgen()->IsUnsafeSmi(source.handle())) {
    300               esi_caches = i;
    301               cgen()->MoveUnsafeSmi(esi, source.handle());
    302               __ mov(Operand(ebp, fp_relative(i)), esi);
    303             } else {
    304               __ Set(Operand(ebp, fp_relative(i)), Immediate(source.handle()));
    305             }
    306           }
    307           break;
    308 
    309         case FrameElement::COPY:
    310           if (!source.is_synced()) {
    311             int backing_index = source.index();
    312             FrameElement backing_element = elements_[backing_index];
    313             if (backing_element.is_memory()) {
    314               // If we have to spill a register, we spill esi.
    315               if (esi_caches != backing_index) {
    316                 esi_caches = backing_index;
    317                 __ mov(esi, Operand(ebp, fp_relative(backing_index)));
    318               }
    319               __ mov(Operand(ebp, fp_relative(i)), esi);
    320             } else {
    321               ASSERT(backing_element.is_register());
    322               __ mov(Operand(ebp, fp_relative(i)), backing_element.reg());
    323             }
    324           }
    325           break;
    326       }
    327     }
    328     elements_[i] = target;
    329   }
    330 
    331   if (esi_caches != kIllegalIndex) {
    332     __ mov(esi, Operand(ebp, fp_relative(context_index())));
    333   }
    334 }
    335 
    336 
    337 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) {
    338   // We have already done X-to-memory moves.
    339   ASSERT(stack_pointer_ >= expected->stack_pointer_);
    340 
    341   for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
    342     // Move the right value into register i if it is currently in a register.
    343     int index = expected->register_location(i);
    344     int use_index = register_location(i);
    345     // Skip if register i is unused in the target or else if source is
    346     // not a register (this is not a register-to-register move).
    347     if (index == kIllegalIndex || !elements_[index].is_register()) continue;
    348 
    349     Register target = RegisterAllocator::ToRegister(i);
    350     Register source = elements_[index].reg();
    351     if (index != use_index) {
    352       if (use_index == kIllegalIndex) {  // Target is currently unused.
    353         // Copy contents of source from source to target.
    354         // Set frame element register to target.
    355         Use(target, index);
    356         Unuse(source);
    357         __ mov(target, source);
    358       } else {
    359         // Exchange contents of registers source and target.
    360         // Nothing except the register backing use_index has changed.
    361         elements_[use_index].set_reg(source);
    362         set_register_location(target, index);
    363         set_register_location(source, use_index);
    364         __ xchg(source, target);
    365       }
    366     }
    367 
    368     if (!elements_[index].is_synced() &&
    369         expected->elements_[index].is_synced()) {
    370       __ mov(Operand(ebp, fp_relative(index)), target);
    371     }
    372     elements_[index] = expected->elements_[index];
    373   }
    374 }
    375 
    376 
    377 void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) {
    378   // Move memory, constants, and copies to registers.  This is the
    379   // final step and since it is not done from the bottom up, but in
    380   // register code order, we have special code to ensure that the backing
    381   // elements of copies are in their correct locations when we
    382   // encounter the copies.
    383   for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
    384     int index = expected->register_location(i);
    385     if (index != kIllegalIndex) {
    386       FrameElement source = elements_[index];
    387       FrameElement target = expected->elements_[index];
    388       Register target_reg = RegisterAllocator::ToRegister(i);
    389       ASSERT(target.reg().is(target_reg));
    390       switch (source.type()) {
    391         case FrameElement::INVALID:  // Fall through.
    392           UNREACHABLE();
    393           break;
    394         case FrameElement::REGISTER:
    395           ASSERT(source.Equals(target));
    396           // Go to next iteration.  Skips Use(target_reg) and syncing
    397           // below.  It is safe to skip syncing because a target
    398           // register frame element would only be synced if all source
    399           // elements were.
    400           continue;
    401           break;
    402         case FrameElement::MEMORY:
    403           ASSERT(index <= stack_pointer_);
    404           __ mov(target_reg, Operand(ebp, fp_relative(index)));
    405           break;
    406 
    407         case FrameElement::CONSTANT:
    408           if (cgen()->IsUnsafeSmi(source.handle())) {
    409             cgen()->MoveUnsafeSmi(target_reg, source.handle());
    410           } else {
    411            __ Set(target_reg, Immediate(source.handle()));
    412           }
    413           break;
    414 
    415         case FrameElement::COPY: {
    416           int backing_index = source.index();
    417           FrameElement backing = elements_[backing_index];
    418           ASSERT(backing.is_memory() || backing.is_register());
    419           if (backing.is_memory()) {
    420             ASSERT(backing_index <= stack_pointer_);
    421             // Code optimization if backing store should also move
    422             // to a register: move backing store to its register first.
    423             if (expected->elements_[backing_index].is_register()) {
    424               FrameElement new_backing = expected->elements_[backing_index];
    425               Register new_backing_reg = new_backing.reg();
    426               ASSERT(!is_used(new_backing_reg));
    427               elements_[backing_index] = new_backing;
    428               Use(new_backing_reg, backing_index);
    429               __ mov(new_backing_reg,
    430                      Operand(ebp, fp_relative(backing_index)));
    431               __ mov(target_reg, new_backing_reg);
    432             } else {
    433               __ mov(target_reg, Operand(ebp, fp_relative(backing_index)));
    434             }
    435           } else {
    436             __ mov(target_reg, backing.reg());
    437           }
    438         }
    439       }
    440       // Ensure the proper sync state.
    441       if (target.is_synced() && !source.is_synced()) {
    442         __ mov(Operand(ebp, fp_relative(index)), target_reg);
    443       }
    444       Use(target_reg, index);
    445       elements_[index] = target;
    446     }
    447   }
    448 }
    449 
    450 
    451 void VirtualFrame::Enter() {
    452   // Registers live on entry: esp, ebp, esi, edi.
    453   Comment cmnt(masm(), "[ Enter JS frame");
    454 
    455 #ifdef DEBUG
    456   if (FLAG_debug_code) {
    457     // Verify that edi contains a JS function.  The following code
    458     // relies on eax being available for use.
    459     __ test(edi, Immediate(kSmiTagMask));
    460     __ Check(not_zero,
    461              "VirtualFrame::Enter - edi is not a function (smi check).");
    462     __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
    463     __ Check(equal,
    464              "VirtualFrame::Enter - edi is not a function (map check).");
    465   }
    466 #endif
    467 
    468   EmitPush(ebp);
    469 
    470   __ mov(ebp, Operand(esp));
    471 
    472   // Store the context in the frame.  The context is kept in esi and a
    473   // copy is stored in the frame.  The external reference to esi
    474   // remains.
    475   EmitPush(esi);
    476 
    477   // Store the function in the frame.  The frame owns the register
    478   // reference now (ie, it can keep it in edi or spill it later).
    479   Push(edi);
    480   SyncElementAt(element_count() - 1);
    481   cgen()->allocator()->Unuse(edi);
    482 }
    483 
    484 
    485 void VirtualFrame::Exit() {
    486   Comment cmnt(masm(), "[ Exit JS frame");
    487   // Record the location of the JS exit code for patching when setting
    488   // break point.
    489   __ RecordJSReturn();
    490 
    491   // Avoid using the leave instruction here, because it is too
    492   // short. We need the return sequence to be a least the size of a
    493   // call instruction to support patching the exit code in the
    494   // debugger. See VisitReturnStatement for the full return sequence.
    495   __ mov(esp, Operand(ebp));
    496   stack_pointer_ = frame_pointer();
    497   for (int i = element_count() - 1; i > stack_pointer_; i--) {
    498     FrameElement last = elements_.RemoveLast();
    499     if (last.is_register()) {
    500       Unuse(last.reg());
    501     }
    502   }
    503 
    504   EmitPop(ebp);
    505 }
    506 
    507 
    508 void VirtualFrame::AllocateStackSlots() {
    509   int count = local_count();
    510   if (count > 0) {
    511     Comment cmnt(masm(), "[ Allocate space for locals");
    512     // The locals are initialized to a constant (the undefined value), but
    513     // we sync them with the actual frame to allocate space for spilling
    514     // them later.  First sync everything above the stack pointer so we can
    515     // use pushes to allocate and initialize the locals.
    516     SyncRange(stack_pointer_ + 1, element_count() - 1);
    517     Handle<Object> undefined = Factory::undefined_value();
    518     FrameElement initial_value =
    519         FrameElement::ConstantElement(undefined, FrameElement::SYNCED);
    520     if (count == 1) {
    521       __ push(Immediate(undefined));
    522     } else if (count < kLocalVarBound) {
    523       // For less locals the unrolled loop is more compact.
    524       Result temp = cgen()->allocator()->Allocate();
    525       ASSERT(temp.is_valid());
    526       __ Set(temp.reg(), Immediate(undefined));
    527       for (int i = 0; i < count; i++) {
    528         __ push(temp.reg());
    529       }
    530     } else {
    531       // For more locals a loop in generated code is more compact.
    532       Label alloc_locals_loop;
    533       Result cnt = cgen()->allocator()->Allocate();
    534       Result tmp = cgen()->allocator()->Allocate();
    535       ASSERT(cnt.is_valid());
    536       ASSERT(tmp.is_valid());
    537       __ mov(cnt.reg(), Immediate(count));
    538       __ mov(tmp.reg(), Immediate(undefined));
    539       __ bind(&alloc_locals_loop);
    540       __ push(tmp.reg());
    541       __ dec(cnt.reg());
    542       __ j(not_zero, &alloc_locals_loop);
    543     }
    544     for (int i = 0; i < count; i++) {
    545       elements_.Add(initial_value);
    546       stack_pointer_++;
    547     }
    548   }
    549 }
    550 
    551 
    552 void VirtualFrame::SaveContextRegister() {
    553   ASSERT(elements_[context_index()].is_memory());
    554   __ mov(Operand(ebp, fp_relative(context_index())), esi);
    555 }
    556 
    557 
    558 void VirtualFrame::RestoreContextRegister() {
    559   ASSERT(elements_[context_index()].is_memory());
    560   __ mov(esi, Operand(ebp, fp_relative(context_index())));
    561 }
    562 
    563 
    564 void VirtualFrame::PushReceiverSlotAddress() {
    565   Result temp = cgen()->allocator()->Allocate();
    566   ASSERT(temp.is_valid());
    567   __ lea(temp.reg(), ParameterAt(-1));
    568   Push(&temp);
    569 }
    570 
    571 
    572 int VirtualFrame::InvalidateFrameSlotAt(int index) {
    573   FrameElement original = elements_[index];
    574 
    575   // Is this element the backing store of any copies?
    576   int new_backing_index = kIllegalIndex;
    577   if (original.is_copied()) {
    578     // Verify it is copied, and find first copy.
    579     for (int i = index + 1; i < element_count(); i++) {
    580       if (elements_[i].is_copy() && elements_[i].index() == index) {
    581         new_backing_index = i;
    582         break;
    583       }
    584     }
    585   }
    586 
    587   if (new_backing_index == kIllegalIndex) {
    588     // No copies found, return kIllegalIndex.
    589     if (original.is_register()) {
    590       Unuse(original.reg());
    591     }
    592     elements_[index] = FrameElement::InvalidElement();
    593     return kIllegalIndex;
    594   }
    595 
    596   // This is the backing store of copies.
    597   Register backing_reg;
    598   if (original.is_memory()) {
    599     Result fresh = cgen()->allocator()->Allocate();
    600     ASSERT(fresh.is_valid());
    601     Use(fresh.reg(), new_backing_index);
    602     backing_reg = fresh.reg();
    603     __ mov(backing_reg, Operand(ebp, fp_relative(index)));
    604   } else {
    605     // The original was in a register.
    606     backing_reg = original.reg();
    607     set_register_location(backing_reg, new_backing_index);
    608   }
    609   // Invalidate the element at index.
    610   elements_[index] = FrameElement::InvalidElement();
    611   // Set the new backing element.
    612   if (elements_[new_backing_index].is_synced()) {
    613     elements_[new_backing_index] =
    614         FrameElement::RegisterElement(backing_reg,
    615                                       FrameElement::SYNCED,
    616                                       original.number_info());
    617   } else {
    618     elements_[new_backing_index] =
    619         FrameElement::RegisterElement(backing_reg,
    620                                       FrameElement::NOT_SYNCED,
    621                                       original.number_info());
    622   }
    623   // Update the other copies.
    624   for (int i = new_backing_index + 1; i < element_count(); i++) {
    625     if (elements_[i].is_copy() && elements_[i].index() == index) {
    626       elements_[i].set_index(new_backing_index);
    627       elements_[new_backing_index].set_copied();
    628     }
    629   }
    630   return new_backing_index;
    631 }
    632 
    633 
    634 void VirtualFrame::TakeFrameSlotAt(int index) {
    635   ASSERT(index >= 0);
    636   ASSERT(index <= element_count());
    637   FrameElement original = elements_[index];
    638   int new_backing_store_index = InvalidateFrameSlotAt(index);
    639   if (new_backing_store_index != kIllegalIndex) {
    640     elements_.Add(CopyElementAt(new_backing_store_index));
    641     return;
    642   }
    643 
    644   switch (original.type()) {
    645     case FrameElement::MEMORY: {
    646       // Emit code to load the original element's data into a register.
    647       // Push that register as a FrameElement on top of the frame.
    648       Result fresh = cgen()->allocator()->Allocate();
    649       ASSERT(fresh.is_valid());
    650       FrameElement new_element =
    651           FrameElement::RegisterElement(fresh.reg(),
    652                                         FrameElement::NOT_SYNCED,
    653                                         original.number_info());
    654       Use(fresh.reg(), element_count());
    655       elements_.Add(new_element);
    656       __ mov(fresh.reg(), Operand(ebp, fp_relative(index)));
    657       break;
    658     }
    659     case FrameElement::REGISTER:
    660       Use(original.reg(), element_count());
    661       // Fall through.
    662     case FrameElement::CONSTANT:
    663     case FrameElement::COPY:
    664       original.clear_sync();
    665       elements_.Add(original);
    666       break;
    667     case FrameElement::INVALID:
    668       UNREACHABLE();
    669       break;
    670   }
    671 }
    672 
    673 
    674 void VirtualFrame::StoreToFrameSlotAt(int index) {
    675   // Store the value on top of the frame to the virtual frame slot at
    676   // a given index.  The value on top of the frame is left in place.
    677   // This is a duplicating operation, so it can create copies.
    678   ASSERT(index >= 0);
    679   ASSERT(index < element_count());
    680 
    681   int top_index = element_count() - 1;
    682   FrameElement top = elements_[top_index];
    683   FrameElement original = elements_[index];
    684   if (top.is_copy() && top.index() == index) return;
    685   ASSERT(top.is_valid());
    686 
    687   InvalidateFrameSlotAt(index);
    688 
    689   // InvalidateFrameSlotAt can potentially change any frame element, due
    690   // to spilling registers to allocate temporaries in order to preserve
    691   // the copy-on-write semantics of aliased elements.  Reload top from
    692   // the frame.
    693   top = elements_[top_index];
    694 
    695   if (top.is_copy()) {
    696     // There are two cases based on the relative positions of the
    697     // stored-to slot and the backing slot of the top element.
    698     int backing_index = top.index();
    699     ASSERT(backing_index != index);
    700     if (backing_index < index) {
    701       // 1. The top element is a copy of a slot below the stored-to
    702       // slot.  The stored-to slot becomes an unsynced copy of that
    703       // same backing slot.
    704       elements_[index] = CopyElementAt(backing_index);
    705     } else {
    706       // 2. The top element is a copy of a slot above the stored-to
    707       // slot.  The stored-to slot becomes the new (unsynced) backing
    708       // slot and both the top element and the element at the former
    709       // backing slot become copies of it.  The sync state of the top
    710       // and former backing elements is preserved.
    711       FrameElement backing_element = elements_[backing_index];
    712       ASSERT(backing_element.is_memory() || backing_element.is_register());
    713       if (backing_element.is_memory()) {
    714         // Because sets of copies are canonicalized to be backed by
    715         // their lowest frame element, and because memory frame
    716         // elements are backed by the corresponding stack address, we
    717         // have to move the actual value down in the stack.
    718         //
    719         // TODO(209): considering allocating the stored-to slot to the
    720         // temp register.  Alternatively, allow copies to appear in
    721         // any order in the frame and lazily move the value down to
    722         // the slot.
    723         Result temp = cgen()->allocator()->Allocate();
    724         ASSERT(temp.is_valid());
    725         __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index)));
    726         __ mov(Operand(ebp, fp_relative(index)), temp.reg());
    727       } else {
    728         set_register_location(backing_element.reg(), index);
    729         if (backing_element.is_synced()) {
    730           // If the element is a register, we will not actually move
    731           // anything on the stack but only update the virtual frame
    732           // element.
    733           backing_element.clear_sync();
    734         }
    735       }
    736       elements_[index] = backing_element;
    737 
    738       // The old backing element becomes a copy of the new backing
    739       // element.
    740       FrameElement new_element = CopyElementAt(index);
    741       elements_[backing_index] = new_element;
    742       if (backing_element.is_synced()) {
    743         elements_[backing_index].set_sync();
    744       }
    745 
    746       // All the copies of the old backing element (including the top
    747       // element) become copies of the new backing element.
    748       for (int i = backing_index + 1; i < element_count(); i++) {
    749         if (elements_[i].is_copy() && elements_[i].index() == backing_index) {
    750           elements_[i].set_index(index);
    751         }
    752       }
    753     }
    754     return;
    755   }
    756 
    757   // Move the top element to the stored-to slot and replace it (the
    758   // top element) with a copy.
    759   elements_[index] = top;
    760   if (top.is_memory()) {
    761     // TODO(209): consider allocating the stored-to slot to the temp
    762     // register.  Alternatively, allow copies to appear in any order
    763     // in the frame and lazily move the value down to the slot.
    764     FrameElement new_top = CopyElementAt(index);
    765     new_top.set_sync();
    766     elements_[top_index] = new_top;
    767 
    768     // The sync state of the former top element is correct (synced).
    769     // Emit code to move the value down in the frame.
    770     Result temp = cgen()->allocator()->Allocate();
    771     ASSERT(temp.is_valid());
    772     __ mov(temp.reg(), Operand(esp, 0));
    773     __ mov(Operand(ebp, fp_relative(index)), temp.reg());
    774   } else if (top.is_register()) {
    775     set_register_location(top.reg(), index);
    776     // The stored-to slot has the (unsynced) register reference and
    777     // the top element becomes a copy.  The sync state of the top is
    778     // preserved.
    779     FrameElement new_top = CopyElementAt(index);
    780     if (top.is_synced()) {
    781       new_top.set_sync();
    782       elements_[index].clear_sync();
    783     }
    784     elements_[top_index] = new_top;
    785   } else {
    786     // The stored-to slot holds the same value as the top but
    787     // unsynced.  (We do not have copies of constants yet.)
    788     ASSERT(top.is_constant());
    789     elements_[index].clear_sync();
    790   }
    791 }
    792 
    793 
    794 void VirtualFrame::PushTryHandler(HandlerType type) {
    795   ASSERT(cgen()->HasValidEntryRegisters());
    796   // Grow the expression stack by handler size less one (the return
    797   // address is already pushed by a call instruction).
    798   Adjust(kHandlerSize - 1);
    799   __ PushTryHandler(IN_JAVASCRIPT, type);
    800 }
    801 
    802 
    803 Result VirtualFrame::RawCallStub(CodeStub* stub) {
    804   ASSERT(cgen()->HasValidEntryRegisters());
    805   __ CallStub(stub);
    806   Result result = cgen()->allocator()->Allocate(eax);
    807   ASSERT(result.is_valid());
    808   return result;
    809 }
    810 
    811 
    812 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) {
    813   PrepareForCall(0, 0);
    814   arg->ToRegister(eax);
    815   arg->Unuse();
    816   return RawCallStub(stub);
    817 }
    818 
    819 
    820 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
    821   PrepareForCall(0, 0);
    822 
    823   if (arg0->is_register() && arg0->reg().is(eax)) {
    824     if (arg1->is_register() && arg1->reg().is(edx)) {
    825       // Wrong registers.
    826       __ xchg(eax, edx);
    827     } else {
    828       // Register edx is free for arg0, which frees eax for arg1.
    829       arg0->ToRegister(edx);
    830       arg1->ToRegister(eax);
    831     }
    832   } else {
    833     // Register eax is free for arg1, which guarantees edx is free for
    834     // arg0.
    835     arg1->ToRegister(eax);
    836     arg0->ToRegister(edx);
    837   }
    838 
    839   arg0->Unuse();
    840   arg1->Unuse();
    841   return RawCallStub(stub);
    842 }
    843 
    844 
    845 Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
    846   PrepareForCall(arg_count, arg_count);
    847   ASSERT(cgen()->HasValidEntryRegisters());
    848   __ CallRuntime(f, arg_count);
    849   Result result = cgen()->allocator()->Allocate(eax);
    850   ASSERT(result.is_valid());
    851   return result;
    852 }
    853 
    854 
    855 Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
    856   PrepareForCall(arg_count, arg_count);
    857   ASSERT(cgen()->HasValidEntryRegisters());
    858   __ CallRuntime(id, arg_count);
    859   Result result = cgen()->allocator()->Allocate(eax);
    860   ASSERT(result.is_valid());
    861   return result;
    862 }
    863 
    864 
    865 #ifdef ENABLE_DEBUGGER_SUPPORT
    866 void VirtualFrame::DebugBreak() {
    867   PrepareForCall(0, 0);
    868   ASSERT(cgen()->HasValidEntryRegisters());
    869   __ DebugBreak();
    870   Result result = cgen()->allocator()->Allocate(eax);
    871   ASSERT(result.is_valid());
    872 }
    873 #endif
    874 
    875 
    876 Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
    877                                    InvokeFlag flag,
    878                                    int arg_count) {
    879   PrepareForCall(arg_count, arg_count);
    880   ASSERT(cgen()->HasValidEntryRegisters());
    881   __ InvokeBuiltin(id, flag);
    882   Result result = cgen()->allocator()->Allocate(eax);
    883   ASSERT(result.is_valid());
    884   return result;
    885 }
    886 
    887 
    888 Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
    889                                        RelocInfo::Mode rmode) {
    890   ASSERT(cgen()->HasValidEntryRegisters());
    891   __ call(code, rmode);
    892   Result result = cgen()->allocator()->Allocate(eax);
    893   ASSERT(result.is_valid());
    894   return result;
    895 }
    896 
    897 
    898 Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
    899   // Name and receiver are on the top of the frame.  The IC expects
    900   // name in ecx and receiver in eax.
    901   Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
    902   Result name = Pop();
    903   Result receiver = Pop();
    904   PrepareForCall(0, 0);  // No stack arguments.
    905   // Move results to the right registers:
    906   if (name.is_register() && name.reg().is(eax)) {
    907     if (receiver.is_register() && receiver.reg().is(ecx)) {
    908       // Wrong registers.
    909       __ xchg(eax, ecx);
    910     } else {
    911       // Register ecx is free for name, which frees eax for receiver.
    912       name.ToRegister(ecx);
    913       receiver.ToRegister(eax);
    914     }
    915   } else {
    916     // Register eax is free for receiver, which frees ecx for name.
    917     receiver.ToRegister(eax);
    918     name.ToRegister(ecx);
    919   }
    920   name.Unuse();
    921   receiver.Unuse();
    922   return RawCallCodeObject(ic, mode);
    923 }
    924 
    925 
    926 Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
    927   // Key and receiver are on top of the frame. Put them in eax and edx.
    928   Result key = Pop();
    929   Result receiver = Pop();
    930   PrepareForCall(0, 0);
    931 
    932   if (!key.is_register() || !key.reg().is(edx)) {
    933     // Register edx is available for receiver.
    934     receiver.ToRegister(edx);
    935     key.ToRegister(eax);
    936   } else if (!receiver.is_register() || !receiver.reg().is(eax)) {
    937     // Register eax is available for key.
    938     key.ToRegister(eax);
    939     receiver.ToRegister(edx);
    940   } else {
    941     __ xchg(edx, eax);
    942   }
    943   key.Unuse();
    944   receiver.Unuse();
    945 
    946   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
    947   return RawCallCodeObject(ic, mode);
    948 }
    949 
    950 
    951 Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
    952   // Value and (if not contextual) receiver are on top of the frame.
    953   //  The IC expects name in ecx, value in eax, and receiver in edx.
    954   Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
    955   Result value = Pop();
    956   if (is_contextual) {
    957     PrepareForCall(0, 0);
    958     value.ToRegister(eax);
    959     __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
    960     __ mov(ecx, name);
    961   } else {
    962     Result receiver = Pop();
    963     PrepareForCall(0, 0);
    964 
    965     if (value.is_register() && value.reg().is(edx)) {
    966       if (receiver.is_register() && receiver.reg().is(eax)) {
    967         // Wrong registers.
    968         __ xchg(eax, edx);
    969       } else {
    970         // Register eax is free for value, which frees edx for receiver.
    971         value.ToRegister(eax);
    972         receiver.ToRegister(edx);
    973       }
    974     } else {
    975       // Register edx is free for receiver, which guarantees eax is free for
    976       // value.
    977       receiver.ToRegister(edx);
    978       value.ToRegister(eax);
    979     }
    980   }
    981   __ mov(ecx, name);
    982   value.Unuse();
    983   return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
    984 }
    985 
    986 
    987 Result VirtualFrame::CallKeyedStoreIC() {
    988   // Value, key, and receiver are on the top of the frame.  The IC
    989   // expects value in eax and key and receiver on the stack.  It does
    990   // not drop the key and receiver.
    991   Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
    992   Result value = Pop();
    993   PrepareForCall(2, 0);  // Two stack args, neither callee-dropped.
    994   value.ToRegister(eax);
    995   value.Unuse();
    996   return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
    997 }
    998 
    999 
   1000 Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
   1001                                 int arg_count,
   1002                                 int loop_nesting) {
   1003   // Function name, arguments, and receiver are on top of the frame.
   1004   // The IC expects the name in ecx and the rest on the stack and
   1005   // drops them all.
   1006   InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
   1007   Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
   1008   // Spill args, receiver, and function.  The call will drop args and
   1009   // receiver.
   1010   Result name = Pop();
   1011   PrepareForCall(arg_count + 1, arg_count + 1);  // Arguments + receiver.
   1012   name.ToRegister(ecx);
   1013   name.Unuse();
   1014   return RawCallCodeObject(ic, mode);
   1015 }
   1016 
   1017 
   1018 Result VirtualFrame::CallConstructor(int arg_count) {
   1019   // Arguments, receiver, and function are on top of the frame.  The
   1020   // IC expects arg count in eax, function in edi, and the arguments
   1021   // and receiver on the stack.
   1022   Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
   1023   // Duplicate the function before preparing the frame.
   1024   PushElementAt(arg_count + 1);
   1025   Result function = Pop();
   1026   PrepareForCall(arg_count + 1, arg_count + 1);  // Spill args and receiver.
   1027   function.ToRegister(edi);
   1028 
   1029   // Constructors are called with the number of arguments in register
   1030   // eax for now. Another option would be to have separate construct
   1031   // call trampolines per different arguments counts encountered.
   1032   Result num_args = cgen()->allocator()->Allocate(eax);
   1033   ASSERT(num_args.is_valid());
   1034   __ Set(num_args.reg(), Immediate(arg_count));
   1035 
   1036   function.Unuse();
   1037   num_args.Unuse();
   1038   return RawCallCodeObject(ic, RelocInfo::CONSTRUCT_CALL);
   1039 }
   1040 
   1041 
   1042 void VirtualFrame::Drop(int count) {
   1043   ASSERT(count >= 0);
   1044   ASSERT(height() >= count);
   1045   int num_virtual_elements = (element_count() - 1) - stack_pointer_;
   1046 
   1047   // Emit code to lower the stack pointer if necessary.
   1048   if (num_virtual_elements < count) {
   1049     int num_dropped = count - num_virtual_elements;
   1050     stack_pointer_ -= num_dropped;
   1051     __ add(Operand(esp), Immediate(num_dropped * kPointerSize));
   1052   }
   1053 
   1054   // Discard elements from the virtual frame and free any registers.
   1055   for (int i = 0; i < count; i++) {
   1056     FrameElement dropped = elements_.RemoveLast();
   1057     if (dropped.is_register()) {
   1058       Unuse(dropped.reg());
   1059     }
   1060   }
   1061 }
   1062 
   1063 
   1064 Result VirtualFrame::Pop() {
   1065   FrameElement element = elements_.RemoveLast();
   1066   int index = element_count();
   1067   ASSERT(element.is_valid());
   1068 
   1069   // Get number type information of the result.
   1070   NumberInfo::Type info;
   1071   if (!element.is_copy()) {
   1072     info = element.number_info();
   1073   } else {
   1074     info = elements_[element.index()].number_info();
   1075   }
   1076 
   1077   bool pop_needed = (stack_pointer_ == index);
   1078   if (pop_needed) {
   1079     stack_pointer_--;
   1080     if (element.is_memory()) {
   1081       Result temp = cgen()->allocator()->Allocate();
   1082       ASSERT(temp.is_valid());
   1083       __ pop(temp.reg());
   1084       temp.set_number_info(info);
   1085       return temp;
   1086     }
   1087 
   1088     __ add(Operand(esp), Immediate(kPointerSize));
   1089   }
   1090   ASSERT(!element.is_memory());
   1091 
   1092   // The top element is a register, constant, or a copy.  Unuse
   1093   // registers and follow copies to their backing store.
   1094   if (element.is_register()) {
   1095     Unuse(element.reg());
   1096   } else if (element.is_copy()) {
   1097     ASSERT(element.index() < index);
   1098     index = element.index();
   1099     element = elements_[index];
   1100   }
   1101   ASSERT(!element.is_copy());
   1102 
   1103   // The element is memory, a register, or a constant.
   1104   if (element.is_memory()) {
   1105     // Memory elements could only be the backing store of a copy.
   1106     // Allocate the original to a register.
   1107     ASSERT(index <= stack_pointer_);
   1108     Result temp = cgen()->allocator()->Allocate();
   1109     ASSERT(temp.is_valid());
   1110     Use(temp.reg(), index);
   1111     FrameElement new_element =
   1112         FrameElement::RegisterElement(temp.reg(),
   1113                                       FrameElement::SYNCED,
   1114                                       element.number_info());
   1115     // Preserve the copy flag on the element.
   1116     if (element.is_copied()) new_element.set_copied();
   1117     elements_[index] = new_element;
   1118     __ mov(temp.reg(), Operand(ebp, fp_relative(index)));
   1119     return Result(temp.reg(), info);
   1120   } else if (element.is_register()) {
   1121     return Result(element.reg(), info);
   1122   } else {
   1123     ASSERT(element.is_constant());
   1124     return Result(element.handle());
   1125   }
   1126 }
   1127 
   1128 
   1129 void VirtualFrame::EmitPop(Register reg) {
   1130   ASSERT(stack_pointer_ == element_count() - 1);
   1131   stack_pointer_--;
   1132   elements_.RemoveLast();
   1133   __ pop(reg);
   1134 }
   1135 
   1136 
   1137 void VirtualFrame::EmitPop(Operand operand) {
   1138   ASSERT(stack_pointer_ == element_count() - 1);
   1139   stack_pointer_--;
   1140   elements_.RemoveLast();
   1141   __ pop(operand);
   1142 }
   1143 
   1144 
   1145 void VirtualFrame::EmitPush(Register reg, NumberInfo::Type info) {
   1146   ASSERT(stack_pointer_ == element_count() - 1);
   1147   elements_.Add(FrameElement::MemoryElement(info));
   1148   stack_pointer_++;
   1149   __ push(reg);
   1150 }
   1151 
   1152 
   1153 void VirtualFrame::EmitPush(Operand operand, NumberInfo::Type info) {
   1154   ASSERT(stack_pointer_ == element_count() - 1);
   1155   elements_.Add(FrameElement::MemoryElement(info));
   1156   stack_pointer_++;
   1157   __ push(operand);
   1158 }
   1159 
   1160 
   1161 void VirtualFrame::EmitPush(Immediate immediate, NumberInfo::Type info) {
   1162   ASSERT(stack_pointer_ == element_count() - 1);
   1163   elements_.Add(FrameElement::MemoryElement(info));
   1164   stack_pointer_++;
   1165   __ push(immediate);
   1166 }
   1167 
   1168 
   1169 void VirtualFrame::Push(Expression* expr) {
   1170   ASSERT(expr->IsTrivial());
   1171 
   1172   Literal* lit = expr->AsLiteral();
   1173   if (lit != NULL) {
   1174     Push(lit->handle());
   1175     return;
   1176   }
   1177 
   1178   VariableProxy* proxy = expr->AsVariableProxy();
   1179   if (proxy != NULL && proxy->is_this()) {
   1180     PushParameterAt(-1);
   1181     return;
   1182   }
   1183 
   1184   UNREACHABLE();
   1185 }
   1186 
   1187 
   1188 #undef __
   1189 
   1190 } }  // namespace v8::internal
   1191