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