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-inl.h" 20 #include "mirror/object-inl.h" 21 #include "quick/quick_method_frame_info.h" 22 #include "stack.h" 23 24 namespace art { 25 namespace x86_64 { 26 27 static constexpr uintptr_t gZero = 0; 28 29 void X86_64Context::Reset() { 30 for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { 31 gprs_[i] = nullptr; 32 } 33 for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { 34 fprs_[i] = nullptr; 35 } 36 gprs_[RSP] = &rsp_; 37 // Initialize registers with easy to spot debug values. 38 rsp_ = X86_64Context::kBadGprBase + RSP; 39 rip_ = X86_64Context::kBadGprBase + kNumberOfCpuRegisters; 40 } 41 42 void X86_64Context::FillCalleeSaves(const StackVisitor& fr) { 43 mirror::ArtMethod* method = fr.GetMethod(); 44 const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); 45 size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); 46 size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); 47 if (spill_count > 0) { 48 // Lowest number spill is farthest away, walk registers and fill into context. 49 size_t j = 2; // Offset j to skip return address spill. 50 for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { 51 if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { 52 gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); 53 j++; 54 } 55 } 56 } 57 if (fp_spill_count > 0) { 58 // Lowest number spill is farthest away, walk registers and fill into context. 59 size_t j = 2; // Offset j to skip return address spill. 60 for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { 61 if (((frame_info.FpSpillMask() >> i) & 1) != 0) { 62 fprs_[i] = reinterpret_cast<uint64_t*>( 63 fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_info.FrameSizeInBytes())); 64 j++; 65 } 66 } 67 } 68 } 69 70 void 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 fprs_[XMM0] = nullptr; 82 fprs_[XMM1] = nullptr; 83 fprs_[XMM2] = nullptr; 84 fprs_[XMM3] = nullptr; 85 fprs_[XMM4] = nullptr; 86 fprs_[XMM5] = nullptr; 87 fprs_[XMM6] = nullptr; 88 fprs_[XMM7] = nullptr; 89 fprs_[XMM8] = nullptr; 90 fprs_[XMM9] = nullptr; 91 fprs_[XMM10] = nullptr; 92 fprs_[XMM11] = nullptr; 93 } 94 95 bool X86_64Context::SetGPR(uint32_t reg, uintptr_t value) { 96 CHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters)); 97 CHECK_NE(gprs_[reg], &gZero); 98 if (gprs_[reg] != nullptr) { 99 *gprs_[reg] = value; 100 return true; 101 } else { 102 return false; 103 } 104 } 105 106 bool X86_64Context::SetFPR(uint32_t reg, uintptr_t value) { 107 CHECK_LT(reg, static_cast<uint32_t>(kNumberOfFloatRegisters)); 108 CHECK_NE(fprs_[reg], reinterpret_cast<const uint64_t*>(&gZero)); 109 if (fprs_[reg] != nullptr) { 110 *fprs_[reg] = value; 111 return true; 112 } else { 113 return false; 114 } 115 } 116 117 extern "C" void art_quick_do_long_jump(uintptr_t*, uintptr_t*); 118 119 void X86_64Context::DoLongJump() { 120 #if defined(__x86_64__) 121 uintptr_t gprs[kNumberOfCpuRegisters + 1]; 122 uintptr_t fprs[kNumberOfFloatRegisters]; 123 124 for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { 125 gprs[kNumberOfCpuRegisters - i - 1] = gprs_[i] != nullptr ? *gprs_[i] : X86_64Context::kBadGprBase + i; 126 } 127 for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { 128 fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : X86_64Context::kBadFprBase + i; 129 } 130 131 // We want to load the stack pointer one slot below so that the ret will pop eip. 132 uintptr_t rsp = gprs[kNumberOfCpuRegisters - RSP - 1] - kWordSize; 133 gprs[kNumberOfCpuRegisters] = rsp; 134 *(reinterpret_cast<uintptr_t*>(rsp)) = rip_; 135 136 art_quick_do_long_jump(gprs, fprs); 137 #else 138 UNIMPLEMENTED(FATAL); 139 #endif 140 } 141 142 } // namespace x86_64 143 } // namespace art 144