Home | History | Annotate | Download | only in ia32
      1 // Copyright 2011 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 #if defined(V8_TARGET_ARCH_IA32)
     31 
     32 #include "codegen.h"
     33 #include "deoptimizer.h"
     34 #include "full-codegen.h"
     35 #include "safepoint-table.h"
     36 
     37 namespace v8 {
     38 namespace internal {
     39 
     40 int Deoptimizer::table_entry_size_ = 10;
     41 
     42 
     43 int Deoptimizer::patch_size() {
     44   return Assembler::kCallInstructionLength;
     45 }
     46 
     47 
     48 static void ZapCodeRange(Address start, Address end) {
     49 #ifdef DEBUG
     50   ASSERT(start <= end);
     51   int size = end - start;
     52   CodePatcher destroyer(start, size);
     53   while (size-- > 0) destroyer.masm()->int3();
     54 #endif
     55 }
     56 
     57 
     58 void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
     59   Isolate* isolate = code->GetIsolate();
     60   HandleScope scope(isolate);
     61 
     62   // Compute the size of relocation information needed for the code
     63   // patching in Deoptimizer::DeoptimizeFunction.
     64   int min_reloc_size = 0;
     65   Address prev_reloc_address = code->instruction_start();
     66   Address code_start_address = code->instruction_start();
     67   SafepointTable table(*code);
     68   for (unsigned i = 0; i < table.length(); ++i) {
     69     Address curr_reloc_address = code_start_address + table.GetPcOffset(i);
     70     ASSERT_GE(curr_reloc_address, prev_reloc_address);
     71     SafepointEntry safepoint_entry = table.GetEntry(i);
     72     int deoptimization_index = safepoint_entry.deoptimization_index();
     73     if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
     74       // The gap code is needed to get to the state expected at the
     75       // bailout and we need to skip the call opcode to get to the
     76       // address that needs reloc.
     77       curr_reloc_address += safepoint_entry.gap_code_size() + 1;
     78       int pc_delta = curr_reloc_address - prev_reloc_address;
     79       // We use RUNTIME_ENTRY reloc info which has a size of 2 bytes
     80       // if encodable with small pc delta encoding and up to 6 bytes
     81       // otherwise.
     82       if (pc_delta <= RelocInfo::kMaxSmallPCDelta) {
     83         min_reloc_size += 2;
     84       } else {
     85         min_reloc_size += 6;
     86       }
     87       prev_reloc_address = curr_reloc_address;
     88     }
     89   }
     90 
     91   // If the relocation information is not big enough we create a new
     92   // relocation info object that is padded with comments to make it
     93   // big enough for lazy doptimization.
     94   int reloc_length = code->relocation_info()->length();
     95   if (min_reloc_size > reloc_length) {
     96     int comment_reloc_size = RelocInfo::kMinRelocCommentSize;
     97     // Padding needed.
     98     int min_padding = min_reloc_size - reloc_length;
     99     // Number of comments needed to take up at least that much space.
    100     int additional_comments =
    101         (min_padding + comment_reloc_size - 1) / comment_reloc_size;
    102     // Actual padding size.
    103     int padding = additional_comments * comment_reloc_size;
    104     // Allocate new relocation info and copy old relocation to the end
    105     // of the new relocation info array because relocation info is
    106     // written and read backwards.
    107     Factory* factory = isolate->factory();
    108     Handle<ByteArray> new_reloc =
    109         factory->NewByteArray(reloc_length + padding, TENURED);
    110     memcpy(new_reloc->GetDataStartAddress() + padding,
    111            code->relocation_info()->GetDataStartAddress(),
    112            reloc_length);
    113     // Create a relocation writer to write the comments in the padding
    114     // space. Use position 0 for everything to ensure short encoding.
    115     RelocInfoWriter reloc_info_writer(
    116         new_reloc->GetDataStartAddress() + padding, 0);
    117     intptr_t comment_string
    118         = reinterpret_cast<intptr_t>(RelocInfo::kFillerCommentString);
    119     RelocInfo rinfo(0, RelocInfo::COMMENT, comment_string);
    120     for (int i = 0; i < additional_comments; ++i) {
    121 #ifdef DEBUG
    122       byte* pos_before = reloc_info_writer.pos();
    123 #endif
    124       reloc_info_writer.Write(&rinfo);
    125       ASSERT(RelocInfo::kMinRelocCommentSize ==
    126              pos_before - reloc_info_writer.pos());
    127     }
    128     // Replace relocation information on the code object.
    129     code->set_relocation_info(*new_reloc);
    130   }
    131 }
    132 
    133 
    134 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
    135   if (!function->IsOptimized()) return;
    136 
    137   Isolate* isolate = function->GetIsolate();
    138   HandleScope scope(isolate);
    139   AssertNoAllocation no_allocation;
    140 
    141   // Get the optimized code.
    142   Code* code = function->code();
    143   Address code_start_address = code->instruction_start();
    144 
    145   // We will overwrite the code's relocation info in-place. Relocation info
    146   // is written backward. The relocation info is the payload of a byte
    147   // array.  Later on we will slide this to the start of the byte array and
    148   // create a filler object in the remaining space.
    149   ByteArray* reloc_info = code->relocation_info();
    150   Address reloc_end_address = reloc_info->address() + reloc_info->Size();
    151   RelocInfoWriter reloc_info_writer(reloc_end_address, code_start_address);
    152 
    153   // For each return after a safepoint insert a call to the corresponding
    154   // deoptimization entry.  Since the call is a relative encoding, write new
    155   // reloc info.  We do not need any of the existing reloc info because the
    156   // existing code will not be used again (we zap it in debug builds).
    157   SafepointTable table(code);
    158   Address prev_address = code_start_address;
    159   for (unsigned i = 0; i < table.length(); ++i) {
    160     Address curr_address = code_start_address + table.GetPcOffset(i);
    161     ASSERT_GE(curr_address, prev_address);
    162     ZapCodeRange(prev_address, curr_address);
    163 
    164     SafepointEntry safepoint_entry = table.GetEntry(i);
    165     int deoptimization_index = safepoint_entry.deoptimization_index();
    166     if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
    167       // The gap code is needed to get to the state expected at the bailout.
    168       curr_address += safepoint_entry.gap_code_size();
    169 
    170       CodePatcher patcher(curr_address, patch_size());
    171       Address deopt_entry = GetDeoptimizationEntry(deoptimization_index, LAZY);
    172       patcher.masm()->call(deopt_entry, RelocInfo::NONE);
    173 
    174       // We use RUNTIME_ENTRY for deoptimization bailouts.
    175       RelocInfo rinfo(curr_address + 1,  // 1 after the call opcode.
    176                       RelocInfo::RUNTIME_ENTRY,
    177                       reinterpret_cast<intptr_t>(deopt_entry));
    178       reloc_info_writer.Write(&rinfo);
    179       ASSERT_GE(reloc_info_writer.pos(),
    180                 reloc_info->address() + ByteArray::kHeaderSize);
    181       curr_address += patch_size();
    182     }
    183     prev_address = curr_address;
    184   }
    185   ZapCodeRange(prev_address,
    186                code_start_address + code->safepoint_table_offset());
    187 
    188   // Move the relocation info to the beginning of the byte array.
    189   int new_reloc_size = reloc_end_address - reloc_info_writer.pos();
    190   memmove(code->relocation_start(), reloc_info_writer.pos(), new_reloc_size);
    191 
    192   // The relocation info is in place, update the size.
    193   reloc_info->set_length(new_reloc_size);
    194 
    195   // Handle the junk part after the new relocation info. We will create
    196   // a non-live object in the extra space at the end of the former reloc info.
    197   Address junk_address = reloc_info->address() + reloc_info->Size();
    198   ASSERT(junk_address <= reloc_end_address);
    199   isolate->heap()->CreateFillerObjectAt(junk_address,
    200                                         reloc_end_address - junk_address);
    201 
    202   // Add the deoptimizing code to the list.
    203   DeoptimizingCodeListNode* node = new DeoptimizingCodeListNode(code);
    204   DeoptimizerData* data = isolate->deoptimizer_data();
    205   node->set_next(data->deoptimizing_code_list_);
    206   data->deoptimizing_code_list_ = node;
    207 
    208   // Set the code for the function to non-optimized version.
    209   function->ReplaceCode(function->shared()->code());
    210 
    211   if (FLAG_trace_deopt) {
    212     PrintF("[forced deoptimization: ");
    213     function->PrintName();
    214     PrintF(" / %x]\n", reinterpret_cast<uint32_t>(function));
    215 #ifdef DEBUG
    216     if (FLAG_print_code) {
    217       code->PrintLn();
    218     }
    219 #endif
    220   }
    221 }
    222 
    223 
    224 void Deoptimizer::PatchStackCheckCodeAt(Address pc_after,
    225                                         Code* check_code,
    226                                         Code* replacement_code) {
    227   Address call_target_address = pc_after - kIntSize;
    228   ASSERT(check_code->entry() ==
    229          Assembler::target_address_at(call_target_address));
    230   // The stack check code matches the pattern:
    231   //
    232   //     cmp esp, <limit>
    233   //     jae ok
    234   //     call <stack guard>
    235   //     test eax, <loop nesting depth>
    236   // ok: ...
    237   //
    238   // We will patch away the branch so the code is:
    239   //
    240   //     cmp esp, <limit>  ;; Not changed
    241   //     nop
    242   //     nop
    243   //     call <on-stack replacment>
    244   //     test eax, <loop nesting depth>
    245   // ok:
    246   ASSERT(*(call_target_address - 3) == 0x73 &&  // jae
    247          *(call_target_address - 2) == 0x07 &&  // offset
    248          *(call_target_address - 1) == 0xe8);   // call
    249   *(call_target_address - 3) = 0x90;  // nop
    250   *(call_target_address - 2) = 0x90;  // nop
    251   Assembler::set_target_address_at(call_target_address,
    252                                    replacement_code->entry());
    253 }
    254 
    255 
    256 void Deoptimizer::RevertStackCheckCodeAt(Address pc_after,
    257                                          Code* check_code,
    258                                          Code* replacement_code) {
    259   Address call_target_address = pc_after - kIntSize;
    260   ASSERT(replacement_code->entry() ==
    261          Assembler::target_address_at(call_target_address));
    262   // Replace the nops from patching (Deoptimizer::PatchStackCheckCode) to
    263   // restore the conditional branch.
    264   ASSERT(*(call_target_address - 3) == 0x90 &&  // nop
    265          *(call_target_address - 2) == 0x90 &&  // nop
    266          *(call_target_address - 1) == 0xe8);   // call
    267   *(call_target_address - 3) = 0x73;  // jae
    268   *(call_target_address - 2) = 0x07;  // offset
    269   Assembler::set_target_address_at(call_target_address,
    270                                    check_code->entry());
    271 }
    272 
    273 
    274 static int LookupBailoutId(DeoptimizationInputData* data, unsigned ast_id) {
    275   ByteArray* translations = data->TranslationByteArray();
    276   int length = data->DeoptCount();
    277   for (int i = 0; i < length; i++) {
    278     if (static_cast<unsigned>(data->AstId(i)->value()) == ast_id) {
    279       TranslationIterator it(translations,  data->TranslationIndex(i)->value());
    280       int value = it.Next();
    281       ASSERT(Translation::BEGIN == static_cast<Translation::Opcode>(value));
    282       // Read the number of frames.
    283       value = it.Next();
    284       if (value == 1) return i;
    285     }
    286   }
    287   UNREACHABLE();
    288   return -1;
    289 }
    290 
    291 
    292 void Deoptimizer::DoComputeOsrOutputFrame() {
    293   DeoptimizationInputData* data = DeoptimizationInputData::cast(
    294       optimized_code_->deoptimization_data());
    295   unsigned ast_id = data->OsrAstId()->value();
    296   // TODO(kasperl): This should not be the bailout_id_. It should be
    297   // the ast id. Confusing.
    298   ASSERT(bailout_id_ == ast_id);
    299 
    300   int bailout_id = LookupBailoutId(data, ast_id);
    301   unsigned translation_index = data->TranslationIndex(bailout_id)->value();
    302   ByteArray* translations = data->TranslationByteArray();
    303 
    304   TranslationIterator iterator(translations, translation_index);
    305   Translation::Opcode opcode =
    306       static_cast<Translation::Opcode>(iterator.Next());
    307   ASSERT(Translation::BEGIN == opcode);
    308   USE(opcode);
    309   int count = iterator.Next();
    310   ASSERT(count == 1);
    311   USE(count);
    312 
    313   opcode = static_cast<Translation::Opcode>(iterator.Next());
    314   USE(opcode);
    315   ASSERT(Translation::FRAME == opcode);
    316   unsigned node_id = iterator.Next();
    317   USE(node_id);
    318   ASSERT(node_id == ast_id);
    319   JSFunction* function = JSFunction::cast(ComputeLiteral(iterator.Next()));
    320   USE(function);
    321   ASSERT(function == function_);
    322   unsigned height = iterator.Next();
    323   unsigned height_in_bytes = height * kPointerSize;
    324   USE(height_in_bytes);
    325 
    326   unsigned fixed_size = ComputeFixedSize(function_);
    327   unsigned input_frame_size = input_->GetFrameSize();
    328   ASSERT(fixed_size + height_in_bytes == input_frame_size);
    329 
    330   unsigned stack_slot_size = optimized_code_->stack_slots() * kPointerSize;
    331   unsigned outgoing_height = data->ArgumentsStackHeight(bailout_id)->value();
    332   unsigned outgoing_size = outgoing_height * kPointerSize;
    333   unsigned output_frame_size = fixed_size + stack_slot_size + outgoing_size;
    334   ASSERT(outgoing_size == 0);  // OSR does not happen in the middle of a call.
    335 
    336   if (FLAG_trace_osr) {
    337     PrintF("[on-stack replacement: begin 0x%08" V8PRIxPTR " ",
    338            reinterpret_cast<intptr_t>(function_));
    339     function_->PrintName();
    340     PrintF(" => node=%u, frame=%d->%d]\n",
    341            ast_id,
    342            input_frame_size,
    343            output_frame_size);
    344   }
    345 
    346   // There's only one output frame in the OSR case.
    347   output_count_ = 1;
    348   output_ = new FrameDescription*[1];
    349   output_[0] = new(output_frame_size) FrameDescription(
    350       output_frame_size, function_);
    351 
    352   // Clear the incoming parameters in the optimized frame to avoid
    353   // confusing the garbage collector.
    354   unsigned output_offset = output_frame_size - kPointerSize;
    355   int parameter_count = function_->shared()->formal_parameter_count() + 1;
    356   for (int i = 0; i < parameter_count; ++i) {
    357     output_[0]->SetFrameSlot(output_offset, 0);
    358     output_offset -= kPointerSize;
    359   }
    360 
    361   // Translate the incoming parameters. This may overwrite some of the
    362   // incoming argument slots we've just cleared.
    363   int input_offset = input_frame_size - kPointerSize;
    364   bool ok = true;
    365   int limit = input_offset - (parameter_count * kPointerSize);
    366   while (ok && input_offset > limit) {
    367     ok = DoOsrTranslateCommand(&iterator, &input_offset);
    368   }
    369 
    370   // There are no translation commands for the caller's pc and fp, the
    371   // context, and the function.  Set them up explicitly.
    372   for (int i =  StandardFrameConstants::kCallerPCOffset;
    373        ok && i >=  StandardFrameConstants::kMarkerOffset;
    374        i -= kPointerSize) {
    375     uint32_t input_value = input_->GetFrameSlot(input_offset);
    376     if (FLAG_trace_osr) {
    377       const char* name = "UNKNOWN";
    378       switch (i) {
    379         case StandardFrameConstants::kCallerPCOffset:
    380           name = "caller's pc";
    381           break;
    382         case StandardFrameConstants::kCallerFPOffset:
    383           name = "fp";
    384           break;
    385         case StandardFrameConstants::kContextOffset:
    386           name = "context";
    387           break;
    388         case StandardFrameConstants::kMarkerOffset:
    389           name = "function";
    390           break;
    391       }
    392       PrintF("    [esp + %d] <- 0x%08x ; [esp + %d] (fixed part - %s)\n",
    393              output_offset,
    394              input_value,
    395              input_offset,
    396              name);
    397     }
    398     output_[0]->SetFrameSlot(output_offset, input_->GetFrameSlot(input_offset));
    399     input_offset -= kPointerSize;
    400     output_offset -= kPointerSize;
    401   }
    402 
    403   // Translate the rest of the frame.
    404   while (ok && input_offset >= 0) {
    405     ok = DoOsrTranslateCommand(&iterator, &input_offset);
    406   }
    407 
    408   // If translation of any command failed, continue using the input frame.
    409   if (!ok) {
    410     delete output_[0];
    411     output_[0] = input_;
    412     output_[0]->SetPc(reinterpret_cast<uint32_t>(from_));
    413   } else {
    414     // Setup the frame pointer and the context pointer.
    415     output_[0]->SetRegister(ebp.code(), input_->GetRegister(ebp.code()));
    416     output_[0]->SetRegister(esi.code(), input_->GetRegister(esi.code()));
    417 
    418     unsigned pc_offset = data->OsrPcOffset()->value();
    419     uint32_t pc = reinterpret_cast<uint32_t>(
    420         optimized_code_->entry() + pc_offset);
    421     output_[0]->SetPc(pc);
    422   }
    423   Code* continuation =
    424       function->GetIsolate()->builtins()->builtin(Builtins::kNotifyOSR);
    425   output_[0]->SetContinuation(
    426       reinterpret_cast<uint32_t>(continuation->entry()));
    427 
    428   if (FLAG_trace_osr) {
    429     PrintF("[on-stack replacement translation %s: 0x%08" V8PRIxPTR " ",
    430            ok ? "finished" : "aborted",
    431            reinterpret_cast<intptr_t>(function));
    432     function->PrintName();
    433     PrintF(" => pc=0x%0x]\n", output_[0]->GetPc());
    434   }
    435 }
    436 
    437 
    438 void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
    439                                  int frame_index) {
    440   // Read the ast node id, function, and frame height for this output frame.
    441   Translation::Opcode opcode =
    442       static_cast<Translation::Opcode>(iterator->Next());
    443   USE(opcode);
    444   ASSERT(Translation::FRAME == opcode);
    445   int node_id = iterator->Next();
    446   JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
    447   unsigned height = iterator->Next();
    448   unsigned height_in_bytes = height * kPointerSize;
    449   if (FLAG_trace_deopt) {
    450     PrintF("  translating ");
    451     function->PrintName();
    452     PrintF(" => node=%d, height=%d\n", node_id, height_in_bytes);
    453   }
    454 
    455   // The 'fixed' part of the frame consists of the incoming parameters and
    456   // the part described by JavaScriptFrameConstants.
    457   unsigned fixed_frame_size = ComputeFixedSize(function);
    458   unsigned input_frame_size = input_->GetFrameSize();
    459   unsigned output_frame_size = height_in_bytes + fixed_frame_size;
    460 
    461   // Allocate and store the output frame description.
    462   FrameDescription* output_frame =
    463       new(output_frame_size) FrameDescription(output_frame_size, function);
    464 
    465   bool is_bottommost = (0 == frame_index);
    466   bool is_topmost = (output_count_ - 1 == frame_index);
    467   ASSERT(frame_index >= 0 && frame_index < output_count_);
    468   ASSERT(output_[frame_index] == NULL);
    469   output_[frame_index] = output_frame;
    470 
    471   // The top address for the bottommost output frame can be computed from
    472   // the input frame pointer and the output frame's height.  For all
    473   // subsequent output frames, it can be computed from the previous one's
    474   // top address and the current frame's size.
    475   uint32_t top_address;
    476   if (is_bottommost) {
    477     // 2 = context and function in the frame.
    478     top_address =
    479         input_->GetRegister(ebp.code()) - (2 * kPointerSize) - height_in_bytes;
    480   } else {
    481     top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
    482   }
    483   output_frame->SetTop(top_address);
    484 
    485   // Compute the incoming parameter translation.
    486   int parameter_count = function->shared()->formal_parameter_count() + 1;
    487   unsigned output_offset = output_frame_size;
    488   unsigned input_offset = input_frame_size;
    489   for (int i = 0; i < parameter_count; ++i) {
    490     output_offset -= kPointerSize;
    491     DoTranslateCommand(iterator, frame_index, output_offset);
    492   }
    493   input_offset -= (parameter_count * kPointerSize);
    494 
    495   // There are no translation commands for the caller's pc and fp, the
    496   // context, and the function.  Synthesize their values and set them up
    497   // explicitly.
    498   //
    499   // The caller's pc for the bottommost output frame is the same as in the
    500   // input frame.  For all subsequent output frames, it can be read from the
    501   // previous one.  This frame's pc can be computed from the non-optimized
    502   // function code and AST id of the bailout.
    503   output_offset -= kPointerSize;
    504   input_offset -= kPointerSize;
    505   intptr_t value;
    506   if (is_bottommost) {
    507     value = input_->GetFrameSlot(input_offset);
    508   } else {
    509     value = output_[frame_index - 1]->GetPc();
    510   }
    511   output_frame->SetFrameSlot(output_offset, value);
    512   if (FLAG_trace_deopt) {
    513     PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
    514            top_address + output_offset, output_offset, value);
    515   }
    516 
    517   // The caller's frame pointer for the bottommost output frame is the same
    518   // as in the input frame.  For all subsequent output frames, it can be
    519   // read from the previous one.  Also compute and set this frame's frame
    520   // pointer.
    521   output_offset -= kPointerSize;
    522   input_offset -= kPointerSize;
    523   if (is_bottommost) {
    524     value = input_->GetFrameSlot(input_offset);
    525   } else {
    526     value = output_[frame_index - 1]->GetFp();
    527   }
    528   output_frame->SetFrameSlot(output_offset, value);
    529   intptr_t fp_value = top_address + output_offset;
    530   ASSERT(!is_bottommost || input_->GetRegister(ebp.code()) == fp_value);
    531   output_frame->SetFp(fp_value);
    532   if (is_topmost) output_frame->SetRegister(ebp.code(), fp_value);
    533   if (FLAG_trace_deopt) {
    534     PrintF("    0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
    535            fp_value, output_offset, value);
    536   }
    537 
    538   // For the bottommost output frame the context can be gotten from the input
    539   // frame. For all subsequent output frames it can be gotten from the function
    540   // so long as we don't inline functions that need local contexts.
    541   output_offset -= kPointerSize;
    542   input_offset -= kPointerSize;
    543   if (is_bottommost) {
    544     value = input_->GetFrameSlot(input_offset);
    545   } else {
    546     value = reinterpret_cast<uint32_t>(function->context());
    547   }
    548   output_frame->SetFrameSlot(output_offset, value);
    549   if (is_topmost) output_frame->SetRegister(esi.code(), value);
    550   if (FLAG_trace_deopt) {
    551     PrintF("    0x%08x: [top + %d] <- 0x%08x ; context\n",
    552            top_address + output_offset, output_offset, value);
    553   }
    554 
    555   // The function was mentioned explicitly in the BEGIN_FRAME.
    556   output_offset -= kPointerSize;
    557   input_offset -= kPointerSize;
    558   value = reinterpret_cast<uint32_t>(function);
    559   // The function for the bottommost output frame should also agree with the
    560   // input frame.
    561   ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
    562   output_frame->SetFrameSlot(output_offset, value);
    563   if (FLAG_trace_deopt) {
    564     PrintF("    0x%08x: [top + %d] <- 0x%08x ; function\n",
    565            top_address + output_offset, output_offset, value);
    566   }
    567 
    568   // Translate the rest of the frame.
    569   for (unsigned i = 0; i < height; ++i) {
    570     output_offset -= kPointerSize;
    571     DoTranslateCommand(iterator, frame_index, output_offset);
    572   }
    573   ASSERT(0 == output_offset);
    574 
    575   // Compute this frame's PC, state, and continuation.
    576   Code* non_optimized_code = function->shared()->code();
    577   FixedArray* raw_data = non_optimized_code->deoptimization_data();
    578   DeoptimizationOutputData* data = DeoptimizationOutputData::cast(raw_data);
    579   Address start = non_optimized_code->instruction_start();
    580   unsigned pc_and_state = GetOutputInfo(data, node_id, function->shared());
    581   unsigned pc_offset = FullCodeGenerator::PcField::decode(pc_and_state);
    582   uint32_t pc_value = reinterpret_cast<uint32_t>(start + pc_offset);
    583   output_frame->SetPc(pc_value);
    584 
    585   FullCodeGenerator::State state =
    586       FullCodeGenerator::StateField::decode(pc_and_state);
    587   output_frame->SetState(Smi::FromInt(state));
    588 
    589   // Set the continuation for the topmost frame.
    590   if (is_topmost) {
    591     Builtins* builtins = isolate_->builtins();
    592     Code* continuation = (bailout_type_ == EAGER)
    593         ? builtins->builtin(Builtins::kNotifyDeoptimized)
    594         : builtins->builtin(Builtins::kNotifyLazyDeoptimized);
    595     output_frame->SetContinuation(
    596         reinterpret_cast<uint32_t>(continuation->entry()));
    597   }
    598 
    599   if (output_count_ - 1 == frame_index) iterator->Done();
    600 }
    601 
    602 
    603 #define __ masm()->
    604 
    605 void Deoptimizer::EntryGenerator::Generate() {
    606   GeneratePrologue();
    607   CpuFeatures::Scope scope(SSE2);
    608 
    609   Isolate* isolate = masm()->isolate();
    610 
    611   // Save all general purpose registers before messing with them.
    612   const int kNumberOfRegisters = Register::kNumRegisters;
    613 
    614   const int kDoubleRegsSize = kDoubleSize *
    615                               XMMRegister::kNumAllocatableRegisters;
    616   __ sub(Operand(esp), Immediate(kDoubleRegsSize));
    617   for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) {
    618     XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i);
    619     int offset = i * kDoubleSize;
    620     __ movdbl(Operand(esp, offset), xmm_reg);
    621   }
    622 
    623   __ pushad();
    624 
    625   const int kSavedRegistersAreaSize = kNumberOfRegisters * kPointerSize +
    626                                       kDoubleRegsSize;
    627 
    628   // Get the bailout id from the stack.
    629   __ mov(ebx, Operand(esp, kSavedRegistersAreaSize));
    630 
    631   // Get the address of the location in the code object if possible
    632   // and compute the fp-to-sp delta in register edx.
    633   if (type() == EAGER) {
    634     __ Set(ecx, Immediate(0));
    635     __ lea(edx, Operand(esp, kSavedRegistersAreaSize + 1 * kPointerSize));
    636   } else {
    637     __ mov(ecx, Operand(esp, kSavedRegistersAreaSize + 1 * kPointerSize));
    638     __ lea(edx, Operand(esp, kSavedRegistersAreaSize + 2 * kPointerSize));
    639   }
    640   __ sub(edx, Operand(ebp));
    641   __ neg(edx);
    642 
    643   // Allocate a new deoptimizer object.
    644   __ PrepareCallCFunction(6, eax);
    645   __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
    646   __ mov(Operand(esp, 0 * kPointerSize), eax);  // Function.
    647   __ mov(Operand(esp, 1 * kPointerSize), Immediate(type()));  // Bailout type.
    648   __ mov(Operand(esp, 2 * kPointerSize), ebx);  // Bailout id.
    649   __ mov(Operand(esp, 3 * kPointerSize), ecx);  // Code address or 0.
    650   __ mov(Operand(esp, 4 * kPointerSize), edx);  // Fp-to-sp delta.
    651   __ mov(Operand(esp, 5 * kPointerSize),
    652          Immediate(ExternalReference::isolate_address()));
    653   __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate), 6);
    654 
    655   // Preserve deoptimizer object in register eax and get the input
    656   // frame descriptor pointer.
    657   __ mov(ebx, Operand(eax, Deoptimizer::input_offset()));
    658 
    659   // Fill in the input registers.
    660   for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
    661     int offset = (i * kPointerSize) + FrameDescription::registers_offset();
    662     __ pop(Operand(ebx, offset));
    663   }
    664 
    665   // Fill in the double input registers.
    666   int double_regs_offset = FrameDescription::double_registers_offset();
    667   for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) {
    668     int dst_offset = i * kDoubleSize + double_regs_offset;
    669     int src_offset = i * kDoubleSize;
    670     __ movdbl(xmm0, Operand(esp, src_offset));
    671     __ movdbl(Operand(ebx, dst_offset), xmm0);
    672   }
    673 
    674   // Remove the bailout id and the double registers from the stack.
    675   if (type() == EAGER) {
    676     __ add(Operand(esp), Immediate(kDoubleRegsSize + kPointerSize));
    677   } else {
    678     __ add(Operand(esp), Immediate(kDoubleRegsSize + 2 * kPointerSize));
    679   }
    680 
    681   // Compute a pointer to the unwinding limit in register ecx; that is
    682   // the first stack slot not part of the input frame.
    683   __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset()));
    684   __ add(ecx, Operand(esp));
    685 
    686   // Unwind the stack down to - but not including - the unwinding
    687   // limit and copy the contents of the activation frame to the input
    688   // frame description.
    689   __ lea(edx, Operand(ebx, FrameDescription::frame_content_offset()));
    690   Label pop_loop;
    691   __ bind(&pop_loop);
    692   __ pop(Operand(edx, 0));
    693   __ add(Operand(edx), Immediate(sizeof(uint32_t)));
    694   __ cmp(ecx, Operand(esp));
    695   __ j(not_equal, &pop_loop);
    696 
    697   // Compute the output frame in the deoptimizer.
    698   __ push(eax);
    699   __ PrepareCallCFunction(1, ebx);
    700   __ mov(Operand(esp, 0 * kPointerSize), eax);
    701   __ CallCFunction(
    702       ExternalReference::compute_output_frames_function(isolate), 1);
    703   __ pop(eax);
    704 
    705   // Replace the current frame with the output frames.
    706   Label outer_push_loop, inner_push_loop;
    707   // Outer loop state: eax = current FrameDescription**, edx = one past the
    708   // last FrameDescription**.
    709   __ mov(edx, Operand(eax, Deoptimizer::output_count_offset()));
    710   __ mov(eax, Operand(eax, Deoptimizer::output_offset()));
    711   __ lea(edx, Operand(eax, edx, times_4, 0));
    712   __ bind(&outer_push_loop);
    713   // Inner loop state: ebx = current FrameDescription*, ecx = loop index.
    714   __ mov(ebx, Operand(eax, 0));
    715   __ mov(ecx, Operand(ebx, FrameDescription::frame_size_offset()));
    716   __ bind(&inner_push_loop);
    717   __ sub(Operand(ecx), Immediate(sizeof(uint32_t)));
    718   __ push(Operand(ebx, ecx, times_1, FrameDescription::frame_content_offset()));
    719   __ test(ecx, Operand(ecx));
    720   __ j(not_zero, &inner_push_loop);
    721   __ add(Operand(eax), Immediate(kPointerSize));
    722   __ cmp(eax, Operand(edx));
    723   __ j(below, &outer_push_loop);
    724 
    725   // In case of OSR, we have to restore the XMM registers.
    726   if (type() == OSR) {
    727     for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; ++i) {
    728       XMMRegister xmm_reg = XMMRegister::FromAllocationIndex(i);
    729       int src_offset = i * kDoubleSize + double_regs_offset;
    730       __ movdbl(xmm_reg, Operand(ebx, src_offset));
    731     }
    732   }
    733 
    734   // Push state, pc, and continuation from the last output frame.
    735   if (type() != OSR) {
    736     __ push(Operand(ebx, FrameDescription::state_offset()));
    737   }
    738   __ push(Operand(ebx, FrameDescription::pc_offset()));
    739   __ push(Operand(ebx, FrameDescription::continuation_offset()));
    740 
    741 
    742   // Push the registers from the last output frame.
    743   for (int i = 0; i < kNumberOfRegisters; i++) {
    744     int offset = (i * kPointerSize) + FrameDescription::registers_offset();
    745     __ push(Operand(ebx, offset));
    746   }
    747 
    748   // Restore the registers from the stack.
    749   __ popad();
    750 
    751   // Return to the continuation point.
    752   __ ret(0);
    753 }
    754 
    755 
    756 void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
    757   // Create a sequence of deoptimization entries.
    758   Label done;
    759   for (int i = 0; i < count(); i++) {
    760     int start = masm()->pc_offset();
    761     USE(start);
    762     __ push_imm32(i);
    763     __ jmp(&done);
    764     ASSERT(masm()->pc_offset() - start == table_entry_size_);
    765   }
    766   __ bind(&done);
    767 }
    768 
    769 #undef __
    770 
    771 
    772 } }  // namespace v8::internal
    773 
    774 #endif  // V8_TARGET_ARCH_IA32
    775