LCOV - code coverage report
Current view: top level - src/x64 - deoptimizer-x64.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 109 111 98.2 %
Date: 2017-10-20 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/objects-inl.h"
       9             : #include "src/register-configuration.h"
      10             : #include "src/safepoint-table.h"
      11             : 
      12             : namespace v8 {
      13             : namespace internal {
      14             : 
      15             : 
      16             : const int Deoptimizer::table_entry_size_ = 10;
      17             : 
      18             : #define __ masm()->
      19             : 
      20     8724064 : void Deoptimizer::TableEntryGenerator::Generate() {
      21       38432 :   GeneratePrologue();
      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       38432 :   __ subp(rsp, Immediate(kDoubleRegsSize));
      28             : 
      29     3036128 :   const RegisterConfiguration* config = RegisterConfiguration::Default();
      30     1229824 :   for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
      31             :     int code = config->GetAllocatableDoubleCode(i);
      32      576480 :     XMMRegister xmm_reg = XMMRegister::from_code(code);
      33      576480 :     int offset = code * kDoubleSize;
      34     1152960 :     __ Movsd(Operand(rsp, offset), xmm_reg);
      35             :   }
      36             : 
      37             :   const int kFloatRegsSize = kFloatSize * XMMRegister::kNumRegisters;
      38       38432 :   __ subp(rsp, Immediate(kFloatRegsSize));
      39             : 
      40     1229824 :   for (int i = 0; i < config->num_allocatable_float_registers(); ++i) {
      41             :     int code = config->GetAllocatableFloatCode(i);
      42      576480 :     XMMRegister xmm_reg = XMMRegister::from_code(code);
      43      576480 :     int offset = code * kFloatSize;
      44     1152960 :     __ 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      614912 :   for (int i = 0; i < kNumberOfRegisters; i++) {
      50      614912 :     Register r = Register::from_code(i);
      51      614912 :     __ pushq(r);
      52             :   }
      53             : 
      54             :   const int kSavedRegistersAreaSize =
      55             :       kNumberOfRegisters * kRegisterSize + kDoubleRegsSize + kFloatRegsSize;
      56             : 
      57             :   __ Store(ExternalReference(IsolateAddressId::kCEntryFPAddress, isolate()),
      58       76864 :            rbp);
      59             : 
      60             :   // We use this to keep the value of the fifth argument temporarily.
      61             :   // Unfortunately we can't store it directly in r8 (used for passing
      62             :   // this on linux), since it is another parameter passing register on windows.
      63             :   Register arg5 = r11;
      64             : 
      65             :   // Get the bailout id from the stack.
      66      115296 :   __ movp(arg_reg_3, Operand(rsp, kSavedRegistersAreaSize));
      67             : 
      68             :   // Get the address of the location in the code object
      69             :   // and compute the fp-to-sp delta in register arg5.
      70      115296 :   __ movp(arg_reg_4, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize));
      71             :   __ leap(arg5, Operand(rsp, kSavedRegistersAreaSize + 1 * kRegisterSize +
      72      115296 :                             kPCOnStackSize));
      73             : 
      74       38432 :   __ subp(arg5, rbp);
      75       38432 :   __ negp(arg5);
      76             : 
      77             :   // Allocate a new deoptimizer object.
      78       38432 :   __ PrepareCallCFunction(6);
      79       38432 :   __ movp(rax, Immediate(0));
      80             :   Label context_check;
      81      115296 :   __ movp(rdi, Operand(rbp, CommonFrameConstants::kContextOrFrameTypeOffset));
      82       38432 :   __ JumpIfSmi(rdi, &context_check);
      83      115296 :   __ movp(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
      84       38432 :   __ bind(&context_check);
      85       38432 :   __ movp(arg_reg_1, rax);
      86       76864 :   __ Set(arg_reg_2, type());
      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       38432 :   __ movp(r8, arg5);
      97       76864 :   __ LoadAddress(r9, ExternalReference::isolate_address(isolate()));
      98             : #endif
      99             : 
     100             :   { AllowExternalCallThatCantCauseGC scope(masm());
     101       76864 :     __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
     102             :   }
     103             :   // Preserve deoptimizer object in register rax and get the input
     104             :   // frame descriptor pointer.
     105      115296 :   __ movp(rbx, Operand(rax, Deoptimizer::input_offset()));
     106             : 
     107             :   // Fill in the input registers.
     108      653344 :   for (int i = kNumberOfRegisters -1; i >= 0; i--) {
     109      614912 :     int offset = (i * kPointerSize) + FrameDescription::registers_offset();
     110     1229824 :     __ PopQuad(Operand(rbx, offset));
     111             :   }
     112             : 
     113             :   // Fill in the float input registers.
     114             :   int float_regs_offset = FrameDescription::float_registers_offset();
     115      614912 :   for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
     116      614912 :     int src_offset = i * kFloatSize;
     117      614912 :     int dst_offset = i * kFloatSize + float_regs_offset;
     118     1844736 :     __ movl(rcx, Operand(rsp, src_offset));
     119     1844736 :     __ movl(Operand(rbx, dst_offset), rcx);
     120             :   }
     121       38432 :   __ addp(rsp, Immediate(kFloatRegsSize));
     122             : 
     123             :   // Fill in the double input registers.
     124             :   int double_regs_offset = FrameDescription::double_registers_offset();
     125      653344 :   for (int i = 0; i < XMMRegister::kNumRegisters; i++) {
     126      614912 :     int dst_offset = i * kDoubleSize + double_regs_offset;
     127     1229824 :     __ popq(Operand(rbx, dst_offset));
     128             :   }
     129             : 
     130             :   // Remove the bailout id and return address from the stack.
     131       38432 :   __ addp(rsp, Immediate(1 * kRegisterSize + kPCOnStackSize));
     132             : 
     133             :   // Compute a pointer to the unwinding limit in register rcx; that is
     134             :   // the first stack slot not part of the input frame.
     135      115296 :   __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     136       38432 :   __ addp(rcx, rsp);
     137             : 
     138             :   // Unwind the stack down to - but not including - the unwinding
     139             :   // limit and copy the contents of the activation frame to the input
     140             :   // frame description.
     141      115296 :   __ leap(rdx, Operand(rbx, FrameDescription::frame_content_offset()));
     142             :   Label pop_loop_header;
     143       38432 :   __ jmp(&pop_loop_header);
     144             :   Label pop_loop;
     145       38432 :   __ bind(&pop_loop);
     146       76864 :   __ Pop(Operand(rdx, 0));
     147       38432 :   __ addp(rdx, Immediate(sizeof(intptr_t)));
     148       38432 :   __ bind(&pop_loop_header);
     149       38432 :   __ cmpp(rcx, rsp);
     150       38432 :   __ j(not_equal, &pop_loop);
     151             : 
     152             :   // Compute the output frame in the deoptimizer.
     153       38432 :   __ pushq(rax);
     154       38432 :   __ PrepareCallCFunction(2);
     155       38432 :   __ movp(arg_reg_1, rax);
     156       76864 :   __ LoadAddress(arg_reg_2, ExternalReference::isolate_address(isolate()));
     157             :   {
     158             :     AllowExternalCallThatCantCauseGC scope(masm());
     159             :     __ CallCFunction(
     160       76864 :         ExternalReference::compute_output_frames_function(isolate()), 2);
     161             :   }
     162       38432 :   __ popq(rax);
     163             : 
     164      115296 :   __ movp(rsp, Operand(rax, Deoptimizer::caller_frame_top_offset()));
     165             : 
     166             :   // Replace the current (input) frame with the output frames.
     167             :   Label outer_push_loop, inner_push_loop,
     168             :       outer_loop_header, inner_loop_header;
     169             :   // Outer loop state: rax = current FrameDescription**, rdx = one past the
     170             :   // last FrameDescription**.
     171      115296 :   __ movl(rdx, Operand(rax, Deoptimizer::output_count_offset()));
     172      115296 :   __ movp(rax, Operand(rax, Deoptimizer::output_offset()));
     173      115296 :   __ leap(rdx, Operand(rax, rdx, times_pointer_size, 0));
     174       38432 :   __ jmp(&outer_loop_header);
     175       38432 :   __ bind(&outer_push_loop);
     176             :   // Inner loop state: rbx = current FrameDescription*, rcx = loop index.
     177      115296 :   __ movp(rbx, Operand(rax, 0));
     178      115296 :   __ movp(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
     179       38432 :   __ jmp(&inner_loop_header);
     180       38432 :   __ bind(&inner_push_loop);
     181       38432 :   __ subp(rcx, Immediate(sizeof(intptr_t)));
     182       76864 :   __ Push(Operand(rbx, rcx, times_1, FrameDescription::frame_content_offset()));
     183       38432 :   __ bind(&inner_loop_header);
     184       38432 :   __ testp(rcx, rcx);
     185       38432 :   __ j(not_zero, &inner_push_loop);
     186       38432 :   __ addp(rax, Immediate(kPointerSize));
     187       38432 :   __ bind(&outer_loop_header);
     188       38432 :   __ cmpp(rax, rdx);
     189       38432 :   __ j(below, &outer_push_loop);
     190             : 
     191     1229824 :   for (int i = 0; i < config->num_allocatable_double_registers(); ++i) {
     192             :     int code = config->GetAllocatableDoubleCode(i);
     193      576480 :     XMMRegister xmm_reg = XMMRegister::from_code(code);
     194      576480 :     int src_offset = code * kDoubleSize + double_regs_offset;
     195     1152960 :     __ Movsd(xmm_reg, Operand(rbx, src_offset));
     196             :   }
     197             : 
     198             :   // Push pc and continuation from the last output frame.
     199       76864 :   __ PushQuad(Operand(rbx, FrameDescription::pc_offset()));
     200       76864 :   __ PushQuad(Operand(rbx, FrameDescription::continuation_offset()));
     201             : 
     202             :   // Push the registers from the last output frame.
     203      653344 :   for (int i = 0; i < kNumberOfRegisters; i++) {
     204      614912 :     int offset = (i * kPointerSize) + FrameDescription::registers_offset();
     205     1229824 :     __ PushQuad(Operand(rbx, offset));
     206             :   }
     207             : 
     208             :   // Restore the registers from the stack.
     209      614912 :   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      614912 :     if (r == rsp) {
     214             :       DCHECK_GT(i, 0);
     215       38432 :       r = Register::from_code(i - 1);
     216             :     }
     217      614912 :     __ popq(r);
     218             :   }
     219             : 
     220             :   // Set up the roots register.
     221       38432 :   __ InitializeRootRegister();
     222             : 
     223             :   // Return to the continuation point.
     224       38432 :   __ ret(0);
     225       38432 : }
     226             : 
     227             : 
     228  1798919514 : void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
     229             :   // Create a sequence of deoptimization entries.
     230             :   Label done;
     231  1199280370 :   for (int i = 0; i < count(); i++) {
     232             :     int start = masm()->pc_offset();
     233             :     USE(start);
     234   599601753 :     __ pushq_imm32(i);
     235   599600455 :     __ jmp(&done);
     236             :     DCHECK(masm()->pc_offset() - start == table_entry_size_);
     237             :   }
     238       38432 :   __ bind(&done);
     239       38432 : }
     240             : 
     241      293646 : bool Deoptimizer::PadTopOfStackRegister() { return false; }
     242             : 
     243      155866 : void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
     244             :   if (kPCOnStackSize == 2 * kPointerSize) {
     245             :     // Zero out the high-32 bit of PC for x32 port.
     246             :     SetFrameSlot(offset + kPointerSize, 0);
     247             :   }
     248             :   SetFrameSlot(offset, value);
     249      155866 : }
     250             : 
     251             : 
     252      155866 : void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
     253             :   if (kFPOnStackSize == 2 * kPointerSize) {
     254             :     // Zero out the high-32 bit of FP for x32 port.
     255             :     SetFrameSlot(offset + kPointerSize, 0);
     256             :   }
     257             :   SetFrameSlot(offset, value);
     258      155866 : }
     259             : 
     260             : 
     261           0 : void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
     262             :   // No embedded constant pool support.
     263           0 :   UNREACHABLE();
     264             : }
     265             : 
     266             : 
     267             : #undef __
     268             : 
     269             : 
     270             : }  // namespace internal
     271             : }  // namespace v8
     272             : 
     273             : #endif  // V8_TARGET_ARCH_X64

Generated by: LCOV version 1.10