1 /*
   2  * Copyright (c) 2015, Red Hat, Inc. and/or its affiliates.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  *
  22  */
  23 
  24 #include "gc/shenandoah/brooksPointer.hpp"
  25 #include "gc/shenandoah/shenandoahBarrierSet.hpp"
  26 
  27 #include "asm/macroAssembler.hpp"
  28 #include "interpreter/interpreter.hpp"
  29 
  30 #define __ masm->
  31 
  32 #ifndef CC_INTERP
  33 void ShenandoahBarrierSet::compile_resolve_oop_runtime(MacroAssembler* masm, Register dst) {
  34 
  35   __ push(rscratch1);
  36 
  37   if (dst != rax) {
  38     __ push(rax);
  39   }
  40   if (dst != rbx) {
  41     __ push(rbx);
  42   }
  43   if (dst != rcx) {
  44     __ push(rcx);
  45   }
  46   if (dst != rdx) {
  47     __ push(rdx);
  48   }
  49   if (dst != rdi) {
  50     __ push(rdi);
  51   }
  52   if (dst != rsi) {
  53     __ push(rsi);
  54   }
  55   if (dst != rbp) {
  56     __ push(rbp);
  57   }
  58   if (dst != r8) {
  59     __ push(r8);
  60   }
  61   if (dst != r9) {
  62     __ push(r9);
  63   }
  64   if (dst != r11) {
  65     __ push(r11);
  66   }
  67   if (dst != r12) {
  68     __ push(r12);
  69   }
  70   if (dst != r13) {
  71     __ push(r13);
  72   }
  73   if (dst != r14) {
  74     __ push(r14);
  75   }
  76   if (dst != r15) {
  77     __ push(r15);
  78   }
  79 
  80   __ subptr(rsp, 128);
  81   __ movdbl(Address(rsp, 0), xmm0);
  82   __ movdbl(Address(rsp, 8), xmm1);
  83   __ movdbl(Address(rsp, 16), xmm2);
  84   __ movdbl(Address(rsp, 24), xmm3);
  85   __ movdbl(Address(rsp, 32), xmm4);
  86   __ movdbl(Address(rsp, 40), xmm5);
  87   __ movdbl(Address(rsp, 48), xmm6);
  88   __ movdbl(Address(rsp, 56), xmm7);
  89   __ movdbl(Address(rsp, 64), xmm8);
  90   __ movdbl(Address(rsp, 72), xmm9);
  91   __ movdbl(Address(rsp, 80), xmm10);
  92   __ movdbl(Address(rsp, 88), xmm11);
  93   __ movdbl(Address(rsp, 96), xmm12);
  94   __ movdbl(Address(rsp, 104), xmm13);
  95   __ movdbl(Address(rsp, 112), xmm14);
  96   __ movdbl(Address(rsp, 120), xmm15);
  97 
  98   __ mov(c_rarg1, dst);
  99   __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahBarrierSet::resolve_oop_static), c_rarg1);
 100   __ mov(rscratch1, rax);
 101 
 102   __ movdbl(xmm0, Address(rsp, 0));
 103   __ movdbl(xmm1, Address(rsp, 8));
 104   __ movdbl(xmm2, Address(rsp, 16));
 105   __ movdbl(xmm3, Address(rsp, 24));
 106   __ movdbl(xmm4, Address(rsp, 32));
 107   __ movdbl(xmm5, Address(rsp, 40));
 108   __ movdbl(xmm6, Address(rsp, 48));
 109   __ movdbl(xmm7, Address(rsp, 56));
 110   __ movdbl(xmm8, Address(rsp, 64));
 111   __ movdbl(xmm9, Address(rsp, 72));
 112   __ movdbl(xmm10, Address(rsp, 80));
 113   __ movdbl(xmm11, Address(rsp, 88));
 114   __ movdbl(xmm12, Address(rsp, 96));
 115   __ movdbl(xmm13, Address(rsp, 104));
 116   __ movdbl(xmm14, Address(rsp, 112));
 117   __ movdbl(xmm15, Address(rsp, 120));
 118   __ addptr(rsp, 128);
 119 
 120   if (dst != r15) {
 121     __ pop(r15);
 122   }
 123   if (dst != r14) {
 124     __ pop(r14);
 125   }
 126   if (dst != r13) {
 127     __ pop(r13);
 128   }
 129   if (dst != r12) {
 130     __ pop(r12);
 131   }
 132   if (dst != r11) {
 133     __ pop(r11);
 134   }
 135   if (dst != r9) {
 136     __ pop(r9);
 137   }
 138   if (dst != r8) {
 139     __ pop(r8);
 140   }
 141   if (dst != rbp) {
 142     __ pop(rbp);
 143   }
 144   if (dst != rsi) {
 145     __ pop(rsi);
 146   }
 147   if (dst != rdi) {
 148     __ pop(rdi);
 149   }
 150   if (dst != rdx) {
 151     __ pop(rdx);
 152   }
 153   if (dst != rcx) {
 154     __ pop(rcx);
 155   }
 156   if (dst != rbx) {
 157     __ pop(rbx);
 158   }
 159   if (dst != rax) {
 160     __ pop(rax);
 161   }
 162 
 163   __ mov(dst, rscratch1);
 164 
 165   __ pop(rscratch1);
 166 }
 167 
 168 void ShenandoahBarrierSet::interpreter_read_barrier(MacroAssembler* masm, Register dst) {
 169   if (ShenandoahReadBarrier) {
 170 
 171     Label is_null;
 172     __ testptr(dst, dst);
 173     __ jcc(Assembler::zero, is_null);
 174     interpreter_read_barrier_not_null(masm, dst);
 175     __ bind(is_null);
 176   }
 177 }
 178 
 179 void ShenandoahBarrierSet::interpreter_read_barrier_not_null(MacroAssembler* masm, Register dst) {
 180   if (ShenandoahReadBarrier) {
 181     if (ShenandoahVerifyReadsToFromSpace) {
 182       compile_resolve_oop_runtime(masm, dst);
 183       return;
 184     }
 185     __ movptr(dst, Address(dst, BrooksPointer::BYTE_OFFSET));
 186   }
 187 }
 188 
 189 void ShenandoahBarrierSet::interpreter_write_barrier(MacroAssembler* masm, Register dst) {
 190 
 191   if (! ShenandoahWriteBarrier) {
 192     assert(! ShenandoahConcurrentEvacuation, "Can only do this without concurrent evacuation");
 193     return interpreter_read_barrier(masm, dst);
 194   }
 195 
 196   assert(dst != rscratch1, "different regs");
 197   //assert(dst != rscratch2, "Need rscratch2");
 198 
 199   Label done;
 200 
 201   Address evacuation_in_progress = Address(r15_thread, in_bytes(JavaThread::evacuation_in_progress_offset()));
 202 
 203   __ cmpb(evacuation_in_progress, 0);
 204 
 205   // Now check if evacuation is in progress.
 206   interpreter_read_barrier_not_null(masm, dst);
 207 
 208   __ jcc(Assembler::equal, done);
 209   __ push(rscratch1);
 210   __ push(rscratch2);
 211 
 212   __ movptr(rscratch1, dst);
 213   __ shrptr(rscratch1, ShenandoahHeapRegion::RegionSizeShift);
 214   __ movptr(rscratch2, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr());
 215   __ movbool(rscratch2, Address(rscratch2, rscratch1, Address::times_1));
 216   __ testb(rscratch2, 0x1);
 217 
 218   __ pop(rscratch2);
 219   __ pop(rscratch1);
 220 
 221   __ jcc(Assembler::zero, done);
 222 
 223   __ push(rscratch1);
 224 
 225   // Save possibly live regs.
 226   if (dst != rax) {
 227     __ push(rax);
 228   }
 229   if (dst != rbx) {
 230     __ push(rbx);
 231   }
 232   if (dst != rcx) {
 233     __ push(rcx);
 234   }
 235   if (dst != rdx) {
 236     __ push(rdx);
 237   }
 238   if (dst != c_rarg1) {
 239     __ push(c_rarg1);
 240   }
 241 
 242   __ subptr(rsp, 2 * wordSize);
 243   __ movdbl(Address(rsp, 0), xmm0);
 244 
 245   // Call into runtime
 246   __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahBarrierSet::write_barrier_interp), dst);
 247   __ mov(rscratch1, rax);
 248 
 249   // Restore possibly live regs.
 250   __ movdbl(xmm0, Address(rsp, 0));
 251   __ addptr(rsp, 2 * Interpreter::stackElementSize);
 252 
 253   if (dst != c_rarg1) {
 254     __ pop(c_rarg1);
 255   }
 256   if (dst != rdx) {
 257     __ pop(rdx);
 258   }
 259   if (dst != rcx) {
 260     __ pop(rcx);
 261   }
 262   if (dst != rbx) {
 263     __ pop(rbx);
 264   }
 265   if (dst != rax) {
 266     __ pop(rax);
 267   }
 268 
 269   // Move result into dst reg.
 270   __ mov(dst, rscratch1);
 271 
 272   __ pop(rscratch1);
 273 
 274   __ bind(done);
 275 }
 276 
 277 void ShenandoahHeap::compile_prepare_oop(MacroAssembler* masm, Register obj) {
 278   __ incrementq(obj, BrooksPointer::BROOKS_POINTER_OBJ_SIZE * HeapWordSize);
 279   __ movptr(Address(obj, -1 * HeapWordSize), obj);
 280 }
 281 #endif