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