12faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes/*
22faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Copyright (C) 2011 The Android Open Source Project
32faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
42faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
52faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * you may not use this file except in compliance with the License.
62faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * You may obtain a copy of the License at
72faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
82faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
92faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes *
102faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * Unless required by applicable law or agreed to in writing, software
112faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
122faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * See the License for the specific language governing permissions and
142faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes * limitations under the License.
152faa5f1271587cda765f26bcf2951065300a01ffElliott Hughes */
16bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
17bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers#include "context_x86.h"
18bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
1980afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko#include "base/bit_utils.h"
207624d25dad2d1ba25969ae704fccf68649103ae5Vladimir Marko#include "quick/quick_method_frame_info.h"
2185d1545e985ac689db4bad7849880e843707c862Elliott Hughes
22bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogersnamespace art {
23bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogersnamespace x86 {
24bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
250bcb2902ec21393d71c94e63aa6733cb5311a0ccSebastien Hertzstatic constexpr uintptr_t gZero = 0;
266702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier
276702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartiervoid X86Context::Reset() {
2880afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  std::fill_n(gprs_, arraysize(gprs_), nullptr);
2980afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  std::fill_n(fprs_, arraysize(fprs_), nullptr);
306702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  gprs_[ESP] = &esp_;
31639bdd13993644a267f177f8f5936496bda65e2bAndreas Gampe  gprs_[EAX] = &arg0_;
326702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  // Initialize registers with easy to spot debug values.
336702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  esp_ = X86Context::kBadGprBase + ESP;
346702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  eip_ = X86Context::kBadGprBase + kNumberOfCpuRegisters;
35639bdd13993644a267f177f8f5936496bda65e2bAndreas Gampe  arg0_ = 0;
3667375acd9fec74cc2054554fe1ed0a7d213e1e47Ian Rogers}
3767375acd9fec74cc2054554fe1ed0a7d213e1e47Ian Rogers
38524e7ea8cd17bad17bd9f3e0ccbb19ad0d4d9c02Nicolas Geoffrayvoid X86Context::FillCalleeSaves(uint8_t* frame, const QuickMethodFrameInfo& frame_info) {
3980afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  int spill_pos = 0;
4080afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko
4180afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  // Core registers come first, from the highest down to the lowest.
4280afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  uint32_t core_regs =
4380afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko      frame_info.CoreSpillMask() & ~(static_cast<uint32_t>(-1) << kNumberOfCpuRegisters);
4480afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  DCHECK_EQ(1, POPCOUNT(frame_info.CoreSpillMask() & ~core_regs));  // Return address spill.
4580afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  for (uint32_t core_reg : HighToLowBits(core_regs)) {
46524e7ea8cd17bad17bd9f3e0ccbb19ad0d4d9c02Nicolas Geoffray    gprs_[core_reg] = CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes());
4780afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko    ++spill_pos;
4867375acd9fec74cc2054554fe1ed0a7d213e1e47Ian Rogers  }
4980afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) - 1);
5080afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko
5180afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  // FP registers come second, from the highest down to the lowest.
5280afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  uint32_t fp_regs = frame_info.FpSpillMask();
5380afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  DCHECK_EQ(0u, fp_regs & (static_cast<uint32_t>(-1) << kNumberOfFloatRegisters));
5480afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  for (uint32_t fp_reg : HighToLowBits(fp_regs)) {
5580afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko    // Two void* per XMM register.
560eb42511405f3919572a480a009426dfb776cfb5Vladimir Marko    fprs_[2 * fp_reg] = reinterpret_cast<uint32_t*>(
57524e7ea8cd17bad17bd9f3e0ccbb19ad0d4d9c02Nicolas Geoffray        CalleeSaveAddress(frame, spill_pos + 1, frame_info.FrameSizeInBytes()));
580eb42511405f3919572a480a009426dfb776cfb5Vladimir Marko    fprs_[2 * fp_reg + 1] = reinterpret_cast<uint32_t*>(
59524e7ea8cd17bad17bd9f3e0ccbb19ad0d4d9c02Nicolas Geoffray        CalleeSaveAddress(frame, spill_pos, frame_info.FrameSizeInBytes()));
6080afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko    spill_pos += 2;
61966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  }
6280afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko  DCHECK_EQ(spill_pos,
6380afd02024d20e60b197d3adfbb43cc303cf29e0Vladimir Marko            POPCOUNT(frame_info.CoreSpillMask()) - 1 + 2 * POPCOUNT(frame_info.FpSpillMask()));
6467375acd9fec74cc2054554fe1ed0a7d213e1e47Ian Rogers}
6567375acd9fec74cc2054554fe1ed0a7d213e1e47Ian Rogers
669c750f9b6283f62b3e6a93c0c6b2838abde5000eElliott Hughesvoid X86Context::SmashCallerSaves() {
676702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  // This needs to be 0 because we want a null/zero return value.
68ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  gprs_[EAX] = const_cast<uintptr_t*>(&gZero);
69ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  gprs_[EDX] = const_cast<uintptr_t*>(&gZero);
700bcb2902ec21393d71c94e63aa6733cb5311a0ccSebastien Hertz  gprs_[ECX] = nullptr;
710bcb2902ec21393d71c94e63aa6733cb5311a0ccSebastien Hertz  gprs_[EBX] = nullptr;
72966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  memset(&fprs_[0], '\0', sizeof(fprs_));
736702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier}
746702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier
7596ba8dc82e7bd859106af837623fe8b2e9e772c3Sebastien Hertzvoid X86Context::SetGPR(uint32_t reg, uintptr_t value) {
766f675178900a8a20d6c8c74a4a251a49247c706bBrian Carlstrom  CHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters));
7796ba8dc82e7bd859106af837623fe8b2e9e772c3Sebastien Hertz  DCHECK(IsAccessibleGPR(reg));
786702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  CHECK_NE(gprs_[reg], &gZero);
7996ba8dc82e7bd859106af837623fe8b2e9e772c3Sebastien Hertz  *gprs_[reg] = value;
809c750f9b6283f62b3e6a93c0c6b2838abde5000eElliott Hughes}
819c750f9b6283f62b3e6a93c0c6b2838abde5000eElliott Hughes
82966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendellvoid X86Context::SetFPR(uint32_t reg, uintptr_t value) {
83966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  CHECK_LT(reg, static_cast<uint32_t>(kNumberOfFloatRegisters));
84966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  DCHECK(IsAccessibleFPR(reg));
85966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  CHECK_NE(fprs_[reg], reinterpret_cast<const uint32_t*>(&gZero));
86966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  *fprs_[reg] = value;
876a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers}
886a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers
89bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogersvoid X86Context::DoLongJump() {
9085d1545e985ac689db4bad7849880e843707c862Elliott Hughes#if defined(__i386__)
916702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  // Array of GPR values, filled from the context backward for the long jump pop. We add a slot at
926702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  // the top for the stack pointer that doesn't get popped in a pop-all.
936702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  volatile uintptr_t gprs[kNumberOfCpuRegisters + 1];
946702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) {
950bcb2902ec21393d71c94e63aa6733cb5311a0ccSebastien Hertz    gprs[kNumberOfCpuRegisters - i - 1] = gprs_[i] != nullptr ? *gprs_[i] : X86Context::kBadGprBase + i;
966702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  }
97966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  uint32_t fprs[kNumberOfFloatRegisters];
98966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) {
99966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell    fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : X86Context::kBadFprBase + i;
100966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell  }
1016702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  // We want to load the stack pointer one slot below so that the ret will pop eip.
10213735955f39b3b304c37d2b2840663c131262c18Ian Rogers  uintptr_t esp = gprs[kNumberOfCpuRegisters - ESP - 1] - sizeof(intptr_t);
1036702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  gprs[kNumberOfCpuRegisters] = esp;
1046702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier  *(reinterpret_cast<uintptr_t*>(esp)) = eip_;
1057834cbd5d8a0e61db14339910d2223a3e59d7efcElliott Hughes  __asm__ __volatile__(
106966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movl %1, %%ebx\n\t"          // Address base of FPRs.
107966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 0(%%ebx), %%xmm0\n\t"  // Load up XMM0-XMM7.
108966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 8(%%ebx), %%xmm1\n\t"
109966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 16(%%ebx), %%xmm2\n\t"
110966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 24(%%ebx), %%xmm3\n\t"
111966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 32(%%ebx), %%xmm4\n\t"
112966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 40(%%ebx), %%xmm5\n\t"
113966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 48(%%ebx), %%xmm6\n\t"
114966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      "movsd 56(%%ebx), %%xmm7\n\t"
1156702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier      "movl %0, %%esp\n\t"  // ESP points to gprs.
1166702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier      "popal\n\t"           // Load all registers except ESP and EIP with values in gprs.
1176702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier      "popl %%esp\n\t"      // Load stack pointer.
1186702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier      "ret\n\t"             // From higher in the stack pop eip.
1196702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier      :  // output.
120966c3ae95d3c699ee9fbdbccc1acdaaf02325fafMark P Mendell      : "g"(&gprs[0]), "g"(&fprs[0]) // input.
1216702243ea2332b566d8e8b871cc9db0906d835adMathieu Chartier      :);  // clobber.
12285d1545e985ac689db4bad7849880e843707c862Elliott Hughes#else
123ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogers  UNIMPLEMENTED(FATAL);
12485d1545e985ac689db4bad7849880e843707c862Elliott Hughes#endif
125794ad76e8d5b5b9132819d5b08a0570e27615644Andreas Gampe  UNREACHABLE();
126bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers}
127bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers
128bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers}  // namespace x86
129bdb0391258abc54bf77c676e36847d28a783bfe5Ian Rogers}  // namespace art
130