< prev index next >

src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp

Print this page

  24  */
  25 
  26 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
  27 #include "gc/shenandoah/mode/shenandoahMode.hpp"
  28 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
  29 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
  30 #include "gc/shenandoah/shenandoahForwarding.hpp"
  31 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  32 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
  33 #include "gc/shenandoah/shenandoahRuntime.hpp"
  34 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
  35 #include "interpreter/interpreter.hpp"
  36 #include "runtime/javaThread.hpp"
  37 #include "runtime/sharedRuntime.hpp"
  38 #include "utilities/macros.hpp"
  39 #ifdef COMPILER1
  40 #include "c1/c1_LIRAssembler.hpp"
  41 #include "c1/c1_MacroAssembler.hpp"
  42 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
  43 #endif



  44 
  45 #define __ masm->
  46 
  47 static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handle_fp) {
  48   if (handle_gpr) {
  49     __ push_IU_state();
  50   }
  51 
  52   if (handle_fp) {
  53     // Some paths can be reached from the c2i adapter with live fp arguments in registers.
  54     assert(Argument::n_float_register_parameters_j == 8, "8 fp registers to save at java call");
  55 
  56     const int xmm_size = wordSize * 2;
  57     __ subptr(rsp, xmm_size * 8);
  58     __ movdbl(Address(rsp, xmm_size * 0), xmm0);
  59     __ movdbl(Address(rsp, xmm_size * 1), xmm1);
  60     __ movdbl(Address(rsp, xmm_size * 2), xmm2);
  61     __ movdbl(Address(rsp, xmm_size * 3), xmm3);
  62     __ movdbl(Address(rsp, xmm_size * 4), xmm4);
  63     __ movdbl(Address(rsp, xmm_size * 5), xmm5);

 655   if (UseCompressedOops) {
 656     __ lock();
 657     __ cmpxchgl(newval, addr);
 658   } else {
 659     __ lock();
 660     __ cmpxchgptr(newval, addr);
 661   }
 662   __ jcc(Assembler::equal, L_success);
 663 
 664   // Step 2. CAS had failed. This may be a false negative.
 665   //
 666   // The trouble comes when we compare the to-space pointer with the from-space
 667   // pointer to the same object. To resolve this, it will suffice to resolve
 668   // the value from memory -- this will give both to-space pointers.
 669   // If they mismatch, then it was a legitimate failure.
 670   //
 671   // Before reaching to resolve sequence, see if we can avoid the whole shebang
 672   // with filters.
 673 
 674   // Filter: when offending in-memory value is null, the failure is definitely legitimate
 675   __ testptr(oldval, oldval);




 676   __ jcc(Assembler::zero, L_failure);
 677 
 678   // Filter: when heap is stable, the failure is definitely legitimate
 679   const Register thread = r15_thread;
 680   Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 681   __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED);
 682   __ jcc(Assembler::zero, L_failure);
 683 
 684   if (UseCompressedOops) {
 685     __ movl(tmp2, oldval);
 686     __ decode_heap_oop(tmp2);
 687   } else {
 688     __ movptr(tmp2, oldval);
 689   }
 690 
 691   // Decode offending in-memory value.
 692   // Test if-forwarded
 693   __ testb(Address(tmp2, oopDesc::mark_offset_in_bytes()), markWord::marked_value);
 694   __ jcc(Assembler::noParity, L_failure);  // When odd number of bits, then not forwarded
 695   __ jcc(Assembler::zero, L_failure);      // When it is 00, then also not forwarded

 757   // and promote the result. Note that we handle the flag from both the 1st and 2nd CAS.
 758   // Otherwise, failure witness for CAE is in oldval on all paths, and we can return.
 759 
 760   if (exchange) {
 761     __ bind(L_failure);
 762     __ bind(L_success);
 763   } else {
 764     assert(res != noreg, "need result register");
 765 
 766     Label exit;
 767     __ bind(L_failure);
 768     __ xorptr(res, res);
 769     __ jmpb(exit);
 770 
 771     __ bind(L_success);
 772     __ movptr(res, 1);
 773     __ bind(exit);
 774   }
 775 }
 776 





















































































































































































































































































































































 777 #ifdef PRODUCT
 778 #define BLOCK_COMMENT(str) /* nothing */
 779 #else
 780 #define BLOCK_COMMENT(str) __ block_comment(str)
 781 #endif
 782 
 783 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
 784 
 785 #define TIMES_OOP (UseCompressedOops ? Address::times_4 : Address::times_8)
 786 
 787 void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
 788                                                                      Register addr, Register count,
 789                                                                      Register tmp) {
 790   assert(ShenandoahCardBarrier, "Should have been checked by caller");
 791 
 792   Label L_loop, L_done;
 793   const Register end = count;
 794   assert_different_registers(addr, end);
 795 
 796   // Zero count? Nothing to do.

  24  */
  25 
  26 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
  27 #include "gc/shenandoah/mode/shenandoahMode.hpp"
  28 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
  29 #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
  30 #include "gc/shenandoah/shenandoahForwarding.hpp"
  31 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  32 #include "gc/shenandoah/shenandoahHeapRegion.hpp"
  33 #include "gc/shenandoah/shenandoahRuntime.hpp"
  34 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
  35 #include "interpreter/interpreter.hpp"
  36 #include "runtime/javaThread.hpp"
  37 #include "runtime/sharedRuntime.hpp"
  38 #include "utilities/macros.hpp"
  39 #ifdef COMPILER1
  40 #include "c1/c1_LIRAssembler.hpp"
  41 #include "c1/c1_MacroAssembler.hpp"
  42 #include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp"
  43 #endif
  44 #ifdef COMPILER2
  45 #include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
  46 #endif
  47 
  48 #define __ masm->
  49 
  50 static void save_machine_state(MacroAssembler* masm, bool handle_gpr, bool handle_fp) {
  51   if (handle_gpr) {
  52     __ push_IU_state();
  53   }
  54 
  55   if (handle_fp) {
  56     // Some paths can be reached from the c2i adapter with live fp arguments in registers.
  57     assert(Argument::n_float_register_parameters_j == 8, "8 fp registers to save at java call");
  58 
  59     const int xmm_size = wordSize * 2;
  60     __ subptr(rsp, xmm_size * 8);
  61     __ movdbl(Address(rsp, xmm_size * 0), xmm0);
  62     __ movdbl(Address(rsp, xmm_size * 1), xmm1);
  63     __ movdbl(Address(rsp, xmm_size * 2), xmm2);
  64     __ movdbl(Address(rsp, xmm_size * 3), xmm3);
  65     __ movdbl(Address(rsp, xmm_size * 4), xmm4);
  66     __ movdbl(Address(rsp, xmm_size * 5), xmm5);

 658   if (UseCompressedOops) {
 659     __ lock();
 660     __ cmpxchgl(newval, addr);
 661   } else {
 662     __ lock();
 663     __ cmpxchgptr(newval, addr);
 664   }
 665   __ jcc(Assembler::equal, L_success);
 666 
 667   // Step 2. CAS had failed. This may be a false negative.
 668   //
 669   // The trouble comes when we compare the to-space pointer with the from-space
 670   // pointer to the same object. To resolve this, it will suffice to resolve
 671   // the value from memory -- this will give both to-space pointers.
 672   // If they mismatch, then it was a legitimate failure.
 673   //
 674   // Before reaching to resolve sequence, see if we can avoid the whole shebang
 675   // with filters.
 676 
 677   // Filter: when offending in-memory value is null, the failure is definitely legitimate
 678   if (UseCompressedOops) {
 679     __ testl(oldval, oldval);
 680   } else {
 681     __ testptr(oldval, oldval);
 682   }
 683   __ jcc(Assembler::zero, L_failure);
 684 
 685   // Filter: when heap is stable, the failure is definitely legitimate
 686   const Register thread = r15_thread;
 687   Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 688   __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED);
 689   __ jcc(Assembler::zero, L_failure);
 690 
 691   if (UseCompressedOops) {
 692     __ movl(tmp2, oldval);
 693     __ decode_heap_oop(tmp2);
 694   } else {
 695     __ movptr(tmp2, oldval);
 696   }
 697 
 698   // Decode offending in-memory value.
 699   // Test if-forwarded
 700   __ testb(Address(tmp2, oopDesc::mark_offset_in_bytes()), markWord::marked_value);
 701   __ jcc(Assembler::noParity, L_failure);  // When odd number of bits, then not forwarded
 702   __ jcc(Assembler::zero, L_failure);      // When it is 00, then also not forwarded

 764   // and promote the result. Note that we handle the flag from both the 1st and 2nd CAS.
 765   // Otherwise, failure witness for CAE is in oldval on all paths, and we can return.
 766 
 767   if (exchange) {
 768     __ bind(L_failure);
 769     __ bind(L_success);
 770   } else {
 771     assert(res != noreg, "need result register");
 772 
 773     Label exit;
 774     __ bind(L_failure);
 775     __ xorptr(res, res);
 776     __ jmpb(exit);
 777 
 778     __ bind(L_success);
 779     __ movptr(res, 1);
 780     __ bind(exit);
 781   }
 782 }
 783 
 784 #ifdef COMPILER2
 785 void ShenandoahBarrierSetAssembler::load_ref_barrier_c2(const MachNode* node, MacroAssembler* masm, Register obj, Register addr, Register tmp1, Register tmp2, Register tmp3, bool narrow) {
 786   if (!ShenandoahLoadRefBarrierStubC2::needs_barrier(node)) {
 787     return;
 788   }
 789   Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
 790 
 791   ShenandoahLoadRefBarrierStubC2* const stub = ShenandoahLoadRefBarrierStubC2::create(node, obj, addr, tmp1, tmp2, tmp3, narrow);
 792   stub->dont_preserve(obj);
 793 
 794   // Test for null.
 795   if (narrow) {
 796     __ testl(obj, obj);
 797   } else {
 798     __ testptr(obj, obj);
 799   }
 800   __ jccb(Assembler::zero, *stub->continuation());
 801 
 802   Address gc_state(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 803   int flags = ShenandoahHeap::HAS_FORWARDED;
 804   bool is_strong = (node->barrier_data() & ShenandoahBarrierStrong) != 0;
 805   if (!is_strong) {
 806     flags |= ShenandoahHeap::WEAK_ROOTS;
 807   }
 808   __ testb(gc_state, flags);
 809   __ jcc(Assembler::notZero, *stub->entry());
 810   __ bind(*stub->continuation());
 811 }
 812 
 813 void ShenandoahBarrierSetAssembler::satb_barrier_c2(const MachNode* node, MacroAssembler* masm,
 814                                                     Register addr, Register preval, Register tmp) {
 815   if (!ShenandoahSATBBarrierStubC2::needs_barrier(node)) {
 816     return;
 817   }
 818   ShenandoahSATBBarrierStubC2* const stub = ShenandoahSATBBarrierStubC2::create(node, addr, preval, tmp);
 819   Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
 820   Address gc_state(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
 821   __ testb(gc_state, ShenandoahHeap::MARKING);
 822   __ jcc(Assembler::notZero, *stub->entry());
 823   __ bind(*stub->continuation());
 824 }
 825 
 826 void ShenandoahBarrierSetAssembler::card_barrier_c2(const MachNode* node, MacroAssembler* masm,
 827                                                     Register addr, Register addr_tmp, Register tmp) {
 828   if (!ShenandoahCardBarrier ||
 829       (node->barrier_data() & (ShenandoahBarrierCardMark | ShenandoahBarrierCardMarkNotNull)) == 0) {
 830     return;
 831   }
 832   Assembler::InlineSkippedInstructionsCounter skip_counter(masm);
 833   if (addr != noreg) {
 834     __ mov(addr_tmp, addr);
 835   }
 836   __ shrptr(addr_tmp, CardTable::card_shift());
 837 
 838   Address curr_ct_holder_addr(r15_thread, in_bytes(ShenandoahThreadLocalData::card_table_offset()));
 839   __ movptr(tmp, curr_ct_holder_addr);
 840   Address card_addr(tmp, addr_tmp, Address::times_1);
 841 
 842   int dirty = CardTable::dirty_card_val();
 843   if (UseCondCardMark) {
 844     Label L_already_dirty;
 845     __ cmpb(card_addr, dirty);
 846     __ jccb(Assembler::equal, L_already_dirty);
 847     __ movb(card_addr, dirty);
 848     __ bind(L_already_dirty);
 849   } else {
 850     __ movb(card_addr, dirty);
 851   }
 852 }
 853 
 854 void ShenandoahBarrierSetAssembler::cmpxchg_oop_c2(const MachNode* node, MacroAssembler* masm,
 855                                                 Register res, Address addr, Register oldval, Register newval, Register tmp1, Register tmp2,
 856                                                 bool exchange) {
 857   assert(oldval == rax, "must be in rax for implicit use in cmpxchg");
 858   assert_different_registers(oldval, tmp1, tmp2);
 859   assert_different_registers(newval, tmp1, tmp2);
 860 
 861   ShenandoahCASBarrierSlowStubC2* const slow_stub = ShenandoahCASBarrierSlowStubC2::create(node, addr, oldval, newval, res, tmp1, tmp2, exchange);
 862   ShenandoahCASBarrierMidStubC2* const mid_stub = ShenandoahCASBarrierMidStubC2::create(node, slow_stub, oldval, res, tmp1, exchange);
 863 
 864   Label L_success, L_failure;
 865 
 866   // Remember oldval for retry logic below. It will be overwritten by the CAS.
 867   if (ShenandoahCASBarrier) {
 868     __ movptr(tmp2, oldval);
 869   }
 870 
 871   // Step 1. Fast-path.
 872   //
 873   // Try to CAS with given arguments. If successful, then we are done.
 874   __ lock();
 875   if (UseCompressedOops) {
 876     __ cmpxchgl(newval, addr);
 877   } else {
 878     __ cmpxchgptr(newval, addr);
 879   }
 880 
 881   if (!ShenandoahCASBarrier) {
 882     if (!exchange) {
 883       assert(res != noreg, "need result register");
 884       __ setcc(Assembler::equal, res);
 885     }
 886     return;
 887   }
 888 
 889   __ jcc(Assembler::notEqual, *mid_stub->entry());
 890 
 891   // Slow-stub re-enters with condition flags according to CAS, we may need to
 892   // set result accordingly.
 893   __ bind(*slow_stub->continuation());
 894 
 895   // Step 5. If we need a boolean result out of CAS, set the flag appropriately.
 896   // and promote the result. Note that we handle the flag from both the 1st and 2nd CAS.
 897   // Otherwise, failure witness for CAE is in oldval on all paths, and we can return.
 898 
 899   if (!exchange) {
 900     assert(res != noreg, "need result register");
 901     __ setcc(Assembler::equal, res);
 902   }
 903 
 904   // Mid-stub re-enters with result set correctly.
 905   __ bind(*mid_stub->continuation());
 906 }
 907 
 908 #undef __
 909 #define __ masm.
 910 
 911 void ShenandoahLoadRefBarrierStubC2::emit_code(MacroAssembler& masm) {
 912   Assembler::InlineSkippedInstructionsCounter skip_counter(&masm);
 913   __ bind(*entry());
 914 
 915   Register obj = _obj;
 916   if (_narrow) {
 917     __ movl(_tmp1, _obj);
 918     __ decode_heap_oop(_tmp1);
 919     obj = _tmp1;
 920   }
 921 
 922   // Weak/phantom loads always need to go to runtime.
 923   if ((_node->barrier_data() & ShenandoahBarrierStrong) != 0) {
 924     __ movptr(_tmp2, obj);
 925     __ shrptr(_tmp2, ShenandoahHeapRegion::region_size_bytes_shift_jint());
 926     __ movptr(_tmp3, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr());
 927     __ movbool(_tmp2, Address(_tmp2, _tmp3, Address::times_1));
 928     __ testbool(_tmp2);
 929     __ jcc(Assembler::zero, *continuation());
 930   }
 931 
 932   {
 933     SaveLiveRegisters save_registers(&masm, this);
 934     if (c_rarg0 != obj) {
 935       if (c_rarg0 == _addr) {
 936         __ movptr(_tmp2, _addr);
 937         _addr = _tmp2;
 938       }
 939       __ movptr(c_rarg0, obj);
 940     }
 941     __ movptr(c_rarg1, _addr);
 942 
 943     address entry;
 944     if (_narrow) {
 945       if ((_node->barrier_data() & ShenandoahBarrierStrong) != 0) {
 946         entry = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong_narrow);
 947       } else if ((_node->barrier_data() & ShenandoahBarrierWeak) != 0) {
 948         entry = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak_narrow);
 949       } else if ((_node->barrier_data() & ShenandoahBarrierPhantom) != 0) {
 950         entry = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom_narrow);
 951       }
 952     } else {
 953       if ((_node->barrier_data() & ShenandoahBarrierStrong) != 0) {
 954         entry = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_strong);
 955       } else if ((_node->barrier_data() & ShenandoahBarrierWeak) != 0) {
 956         entry = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak);
 957       } else if ((_node->barrier_data() & ShenandoahBarrierPhantom) != 0) {
 958         entry = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom);
 959       }
 960     }
 961     __ call(RuntimeAddress(entry), rax);
 962     assert(!save_registers.contains(_obj), "must not save result register");
 963     __ movptr(_obj, rax);
 964   }
 965   if (_narrow) {
 966     __ encode_heap_oop(_obj);
 967   }
 968 
 969   __ jmp(*continuation());
 970 }
 971 
 972 void ShenandoahSATBBarrierStubC2::emit_code(MacroAssembler& masm) {
 973   __ bind(*entry());
 974   Address index(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset()));
 975   Address buffer(r15_thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset()));
 976 
 977   Label runtime;
 978 
 979   // Do we need to load the previous value?
 980   if (_addr != noreg) {
 981     __ load_heap_oop(_preval, Address(_addr, 0), noreg, AS_RAW);
 982   }
 983   // Is the previous value null?
 984   __ cmpptr(_preval, NULL_WORD);
 985   __ jcc(Assembler::equal, *continuation());
 986 
 987   // Can we store a value in the given thread's buffer?
 988   // (The index field is typed as size_t.)
 989   __ movptr(_tmp, index);
 990   __ testptr(_tmp, _tmp);
 991   __ jccb(Assembler::zero, runtime);
 992   // The buffer is not full, store value into it.
 993   __ subptr(_tmp, wordSize);
 994   __ movptr(index, _tmp);
 995   __ addptr(_tmp, buffer);
 996   __ movptr(Address(_tmp, 0), _preval);
 997 
 998   __ jmp(*continuation());
 999 
