LCOV - code coverage report
Current view: top level - src/x64 - deoptimizer-x64.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 133 146 91.1 %
Date: 2017-04-26 Functions: 9 10 90.0 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #if V8_TARGET_ARCH_X64
       6             : 
       7             : #include "src/codegen.h"
       8             : #include "src/deoptimizer.h"
       9             : #include "src/full-codegen/full-codegen.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/register-configuration.h"
      12             : #include "src/safepoint-table.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : 
      18             : const int Deoptimizer::table_entry_size_ = 10;
      19             : 
      20             : 
      21     5493794 : int Deoptimizer::patch_size() {
      22     5493794 :   return Assembler::kCallSequenceLength;
      23             : }
      24             : 
      25             : 
      26      391814 : void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) {
      27             :   // Empty because there is no need for relocation information for the code
      28             :   // patching in Deoptimizer::PatchCodeForDeoptimization below.
      29      391814 : }
      30             : 
      31             : 
      32      422165 : void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
      33             :   // Invalidate the relocation information, as it will become invalid by the
      34             :   // code patching below, and is not needed any more.
      35      422165 :   code->InvalidateRelocation();
      36             : 
      37      422165 :   if (FLAG_zap_code_space) {
      38             :     // Fail hard and early if we enter this code object again.
      39           0 :     byte* pointer = code->FindCodeAgeSequence();
      40           0 :     if (pointer != NULL) {
      41           0 :       pointer += kNoCodeAgeSequenceLength;
      42             :     } else {
      43           0 :       pointer = code->instruction_start();
      44             :     }
      45           0 :     CodePatcher patcher(isolate, pointer, 1);
      46           0 :     patcher.masm()->int3();
      47             : 
      48             :     DeoptimizationInputData* data =
      49             :         DeoptimizationInputData::cast(code->deoptimization_data());
      50             :     int osr_offset = data->OsrPcOffset()->value();
      51           0 :     if (osr_offset > 0) {
      52           0 :       CodePatcher osr_patcher(isolate, code->instruction_start() + osr_offset,
      53           0 :                               1);
      54           0 :       osr_patcher.masm()->int3();
      55           0 :     }
      56             :   }
      57             : 
      58             :   // For each LLazyBailout instruction insert a absolute call to the
      59             :   // corresponding deoptimization entry, or a short call to an absolute
      60             :   // jump if space is short. The absolute jumps are put in a table just
      61             :   // before the safepoint table (space was allocated there when the Code
      62             :   // object was created, if necessary).
      63             : 
      64      422165 :   Address instruction_start = code->instruction_start();
      65             : #ifdef DEBUG
      66             :   Address prev_call_address = NULL;
      67             : #endif
      68             :   DeoptimizationInputData* deopt_data =
      69             :       DeoptimizationInputData::cast(code->deoptimization_data());
      70             :   deopt_data->SetSharedFunctionInfo(Smi::kZero);
      71             :   // For each LLazyBailout instruction insert a call to the corresponding
      72             :   // deoptimization entry.
      73    10071404 :   for (int i = 0; i < deopt_data->DeoptCount(); i++) {
      74    10925749 :     if (deopt_data->Pc(i)->value() == -1) continue;
      75             :     // Position where Call will be patched in.
      76     5829724 :     Address call_address = instruction_start + deopt_data->Pc(i)->value();
      77             :     // There is room enough to write a long call instruction because we pad
      78             :     // LLazyBailout instructions with nops if necessary.
      79     2914862 :     CodePatcher patcher(isolate, call_address, Assembler::kCallSequenceLength);
      80             :     patcher.masm()->Call(GetDeoptimizationEntry(isolate, i, LAZY),
      81     2914862 :                          Assembler::RelocInfoNone());
      82             :     DCHECK(prev_call_address == NULL ||
      83             :            call_address >= prev_call_address + patch_size());
      84             :     DCHECK(call_address + patch_size() <= code->instruction_end());
      85             : #ifdef DEBUG
      86             :     prev_call_address = call_address;
      87             : #endif
      88     2914862 :   }
      89      422165 : }
      90             : 
      91             : 
      92       26647 : void Deoptimizer::SetPlatformCompiledStubRegisters(
      93       26647 :     FrameDescription* output_frame, CodeStubDescriptor* descriptor) {
      94             :   intptr_t handler =
      95       26647 :       reinterpret_cast<intptr_t>(descriptor->deoptimization_handler());
      96             :   int params = descriptor->GetHandlerParameterCount();
      97       26647 :   output_frame->SetRegister(rax.code(), params);
      98             :   output_frame->SetRegister(rbx.code(), handler);
      99       26647 : }
     100             : 
     101             : 
     102       26647 : void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
     103      452999 :   for (int i = 0; i < XMMRegister::kMaxNumRegisters; ++i) {
     104      426352 :     Float64 double_value = input_->GetDoubleRegister(i);
     105             :     output_frame->SetDoubleRegister(i, double_value);
     106             :   }
     107       26647 : }
     108             : 
     109             : #define __ masm()->
     110             : 
     111    19419900 : void Deoptimizer::TableEntryGenerator::Generate() {
     112       85175 :   GeneratePrologue();
     113             : 
     114             :   // Save all general purpose registers before messing with them.
     115             :   const int kNumberOfRegisters = Register::kNumRegisters;
     116             : 
     117             :   const int kDoubleRegsSize = kDoubleSize * XMMRegister::kMaxNumRegisters;
     118       85175 :   __ subp(rsp, Immediate(kDoubleRegsSize));
     119             : 
     120     6728825 :   const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
     121     2725600 :   for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
     122             :     int code = config->GetAllocatableDoubleCode(i);
     123     1277625 :     XMMRegister xmm_reg = XMMRegister::from_code(code);
     124     1277625 :     int offset = code * kDoubleSize;
     125     2555250 :     __ Movsd(Operand(rsp, offset), xmm_reg);
     126             :   }
     127             : 
     128             :   const int kFloatRegsSize = kFloatSize * XMMRegister::kMaxNumRegisters;
     129       85175 :   __ subp(rsp, Immediate(kFloatRegsSize));
     130             : 
     131     2725600 :   for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
     132             :     int code = config->GetAllocatableFloatCode(i);
     133     1277625 :     XMMRegister xmm_reg = XMMRegister::from_code(code);
     134     1277625 :     int offset = code * kFloatSize;
     135     2555250 :     __ Movss(Operand(rsp, offset), xmm_reg);
     136             :   }
     137             : 
     138             :   // We push all registers onto the stack, even though we do not need
     139             :   // to restore all later.
     140     1362800 :   for (int i = 0; i < kNumberOfRegisters; i++) {
     141     1362800 :     Register r = Register::from_code(i);
     142     1362800 :     __ pushq(r);
     143             :   }
     144             : 
     145             :   const int kSavedRegistersAreaSize =
     146             :       kNumberOfRegisters * kRegisterSize + kDoubleRegsSize + kFloatRegsSize;
     147             : 
     148      170350 :   __ Store(ExternalReference(Isolate::kCEntryFPAddress, isolate()), rbp);
     149             : 
     150             :   // We use this to keep the value of the fifth argument temporarily.
     151             :   // Unfortunately we can't store it directly in r8 (used for passing
     152             :   // this on linux), since it is another parameter passing register on windows.
     153             :   Register arg5 = r11;
     154             : 
     155             :   // Get the bailout id from the stack.
     156      255525 :   __ movp(arg_reg_3, Operand(rsp, kSavedRegistersAreaSize));
     157             : 
     158             :   // Get the address of the location in the code object
     159             :   // and compute the fp-to-sp delta in register arg5.
     160      255525 :   __ movp(arg_reg_4, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize));
     161             :   __ leap(arg5, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize +
     162      255525 :                             kPCOnStackSize));
     163             : 
     164       85175 :   __ subp(arg5, rbp);
     165       85175 :   __ negp(arg5);
     166             : 
     167             :   // Allocate a new deoptimizer object.
     168       85175 :   __ PrepareCallCFunction(6);
     169       85175 :   __ movp(rax, Immediate(0));
     170             :   Label context_check;
     171      255525 :   __ movp(rdi, Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset));
     172       85175 :   __ JumpIfSmi(rdi, &context_check);
     173      255525 :   __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
     174       85175 :   __ bind(&context_check);
     175       85175 :   __ movp(arg_reg_1, rax);
     176      170350 :   __ Set(arg_reg_2, type());
     177             :   // Args 3 and 4 are already in the right registers.
     178             : 
     179             :   // On windows put the arguments on the stack (PrepareCallCFunction
     180             :   // has created space for this). On linux pass the arguments in r8 and r9.
     181             : #ifdef _WIN64
     182             :   __ movq(Operand(rsp, 4 * kRegisterSize), arg5);
     183             :   __ LoadAddress(arg5, ExternalReference::isolate_address(isolate()));
     184             :   __ movq(Operand(rsp, 5 * kRegisterSize), arg5);
     185             : #else
     186       85175 :   __ movp(r8, arg5);
     187      170350 :   __ LoadAddress(r9, ExternalReference::isolate_address(isolate()));
     188             : #endif
     189             : 
     190             :   { AllowExternalCallThatCantCauseGC scope(masm());
     191      170350 :     __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
     192             :   }
     193             :   // Preserve deoptimizer object in register rax and get the input
     194             :   // frame descriptor pointer.
     195      255525 :   __ movp(rbx, Operand(rax, Deoptimizer::input_offset()));
     196             : 
     197             :   // Fill in the input registers.
     198     1447975 :   for (int i = kNumberOfRegisters -1; i >= 0; i--) {
     199     1362800 :     int offset = (i * kPointerSize) + FrameDescription::registers_offset();
     200     2725600 :     __ PopQuad(Operand(rbx, offset));
     201             :   }
     202             : 
     203             :   // Fill in the float input registers.
     204             :   int float_regs_offset = FrameDescription::float_registers_offset();
     205     1362800 :   for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
     206     1362800 :     int src_offset = i * kFloatSize;
     207     1362800 :     int dst_offset = i * kFloatSize + float_regs_offset;
     208     4088400 :     __ movl(rcx, Operand(rsp, src_offset));
     209     4088400 :     __ movl(Operand(rbx, dst_offset), rcx);
     210             :   }
     211       85175 :   __ addp(rsp, Immediate(kFloatRegsSize));
     212             : 
     213             :   // Fill in the double input registers.
     214             :   int double_regs_offset = FrameDescription::double_registers_offset();
     215     1447975 :   for (int i = 0; i < XMMRegister::kMaxNumRegisters; i++) {
     216     1362800 :     int dst_offset = i * kDoubleSize + double_regs_offset;
     217     2725600 :     __ popq(Operand(rbx, dst_offset));
     218             :   }
     219             : 
     220             :   // Remove the bailout id and return address from the stack.
     221       85175 :   __ addp(rsp, Immediate(1 * kRegisterSize + kPCOnStackSize));
     222             : 
     223             :   // Compute a pointer to the unwinding limit in register rcx; that is
     224             :   // the first stack slot not part of the input frame.
     225      255525 :   __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     226       85175 :   __ addp(rcx, rsp);
     227             : 
     228             :   // Unwind the stack down to - but not including - the unwinding
     229             :   // limit and copy the contents of the activation frame to the input
     230             :   // frame description.
     231      255525 :   __ leap(rdx, Operand(rbx, FrameDescription::frame_content_offset()));
     232             :   Label pop_loop_header;
     233       85175 :   __ jmp(&pop_loop_header);
     234             :   Label pop_loop;
     235       85175 :   __ bind(&pop_loop);
     236      170350 :   __ Pop(Operand(rdx, 0));
     237       85175 :   __ addp(rdx, Immediate(sizeof(intptr_t)));
     238       85175 :   __ bind(&pop_loop_header);
     239       85175 :   __ cmpp(rcx, rsp);
     240       85175 :   __ j(not_equal, &pop_loop);
     241             : 
     242             :   // Compute the output frame in the deoptimizer.
     243       85175 :   __ pushq(rax);
     244       85175 :   __ PrepareCallCFunction(2);
     245       85175 :   __ movp(arg_reg_1, rax);
     246      170350 :   __ LoadAddress(arg_reg_2, ExternalReference::isolate_address(isolate()));
     247             :   {
     248             :     AllowExternalCallThatCantCauseGC scope(masm());
     249             :     __ CallCFunction(
     250      170350 :         ExternalReference::compute_output_frames_function(isolate()), 2);
     251             :   }
     252       85175 :   __ popq(rax);
     253             : 
     254      255525 :   __ movp(rsp, Operand(rax, Deoptimizer::caller_frame_top_offset()));
     255             : 
     256             :   // Replace the current (input) frame with the output frames.
     257             :   Label outer_push_loop, inner_push_loop,
     258             :       outer_loop_header, inner_loop_header;
     259             :   // Outer loop state: rax = current FrameDescription**, rdx = one past the
     260             :   // last FrameDescription**.
     261      255525 :   __ movl(rdx, Operand(rax, Deoptimizer::output_count_offset()));
     262      255525 :   __ movp(rax, Operand(rax, Deoptimizer::output_offset()));
     263      255525 :   __ leap(rdx, Operand(rax, rdx, times_pointer_size, 0));
     264       85175 :   __ jmp(&outer_loop_header);
     265       85175 :   __ bind(&outer_push_loop);
     266             :   // Inner loop state: rbx = current FrameDescription*, rcx = loop index.
     267      255525 :   __ movp(rbx, Operand(rax, 0));
     268      255525 :   __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     269       85175 :   __ jmp(&inner_loop_header);
     270       85175 :   __ bind(&inner_push_loop);
     271       85175 :   __ subp(rcx, Immediate(sizeof(intptr_t)));
     272      170350 :   __ Push(Operand(rbx, rcx, times_1, FrameDescription::frame_content_offset()));
     273       85175 :   __ bind(&inner_loop_header);
     274       85175 :   __ testp(rcx, rcx);
     275       85175 :   __ j(not_zero, &inner_push_loop);
     276       85175 :   __ addp(rax, Immediate(kPointerSize));
     277       85175 :   __ bind(&outer_loop_header);
     278       85175 :   __ cmpp(rax, rdx);
     279       85175 :   __ j(below, &outer_push_loop);
     280             : 
     281     2725600 :   for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
     282             :     int code = config->GetAllocatableDoubleCode(i);
     283     1277625 :     XMMRegister xmm_reg = XMMRegister::from_code(code);
     284     1277625 :     int src_offset = code * kDoubleSize + double_regs_offset;
     285     2555250 :     __ Movsd(xmm_reg, Operand(rbx, src_offset));
     286             :   }
     287             : 
     288             :   // Push state, pc, and continuation from the last output frame.
     289      170350 :   __ Push(Operand(rbx, FrameDescription::state_offset()));
     290      170350 :   __ PushQuad(Operand(rbx, FrameDescription::pc_offset()));
     291      170350 :   __ PushQuad(Operand(rbx, FrameDescription::continuation_offset()));
     292             : 
     293             :   // Push the registers from the last output frame.
     294     1447975 :   for (int i = 0; i < kNumberOfRegisters; i++) {
     295     1362800 :     int offset = (i * kPointerSize) + FrameDescription::registers_offset();
     296     2725600 :     __ PushQuad(Operand(rbx, offset));
     297             :   }
     298             : 
     299             :   // Restore the registers from the stack.
     300     1362800 :   for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) {
     301             :     Register r = Register::from_code(i);
     302             :     // Do not restore rsp, simply pop the value into the next register
     303             :     // and overwrite this afterwards.
     304     1362800 :     if (r.is(rsp)) {
     305             :       DCHECK(i > 0);
     306       85175 :       r = Register::from_code(i - 1);
     307             :     }
     308     1362800 :     __ popq(r);
     309             :   }
     310             : 
     311             :   // Set up the roots register.
     312       85175 :   __ InitializeRootRegister();
     313             : 
     314             :   // Return to the continuation point.
     315       85175 :   __ ret(0);
     316       85175 : }
     317             : 
     318             : 
     319    25002981 : void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
     320             :   // Create a sequence of deoptimization entries.
     321             :   Label done;
     322    16668654 :   for (int i = 0; i < count(); i++) {
     323             :     int start = masm()->pc_offset();
     324             :     USE(start);
     325     8249152 :     __ pushq_imm32(i);
     326     8249152 :     __ jmp(&done);
     327             :     DCHECK(masm()->pc_offset() - start == table_entry_size_);
     328             :   }
     329       85175 :   __ bind(&done);
     330       85175 : }
     331             : 
     332             : 
     333      155057 : void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
     334             :   if (kPCOnStackSize == 2 * kPointerSize) {
     335             :     // Zero out the high-32 bit of PC for x32 port.
     336             :     SetFrameSlot(offset + kPointerSize, 0);
     337             :   }
     338             :   SetFrameSlot(offset, value);
     339      155057 : }
     340             : 
     341             : 
     342      155057 : void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
     343             :   if (kFPOnStackSize == 2 * kPointerSize) {
     344             :     // Zero out the high-32 bit of FP for x32 port.
     345             :     SetFrameSlot(offset + kPointerSize, 0);
     346             :   }
     347             :   SetFrameSlot(offset, value);
     348      155057 : }
     349             : 
     350             : 
     351           0 : void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
     352             :   // No embedded constant pool support.
     353           0 :   UNREACHABLE();
     354             : }
     355             : 
     356             : 
     357             : #undef __
     358             : 
     359             : 
     360             : }  // namespace internal
     361             : }  // namespace v8
     362             : 
     363             : #endif  // V8_TARGET_ARCH_X64

Generated by: LCOV version 1.10