call_x86.cc revision 648d7112609dd19c38131b3e71c37bcbbd19d11e
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"
207940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom#include "dex/quick/mir_to_lir-inl.h"
21576ca0cd692c0b6ae70e776de91015b8ff000a08Ian Rogers#include "gc/accounting/card_table.h"
22641ce0371c2f0dc95d26be02d8366124c8b66653Brian Carlstrom#include "x86_lir.h"
231bc37c60da71c923ea9a2e99d31ba1b3d76d79a8buzbee
24efc6369224b036a1fb77849f7ae65b3492c832c0buzbeenamespace art {
25efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
26efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/*
27efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * The sparse table in the literal pool is an array of <key,displacement>
28efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * pairs.
29efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */
3048971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid X86Mir2Lir::GenLargeSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
311fd3346740dfb7f47be9922312b68a4227fada96buzbee  const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset;
321fd3346740dfb7f47be9922312b68a4227fada96buzbee  if (cu_->verbose) {
3352a77fc135f0e0df57ee24641c3f5ae415ff7bd6buzbee    DumpSparseSwitchTable(table);
34efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  }
35efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  int entries = table[1];
360d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee  const int32_t* keys = reinterpret_cast<const int32_t*>(&table[2]);
370d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee  const int32_t* targets = &keys[entries];
381fd3346740dfb7f47be9922312b68a4227fada96buzbee  rl_src = LoadValue(rl_src, kCoreReg);
39efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  for (int i = 0; i < entries; i++) {
40efc6369224b036a1fb77849f7ae65b3492c832c0buzbee    int key = keys[i];
41311ca169f4727d46a55bdc8dfa0059719fa72b65buzbee    BasicBlock* case_block =
421fd3346740dfb7f47be9922312b68a4227fada96buzbee        mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]);
432700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee    OpCmpImmBranch(kCondEq, rl_src.reg, key, &block_label_list_[case_block->id]);
44efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  }
45efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
46efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
47efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/*
48efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Code pattern will look something like:
49efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *
50fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov  r_val, ..
51efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * call 0
52fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * pop  r_start_of_method
53fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * sub  r_start_of_method, ..
54fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov  r_key_reg, r_val
55fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * sub  r_key_reg, low_key
56fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * cmp  r_key_reg, size-1  ; bound check
57efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * ja   done
58fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov  r_disp, [r_start_of_method + r_key_reg * 4 + table_offset]
59fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * add  r_start_of_method, r_disp
60fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * jmp  r_start_of_method
61efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * done:
62efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */
6348971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid X86Mir2Lir::GenLargePackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) {
641fd3346740dfb7f47be9922312b68a4227fada96buzbee  const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset;
651fd3346740dfb7f47be9922312b68a4227fada96buzbee  if (cu_->verbose) {
6652a77fc135f0e0df57ee24641c3f5ae415ff7bd6buzbee    DumpPackedSwitchTable(table);
67efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  }
68efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Add the table to the list - we'll process it later
690d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee  SwitchTable* tab_rec =
7083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko      static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData));
71fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  tab_rec->table = table;
721fd3346740dfb7f47be9922312b68a4227fada96buzbee  tab_rec->vaddr = current_dalvik_offset_;
73efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  int size = table[1];
74f6c4b3ba3825de1dbb3e747a68b809c6cc8eb4dbMathieu Chartier  tab_rec->targets = static_cast<LIR**>(arena_->Alloc(size * sizeof(LIR*),
7583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko                                                      kArenaAllocLIR));
76862a76027076c341c26aa6cd4a30a7cdd6dc2143buzbee  switch_tables_.Insert(tab_rec);
77efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
78efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Get the switch value
791fd3346740dfb7f47be9922312b68a4227fada96buzbee  rl_src = LoadValue(rl_src, kCoreReg);
807934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  // NewLIR0(kX86Bkpt);
8167c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell
8267c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  // Materialize a pointer to the switch table
832700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee  RegStorage start_of_method_reg;
8467c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  if (base_of_code_ != nullptr) {
8567c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    // We can use the saved value.
8667c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
87e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu    if (rl_method.wide) {
88e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu      rl_method = LoadValueWide(rl_method, kCoreReg);
89e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu    } else {
90e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu      rl_method = LoadValue(rl_method, kCoreReg);
91e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu    }
922700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee    start_of_method_reg = rl_method.reg;
9355d0eac918321e0525f6e6491f36a80977e0d416Mark Mendell    store_method_addr_used_ = true;
9467c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  } else {
95407a9d2847161b843966a443b71760b1280bd396Serguei Katkov    start_of_method_reg = AllocTempRef();
962700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee    NewLIR1(kX86StartOfMethod, start_of_method_reg.GetReg());
9767c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  }
98407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  DCHECK_EQ(start_of_method_reg.Is64Bit(), cu_->target64);
99fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  int low_key = s4FromSwitchData(&table[2]);
1002700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee  RegStorage keyReg;
101efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Remove the bias, if necessary
102fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  if (low_key == 0) {
1032700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee    keyReg = rl_src.reg;
104efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  } else {
1051fd3346740dfb7f47be9922312b68a4227fada96buzbee    keyReg = AllocTemp();
1062700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee    OpRegRegImm(kOpSub, keyReg, rl_src.reg, low_key);
107efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  }
108efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Bounds check - if < 0 or >= size continue following switch
109407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  OpRegImm(kOpCmp, keyReg, size - 1);
1101fd3346740dfb7f47be9922312b68a4227fada96buzbee  LIR* branch_over = OpCondBranch(kCondHi, NULL);
111efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
112efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Load the displacement from the switch table
1132700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee  RegStorage disp_reg = AllocTemp();
114e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu  NewLIR5(kX86PcRelLoadRA, disp_reg.GetReg(), start_of_method_reg.GetReg(), keyReg.GetReg(),
115e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu          2, WrapPointer(tab_rec));
116efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Add displacement to start of method
117407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  OpRegReg(kOpAdd, start_of_method_reg, cu_->target64 ? As64BitReg(disp_reg) : disp_reg);
118efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // ..and go!
1192700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee  LIR* switch_branch = NewLIR1(kX86JmpR, start_of_method_reg.GetReg());
120fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  tab_rec->anchor = switch_branch;
121efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
122fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  /* branch_over target here */
1231fd3346740dfb7f47be9922312b68a4227fada96buzbee  LIR* target = NewLIR0(kPseudoTargetLabel);
124fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  branch_over->target = target;
125efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
126efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
127efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/*
128efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Array data table format:
129efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *  ushort ident = 0x0300   magic value
130efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *  ushort width            width of each element in the table
131efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *  uint   size             number of elements in the table
132efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *  ubyte  data[size*width] table of data values (may contain a single-byte
133efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *                          padding at the end)
134efc6369224b036a1fb77849f7ae65b3492c832c0buzbee *
135efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Total size is 4+(width * size + 1)/2 16-bit code units.
136efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */
1370d82948094d9a198e01aa95f64012bdedd5b6fc9buzbeevoid X86Mir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) {
1381fd3346740dfb7f47be9922312b68a4227fada96buzbee  const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset;
139efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Add the table to the list - we'll process it later
1400d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee  FillArrayData* tab_rec =
14183cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko      static_cast<FillArrayData*>(arena_->Alloc(sizeof(FillArrayData), kArenaAllocData));
142fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  tab_rec->table = table;
1431fd3346740dfb7f47be9922312b68a4227fada96buzbee  tab_rec->vaddr = current_dalvik_offset_;
144fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  uint16_t width = tab_rec->table[1];
145fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  uint32_t size = tab_rec->table[2] | ((static_cast<uint32_t>(tab_rec->table[3])) << 16);
146fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  tab_rec->size = (size * width) + 8;
147efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
148862a76027076c341c26aa6cd4a30a7cdd6dc2143buzbee  fill_array_data_.Insert(tab_rec);
149efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
150efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Making a call - use explicit registers
1511fd3346740dfb7f47be9922312b68a4227fada96buzbee  FlushAllRegs();   /* Everything to home location */
152ccc60264229ac96d798528d2cb7dbbdd0deca993Andreas Gampe  RegStorage array_ptr = TargetReg(kArg0, kRef);
153a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu  RegStorage payload = TargetPtrReg(kArg1);
154a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu  RegStorage method_start = TargetPtrReg(kArg2);
155a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu
156a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu  LoadValueDirectFixed(rl_src, array_ptr);
157efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  // Materialize a pointer to the fill data image
15867c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  if (base_of_code_ != nullptr) {
15967c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    // We can use the saved value.
16067c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low);
161e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu    if (rl_method.wide) {
162a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu      LoadValueDirectWide(rl_method, method_start);
163e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu    } else {
164a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu      LoadValueDirect(rl_method, method_start);
165e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu    }
16655d0eac918321e0525f6e6491f36a80977e0d416Mark Mendell    store_method_addr_used_ = true;
16767c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  } else {
168a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu    NewLIR1(kX86StartOfMethod, method_start.GetReg());
16967c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  }
170a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu  NewLIR2(kX86PcRelAdr, payload.GetReg(), WrapPointer(tab_rec));
171a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu  OpRegReg(kOpAdd, payload, method_start);
172984305917bf57b3f8d92965e4715a0370cc5bcfbAndreas Gampe  CallRuntimeHelperRegReg(kQuickHandleFillArrayData, array_ptr, payload, true);
173efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
174efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
1752ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid X86Mir2Lir::GenMoveException(RegLocation rl_dest) {
17633ae5583bdd69847a7316ab38a8fa8ccd63093efbuzbee  int ex_offset = cu_->target64 ?
1772f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::ExceptionOffset<8>().Int32Value() :
1782f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::ExceptionOffset<4>().Int32Value();
179a0cd2d701f29e0bc6275f1b13c0edfd4ec391879buzbee  RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
180407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  NewLIR2(cu_->target64 ? kX86Mov64RT : kX86Mov32RT, rl_result.reg.GetReg(), ex_offset);
181407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  NewLIR2(cu_->target64 ? kX86Mov64TI : kX86Mov32TI, ex_offset, 0);
1821fd3346740dfb7f47be9922312b68a4227fada96buzbee  StoreValue(rl_dest, rl_result);
1831eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao}
1841eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao
185efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/*
186efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Mark garbage collection card. Skip if the value we're storing is null.
187efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */
1882700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbeevoid X86Mir2Lir::MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) {
189407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  DCHECK_EQ(tgt_addr_reg.Is64Bit(), cu_->target64);
190407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  DCHECK_EQ(val_reg.Is64Bit(), cu_->target64);
191407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  RegStorage reg_card_base = AllocTempRef();
192407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  RegStorage reg_card_no = AllocTempRef();
1931fd3346740dfb7f47be9922312b68a4227fada96buzbee  LIR* branch_over = OpCmpImmBranch(kCondEq, val_reg, 0, NULL);
19433ae5583bdd69847a7316ab38a8fa8ccd63093efbuzbee  int ct_offset = cu_->target64 ?
1952f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::CardTableOffset<8>().Int32Value() :
1962f244e9faccfcca68af3c5484c397a01a1c3a342Andreas Gampe      Thread::CardTableOffset<4>().Int32Value();
197407a9d2847161b843966a443b71760b1280bd396Serguei Katkov  NewLIR2(cu_->target64 ? kX86Mov64RT : kX86Mov32RT, reg_card_base.GetReg(), ct_offset);
1981d54e73444e017d3a65234e0f193846f3e27472bIan Rogers  OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
1992700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee  StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
2001fd3346740dfb7f47be9922312b68a4227fada96buzbee  LIR* target = NewLIR0(kPseudoTargetLabel);
201fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  branch_over->target = target;
2021fd3346740dfb7f47be9922312b68a4227fada96buzbee  FreeTemp(reg_card_base);
2031fd3346740dfb7f47be9922312b68a4227fada96buzbee  FreeTemp(reg_card_no);
204efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
205efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
2062ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
207efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /*
208efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * On entry, rX86_ARG0, rX86_ARG1, rX86_ARG2 are live.  Let the register
209efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * allocation mechanism know so it doesn't try to use any of them when
210efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * expanding the frame or flushing.  This leaves the utility
211efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * code with no spare temps.
212efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   */
213091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  LockTemp(rs_rX86_ARG0);
214091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  LockTemp(rs_rX86_ARG1);
215091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  LockTemp(rs_rX86_ARG2);
216efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
217efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /*
218efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * We can safely skip the stack overflow check if we're
219efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * a leaf *and* our frame size < fudge factor.
220efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   */
22169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  InstructionSet isa =  cu_->target64 ? kX86_64 : kX86;
222648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison  bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, isa);
22369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
22469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // If we doing an implicit stack overflow check, perform the load immediately
22569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // before the stack pointer is decremented and anything is saved.
22669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  if (!skip_overflow_check &&
22769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
22869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    // Implicit stack overflow check.
22969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    // test eax,[esp + -overflow]
23069dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    int overflow = GetStackOverflowReservedBytes(isa);
23169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rX86_SP.GetReg(), -overflow);
23269dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    MarkPossibleStackOverflowException();
23369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  }
23469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
23569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  /* Build frame, return address already on stack */
23669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  stack_decrement_ = OpRegImm(kOpSub, rs_rX86_SP, frame_size_ -
23769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison                              GetInstructionSetPointerSize(cu_->instruction_set));
23869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
2391fd3346740dfb7f47be9922312b68a4227fada96buzbee  NewLIR0(kPseudoMethodEntry);
240efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /* Spill core callee saves */
2411fd3346740dfb7f47be9922312b68a4227fada96buzbee  SpillCoreRegs();
242c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkov  SpillFPRegs();
243fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee  if (!skip_overflow_check) {
2440d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier    class StackOverflowSlowPath : public LIRSlowPath {
2450d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier     public:
2460d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace)
2470d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier          : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, nullptr), sp_displace_(sp_displace) {
2480d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      }
2490d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      void Compile() OVERRIDE {
2500d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        m2l_->ResetRegPool();
2510d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        m2l_->ResetDefTracking();
2526ffcfa04ebb2660e238742a6000f5ccebdd5df15Mingyao Yang        GenerateTargetLabel(kPseudoThrowTarget);
2532700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee        m2l_->OpRegImm(kOpAdd, rs_rX86_SP, sp_displace_);
2540d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        m2l_->ClobberCallerSave();
2550d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier        // Assumes codegen and target are in thumb2 mode.
256984305917bf57b3f8d92965e4715a0370cc5bcfbAndreas Gampe        m2l_->CallHelper(RegStorage::InvalidReg(), kQuickThrowStackOverflow,
257984305917bf57b3f8d92965e4715a0370cc5bcfbAndreas Gampe                         false /* MarkSafepointPC */, false /* UseLink */);
2580d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      }
2590d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier
2600d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier     private:
2610d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier      const size_t sp_displace_;
2620d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier    };
26369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
26469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // TODO: for large frames we should do something like:
26569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // spill ebp
26669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // lea ebp, [esp + frame_size]
26769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // cmp ebp, fs:[stack_end_]
26869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // jcc stack_overflow_exception
26969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // mov esp, ebp
27069dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // in case a signal comes in that's not using an alternate signal stack and the large frame
27169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // may have moved us outside of the reserved area at the end of the stack.
27269dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      // cmp rs_rX86_SP, fs:[stack_end_]; jcc throw_slowpath
27369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      if (cu_->target64) {
27469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison        OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<8>());
27569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      } else {
27669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison        OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
27769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      }
27869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      LIR* branch = OpCondBranch(kCondUlt, nullptr);
27969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison      AddSlowPath(
280e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu        new(arena_)StackOverflowSlowPath(this, branch,
281e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu                                         frame_size_ -
282e0ccdc0dd166136cd43e5f54201179a4496d33e8Chao-ying Fu                                         GetInstructionSetPointerSize(cu_->instruction_set)));
28369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    }
284efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  }
285efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
2861fd3346740dfb7f47be9922312b68a4227fada96buzbee  FlushIns(ArgLocs, rl_method);
287efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
28867c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  if (base_of_code_ != nullptr) {
289a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu    RegStorage method_start = TargetPtrReg(kArg0);
29067c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    // We have been asked to save the address of the method start for later use.
291a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu    setup_method_address_[0] = NewLIR1(kX86StartOfMethod, method_start.GetReg());
29267c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell    int displacement = SRegOffset(base_of_code_->s_reg_low);
293695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee    // Native pointer - must be natural word size.
294a77ee5103532abb197f492c14a9e6fb437054e2aChao-ying Fu    setup_method_address_[1] = StoreBaseDisp(rs_rX86_SP, displacement, method_start,
295dd64450b37776f68b9bfc47f8d9a88bc72c95727Elena Sayapina                                             cu_->target64 ? k64 : k32, kNotVolatile);
29667c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell  }
29767c39c4aefca23cb136157b889c09ee200b3dec6Mark Mendell
298091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  FreeTemp(rs_rX86_ARG0);
299091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  FreeTemp(rs_rX86_ARG1);
300091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  FreeTemp(rs_rX86_ARG2);
301efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
302efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
3031fd3346740dfb7f47be9922312b68a4227fada96buzbeevoid X86Mir2Lir::GenExitSequence() {
304efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /*
305efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * In the exit path, rX86_RET0/rX86_RET1 are live - make sure they aren't
306efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   * allocated by the register utilities as temps.
307efc6369224b036a1fb77849f7ae65b3492c832c0buzbee   */
308091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  LockTemp(rs_rX86_RET0);
309091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee  LockTemp(rs_rX86_RET1);
310efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
3111fd3346740dfb7f47be9922312b68a4227fada96buzbee  NewLIR0(kPseudoMethodExit);
3121fd3346740dfb7f47be9922312b68a4227fada96buzbee  UnSpillCoreRegs();
313c380191f3048db2a3796d65db8e5d5a5e7b08c65Serguei Katkov  UnSpillFPRegs();
314efc6369224b036a1fb77849f7ae65b3492c832c0buzbee  /* Remove frame except for return address */
3159ee801f5308aa3c62ae3bedae2658612762ffb91Dmitry Petrochenko  stack_increment_ = OpRegImm(kOpAdd, rs_rX86_SP, frame_size_ - GetInstructionSetPointerSize(cu_->instruction_set));
3161fd3346740dfb7f47be9922312b68a4227fada96buzbee  NewLIR0(kX86Ret);
317efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}
318efc6369224b036a1fb77849f7ae65b3492c832c0buzbee
3193bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoruvoid X86Mir2Lir::GenSpecialExitSequence() {
3203bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru  NewLIR0(kX86Ret);
3213bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru}
3223bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru
32369dfe51b684dd9d510dbcb63295fe180f998efdeDave Allisonvoid X86Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) {
32469dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
32569dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison    return;
32669dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  }
32769dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // Implicit null pointer check.
32869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  // test eax,[arg1+0]
32969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  NewLIR3(kX86Test32RM, rs_rAX.GetReg(), reg.GetReg(), 0);
33069dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison  MarkPossibleNullPointerException(opt_flags);
33169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison}
33269dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison
333efc6369224b036a1fb77849f7ae65b3492c832c0buzbee}  // namespace art
334