1efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* 2efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * Copyright (C) 2011 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 Thumb2 ISA. */ 18efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 1902031b185b4653e6c72e21f7a51238b903f6d638buzbee#include "codegen_arm.h" 200b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe 210b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "arm_lir.h" 223d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier#include "art_method.h" 2341b175aba41c9365a1c53b8a1afbd17129c87c14Vladimir Marko#include "base/bit_utils.h" 240b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "base/logging.h" 250b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "dex/mir_graph.h" 26848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao#include "dex/quick/dex_file_to_method_inliner_map.h" 277940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom#include "dex/quick/mir_to_lir-inl.h" 280b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "driver/compiler_driver.h" 2920f85597828194c12be10d3a927999def066555eVladimir Marko#include "driver/compiler_options.h" 30576ca0cd692c0b6ae70e776de91015b8ff000a08Ian Rogers#include "gc/accounting/card_table.h" 31f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko#include "mirror/object_array-inl.h" 32166db04e259ca51838c311891598664deeed85adIan Rogers#include "entrypoints/quick/quick_entrypoints.h" 33e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko#include "utils/dex_cache_arrays_layout-inl.h" 34efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 35efc6369224b036a1fb77849f7ae65b3492c832c0buzbeenamespace art { 36efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 37efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* 38efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * The sparse table in the literal pool is an array of <key,displacement> 39efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * pairs. For each set, we'll load them as a pair using ldmia. 40efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * This means that the register number of the temp we use for the key 41efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * must be lower than the reg for the displacement. 42efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * 43efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * The test loop will look something like: 44efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * 452700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee * adr r_base, <table> 46fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * ldr r_val, [rARM_SP, v_reg_off] 47fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov r_idx, #table_size 48efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * lp: 492700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee * ldmia r_base!, {r_key, r_disp} 50fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * sub r_idx, #1 51fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * cmp r_val, r_key 52efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * ifeq 53fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * add rARM_PC, r_disp ; This is the branch from which we compute displacement 54fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * cbnz r_idx, lp 55efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 5648971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid ArmMir2Lir::GenLargeSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src) { 578d0d03e24325463f0060abfd05dba5598044e9b1Razvan A Lupusoru const uint16_t* table = mir_graph_->GetTable(mir, table_offset); 58efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Add the table to the list - we'll process it later 59fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee SwitchTable *tab_rec = 6083cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData)); 6172f53af0307b9109a1cfc0671675ce5d45c66d3aChao-ying Fu tab_rec->switch_mir = mir; 62fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->table = table; 631fd3346740dfb7f47be9922312b68a4227fada96buzbee tab_rec->vaddr = current_dalvik_offset_; 640d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee uint32_t size = table[1]; 65e39c54ea575ec710d5e84277fcdcc049f8acb3c9Vladimir Marko switch_tables_.push_back(tab_rec); 66efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 67efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Get the switch value 681fd3346740dfb7f47be9922312b68a4227fada96buzbee rl_src = LoadValue(rl_src, kCoreReg); 692700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_base = AllocTemp(); 70efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Allocate key and disp temps */ 712700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_key = AllocTemp(); 722700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_disp = AllocTemp(); 73fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee // Make sure r_key's register number is less than r_disp's number for ldmia 742700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee if (r_key.GetReg() > r_disp.GetReg()) { 752700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage tmp = r_disp; 76fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee r_disp = r_key; 77fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee r_key = tmp; 78efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 79efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Materialize a pointer to the switch table 802700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee NewLIR3(kThumb2Adr, r_base.GetReg(), 0, WrapPointer(tab_rec)); 81fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee // Set up r_idx 822700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_idx = AllocTemp(); 831fd3346740dfb7f47be9922312b68a4227fada96buzbee LoadConstant(r_idx, size); 84efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Establish loop branch target 851fd3346740dfb7f47be9922312b68a4227fada96buzbee LIR* target = NewLIR0(kPseudoTargetLabel); 86efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Load next key/disp 87091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetRegNum()) | (1 << r_disp.GetRegNum())); 882700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegReg(kOpCmp, r_key, rl_src.reg); 89efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Go if match. NOTE: No instruction set switch here - must stay Thumb2 903da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison LIR* it = OpIT(kCondEq, ""); 912700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* switch_branch = NewLIR1(kThumb2AddPCR, r_disp.GetReg()); 923da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison OpEndIT(it); 93fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->anchor = switch_branch; 94efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Needs to use setflags encoding here 95dbb8c49d540edd2a39076093163c7218f03aa502Vladimir Marko OpRegRegImm(kOpSub, r_idx, r_idx, 1); // For value == 1, this should set flags. 968dea81ca9c0201ceaa88086b927a5838a06a3e69Vladimir Marko DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode)); 971fd3346740dfb7f47be9922312b68a4227fada96buzbee OpCondBranch(kCondNe, target); 98efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 99efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 100efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 10148971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid ArmMir2Lir::GenLargePackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src) { 1028d0d03e24325463f0060abfd05dba5598044e9b1Razvan A Lupusoru const uint16_t* table = mir_graph_->GetTable(mir, table_offset); 103efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Add the table to the list - we'll process it later 104fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee SwitchTable *tab_rec = 10583cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData)); 10672f53af0307b9109a1cfc0671675ce5d45c66d3aChao-ying Fu tab_rec->switch_mir = mir; 107fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->table = table; 1081fd3346740dfb7f47be9922312b68a4227fada96buzbee tab_rec->vaddr = current_dalvik_offset_; 1090d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee uint32_t size = table[1]; 110e39c54ea575ec710d5e84277fcdcc049f8acb3c9Vladimir Marko switch_tables_.push_back(tab_rec); 111efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 112efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Get the switch value 1131fd3346740dfb7f47be9922312b68a4227fada96buzbee rl_src = LoadValue(rl_src, kCoreReg); 1142700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage table_base = AllocTemp(); 115efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Materialize a pointer to the switch table 1162700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee NewLIR3(kThumb2Adr, table_base.GetReg(), 0, WrapPointer(tab_rec)); 117fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee int low_key = s4FromSwitchData(&table[2]); 1182700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage keyReg; 119efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Remove the bias, if necessary 120fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee if (low_key == 0) { 1212700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee keyReg = rl_src.reg; 122efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } else { 1231fd3346740dfb7f47be9922312b68a4227fada96buzbee keyReg = AllocTemp(); 1242700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegRegImm(kOpSub, keyReg, rl_src.reg, low_key); 125efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 126efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Bounds check - if < 0 or >= size continue following switch 1271fd3346740dfb7f47be9922312b68a4227fada96buzbee OpRegImm(kOpCmp, keyReg, size-1); 1282cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* branch_over = OpCondBranch(kCondHi, nullptr); 129efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 130efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Load the displacement from the switch table 1312700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage disp_reg = AllocTemp(); 132695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee LoadBaseIndexed(table_base, keyReg, disp_reg, 2, k32); 133efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 134efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // ..and go! NOTE: No instruction set switch here - must stay Thumb2 1352700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* switch_branch = NewLIR1(kThumb2AddPCR, disp_reg.GetReg()); 136fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->anchor = switch_branch; 137efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 138fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee /* branch_over target here */ 1391fd3346740dfb7f47be9922312b68a4227fada96buzbee LIR* target = NewLIR0(kPseudoTargetLabel); 140fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee branch_over->target = target; 141efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 142efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 143efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* 144d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * Handle unlocked -> thin locked transition inline or else call out to quick entrypoint. For more 145d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * details see monitor.cc. 146efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 1472ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { 1481fd3346740dfb7f47be9922312b68a4227fada96buzbee FlushAllRegs(); 149695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee // FIXME: need separate LoadValues for object references. 1502700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LoadValueDirectFixed(rl_src, rs_r0); // Get obj 1511fd3346740dfb7f47be9922312b68a4227fada96buzbee LockCallTemps(); // Prepare for explicit register usage 152d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15. 153d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (kArchVariantHasGoodBranchPredictor) { 154f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison LIR* null_check_branch = nullptr; 155d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) { 156d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch = nullptr; // No null check. 157d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 158d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // If the null-check fails its handled by the slow-path to reduce exception related meta-data. 15969dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 1602cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, nullptr); 161f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison } 162d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 163695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 164091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 165091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 166f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison MarkPossibleNullPointerException(opt_flags); 167e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 168e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 1692cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_r3, 0, nullptr); 170e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // r1 is zero except for the rb bits here. Copy the read barrier bits into r2. 171e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegReg(kOpOr, rs_r2, rs_r2, rs_r1); 172091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR4(kThumb2Strex, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(), 173091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 1742cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* lock_success_branch = OpCmpImmBranch(kCondEq, rs_r1, 0, nullptr); 175d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 176d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 177d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); 178d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers not_unlocked_branch->target = slow_path_target; 179d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (null_check_branch != nullptr) { 180d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch->target = slow_path_target; 181d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 182d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // TODO: move to a slow path. 183d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Go expensive route - artLockObjectFromCode(obj); 184dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), rs_rARM_LR); 18531c2aac7137b69d5622eea09597500731fbee2efVladimir Marko ClobberCallerSave(); 1862700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR); 187d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers MarkSafepointPC(call_inst); 188d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 189d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* success_target = NewLIR0(kPseudoTargetLabel); 190d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers lock_success_branch->target = success_target; 19148f5c47907654350ce30a8dfdda0e977f5d3d39fHans Boehm GenMemBarrier(kLoadAny); 192d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 193d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Explicit null-check as slow-path is entered using an IT. 1942700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee GenNullCheck(rs_r0, opt_flags); 195695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 196091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 197091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 198f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison MarkPossibleNullPointerException(opt_flags); 199e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 200e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 201e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // r1 will be zero except for the rb bits if the following 202e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // cmp-and-branch branches to eq where r2 will be used. Copy the 203e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // read barrier bits into r2. 204e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegReg(kOpOr, rs_r2, rs_r2, rs_r1); 205e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegImm(kOpCmp, rs_r3, 0); 206e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi 2073da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison LIR* it = OpIT(kCondEq, ""); 208091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR4(kThumb2Strex/*eq*/, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(), 209091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 2103da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison OpEndIT(it); 2112700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegImm(kOpCmp, rs_r1, 0); 2123da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison it = OpIT(kCondNe, "T"); 213d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Go expensive route - artLockObjectFromCode(self, obj); 214091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), 215091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee rs_rARM_LR); 21631c2aac7137b69d5622eea09597500731fbee2efVladimir Marko ClobberCallerSave(); 2172700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR); 2183da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison OpEndIT(it); 219d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers MarkSafepointPC(call_inst); 22048f5c47907654350ce30a8dfdda0e977f5d3d39fHans Boehm GenMemBarrier(kLoadAny); 221d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 222efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 223efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 224efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* 225d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * Handle thin locked -> unlocked transition inline or else call out to quick entrypoint. For more 226d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * details see monitor.cc. Note the code below doesn't use ldrex/strex as the code holds the lock 227d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * and can only give away ownership if its suspended. 228efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 2292ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { 2301fd3346740dfb7f47be9922312b68a4227fada96buzbee FlushAllRegs(); 2312700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LoadValueDirectFixed(rl_src, rs_r0); // Get obj 2321fd3346740dfb7f47be9922312b68a4227fada96buzbee LockCallTemps(); // Prepare for explicit register usage 233f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison LIR* null_check_branch = nullptr; 234695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 235d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15. 236d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (kArchVariantHasGoodBranchPredictor) { 237d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) { 238d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch = nullptr; // No null check. 239d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 240d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // If the null-check fails its handled by the slow-path to reduce exception related meta-data. 24169dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 2422cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, nullptr); 243f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison } 244d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 245e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 246e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Load32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); // Get lock 247e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 248e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 249e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 250e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 251f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison MarkPossibleNullPointerException(opt_flags); 252e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 253e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 254e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out except the read barrier bits. 255e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r1, rs_r1, LockWord::kReadBarrierStateMaskShifted); 2562cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_r3, rs_r2, nullptr); 25748f5c47907654350ce30a8dfdda0e977f5d3d39fHans Boehm GenMemBarrier(kAnyStore); 258e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* unlock_success_branch; 259e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 260e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Store32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); 2612cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier unlock_success_branch = OpUnconditionalBranch(nullptr); 262e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 263e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR4(kThumb2Strex, rs_r2.GetReg(), rs_r1.GetReg(), rs_r0.GetReg(), 264e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 2652cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier unlock_success_branch = OpCmpImmBranch(kCondEq, rs_r2, 0, nullptr); 266e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 267d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); 268d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers slow_unlock_branch->target = slow_path_target; 269d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (null_check_branch != nullptr) { 270d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch->target = slow_path_target; 271d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 272d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // TODO: move to a slow path. 273d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Go expensive route - artUnlockObjectFromCode(obj); 274dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(), rs_rARM_LR); 27531c2aac7137b69d5622eea09597500731fbee2efVladimir Marko ClobberCallerSave(); 2762700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR); 277d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers MarkSafepointPC(call_inst); 278d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 279d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* success_target = NewLIR0(kPseudoTargetLabel); 280d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers unlock_success_branch->target = success_target; 281d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 282d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Explicit null-check as slow-path is entered using an IT. 2832700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee GenNullCheck(rs_r0, opt_flags); 284e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 285e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Load32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); // Get lock 286e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 287e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // If we use read barriers, we need to use atomic instructions. 288e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 289e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 290e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 291b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison MarkPossibleNullPointerException(opt_flags); 292695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 293e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 294e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 295e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out except the read barrier bits. 296e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r1, rs_r1, LockWord::kReadBarrierStateMaskShifted); 297d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Is lock unheld on lock or held by us (==thread_id) on unlock? 298e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegReg(kOpCmp, rs_r3, rs_r2); 299e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 300e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* it = OpIT(kCondEq, "EE"); 301e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (GenMemBarrier(kAnyStore)) { 302e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi UpdateIT(it, "TEE"); 303e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 304e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Store32Disp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); 305e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Go expensive route - UnlockObjectFromCode(obj); 306e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(), 307e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi rs_rARM_LR); 308e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi ClobberCallerSave(); 309e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR); 310e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpEndIT(it); 311e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi MarkSafepointPC(call_inst); 312e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 313e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // If we use read barriers, we need to use atomic instructions. 314e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* it = OpIT(kCondEq, ""); 315e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (GenMemBarrier(kAnyStore)) { 316e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi UpdateIT(it, "T"); 317e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 318e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR4/*eq*/(kThumb2Strex, rs_r2.GetReg(), rs_r1.GetReg(), rs_r0.GetReg(), 319e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 320e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpEndIT(it); 321e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Since we know r2 wasn't zero before the above it instruction, 322e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // if r2 is zero here, we know r3 was equal to r2 and the strex 323e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // suceeded (we're done). Otherwise (either r3 wasn't equal to r2 324e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // or the strex failed), call the entrypoint. 325e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegImm(kOpCmp, rs_r2, 0); 326e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* it2 = OpIT(kCondNe, "T"); 327e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Go expensive route - UnlockObjectFromCode(obj); 328e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(), 329e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi rs_rARM_LR); 330e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi ClobberCallerSave(); 331e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR); 332e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpEndIT(it2); 333e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi MarkSafepointPC(call_inst); 334b14329f90f725af0f67c45dfcb94933a426d63ceAndreas Gampe } 335d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 336efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 337efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 3382ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenMoveException(RegLocation rl_dest) { 339dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers int ex_offset = Thread::ExceptionOffset<4>().Int32Value(); 340a0cd2d701f29e0bc6275f1b13c0edfd4ec391879buzbee RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); 341a0cd2d701f29e0bc6275f1b13c0edfd4ec391879buzbee RegStorage reset_reg = AllocTempRef(); 3423c12c512faf6837844d5465b23b9410889e5eb11Andreas Gampe LoadRefDisp(rs_rARM_SELF, ex_offset, rl_result.reg, kNotVolatile); 3431fd3346740dfb7f47be9922312b68a4227fada96buzbee LoadConstant(reset_reg, 0); 3443c12c512faf6837844d5465b23b9410889e5eb11Andreas Gampe StoreRefDisp(rs_rARM_SELF, ex_offset, reset_reg, kNotVolatile); 3451fd3346740dfb7f47be9922312b68a4227fada96buzbee FreeTemp(reset_reg); 3461fd3346740dfb7f47be9922312b68a4227fada96buzbee StoreValue(rl_dest, rl_result); 3471eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao} 3481eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao 349bf535be514570fc33fc0a6347a87dcd9097d9bfdVladimir Markovoid ArmMir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) { 3502700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage reg_card_base = AllocTemp(); 3512700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage reg_card_no = AllocTemp(); 352dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers LoadWordDisp(rs_rARM_SELF, Thread::CardTableOffset<4>().Int32Value(), reg_card_base); 3531d54e73444e017d3a65234e0f193846f3e27472bIan Rogers OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift); 3542700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte); 3551fd3346740dfb7f47be9922312b68a4227fada96buzbee FreeTemp(reg_card_base); 3561fd3346740dfb7f47be9922312b68a4227fada96buzbee FreeTemp(reg_card_no); 357efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 358efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 3591109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbeckystatic dwarf::Reg DwarfCoreReg(int num) { 3601109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky return dwarf::Reg::ArmCore(num); 3611109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky} 3621109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky 3631109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbeckystatic dwarf::Reg DwarfFpReg(int num) { 3641109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky return dwarf::Reg::ArmFp(num); 3651109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky} 3661109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky 3672ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { 3681109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky DCHECK_EQ(cfi_.GetCurrentCFAOffset(), 0); // empty stack. 3691fd3346740dfb7f47be9922312b68a4227fada96buzbee int spill_count = num_core_spills_ + num_fp_spills_; 370efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 371efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * On entry, r0, r1, r2 & r3 are live. Let the register allocation 372efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * mechanism know so it doesn't try to use any of them when 373efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * expanding the frame or flushing. This leaves the utility 374efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * code with a single temp: r12. This should be enough. 375efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 376091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r0); 377091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r1); 378091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r2); 379091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r3); 380efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 381efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 382efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * We can safely skip the stack overflow check if we're 383efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * a leaf *and* our frame size < fudge factor. 384efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 385648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, kArm); 386648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison const size_t kStackOverflowReservedUsableBytes = GetStackOverflowReservedBytes(kArm); 3877cd26f355ba83be75b72ed628ed5ee84a3245c4fAndreas Gampe bool large_frame = (static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes); 388648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison bool generate_explicit_stack_overflow_check = large_frame || 389648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison !cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks(); 390fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee if (!skip_overflow_check) { 391648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison if (generate_explicit_stack_overflow_check) { 392fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee if (!large_frame) { 393fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee /* Load stack limit */ 394fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee LockTemp(rs_r12); 395fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12); 396fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee } 3975cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison } else { 3985cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Implicit stack overflow check. 3995cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Generate a load from [sp, #-overflowsize]. If this is in the stack 4005cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // redzone we will get a segmentation fault. 4015cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // 4025cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Caveat coder: if someone changes the kStackOverflowReservedBytes value 4035cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // we need to make sure that it's loadable in an immediate field of 4045cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // a sub instruction. Otherwise we will get a temp allocation and the 4055cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // code size will increase. 4065cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // 4075cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // This is done before the callee save instructions to avoid any possibility 4085cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // of these overflowing. This uses r12 and that's never saved in a callee 4095cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // save. 4107ea6f79bbddd69d5db86a8656a31aaaf64ae2582Andreas Gampe OpRegRegImm(kOpSub, rs_r12, rs_rARM_SP, GetStackOverflowReservedBytes(kArm)); 4115cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison Load32Disp(rs_r12, 0, rs_r12); 4125cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison MarkPossibleStackOverflowException(); 413b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison } 414efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 415efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Spill core callee saves */ 4161109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (core_spill_mask_ != 0u) { 4171109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_LR.GetRegNum()))) == 0u) { 4181109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // Spilling only low regs and/or LR, use 16-bit PUSH. 4191109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky constexpr int lr_bit_shift = rs_rARM_LR.GetRegNum() - 8; 4201109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumbPush, 4211109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) | 4221109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky ((core_spill_mask_ & (1u << rs_rARM_LR.GetRegNum())) >> lr_bit_shift)); 4231109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else if (IsPowerOfTwo(core_spill_mask_)) { 4241109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // kThumb2Push cannot be used to spill a single register. 4251109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Push1, CTZ(core_spill_mask_)); 4261109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else { 4271109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Push, core_spill_mask_); 4281109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } 4291109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(num_core_spills_ * kArmPointerSize); 4301109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RelOffsetForMany(DwarfCoreReg(0), 0, core_spill_mask_, kArmPointerSize); 4319d5c25acdd1e9635fde8f8bf52a126b4d371dabdVladimir Marko } 432efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Need to spill any FP regs? */ 4331109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (num_fp_spills_ != 0u) { 434efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 435efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * NOTE: fp spills are a little different from core spills in that 436efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * they are pushed as a contiguous block. When promoting from 437efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * the fp set, we must allocate all singles from s16..highest-promoted 438efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 4391fd3346740dfb7f47be9922312b68a4227fada96buzbee NewLIR1(kThumb2VPushCS, num_fp_spills_); 4401109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(num_fp_spills_ * kArmPointerSize); 4411109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RelOffsetForMany(DwarfFpReg(0), 0, fp_spill_mask_, kArmPointerSize); 442efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 4430d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier 44405a48b1f8e62564abb7c2fe674e3234d5861647fMathieu Chartier const int spill_size = spill_count * 4; 44505a48b1f8e62564abb7c2fe674e3234d5861647fMathieu Chartier const int frame_size_without_spills = frame_size_ - spill_size; 446fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee if (!skip_overflow_check) { 447648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison if (generate_explicit_stack_overflow_check) { 4480d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier class StackOverflowSlowPath : public LIRSlowPath { 4490d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier public: 4500d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, bool restore_lr, size_t sp_displace) 4510b40ecf156e309aa17c72a28cd1b0237dbfb8746Vladimir Marko : LIRSlowPath(m2l, branch), restore_lr_(restore_lr), 4520d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier sp_displace_(sp_displace) { 4530d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 4540d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier void Compile() OVERRIDE { 4550d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier m2l_->ResetRegPool(); 4560d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier m2l_->ResetDefTracking(); 4576ffcfa04ebb2660e238742a6000f5ccebdd5df15Mingyao Yang GenerateTargetLabel(kPseudoThrowTarget); 4580d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier if (restore_lr_) { 4592700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee m2l_->LoadWordDisp(rs_rARM_SP, sp_displace_ - 4, rs_rARM_LR); 4600d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 4612700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee m2l_->OpRegImm(kOpAdd, rs_rARM_SP, sp_displace_); 4621109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky m2l_->cfi().AdjustCFAOffset(-sp_displace_); 4630d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier m2l_->ClobberCallerSave(); 464dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers ThreadOffset<4> func_offset = QUICK_ENTRYPOINT_OFFSET(4, pThrowStackOverflow); 4650d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier // Load the entrypoint directly into the pc instead of doing a load + branch. Assumes 4660d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier // codegen and target are in thumb2 mode. 467695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee // NOTE: native pointer. 4682700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee m2l_->LoadWordDisp(rs_rARM_SELF, func_offset.Int32Value(), rs_rARM_PC); 4691109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky m2l_->cfi().AdjustCFAOffset(sp_displace_); 4700d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 4710d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier 4720d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier private: 4730d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier const bool restore_lr_; 4740d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier const size_t sp_displace_; 4750d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier }; 476fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee if (large_frame) { 477fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee // Note: may need a temp reg, and we only have r12 free at this point. 4782700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegRegImm(kOpSub, rs_rARM_LR, rs_rARM_SP, frame_size_without_spills); 479fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12); 4802700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_LR, rs_r12, nullptr); 4810d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier // Need to restore LR since we used it as a temp. 48205a48b1f8e62564abb7c2fe674e3234d5861647fMathieu Chartier AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, true, spill_size)); 4832700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegCopy(rs_rARM_SP, rs_rARM_LR); // Establish stack 4841109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 4850d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } else { 486fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee /* 487fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee * If the frame is small enough we are guaranteed to have enough space that remains to 488fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee * handle signals on the user stack. However, we may not have any free temp 489fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee * registers at this point, so we'll temporarily add LR to the temp pool. 490fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee */ 491fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee DCHECK(!GetRegInfo(rs_rARM_LR)->IsTemp()); 492fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee MarkTemp(rs_rARM_LR); 493fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee FreeTemp(rs_rARM_LR); 4942700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegRegImm(kOpSub, rs_rARM_SP, rs_rARM_SP, frame_size_without_spills); 4951109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 496fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee Clobber(rs_rARM_LR); 497fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee UnmarkTemp(rs_rARM_LR); 4982700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_SP, rs_r12, nullptr); 4990d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, false, frame_size_)); 5000d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 501b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison } else { 5025cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Implicit stack overflow check has already been done. Just make room on the 5035cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // stack for the frame now. 504f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison OpRegImm(kOpSub, rs_rARM_SP, frame_size_without_spills); 5051109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 506b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison } 507efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } else { 5082700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegImm(kOpSub, rs_rARM_SP, frame_size_without_spills); 5091109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 510efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 511efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5121fd3346740dfb7f47be9922312b68a4227fada96buzbee FlushIns(ArgLocs, rl_method); 513efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 514cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko // We can promote a PC-relative reference to dex cache arrays to a register 515cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko // if it's used at least twice. Without investigating where we should lazily 516cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko // load the reference, we conveniently load it after flushing inputs. 517cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko if (dex_cache_arrays_base_reg_.Valid()) { 518cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko OpPcRelDexCacheArrayAddr(cu_->dex_file, dex_cache_arrays_min_offset_, 519cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko dex_cache_arrays_base_reg_); 520cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko } 521cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko 522091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r0); 523091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r1); 524091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r2); 525091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r3); 526fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee FreeTemp(rs_r12); 527efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 528efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5292ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenExitSequence() { 5301109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RememberState(); 5311fd3346740dfb7f47be9922312b68a4227fada96buzbee int spill_count = num_core_spills_ + num_fp_spills_; 5321109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky 533efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 534efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * In the exit path, r0/r1 are live - make sure they aren't 535efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * allocated by the register utilities as temps. 536efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 537091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r0); 538091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r1); 539efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5401109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky int adjust = frame_size_ - (spill_count * kArmPointerSize); 5411109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky OpRegImm(kOpAdd, rs_rARM_SP, adjust); 5421109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-adjust); 543efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Need to restore any FP callee saves? */ 5441fd3346740dfb7f47be9922312b68a4227fada96buzbee if (num_fp_spills_) { 5451fd3346740dfb7f47be9922312b68a4227fada96buzbee NewLIR1(kThumb2VPopCS, num_fp_spills_); 5461109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-num_fp_spills_ * kArmPointerSize); 5471109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreMany(DwarfFpReg(0), fp_spill_mask_); 548efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 5491109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky bool unspill_LR_to_PC = (core_spill_mask_ & (1 << rs_rARM_LR.GetRegNum())) != 0; 5501109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (unspill_LR_to_PC) { 551091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee core_spill_mask_ &= ~(1 << rs_rARM_LR.GetRegNum()); 552091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee core_spill_mask_ |= (1 << rs_rARM_PC.GetRegNum()); 553efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 5541109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (core_spill_mask_ != 0u) { 5551109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_PC.GetRegNum()))) == 0u) { 5561109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // Unspilling only low regs and/or PC, use 16-bit POP. 5571109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky constexpr int pc_bit_shift = rs_rARM_PC.GetRegNum() - 8; 5581109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumbPop, 5591109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky (core_spill_mask_ & ~(1u << rs_rARM_PC.GetRegNum())) | 5601109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky ((core_spill_mask_ & (1u << rs_rARM_PC.GetRegNum())) >> pc_bit_shift)); 5611109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else if (IsPowerOfTwo(core_spill_mask_)) { 5621109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // kThumb2Pop cannot be used to unspill a single register. 5631109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Pop1, CTZ(core_spill_mask_)); 5641109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else { 5651109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Pop, core_spill_mask_); 5661109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } 5671109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // If we pop to PC, there is no further epilogue code. 5681109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (!unspill_LR_to_PC) { 5691109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-num_core_spills_ * kArmPointerSize); 5701109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreMany(DwarfCoreReg(0), core_spill_mask_); 5711109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky DCHECK_EQ(cfi_.GetCurrentCFAOffset(), 0); // empty stack. 5721109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } 5739d5c25acdd1e9635fde8f8bf52a126b4d371dabdVladimir Marko } 5741109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (!unspill_LR_to_PC) { 575efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* We didn't pop to rARM_PC, so must do a bv rARM_LR */ 576091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR1(kThumbBx, rs_rARM_LR.GetReg()); 577efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 5781109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // The CFI should be restored for any code that follows the exit block. 5791109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreState(); 5801109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.DefCFAOffset(frame_size_); 581efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 582efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5833bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoruvoid ArmMir2Lir::GenSpecialExitSequence() { 584091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR1(kThumbBx, rs_rARM_LR.GetReg()); 5853bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru} 5863bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru 5876ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Markovoid ArmMir2Lir::GenSpecialEntryForSuspend() { 5886ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko // Keep 16-byte stack alignment - push r0, i.e. ArtMethod*, r5, r6, lr. 5896ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko DCHECK(!IsTemp(rs_r5)); 5906ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko DCHECK(!IsTemp(rs_r6)); 5916ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko core_spill_mask_ = 5926ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko (1u << rs_r5.GetRegNum()) | (1u << rs_r6.GetRegNum()) | (1u << rs_rARM_LR.GetRegNum()); 5936ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko num_core_spills_ = 3u; 5946ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko fp_spill_mask_ = 0u; 5956ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko num_fp_spills_ = 0u; 5966ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko frame_size_ = 16u; 5976ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko core_vmap_table_.clear(); 5986ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko fp_vmap_table_.clear(); 5996ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko NewLIR1(kThumbPush, (1u << rs_r0.GetRegNum()) | // ArtMethod* 6006ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) | // Spills other than LR. 6016ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko (1u << 8)); // LR encoded for 16-bit push. 6021109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_); 6031109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // Do not generate CFI for scratch register r0. 6041109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RelOffsetForMany(DwarfCoreReg(0), 4, core_spill_mask_, kArmPointerSize); 6056ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko} 6066ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko 6076ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Markovoid ArmMir2Lir::GenSpecialExitForSuspend() { 6086ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko // Pop the frame. (ArtMethod* no longer needed but restore it anyway.) 6096ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko NewLIR1(kThumb2Pop, (1u << rs_r0.GetRegNum()) | core_spill_mask_); // 32-bit because of LR. 6101109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-frame_size_); 6111109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreMany(DwarfCoreReg(0), core_spill_mask_); 6126ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko} 6136ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko 614f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Markostatic bool ArmUseRelativeCall(CompilationUnit* cu, const MethodReference& target_method) { 615f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Emit relative calls only within a dex file due to the limited range of the BL insn. 616f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return cu->dex_file == target_method.dex_file; 617f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 618f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 619f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko/* 620f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko * Bit of a hack here - in the absence of a real scheduling pass, 621f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko * emit the next instruction in static & direct invoke sequences. 622f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko */ 623848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haoint ArmMir2Lir::ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info, 624e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko int state, const MethodReference& target_method, 625e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko uint32_t unused_idx ATTRIBUTE_UNUSED, 626e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko uintptr_t direct_code, uintptr_t direct_method, 627e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko InvokeType type) { 628e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko ArmMir2Lir* cg = static_cast<ArmMir2Lir*>(cu->cg.get()); 629848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao if (info->string_init_offset != 0) { 630848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); 631848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao switch (state) { 632848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao case 0: { // Grab target method* from thread pointer 633848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao cg->LoadRefDisp(rs_rARM_SELF, info->string_init_offset, arg0_ref, kNotVolatile); 634848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao break; 635848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao } 636848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao case 1: // Grab the code from the method* 637848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao if (direct_code == 0) { 638848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao // kInvokeTgt := arg0_ref->entrypoint 639848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao cg->LoadWordDisp(arg0_ref, 6403d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier ArtMethod::EntryPointFromQuickCompiledCodeOffset( 641848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kArmPointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt)); 642848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao } 643848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao break; 644848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao default: 645848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao return -1; 646848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao } 647848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao } else if (direct_code != 0 && direct_method != 0) { 648f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko switch (state) { 649f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 0: // Get the current Method* [sets kArg0] 650f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code != static_cast<uintptr_t>(-1)) { 651f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code); 652f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else if (ArmUseRelativeCall(cu, target_method)) { 653f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Defer to linker patch. 654f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 655f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadCodeAddress(target_method, type, kInvokeTgt); 656f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 657f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_method != static_cast<uintptr_t>(-1)) { 658f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method); 659f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 660f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadMethodAddress(target_method, type, kArg0); 661f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 662f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko break; 663f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko default: 664f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return -1; 665f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 666f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 667e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko bool use_pc_rel = cg->CanUseOpPcRelDexCacheArrayLoad(); 668f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); 669f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko switch (state) { 670f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 0: // Get the current Method* [sets kArg0] 671f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // TUNING: we can save a reg copy if Method* has been promoted. 672e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel) { 673e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko cg->LoadCurrMethodDirect(arg0_ref); 674e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko break; 675e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 676e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko ++state; 677e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko FALLTHROUGH_INTENDED; 678f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 1: // Get method->dex_cache_resolved_methods_ 679e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel) { 680e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko cg->LoadRefDisp(arg0_ref, 6813d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), 682e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko arg0_ref, 683e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko kNotVolatile); 684e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 685f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Set up direct code if known. 686f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code != 0) { 687f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code != static_cast<uintptr_t>(-1)) { 688f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code); 689f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else if (ArmUseRelativeCall(cu, target_method)) { 690f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Defer to linker patch. 691f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 692f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); 693f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadCodeAddress(target_method, type, kInvokeTgt); 694f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 695f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 696e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel || direct_code != 0) { 697e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko break; 698e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 699e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko ++state; 700e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko FALLTHROUGH_INTENDED; 701f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 2: // Grab target method* 702f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko CHECK_EQ(cu->dex_file, target_method.dex_file); 703e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel) { 704e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko cg->LoadRefDisp(arg0_ref, 705e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko mirror::ObjectArray<mirror::Object>::OffsetOfElement( 706e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko target_method.dex_method_index).Int32Value(), 707e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko arg0_ref, 708e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko kNotVolatile); 709e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } else { 710e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index); 7113d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, arg0_ref, false); 712e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 713f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko break; 714f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 3: // Grab the code from the method* 715f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code == 0) { 716f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // kInvokeTgt := arg0_ref->entrypoint 717f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadWordDisp(arg0_ref, 7183d21bdf8894e780d349c481e5c9e29fe1556051cMathieu Chartier ArtMethod::EntryPointFromQuickCompiledCodeOffset( 7192d7210188805292e463be4bcf7a133b654d7e0eaMathieu Chartier kArmPointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt)); 720f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 721f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko break; 722f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko default: 723f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return -1; 724f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 725f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 726f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return state + 1; 727f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 728f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 729f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir MarkoNextCallInsn ArmMir2Lir::GetNextSDCallInsn() { 730f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return ArmNextSDCallInsn; 731f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 732f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 733f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir MarkoLIR* ArmMir2Lir::CallWithLinkerFixup(const MethodReference& target_method, InvokeType type) { 734f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // For ARM, just generate a relative BL instruction that will be filled in at 'link time'. 735f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // If the target turns out to be too far, the linker will generate a thunk for dispatch. 736f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko int target_method_idx = target_method.dex_method_index; 737f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko const DexFile* target_dex_file = target_method.dex_file; 738f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 739f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Generate the call instruction and save index, dex_file, and type. 740f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // NOTE: Method deduplication takes linker patches into account, so we can just pass 0 741f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // as a placeholder for the offset. 742f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko LIR* call = RawLIR(current_dalvik_offset_, kThumb2Bl, 0, 743f6737f7ed741b15cfd60c2530dab69f897540735Vladimir Marko target_method_idx, WrapPointer(target_dex_file), type); 744f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko AppendLIR(call); 745f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko call_method_insns_.push_back(call); 746f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return call; 747f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 748f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 749f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir MarkoLIR* ArmMir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info) { 750f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko LIR* call_insn; 751f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (method_info.FastPath() && ArmUseRelativeCall(cu_, method_info.GetTargetMethod()) && 752f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko (method_info.GetSharpType() == kDirect || method_info.GetSharpType() == kStatic) && 753f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko method_info.DirectCode() == static_cast<uintptr_t>(-1)) { 754f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko call_insn = CallWithLinkerFixup(method_info.GetTargetMethod(), method_info.GetSharpType()); 755f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 756f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko call_insn = OpReg(kOpBlx, TargetPtrReg(kInvokeTgt)); 757f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 758f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return call_insn; 759f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 760f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 761efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} // namespace art 762