Home | History | Annotate | Download | only in x64
      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 #include "src/x64/codegen-x64.h"
      6 
      7 #if V8_TARGET_ARCH_X64
      8 
      9 #include "src/codegen.h"
     10 #include "src/macro-assembler.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 // -------------------------------------------------------------------------
     16 // Platform-specific RuntimeCallHelper functions.
     17 
     18 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
     19   masm->EnterFrame(StackFrame::INTERNAL);
     20   DCHECK(!masm->has_frame());
     21   masm->set_has_frame(true);
     22 }
     23 
     24 
     25 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
     26   masm->LeaveFrame(StackFrame::INTERNAL);
     27   DCHECK(masm->has_frame());
     28   masm->set_has_frame(false);
     29 }
     30 
     31 
     32 #define __ masm.
     33 
     34 
     35 UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
     36   size_t actual_size;
     37   byte* buffer =
     38       static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
     39   if (buffer == nullptr) return nullptr;
     40   ExternalReference::InitializeMathExpData();
     41 
     42   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
     43                       CodeObjectRequired::kNo);
     44   // xmm0: raw double input.
     45   XMMRegister input = xmm0;
     46   XMMRegister result = xmm1;
     47   __ pushq(rax);
     48   __ pushq(rbx);
     49 
     50   MathExpGenerator::EmitMathExp(&masm, input, result, xmm2, rax, rbx);
     51 
     52   __ popq(rbx);
     53   __ popq(rax);
     54   __ Movsd(xmm0, result);
     55   __ Ret();
     56 
     57   CodeDesc desc;
     58   masm.GetCode(&desc);
     59   DCHECK(!RelocInfo::RequiresRelocation(desc));
     60 
     61   Assembler::FlushICache(isolate, buffer, actual_size);
     62   base::OS::ProtectCode(buffer, actual_size);
     63   return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
     64 }
     65 
     66 
     67 UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
     68   size_t actual_size;
     69   // Allocate buffer in executable space.
     70   byte* buffer =
     71       static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
     72   if (buffer == nullptr) return nullptr;
     73 
     74   MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
     75                       CodeObjectRequired::kNo);
     76   // xmm0: raw double input.
     77   // Move double input into registers.
     78   __ Sqrtsd(xmm0, xmm0);
     79   __ Ret();
     80 
     81   CodeDesc desc;
     82   masm.GetCode(&desc);
     83   DCHECK(!RelocInfo::RequiresRelocation(desc));
     84 
     85   Assembler::FlushICache(isolate, buffer, actual_size);
     86   base::OS::ProtectCode(buffer, actual_size);
     87   return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
     88 }
     89 
     90 #undef __
     91 
     92 // -------------------------------------------------------------------------
     93 // Code generators
     94 
     95 #define __ ACCESS_MASM(masm)
     96 
     97 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
     98     MacroAssembler* masm,
     99     Register receiver,
    100     Register key,
    101     Register value,
    102     Register target_map,
    103     AllocationSiteMode mode,
    104     Label* allocation_memento_found) {
    105   // Return address is on the stack.
    106   Register scratch = rdi;
    107   DCHECK(!AreAliased(receiver, key, value, target_map, scratch));
    108 
    109   if (mode == TRACK_ALLOCATION_SITE) {
    110     DCHECK(allocation_memento_found != NULL);
    111     __ JumpIfJSArrayHasAllocationMemento(
    112         receiver, scratch, allocation_memento_found);
    113   }
    114 
    115   // Set transitioned map.
    116   __ movp(FieldOperand(receiver, HeapObject::kMapOffset), target_map);
    117   __ RecordWriteField(receiver,
    118                       HeapObject::kMapOffset,
    119                       target_map,
    120                       scratch,
    121                       kDontSaveFPRegs,
    122                       EMIT_REMEMBERED_SET,
    123                       OMIT_SMI_CHECK);
    124 }
    125 
    126 
    127 void ElementsTransitionGenerator::GenerateSmiToDouble(
    128     MacroAssembler* masm,
    129     Register receiver,
    130     Register key,
    131     Register value,
    132     Register target_map,
    133     AllocationSiteMode mode,
    134     Label* fail) {
    135   // Return address is on the stack.
    136   DCHECK(receiver.is(rdx));
    137   DCHECK(key.is(rcx));
    138   DCHECK(value.is(rax));
    139   DCHECK(target_map.is(rbx));
    140 
    141   // The fail label is not actually used since we do not allocate.
    142   Label allocated, new_backing_store, only_change_map, done;
    143 
    144   if (mode == TRACK_ALLOCATION_SITE) {
    145     __ JumpIfJSArrayHasAllocationMemento(rdx, rdi, fail);
    146   }
    147 
    148   // Check for empty arrays, which only require a map transition and no changes
    149   // to the backing store.
    150   __ movp(r8, FieldOperand(rdx, JSObject::kElementsOffset));
    151   __ CompareRoot(r8, Heap::kEmptyFixedArrayRootIndex);
    152   __ j(equal, &only_change_map);
    153 
    154   __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
    155   if (kPointerSize == kDoubleSize) {
    156     // Check backing store for COW-ness. For COW arrays we have to
    157     // allocate a new backing store.
    158     __ CompareRoot(FieldOperand(r8, HeapObject::kMapOffset),
    159                    Heap::kFixedCOWArrayMapRootIndex);
    160     __ j(equal, &new_backing_store);
    161   } else {
    162     // For x32 port we have to allocate a new backing store as SMI size is
    163     // not equal with double size.
    164     DCHECK(kDoubleSize == 2 * kPointerSize);
    165     __ jmp(&new_backing_store);
    166   }
    167 
    168   // Check if the backing store is in new-space. If not, we need to allocate
    169   // a new one since the old one is in pointer-space.
    170   // If in new space, we can reuse the old backing store because it is
    171   // the same size.
    172   __ JumpIfNotInNewSpace(r8, rdi, &new_backing_store);
    173 
    174   __ movp(r14, r8);  // Destination array equals source array.
    175 
    176   // r8 : source FixedArray
    177   // r9 : elements array length
    178   // r14: destination FixedDoubleArray
    179   // Set backing store's map
    180   __ LoadRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
    181   __ movp(FieldOperand(r14, HeapObject::kMapOffset), rdi);
    182 
    183   __ bind(&allocated);
    184   // Set transitioned map.
    185   __ movp(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
    186   __ RecordWriteField(rdx,
    187                       HeapObject::kMapOffset,
    188                       rbx,
    189                       rdi,
    190                       kDontSaveFPRegs,
    191                       EMIT_REMEMBERED_SET,
    192                       OMIT_SMI_CHECK);
    193 
    194   // Convert smis to doubles and holes to hole NaNs.  The Array's length
    195   // remains unchanged.
    196   STATIC_ASSERT(FixedDoubleArray::kLengthOffset == FixedArray::kLengthOffset);
    197   STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize);
    198 
    199   Label loop, entry, convert_hole;
    200   __ movq(r15, bit_cast<int64_t, uint64_t>(kHoleNanInt64));
    201   // r15: the-hole NaN
    202   __ jmp(&entry);
    203 
    204   // Allocate new backing store.
    205   __ bind(&new_backing_store);
    206   __ leap(rdi, Operand(r9, times_8, FixedArray::kHeaderSize));
    207   __ Allocate(rdi, r14, r11, r15, fail, TAG_OBJECT);
    208   // Set backing store's map
    209   __ LoadRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
    210   __ movp(FieldOperand(r14, HeapObject::kMapOffset), rdi);
    211   // Set receiver's backing store.
    212   __ movp(FieldOperand(rdx, JSObject::kElementsOffset), r14);
    213   __ movp(r11, r14);
    214   __ RecordWriteField(rdx,
    215                       JSObject::kElementsOffset,
    216                       r11,
    217                       r15,
    218                       kDontSaveFPRegs,
    219                       EMIT_REMEMBERED_SET,
    220                       OMIT_SMI_CHECK);
    221   // Set backing store's length.
    222   __ Integer32ToSmi(r11, r9);
    223   __ movp(FieldOperand(r14, FixedDoubleArray::kLengthOffset), r11);
    224   __ jmp(&allocated);
    225 
    226   __ bind(&only_change_map);
    227   // Set transitioned map.
    228   __ movp(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
    229   __ RecordWriteField(rdx,
    230                       HeapObject::kMapOffset,
    231                       rbx,
    232                       rdi,
    233                       kDontSaveFPRegs,
    234                       OMIT_REMEMBERED_SET,
    235                       OMIT_SMI_CHECK);
    236   __ jmp(&done);
    237 
    238   // Conversion loop.
    239   __ bind(&loop);
    240   __ movp(rbx,
    241           FieldOperand(r8, r9, times_pointer_size, FixedArray::kHeaderSize));
    242   // r9 : current element's index
    243   // rbx: current element (smi-tagged)
    244   __ JumpIfNotSmi(rbx, &convert_hole);
    245   __ SmiToInteger32(rbx, rbx);
    246   __ Cvtlsi2sd(xmm0, rbx);
    247   __ Movsd(FieldOperand(r14, r9, times_8, FixedDoubleArray::kHeaderSize), xmm0);
    248   __ jmp(&entry);
    249   __ bind(&convert_hole);
    250 
    251   if (FLAG_debug_code) {
    252     __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
    253     __ Assert(equal, kObjectFoundInSmiOnlyArray);
    254   }
    255 
    256   __ movq(FieldOperand(r14, r9, times_8, FixedDoubleArray::kHeaderSize), r15);
    257   __ bind(&entry);
    258   __ decp(r9);
    259   __ j(not_sign, &loop);
    260 
    261   __ bind(&done);
    262 }
    263 
    264 
    265 void ElementsTransitionGenerator::GenerateDoubleToObject(
    266     MacroAssembler* masm,
    267     Register receiver,
    268     Register key,
    269     Register value,
    270     Register target_map,
    271     AllocationSiteMode mode,
    272     Label* fail) {
    273   // Return address is on the stack.
    274   DCHECK(receiver.is(rdx));
    275   DCHECK(key.is(rcx));
    276   DCHECK(value.is(rax));
    277   DCHECK(target_map.is(rbx));
    278 
    279   Label loop, entry, convert_hole, gc_required, only_change_map;
    280 
    281   if (mode == TRACK_ALLOCATION_SITE) {
    282     __ JumpIfJSArrayHasAllocationMemento(rdx, rdi, fail);
    283   }
    284 
    285   // Check for empty arrays, which only require a map transition and no changes
    286   // to the backing store.
    287   __ movp(r8, FieldOperand(rdx, JSObject::kElementsOffset));
    288   __ CompareRoot(r8, Heap::kEmptyFixedArrayRootIndex);
    289   __ j(equal, &only_change_map);
    290 
    291   __ Push(rax);
    292 
    293   __ movp(r8, FieldOperand(rdx, JSObject::kElementsOffset));
    294   __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
    295   // r8 : source FixedDoubleArray
    296   // r9 : number of elements
    297   __ leap(rdi, Operand(r9, times_pointer_size, FixedArray::kHeaderSize));
    298   __ Allocate(rdi, r11, r14, r15, &gc_required, TAG_OBJECT);
    299   // r11: destination FixedArray
    300   __ LoadRoot(rdi, Heap::kFixedArrayMapRootIndex);
    301   __ movp(FieldOperand(r11, HeapObject::kMapOffset), rdi);
    302   __ Integer32ToSmi(r14, r9);
    303   __ movp(FieldOperand(r11, FixedArray::kLengthOffset), r14);
    304 
    305   // Prepare for conversion loop.
    306   __ movq(rsi, bit_cast<int64_t, uint64_t>(kHoleNanInt64));
    307   __ LoadRoot(rdi, Heap::kTheHoleValueRootIndex);
    308   // rsi: the-hole NaN
    309   // rdi: pointer to the-hole
    310 
    311   // Allocating heap numbers in the loop below can fail and cause a jump to
    312   // gc_required. We can't leave a partly initialized FixedArray behind,
    313   // so pessimistically fill it with holes now.
    314   Label initialization_loop, initialization_loop_entry;
    315   __ jmp(&initialization_loop_entry, Label::kNear);
    316   __ bind(&initialization_loop);
    317   __ movp(FieldOperand(r11, r9, times_pointer_size, FixedArray::kHeaderSize),
    318           rdi);
    319   __ bind(&initialization_loop_entry);
    320   __ decp(r9);
    321   __ j(not_sign, &initialization_loop);
    322 
    323   __ SmiToInteger32(r9, FieldOperand(r8, FixedDoubleArray::kLengthOffset));
    324   __ jmp(&entry);
    325 
    326   // Call into runtime if GC is required.
    327   __ bind(&gc_required);
    328   __ Pop(rax);
    329   __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
    330   __ jmp(fail);
    331 
    332   // Box doubles into heap numbers.
    333   __ bind(&loop);
    334   __ movq(r14, FieldOperand(r8,
    335                             r9,
    336                             times_8,
    337                             FixedDoubleArray::kHeaderSize));
    338   // r9 : current element's index
    339   // r14: current element
    340   __ cmpq(r14, rsi);
    341   __ j(equal, &convert_hole);
    342 
    343   // Non-hole double, copy value into a heap number.
    344   __ AllocateHeapNumber(rax, r15, &gc_required);
    345   // rax: new heap number
    346   __ movq(FieldOperand(rax, HeapNumber::kValueOffset), r14);
    347   __ movp(FieldOperand(r11,
    348                        r9,
    349                        times_pointer_size,
    350                        FixedArray::kHeaderSize),
    351           rax);
    352   __ movp(r15, r9);
    353   __ RecordWriteArray(r11,
    354                       rax,
    355                       r15,
    356                       kDontSaveFPRegs,
    357                       EMIT_REMEMBERED_SET,
    358                       OMIT_SMI_CHECK);
    359   __ jmp(&entry, Label::kNear);
    360 
    361   // Replace the-hole NaN with the-hole pointer.
    362   __ bind(&convert_hole);
    363   __ movp(FieldOperand(r11,
    364                        r9,
    365                        times_pointer_size,
    366                        FixedArray::kHeaderSize),
    367           rdi);
    368 
    369   __ bind(&entry);
    370   __ decp(r9);
    371   __ j(not_sign, &loop);
    372 
    373   // Replace receiver's backing store with newly created and filled FixedArray.
    374   __ movp(FieldOperand(rdx, JSObject::kElementsOffset), r11);
    375   __ RecordWriteField(rdx,
    376                       JSObject::kElementsOffset,
    377                       r11,
    378                       r15,
    379                       kDontSaveFPRegs,
    380                       EMIT_REMEMBERED_SET,
    381                       OMIT_SMI_CHECK);
    382   __ Pop(rax);
    383   __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
    384 
    385   __ bind(&only_change_map);
    386   // Set transitioned map.
    387   __ movp(FieldOperand(rdx, HeapObject::kMapOffset), rbx);
    388   __ RecordWriteField(rdx,
    389                       HeapObject::kMapOffset,
    390                       rbx,
    391                       rdi,
    392                       kDontSaveFPRegs,
    393                       OMIT_REMEMBERED_SET,
    394                       OMIT_SMI_CHECK);
    395 }
    396 
    397 
    398 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
    399                                        Register string,
    400                                        Register index,
    401                                        Register result,
    402                                        Label* call_runtime) {
    403   // Fetch the instance type of the receiver into result register.
    404   __ movp(result, FieldOperand(string, HeapObject::kMapOffset));
    405   __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset));
    406 
    407   // We need special handling for indirect strings.
    408   Label check_sequential;
    409   __ testb(result, Immediate(kIsIndirectStringMask));
    410   __ j(zero, &check_sequential, Label::kNear);
    411 
    412   // Dispatch on the indirect string shape: slice or cons.
    413   Label cons_string;
    414   __ testb(result, Immediate(kSlicedNotConsMask));
    415   __ j(zero, &cons_string, Label::kNear);
    416 
    417   // Handle slices.
    418   Label indirect_string_loaded;
    419   __ SmiToInteger32(result, FieldOperand(string, SlicedString::kOffsetOffset));
    420   __ addp(index, result);
    421   __ movp(string, FieldOperand(string, SlicedString::kParentOffset));
    422   __ jmp(&indirect_string_loaded, Label::kNear);
    423 
    424   // Handle cons strings.
    425   // Check whether the right hand side is the empty string (i.e. if
    426   // this is really a flat string in a cons string). If that is not
    427   // the case we would rather go to the runtime system now to flatten
    428   // the string.
    429   __ bind(&cons_string);
    430   __ CompareRoot(FieldOperand(string, ConsString::kSecondOffset),
    431                  Heap::kempty_stringRootIndex);
    432   __ j(not_equal, call_runtime);
    433   __ movp(string, FieldOperand(string, ConsString::kFirstOffset));
    434 
    435   __ bind(&indirect_string_loaded);
    436   __ movp(result, FieldOperand(string, HeapObject::kMapOffset));
    437   __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset));
    438 
    439   // Distinguish sequential and external strings. Only these two string
    440   // representations can reach here (slices and flat cons strings have been
    441   // reduced to the underlying sequential or external string).
    442   Label seq_string;
    443   __ bind(&check_sequential);
    444   STATIC_ASSERT(kSeqStringTag == 0);
    445   __ testb(result, Immediate(kStringRepresentationMask));
    446   __ j(zero, &seq_string, Label::kNear);
    447 
    448   // Handle external strings.
    449   Label one_byte_external, done;
    450   if (FLAG_debug_code) {
    451     // Assert that we do not have a cons or slice (indirect strings) here.
    452     // Sequential strings have already been ruled out.
    453     __ testb(result, Immediate(kIsIndirectStringMask));
    454     __ Assert(zero, kExternalStringExpectedButNotFound);
    455   }
    456   // Rule out short external strings.
    457   STATIC_ASSERT(kShortExternalStringTag != 0);
    458   __ testb(result, Immediate(kShortExternalStringTag));
    459   __ j(not_zero, call_runtime);
    460   // Check encoding.
    461   STATIC_ASSERT(kTwoByteStringTag == 0);
    462   __ testb(result, Immediate(kStringEncodingMask));
    463   __ movp(result, FieldOperand(string, ExternalString::kResourceDataOffset));
    464   __ j(not_equal, &one_byte_external, Label::kNear);
    465   // Two-byte string.
    466   __ movzxwl(result, Operand(result, index, times_2, 0));
    467   __ jmp(&done, Label::kNear);
    468   __ bind(&one_byte_external);
    469   // One-byte string.
    470   __ movzxbl(result, Operand(result, index, times_1, 0));
    471   __ jmp(&done, Label::kNear);
    472 
    473   // Dispatch on the encoding: one-byte or two-byte.
    474   Label one_byte;
    475   __ bind(&seq_string);
    476   STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
    477   STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
    478   __ testb(result, Immediate(kStringEncodingMask));
    479   __ j(not_zero, &one_byte, Label::kNear);
    480 
    481   // Two-byte string.
    482   // Load the two-byte character code into the result register.
    483   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
    484   __ movzxwl(result, FieldOperand(string,
    485                                   index,
    486                                   times_2,
    487                                   SeqTwoByteString::kHeaderSize));
    488   __ jmp(&done, Label::kNear);
    489 
    490   // One-byte string.
    491   // Load the byte into the result register.
    492   __ bind(&one_byte);
    493   __ movzxbl(result, FieldOperand(string,
    494                                   index,
    495                                   times_1,
    496                                   SeqOneByteString::kHeaderSize));
    497   __ bind(&done);
    498 }
    499 
    500 
    501 void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
    502                                    XMMRegister input,
    503                                    XMMRegister result,
    504                                    XMMRegister double_scratch,
    505                                    Register temp1,
    506                                    Register temp2) {
    507   DCHECK(!input.is(result));
    508   DCHECK(!input.is(double_scratch));
    509   DCHECK(!result.is(double_scratch));
    510   DCHECK(!temp1.is(temp2));
    511   DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
    512   DCHECK(!masm->serializer_enabled());  // External references not serializable.
    513 
    514   Label done;
    515 
    516   __ Move(kScratchRegister, ExternalReference::math_exp_constants(0));
    517   __ Movsd(double_scratch, Operand(kScratchRegister, 0 * kDoubleSize));
    518   __ Xorpd(result, result);
    519   __ Ucomisd(double_scratch, input);
    520   __ j(above_equal, &done);
    521   __ Ucomisd(input, Operand(kScratchRegister, 1 * kDoubleSize));
    522   __ Movsd(result, Operand(kScratchRegister, 2 * kDoubleSize));
    523   __ j(above_equal, &done);
    524   __ Movsd(double_scratch, Operand(kScratchRegister, 3 * kDoubleSize));
    525   __ Movsd(result, Operand(kScratchRegister, 4 * kDoubleSize));
    526   __ Mulsd(double_scratch, input);
    527   __ Addsd(double_scratch, result);
    528   __ Movq(temp2, double_scratch);
    529   __ Subsd(double_scratch, result);
    530   __ Movsd(result, Operand(kScratchRegister, 6 * kDoubleSize));
    531   __ leaq(temp1, Operand(temp2, 0x1ff800));
    532   __ andq(temp2, Immediate(0x7ff));
    533   __ shrq(temp1, Immediate(11));
    534   __ Mulsd(double_scratch, Operand(kScratchRegister, 5 * kDoubleSize));
    535   __ Move(kScratchRegister, ExternalReference::math_exp_log_table());
    536   __ shlq(temp1, Immediate(52));
    537   __ orq(temp1, Operand(kScratchRegister, temp2, times_8, 0));
    538   __ Move(kScratchRegister, ExternalReference::math_exp_constants(0));
    539   __ Subsd(double_scratch, input);
    540   __ Movsd(input, double_scratch);
    541   __ Subsd(result, double_scratch);
    542   __ Mulsd(input, double_scratch);
    543   __ Mulsd(result, input);
    544   __ Movq(input, temp1);
    545   __ Mulsd(result, Operand(kScratchRegister, 7 * kDoubleSize));
    546   __ Subsd(result, double_scratch);
    547   __ Addsd(result, Operand(kScratchRegister, 8 * kDoubleSize));
    548   __ Mulsd(result, input);
    549 
    550   __ bind(&done);
    551 }
    552 
    553 #undef __
    554 
    555 
    556 CodeAgingHelper::CodeAgingHelper(Isolate* isolate) {
    557   USE(isolate);
    558   DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
    559   // The sequence of instructions that is patched out for aging code is the
    560   // following boilerplate stack-building prologue that is found both in
    561   // FUNCTION and OPTIMIZED_FUNCTION code:
    562   CodePatcher patcher(isolate, young_sequence_.start(),
    563                       young_sequence_.length());
    564   patcher.masm()->pushq(rbp);
    565   patcher.masm()->movp(rbp, rsp);
    566   patcher.masm()->Push(rsi);
    567   patcher.masm()->Push(rdi);
    568 }
    569 
    570 
    571 #ifdef DEBUG
    572 bool CodeAgingHelper::IsOld(byte* candidate) const {
    573   return *candidate == kCallOpcode;
    574 }
    575 #endif
    576 
    577 
    578 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
    579   bool result = isolate->code_aging_helper()->IsYoung(sequence);
    580   DCHECK(result || isolate->code_aging_helper()->IsOld(sequence));
    581   return result;
    582 }
    583 
    584 
    585 void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
    586                                MarkingParity* parity) {
    587   if (IsYoungSequence(isolate, sequence)) {
    588     *age = kNoAgeCodeAge;
    589     *parity = NO_MARKING_PARITY;
    590   } else {
    591     sequence++;  // Skip the kCallOpcode byte
    592     Address target_address = sequence + *reinterpret_cast<int*>(sequence) +
    593         Assembler::kCallTargetAddressOffset;
    594     Code* stub = GetCodeFromTargetAddress(target_address);
    595     GetCodeAgeAndParity(stub, age, parity);
    596   }
    597 }
    598 
    599 
    600 void Code::PatchPlatformCodeAge(Isolate* isolate,
    601                                 byte* sequence,
    602                                 Code::Age age,
    603                                 MarkingParity parity) {
    604   uint32_t young_length = isolate->code_aging_helper()->young_sequence_length();
    605   if (age == kNoAgeCodeAge) {
    606     isolate->code_aging_helper()->CopyYoungSequenceTo(sequence);
    607     Assembler::FlushICache(isolate, sequence, young_length);
    608   } else {
    609     Code* stub = GetCodeAgeStub(isolate, age, parity);
    610     CodePatcher patcher(isolate, sequence, young_length);
    611     patcher.masm()->call(stub->instruction_start());
    612     patcher.masm()->Nop(
    613         kNoCodeAgeSequenceLength - Assembler::kShortCallInstructionLength);
    614   }
    615 }
    616 
    617 
    618 Operand StackArgumentsAccessor::GetArgumentOperand(int index) {
    619   DCHECK(index >= 0);
    620   int receiver = (receiver_mode_ == ARGUMENTS_CONTAIN_RECEIVER) ? 1 : 0;
    621   int displacement_to_last_argument = base_reg_.is(rsp) ?
    622       kPCOnStackSize : kFPOnStackSize + kPCOnStackSize;
    623   displacement_to_last_argument += extra_displacement_to_last_argument_;
    624   if (argument_count_reg_.is(no_reg)) {
    625     // argument[0] is at base_reg_ + displacement_to_last_argument +
    626     // (argument_count_immediate_ + receiver - 1) * kPointerSize.
    627     DCHECK(argument_count_immediate_ + receiver > 0);
    628     return Operand(base_reg_, displacement_to_last_argument +
    629         (argument_count_immediate_ + receiver - 1 - index) * kPointerSize);
    630   } else {
    631     // argument[0] is at base_reg_ + displacement_to_last_argument +
    632     // argument_count_reg_ * times_pointer_size + (receiver - 1) * kPointerSize.
    633     return Operand(base_reg_, argument_count_reg_, times_pointer_size,
    634         displacement_to_last_argument + (receiver - 1 - index) * kPointerSize);
    635   }
    636 }
    637 
    638 
    639 }  // namespace internal
    640 }  // namespace v8
    641 
    642 #endif  // V8_TARGET_ARCH_X64
    643