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