call_x86.cc revision 72f53af0307b9109a1cfc0671675ce5d45c66d3a
1efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/*
2efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Copyright (C) 2012 The Android Open Source Project
3efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *
4efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Licensed under the Apache License, Version 2.0 (the "License");
5efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * you may not use this file except in compliance with the License.
6efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * You may obtain a copy of the License at
7efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *
8efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *      http://www.apache.org/licenses/LICENSE-2.0
9efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *
10efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Unless required by applicable law or agreed to in writing, software
11efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * distributed under the License is distributed on an "AS IS" BASIS,
12efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * See the License for the specific language governing permissions and
14efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * limitations under the License.
15efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */
16efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
17efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* This file contains codegen for the X86 ISA */
18efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
1902031b185b4653e6c72e21f7a51238b903f6d638buzbee#include "codegen_x86.h"
200b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe
210b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "base/logging.h"
227940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom#include "dex/quick/mir_to_lir-inl.h"
230b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "driver/compiler_driver.h"
24576ca0cd692c0b6ae70e776de91015b8ff000a08Ian Rogers#include "gc/accounting/card_table.h"
25f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko#include "mirror/art_method.h"
26f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko#include "mirror/object_array-inl.h"
27641ce0371c2f0dc95d26be02d8366124c8b66653Brian Carlstrom#include "x86_lir.h"
281bc37c60da71c923ea9a2e99d31ba1b3d76d79a8buzbee
29efc6369224b036a1fb77849f7ae65b3492c832c0buzbeenamespace art {
30efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
31efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/*
32efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * The sparse table in the literal pool is an array of <key,displacement>
33efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * pairs.
34efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */
3548971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid X86Mir2Lir::GenLargeSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
36da96aeda912ff317de2c41e5a49bd244427238acChao-ying Fu  GenSmallSparseSwitch(mir, table_offset, rl_src);
37da96aeda912ff317de2c41e5a49bd244427238acChao-ying Fu}
38da96aeda912ff317de2c41e5a49bd244427238acChao-ying Fu
39da96aeda912ff317de2c41e5a49bd244427238acChao-ying Fu/*
40efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Code pattern will look something like:
41efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *
42fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov  r_val, ..
43efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * call 0
44fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * pop  r_start_of_method
45fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * sub  r_start_of_method, ..
46fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov  r_key_reg, r_val
47fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * sub  r_key_reg, low_key
48fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * cmp  r_key_reg, size-1  ; bound check
49efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * ja   done
50fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov  r_disp, [r_start_of_method + r_key_reg * 4 + table_offset]
51fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * add  r_start_of_method, r_disp
52fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * jmp  r_start_of_method
53efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * done:
54efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */
5548971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid X86Mir2Lir::GenLargePackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
5672f53af0307b9109a1cfc0671675ce5d45c66d3aChao-ying Fu  const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
57efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Add the table to the list - we'll process it later
580d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee  SwitchTable* tab_rec =
5983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko      static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData));
6072f53af0307b9109a1cfc0671675ce5d45c66d3aChao-ying Fu  tab_rec->switch_mir = mir;
61fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  tab_rec->table = table;
621fd3346740dfb7f47be9922312b68a4227fada96buzbee  tab_rec->vaddr = current_dalvik_offset_;
63efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  int size = table[1];
64e39c54ea575ec710d5e84277fcdcc049f8acb3c9Vladimir Marko  switch_tables_.push_back(tab_rec);
65efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
66efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Get the switch value
671fd3346740dfb7f47be9922312b68a4227fada96buzbee  rl_src = LoadValue(rl_src, kCoreReg);
6827dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell
69fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  int low_key = s4FromSwitchData(&table[2]);
702700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee  RegStorage keyReg;
71efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Remove the bias, if necessary
72fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  if (low_key == 0) {
732700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee    keyReg = rl_src.reg;
74efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  } else {
751fd3346740dfb7f47be9922312b68a4227fada96buzbee    keyReg = AllocTemp();
762700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee    OpRegRegImm(kOpSub, keyReg, rl_src.reg, low_key);
77efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  }
7827dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell
79efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Bounds check - if < 0 or >= size continue following switch
80407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  OpRegImm(kOpCmp, keyReg, size - 1);
811fd3346740dfb7f47be9922312b68a4227fada96buzbee  LIR* branch_over = OpCondBranch(kCondHi, NULL);
82efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
8327dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell  RegStorage addr_for_jump;
8427dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell  if (cu_->target64) {
8527dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    RegStorage table_base = AllocTempWide();
8627dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    // Load the address of the table into table_base.
8727dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    LIR* lea = RawLIR(current_dalvik_offset_, kX86Lea64RM, table_base.GetReg(), kRIPReg,
8827dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell                      256, 0, WrapPointer(tab_rec));
8927dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    lea->flags.fixup = kFixupSwitchTable;
9027dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    AppendLIR(lea);
9127dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell
9227dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    // Load the offset from the table out of the table.
9327dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    addr_for_jump = AllocTempWide();
9427dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    NewLIR5(kX86MovsxdRA, addr_for_jump.GetReg(), table_base.GetReg(), keyReg.GetReg(), 2, 0);
9527dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell
9627dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    // Add the offset from the table to the table base.
9727dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    OpRegReg(kOpAdd, addr_for_jump, table_base);
9827dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell  } else {
9927dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    // Materialize a pointer to the switch table.
10027dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    RegStorage start_of_method_reg;
10127dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    if (base_of_code_ != nullptr) {
10227dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell      // We can use the saved value.
10327dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell      RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
10427dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell      rl_method = LoadValue(rl_method, kCoreReg);
10527dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell      start_of_method_reg = rl_method.reg;
10627dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell      store_method_addr_used_ = true;
10727dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    } else {
10827dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell      start_of_method_reg = AllocTempRef();
10927dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell      NewLIR1(kX86StartOfMethod, start_of_method_reg.GetReg());
11027dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    }
11127dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    // Load the displacement from the switch table.
11227dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    addr_for_jump = AllocTemp();
11327dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    NewLIR5(kX86PcRelLoadRA, addr_for_jump.GetReg(), start_of_method_reg.GetReg(), keyReg.GetReg(),
11427dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell            2, WrapPointer(tab_rec));
11527dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    // Add displacement to start of method.
11627dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell    OpRegReg(kOpAdd, addr_for_jump, start_of_method_reg);
11727dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell  }
11827dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell
119efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // ..and go!
12027dee8bcd7b4a53840b60818da8d2c819ef199bdMark Mendell  tab_rec->anchor = NewLIR1(kX86JmpR, addr_for_jump.GetReg());
121efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
122fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  /* branch_over target here */
1231fd3346740dfb7f47be9922312b68a4227fada96buzbee  LIR* target = NewLIR0(kPseudoTargetLabel);
124fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  branch_over->target = target;
125efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
126efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
1272ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid X86Mir2Lir::GenMoveException(RegLocation rl_dest) {
12833ae5583bdd69847a7316ab38a8fa8ccd63093efbuzbee  int ex_offset = cu_->target64 ?
1292f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::ExceptionOffset<8>().Int32Value() :
1302f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::ExceptionOffset<4>().Int32Value();
131a0cd2d701f29e0bc6275f1b13c0edfd4ec391879buzbee  RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
132407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  NewLIR2(cu_->target64 ? kX86Mov64RT : kX86Mov32RT, rl_result.reg.GetReg(), ex_offset);
133407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  NewLIR2(cu_->target64 ? kX86Mov64TI : kX86Mov32TI, ex_offset, 0);
1341fd3346740dfb7f47be9922312b68a4227fada96buzbee  StoreValue(rl_dest, rl_result);
1351eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao}
1361eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao
137bf535be514570fc33fc0a6347a87dcd9097d9bfdVladimir Markovoid X86Mir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) {
138407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  DCHECK_EQ(tgt_addr_reg.Is64Bit(), cu_->target64);
139407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  RegStorage reg_card_base = AllocTempRef();
140407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  RegStorage reg_card_no = AllocTempRef();
14133ae5583bdd69847a7316ab38a8fa8ccd63093efbuzbee  int ct_offset = cu_->target64 ?
1422f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::CardTableOffset<8>().Int32Value() :
1432f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::CardTableOffset<4>().Int32Value();
144407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  NewLIR2(cu_->target64 ? kX86Mov64RT : kX86Mov32RT, reg_card_base.GetReg(), ct_offset);
1451d54e73444e017d3a65234e0f193846f3e27472bIan Rogers  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
1462700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee  StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
1471fd3346740dfb7f47be9922312b68a4227fada96buzbee  FreeTemp(reg_card_base);
1481fd3346740dfb7f47be9922312b68a4227fada96buzbee  FreeTemp(reg_card_no);
149efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
150efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
1512ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
152efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /*
153efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * On entry, rX86_ARG0, rX86_ARG1, rX86_ARG2 are live.  Let the register
154efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * allocation mechanism know so it doesn't try to use any of them when
155efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * expanding the frame or flushing.  This leaves the utility
156efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * code with no spare temps.
157efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   */
158b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  const RegStorage arg0 = TargetReg32(kArg0);
159b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  const RegStorage arg1 = TargetReg32(kArg1);
160b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  const RegStorage arg2 = TargetReg32(kArg2);
161b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  LockTemp(arg0);
162b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  LockTemp(arg1);
163b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  LockTemp(arg2);
164efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
165efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /*
166efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * We can safely skip the stack overflow check if we're
167efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * a leaf *and* our frame size < fudge factor.
168efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   */
169b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  const InstructionSet isa =  cu_->target64 ? kX86_64 : kX86;
170648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison  bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, isa);
171b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
17269dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
17369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // If we doing an implicit stack overflow check, perform the load immediately
17469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // before the stack pointer is decremented and anything is saved.
17569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  if (!skip_overflow_check &&
17669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
17769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    // Implicit stack overflow check.
17869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    // test eax,[esp + -overflow]
17969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    int overflow = GetStackOverflowReservedBytes(isa);
180b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers    NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rSP.GetReg(), -overflow);
18169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    MarkPossibleStackOverflowException();
18269dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  }
18369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
18469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  /* Build frame, return address already on stack */
185b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  stack_decrement_ = OpRegImm(kOpSub, rs_rSP, frame_size_ -
18669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison                              GetInstructionSetPointerSize(cu_->instruction_set));
18769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
1881fd3346740dfb7f47be9922312b68a4227fada96buzbee  NewLIR0(kPseudoMethodEntry);
189efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /* Spill core callee saves */
1901fd3346740dfb7f47be9922312b68a4227fada96buzbee  SpillCoreRegs();
191c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkov  SpillFPRegs();
192fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  if (!skip_overflow_check) {
1930d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier    class StackOverflowSlowPath : public LIRSlowPath {
1940d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier     public:
1950d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace)
1960d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier          : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, nullptr), sp_displace_(sp_displace) {
1970d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      }
1980d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      void Compile() OVERRIDE {
1990d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        m2l_->ResetRegPool();
2000d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        m2l_->ResetDefTracking();
2016ffcfa04ebb2660e238742a6000f5ccebdd5df15Mingyao Yang        GenerateTargetLabel(kPseudoThrowTarget);
202b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers        const RegStorage local_rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
203b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers        m2l_->OpRegImm(kOpAdd, local_rs_rSP, sp_displace_);
2040d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        m2l_->ClobberCallerSave();
2050d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        // Assumes codegen and target are in thumb2 mode.
206984305917bf57b3f8d92965e4715a0370cc5bcfbAndreas Gampe        m2l_->CallHelper(RegStorage::InvalidReg(), kQuickThrowStackOverflow,
207984305917bf57b3f8d92965e4715a0370cc5bcfbAndreas Gampe                         false /* MarkSafepointPC */, false /* UseLink */);
2080d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      }
2090d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier
2100d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier     private:
2110d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      const size_t sp_displace_;
2120d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier    };
21369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
21469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // TODO: for large frames we should do something like:
21569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // spill ebp
21669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // lea ebp, [esp + frame_size]
21769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // cmp ebp, fs:[stack_end_]
21869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // jcc stack_overflow_exception
21969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // mov esp, ebp
22069dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // in case a signal comes in that's not using an alternate signal stack and the large frame
22169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // may have moved us outside of the reserved area at the end of the stack.
22269dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // cmp rs_rX86_SP, fs:[stack_end_]; jcc throw_slowpath
22369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      if (cu_->target64) {
224b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers        OpRegThreadMem(kOpCmp, rs_rX86_SP_64, Thread::StackEndOffset<8>());
22569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      } else {
226b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers        OpRegThreadMem(kOpCmp, rs_rX86_SP_32, Thread::StackEndOffset<4>());
22769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      }
22869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      LIR* branch = OpCondBranch(kCondUlt, nullptr);
22969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      AddSlowPath(
230e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu        new(arena_)StackOverflowSlowPath(this, branch,
231e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu                                         frame_size_ -
232e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu                                         GetInstructionSetPointerSize(cu_->instruction_set)));
23369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    }
234efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  }
235efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
2361fd3346740dfb7f47be9922312b68a4227fada96buzbee  FlushIns(ArgLocs, rl_method);
237efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
23867c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  if (base_of_code_ != nullptr) {
239a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu    RegStorage method_start = TargetPtrReg(kArg0);
24067c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    // We have been asked to save the address of the method start for later use.
241a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu    setup_method_address_[0] = NewLIR1(kX86StartOfMethod, method_start.GetReg());
24267c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    int displacement = SRegOffset(base_of_code_->s_reg_low);
243695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee    // Native pointer - must be natural word size.
244b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers    setup_method_address_[1] = StoreBaseDisp(rs_rSP, displacement, method_start,
245dd64450b37776f68b9bfc47f8d9a88bc72c95727Elena Sayapina                                             cu_->target64 ? k64 : k32, kNotVolatile);
24667c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  }
24767c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell
248b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  FreeTemp(arg0);
249b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  FreeTemp(arg1);
250b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  FreeTemp(arg2);
251efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
252efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
2531fd3346740dfb7f47be9922312b68a4227fada96buzbeevoid X86Mir2Lir::GenExitSequence() {
254efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /*
255efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * In the exit path, rX86_RET0/rX86_RET1 are live - make sure they aren't
256efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * allocated by the register utilities as temps.
257efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   */
258091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  LockTemp(rs_rX86_RET0);
259091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  LockTemp(rs_rX86_RET1);
260efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
2611fd3346740dfb7f47be9922312b68a4227fada96buzbee  NewLIR0(kPseudoMethodExit);
2621fd3346740dfb7f47be9922312b68a4227fada96buzbee  UnSpillCoreRegs();
263c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkov  UnSpillFPRegs();
264efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /* Remove frame except for return address */
265b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  const RegStorage rs_rSP = cu_->target64 ? rs_rX86_SP_64 : rs_rX86_SP_32;
266b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers  stack_increment_ = OpRegImm(kOpAdd, rs_rSP,
267b28c1c06236751aa5c9e64dcb68b3c940341e496Ian Rogers                              frame_size_ - GetInstructionSetPointerSize(cu_->instruction_set));
2681fd3346740dfb7f47be9922312b68a4227fada96buzbee  NewLIR0(kX86Ret);
269efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
270efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
2713bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoruvoid X86Mir2Lir::GenSpecialExitSequence() {
2723bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru  NewLIR0(kX86Ret);
2733bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru}
2743bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru
27569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allisonvoid X86Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) {
27669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
27769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    return;
27869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  }
27969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // Implicit null pointer check.
28069dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // test eax,[arg1+0]
28169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  NewLIR3(kX86Test32RM, rs_rAX.GetReg(), reg.GetReg(), 0);
28269dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  MarkPossibleNullPointerException(opt_flags);
28369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison}
28469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
285f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko/*
286f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko * Bit of a hack here - in the absence of a real scheduling pass,
287f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko * emit the next instruction in static & direct invoke sequences.
288f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko */
289f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Markostatic int X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
290f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                             int state, const MethodReference& target_method,
2916a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers                             uint32_t,
292f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                             uintptr_t direct_code, uintptr_t direct_method,
293f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                             InvokeType type) {
2946a3c1fcb4ba42ad4d5d142c17a3712a6ddd3866fIan Rogers  UNUSED(info, direct_code);
295f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
296f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko  if (direct_method != 0) {
297f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    switch (state) {
298f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    case 0:  // Get the current Method* [sets kArg0]
299f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      if (direct_method != static_cast<uintptr_t>(-1)) {
300f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko        cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method);
301f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      } else {
302f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko        cg->LoadMethodAddress(target_method, type, kArg0);
303f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      }
304f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      break;
305f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    default:
306f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      return -1;
307f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    }
308f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko  } else {
309f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
310f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    switch (state) {
311f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    case 0:  // Get the current Method* [sets kArg0]
312f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      // TUNING: we can save a reg copy if Method* has been promoted.
313f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      cg->LoadCurrMethodDirect(arg0_ref);
314f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      break;
315f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    case 1:  // Get method->dex_cache_resolved_methods_
316f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      cg->LoadRefDisp(arg0_ref,
317f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                      mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
318f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                      arg0_ref,
319f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                      kNotVolatile);
320f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      break;
321f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    case 2:  // Grab target method*
322f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      CHECK_EQ(cu->dex_file, target_method.dex_file);
323f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      cg->LoadRefDisp(arg0_ref,
324f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                      mirror::ObjectArray<mirror::Object>::OffsetOfElement(
325f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                          target_method.dex_method_index).Int32Value(),
326f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                      arg0_ref,
327f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko                      kNotVolatile);
328f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      break;
329f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    default:
330f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko      return -1;
331f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko    }
332f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko  }
333f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko  return state + 1;
334f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko}
335f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko
336f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir MarkoNextCallInsn X86Mir2Lir::GetNextSDCallInsn() {
337f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko  return X86NextSDCallInsn;
338f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko}
339f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko
340efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}  // namespace art
341