1000   __ bind(runtime);
1001   {
1002     SaveLiveRegisters save_registers(&masm, this);
1003     if (c_rarg0 != _preval) {
1004       __ mov(c_rarg0, _preval);
1005     }
1006     // rax is a caller-saved, non-argument-passing register, so it does not
1007     // interfere with c_rarg0 or c_rarg1. If it contained any live value before
1008     // entering this stub, it is saved at this point, and restored after the
1009     // call. If it did not contain any live value, it is free to be used. In
1010     // either case, it is safe to use it here as a call scratch register.
1011     __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre_c2)), rax);
1012   }
1013   __ jmp(*continuation());
1014 }
1015 
1016 void ShenandoahCASBarrierMidStubC2::emit_code(MacroAssembler& masm) {
1017   __ bind(*entry());
1018 
1019   if (!_cae) {
1020     // Set result to false, in case that we fail the following tests.
1021     // Failing those tests means legitimate failures.
1022     // Otherwise, result will be set correctly after returning from
1023     // the slow-path.
1024     __ movl(_result, 0); // Result = false.
1025   }
1026   // Check if CAS result is null. If it is, then we must have a legitimate failure.
1027   // This makes loading the fwdptr in the slow-path simpler.
1028   if (UseCompressedOops) {
1029     __ testl(_expected, _expected);
1030   } else {
1031     __ testptr(_expected, _expected);
1032   }
1033   __ jcc(Assembler::equal, *continuation());
1034 
1035   // Check if GC is in progress, otherwise we must have a legitimate failure.
1036   Address gc_state(r15_thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset()));
1037   __ testb(gc_state, ShenandoahHeap::HAS_FORWARDED);
1038   __ jcc(Assembler::notZero, *_slow_stub->entry());
1039   __ jmp(*continuation());
1040 }
1041 
1042 void ShenandoahCASBarrierSlowStubC2::emit_code(MacroAssembler& masm) {
1043   __ bind(*entry());
1044 
1045   assert(_expected == rax, "expected must be rax");
1046 
1047   // Step 2. CAS has failed because the value held at addr does not
1048   // match expected.  This may be a false negative because the value fetched
1049   // from addr (now held in result) may be a from-space pointer to the
1050   // original copy of same object referenced by to-space pointer expected.
1051   //
1052   // To resolve this, it suffices to find the forward pointer associated
1053   // with fetched value.  If this matches expected, retry CAS with new
1054   // parameters.  If this mismatches, then we have a legitimate
1055   // failure, and we're done.
1056 
1057   // overwrite tmp1 with from-space pointer fetched from memory
1058   __ movptr(_tmp1, _expected);
1059 
1060   if (UseCompressedOops) {
1061     __ decode_heap_oop_not_null(_tmp1);
1062   }
1063 
1064   // Load/decode forwarding pointer.
1065   __ movq(_tmp1, Address(_tmp1, oopDesc::mark_offset_in_bytes()));
1066   // Negate the mark-word. This allows us to test lowest 2 bits easily while preserving the upper bits.
1067   __ negq(_tmp1);
1068   __ testq(_tmp1, markWord::lock_mask_in_place);
1069   // Not forwarded, must have a legit CAS failure.
1070   __ jcc(Assembler::notEqual, *continuation());
1071   // Set the lowest two bits. This is equivalent to clearing the two bits after
1072   // the subsequent inversion.
1073   __ orq(_tmp1, markWord::marked_value);
1074   // And invert back to get the forwardee.
1075   __ negq(_tmp1);
1076 
1077   if (UseCompressedOops) {
1078     __ encode_heap_oop_not_null(_tmp1); // encode for comparison
1079   }
1080 
1081   // Now we have the forwarded offender in tmp1.
1082   // We preserved the original expected value in tmp2 in the fast-path.
1083   // Compare and if they don't match, we have legitimate failure
1084   __ cmpptr(_tmp1, _tmp2);
1085   __ jcc(Assembler::notEqual, *continuation());
1086 
1087   // Fall through to step 3.
1088 
1089   // Step 3.  We've confirmed that the value originally held in memory
1090   // (now held in result) pointed to from-space version of original
1091   // expected value.  Try the CAS again with the from-space expected
1092   // value.  If it now succeeds, we're good.
1093   //
1094   // Note: expected holds encoded from-space pointer that matches to-space
1095   // object residing at tmp1.
1096   __ lock();
1097   if (UseCompressedOops) {
1098     __ cmpxchgl(_new_val, _addr);
1099   } else {
1100     __ cmpxchgptr(_new_val, _addr);
1101   }
1102 
1103   // If fetched value did not equal the new expected, this could
1104   // still be a false negative because some other (GC) thread may have
1105   // newly overwritten the memory value with its to-space equivalent.
1106   __ jcc(Assembler::equal, *continuation());
1107 
1108   // Step 4. Try to CAS again, but with the original to-space expected.
1109   // This should be very rare.
1110   __ movptr(_expected, _tmp2);
1111   __ lock();
1112   if (UseCompressedOops) {
1113     __ cmpxchgl(_new_val, _addr);
1114   } else {
1115     __ cmpxchgptr(_new_val, _addr);
1116   }
1117   // At this point, there can no longer be false negatives.
1118   __ jmp(*continuation());
1119 }
1120 
1121 #undef __
1122 #define __ masm->
1123 #endif
1124 
1125 #ifdef PRODUCT
1126 #define BLOCK_COMMENT(str) /* nothing */
1127 #else
1128 #define BLOCK_COMMENT(str) __ block_comment(str)
1129 #endif
1130 
1131 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
1132 
1133 #define TIMES_OOP (UseCompressedOops ? Address::times_4 : Address::times_8)
1134 
1135 void ShenandoahBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
1136                                                                      Register addr, Register count,
1137                                                                      Register tmp) {
1138   assert(ShenandoahCardBarrier, "Should have been checked by caller");
1139 
1140   Label L_loop, L_done;
1141   const Register end = count;
1142   assert_different_registers(addr, end);
1143 
1144   // Zero count? Nothing to do.
< prev index next >