call_arm.cc revision 2cebb24bfc3247d3e9be138a3350106737455918
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" 220b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "base/logging.h" 230b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "dex/mir_graph.h" 247940e44f4517de5e2634a7e07d58d0fb26160513Brian Carlstrom#include "dex/quick/mir_to_lir-inl.h" 250b9203e7996ee1856f620f95d95d8a273c43a3dfAndreas Gampe#include "driver/compiler_driver.h" 2620f85597828194c12be10d3a927999def066555eVladimir Marko#include "driver/compiler_options.h" 27576ca0cd692c0b6ae70e776de91015b8ff000a08Ian Rogers#include "gc/accounting/card_table.h" 28f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko#include "mirror/art_method.h" 29f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko#include "mirror/object_array-inl.h" 30166db04e259ca51838c311891598664deeed85adIan Rogers#include "entrypoints/quick/quick_entrypoints.h" 317e499925f8b4da46ae51040e9322690f3df992e6Andreas Gampe#include "utils.h" 32e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko#include "utils/dex_cache_arrays_layout-inl.h" 33efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 34efc6369224b036a1fb77849f7ae65b3492c832c0buzbeenamespace art { 35efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 36efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* 37efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * The sparse table in the literal pool is an array of <key,displacement> 38efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * pairs. For each set, we'll load them as a pair using ldmia. 39efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * This means that the register number of the temp we use for the key 40efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * must be lower than the reg for the displacement. 41efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * 42efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * The test loop will look something like: 43efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * 442700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee * adr r_base, <table> 45fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * ldr r_val, [rARM_SP, v_reg_off] 46fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * mov r_idx, #table_size 47efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * lp: 482700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee * ldmia r_base!, {r_key, r_disp} 49fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * sub r_idx, #1 50fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * cmp r_val, r_key 51efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * ifeq 52fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * add rARM_PC, r_disp ; This is the branch from which we compute displacement 53fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee * cbnz r_idx, lp 54efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 5548971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid ArmMir2Lir::GenLargeSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src) { 568d0d03e24325463f0060abfd05dba5598044e9b1Razvan A Lupusoru const uint16_t* table = mir_graph_->GetTable(mir, table_offset); 57efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Add the table to the list - we'll process it later 58fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee SwitchTable *tab_rec = 5983cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData)); 6072f53af0307b9109a1cfc0671675ce5d45c66d3aChao-ying Fu tab_rec->switch_mir = mir; 61fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->table = table; 621fd3346740dfb7f47be9922312b68a4227fada96buzbee tab_rec->vaddr = current_dalvik_offset_; 630d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee uint32_t size = table[1]; 64e39c54ea575ec710d5e84277fcdcc049f8acb3c9Vladimir Marko switch_tables_.push_back(tab_rec); 65efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 66efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Get the switch value 671fd3346740dfb7f47be9922312b68a4227fada96buzbee rl_src = LoadValue(rl_src, kCoreReg); 682700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_base = AllocTemp(); 69efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Allocate key and disp temps */ 702700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_key = AllocTemp(); 712700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_disp = AllocTemp(); 72fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee // Make sure r_key's register number is less than r_disp's number for ldmia 732700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee if (r_key.GetReg() > r_disp.GetReg()) { 742700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage tmp = r_disp; 75fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee r_disp = r_key; 76fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee r_key = tmp; 77efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 78efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Materialize a pointer to the switch table 792700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee NewLIR3(kThumb2Adr, r_base.GetReg(), 0, WrapPointer(tab_rec)); 80fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee // Set up r_idx 812700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage r_idx = AllocTemp(); 821fd3346740dfb7f47be9922312b68a4227fada96buzbee LoadConstant(r_idx, size); 83efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Establish loop branch target 841fd3346740dfb7f47be9922312b68a4227fada96buzbee LIR* target = NewLIR0(kPseudoTargetLabel); 85efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Load next key/disp 86091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetRegNum()) | (1 << r_disp.GetRegNum())); 872700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegReg(kOpCmp, r_key, rl_src.reg); 88efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Go if match. NOTE: No instruction set switch here - must stay Thumb2 893da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison LIR* it = OpIT(kCondEq, ""); 902700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* switch_branch = NewLIR1(kThumb2AddPCR, r_disp.GetReg()); 913da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison OpEndIT(it); 92fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->anchor = switch_branch; 93efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Needs to use setflags encoding here 94dbb8c49d540edd2a39076093163c7218f03aa502Vladimir Marko OpRegRegImm(kOpSub, r_idx, r_idx, 1); // For value == 1, this should set flags. 958dea81ca9c0201ceaa88086b927a5838a06a3e69Vladimir Marko DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode)); 961fd3346740dfb7f47be9922312b68a4227fada96buzbee OpCondBranch(kCondNe, target); 97efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 98efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 99efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 10048971b3242e5126bcd800cc9c68df64596b43d13Andreas Gampevoid ArmMir2Lir::GenLargePackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src) { 1018d0d03e24325463f0060abfd05dba5598044e9b1Razvan A Lupusoru const uint16_t* table = mir_graph_->GetTable(mir, table_offset); 102efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Add the table to the list - we'll process it later 103fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee SwitchTable *tab_rec = 10483cc7ae96d4176533dd0391a1591d321b0a87f4fVladimir Marko static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData)); 10572f53af0307b9109a1cfc0671675ce5d45c66d3aChao-ying Fu tab_rec->switch_mir = mir; 106fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->table = table; 1071fd3346740dfb7f47be9922312b68a4227fada96buzbee tab_rec->vaddr = current_dalvik_offset_; 1080d82948094d9a198e01aa95f64012bdedd5b6fc9buzbee uint32_t size = table[1]; 109e39c54ea575ec710d5e84277fcdcc049f8acb3c9Vladimir Marko switch_tables_.push_back(tab_rec); 110efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 111efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Get the switch value 1121fd3346740dfb7f47be9922312b68a4227fada96buzbee rl_src = LoadValue(rl_src, kCoreReg); 1132700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage table_base = AllocTemp(); 114efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Materialize a pointer to the switch table 1152700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee NewLIR3(kThumb2Adr, table_base.GetReg(), 0, WrapPointer(tab_rec)); 116fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee int low_key = s4FromSwitchData(&table[2]); 1172700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage keyReg; 118efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Remove the bias, if necessary 119fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee if (low_key == 0) { 1202700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee keyReg = rl_src.reg; 121efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } else { 1221fd3346740dfb7f47be9922312b68a4227fada96buzbee keyReg = AllocTemp(); 1232700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegRegImm(kOpSub, keyReg, rl_src.reg, low_key); 124efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 125efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Bounds check - if < 0 or >= size continue following switch 1261fd3346740dfb7f47be9922312b68a4227fada96buzbee OpRegImm(kOpCmp, keyReg, size-1); 1272cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* branch_over = OpCondBranch(kCondHi, nullptr); 128efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 129efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // Load the displacement from the switch table 1302700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage disp_reg = AllocTemp(); 131695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee LoadBaseIndexed(table_base, keyReg, disp_reg, 2, k32); 132efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 133efc6369224b036a1fb77849f7ae65b3492c832c0buzbee // ..and go! NOTE: No instruction set switch here - must stay Thumb2 1342700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* switch_branch = NewLIR1(kThumb2AddPCR, disp_reg.GetReg()); 135fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee tab_rec->anchor = switch_branch; 136efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 137fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee /* branch_over target here */ 1381fd3346740dfb7f47be9922312b68a4227fada96buzbee LIR* target = NewLIR0(kPseudoTargetLabel); 139fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee branch_over->target = target; 140efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 141efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 142efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* 143d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * Handle unlocked -> thin locked transition inline or else call out to quick entrypoint. For more 144d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * details see monitor.cc. 145efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 1462ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { 1471fd3346740dfb7f47be9922312b68a4227fada96buzbee FlushAllRegs(); 148695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee // FIXME: need separate LoadValues for object references. 1492700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LoadValueDirectFixed(rl_src, rs_r0); // Get obj 1501fd3346740dfb7f47be9922312b68a4227fada96buzbee LockCallTemps(); // Prepare for explicit register usage 151d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15. 152d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (kArchVariantHasGoodBranchPredictor) { 153f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison LIR* null_check_branch = nullptr; 154d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) { 155d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch = nullptr; // No null check. 156d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 157d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // If the null-check fails its handled by the slow-path to reduce exception related meta-data. 15869dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 1592cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, nullptr); 160f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison } 161d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 162695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 163091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 164091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 165f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison MarkPossibleNullPointerException(opt_flags); 166e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 167e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 1682cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_r3, 0, nullptr); 169e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // r1 is zero except for the rb bits here. Copy the read barrier bits into r2. 170e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegReg(kOpOr, rs_r2, rs_r2, rs_r1); 171091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR4(kThumb2Strex, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(), 172091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 1732cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* lock_success_branch = OpCmpImmBranch(kCondEq, rs_r1, 0, nullptr); 174d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 175d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 176d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); 177d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers not_unlocked_branch->target = slow_path_target; 178d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (null_check_branch != nullptr) { 179d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch->target = slow_path_target; 180d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 181d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // TODO: move to a slow path. 182d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Go expensive route - artLockObjectFromCode(obj); 183dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), rs_rARM_LR); 18431c2aac7137b69d5622eea09597500731fbee2efVladimir Marko ClobberCallerSave(); 1852700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR); 186d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers MarkSafepointPC(call_inst); 187d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 188d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* success_target = NewLIR0(kPseudoTargetLabel); 189d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers lock_success_branch->target = success_target; 19048f5c47907654350ce30a8dfdda0e977f5d3d39fHans Boehm GenMemBarrier(kLoadAny); 191d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 192d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Explicit null-check as slow-path is entered using an IT. 1932700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee GenNullCheck(rs_r0, opt_flags); 194695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 195091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 196091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 197f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison MarkPossibleNullPointerException(opt_flags); 198e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 199e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 200e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // r1 will be zero except for the rb bits if the following 201e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // cmp-and-branch branches to eq where r2 will be used. Copy the 202e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // read barrier bits into r2. 203e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegReg(kOpOr, rs_r2, rs_r2, rs_r1); 204e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegImm(kOpCmp, rs_r3, 0); 205e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi 2063da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison LIR* it = OpIT(kCondEq, ""); 207091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR4(kThumb2Strex/*eq*/, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(), 208091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee mirror::Object::MonitorOffset().Int32Value() >> 2); 2093da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison OpEndIT(it); 2102700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegImm(kOpCmp, rs_r1, 0); 2113da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison it = OpIT(kCondNe, "T"); 212d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Go expensive route - artLockObjectFromCode(self, obj); 213091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), 214091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee rs_rARM_LR); 21531c2aac7137b69d5622eea09597500731fbee2efVladimir Marko ClobberCallerSave(); 2162700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR); 2173da67a558f1fd3d8a157d8044d521753f3f99ac8Dave Allison OpEndIT(it); 218d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers MarkSafepointPC(call_inst); 21948f5c47907654350ce30a8dfdda0e977f5d3d39fHans Boehm GenMemBarrier(kLoadAny); 220d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 221efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 222efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 223efc6369224b036a1fb77849f7ae65b3492c832c0buzbee/* 224d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * Handle thin locked -> unlocked transition inline or else call out to quick entrypoint. For more 225d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * details see monitor.cc. Note the code below doesn't use ldrex/strex as the code holds the lock 226d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers * and can only give away ownership if its suspended. 227efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 2282ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { 2291fd3346740dfb7f47be9922312b68a4227fada96buzbee FlushAllRegs(); 2302700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LoadValueDirectFixed(rl_src, rs_r0); // Get obj 2311fd3346740dfb7f47be9922312b68a4227fada96buzbee LockCallTemps(); // Prepare for explicit register usage 232f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison LIR* null_check_branch = nullptr; 233695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 234d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15. 235d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (kArchVariantHasGoodBranchPredictor) { 236d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) { 237d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch = nullptr; // No null check. 238d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 239d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // If the null-check fails its handled by the slow-path to reduce exception related meta-data. 24069dfe51b684dd9d510dbcb63295fe180f998efdeDave Allison if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 2412cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, nullptr); 242f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison } 243d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 244e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 245e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Load32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); // Get lock 246e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 247e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 248e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 249e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 250f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison MarkPossibleNullPointerException(opt_flags); 251e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 252e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 253e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out except the read barrier bits. 254e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r1, rs_r1, LockWord::kReadBarrierStateMaskShifted); 2552cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_r3, rs_r2, nullptr); 25648f5c47907654350ce30a8dfdda0e977f5d3d39fHans Boehm GenMemBarrier(kAnyStore); 257e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* unlock_success_branch; 258e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 259e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Store32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); 2602cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier unlock_success_branch = OpUnconditionalBranch(nullptr); 261e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 262e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR4(kThumb2Strex, rs_r2.GetReg(), rs_r1.GetReg(), rs_r0.GetReg(), 263e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 2642cebb24bfc3247d3e9be138a3350106737455918Mathieu Chartier unlock_success_branch = OpCmpImmBranch(kCondEq, rs_r2, 0, nullptr); 265e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 266d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); 267d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers slow_unlock_branch->target = slow_path_target; 268d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers if (null_check_branch != nullptr) { 269d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers null_check_branch->target = slow_path_target; 270d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 271d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // TODO: move to a slow path. 272d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Go expensive route - artUnlockObjectFromCode(obj); 273dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(), rs_rARM_LR); 27431c2aac7137b69d5622eea09597500731fbee2efVladimir Marko ClobberCallerSave(); 2752700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR); 276d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers MarkSafepointPC(call_inst); 277d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers 278d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers LIR* success_target = NewLIR0(kPseudoTargetLabel); 279d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers unlock_success_branch->target = success_target; 280d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } else { 281d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Explicit null-check as slow-path is entered using an IT. 2822700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee GenNullCheck(rs_r0, opt_flags); 283e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 284e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Load32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); // Get lock 285e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 286e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // If we use read barriers, we need to use atomic instructions. 287e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(), 288e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 289e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 290b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison MarkPossibleNullPointerException(opt_flags); 291695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2); 292e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out the read barrier bits. 293e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled); 294e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Zero out except the read barrier bits. 295e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegRegImm(kOpAnd, rs_r1, rs_r1, LockWord::kReadBarrierStateMaskShifted); 296d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers // Is lock unheld on lock or held by us (==thread_id) on unlock? 297e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegReg(kOpCmp, rs_r3, rs_r2); 298e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (!kUseReadBarrier) { 299e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* it = OpIT(kCondEq, "EE"); 300e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (GenMemBarrier(kAnyStore)) { 301e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi UpdateIT(it, "TEE"); 302e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 303e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi Store32Disp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); 304e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Go expensive route - UnlockObjectFromCode(obj); 305e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(), 306e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi rs_rARM_LR); 307e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi ClobberCallerSave(); 308e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR); 309e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpEndIT(it); 310e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi MarkSafepointPC(call_inst); 311e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } else { 312e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // If we use read barriers, we need to use atomic instructions. 313e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* it = OpIT(kCondEq, ""); 314e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi if (GenMemBarrier(kAnyStore)) { 315e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi UpdateIT(it, "T"); 316e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi } 317e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi NewLIR4/*eq*/(kThumb2Strex, rs_r2.GetReg(), rs_r1.GetReg(), rs_r0.GetReg(), 318e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi mirror::Object::MonitorOffset().Int32Value() >> 2); 319e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpEndIT(it); 320e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Since we know r2 wasn't zero before the above it instruction, 321e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // if r2 is zero here, we know r3 was equal to r2 and the strex 322e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // suceeded (we're done). Otherwise (either r3 wasn't equal to r2 323e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // or the strex failed), call the entrypoint. 324e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpRegImm(kOpCmp, rs_r2, 0); 325e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* it2 = OpIT(kCondNe, "T"); 326e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi // Go expensive route - UnlockObjectFromCode(obj); 327e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(), 328e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi rs_rARM_LR); 329e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi ClobberCallerSave(); 330e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR); 331e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi OpEndIT(it2); 332e15ea086439b41a805d164d2beb07b4ba96aaa97Hiroshi Yamauchi MarkSafepointPC(call_inst); 333b14329f90f725af0f67c45dfcb94933a426d63ceAndreas Gampe } 334d9c4fc94fa618617f94e1de9af5f034549100753Ian Rogers } 335efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 336efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 3372ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenMoveException(RegLocation rl_dest) { 338dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers int ex_offset = Thread::ExceptionOffset<4>().Int32Value(); 339a0cd2d701f29e0bc6275f1b13c0edfd4ec391879buzbee RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); 340a0cd2d701f29e0bc6275f1b13c0edfd4ec391879buzbee RegStorage reset_reg = AllocTempRef(); 3413c12c512faf6837844d5465b23b9410889e5eb11Andreas Gampe LoadRefDisp(rs_rARM_SELF, ex_offset, rl_result.reg, kNotVolatile); 3421fd3346740dfb7f47be9922312b68a4227fada96buzbee LoadConstant(reset_reg, 0); 3433c12c512faf6837844d5465b23b9410889e5eb11Andreas Gampe StoreRefDisp(rs_rARM_SELF, ex_offset, reset_reg, kNotVolatile); 3441fd3346740dfb7f47be9922312b68a4227fada96buzbee FreeTemp(reset_reg); 3451fd3346740dfb7f47be9922312b68a4227fada96buzbee StoreValue(rl_dest, rl_result); 3461eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao} 3471eab958cde39a7e2f0e5ce01730f4e2e75c72519jeffhao 348bf535be514570fc33fc0a6347a87dcd9097d9bfdVladimir Markovoid ArmMir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) { 3492700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage reg_card_base = AllocTemp(); 3502700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee RegStorage reg_card_no = AllocTemp(); 351dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers LoadWordDisp(rs_rARM_SELF, Thread::CardTableOffset<4>().Int32Value(), reg_card_base); 3521d54e73444e017d3a65234e0f193846f3e27472bIan Rogers OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift); 3532700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte); 3541fd3346740dfb7f47be9922312b68a4227fada96buzbee FreeTemp(reg_card_base); 3551fd3346740dfb7f47be9922312b68a4227fada96buzbee FreeTemp(reg_card_no); 356efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 357efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 3581109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbeckystatic dwarf::Reg DwarfCoreReg(int num) { 3591109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky return dwarf::Reg::ArmCore(num); 3601109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky} 3611109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky 3621109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbeckystatic dwarf::Reg DwarfFpReg(int num) { 3631109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky return dwarf::Reg::ArmFp(num); 3641109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky} 3651109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky 3662ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { 3671109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky DCHECK_EQ(cfi_.GetCurrentCFAOffset(), 0); // empty stack. 3681fd3346740dfb7f47be9922312b68a4227fada96buzbee int spill_count = num_core_spills_ + num_fp_spills_; 369efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 370efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * On entry, r0, r1, r2 & r3 are live. Let the register allocation 371efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * mechanism know so it doesn't try to use any of them when 372efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * expanding the frame or flushing. This leaves the utility 373efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * code with a single temp: r12. This should be enough. 374efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 375091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r0); 376091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r1); 377091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r2); 378091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r3); 379efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 380efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 381efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * We can safely skip the stack overflow check if we're 382efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * a leaf *and* our frame size < fudge factor. 383efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 384648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, kArm); 385648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison const size_t kStackOverflowReservedUsableBytes = GetStackOverflowReservedBytes(kArm); 3867cd26f355ba83be75b72ed628ed5ee84a3245c4fAndreas Gampe bool large_frame = (static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes); 387648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison bool generate_explicit_stack_overflow_check = large_frame || 388648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison !cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks(); 389fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee if (!skip_overflow_check) { 390648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison if (generate_explicit_stack_overflow_check) { 391fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee if (!large_frame) { 392fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee /* Load stack limit */ 393fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee LockTemp(rs_r12); 394fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12); 395fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee } 3965cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison } else { 3975cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Implicit stack overflow check. 3985cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Generate a load from [sp, #-overflowsize]. If this is in the stack 3995cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // redzone we will get a segmentation fault. 4005cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // 4015cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Caveat coder: if someone changes the kStackOverflowReservedBytes value 4025cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // we need to make sure that it's loadable in an immediate field of 4035cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // a sub instruction. Otherwise we will get a temp allocation and the 4045cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // code size will increase. 4055cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // 4065cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // This is done before the callee save instructions to avoid any possibility 4075cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // of these overflowing. This uses r12 and that's never saved in a callee 4085cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // save. 4097ea6f79bbddd69d5db86a8656a31aaaf64ae2582Andreas Gampe OpRegRegImm(kOpSub, rs_r12, rs_rARM_SP, GetStackOverflowReservedBytes(kArm)); 4105cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison Load32Disp(rs_r12, 0, rs_r12); 4115cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison MarkPossibleStackOverflowException(); 412b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison } 413efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 414efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Spill core callee saves */ 4151109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (core_spill_mask_ != 0u) { 4161109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_LR.GetRegNum()))) == 0u) { 4171109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // Spilling only low regs and/or LR, use 16-bit PUSH. 4181109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky constexpr int lr_bit_shift = rs_rARM_LR.GetRegNum() - 8; 4191109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumbPush, 4201109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) | 4211109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky ((core_spill_mask_ & (1u << rs_rARM_LR.GetRegNum())) >> lr_bit_shift)); 4221109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else if (IsPowerOfTwo(core_spill_mask_)) { 4231109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // kThumb2Push cannot be used to spill a single register. 4241109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Push1, CTZ(core_spill_mask_)); 4251109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else { 4261109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Push, core_spill_mask_); 4271109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } 4281109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(num_core_spills_ * kArmPointerSize); 4291109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RelOffsetForMany(DwarfCoreReg(0), 0, core_spill_mask_, kArmPointerSize); 4309d5c25acdd1e9635fde8f8bf52a126b4d371dabdVladimir Marko } 431efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Need to spill any FP regs? */ 4321109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (num_fp_spills_ != 0u) { 433efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 434efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * NOTE: fp spills are a little different from core spills in that 435efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * they are pushed as a contiguous block. When promoting from 436efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * the fp set, we must allocate all singles from s16..highest-promoted 437efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 4381fd3346740dfb7f47be9922312b68a4227fada96buzbee NewLIR1(kThumb2VPushCS, num_fp_spills_); 4391109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(num_fp_spills_ * kArmPointerSize); 4401109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RelOffsetForMany(DwarfFpReg(0), 0, fp_spill_mask_, kArmPointerSize); 441efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 4420d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier 44305a48b1f8e62564abb7c2fe674e3234d5861647fMathieu Chartier const int spill_size = spill_count * 4; 44405a48b1f8e62564abb7c2fe674e3234d5861647fMathieu Chartier const int frame_size_without_spills = frame_size_ - spill_size; 445fa57c47f1b72916371a9c2d5c1389219bce655b4buzbee if (!skip_overflow_check) { 446648d7112609dd19c38131b3e71c37bcbbd19d11eDave Allison if (generate_explicit_stack_overflow_check) { 4470d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier class StackOverflowSlowPath : public LIRSlowPath { 4480d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier public: 4490d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, bool restore_lr, size_t sp_displace) 4500b40ecf156e309aa17c72a28cd1b0237dbfb8746Vladimir Marko : LIRSlowPath(m2l, branch), restore_lr_(restore_lr), 4510d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier sp_displace_(sp_displace) { 4520d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 4530d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier void Compile() OVERRIDE { 4540d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier m2l_->ResetRegPool(); 4550d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier m2l_->ResetDefTracking(); 4566ffcfa04ebb2660e238742a6000f5ccebdd5df15Mingyao Yang GenerateTargetLabel(kPseudoThrowTarget); 4570d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier if (restore_lr_) { 4582700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee m2l_->LoadWordDisp(rs_rARM_SP, sp_displace_ - 4, rs_rARM_LR); 4590d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 4602700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee m2l_->OpRegImm(kOpAdd, rs_rARM_SP, sp_displace_); 4611109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky m2l_->cfi().AdjustCFAOffset(-sp_displace_); 4620d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier m2l_->ClobberCallerSave(); 463dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers ThreadOffset<4> func_offset = QUICK_ENTRYPOINT_OFFSET(4, pThrowStackOverflow); 4640d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier // Load the entrypoint directly into the pc instead of doing a load + branch. Assumes 4650d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier // codegen and target are in thumb2 mode. 466695d13a82d6dd801aaa57a22a9d4b3f6db0d0fdbbuzbee // NOTE: native pointer. 4672700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee m2l_->LoadWordDisp(rs_rARM_SELF, func_offset.Int32Value(), rs_rARM_PC); 4681109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky m2l_->cfi().AdjustCFAOffset(sp_displace_); 4690d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 4700d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier 4710d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier private: 4720d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier const bool restore_lr_; 4730d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier const size_t sp_displace_; 4740d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier }; 475fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee if (large_frame) { 476fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee // Note: may need a temp reg, and we only have r12 free at this point. 4772700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegRegImm(kOpSub, rs_rARM_LR, rs_rARM_SP, frame_size_without_spills); 478fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12); 4792700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_LR, rs_r12, nullptr); 4800d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier // Need to restore LR since we used it as a temp. 48105a48b1f8e62564abb7c2fe674e3234d5861647fMathieu Chartier AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, true, spill_size)); 4822700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegCopy(rs_rARM_SP, rs_rARM_LR); // Establish stack 4831109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 4840d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } else { 485fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee /* 486fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee * If the frame is small enough we are guaranteed to have enough space that remains to 487fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee * handle signals on the user stack. However, we may not have any free temp 488fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee * registers at this point, so we'll temporarily add LR to the temp pool. 489fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee */ 490fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee DCHECK(!GetRegInfo(rs_rARM_LR)->IsTemp()); 491fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee MarkTemp(rs_rARM_LR); 492fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee FreeTemp(rs_rARM_LR); 4932700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegRegImm(kOpSub, rs_rARM_SP, rs_rARM_SP, frame_size_without_spills); 4941109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 495fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee Clobber(rs_rARM_LR); 496fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee UnmarkTemp(rs_rARM_LR); 4972700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_SP, rs_r12, nullptr); 4980d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, false, frame_size_)); 4990d507d1e0441e6bd6f3affca3a60774ea920f317Mathieu Chartier } 500b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison } else { 5015cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // Implicit stack overflow check has already been done. Just make room on the 5025cd33753b96d92c03e3cb10cb802e68fb6ef2f21Dave Allison // stack for the frame now. 503f943914730db8ad2ff03d49a2cacd31885d08fd7Dave Allison OpRegImm(kOpSub, rs_rARM_SP, frame_size_without_spills); 5041109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 505b373e091eac39b1a79c11f2dcbd610af01e9e8a9Dave Allison } 506efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } else { 5072700f7e1edbcd2518f4978e4cd0e05a4149f91b6buzbee OpRegImm(kOpSub, rs_rARM_SP, frame_size_without_spills); 5081109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_without_spills); 509efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 510efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5111fd3346740dfb7f47be9922312b68a4227fada96buzbee FlushIns(ArgLocs, rl_method); 512efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 513cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko // We can promote a PC-relative reference to dex cache arrays to a register 514cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko // if it's used at least twice. Without investigating where we should lazily 515cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko // load the reference, we conveniently load it after flushing inputs. 516cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko if (dex_cache_arrays_base_reg_.Valid()) { 517cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko OpPcRelDexCacheArrayAddr(cu_->dex_file, dex_cache_arrays_min_offset_, 518cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko dex_cache_arrays_base_reg_); 519cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko } 520cc23481b66fd1f2b459d82da4852073e32f033aaVladimir Marko 521091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r0); 522091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r1); 523091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r2); 524091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee FreeTemp(rs_r3); 525fe8cf8b1c1b4af0f8b4bb639576f7a5fc59f52eaBill Buzbee FreeTemp(rs_r12); 526efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 527efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5282ce745c06271d5223d57dbf08117b20d5b60694aBrian Carlstromvoid ArmMir2Lir::GenExitSequence() { 5291109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RememberState(); 5301fd3346740dfb7f47be9922312b68a4227fada96buzbee int spill_count = num_core_spills_ + num_fp_spills_; 5311109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky 532efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* 533efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * In the exit path, r0/r1 are live - make sure they aren't 534efc6369224b036a1fb77849f7ae65b3492c832c0buzbee * allocated by the register utilities as temps. 535efc6369224b036a1fb77849f7ae65b3492c832c0buzbee */ 536091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r0); 537091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee LockTemp(rs_r1); 538efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5391109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky int adjust = frame_size_ - (spill_count * kArmPointerSize); 5401109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky OpRegImm(kOpAdd, rs_rARM_SP, adjust); 5411109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-adjust); 542efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* Need to restore any FP callee saves? */ 5431fd3346740dfb7f47be9922312b68a4227fada96buzbee if (num_fp_spills_) { 5441fd3346740dfb7f47be9922312b68a4227fada96buzbee NewLIR1(kThumb2VPopCS, num_fp_spills_); 5451109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-num_fp_spills_ * kArmPointerSize); 5461109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreMany(DwarfFpReg(0), fp_spill_mask_); 547efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 5481109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky bool unspill_LR_to_PC = (core_spill_mask_ & (1 << rs_rARM_LR.GetRegNum())) != 0; 5491109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (unspill_LR_to_PC) { 550091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee core_spill_mask_ &= ~(1 << rs_rARM_LR.GetRegNum()); 551091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee core_spill_mask_ |= (1 << rs_rARM_PC.GetRegNum()); 552efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 5531109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (core_spill_mask_ != 0u) { 5541109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_PC.GetRegNum()))) == 0u) { 5551109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // Unspilling only low regs and/or PC, use 16-bit POP. 5561109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky constexpr int pc_bit_shift = rs_rARM_PC.GetRegNum() - 8; 5571109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumbPop, 5581109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky (core_spill_mask_ & ~(1u << rs_rARM_PC.GetRegNum())) | 5591109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky ((core_spill_mask_ & (1u << rs_rARM_PC.GetRegNum())) >> pc_bit_shift)); 5601109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else if (IsPowerOfTwo(core_spill_mask_)) { 5611109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // kThumb2Pop cannot be used to unspill a single register. 5621109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Pop1, CTZ(core_spill_mask_)); 5631109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } else { 5641109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky NewLIR1(kThumb2Pop, core_spill_mask_); 5651109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } 5661109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // If we pop to PC, there is no further epilogue code. 5671109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (!unspill_LR_to_PC) { 5681109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-num_core_spills_ * kArmPointerSize); 5691109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreMany(DwarfCoreReg(0), core_spill_mask_); 5701109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky DCHECK_EQ(cfi_.GetCurrentCFAOffset(), 0); // empty stack. 5711109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky } 5729d5c25acdd1e9635fde8f8bf52a126b4d371dabdVladimir Marko } 5731109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky if (!unspill_LR_to_PC) { 574efc6369224b036a1fb77849f7ae65b3492c832c0buzbee /* We didn't pop to rARM_PC, so must do a bv rARM_LR */ 575091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR1(kThumbBx, rs_rARM_LR.GetReg()); 576efc6369224b036a1fb77849f7ae65b3492c832c0buzbee } 5771109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // The CFI should be restored for any code that follows the exit block. 5781109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreState(); 5791109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.DefCFAOffset(frame_size_); 580efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} 581efc6369224b036a1fb77849f7ae65b3492c832c0buzbee 5823bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoruvoid ArmMir2Lir::GenSpecialExitSequence() { 583091cc408e9dc87e60fb64c61e186bea568fc3d3abuzbee NewLIR1(kThumbBx, rs_rARM_LR.GetReg()); 5843bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru} 5853bc01748ef1c3e43361bdf520947a9d656658bf8Razvan A Lupusoru 5866ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Markovoid ArmMir2Lir::GenSpecialEntryForSuspend() { 5876ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko // Keep 16-byte stack alignment - push r0, i.e. ArtMethod*, r5, r6, lr. 5886ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko DCHECK(!IsTemp(rs_r5)); 5896ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko DCHECK(!IsTemp(rs_r6)); 5906ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko core_spill_mask_ = 5916ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko (1u << rs_r5.GetRegNum()) | (1u << rs_r6.GetRegNum()) | (1u << rs_rARM_LR.GetRegNum()); 5926ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko num_core_spills_ = 3u; 5936ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko fp_spill_mask_ = 0u; 5946ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko num_fp_spills_ = 0u; 5956ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko frame_size_ = 16u; 5966ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko core_vmap_table_.clear(); 5976ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko fp_vmap_table_.clear(); 5986ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko NewLIR1(kThumbPush, (1u << rs_r0.GetRegNum()) | // ArtMethod* 5996ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) | // Spills other than LR. 6006ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko (1u << 8)); // LR encoded for 16-bit push. 6011109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(frame_size_); 6021109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky // Do not generate CFI for scratch register r0. 6031109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RelOffsetForMany(DwarfCoreReg(0), 4, core_spill_mask_, kArmPointerSize); 6046ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko} 6056ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko 6066ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Markovoid ArmMir2Lir::GenSpecialExitForSuspend() { 6076ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko // Pop the frame. (ArtMethod* no longer needed but restore it anyway.) 6086ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko NewLIR1(kThumb2Pop, (1u << rs_r0.GetRegNum()) | core_spill_mask_); // 32-bit because of LR. 6091109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.AdjustCFAOffset(-frame_size_); 6101109fb3cacc8bb667979780c2b4b12ce5bb64549David Srbecky cfi_.RestoreMany(DwarfCoreReg(0), core_spill_mask_); 6116ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko} 6126ce3eba0f2e6e505ed408cdc40d213c8a512238dVladimir Marko 613f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Markostatic bool ArmUseRelativeCall(CompilationUnit* cu, const MethodReference& target_method) { 614f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Emit relative calls only within a dex file due to the limited range of the BL insn. 615f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return cu->dex_file == target_method.dex_file; 616f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 617f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 618f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko/* 619f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko * Bit of a hack here - in the absence of a real scheduling pass, 620f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko * emit the next instruction in static & direct invoke sequences. 621f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko */ 622e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Markoint ArmMir2Lir::ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED, 623e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko int state, const MethodReference& target_method, 624e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko uint32_t unused_idx ATTRIBUTE_UNUSED, 625e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko uintptr_t direct_code, uintptr_t direct_method, 626e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko InvokeType type) { 627e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko ArmMir2Lir* cg = static_cast<ArmMir2Lir*>(cu->cg.get()); 628f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code != 0 && direct_method != 0) { 629f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko switch (state) { 630f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 0: // Get the current Method* [sets kArg0] 631f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code != static_cast<uintptr_t>(-1)) { 632f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code); 633f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else if (ArmUseRelativeCall(cu, target_method)) { 634f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Defer to linker patch. 635f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 636f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadCodeAddress(target_method, type, kInvokeTgt); 637f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 638f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_method != static_cast<uintptr_t>(-1)) { 639f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method); 640f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 641f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadMethodAddress(target_method, type, kArg0); 642f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 643f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko break; 644f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko default: 645f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return -1; 646f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 647f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 648e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko bool use_pc_rel = cg->CanUseOpPcRelDexCacheArrayLoad(); 649f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); 650f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko switch (state) { 651f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 0: // Get the current Method* [sets kArg0] 652f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // TUNING: we can save a reg copy if Method* has been promoted. 653e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel) { 654e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko cg->LoadCurrMethodDirect(arg0_ref); 655e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko break; 656e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 657e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko ++state; 658e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko FALLTHROUGH_INTENDED; 659f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 1: // Get method->dex_cache_resolved_methods_ 660e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel) { 661e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko cg->LoadRefDisp(arg0_ref, 662e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), 663e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko arg0_ref, 664e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko kNotVolatile); 665e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 666f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Set up direct code if known. 667f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code != 0) { 668f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code != static_cast<uintptr_t>(-1)) { 669f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code); 670f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else if (ArmUseRelativeCall(cu, target_method)) { 671f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Defer to linker patch. 672f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 673f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); 674f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadCodeAddress(target_method, type, kInvokeTgt); 675f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 676f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 677e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel || direct_code != 0) { 678e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko break; 679e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 680e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko ++state; 681e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko FALLTHROUGH_INTENDED; 682f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 2: // Grab target method* 683f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko CHECK_EQ(cu->dex_file, target_method.dex_file); 684e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko if (!use_pc_rel) { 685e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko cg->LoadRefDisp(arg0_ref, 686e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko mirror::ObjectArray<mirror::Object>::OffsetOfElement( 687e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko target_method.dex_method_index).Int32Value(), 688e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko arg0_ref, 689e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko kNotVolatile); 690e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } else { 691e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index); 692e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, arg0_ref); 693e5c76c515a481074aaa6b869aa16490a47ba98bcVladimir Marko } 694f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko break; 695f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko case 3: // Grab the code from the method* 696f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (direct_code == 0) { 697f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // kInvokeTgt := arg0_ref->entrypoint 698f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko cg->LoadWordDisp(arg0_ref, 6992d7210188805292e463be4bcf7a133b654d7e0eaMathieu Chartier mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 7002d7210188805292e463be4bcf7a133b654d7e0eaMathieu Chartier kArmPointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt)); 701f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 702f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko break; 703f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko default: 704f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return -1; 705f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 706f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 707f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return state + 1; 708f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 709f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 710f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir MarkoNextCallInsn ArmMir2Lir::GetNextSDCallInsn() { 711f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return ArmNextSDCallInsn; 712f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 713f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 714f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir MarkoLIR* ArmMir2Lir::CallWithLinkerFixup(const MethodReference& target_method, InvokeType type) { 715f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // For ARM, just generate a relative BL instruction that will be filled in at 'link time'. 716f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // If the target turns out to be too far, the linker will generate a thunk for dispatch. 717f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko int target_method_idx = target_method.dex_method_index; 718f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko const DexFile* target_dex_file = target_method.dex_file; 719f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 720f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // Generate the call instruction and save index, dex_file, and type. 721f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // NOTE: Method deduplication takes linker patches into account, so we can just pass 0 722f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko // as a placeholder for the offset. 723f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko LIR* call = RawLIR(current_dalvik_offset_, kThumb2Bl, 0, 724f6737f7ed741b15cfd60c2530dab69f897540735Vladimir Marko target_method_idx, WrapPointer(target_dex_file), type); 725f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko AppendLIR(call); 726f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko call_method_insns_.push_back(call); 727f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return call; 728f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 729f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 730f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir MarkoLIR* ArmMir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info) { 731f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko LIR* call_insn; 732f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko if (method_info.FastPath() && ArmUseRelativeCall(cu_, method_info.GetTargetMethod()) && 733f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko (method_info.GetSharpType() == kDirect || method_info.GetSharpType() == kStatic) && 734f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko method_info.DirectCode() == static_cast<uintptr_t>(-1)) { 735f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko call_insn = CallWithLinkerFixup(method_info.GetTargetMethod(), method_info.GetSharpType()); 736f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } else { 737f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko call_insn = OpReg(kOpBlx, TargetPtrReg(kInvokeTgt)); 738f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko } 739f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko return call_insn; 740f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko} 741f4da675bbc4615c5f854c81964cac9dd1153baeaVladimir Marko 742efc6369224b036a1fb77849f7ae65b3492c832c0buzbee} // namespace art 743