1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_X64_CODE_STUBS_X64_H_ 29 #define V8_X64_CODE_STUBS_X64_H_ 30 31 #include "ic-inl.h" 32 #include "type-info.h" 33 34 namespace v8 { 35 namespace internal { 36 37 38 // Compute a transcendental math function natively, or call the 39 // TranscendentalCache runtime function. 40 class TranscendentalCacheStub: public CodeStub { 41 public: 42 enum ArgumentType { 43 TAGGED = 0, 44 UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits 45 }; 46 47 explicit TranscendentalCacheStub(TranscendentalCache::Type type, 48 ArgumentType argument_type) 49 : type_(type), argument_type_(argument_type) {} 50 void Generate(MacroAssembler* masm); 51 static void GenerateOperation(MacroAssembler* masm, 52 TranscendentalCache::Type type); 53 private: 54 TranscendentalCache::Type type_; 55 ArgumentType argument_type_; 56 57 Major MajorKey() { return TranscendentalCache; } 58 int MinorKey() { return type_ | argument_type_; } 59 Runtime::FunctionId RuntimeFunction(); 60 }; 61 62 63 class StoreBufferOverflowStub: public CodeStub { 64 public: 65 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp) 66 : save_doubles_(save_fp) { } 67 68 void Generate(MacroAssembler* masm); 69 70 virtual bool IsPregenerated() { return true; } 71 static void GenerateFixedRegStubsAheadOfTime(); 72 virtual bool SometimesSetsUpAFrame() { return false; } 73 74 private: 75 SaveFPRegsMode save_doubles_; 76 77 Major MajorKey() { return StoreBufferOverflow; } 78 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } 79 }; 80 81 82 // Flag that indicates how to generate code for the stub GenericBinaryOpStub. 83 enum GenericBinaryFlags { 84 NO_GENERIC_BINARY_FLAGS = 0, 85 NO_SMI_CODE_IN_STUB = 1 << 0 // Omit smi code in stub. 86 }; 87 88 89 class UnaryOpStub: public CodeStub { 90 public: 91 UnaryOpStub(Token::Value op, 92 UnaryOverwriteMode mode, 93 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED) 94 : op_(op), 95 mode_(mode), 96 operand_type_(operand_type) { 97 } 98 99 private: 100 Token::Value op_; 101 UnaryOverwriteMode mode_; 102 103 // Operand type information determined at runtime. 104 UnaryOpIC::TypeInfo operand_type_; 105 106 virtual void PrintName(StringStream* stream); 107 108 class ModeBits: public BitField<UnaryOverwriteMode, 0, 1> {}; 109 class OpBits: public BitField<Token::Value, 1, 7> {}; 110 class OperandTypeInfoBits: public BitField<UnaryOpIC::TypeInfo, 8, 3> {}; 111 112 Major MajorKey() { return UnaryOp; } 113 int MinorKey() { 114 return ModeBits::encode(mode_) 115 | OpBits::encode(op_) 116 | OperandTypeInfoBits::encode(operand_type_); 117 } 118 119 // Note: A lot of the helper functions below will vanish when we use virtual 120 // function instead of switch more often. 121 void Generate(MacroAssembler* masm); 122 123 void GenerateTypeTransition(MacroAssembler* masm); 124 125 void GenerateSmiStub(MacroAssembler* masm); 126 void GenerateSmiStubSub(MacroAssembler* masm); 127 void GenerateSmiStubBitNot(MacroAssembler* masm); 128 void GenerateSmiCodeSub(MacroAssembler* masm, 129 Label* non_smi, 130 Label* slow, 131 Label::Distance non_smi_near = Label::kFar, 132 Label::Distance slow_near = Label::kFar); 133 void GenerateSmiCodeBitNot(MacroAssembler* masm, 134 Label* non_smi, 135 Label::Distance non_smi_near); 136 137 void GenerateHeapNumberStub(MacroAssembler* masm); 138 void GenerateHeapNumberStubSub(MacroAssembler* masm); 139 void GenerateHeapNumberStubBitNot(MacroAssembler* masm); 140 void GenerateHeapNumberCodeSub(MacroAssembler* masm, Label* slow); 141 void GenerateHeapNumberCodeBitNot(MacroAssembler* masm, Label* slow); 142 143 void GenerateGenericStub(MacroAssembler* masm); 144 void GenerateGenericStubSub(MacroAssembler* masm); 145 void GenerateGenericStubBitNot(MacroAssembler* masm); 146 void GenerateGenericCodeFallback(MacroAssembler* masm); 147 148 virtual int GetCodeKind() { return Code::UNARY_OP_IC; } 149 150 virtual InlineCacheState GetICState() { 151 return UnaryOpIC::ToState(operand_type_); 152 } 153 154 virtual void FinishCode(Handle<Code> code) { 155 code->set_unary_op_type(operand_type_); 156 } 157 }; 158 159 160 class BinaryOpStub: public CodeStub { 161 public: 162 BinaryOpStub(Token::Value op, OverwriteMode mode) 163 : op_(op), 164 mode_(mode), 165 operands_type_(BinaryOpIC::UNINITIALIZED), 166 result_type_(BinaryOpIC::UNINITIALIZED) { 167 ASSERT(OpBits::is_valid(Token::NUM_TOKENS)); 168 } 169 170 BinaryOpStub( 171 int key, 172 BinaryOpIC::TypeInfo operands_type, 173 BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED) 174 : op_(OpBits::decode(key)), 175 mode_(ModeBits::decode(key)), 176 operands_type_(operands_type), 177 result_type_(result_type) { } 178 179 private: 180 enum SmiCodeGenerateHeapNumberResults { 181 ALLOW_HEAPNUMBER_RESULTS, 182 NO_HEAPNUMBER_RESULTS 183 }; 184 185 Token::Value op_; 186 OverwriteMode mode_; 187 188 // Operand type information determined at runtime. 189 BinaryOpIC::TypeInfo operands_type_; 190 BinaryOpIC::TypeInfo result_type_; 191 192 virtual void PrintName(StringStream* stream); 193 194 // Minor key encoding in 15 bits RRRTTTOOOOOOOMM. 195 class ModeBits: public BitField<OverwriteMode, 0, 2> {}; 196 class OpBits: public BitField<Token::Value, 2, 7> {}; 197 class OperandTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 9, 3> {}; 198 class ResultTypeInfoBits: public BitField<BinaryOpIC::TypeInfo, 12, 3> {}; 199 200 Major MajorKey() { return BinaryOp; } 201 int MinorKey() { 202 return OpBits::encode(op_) 203 | ModeBits::encode(mode_) 204 | OperandTypeInfoBits::encode(operands_type_) 205 | ResultTypeInfoBits::encode(result_type_); 206 } 207 208 void Generate(MacroAssembler* masm); 209 void GenerateGeneric(MacroAssembler* masm); 210 void GenerateSmiCode(MacroAssembler* masm, 211 Label* slow, 212 SmiCodeGenerateHeapNumberResults heapnumber_results); 213 void GenerateFloatingPointCode(MacroAssembler* masm, 214 Label* allocation_failure, 215 Label* non_numeric_failure); 216 void GenerateStringAddCode(MacroAssembler* masm); 217 void GenerateCallRuntimeCode(MacroAssembler* masm); 218 void GenerateLoadArguments(MacroAssembler* masm); 219 void GenerateReturn(MacroAssembler* masm); 220 void GenerateUninitializedStub(MacroAssembler* masm); 221 void GenerateSmiStub(MacroAssembler* masm); 222 void GenerateInt32Stub(MacroAssembler* masm); 223 void GenerateHeapNumberStub(MacroAssembler* masm); 224 void GenerateOddballStub(MacroAssembler* masm); 225 void GenerateStringStub(MacroAssembler* masm); 226 void GenerateBothStringStub(MacroAssembler* masm); 227 void GenerateGenericStub(MacroAssembler* masm); 228 229 void GenerateHeapResultAllocation(MacroAssembler* masm, Label* alloc_failure); 230 void GenerateRegisterArgsPush(MacroAssembler* masm); 231 void GenerateTypeTransition(MacroAssembler* masm); 232 void GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm); 233 234 virtual int GetCodeKind() { return Code::BINARY_OP_IC; } 235 236 virtual InlineCacheState GetICState() { 237 return BinaryOpIC::ToState(operands_type_); 238 } 239 240 virtual void FinishCode(Handle<Code> code) { 241 code->set_binary_op_type(operands_type_); 242 code->set_binary_op_result_type(result_type_); 243 } 244 245 friend class CodeGenerator; 246 }; 247 248 249 class StringHelper : public AllStatic { 250 public: 251 // Generate code for copying characters using a simple loop. This should only 252 // be used in places where the number of characters is small and the 253 // additional setup and checking in GenerateCopyCharactersREP adds too much 254 // overhead. Copying of overlapping regions is not supported. 255 static void GenerateCopyCharacters(MacroAssembler* masm, 256 Register dest, 257 Register src, 258 Register count, 259 bool ascii); 260 261 // Generate code for copying characters using the rep movs instruction. 262 // Copies rcx characters from rsi to rdi. Copying of overlapping regions is 263 // not supported. 264 static void GenerateCopyCharactersREP(MacroAssembler* masm, 265 Register dest, // Must be rdi. 266 Register src, // Must be rsi. 267 Register count, // Must be rcx. 268 bool ascii); 269 270 271 // Probe the symbol table for a two character string. If the string is 272 // not found by probing a jump to the label not_found is performed. This jump 273 // does not guarantee that the string is not in the symbol table. If the 274 // string is found the code falls through with the string in register rax. 275 static void GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 276 Register c1, 277 Register c2, 278 Register scratch1, 279 Register scratch2, 280 Register scratch3, 281 Register scratch4, 282 Label* not_found); 283 284 // Generate string hash. 285 static void GenerateHashInit(MacroAssembler* masm, 286 Register hash, 287 Register character, 288 Register scratch); 289 static void GenerateHashAddCharacter(MacroAssembler* masm, 290 Register hash, 291 Register character, 292 Register scratch); 293 static void GenerateHashGetHash(MacroAssembler* masm, 294 Register hash, 295 Register scratch); 296 297 private: 298 DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper); 299 }; 300 301 302 // Flag that indicates how to generate code for the stub StringAddStub. 303 enum StringAddFlags { 304 NO_STRING_ADD_FLAGS = 0, 305 // Omit left string check in stub (left is definitely a string). 306 NO_STRING_CHECK_LEFT_IN_STUB = 1 << 0, 307 // Omit right string check in stub (right is definitely a string). 308 NO_STRING_CHECK_RIGHT_IN_STUB = 1 << 1, 309 // Omit both string checks in stub. 310 NO_STRING_CHECK_IN_STUB = 311 NO_STRING_CHECK_LEFT_IN_STUB | NO_STRING_CHECK_RIGHT_IN_STUB 312 }; 313 314 315 class StringAddStub: public CodeStub { 316 public: 317 explicit StringAddStub(StringAddFlags flags) : flags_(flags) {} 318 319 private: 320 Major MajorKey() { return StringAdd; } 321 int MinorKey() { return flags_; } 322 323 void Generate(MacroAssembler* masm); 324 325 void GenerateConvertArgument(MacroAssembler* masm, 326 int stack_offset, 327 Register arg, 328 Register scratch1, 329 Register scratch2, 330 Register scratch3, 331 Label* slow); 332 333 const StringAddFlags flags_; 334 }; 335 336 337 class SubStringStub: public CodeStub { 338 public: 339 SubStringStub() {} 340 341 private: 342 Major MajorKey() { return SubString; } 343 int MinorKey() { return 0; } 344 345 void Generate(MacroAssembler* masm); 346 }; 347 348 349 class StringCompareStub: public CodeStub { 350 public: 351 StringCompareStub() {} 352 353 // Compares two flat ASCII strings and returns result in rax. 354 static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 355 Register left, 356 Register right, 357 Register scratch1, 358 Register scratch2, 359 Register scratch3, 360 Register scratch4); 361 362 // Compares two flat ASCII strings for equality and returns result 363 // in rax. 364 static void GenerateFlatAsciiStringEquals(MacroAssembler* masm, 365 Register left, 366 Register right, 367 Register scratch1, 368 Register scratch2); 369 370 private: 371 virtual Major MajorKey() { return StringCompare; } 372 virtual int MinorKey() { return 0; } 373 virtual void Generate(MacroAssembler* masm); 374 375 static void GenerateAsciiCharsCompareLoop( 376 MacroAssembler* masm, 377 Register left, 378 Register right, 379 Register length, 380 Register scratch, 381 Label* chars_not_equal, 382 Label::Distance near_jump = Label::kFar); 383 }; 384 385 386 class NumberToStringStub: public CodeStub { 387 public: 388 NumberToStringStub() { } 389 390 // Generate code to do a lookup in the number string cache. If the number in 391 // the register object is found in the cache the generated code falls through 392 // with the result in the result register. The object and the result register 393 // can be the same. If the number is not found in the cache the code jumps to 394 // the label not_found with only the content of register object unchanged. 395 static void GenerateLookupNumberStringCache(MacroAssembler* masm, 396 Register object, 397 Register result, 398 Register scratch1, 399 Register scratch2, 400 bool object_is_smi, 401 Label* not_found); 402 403 private: 404 static void GenerateConvertHashCodeToIndex(MacroAssembler* masm, 405 Register hash, 406 Register mask); 407 408 Major MajorKey() { return NumberToString; } 409 int MinorKey() { return 0; } 410 411 void Generate(MacroAssembler* masm); 412 }; 413 414 415 class StringDictionaryLookupStub: public CodeStub { 416 public: 417 enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP }; 418 419 StringDictionaryLookupStub(Register dictionary, 420 Register result, 421 Register index, 422 LookupMode mode) 423 : dictionary_(dictionary), result_(result), index_(index), mode_(mode) { } 424 425 void Generate(MacroAssembler* masm); 426 427 static void GenerateNegativeLookup(MacroAssembler* masm, 428 Label* miss, 429 Label* done, 430 Register properties, 431 Handle<String> name, 432 Register r0); 433 434 static void GeneratePositiveLookup(MacroAssembler* masm, 435 Label* miss, 436 Label* done, 437 Register elements, 438 Register name, 439 Register r0, 440 Register r1); 441 442 virtual bool SometimesSetsUpAFrame() { return false; } 443 444 private: 445 static const int kInlinedProbes = 4; 446 static const int kTotalProbes = 20; 447 448 static const int kCapacityOffset = 449 StringDictionary::kHeaderSize + 450 StringDictionary::kCapacityIndex * kPointerSize; 451 452 static const int kElementsStartOffset = 453 StringDictionary::kHeaderSize + 454 StringDictionary::kElementsStartIndex * kPointerSize; 455 456 Major MajorKey() { return StringDictionaryLookup; } 457 458 int MinorKey() { 459 return DictionaryBits::encode(dictionary_.code()) | 460 ResultBits::encode(result_.code()) | 461 IndexBits::encode(index_.code()) | 462 LookupModeBits::encode(mode_); 463 } 464 465 class DictionaryBits: public BitField<int, 0, 4> {}; 466 class ResultBits: public BitField<int, 4, 4> {}; 467 class IndexBits: public BitField<int, 8, 4> {}; 468 class LookupModeBits: public BitField<LookupMode, 12, 1> {}; 469 470 Register dictionary_; 471 Register result_; 472 Register index_; 473 LookupMode mode_; 474 }; 475 476 477 class RecordWriteStub: public CodeStub { 478 public: 479 RecordWriteStub(Register object, 480 Register value, 481 Register address, 482 RememberedSetAction remembered_set_action, 483 SaveFPRegsMode fp_mode) 484 : object_(object), 485 value_(value), 486 address_(address), 487 remembered_set_action_(remembered_set_action), 488 save_fp_regs_mode_(fp_mode), 489 regs_(object, // An input reg. 490 address, // An input reg. 491 value) { // One scratch reg. 492 } 493 494 enum Mode { 495 STORE_BUFFER_ONLY, 496 INCREMENTAL, 497 INCREMENTAL_COMPACTION 498 }; 499 500 virtual bool IsPregenerated(); 501 static void GenerateFixedRegStubsAheadOfTime(); 502 virtual bool SometimesSetsUpAFrame() { return false; } 503 504 static const byte kTwoByteNopInstruction = 0x3c; // Cmpb al, #imm8. 505 static const byte kTwoByteJumpInstruction = 0xeb; // Jmp #imm8. 506 507 static const byte kFiveByteNopInstruction = 0x3d; // Cmpl eax, #imm32. 508 static const byte kFiveByteJumpInstruction = 0xe9; // Jmp #imm32. 509 510 static Mode GetMode(Code* stub) { 511 byte first_instruction = stub->instruction_start()[0]; 512 byte second_instruction = stub->instruction_start()[2]; 513 514 if (first_instruction == kTwoByteJumpInstruction) { 515 return INCREMENTAL; 516 } 517 518 ASSERT(first_instruction == kTwoByteNopInstruction); 519 520 if (second_instruction == kFiveByteJumpInstruction) { 521 return INCREMENTAL_COMPACTION; 522 } 523 524 ASSERT(second_instruction == kFiveByteNopInstruction); 525 526 return STORE_BUFFER_ONLY; 527 } 528 529 static void Patch(Code* stub, Mode mode) { 530 switch (mode) { 531 case STORE_BUFFER_ONLY: 532 ASSERT(GetMode(stub) == INCREMENTAL || 533 GetMode(stub) == INCREMENTAL_COMPACTION); 534 stub->instruction_start()[0] = kTwoByteNopInstruction; 535 stub->instruction_start()[2] = kFiveByteNopInstruction; 536 break; 537 case INCREMENTAL: 538 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); 539 stub->instruction_start()[0] = kTwoByteJumpInstruction; 540 break; 541 case INCREMENTAL_COMPACTION: 542 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); 543 stub->instruction_start()[0] = kTwoByteNopInstruction; 544 stub->instruction_start()[2] = kFiveByteJumpInstruction; 545 break; 546 } 547 ASSERT(GetMode(stub) == mode); 548 CPU::FlushICache(stub->instruction_start(), 7); 549 } 550 551 private: 552 // This is a helper class for freeing up 3 scratch registers, where the third 553 // is always rcx (needed for shift operations). The input is two registers 554 // that must be preserved and one scratch register provided by the caller. 555 class RegisterAllocation { 556 public: 557 RegisterAllocation(Register object, 558 Register address, 559 Register scratch0) 560 : object_orig_(object), 561 address_orig_(address), 562 scratch0_orig_(scratch0), 563 object_(object), 564 address_(address), 565 scratch0_(scratch0) { 566 ASSERT(!AreAliased(scratch0, object, address, no_reg)); 567 scratch1_ = GetRegThatIsNotRcxOr(object_, address_, scratch0_); 568 if (scratch0.is(rcx)) { 569 scratch0_ = GetRegThatIsNotRcxOr(object_, address_, scratch1_); 570 } 571 if (object.is(rcx)) { 572 object_ = GetRegThatIsNotRcxOr(address_, scratch0_, scratch1_); 573 } 574 if (address.is(rcx)) { 575 address_ = GetRegThatIsNotRcxOr(object_, scratch0_, scratch1_); 576 } 577 ASSERT(!AreAliased(scratch0_, object_, address_, rcx)); 578 } 579 580 void Save(MacroAssembler* masm) { 581 ASSERT(!address_orig_.is(object_)); 582 ASSERT(object_.is(object_orig_) || address_.is(address_orig_)); 583 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_)); 584 ASSERT(!AreAliased(object_orig_, address_, scratch1_, scratch0_)); 585 ASSERT(!AreAliased(object_, address_orig_, scratch1_, scratch0_)); 586 // We don't have to save scratch0_orig_ because it was given to us as 587 // a scratch register. But if we had to switch to a different reg then 588 // we should save the new scratch0_. 589 if (!scratch0_.is(scratch0_orig_)) masm->push(scratch0_); 590 if (!rcx.is(scratch0_orig_) && 591 !rcx.is(object_orig_) && 592 !rcx.is(address_orig_)) { 593 masm->push(rcx); 594 } 595 masm->push(scratch1_); 596 if (!address_.is(address_orig_)) { 597 masm->push(address_); 598 masm->movq(address_, address_orig_); 599 } 600 if (!object_.is(object_orig_)) { 601 masm->push(object_); 602 masm->movq(object_, object_orig_); 603 } 604 } 605 606 void Restore(MacroAssembler* masm) { 607 // These will have been preserved the entire time, so we just need to move 608 // them back. Only in one case is the orig_ reg different from the plain 609 // one, since only one of them can alias with rcx. 610 if (!object_.is(object_orig_)) { 611 masm->movq(object_orig_, object_); 612 masm->pop(object_); 613 } 614 if (!address_.is(address_orig_)) { 615 masm->movq(address_orig_, address_); 616 masm->pop(address_); 617 } 618 masm->pop(scratch1_); 619 if (!rcx.is(scratch0_orig_) && 620 !rcx.is(object_orig_) && 621 !rcx.is(address_orig_)) { 622 masm->pop(rcx); 623 } 624 if (!scratch0_.is(scratch0_orig_)) masm->pop(scratch0_); 625 } 626 627 // If we have to call into C then we need to save and restore all caller- 628 // saved registers that were not already preserved. 629 630 // The three scratch registers (incl. rcx) will be restored by other means 631 // so we don't bother pushing them here. Rbx, rbp and r12-15 are callee 632 // save and don't need to be preserved. 633 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { 634 masm->PushCallerSaved(mode, scratch0_, scratch1_, rcx); 635 } 636 637 inline void RestoreCallerSaveRegisters(MacroAssembler*masm, 638 SaveFPRegsMode mode) { 639 masm->PopCallerSaved(mode, scratch0_, scratch1_, rcx); 640 } 641 642 inline Register object() { return object_; } 643 inline Register address() { return address_; } 644 inline Register scratch0() { return scratch0_; } 645 inline Register scratch1() { return scratch1_; } 646 647 private: 648 Register object_orig_; 649 Register address_orig_; 650 Register scratch0_orig_; 651 Register object_; 652 Register address_; 653 Register scratch0_; 654 Register scratch1_; 655 // Third scratch register is always rcx. 656 657 Register GetRegThatIsNotRcxOr(Register r1, 658 Register r2, 659 Register r3) { 660 for (int i = 0; i < Register::kNumAllocatableRegisters; i++) { 661 Register candidate = Register::FromAllocationIndex(i); 662 if (candidate.is(rcx)) continue; 663 if (candidate.is(r1)) continue; 664 if (candidate.is(r2)) continue; 665 if (candidate.is(r3)) continue; 666 return candidate; 667 } 668 UNREACHABLE(); 669 return no_reg; 670 } 671 friend class RecordWriteStub; 672 }; 673 674 enum OnNoNeedToInformIncrementalMarker { 675 kReturnOnNoNeedToInformIncrementalMarker, 676 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker 677 }; 678 679 void Generate(MacroAssembler* masm); 680 void GenerateIncremental(MacroAssembler* masm, Mode mode); 681 void CheckNeedsToInformIncrementalMarker( 682 MacroAssembler* masm, 683 OnNoNeedToInformIncrementalMarker on_no_need, 684 Mode mode); 685 void InformIncrementalMarker(MacroAssembler* masm, Mode mode); 686 687 Major MajorKey() { return RecordWrite; } 688 689 int MinorKey() { 690 return ObjectBits::encode(object_.code()) | 691 ValueBits::encode(value_.code()) | 692 AddressBits::encode(address_.code()) | 693 RememberedSetActionBits::encode(remembered_set_action_) | 694 SaveFPRegsModeBits::encode(save_fp_regs_mode_); 695 } 696 697 void Activate(Code* code) { 698 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); 699 } 700 701 class ObjectBits: public BitField<int, 0, 4> {}; 702 class ValueBits: public BitField<int, 4, 4> {}; 703 class AddressBits: public BitField<int, 8, 4> {}; 704 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {}; 705 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {}; 706 707 Register object_; 708 Register value_; 709 Register address_; 710 RememberedSetAction remembered_set_action_; 711 SaveFPRegsMode save_fp_regs_mode_; 712 Label slow_; 713 RegisterAllocation regs_; 714 }; 715 716 717 } } // namespace v8::internal 718 719 #endif // V8_X64_CODE_STUBS_X64_H_ 720