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 // TODO: The following should really live in an X86 specific subclass.
 169 void ShenandoahBarrierSet::interpreter_read_barrier(MacroAssembler* masm, Register dst) {
 170   if (ShenandoahReadBarrier) {
 171 
 172     Label is_null;
 173     __ testptr(dst, dst);
 174     __ jcc(Assembler::zero, is_null);
 175     interpreter_read_barrier_not_null(masm, dst);
 176     __ bind(is_null);
 177   }
 178 }
 179 
 180 void ShenandoahBarrierSet::interpreter_read_barrier_not_null(MacroAssembler* masm, Register dst) {
 181   if (ShenandoahReadBarrier) {
 182     if (ShenandoahVerifyReadsToFromSpace) {
 183       compile_resolve_oop_runtime(masm, dst);
 184       return;
 185     }
 186     __ movptr(dst, Address(dst, -8));
 187   }
 188 }
 189 
 190 void ShenandoahBarrierSet::interpreter_write_barrier(MacroAssembler* masm, Register dst) {
 191 
 192   if (! ShenandoahWriteBarrier) {
 193     assert(! ShenandoahConcurrentEvacuation, "Can only do this without concurrent evacuation");
 194     return interpreter_read_barrier(masm, dst);
 195   }
 196 
 197   assert(dst != rscratch1, "different regs");
 198   //assert(dst != rscratch2, "Need rscratch2");
 199 
 200   Label done;
 201 
 202   Address evacuation_in_progress = Address(r15_thread, in_bytes(JavaThread::evacuation_in_progress_offset()));
 203 
 204   __ cmpb(evacuation_in_progress, 0);
 205 
 206   // Now check if evacuation is in progress.
 207   interpreter_read_barrier_not_null(masm, dst);
 208 
 209   __ jcc(Assembler::equal, done);
 210   __ push(rscratch1);
 211   __ push(rscratch2);
 212 
 213   __ movptr(rscratch1, dst);
 214   __ shrptr(rscratch1, ShenandoahHeapRegion::RegionSizeShift);
 215   __ movptr(rscratch2, (intptr_t) ShenandoahHeap::in_cset_fast_test_addr());
 216   __ movbool(rscratch2, Address(rscratch2, rscratch1, Address::times_1));
 217   __ testb(rscratch2, 0x1);
 218 
 219   __ pop(rscratch2);
 220   __ pop(rscratch1);
 221 
 222   __ jcc(Assembler::zero, done);
 223 
 224   __ push(rscratch1);
 225 
 226   // Save possibly live regs.
 227   if (dst != rax) {
 228     __ push(rax);
 229   }
 230   if (dst != rbx) {
 231     __ push(rbx);
 232   }
 233   if (dst != rcx) {
 234     __ push(rcx);
 235   }
 236   if (dst != rdx) {
 237     __ push(rdx);
 238   }
 239   if (dst != c_rarg1) {
 240     __ push(c_rarg1);
 241   }
 242 
 243   __ subptr(rsp, 2 * wordSize);
 244   __ movdbl(Address(rsp, 0), xmm0);
 245 
 246   // Call into runtime
 247   __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahBarrierSet::resolve_and_maybe_copy_oop_interp), dst);
 248   __ mov(rscratch1, rax);
 249 
 250   // Restore possibly live regs.
 251   __ movdbl(xmm0, Address(rsp, 0));
 252   __ addptr(rsp, 2 * Interpreter::stackElementSize);
 253 
 254   if (dst != c_rarg1) {
 255     __ pop(c_rarg1);
 256   }
 257   if (dst != rdx) {
 258     __ pop(rdx);
 259   }
 260   if (dst != rcx) {
 261     __ pop(rcx);
 262   }
 263   if (dst != rbx) {
 264     __ pop(rbx);
 265   }
 266   if (dst != rax) {
 267     __ pop(rax);
 268   }
 269 
 270   // Move result into dst reg.
 271   __ mov(dst, rscratch1);
 272 
 273   __ pop(rscratch1);
 274 
 275   __ bind(done);
 276 }
 277 
 278 void ShenandoahHeap::compile_prepare_oop(MacroAssembler* masm, Register obj) {
 279   __ incrementq(obj, BrooksPointer::BROOKS_POINTER_OBJ_SIZE * HeapWordSize);
 280   __ movptr(Address(obj, -1 * HeapWordSize), obj);
 281 }
 282 #endif
 283