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