context_x86_64.cc revision 8194963098247be6bca9cc4a54dbfa65c73e8ccc
1/* 2 * Copyright (C) 2011 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 "context_x86_64.h" 18 19#include "mirror/art_method.h" 20#include "mirror/object-inl.h" 21#include "stack.h" 22 23namespace art { 24namespace x86_64 { 25 26static const uintptr_t gZero = 0; 27 28void X86_64Context::Reset() { 29 for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { 30 gprs_[i] = nullptr; 31 } 32 for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { 33 fprs_[i] = nullptr; 34 } 35 gprs_[RSP] = &rsp_; 36 // Initialize registers with easy to spot debug values. 37 rsp_ = X86_64Context::kBadGprBase + RSP; 38 rip_ = X86_64Context::kBadGprBase + kNumberOfCpuRegisters; 39} 40 41void X86_64Context::FillCalleeSaves(const StackVisitor& fr) { 42 mirror::ArtMethod* method = fr.GetMethod(); 43 uint32_t core_spills = method->GetCoreSpillMask(); 44 uint32_t fp_core_spills = method->GetFpSpillMask(); 45 size_t spill_count = POPCOUNT(core_spills); 46 size_t fp_spill_count = POPCOUNT(fp_core_spills); 47 size_t frame_size = method->GetFrameSizeInBytes(); 48 if (spill_count > 0) { 49 // Lowest number spill is farthest away, walk registers and fill into context. 50 size_t j = 2; // Offset j to skip return address spill. 51 for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { 52 if (((core_spills >> i) & 1) != 0) { 53 gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_size); 54 j++; 55 } 56 } 57 } 58 if (fp_spill_count > 0) { 59 // Lowest number spill is farthest away, walk registers and fill into context. 60 size_t j = 2; // Offset j to skip return address spill. 61 for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { 62 if (((fp_core_spills >> i) & 1) != 0) { 63 fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_size); 64 j++; 65 } 66 } 67 } 68} 69 70void X86_64Context::SmashCallerSaves() { 71 // This needs to be 0 because we want a null/zero return value. 72 gprs_[RAX] = const_cast<uintptr_t*>(&gZero); 73 gprs_[RDX] = const_cast<uintptr_t*>(&gZero); 74 gprs_[RCX] = nullptr; 75 gprs_[RSI] = nullptr; 76 gprs_[RDI] = nullptr; 77 gprs_[R8] = nullptr; 78 gprs_[R9] = nullptr; 79 gprs_[R10] = nullptr; 80 gprs_[R11] = nullptr; 81} 82 83void X86_64Context::SetGPR(uint32_t reg, uintptr_t value) { 84 CHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters)); 85 CHECK_NE(gprs_[reg], &gZero); 86 CHECK(gprs_[reg] != NULL); 87 *gprs_[reg] = value; 88} 89 90void X86_64Context::DoLongJump() { 91#if defined(__x86_64__) 92 // Array of GPR values, filled from the context backward for the long jump pop. We add a slot at 93 // the top for the stack pointer that doesn't get popped in a pop-all. 94 volatile uintptr_t gprs[kNumberOfCpuRegisters + 1]; 95 for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { 96 gprs[kNumberOfCpuRegisters - i - 1] = gprs_[i] != NULL ? *gprs_[i] : X86_64Context::kBadGprBase + i; 97 } 98 // We want to load the stack pointer one slot below so that the ret will pop eip. 99 uintptr_t rsp = gprs[kNumberOfCpuRegisters - RSP - 1] - kWordSize; 100 gprs[kNumberOfCpuRegisters] = rsp; 101 *(reinterpret_cast<uintptr_t*>(rsp)) = rip_; 102 __asm__ __volatile__( 103 "movq %0, %%rsp\n\t" // RSP points to gprs. 104 "popq %%r15\n\t" // Load all registers except RSP and RIP with values in gprs. 105 "popq %%r14\n\t" 106 "popq %%r13\n\t" 107 "popq %%r12\n\t" 108 "popq %%r11\n\t" 109 "popq %%r10\n\t" 110 "popq %%r9\n\t" 111 "popq %%r8\n\t" 112 "popq %%rdi\n\t" 113 "popq %%rsi\n\t" 114 "popq %%rbp\n\t" 115 "addq $8, %%rsp\n\t" 116 "popq %%rbx\n\t" 117 "popq %%rdx\n\t" 118 "popq %%rcx\n\t" 119 "popq %%rax\n\t" 120 "popq %%rsp\n\t" // Load stack pointer. 121 "ret\n\t" // From higher in the stack pop rip. 122 : // output. 123 : "g"(&gprs[0]) // input. 124 :); // clobber. 125#else 126 UNIMPLEMENTED(FATAL); 127#endif 128} 129 130} // namespace x86_64 131} // namespace art 132