LCOV - code coverage report
Current view: top level - src/x64 - deoptimizer-x64.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 88 90 97.8 %
Date: 2019-04-17 Functions: 5 6 83.3 %

          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       44763 : 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       44763 :   __ subq(rsp, Immediate(kDoubleRegsSize));
      28             : 
      29       44763 :   const RegisterConfiguration* config = RegisterConfiguration::Default();
      30     1387653 :   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      671445 :     int offset = code * kDoubleSize;
      34     1342890 :     __ Movsd(Operand(rsp, offset), xmm_reg);
      35             :   }
      36             : 
      37             :   const int kFloatRegsSize = kFloatSize * XMMRegister::kNumRegisters;
      38             :   __ subq(rsp, Immediate(kFloatRegsSize));
      39             : 
      40     1387653 :   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      671445 :     int offset = code * kFloatSize;
      44     1342890 :     __ 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     1477179 :   for (int i = 0; i < kNumberOfRegisters; i++) {
      50      716208 :     Register r = Register::from_code(i);
      51      716208 :     __ pushq(r);
      52             :   }
      53             : 
      54             :   const int kSavedRegistersAreaSize = kNumberOfRegisters * kSystemPointerSize +
      55             :                                       kDoubleRegsSize + kFloatRegsSize;
      56             : 
      57       44763 :   __ Store(
      58             :       ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate),
      59       44763 :       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             :   __ movq(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       89526 :   __ movq(arg_reg_4, Operand(rsp, kSavedRegistersAreaSize));
      72       89526 :   __ leaq(arg5, Operand(rsp, kSavedRegistersAreaSize + kPCOnStackSize));
      73             : 
      74             :   __ subq(arg5, rbp);
      75             :   __ negq(arg5);
      76             : 
      77             :   // Allocate a new deoptimizer object.
      78       44763 :   __ PrepareCallCFunction(6);
      79             :   __ movq(rax, Immediate(0));
      80       44763 :   Label context_check;
      81       89526 :   __ movq(rdi, Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset));
      82       44763 :   __ JumpIfSmi(rdi, &context_check);
      83       89526 :   __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
      84       44763 :   __ bind(&context_check);
      85             :   __ movq(arg_reg_1, rax);
      86       44763 :   __ 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 * kSystemPointerSize), arg5);
      93             :   __ LoadAddress(arg5, ExternalReference::isolate_address(isolate));
      94             :   __ movq(Operand(rsp, 5 * kSystemPointerSize), arg5);
      95             : #else
      96             :   __ movq(r8, arg5);
      97       44763 :   __ LoadAddress(r9, ExternalReference::isolate_address(isolate));
      98             : #endif
      99             : 
     100             :   {
     101             :     AllowExternalCallThatCantCauseGC scope(masm);
     102       44763 :     __ CallCFunction(ExternalReference::new_deoptimizer_function(), 6);
     103             :   }
     104             :   // Preserve deoptimizer object in register rax and get the input
     105             :   // frame descriptor pointer.
     106       89526 :   __ movq(rbx, Operand(rax, Deoptimizer::input_offset()));
     107             : 
     108             :   // Fill in the input registers.
     109     1477179 :   for (int i = kNumberOfRegisters -1; i >= 0; i--) {
     110             :     int offset =
     111      716208 :         (i * kSystemPointerSize) + FrameDescription::registers_offset();
     112      716208 :     __ PopQuad(Operand(rbx, offset));
     113             :   }
     114             : 
     115             :   // Fill in the float input registers.
     116             :   int float_regs_offset = FrameDescription::float_registers_offset();
     117     1477179 :   for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
     118      716208 :     int src_offset = i * kFloatSize;
     119      716208 :     int dst_offset = i * kFloatSize + float_regs_offset;
     120     1432416 :     __ movl(rcx, Operand(rsp, src_offset));
     121     1432416 :     __ movl(Operand(rbx, dst_offset), rcx);
     122             :   }
     123             :   __ addq(rsp, Immediate(kFloatRegsSize));
     124             : 
     125             :   // Fill in the double input registers.
     126             :   int double_regs_offset = FrameDescription::double_registers_offset();
     127     1477179 :   for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
     128      716208 :     int dst_offset = i * kDoubleSize + double_regs_offset;
     129      716208 :     __ popq(Operand(rbx, dst_offset));
     130             :   }
     131             : 
     132             :   // Remove the return address from the stack.
     133             :   __ addq(rsp, Immediate(kPCOnStackSize));
     134             : 
     135             :   // Compute a pointer to the unwinding limit in register rcx; that is
     136             :   // the first stack slot not part of the input frame.
     137       89526 :   __ movq(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     138             :   __ addq(rcx, rsp);
     139             : 
     140             :   // Unwind the stack down to - but not including - the unwinding
     141             :   // limit and copy the contents of the activation frame to the input
     142             :   // frame description.
     143       89526 :   __ leaq(rdx, Operand(rbx, FrameDescription::frame_content_offset()));
     144       44763 :   Label pop_loop_header;
     145       44763 :   __ jmp(&pop_loop_header);
     146       44763 :   Label pop_loop;
     147       44763 :   __ bind(&pop_loop);
     148       44763 :   __ Pop(Operand(rdx, 0));
     149             :   __ addq(rdx, Immediate(sizeof(intptr_t)));
     150       44763 :   __ bind(&pop_loop_header);
     151             :   __ cmpq(rcx, rsp);
     152       44763 :   __ j(not_equal, &pop_loop);
     153             : 
     154             :   // Compute the output frame in the deoptimizer.
     155       44763 :   __ pushq(rax);
     156       44763 :   __ PrepareCallCFunction(2);
     157             :   __ movq(arg_reg_1, rax);
     158       44763 :   __ LoadAddress(arg_reg_2, ExternalReference::isolate_address(isolate));
     159             :   {
     160             :     AllowExternalCallThatCantCauseGC scope(masm);
     161       44763 :     __ CallCFunction(ExternalReference::compute_output_frames_function(), 2);
     162             :   }
     163       44763 :   __ popq(rax);
     164             : 
     165       89526 :   __ movq(rsp, Operand(rax, Deoptimizer::caller_frame_top_offset()));
     166             : 
     167             :   // Replace the current (input) frame with the output frames.
     168       44763 :   Label outer_push_loop, inner_push_loop,
     169       44763 :       outer_loop_header, inner_loop_header;
     170             :   // Outer loop state: rax = current FrameDescription**, rdx = one past the
     171             :   // last FrameDescription**.
     172       89526 :   __ movl(rdx, Operand(rax, Deoptimizer::output_count_offset()));
     173       89526 :   __ movq(rax, Operand(rax, Deoptimizer::output_offset()));
     174       89526 :   __ leaq(rdx, Operand(rax, rdx, times_system_pointer_size, 0));
     175       44763 :   __ jmp(&outer_loop_header);
     176       44763 :   __ bind(&outer_push_loop);
     177             :   // Inner loop state: rbx = current FrameDescription*, rcx = loop index.
     178       89526 :   __ movq(rbx, Operand(rax, 0));
     179       89526 :   __ movq(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     180       44763 :   __ jmp(&inner_loop_header);
     181       44763 :   __ bind(&inner_push_loop);
     182             :   __ subq(rcx, Immediate(sizeof(intptr_t)));
     183       44763 :   __ Push(Operand(rbx, rcx, times_1, FrameDescription::frame_content_offset()));
     184       44763 :   __ bind(&inner_loop_header);
     185             :   __ testq(rcx, rcx);
     186       44763 :   __ j(not_zero, &inner_push_loop);
     187             :   __ addq(rax, Immediate(kSystemPointerSize));
     188       44763 :   __ bind(&outer_loop_header);
     189             :   __ cmpq(rax, rdx);
     190       44763 :   __ j(below, &outer_push_loop);
     191             : 
     192     1387653 :   for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
     193             :     int code = config->GetAllocatableDoubleCode(i);
     194             :     XMMRegister xmm_reg = XMMRegister::from_code(code);
     195      671445 :     int src_offset = code * kDoubleSize + double_regs_offset;
     196     1342890 :     __ Movsd(xmm_reg, Operand(rbx, src_offset));
     197             :   }
     198             : 
     199             :   // Push pc and continuation from the last output frame.
     200       44763 :   __ PushQuad(Operand(rbx, FrameDescription::pc_offset()));
     201       44763 :   __ PushQuad(Operand(rbx, FrameDescription::continuation_offset()));
     202             : 
     203             :   // Push the registers from the last output frame.
     204     1477179 :   for (int i = 0; i < kNumberOfRegisters; i++) {
     205             :     int offset =
     206      716208 :         (i * kSystemPointerSize) + FrameDescription::registers_offset();
     207      716208 :     __ PushQuad(Operand(rbx, offset));
     208             :   }
     209             : 
     210             :   // Restore the registers from the stack.
     211     1477179 :   for (int i = kNumberOfRegisters - 1; i >= 0 ; i--) {
     212             :     Register r = Register::from_code(i);
     213             :     // Do not restore rsp, simply pop the value into the next register
     214             :     // and overwrite this afterwards.
     215      716208 :     if (r == rsp) {
     216             :       DCHECK_GT(i, 0);
     217       44763 :       r = Register::from_code(i - 1);
     218             :     }
     219      716208 :     __ popq(r);
     220             :   }
     221             : 
     222             :   // Return to the continuation point.
     223       44763 :   __ ret(0);
     224       44763 : }
     225             : 
     226      106160 : bool Deoptimizer::PadTopOfStackRegister() { return false; }
     227             : 
     228       58275 : void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
     229             :   if (kPCOnStackSize == 2 * kSystemPointerSize) {
     230             :     // Zero out the high-32 bit of PC for x32 port.
     231             :     SetFrameSlot(offset + kSystemPointerSize, 0);
     232             :   }
     233             :   SetFrameSlot(offset, value);
     234       58275 : }
     235             : 
     236             : 
     237       58275 : void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
     238             :   if (kFPOnStackSize == 2 * kSystemPointerSize) {
     239             :     // Zero out the high-32 bit of FP for x32 port.
     240             :     SetFrameSlot(offset + kSystemPointerSize, 0);
     241             :   }
     242             :   SetFrameSlot(offset, value);
     243       58275 : }
     244             : 
     245             : 
     246           0 : void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
     247             :   // No embedded constant pool support.
     248           0 :   UNREACHABLE();
     249             : }
     250             : 
     251             : 
     252             : #undef __
     253             : 
     254             : 
     255             : }  // namespace internal
     256      121996 : }  // namespace v8
     257             : 
     258             : #endif  // V8_TARGET_ARCH_X64

Generated by: LCOV version 1.10