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