LCOV - code coverage report
Current view: top level - src/x64 - deoptimizer-x64.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 97 99 98.0 %
Date: 2019-01-20 Functions: 6 7 85.7 %

          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/deoptimizer.h"
       8             : #include "src/macro-assembler.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/register-configuration.h"
      11             : #include "src/safepoint-table.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16             : #define __ masm->
      17             : 
      18       45129 : void Deoptimizer::GenerateDeoptimizationEntries(MacroAssembler* masm,
      19             :                                                 Isolate* isolate,
      20             :                                                 DeoptimizeKind deopt_kind) {
      21             :   NoRootArrayScope no_root_array(masm);
      22             : 
      23             :   // Save all general purpose registers before messing with them.
      24             :   const int kNumberOfRegisters = Register::kNumRegisters;
      25             : 
      26             :   const int kDoubleRegsSize = kDoubleSize * XMMRegister::kNumRegisters;
      27       45129 :   __ subp(rsp, Immediate(kDoubleRegsSize));
      28             : 
      29     3565181 :   const RegisterConfiguration* config = RegisterConfiguration::Default();
      30     1444126 :   for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
      31             :     int code = config->GetAllocatableDoubleCode(i);
      32             :     XMMRegister xmm_reg = XMMRegister::from_code(code);
      33      676934 :     int offset = code * kDoubleSize;
      34     1353869 :     __ Movsd(Operand(rsp, offset), xmm_reg);
      35             :   }
      36             : 
      37             :   const int kFloatRegsSize = kFloatSize * XMMRegister::kNumRegisters;
      38       45129 :   __ subp(rsp, Immediate(kFloatRegsSize));
      39             : 
      40     1444128 :   for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
      41             :     int code = config->GetAllocatableFloatCode(i);
      42             :     XMMRegister xmm_reg = XMMRegister::from_code(code);
      43      676935 :     int offset = code * kFloatSize;
      44     1353870 :     __ Movss(Operand(rsp, offset), xmm_reg);
      45             :   }
      46             : 
      47             :   // We push all registers onto the stack, even though we do not need
      48             :   // to restore all later.
      49      722064 :   for (int i = 0; i < kNumberOfRegisters; i++) {
      50      722064 :     Register r = Register::from_code(i);
      51      722064 :     __ pushq(r);
      52             :   }
      53             : 
      54             :   const int kSavedRegistersAreaSize =
      55             :       kNumberOfRegisters * kRegisterSize + kDoubleRegsSize + kFloatRegsSize;
      56             : 
      57             :   __ Store(
      58             :       ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate),
      59       45129 :       rbp);
      60             : 
      61             :   // We use this to keep the value of the fifth argument temporarily.
      62             :   // Unfortunately we can't store it directly in r8 (used for passing
      63             :   // this on linux), since it is another parameter passing register on windows.
      64             :   Register arg5 = r11;
      65             : 
      66             :   // The bailout id is passed using r13 on the stack.
      67             :   __ movp(arg_reg_3, r13);
      68             : 
      69             :   // Get the address of the location in the code object
      70             :   // and compute the fp-to-sp delta in register arg5.
      71       90258 :   __ movp(arg_reg_4, Operand(rsp, kSavedRegistersAreaSize));
      72       90258 :   __ leap(arg5, Operand(rsp, kSavedRegistersAreaSize + kPCOnStackSize));
      73             : 
      74       45129 :   __ subp(arg5, rbp);
      75             :   __ negp(arg5);
      76             : 
      77             :   // Allocate a new deoptimizer object.
      78       45129 :   __ PrepareCallCFunction(6);
      79             :   __ movp(rax, Immediate(0));
      80       45129 :   Label context_check;
      81       90258 :   __ movp(rdi, Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset));
      82       45129 :   __ JumpIfSmi(rdi, &context_check);
      83       90258 :   __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
      84       45129 :   __ bind(&context_check);
      85             :   __ movp(arg_reg_1, rax);
      86       45127 :   __ Set(arg_reg_2, static_cast<int>(deopt_kind));
      87             :   // Args 3 and 4 are already in the right registers.
      88             : 
      89             :   // On windows put the arguments on the stack (PrepareCallCFunction
      90             :   // has created space for this). On linux pass the arguments in r8 and r9.
      91             : #ifdef _WIN64
      92             :   __ movq(Operand(rsp, 4 * kRegisterSize), arg5);
      93             :   __ LoadAddress(arg5, ExternalReference::isolate_address(isolate));
      94             :   __ movq(Operand(rsp, 5 * kRegisterSize), arg5);
      95             : #else
      96             :   __ movp(r8, arg5);
      97       45129 :   __ LoadAddress(r9, ExternalReference::isolate_address(isolate));
      98             : #endif
      99             : 
     100             :   {
     101             :     AllowExternalCallThatCantCauseGC scope(masm);
     102       45129 :     __ CallCFunction(ExternalReference::new_deoptimizer_function(), 6);
     103             :   }
     104             :   // Preserve deoptimizer object in register rax and get the input
     105             :   // frame descriptor pointer.
     106       90262 :   __ movp(rbx, Operand(rax, Deoptimizer::input_offset()));
     107             : 
     108             :   // Fill in the input registers.
     109      767184 :   for (int i = kNumberOfRegisters -1; i >= 0; i--) {
     110      722054 :     int offset = (i * kRegisterSize) + FrameDescription::registers_offset();
     111      722054 :     __ PopQuad(Operand(rbx, offset));
     112             :   }
     113             : 
     114             :   // Fill in the float input registers.
     115             :   int float_regs_offset = FrameDescription::float_registers_offset();
     116      722060 :   for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
     117      722061 :     int src_offset = i * kFloatSize;
     118      722061 :     int dst_offset = i * kFloatSize + float_regs_offset;
     119     1444123 :     __ movl(rcx, Operand(rsp, src_offset));
     120     1444122 :     __ movl(Operand(rbx, dst_offset), rcx);
     121             :   }
     122       45129 :   __ addp(rsp, Immediate(kFloatRegsSize));
     123             : 
     124             :   // Fill in the double input registers.
     125             :   int double_regs_offset = FrameDescription::double_registers_offset();
     126      767185 :   for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
     127      722056 :     int dst_offset = i * kDoubleSize + double_regs_offset;
     128      722056 :     __ popq(Operand(rbx, dst_offset));
     129             :   }
     130             : 
     131             :   // Remove the return address from the stack.
     132       45129 :   __ addp(rsp, Immediate(kPCOnStackSize));
     133             : 
     134             :   // Compute a pointer to the unwinding limit in register rcx; that is
     135             :   // the first stack slot not part of the input frame.
     136       90258 :   __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     137       45129 :   __ addp(rcx, rsp);
     138             : 
     139             :   // Unwind the stack down to - but not including - the unwinding
     140             :   // limit and copy the contents of the activation frame to the input
     141             :   // frame description.
     142       90258 :   __ leap(rdx, Operand(rbx, FrameDescription::frame_content_offset()));
     143       45129 :   Label pop_loop_header;
     144       45129 :   __ jmp(&pop_loop_header);
     145       45129 :   Label pop_loop;
     146       45129 :   __ bind(&pop_loop);
     147       45129 :   __ Pop(Operand(rdx, 0));
     148       45129 :   __ addp(rdx, Immediate(sizeof(intptr_t)));
     149       45128 :   __ bind(&pop_loop_header);
     150       45129 :   __ cmpp(rcx, rsp);
     151       45129 :   __ j(not_equal, &pop_loop);
     152             : 
     153             :   // Compute the output frame in the deoptimizer.
     154       45128 :   __ pushq(rax);
     155       45129 :   __ PrepareCallCFunction(2);
     156             :   __ movp(arg_reg_1, rax);
     157       45127 :   __ LoadAddress(arg_reg_2, ExternalReference::isolate_address(isolate));
     158             :   {
     159             :     AllowExternalCallThatCantCauseGC scope(masm);
     160       45129 :     __ CallCFunction(ExternalReference::compute_output_frames_function(), 2);
     161             :   }
     162       45129 :   __ popq(rax);
     163             : 
     164       90256 :   __ movp(rsp, Operand(rax, Deoptimizer::caller_frame_top_offset()));
     165             : 
     166             :   // Replace the current (input) frame with the output frames.
     167       45129 :   Label outer_push_loop, inner_push_loop,
     168       45129 :       outer_loop_header, inner_loop_header;
     169             :   // Outer loop state: rax = current FrameDescription**, rdx = one past the
     170             :   // last FrameDescription**.
     171       90257 :   __ movl(rdx, Operand(rax, Deoptimizer::output_count_offset()));
     172       90257 :   __ movp(rax, Operand(rax, Deoptimizer::output_offset()));
     173       90257 :   __ leap(rdx, Operand(rax, rdx, times_pointer_size, 0));
     174       45128 :   __ jmp(&outer_loop_header);
     175       45127 :   __ bind(&outer_push_loop);
     176             :   // Inner loop state: rbx = current FrameDescription*, rcx = loop index.
     177       90256 :   __ movp(rbx, Operand(rax, 0));
     178       90257 :   __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     179       45129 :   __ jmp(&inner_loop_header);
     180       45129 :   __ bind(&inner_push_loop);
     181       45129 :   __ subp(rcx, Immediate(sizeof(intptr_t)));
     182       45129 :   __ Push(Operand(rbx, rcx, times_1, FrameDescription::frame_content_offset()));
     183       45129 :   __ bind(&inner_loop_header);
     184             :   __ testp(rcx, rcx);
     185       45126 :   __ j(not_zero, &inner_push_loop);
     186       45127 :   __ addp(rax, Immediate(kSystemPointerSize));
     187       45129 :   __ bind(&outer_loop_header);
     188       45129 :   __ cmpp(rax, rdx);
     189       45128 :   __ j(below, &outer_push_loop);
     190             : 
     191     1444120 :   for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
     192             :     int code = config->GetAllocatableDoubleCode(i);
     193             :     XMMRegister xmm_reg = XMMRegister::from_code(code);
     194      676931 :     int src_offset = code * kDoubleSize + double_regs_offset;
     195     1353862 :     __ Movsd(xmm_reg, Operand(rbx, src_offset));
     196             :   }
     197             : 
     198             :   // Push pc and continuation from the last output frame.
     199       45129 :   __ PushQuad(Operand(rbx, FrameDescription::pc_offset()));
     200       45129 :   __ PushQuad(Operand(rbx, FrameDescription::continuation_offset()));
     201             : 
     202             :   // Push the registers from the last output frame.
     203      767186 :   for (int i = 0; i < kNumberOfRegisters; i++) {
     204      722059 :     int offset = (i * kRegisterSize) + FrameDescription::registers_offset();
     205      722059 :     __ PushQuad(Operand(rbx, offset));
     206             :   }
     207             : 
     208             :   // Restore the registers from the stack.
     209      722056 :   for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) {
     210             :     Register r = Register::from_code(i);
     211             :     // Do not restore rsp, simply pop the value into the next register
     212             :     // and overwrite this afterwards.
     213      722054 :     if (r == rsp) {
     214             :       DCHECK_GT(i, 0);
     215       45129 :       r = Register::from_code(i - 1);
     216             :     }
     217      722054 :     __ popq(r);
     218             :   }
     219             : 
     220             :   // Return to the continuation point.
     221       45129 :   __ ret(0);
     222       45129 : }
     223             : 
     224      282462 : bool Deoptimizer::PadTopOfStackRegister() { return false; }
     225             : 
     226      146530 : void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
     227             :   if (kPCOnStackSize == 2 * kSystemPointerSize) {
     228             :     // Zero out the high-32 bit of PC for x32 port.
     229             :     SetFrameSlot(offset + kSystemPointerSize, 0);
     230             :   }
     231             :   SetFrameSlot(offset, value);
     232      146530 : }
     233             : 
     234             : 
     235      146530 : void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
     236             :   if (kFPOnStackSize == 2 * kSystemPointerSize) {
     237             :     // Zero out the high-32 bit of FP for x32 port.
     238             :     SetFrameSlot(offset + kSystemPointerSize, 0);
     239             :   }
     240             :   SetFrameSlot(offset, value);
     241      146530 : }
     242             : 
     243             : 
     244           0 : void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
     245             :   // No embedded constant pool support.
     246           0 :   UNREACHABLE();
     247             : }
     248             : 
     249             : 
     250             : #undef __
     251             : 
     252             : 
     253             : }  // namespace internal
     254      183867 : }  // namespace v8
     255             : 
     256             : #endif  // V8_TARGET_ARCH_X64

Generated by: LCOV version 1.10