1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "jni_macro_assembler_x86_64.h" 18 19 #include "base/casts.h" 20 #include "entrypoints/quick/quick_entrypoints.h" 21 #include "memory_region.h" 22 #include "thread.h" 23 24 namespace art { 25 namespace x86_64 { 26 27 static dwarf::Reg DWARFReg(Register reg) { 28 return dwarf::Reg::X86_64Core(static_cast<int>(reg)); 29 } 30 static dwarf::Reg DWARFReg(FloatRegister reg) { 31 return dwarf::Reg::X86_64Fp(static_cast<int>(reg)); 32 } 33 34 constexpr size_t kFramePointerSize = 8; 35 36 #define __ asm_. 37 38 void X86_64JNIMacroAssembler::BuildFrame(size_t frame_size, 39 ManagedRegister method_reg, 40 ArrayRef<const ManagedRegister> spill_regs, 41 const ManagedRegisterEntrySpills& entry_spills) { 42 DCHECK_EQ(CodeSize(), 0U); // Nothing emitted yet. 43 cfi().SetCurrentCFAOffset(8); // Return address on stack. 44 CHECK_ALIGNED(frame_size, kStackAlignment); 45 int gpr_count = 0; 46 for (int i = spill_regs.size() - 1; i >= 0; --i) { 47 x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64(); 48 if (spill.IsCpuRegister()) { 49 __ pushq(spill.AsCpuRegister()); 50 gpr_count++; 51 cfi().AdjustCFAOffset(kFramePointerSize); 52 cfi().RelOffset(DWARFReg(spill.AsCpuRegister().AsRegister()), 0); 53 } 54 } 55 // return address then method on stack. 56 int64_t rest_of_frame = static_cast<int64_t>(frame_size) 57 - (gpr_count * kFramePointerSize) 58 - kFramePointerSize /*return address*/; 59 __ subq(CpuRegister(RSP), Immediate(rest_of_frame)); 60 cfi().AdjustCFAOffset(rest_of_frame); 61 62 // spill xmms 63 int64_t offset = rest_of_frame; 64 for (int i = spill_regs.size() - 1; i >= 0; --i) { 65 x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64(); 66 if (spill.IsXmmRegister()) { 67 offset -= sizeof(double); 68 __ movsd(Address(CpuRegister(RSP), offset), spill.AsXmmRegister()); 69 cfi().RelOffset(DWARFReg(spill.AsXmmRegister().AsFloatRegister()), offset); 70 } 71 } 72 73 static_assert(static_cast<size_t>(kX86_64PointerSize) == kFramePointerSize, 74 "Unexpected frame pointer size."); 75 76 __ movq(Address(CpuRegister(RSP), 0), method_reg.AsX86_64().AsCpuRegister()); 77 78 for (size_t i = 0; i < entry_spills.size(); ++i) { 79 ManagedRegisterSpill spill = entry_spills.at(i); 80 if (spill.AsX86_64().IsCpuRegister()) { 81 if (spill.getSize() == 8) { 82 __ movq(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()), 83 spill.AsX86_64().AsCpuRegister()); 84 } else { 85 CHECK_EQ(spill.getSize(), 4); 86 __ movl(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()), 87 spill.AsX86_64().AsCpuRegister()); 88 } 89 } else { 90 if (spill.getSize() == 8) { 91 __ movsd(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()), 92 spill.AsX86_64().AsXmmRegister()); 93 } else { 94 CHECK_EQ(spill.getSize(), 4); 95 __ movss(Address(CpuRegister(RSP), frame_size + spill.getSpillOffset()), 96 spill.AsX86_64().AsXmmRegister()); 97 } 98 } 99 } 100 } 101 102 void X86_64JNIMacroAssembler::RemoveFrame(size_t frame_size, 103 ArrayRef<const ManagedRegister> spill_regs) { 104 CHECK_ALIGNED(frame_size, kStackAlignment); 105 cfi().RememberState(); 106 int gpr_count = 0; 107 // unspill xmms 108 int64_t offset = static_cast<int64_t>(frame_size) 109 - (spill_regs.size() * kFramePointerSize) 110 - 2 * kFramePointerSize; 111 for (size_t i = 0; i < spill_regs.size(); ++i) { 112 x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64(); 113 if (spill.IsXmmRegister()) { 114 offset += sizeof(double); 115 __ movsd(spill.AsXmmRegister(), Address(CpuRegister(RSP), offset)); 116 cfi().Restore(DWARFReg(spill.AsXmmRegister().AsFloatRegister())); 117 } else { 118 gpr_count++; 119 } 120 } 121 int adjust = static_cast<int>(frame_size) - (gpr_count * kFramePointerSize) - kFramePointerSize; 122 __ addq(CpuRegister(RSP), Immediate(adjust)); 123 cfi().AdjustCFAOffset(-adjust); 124 for (size_t i = 0; i < spill_regs.size(); ++i) { 125 x86_64::X86_64ManagedRegister spill = spill_regs[i].AsX86_64(); 126 if (spill.IsCpuRegister()) { 127 __ popq(spill.AsCpuRegister()); 128 cfi().AdjustCFAOffset(-static_cast<int>(kFramePointerSize)); 129 cfi().Restore(DWARFReg(spill.AsCpuRegister().AsRegister())); 130 } 131 } 132 __ ret(); 133 // The CFI should be restored for any code that follows the exit block. 134 cfi().RestoreState(); 135 cfi().DefCFAOffset(frame_size); 136 } 137 138 void X86_64JNIMacroAssembler::IncreaseFrameSize(size_t adjust) { 139 CHECK_ALIGNED(adjust, kStackAlignment); 140 __ addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust))); 141 cfi().AdjustCFAOffset(adjust); 142 } 143 144 static void DecreaseFrameSizeImpl(size_t adjust, X86_64Assembler* assembler) { 145 CHECK_ALIGNED(adjust, kStackAlignment); 146 assembler->addq(CpuRegister(RSP), Immediate(adjust)); 147 assembler->cfi().AdjustCFAOffset(-adjust); 148 } 149 150 void X86_64JNIMacroAssembler::DecreaseFrameSize(size_t adjust) { 151 DecreaseFrameSizeImpl(adjust, &asm_); 152 } 153 154 void X86_64JNIMacroAssembler::Store(FrameOffset offs, ManagedRegister msrc, size_t size) { 155 X86_64ManagedRegister src = msrc.AsX86_64(); 156 if (src.IsNoRegister()) { 157 CHECK_EQ(0u, size); 158 } else if (src.IsCpuRegister()) { 159 if (size == 4) { 160 CHECK_EQ(4u, size); 161 __ movl(Address(CpuRegister(RSP), offs), src.AsCpuRegister()); 162 } else { 163 CHECK_EQ(8u, size); 164 __ movq(Address(CpuRegister(RSP), offs), src.AsCpuRegister()); 165 } 166 } else if (src.IsRegisterPair()) { 167 CHECK_EQ(0u, size); 168 __ movq(Address(CpuRegister(RSP), offs), src.AsRegisterPairLow()); 169 __ movq(Address(CpuRegister(RSP), FrameOffset(offs.Int32Value()+4)), 170 src.AsRegisterPairHigh()); 171 } else if (src.IsX87Register()) { 172 if (size == 4) { 173 __ fstps(Address(CpuRegister(RSP), offs)); 174 } else { 175 __ fstpl(Address(CpuRegister(RSP), offs)); 176 } 177 } else { 178 CHECK(src.IsXmmRegister()); 179 if (size == 4) { 180 __ movss(Address(CpuRegister(RSP), offs), src.AsXmmRegister()); 181 } else { 182 __ movsd(Address(CpuRegister(RSP), offs), src.AsXmmRegister()); 183 } 184 } 185 } 186 187 void X86_64JNIMacroAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) { 188 X86_64ManagedRegister src = msrc.AsX86_64(); 189 CHECK(src.IsCpuRegister()); 190 __ movl(Address(CpuRegister(RSP), dest), src.AsCpuRegister()); 191 } 192 193 void X86_64JNIMacroAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) { 194 X86_64ManagedRegister src = msrc.AsX86_64(); 195 CHECK(src.IsCpuRegister()); 196 __ movq(Address(CpuRegister(RSP), dest), src.AsCpuRegister()); 197 } 198 199 void X86_64JNIMacroAssembler::StoreImmediateToFrame(FrameOffset dest, 200 uint32_t imm, 201 ManagedRegister) { 202 __ movl(Address(CpuRegister(RSP), dest), Immediate(imm)); // TODO(64) movq? 203 } 204 205 void X86_64JNIMacroAssembler::StoreStackOffsetToThread(ThreadOffset64 thr_offs, 206 FrameOffset fr_offs, 207 ManagedRegister mscratch) { 208 X86_64ManagedRegister scratch = mscratch.AsX86_64(); 209 CHECK(scratch.IsCpuRegister()); 210 __ leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), fr_offs)); 211 __ gs()->movq(Address::Absolute(thr_offs, true), scratch.AsCpuRegister()); 212 } 213 214 void X86_64JNIMacroAssembler::StoreStackPointerToThread(ThreadOffset64 thr_offs) { 215 __ gs()->movq(Address::Absolute(thr_offs, true), CpuRegister(RSP)); 216 } 217 218 void X86_64JNIMacroAssembler::StoreSpanning(FrameOffset /*dst*/, 219 ManagedRegister /*src*/, 220 FrameOffset /*in_off*/, 221 ManagedRegister /*scratch*/) { 222 UNIMPLEMENTED(FATAL); // this case only currently exists for ARM 223 } 224 225 void X86_64JNIMacroAssembler::Load(ManagedRegister mdest, FrameOffset src, size_t size) { 226 X86_64ManagedRegister dest = mdest.AsX86_64(); 227 if (dest.IsNoRegister()) { 228 CHECK_EQ(0u, size); 229 } else if (dest.IsCpuRegister()) { 230 if (size == 4) { 231 CHECK_EQ(4u, size); 232 __ movl(dest.AsCpuRegister(), Address(CpuRegister(RSP), src)); 233 } else { 234 CHECK_EQ(8u, size); 235 __ movq(dest.AsCpuRegister(), Address(CpuRegister(RSP), src)); 236 } 237 } else if (dest.IsRegisterPair()) { 238 CHECK_EQ(0u, size); 239 __ movq(dest.AsRegisterPairLow(), Address(CpuRegister(RSP), src)); 240 __ movq(dest.AsRegisterPairHigh(), Address(CpuRegister(RSP), FrameOffset(src.Int32Value()+4))); 241 } else if (dest.IsX87Register()) { 242 if (size == 4) { 243 __ flds(Address(CpuRegister(RSP), src)); 244 } else { 245 __ fldl(Address(CpuRegister(RSP), src)); 246 } 247 } else { 248 CHECK(dest.IsXmmRegister()); 249 if (size == 4) { 250 __ movss(dest.AsXmmRegister(), Address(CpuRegister(RSP), src)); 251 } else { 252 __ movsd(dest.AsXmmRegister(), Address(CpuRegister(RSP), src)); 253 } 254 } 255 } 256 257 void X86_64JNIMacroAssembler::LoadFromThread(ManagedRegister mdest, 258 ThreadOffset64 src, size_t size) { 259 X86_64ManagedRegister dest = mdest.AsX86_64(); 260 if (dest.IsNoRegister()) { 261 CHECK_EQ(0u, size); 262 } else if (dest.IsCpuRegister()) { 263 if (size == 1u) { 264 __ gs()->movzxb(dest.AsCpuRegister(), Address::Absolute(src, true)); 265 } else { 266 CHECK_EQ(4u, size); 267 __ gs()->movl(dest.AsCpuRegister(), Address::Absolute(src, true)); 268 } 269 } else if (dest.IsRegisterPair()) { 270 CHECK_EQ(8u, size); 271 __ gs()->movq(dest.AsRegisterPairLow(), Address::Absolute(src, true)); 272 } else if (dest.IsX87Register()) { 273 if (size == 4) { 274 __ gs()->flds(Address::Absolute(src, true)); 275 } else { 276 __ gs()->fldl(Address::Absolute(src, true)); 277 } 278 } else { 279 CHECK(dest.IsXmmRegister()); 280 if (size == 4) { 281 __ gs()->movss(dest.AsXmmRegister(), Address::Absolute(src, true)); 282 } else { 283 __ gs()->movsd(dest.AsXmmRegister(), Address::Absolute(src, true)); 284 } 285 } 286 } 287 288 void X86_64JNIMacroAssembler::LoadRef(ManagedRegister mdest, FrameOffset src) { 289 X86_64ManagedRegister dest = mdest.AsX86_64(); 290 CHECK(dest.IsCpuRegister()); 291 __ movq(dest.AsCpuRegister(), Address(CpuRegister(RSP), src)); 292 } 293 294 void X86_64JNIMacroAssembler::LoadRef(ManagedRegister mdest, 295 ManagedRegister mbase, 296 MemberOffset offs, 297 bool unpoison_reference) { 298 X86_64ManagedRegister base = mbase.AsX86_64(); 299 X86_64ManagedRegister dest = mdest.AsX86_64(); 300 CHECK(base.IsCpuRegister()); 301 CHECK(dest.IsCpuRegister()); 302 __ movl(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs)); 303 if (unpoison_reference) { 304 __ MaybeUnpoisonHeapReference(dest.AsCpuRegister()); 305 } 306 } 307 308 void X86_64JNIMacroAssembler::LoadRawPtr(ManagedRegister mdest, 309 ManagedRegister mbase, 310 Offset offs) { 311 X86_64ManagedRegister base = mbase.AsX86_64(); 312 X86_64ManagedRegister dest = mdest.AsX86_64(); 313 CHECK(base.IsCpuRegister()); 314 CHECK(dest.IsCpuRegister()); 315 __ movq(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs)); 316 } 317 318 void X86_64JNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister mdest, ThreadOffset64 offs) { 319 X86_64ManagedRegister dest = mdest.AsX86_64(); 320 CHECK(dest.IsCpuRegister()); 321 __ gs()->movq(dest.AsCpuRegister(), Address::Absolute(offs, true)); 322 } 323 324 void X86_64JNIMacroAssembler::SignExtend(ManagedRegister mreg, size_t size) { 325 X86_64ManagedRegister reg = mreg.AsX86_64(); 326 CHECK(size == 1 || size == 2) << size; 327 CHECK(reg.IsCpuRegister()) << reg; 328 if (size == 1) { 329 __ movsxb(reg.AsCpuRegister(), reg.AsCpuRegister()); 330 } else { 331 __ movsxw(reg.AsCpuRegister(), reg.AsCpuRegister()); 332 } 333 } 334 335 void X86_64JNIMacroAssembler::ZeroExtend(ManagedRegister mreg, size_t size) { 336 X86_64ManagedRegister reg = mreg.AsX86_64(); 337 CHECK(size == 1 || size == 2) << size; 338 CHECK(reg.IsCpuRegister()) << reg; 339 if (size == 1) { 340 __ movzxb(reg.AsCpuRegister(), reg.AsCpuRegister()); 341 } else { 342 __ movzxw(reg.AsCpuRegister(), reg.AsCpuRegister()); 343 } 344 } 345 346 void X86_64JNIMacroAssembler::Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) { 347 X86_64ManagedRegister dest = mdest.AsX86_64(); 348 X86_64ManagedRegister src = msrc.AsX86_64(); 349 if (!dest.Equals(src)) { 350 if (dest.IsCpuRegister() && src.IsCpuRegister()) { 351 __ movq(dest.AsCpuRegister(), src.AsCpuRegister()); 352 } else if (src.IsX87Register() && dest.IsXmmRegister()) { 353 // Pass via stack and pop X87 register 354 __ subl(CpuRegister(RSP), Immediate(16)); 355 if (size == 4) { 356 CHECK_EQ(src.AsX87Register(), ST0); 357 __ fstps(Address(CpuRegister(RSP), 0)); 358 __ movss(dest.AsXmmRegister(), Address(CpuRegister(RSP), 0)); 359 } else { 360 CHECK_EQ(src.AsX87Register(), ST0); 361 __ fstpl(Address(CpuRegister(RSP), 0)); 362 __ movsd(dest.AsXmmRegister(), Address(CpuRegister(RSP), 0)); 363 } 364 __ addq(CpuRegister(RSP), Immediate(16)); 365 } else { 366 // TODO: x87, SSE 367 UNIMPLEMENTED(FATAL) << ": Move " << dest << ", " << src; 368 } 369 } 370 } 371 372 void X86_64JNIMacroAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) { 373 X86_64ManagedRegister scratch = mscratch.AsX86_64(); 374 CHECK(scratch.IsCpuRegister()); 375 __ movl(scratch.AsCpuRegister(), Address(CpuRegister(RSP), src)); 376 __ movl(Address(CpuRegister(RSP), dest), scratch.AsCpuRegister()); 377 } 378 379 void X86_64JNIMacroAssembler::CopyRawPtrFromThread(FrameOffset fr_offs, 380 ThreadOffset64 thr_offs, 381 ManagedRegister mscratch) { 382 X86_64ManagedRegister scratch = mscratch.AsX86_64(); 383 CHECK(scratch.IsCpuRegister()); 384 __ gs()->movq(scratch.AsCpuRegister(), Address::Absolute(thr_offs, true)); 385 Store(fr_offs, scratch, 8); 386 } 387 388 void X86_64JNIMacroAssembler::CopyRawPtrToThread(ThreadOffset64 thr_offs, 389 FrameOffset fr_offs, 390 ManagedRegister mscratch) { 391 X86_64ManagedRegister scratch = mscratch.AsX86_64(); 392 CHECK(scratch.IsCpuRegister()); 393 Load(scratch, fr_offs, 8); 394 __ gs()->movq(Address::Absolute(thr_offs, true), scratch.AsCpuRegister()); 395 } 396 397 void X86_64JNIMacroAssembler::Copy(FrameOffset dest, 398 FrameOffset src, 399 ManagedRegister mscratch, 400 size_t size) { 401 X86_64ManagedRegister scratch = mscratch.AsX86_64(); 402 if (scratch.IsCpuRegister() && size == 8) { 403 Load(scratch, src, 4); 404 Store(dest, scratch, 4); 405 Load(scratch, FrameOffset(src.Int32Value() + 4), 4); 406 Store(FrameOffset(dest.Int32Value() + 4), scratch, 4); 407 } else { 408 Load(scratch, src, size); 409 Store(dest, scratch, size); 410 } 411 } 412 413 void X86_64JNIMacroAssembler::Copy(FrameOffset /*dst*/, 414 ManagedRegister /*src_base*/, 415 Offset /*src_offset*/, 416 ManagedRegister /*scratch*/, 417 size_t /*size*/) { 418 UNIMPLEMENTED(FATAL); 419 } 420 421 void X86_64JNIMacroAssembler::Copy(ManagedRegister dest_base, 422 Offset dest_offset, 423 FrameOffset src, 424 ManagedRegister scratch, 425 size_t size) { 426 CHECK(scratch.IsNoRegister()); 427 CHECK_EQ(size, 4u); 428 __ pushq(Address(CpuRegister(RSP), src)); 429 __ popq(Address(dest_base.AsX86_64().AsCpuRegister(), dest_offset)); 430 } 431 432 void X86_64JNIMacroAssembler::Copy(FrameOffset dest, 433 FrameOffset src_base, 434 Offset src_offset, 435 ManagedRegister mscratch, 436 size_t size) { 437 CpuRegister scratch = mscratch.AsX86_64().AsCpuRegister(); 438 CHECK_EQ(size, 4u); 439 __ movq(scratch, Address(CpuRegister(RSP), src_base)); 440 __ movq(scratch, Address(scratch, src_offset)); 441 __ movq(Address(CpuRegister(RSP), dest), scratch); 442 } 443 444 void X86_64JNIMacroAssembler::Copy(ManagedRegister dest, 445 Offset dest_offset, 446 ManagedRegister src, 447 Offset src_offset, 448 ManagedRegister scratch, 449 size_t size) { 450 CHECK_EQ(size, 4u); 451 CHECK(scratch.IsNoRegister()); 452 __ pushq(Address(src.AsX86_64().AsCpuRegister(), src_offset)); 453 __ popq(Address(dest.AsX86_64().AsCpuRegister(), dest_offset)); 454 } 455 456 void X86_64JNIMacroAssembler::Copy(FrameOffset dest, 457 Offset dest_offset, 458 FrameOffset src, 459 Offset src_offset, 460 ManagedRegister mscratch, 461 size_t size) { 462 CpuRegister scratch = mscratch.AsX86_64().AsCpuRegister(); 463 CHECK_EQ(size, 4u); 464 CHECK_EQ(dest.Int32Value(), src.Int32Value()); 465 __ movq(scratch, Address(CpuRegister(RSP), src)); 466 __ pushq(Address(scratch, src_offset)); 467 __ popq(Address(scratch, dest_offset)); 468 } 469 470 void X86_64JNIMacroAssembler::MemoryBarrier(ManagedRegister) { 471 __ mfence(); 472 } 473 474 void X86_64JNIMacroAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, 475 FrameOffset handle_scope_offset, 476 ManagedRegister min_reg, 477 bool null_allowed) { 478 X86_64ManagedRegister out_reg = mout_reg.AsX86_64(); 479 X86_64ManagedRegister in_reg = min_reg.AsX86_64(); 480 if (in_reg.IsNoRegister()) { // TODO(64): && null_allowed 481 // Use out_reg as indicator of null. 482 in_reg = out_reg; 483 // TODO: movzwl 484 __ movl(in_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset)); 485 } 486 CHECK(in_reg.IsCpuRegister()); 487 CHECK(out_reg.IsCpuRegister()); 488 VerifyObject(in_reg, null_allowed); 489 if (null_allowed) { 490 Label null_arg; 491 if (!out_reg.Equals(in_reg)) { 492 __ xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister()); 493 } 494 __ testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister()); 495 __ j(kZero, &null_arg); 496 __ leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset)); 497 __ Bind(&null_arg); 498 } else { 499 __ leaq(out_reg.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset)); 500 } 501 } 502 503 void X86_64JNIMacroAssembler::CreateHandleScopeEntry(FrameOffset out_off, 504 FrameOffset handle_scope_offset, 505 ManagedRegister mscratch, 506 bool null_allowed) { 507 X86_64ManagedRegister scratch = mscratch.AsX86_64(); 508 CHECK(scratch.IsCpuRegister()); 509 if (null_allowed) { 510 Label null_arg; 511 __ movl(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset)); 512 __ testl(scratch.AsCpuRegister(), scratch.AsCpuRegister()); 513 __ j(kZero, &null_arg); 514 __ leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset)); 515 __ Bind(&null_arg); 516 } else { 517 __ leaq(scratch.AsCpuRegister(), Address(CpuRegister(RSP), handle_scope_offset)); 518 } 519 Store(out_off, scratch, 8); 520 } 521 522 // Given a handle scope entry, load the associated reference. 523 void X86_64JNIMacroAssembler::LoadReferenceFromHandleScope(ManagedRegister mout_reg, 524 ManagedRegister min_reg) { 525 X86_64ManagedRegister out_reg = mout_reg.AsX86_64(); 526 X86_64ManagedRegister in_reg = min_reg.AsX86_64(); 527 CHECK(out_reg.IsCpuRegister()); 528 CHECK(in_reg.IsCpuRegister()); 529 Label null_arg; 530 if (!out_reg.Equals(in_reg)) { 531 __ xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister()); 532 } 533 __ testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister()); 534 __ j(kZero, &null_arg); 535 __ movq(out_reg.AsCpuRegister(), Address(in_reg.AsCpuRegister(), 0)); 536 __ Bind(&null_arg); 537 } 538 539 void X86_64JNIMacroAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) { 540 // TODO: not validating references 541 } 542 543 void X86_64JNIMacroAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) { 544 // TODO: not validating references 545 } 546 547 void X86_64JNIMacroAssembler::Call(ManagedRegister mbase, Offset offset, ManagedRegister) { 548 X86_64ManagedRegister base = mbase.AsX86_64(); 549 CHECK(base.IsCpuRegister()); 550 __ call(Address(base.AsCpuRegister(), offset.Int32Value())); 551 // TODO: place reference map on call 552 } 553 554 void X86_64JNIMacroAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) { 555 CpuRegister scratch = mscratch.AsX86_64().AsCpuRegister(); 556 __ movq(scratch, Address(CpuRegister(RSP), base)); 557 __ call(Address(scratch, offset)); 558 } 559 560 void X86_64JNIMacroAssembler::CallFromThread(ThreadOffset64 offset, ManagedRegister /*mscratch*/) { 561 __ gs()->call(Address::Absolute(offset, true)); 562 } 563 564 void X86_64JNIMacroAssembler::GetCurrentThread(ManagedRegister tr) { 565 __ gs()->movq(tr.AsX86_64().AsCpuRegister(), 566 Address::Absolute(Thread::SelfOffset<kX86_64PointerSize>(), true)); 567 } 568 569 void X86_64JNIMacroAssembler::GetCurrentThread(FrameOffset offset, ManagedRegister mscratch) { 570 X86_64ManagedRegister scratch = mscratch.AsX86_64(); 571 __ gs()->movq(scratch.AsCpuRegister(), 572 Address::Absolute(Thread::SelfOffset<kX86_64PointerSize>(), true)); 573 __ movq(Address(CpuRegister(RSP), offset), scratch.AsCpuRegister()); 574 } 575 576 // Slowpath entered when Thread::Current()->_exception is non-null 577 class X86_64ExceptionSlowPath FINAL : public SlowPath { 578 public: 579 explicit X86_64ExceptionSlowPath(size_t stack_adjust) : stack_adjust_(stack_adjust) {} 580 virtual void Emit(Assembler *sp_asm) OVERRIDE; 581 private: 582 const size_t stack_adjust_; 583 }; 584 585 void X86_64JNIMacroAssembler::ExceptionPoll(ManagedRegister /*scratch*/, size_t stack_adjust) { 586 X86_64ExceptionSlowPath* slow = new (__ GetArena()) X86_64ExceptionSlowPath(stack_adjust); 587 __ GetBuffer()->EnqueueSlowPath(slow); 588 __ gs()->cmpl(Address::Absolute(Thread::ExceptionOffset<kX86_64PointerSize>(), true), Immediate(0)); 589 __ j(kNotEqual, slow->Entry()); 590 } 591 592 std::unique_ptr<JNIMacroLabel> X86_64JNIMacroAssembler::CreateLabel() { 593 return std::unique_ptr<JNIMacroLabel>(new X86_64JNIMacroLabel()); 594 } 595 596 void X86_64JNIMacroAssembler::Jump(JNIMacroLabel* label) { 597 CHECK(label != nullptr); 598 __ jmp(X86_64JNIMacroLabel::Cast(label)->AsX86_64()); 599 } 600 601 void X86_64JNIMacroAssembler::Jump(JNIMacroLabel* label, 602 JNIMacroUnaryCondition condition, 603 ManagedRegister test) { 604 CHECK(label != nullptr); 605 606 art::x86_64::Condition x86_64_cond; 607 switch (condition) { 608 case JNIMacroUnaryCondition::kZero: 609 x86_64_cond = art::x86_64::kZero; 610 break; 611 case JNIMacroUnaryCondition::kNotZero: 612 x86_64_cond = art::x86_64::kNotZero; 613 break; 614 default: 615 LOG(FATAL) << "Not implemented condition: " << static_cast<int>(condition); 616 UNREACHABLE(); 617 } 618 619 // TEST reg, reg 620 // Jcc <Offset> 621 __ testq(test.AsX86_64().AsCpuRegister(), test.AsX86_64().AsCpuRegister()); 622 __ j(x86_64_cond, X86_64JNIMacroLabel::Cast(label)->AsX86_64()); 623 } 624 625 void X86_64JNIMacroAssembler::Bind(JNIMacroLabel* label) { 626 CHECK(label != nullptr); 627 __ Bind(X86_64JNIMacroLabel::Cast(label)->AsX86_64()); 628 } 629 630 #undef __ 631 632 void X86_64ExceptionSlowPath::Emit(Assembler *sasm) { 633 X86_64Assembler* sp_asm = down_cast<X86_64Assembler*>(sasm); 634 #define __ sp_asm-> 635 __ Bind(&entry_); 636 // Note: the return value is dead 637 if (stack_adjust_ != 0) { // Fix up the frame. 638 DecreaseFrameSizeImpl(stack_adjust_, sp_asm); 639 } 640 // Pass exception as argument in RDI 641 __ gs()->movq(CpuRegister(RDI), 642 Address::Absolute(Thread::ExceptionOffset<kX86_64PointerSize>(), true)); 643 __ gs()->call( 644 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64PointerSize, pDeliverException), true)); 645 // this call should never return 646 __ int3(); 647 #undef __ 648 } 649 650 } // namespace x86_64 651 } // namespace art 652