OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 TranscendentalCache::Type type_; | 51 TranscendentalCache::Type type_; |
52 ArgumentType argument_type_; | 52 ArgumentType argument_type_; |
53 void GenerateCallCFunction(MacroAssembler* masm, Register scratch); | 53 void GenerateCallCFunction(MacroAssembler* masm, Register scratch); |
54 | 54 |
55 Major MajorKey() { return TranscendentalCache; } | 55 Major MajorKey() { return TranscendentalCache; } |
56 int MinorKey() { return type_ | argument_type_; } | 56 int MinorKey() { return type_ | argument_type_; } |
57 Runtime::FunctionId RuntimeFunction(); | 57 Runtime::FunctionId RuntimeFunction(); |
58 }; | 58 }; |
59 | 59 |
60 | 60 |
| 61 class StoreBufferOverflowStub: public CodeStub { |
| 62 public: |
| 63 explicit StoreBufferOverflowStub(SaveFPRegsMode save_fp) |
| 64 : save_doubles_(save_fp) { } |
| 65 |
| 66 void Generate(MacroAssembler* masm); |
| 67 |
| 68 virtual bool CompilingCallsToThisStubIsGCSafe() { return true; } |
| 69 static void GenerateFixedRegStubsAheadOfTime(); |
| 70 virtual bool SometimesSetsUpAFrame() { return false; } |
| 71 |
| 72 private: |
| 73 SaveFPRegsMode save_doubles_; |
| 74 |
| 75 Major MajorKey() { return StoreBufferOverflow; } |
| 76 int MinorKey() { return (save_doubles_ == kSaveFPRegs) ? 1 : 0; } |
| 77 }; |
| 78 |
| 79 |
61 class UnaryOpStub: public CodeStub { | 80 class UnaryOpStub: public CodeStub { |
62 public: | 81 public: |
63 UnaryOpStub(Token::Value op, | 82 UnaryOpStub(Token::Value op, |
64 UnaryOverwriteMode mode, | 83 UnaryOverwriteMode mode, |
65 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED) | 84 UnaryOpIC::TypeInfo operand_type = UnaryOpIC::UNINITIALIZED) |
66 : op_(op), | 85 : op_(op), |
67 mode_(mode), | 86 mode_(mode), |
68 operand_type_(operand_type) { | 87 operand_type_(operand_type) { |
69 } | 88 } |
70 | 89 |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 class WriteInt32ToHeapNumberStub : public CodeStub { | 336 class WriteInt32ToHeapNumberStub : public CodeStub { |
318 public: | 337 public: |
319 WriteInt32ToHeapNumberStub(Register the_int, | 338 WriteInt32ToHeapNumberStub(Register the_int, |
320 Register the_heap_number, | 339 Register the_heap_number, |
321 Register scratch) | 340 Register scratch) |
322 : the_int_(the_int), | 341 : the_int_(the_int), |
323 the_heap_number_(the_heap_number), | 342 the_heap_number_(the_heap_number), |
324 scratch_(scratch) { } | 343 scratch_(scratch) { } |
325 | 344 |
326 bool CompilingCallsToThisStubIsGCSafe(); | 345 bool CompilingCallsToThisStubIsGCSafe(); |
327 static void GenerateStubsAheadOfTime(); | 346 static void GenerateFixedRegStubsAheadOfTime(); |
328 | 347 |
329 private: | 348 private: |
330 Register the_int_; | 349 Register the_int_; |
331 Register the_heap_number_; | 350 Register the_heap_number_; |
332 Register scratch_; | 351 Register scratch_; |
333 | 352 |
334 // Minor key encoding in 16 bits. | 353 // Minor key encoding in 16 bits. |
335 class IntRegisterBits: public BitField<int, 0, 4> {}; | 354 class IntRegisterBits: public BitField<int, 0, 4> {}; |
336 class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; | 355 class HeapNumberRegisterBits: public BitField<int, 4, 4> {}; |
337 class ScratchRegisterBits: public BitField<int, 8, 4> {}; | 356 class ScratchRegisterBits: public BitField<int, 8, 4> {}; |
(...skipping 29 matching lines...) Expand all Loading... |
367 Label* not_found); | 386 Label* not_found); |
368 | 387 |
369 private: | 388 private: |
370 Major MajorKey() { return NumberToString; } | 389 Major MajorKey() { return NumberToString; } |
371 int MinorKey() { return 0; } | 390 int MinorKey() { return 0; } |
372 | 391 |
373 void Generate(MacroAssembler* masm); | 392 void Generate(MacroAssembler* masm); |
374 }; | 393 }; |
375 | 394 |
376 | 395 |
| 396 class RecordWriteStub: public CodeStub { |
| 397 public: |
| 398 RecordWriteStub(Register object, |
| 399 Register value, |
| 400 Register address, |
| 401 RememberedSetAction remembered_set_action, |
| 402 SaveFPRegsMode fp_mode) |
| 403 : object_(object), |
| 404 value_(value), |
| 405 address_(address), |
| 406 remembered_set_action_(remembered_set_action), |
| 407 save_fp_regs_mode_(fp_mode), |
| 408 regs_(object, // An input reg. |
| 409 address, // An input reg. |
| 410 value) { // One scratch reg. |
| 411 } |
| 412 |
| 413 enum Mode { |
| 414 STORE_BUFFER_ONLY, |
| 415 INCREMENTAL, |
| 416 INCREMENTAL_COMPACTION |
| 417 }; |
| 418 |
| 419 virtual bool CompilingCallsToThisStubIsGCSafe(); |
| 420 static void GenerateFixedRegStubsAheadOfTime(); |
| 421 virtual bool SometimesSetsUpAFrame() { return false; } |
| 422 |
| 423 static void PatchBranchIntoNop(MacroAssembler* masm, int pos) { |
| 424 masm->instr_at_put(pos, (masm->instr_at(pos) & ~B27) | (B24 | B20)); |
| 425 ASSERT(Assembler::IsTstImmediate(masm->instr_at(pos))); |
| 426 } |
| 427 |
| 428 static void PatchNopIntoBranch(MacroAssembler* masm, int pos) { |
| 429 masm->instr_at_put(pos, (masm->instr_at(pos) & ~(B24 | B20)) | B27); |
| 430 ASSERT(Assembler::IsBranch(masm->instr_at(pos))); |
| 431 } |
| 432 |
| 433 static Mode GetMode(Code* stub) { |
| 434 Instr first_instruction = Assembler::instr_at(stub->instruction_start()); |
| 435 Instr second_instruction = Assembler::instr_at(stub->instruction_start() + |
| 436 Assembler::kInstrSize); |
| 437 |
| 438 if (Assembler::IsBranch(first_instruction)) { |
| 439 return INCREMENTAL; |
| 440 } |
| 441 |
| 442 ASSERT(Assembler::IsTstImmediate(first_instruction)); |
| 443 |
| 444 if (Assembler::IsBranch(second_instruction)) { |
| 445 return INCREMENTAL_COMPACTION; |
| 446 } |
| 447 |
| 448 ASSERT(Assembler::IsTstImmediate(second_instruction)); |
| 449 |
| 450 return STORE_BUFFER_ONLY; |
| 451 } |
| 452 |
| 453 static void Patch(Code* stub, Mode mode) { |
| 454 MacroAssembler masm(NULL, |
| 455 stub->instruction_start(), |
| 456 stub->instruction_size()); |
| 457 switch (mode) { |
| 458 case STORE_BUFFER_ONLY: |
| 459 ASSERT(GetMode(stub) == INCREMENTAL || |
| 460 GetMode(stub) == INCREMENTAL_COMPACTION); |
| 461 PatchBranchIntoNop(&masm, 0); |
| 462 PatchBranchIntoNop(&masm, Assembler::kInstrSize); |
| 463 break; |
| 464 case INCREMENTAL: |
| 465 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); |
| 466 PatchNopIntoBranch(&masm, 0); |
| 467 break; |
| 468 case INCREMENTAL_COMPACTION: |
| 469 ASSERT(GetMode(stub) == STORE_BUFFER_ONLY); |
| 470 PatchNopIntoBranch(&masm, Assembler::kInstrSize); |
| 471 break; |
| 472 } |
| 473 ASSERT(GetMode(stub) == mode); |
| 474 CPU::FlushICache(stub->instruction_start(), 2 * Assembler::kInstrSize); |
| 475 } |
| 476 |
| 477 private: |
| 478 // This is a helper class for freeing up 3 scratch registers. The input is |
| 479 // two registers that must be preserved and one scratch register provided by |
| 480 // the caller. |
| 481 class RegisterAllocation { |
| 482 public: |
| 483 RegisterAllocation(Register object, |
| 484 Register address, |
| 485 Register scratch0) |
| 486 : object_(object), |
| 487 address_(address), |
| 488 scratch0_(scratch0) { |
| 489 ASSERT(!AreAliased(scratch0, object, address, no_reg)); |
| 490 scratch1_ = GetRegThatIsNotOneOf(object_, address_, scratch0_); |
| 491 } |
| 492 |
| 493 void Save(MacroAssembler* masm) { |
| 494 ASSERT(!AreAliased(object_, address_, scratch1_, scratch0_)); |
| 495 // We don't have to save scratch0_ because it was given to us as |
| 496 // a scratch register. |
| 497 masm->push(scratch1_); |
| 498 } |
| 499 |
| 500 void Restore(MacroAssembler* masm) { |
| 501 masm->pop(scratch1_); |
| 502 } |
| 503 |
| 504 // If we have to call into C then we need to save and restore all caller- |
| 505 // saved registers that were not already preserved. The scratch registers |
| 506 // will be restored by other means so we don't bother pushing them here. |
| 507 void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) { |
| 508 masm->stm(db_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); |
| 509 if (mode == kSaveFPRegs) { |
| 510 CpuFeatures::Scope scope(VFP3); |
| 511 masm->sub(sp, |
| 512 sp, |
| 513 Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1))); |
| 514 // Save all VFP registers except d0. |
| 515 for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) { |
| 516 DwVfpRegister reg = DwVfpRegister::from_code(i); |
| 517 masm->vstr(reg, MemOperand(sp, (i - 1) * kDoubleSize)); |
| 518 } |
| 519 } |
| 520 } |
| 521 |
| 522 inline void RestoreCallerSaveRegisters(MacroAssembler*masm, |
| 523 SaveFPRegsMode mode) { |
| 524 if (mode == kSaveFPRegs) { |
| 525 CpuFeatures::Scope scope(VFP3); |
| 526 // Restore all VFP registers except d0. |
| 527 for (int i = DwVfpRegister::kNumRegisters - 1; i > 0; i--) { |
| 528 DwVfpRegister reg = DwVfpRegister::from_code(i); |
| 529 masm->vldr(reg, MemOperand(sp, (i - 1) * kDoubleSize)); |
| 530 } |
| 531 masm->add(sp, |
| 532 sp, |
| 533 Operand(kDoubleSize * (DwVfpRegister::kNumRegisters - 1))); |
| 534 } |
| 535 masm->ldm(ia_w, sp, (kCallerSaved | lr.bit()) & ~scratch1_.bit()); |
| 536 } |
| 537 |
| 538 inline Register object() { return object_; } |
| 539 inline Register address() { return address_; } |
| 540 inline Register scratch0() { return scratch0_; } |
| 541 inline Register scratch1() { return scratch1_; } |
| 542 |
| 543 private: |
| 544 Register object_; |
| 545 Register address_; |
| 546 Register scratch0_; |
| 547 Register scratch1_; |
| 548 |
| 549 Register GetRegThatIsNotOneOf(Register r1, |
| 550 Register r2, |
| 551 Register r3) { |
| 552 for (int i = 0; i < Register::kNumAllocatableRegisters; i++) { |
| 553 Register candidate = Register::FromAllocationIndex(i); |
| 554 if (candidate.is(r1)) continue; |
| 555 if (candidate.is(r2)) continue; |
| 556 if (candidate.is(r3)) continue; |
| 557 return candidate; |
| 558 } |
| 559 UNREACHABLE(); |
| 560 return no_reg; |
| 561 } |
| 562 friend class RecordWriteStub; |
| 563 }; |
| 564 |
| 565 enum OnNoNeedToInformIncrementalMarker { |
| 566 kReturnOnNoNeedToInformIncrementalMarker, |
| 567 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker |
| 568 }; |
| 569 |
| 570 void Generate(MacroAssembler* masm); |
| 571 void GenerateIncremental(MacroAssembler* masm, Mode mode); |
| 572 void CheckNeedsToInformIncrementalMarker( |
| 573 MacroAssembler* masm, |
| 574 OnNoNeedToInformIncrementalMarker on_no_need, |
| 575 Mode mode); |
| 576 void InformIncrementalMarker(MacroAssembler* masm, Mode mode); |
| 577 |
| 578 Major MajorKey() { return RecordWrite; } |
| 579 |
| 580 int MinorKey() { |
| 581 return ObjectBits::encode(object_.code()) | |
| 582 ValueBits::encode(value_.code()) | |
| 583 AddressBits::encode(address_.code()) | |
| 584 RememberedSetActionBits::encode(remembered_set_action_) | |
| 585 SaveFPRegsModeBits::encode(save_fp_regs_mode_); |
| 586 } |
| 587 |
| 588 bool MustBeInStubCache() { |
| 589 // All stubs must be registered in the stub cache |
| 590 // otherwise IncrementalMarker would not be able to find |
| 591 // and patch it. |
| 592 return true; |
| 593 } |
| 594 |
| 595 void Activate(Code* code) { |
| 596 code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code); |
| 597 } |
| 598 |
| 599 class ObjectBits: public BitField<int, 0, 4> {}; |
| 600 class ValueBits: public BitField<int, 4, 4> {}; |
| 601 class AddressBits: public BitField<int, 8, 4> {}; |
| 602 class RememberedSetActionBits: public BitField<RememberedSetAction, 12, 1> {}; |
| 603 class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 13, 1> {}; |
| 604 |
| 605 Register object_; |
| 606 Register value_; |
| 607 Register address_; |
| 608 RememberedSetAction remembered_set_action_; |
| 609 SaveFPRegsMode save_fp_regs_mode_; |
| 610 Label slow_; |
| 611 RegisterAllocation regs_; |
| 612 }; |
| 613 |
| 614 |
377 // Enter C code from generated RegExp code in a way that allows | 615 // Enter C code from generated RegExp code in a way that allows |
378 // the C code to fix the return address in case of a GC. | 616 // the C code to fix the return address in case of a GC. |
379 // Currently only needed on ARM. | 617 // Currently only needed on ARM. |
380 class RegExpCEntryStub: public CodeStub { | 618 class RegExpCEntryStub: public CodeStub { |
381 public: | 619 public: |
382 RegExpCEntryStub() {} | 620 RegExpCEntryStub() {} |
383 virtual ~RegExpCEntryStub() {} | 621 virtual ~RegExpCEntryStub() {} |
384 void Generate(MacroAssembler* masm); | 622 void Generate(MacroAssembler* masm); |
385 | 623 |
386 private: | 624 private: |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
600 | 838 |
601 class LookupModeBits: public BitField<LookupMode, 0, 1> {}; | 839 class LookupModeBits: public BitField<LookupMode, 0, 1> {}; |
602 | 840 |
603 LookupMode mode_; | 841 LookupMode mode_; |
604 }; | 842 }; |
605 | 843 |
606 | 844 |
607 } } // namespace v8::internal | 845 } } // namespace v8::internal |
608 | 846 |
609 #endif // V8_ARM_CODE_STUBS_ARM_H_ | 847 #endif // V8_ARM_CODE_STUBS_ARM_H_ |
OLD | NEW |