blob: 981ab2c1eeef34dd94c9e8d1945746dd932993aa [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* This file contains codegen for the Thumb2 ISA. */
18
Brian Carlstrom7940e442013-07-12 13:46:57 -070019#include "codegen_arm.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080020
21#include "arm_lir.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070022#include "art_method.h"
Vladimir Marko80afd022015-05-19 18:08:00 +010023#include "base/bit_utils.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080024#include "base/logging.h"
25#include "dex/mir_graph.h"
Jeff Hao848f70a2014-01-15 13:49:50 -080026#include "dex/quick/dex_file_to_method_inliner_map.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070027#include "dex/quick/mir_to_lir-inl.h"
Andreas Gampe0b9203e2015-01-22 20:39:27 -080028#include "driver/compiler_driver.h"
Vladimir Marko20f85592015-03-19 10:07:02 +000029#include "driver/compiler_options.h"
Ian Rogers576ca0c2014-06-06 15:58:22 -070030#include "gc/accounting/card_table.h"
Vladimir Markof4da6752014-08-01 19:04:18 +010031#include "mirror/object_array-inl.h"
Ian Rogers166db042013-07-26 12:05:57 -070032#include "entrypoints/quick/quick_entrypoints.h"
Vladimir Markoe5c76c52015-04-06 12:10:19 +010033#include "utils/dex_cache_arrays_layout-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070034
35namespace art {
36
Brian Carlstrom7940e442013-07-12 13:46:57 -070037/*
38 * The sparse table in the literal pool is an array of <key,displacement>
39 * pairs. For each set, we'll load them as a pair using ldmia.
40 * This means that the register number of the temp we use for the key
41 * must be lower than the reg for the displacement.
42 *
43 * The test loop will look something like:
44 *
buzbee2700f7e2014-03-07 09:46:20 -080045 * adr r_base, <table>
Brian Carlstrom7940e442013-07-12 13:46:57 -070046 * ldr r_val, [rARM_SP, v_reg_off]
47 * mov r_idx, #table_size
48 * lp:
buzbee2700f7e2014-03-07 09:46:20 -080049 * ldmia r_base!, {r_key, r_disp}
Brian Carlstrom7940e442013-07-12 13:46:57 -070050 * sub r_idx, #1
51 * cmp r_val, r_key
52 * ifeq
53 * add rARM_PC, r_disp ; This is the branch from which we compute displacement
54 * cbnz r_idx, lp
55 */
Andreas Gampe48971b32014-08-06 10:09:01 -070056void ArmMir2Lir::GenLargeSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src) {
Razvan A Lupusoru8d0d03e2014-06-06 17:04:52 -070057 const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -070058 // Add the table to the list - we'll process it later
59 SwitchTable *tab_rec =
Vladimir Marko83cc7ae2014-02-12 18:02:05 +000060 static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData));
Chao-ying Fu72f53af2014-11-11 16:48:40 -080061 tab_rec->switch_mir = mir;
Brian Carlstrom7940e442013-07-12 13:46:57 -070062 tab_rec->table = table;
63 tab_rec->vaddr = current_dalvik_offset_;
buzbee0d829482013-10-11 15:24:55 -070064 uint32_t size = table[1];
Vladimir Markoe39c54e2014-09-22 14:50:02 +010065 switch_tables_.push_back(tab_rec);
Brian Carlstrom7940e442013-07-12 13:46:57 -070066
67 // Get the switch value
68 rl_src = LoadValue(rl_src, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -080069 RegStorage r_base = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -070070 /* Allocate key and disp temps */
buzbee2700f7e2014-03-07 09:46:20 -080071 RegStorage r_key = AllocTemp();
72 RegStorage r_disp = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -070073 // Make sure r_key's register number is less than r_disp's number for ldmia
buzbee2700f7e2014-03-07 09:46:20 -080074 if (r_key.GetReg() > r_disp.GetReg()) {
75 RegStorage tmp = r_disp;
Brian Carlstrom7940e442013-07-12 13:46:57 -070076 r_disp = r_key;
77 r_key = tmp;
78 }
79 // Materialize a pointer to the switch table
buzbee2700f7e2014-03-07 09:46:20 -080080 NewLIR3(kThumb2Adr, r_base.GetReg(), 0, WrapPointer(tab_rec));
Brian Carlstrom7940e442013-07-12 13:46:57 -070081 // Set up r_idx
buzbee2700f7e2014-03-07 09:46:20 -080082 RegStorage r_idx = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -070083 LoadConstant(r_idx, size);
84 // Establish loop branch target
85 LIR* target = NewLIR0(kPseudoTargetLabel);
86 // Load next key/disp
buzbee091cc402014-03-31 10:14:40 -070087 NewLIR2(kThumb2LdmiaWB, r_base.GetReg(), (1 << r_key.GetRegNum()) | (1 << r_disp.GetRegNum()));
buzbee2700f7e2014-03-07 09:46:20 -080088 OpRegReg(kOpCmp, r_key, rl_src.reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -070089 // Go if match. NOTE: No instruction set switch here - must stay Thumb2
Dave Allison3da67a52014-04-02 17:03:45 -070090 LIR* it = OpIT(kCondEq, "");
buzbee2700f7e2014-03-07 09:46:20 -080091 LIR* switch_branch = NewLIR1(kThumb2AddPCR, r_disp.GetReg());
Dave Allison3da67a52014-04-02 17:03:45 -070092 OpEndIT(it);
Brian Carlstrom7940e442013-07-12 13:46:57 -070093 tab_rec->anchor = switch_branch;
94 // Needs to use setflags encoding here
Vladimir Markodbb8c492014-02-28 17:36:39 +000095 OpRegRegImm(kOpSub, r_idx, r_idx, 1); // For value == 1, this should set flags.
Vladimir Marko8dea81c2014-06-06 14:50:36 +010096 DCHECK(last_lir_insn_->u.m.def_mask->HasBit(ResourceMask::kCCode));
Brian Carlstrom7940e442013-07-12 13:46:57 -070097 OpCondBranch(kCondNe, target);
98}
99
100
Andreas Gampe48971b32014-08-06 10:09:01 -0700101void ArmMir2Lir::GenLargePackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src) {
Razvan A Lupusoru8d0d03e2014-06-06 17:04:52 -0700102 const uint16_t* table = mir_graph_->GetTable(mir, table_offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700103 // Add the table to the list - we'll process it later
104 SwitchTable *tab_rec =
Vladimir Marko83cc7ae2014-02-12 18:02:05 +0000105 static_cast<SwitchTable*>(arena_->Alloc(sizeof(SwitchTable), kArenaAllocData));
Chao-ying Fu72f53af2014-11-11 16:48:40 -0800106 tab_rec->switch_mir = mir;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700107 tab_rec->table = table;
108 tab_rec->vaddr = current_dalvik_offset_;
buzbee0d829482013-10-11 15:24:55 -0700109 uint32_t size = table[1];
Vladimir Markoe39c54e2014-09-22 14:50:02 +0100110 switch_tables_.push_back(tab_rec);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700111
112 // Get the switch value
113 rl_src = LoadValue(rl_src, kCoreReg);
buzbee2700f7e2014-03-07 09:46:20 -0800114 RegStorage table_base = AllocTemp();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700115 // Materialize a pointer to the switch table
buzbee2700f7e2014-03-07 09:46:20 -0800116 NewLIR3(kThumb2Adr, table_base.GetReg(), 0, WrapPointer(tab_rec));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117 int low_key = s4FromSwitchData(&table[2]);
buzbee2700f7e2014-03-07 09:46:20 -0800118 RegStorage keyReg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700119 // Remove the bias, if necessary
120 if (low_key == 0) {
buzbee2700f7e2014-03-07 09:46:20 -0800121 keyReg = rl_src.reg;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700122 } else {
123 keyReg = AllocTemp();
buzbee2700f7e2014-03-07 09:46:20 -0800124 OpRegRegImm(kOpSub, keyReg, rl_src.reg, low_key);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125 }
126 // Bounds check - if < 0 or >= size continue following switch
127 OpRegImm(kOpCmp, keyReg, size-1);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700128 LIR* branch_over = OpCondBranch(kCondHi, nullptr);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700129
130 // Load the displacement from the switch table
buzbee2700f7e2014-03-07 09:46:20 -0800131 RegStorage disp_reg = AllocTemp();
buzbee695d13a2014-04-19 13:32:20 -0700132 LoadBaseIndexed(table_base, keyReg, disp_reg, 2, k32);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700133
134 // ..and go! NOTE: No instruction set switch here - must stay Thumb2
buzbee2700f7e2014-03-07 09:46:20 -0800135 LIR* switch_branch = NewLIR1(kThumb2AddPCR, disp_reg.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700136 tab_rec->anchor = switch_branch;
137
138 /* branch_over target here */
139 LIR* target = NewLIR0(kPseudoTargetLabel);
140 branch_over->target = target;
141}
142
143/*
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700144 * Handle unlocked -> thin locked transition inline or else call out to quick entrypoint. For more
145 * details see monitor.cc.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700146 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700147void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700148 FlushAllRegs();
buzbee695d13a2014-04-19 13:32:20 -0700149 // FIXME: need separate LoadValues for object references.
buzbee2700f7e2014-03-07 09:46:20 -0800150 LoadValueDirectFixed(rl_src, rs_r0); // Get obj
Brian Carlstrom7940e442013-07-12 13:46:57 -0700151 LockCallTemps(); // Prepare for explicit register usage
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700152 constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15.
153 if (kArchVariantHasGoodBranchPredictor) {
Dave Allisonf9439142014-03-27 15:10:22 -0700154 LIR* null_check_branch = nullptr;
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700155 if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) {
156 null_check_branch = nullptr; // No null check.
157 } else {
158 // If the null-check fails its handled by the slow-path to reduce exception related meta-data.
Dave Allison69dfe512014-07-11 17:11:58 +0000159 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700160 null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, nullptr);
Dave Allisonf9439142014-03-27 15:10:22 -0700161 }
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700162 }
buzbee695d13a2014-04-19 13:32:20 -0700163 Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
buzbee091cc402014-03-31 10:14:40 -0700164 NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
165 mirror::Object::MonitorOffset().Int32Value() >> 2);
Dave Allisonf9439142014-03-27 15:10:22 -0700166 MarkPossibleNullPointerException(opt_flags);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800167 // Zero out the read barrier bits.
168 OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700169 LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_r3, 0, nullptr);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800170 // r1 is zero except for the rb bits here. Copy the read barrier bits into r2.
171 OpRegRegReg(kOpOr, rs_r2, rs_r2, rs_r1);
buzbee091cc402014-03-31 10:14:40 -0700172 NewLIR4(kThumb2Strex, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(),
173 mirror::Object::MonitorOffset().Int32Value() >> 2);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700174 LIR* lock_success_branch = OpCmpImmBranch(kCondEq, rs_r1, 0, nullptr);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700175
176
177 LIR* slow_path_target = NewLIR0(kPseudoTargetLabel);
178 not_unlocked_branch->target = slow_path_target;
179 if (null_check_branch != nullptr) {
180 null_check_branch->target = slow_path_target;
181 }
182 // TODO: move to a slow path.
183 // Go expensive route - artLockObjectFromCode(obj);
Ian Rogersdd7624d2014-03-14 17:43:00 -0700184 LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(), rs_rARM_LR);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000185 ClobberCallerSave();
buzbee2700f7e2014-03-07 09:46:20 -0800186 LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700187 MarkSafepointPC(call_inst);
188
189 LIR* success_target = NewLIR0(kPseudoTargetLabel);
190 lock_success_branch->target = success_target;
Hans Boehm48f5c472014-06-27 14:50:10 -0700191 GenMemBarrier(kLoadAny);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700192 } else {
193 // Explicit null-check as slow-path is entered using an IT.
buzbee2700f7e2014-03-07 09:46:20 -0800194 GenNullCheck(rs_r0, opt_flags);
buzbee695d13a2014-04-19 13:32:20 -0700195 Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
buzbee091cc402014-03-31 10:14:40 -0700196 NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
197 mirror::Object::MonitorOffset().Int32Value() >> 2);
Dave Allisonf9439142014-03-27 15:10:22 -0700198 MarkPossibleNullPointerException(opt_flags);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800199 // Zero out the read barrier bits.
200 OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled);
201 // r1 will be zero except for the rb bits if the following
202 // cmp-and-branch branches to eq where r2 will be used. Copy the
203 // read barrier bits into r2.
204 OpRegRegReg(kOpOr, rs_r2, rs_r2, rs_r1);
205 OpRegImm(kOpCmp, rs_r3, 0);
206
Dave Allison3da67a52014-04-02 17:03:45 -0700207 LIR* it = OpIT(kCondEq, "");
buzbee091cc402014-03-31 10:14:40 -0700208 NewLIR4(kThumb2Strex/*eq*/, rs_r1.GetReg(), rs_r2.GetReg(), rs_r0.GetReg(),
209 mirror::Object::MonitorOffset().Int32Value() >> 2);
Dave Allison3da67a52014-04-02 17:03:45 -0700210 OpEndIT(it);
buzbee2700f7e2014-03-07 09:46:20 -0800211 OpRegImm(kOpCmp, rs_r1, 0);
Dave Allison3da67a52014-04-02 17:03:45 -0700212 it = OpIT(kCondNe, "T");
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700213 // Go expensive route - artLockObjectFromCode(self, obj);
buzbee091cc402014-03-31 10:14:40 -0700214 LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pLockObject).Int32Value(),
215 rs_rARM_LR);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000216 ClobberCallerSave();
buzbee2700f7e2014-03-07 09:46:20 -0800217 LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
Dave Allison3da67a52014-04-02 17:03:45 -0700218 OpEndIT(it);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700219 MarkSafepointPC(call_inst);
Hans Boehm48f5c472014-06-27 14:50:10 -0700220 GenMemBarrier(kLoadAny);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700221 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700222}
223
224/*
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700225 * Handle thin locked -> unlocked transition inline or else call out to quick entrypoint. For more
226 * details see monitor.cc. Note the code below doesn't use ldrex/strex as the code holds the lock
227 * and can only give away ownership if its suspended.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700229void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700230 FlushAllRegs();
buzbee2700f7e2014-03-07 09:46:20 -0800231 LoadValueDirectFixed(rl_src, rs_r0); // Get obj
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 LockCallTemps(); // Prepare for explicit register usage
Dave Allisonf9439142014-03-27 15:10:22 -0700233 LIR* null_check_branch = nullptr;
buzbee695d13a2014-04-19 13:32:20 -0700234 Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700235 constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15.
236 if (kArchVariantHasGoodBranchPredictor) {
237 if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) {
238 null_check_branch = nullptr; // No null check.
239 } else {
240 // If the null-check fails its handled by the slow-path to reduce exception related meta-data.
Dave Allison69dfe512014-07-11 17:11:58 +0000241 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700242 null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, nullptr);
Dave Allisonf9439142014-03-27 15:10:22 -0700243 }
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700244 }
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800245 if (!kUseReadBarrier) {
246 Load32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); // Get lock
247 } else {
248 NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
249 mirror::Object::MonitorOffset().Int32Value() >> 2);
250 }
Dave Allisonf9439142014-03-27 15:10:22 -0700251 MarkPossibleNullPointerException(opt_flags);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800252 // Zero out the read barrier bits.
253 OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled);
254 // Zero out except the read barrier bits.
255 OpRegRegImm(kOpAnd, rs_r1, rs_r1, LockWord::kReadBarrierStateMaskShifted);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700256 LIR* slow_unlock_branch = OpCmpBranch(kCondNe, rs_r3, rs_r2, nullptr);
Hans Boehm48f5c472014-06-27 14:50:10 -0700257 GenMemBarrier(kAnyStore);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800258 LIR* unlock_success_branch;
259 if (!kUseReadBarrier) {
260 Store32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700261 unlock_success_branch = OpUnconditionalBranch(nullptr);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800262 } else {
263 NewLIR4(kThumb2Strex, rs_r2.GetReg(), rs_r1.GetReg(), rs_r0.GetReg(),
264 mirror::Object::MonitorOffset().Int32Value() >> 2);
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700265 unlock_success_branch = OpCmpImmBranch(kCondEq, rs_r2, 0, nullptr);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800266 }
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700267 LIR* slow_path_target = NewLIR0(kPseudoTargetLabel);
268 slow_unlock_branch->target = slow_path_target;
269 if (null_check_branch != nullptr) {
270 null_check_branch->target = slow_path_target;
271 }
272 // TODO: move to a slow path.
273 // Go expensive route - artUnlockObjectFromCode(obj);
Ian Rogersdd7624d2014-03-14 17:43:00 -0700274 LoadWordDisp(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(), rs_rARM_LR);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000275 ClobberCallerSave();
buzbee2700f7e2014-03-07 09:46:20 -0800276 LIR* call_inst = OpReg(kOpBlx, rs_rARM_LR);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700277 MarkSafepointPC(call_inst);
278
279 LIR* success_target = NewLIR0(kPseudoTargetLabel);
280 unlock_success_branch->target = success_target;
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700281 } else {
282 // Explicit null-check as slow-path is entered using an IT.
buzbee2700f7e2014-03-07 09:46:20 -0800283 GenNullCheck(rs_r0, opt_flags);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800284 if (!kUseReadBarrier) {
285 Load32Disp(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1); // Get lock
286 } else {
287 // If we use read barriers, we need to use atomic instructions.
288 NewLIR3(kThumb2Ldrex, rs_r1.GetReg(), rs_r0.GetReg(),
289 mirror::Object::MonitorOffset().Int32Value() >> 2);
290 }
Dave Allisonb373e092014-02-20 16:06:36 -0800291 MarkPossibleNullPointerException(opt_flags);
buzbee695d13a2014-04-19 13:32:20 -0700292 Load32Disp(rs_rARM_SELF, Thread::ThinLockIdOffset<4>().Int32Value(), rs_r2);
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800293 // Zero out the read barrier bits.
294 OpRegRegImm(kOpAnd, rs_r3, rs_r1, LockWord::kReadBarrierStateMaskShiftedToggled);
295 // Zero out except the read barrier bits.
296 OpRegRegImm(kOpAnd, rs_r1, rs_r1, LockWord::kReadBarrierStateMaskShifted);
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700297 // Is lock unheld on lock or held by us (==thread_id) on unlock?
Hiroshi Yamauchie15ea082015-02-09 17:11:42 -0800298 OpRegReg(kOpCmp, rs_r3, rs_r2);
299 if (!kUseReadBarrier) {
300 LIR* it = OpIT(kCondEq, "EE");
301 if (GenMemBarrier(kAnyStore)) {
302 UpdateIT(it, "TEE");
303 }
304 Store32Disp/*eq*/(rs_r0, mirror::Object::MonitorOffset().Int32Value(), rs_r1);
305 // Go expensive route - UnlockObjectFromCode(obj);
306 LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(),
307 rs_rARM_LR);
308 ClobberCallerSave();
309 LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
310 OpEndIT(it);
311 MarkSafepointPC(call_inst);
312 } else {
313 // If we use read barriers, we need to use atomic instructions.
314 LIR* it = OpIT(kCondEq, "");
315 if (GenMemBarrier(kAnyStore)) {
316 UpdateIT(it, "T");
317 }
318 NewLIR4/*eq*/(kThumb2Strex, rs_r2.GetReg(), rs_r1.GetReg(), rs_r0.GetReg(),
319 mirror::Object::MonitorOffset().Int32Value() >> 2);
320 OpEndIT(it);
321 // Since we know r2 wasn't zero before the above it instruction,
322 // if r2 is zero here, we know r3 was equal to r2 and the strex
323 // suceeded (we're done). Otherwise (either r3 wasn't equal to r2
324 // or the strex failed), call the entrypoint.
325 OpRegImm(kOpCmp, rs_r2, 0);
326 LIR* it2 = OpIT(kCondNe, "T");
327 // Go expensive route - UnlockObjectFromCode(obj);
328 LoadWordDisp/*ne*/(rs_rARM_SELF, QUICK_ENTRYPOINT_OFFSET(4, pUnlockObject).Int32Value(),
329 rs_rARM_LR);
330 ClobberCallerSave();
331 LIR* call_inst = OpReg(kOpBlx/*ne*/, rs_rARM_LR);
332 OpEndIT(it2);
333 MarkSafepointPC(call_inst);
Andreas Gampeb14329f2014-05-15 11:16:06 -0700334 }
Ian Rogersd9c4fc92013-10-01 19:45:43 -0700335 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700336}
337
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700338void ArmMir2Lir::GenMoveException(RegLocation rl_dest) {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700339 int ex_offset = Thread::ExceptionOffset<4>().Int32Value();
buzbeea0cd2d72014-06-01 09:33:49 -0700340 RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
341 RegStorage reset_reg = AllocTempRef();
Andreas Gampe3c12c512014-06-24 18:46:29 +0000342 LoadRefDisp(rs_rARM_SELF, ex_offset, rl_result.reg, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700343 LoadConstant(reset_reg, 0);
Andreas Gampe3c12c512014-06-24 18:46:29 +0000344 StoreRefDisp(rs_rARM_SELF, ex_offset, reset_reg, kNotVolatile);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700345 FreeTemp(reset_reg);
346 StoreValue(rl_dest, rl_result);
347}
348
Vladimir Markobf535be2014-11-19 18:52:35 +0000349void ArmMir2Lir::UnconditionallyMarkGCCard(RegStorage tgt_addr_reg) {
buzbee2700f7e2014-03-07 09:46:20 -0800350 RegStorage reg_card_base = AllocTemp();
351 RegStorage reg_card_no = AllocTemp();
Ian Rogersdd7624d2014-03-14 17:43:00 -0700352 LoadWordDisp(rs_rARM_SELF, Thread::CardTableOffset<4>().Int32Value(), reg_card_base);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700353 OpRegRegImm(kOpLsr, reg_card_no, tgt_addr_reg, gc::accounting::CardTable::kCardShift);
buzbee2700f7e2014-03-07 09:46:20 -0800354 StoreBaseIndexed(reg_card_base, reg_card_no, reg_card_base, 0, kUnsignedByte);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700355 FreeTemp(reg_card_base);
356 FreeTemp(reg_card_no);
357}
358
David Srbecky1109fb32015-04-07 20:21:06 +0100359static dwarf::Reg DwarfCoreReg(int num) {
360 return dwarf::Reg::ArmCore(num);
361}
362
363static dwarf::Reg DwarfFpReg(int num) {
364 return dwarf::Reg::ArmFp(num);
365}
366
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700367void ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
David Srbecky1109fb32015-04-07 20:21:06 +0100368 DCHECK_EQ(cfi_.GetCurrentCFAOffset(), 0); // empty stack.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700369 int spill_count = num_core_spills_ + num_fp_spills_;
370 /*
371 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
372 * mechanism know so it doesn't try to use any of them when
373 * expanding the frame or flushing. This leaves the utility
374 * code with a single temp: r12. This should be enough.
375 */
buzbee091cc402014-03-31 10:14:40 -0700376 LockTemp(rs_r0);
377 LockTemp(rs_r1);
378 LockTemp(rs_r2);
379 LockTemp(rs_r3);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700380
381 /*
382 * We can safely skip the stack overflow check if we're
383 * a leaf *and* our frame size < fudge factor.
384 */
Dave Allison648d7112014-07-25 16:15:27 -0700385 bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !FrameNeedsStackCheck(frame_size_, kArm);
Dave Allison648d7112014-07-25 16:15:27 -0700386 const size_t kStackOverflowReservedUsableBytes = GetStackOverflowReservedBytes(kArm);
Andreas Gampe7cd26f32014-06-18 17:01:15 -0700387 bool large_frame = (static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes);
Dave Allison648d7112014-07-25 16:15:27 -0700388 bool generate_explicit_stack_overflow_check = large_frame ||
389 !cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700390 if (!skip_overflow_check) {
Dave Allison648d7112014-07-25 16:15:27 -0700391 if (generate_explicit_stack_overflow_check) {
Bill Buzbeefe8cf8b2014-05-15 13:57:54 +0000392 if (!large_frame) {
393 /* Load stack limit */
394 LockTemp(rs_r12);
395 Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12);
396 }
Dave Allison5cd33752014-04-15 15:57:58 -0700397 } else {
398 // Implicit stack overflow check.
399 // Generate a load from [sp, #-overflowsize]. If this is in the stack
400 // redzone we will get a segmentation fault.
401 //
402 // Caveat coder: if someone changes the kStackOverflowReservedBytes value
403 // we need to make sure that it's loadable in an immediate field of
404 // a sub instruction. Otherwise we will get a temp allocation and the
405 // code size will increase.
406 //
407 // This is done before the callee save instructions to avoid any possibility
408 // of these overflowing. This uses r12 and that's never saved in a callee
409 // save.
Andreas Gampe7ea6f792014-07-14 16:21:44 -0700410 OpRegRegImm(kOpSub, rs_r12, rs_rARM_SP, GetStackOverflowReservedBytes(kArm));
Dave Allison5cd33752014-04-15 15:57:58 -0700411 Load32Disp(rs_r12, 0, rs_r12);
412 MarkPossibleStackOverflowException();
Dave Allisonb373e092014-02-20 16:06:36 -0800413 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700414 }
415 /* Spill core callee saves */
David Srbecky1109fb32015-04-07 20:21:06 +0100416 if (core_spill_mask_ != 0u) {
417 if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_LR.GetRegNum()))) == 0u) {
418 // Spilling only low regs and/or LR, use 16-bit PUSH.
419 constexpr int lr_bit_shift = rs_rARM_LR.GetRegNum() - 8;
420 NewLIR1(kThumbPush,
421 (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) |
422 ((core_spill_mask_ & (1u << rs_rARM_LR.GetRegNum())) >> lr_bit_shift));
423 } else if (IsPowerOfTwo(core_spill_mask_)) {
424 // kThumb2Push cannot be used to spill a single register.
425 NewLIR1(kThumb2Push1, CTZ(core_spill_mask_));
426 } else {
427 NewLIR1(kThumb2Push, core_spill_mask_);
428 }
429 cfi_.AdjustCFAOffset(num_core_spills_ * kArmPointerSize);
430 cfi_.RelOffsetForMany(DwarfCoreReg(0), 0, core_spill_mask_, kArmPointerSize);
Vladimir Marko9d5c25a2014-11-26 15:42:32 +0000431 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700432 /* Need to spill any FP regs? */
David Srbecky1109fb32015-04-07 20:21:06 +0100433 if (num_fp_spills_ != 0u) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700434 /*
435 * NOTE: fp spills are a little different from core spills in that
436 * they are pushed as a contiguous block. When promoting from
437 * the fp set, we must allocate all singles from s16..highest-promoted
438 */
439 NewLIR1(kThumb2VPushCS, num_fp_spills_);
David Srbecky1109fb32015-04-07 20:21:06 +0100440 cfi_.AdjustCFAOffset(num_fp_spills_ * kArmPointerSize);
441 cfi_.RelOffsetForMany(DwarfFpReg(0), 0, fp_spill_mask_, kArmPointerSize);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700442 }
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700443
Mathieu Chartier05a48b12014-03-31 16:11:41 -0700444 const int spill_size = spill_count * 4;
445 const int frame_size_without_spills = frame_size_ - spill_size;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700446 if (!skip_overflow_check) {
Dave Allison648d7112014-07-25 16:15:27 -0700447 if (generate_explicit_stack_overflow_check) {
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700448 class StackOverflowSlowPath : public LIRSlowPath {
449 public:
450 StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, bool restore_lr, size_t sp_displace)
Vladimir Marko0b40ecf2015-03-20 12:08:03 +0000451 : LIRSlowPath(m2l, branch), restore_lr_(restore_lr),
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700452 sp_displace_(sp_displace) {
453 }
454 void Compile() OVERRIDE {
455 m2l_->ResetRegPool();
456 m2l_->ResetDefTracking();
Mingyao Yang6ffcfa02014-04-25 11:06:00 -0700457 GenerateTargetLabel(kPseudoThrowTarget);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700458 if (restore_lr_) {
buzbee2700f7e2014-03-07 09:46:20 -0800459 m2l_->LoadWordDisp(rs_rARM_SP, sp_displace_ - 4, rs_rARM_LR);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700460 }
buzbee2700f7e2014-03-07 09:46:20 -0800461 m2l_->OpRegImm(kOpAdd, rs_rARM_SP, sp_displace_);
David Srbecky1109fb32015-04-07 20:21:06 +0100462 m2l_->cfi().AdjustCFAOffset(-sp_displace_);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700463 m2l_->ClobberCallerSave();
Ian Rogersdd7624d2014-03-14 17:43:00 -0700464 ThreadOffset<4> func_offset = QUICK_ENTRYPOINT_OFFSET(4, pThrowStackOverflow);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700465 // Load the entrypoint directly into the pc instead of doing a load + branch. Assumes
466 // codegen and target are in thumb2 mode.
buzbee695d13a2014-04-19 13:32:20 -0700467 // NOTE: native pointer.
buzbee2700f7e2014-03-07 09:46:20 -0800468 m2l_->LoadWordDisp(rs_rARM_SELF, func_offset.Int32Value(), rs_rARM_PC);
David Srbecky1109fb32015-04-07 20:21:06 +0100469 m2l_->cfi().AdjustCFAOffset(sp_displace_);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700470 }
471
472 private:
473 const bool restore_lr_;
474 const size_t sp_displace_;
475 };
Bill Buzbeefe8cf8b2014-05-15 13:57:54 +0000476 if (large_frame) {
477 // Note: may need a temp reg, and we only have r12 free at this point.
buzbee2700f7e2014-03-07 09:46:20 -0800478 OpRegRegImm(kOpSub, rs_rARM_LR, rs_rARM_SP, frame_size_without_spills);
Bill Buzbeefe8cf8b2014-05-15 13:57:54 +0000479 Load32Disp(rs_rARM_SELF, Thread::StackEndOffset<4>().Int32Value(), rs_r12);
buzbee2700f7e2014-03-07 09:46:20 -0800480 LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_LR, rs_r12, nullptr);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700481 // Need to restore LR since we used it as a temp.
Mathieu Chartier05a48b12014-03-31 16:11:41 -0700482 AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, true, spill_size));
buzbee2700f7e2014-03-07 09:46:20 -0800483 OpRegCopy(rs_rARM_SP, rs_rARM_LR); // Establish stack
David Srbecky1109fb32015-04-07 20:21:06 +0100484 cfi_.AdjustCFAOffset(frame_size_without_spills);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700485 } else {
Bill Buzbeefe8cf8b2014-05-15 13:57:54 +0000486 /*
487 * If the frame is small enough we are guaranteed to have enough space that remains to
488 * handle signals on the user stack. However, we may not have any free temp
489 * registers at this point, so we'll temporarily add LR to the temp pool.
490 */
491 DCHECK(!GetRegInfo(rs_rARM_LR)->IsTemp());
492 MarkTemp(rs_rARM_LR);
493 FreeTemp(rs_rARM_LR);
buzbee2700f7e2014-03-07 09:46:20 -0800494 OpRegRegImm(kOpSub, rs_rARM_SP, rs_rARM_SP, frame_size_without_spills);
David Srbecky1109fb32015-04-07 20:21:06 +0100495 cfi_.AdjustCFAOffset(frame_size_without_spills);
Bill Buzbeefe8cf8b2014-05-15 13:57:54 +0000496 Clobber(rs_rARM_LR);
497 UnmarkTemp(rs_rARM_LR);
buzbee2700f7e2014-03-07 09:46:20 -0800498 LIR* branch = OpCmpBranch(kCondUlt, rs_rARM_SP, rs_r12, nullptr);
Mathieu Chartier0d507d12014-03-19 10:17:28 -0700499 AddSlowPath(new(arena_)StackOverflowSlowPath(this, branch, false, frame_size_));
500 }
Dave Allisonb373e092014-02-20 16:06:36 -0800501 } else {
Dave Allison5cd33752014-04-15 15:57:58 -0700502 // Implicit stack overflow check has already been done. Just make room on the
503 // stack for the frame now.
Dave Allisonf9439142014-03-27 15:10:22 -0700504 OpRegImm(kOpSub, rs_rARM_SP, frame_size_without_spills);
David Srbecky1109fb32015-04-07 20:21:06 +0100505 cfi_.AdjustCFAOffset(frame_size_without_spills);
Dave Allisonb373e092014-02-20 16:06:36 -0800506 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700507 } else {
buzbee2700f7e2014-03-07 09:46:20 -0800508 OpRegImm(kOpSub, rs_rARM_SP, frame_size_without_spills);
David Srbecky1109fb32015-04-07 20:21:06 +0100509 cfi_.AdjustCFAOffset(frame_size_without_spills);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700510 }
511
512 FlushIns(ArgLocs, rl_method);
513
Vladimir Markocc234812015-04-07 09:36:09 +0100514 // We can promote a PC-relative reference to dex cache arrays to a register
515 // if it's used at least twice. Without investigating where we should lazily
516 // load the reference, we conveniently load it after flushing inputs.
517 if (dex_cache_arrays_base_reg_.Valid()) {
518 OpPcRelDexCacheArrayAddr(cu_->dex_file, dex_cache_arrays_min_offset_,
519 dex_cache_arrays_base_reg_);
520 }
521
buzbee091cc402014-03-31 10:14:40 -0700522 FreeTemp(rs_r0);
523 FreeTemp(rs_r1);
524 FreeTemp(rs_r2);
525 FreeTemp(rs_r3);
Bill Buzbeefe8cf8b2014-05-15 13:57:54 +0000526 FreeTemp(rs_r12);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700527}
528
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700529void ArmMir2Lir::GenExitSequence() {
David Srbecky1109fb32015-04-07 20:21:06 +0100530 cfi_.RememberState();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700531 int spill_count = num_core_spills_ + num_fp_spills_;
David Srbecky1109fb32015-04-07 20:21:06 +0100532
Brian Carlstrom7940e442013-07-12 13:46:57 -0700533 /*
534 * In the exit path, r0/r1 are live - make sure they aren't
535 * allocated by the register utilities as temps.
536 */
buzbee091cc402014-03-31 10:14:40 -0700537 LockTemp(rs_r0);
538 LockTemp(rs_r1);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700539
David Srbecky1109fb32015-04-07 20:21:06 +0100540 int adjust = frame_size_ - (spill_count * kArmPointerSize);
541 OpRegImm(kOpAdd, rs_rARM_SP, adjust);
542 cfi_.AdjustCFAOffset(-adjust);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700543 /* Need to restore any FP callee saves? */
544 if (num_fp_spills_) {
545 NewLIR1(kThumb2VPopCS, num_fp_spills_);
David Srbecky1109fb32015-04-07 20:21:06 +0100546 cfi_.AdjustCFAOffset(-num_fp_spills_ * kArmPointerSize);
547 cfi_.RestoreMany(DwarfFpReg(0), fp_spill_mask_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700548 }
David Srbecky1109fb32015-04-07 20:21:06 +0100549 bool unspill_LR_to_PC = (core_spill_mask_ & (1 << rs_rARM_LR.GetRegNum())) != 0;
550 if (unspill_LR_to_PC) {
buzbee091cc402014-03-31 10:14:40 -0700551 core_spill_mask_ &= ~(1 << rs_rARM_LR.GetRegNum());
552 core_spill_mask_ |= (1 << rs_rARM_PC.GetRegNum());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700553 }
David Srbecky1109fb32015-04-07 20:21:06 +0100554 if (core_spill_mask_ != 0u) {
555 if ((core_spill_mask_ & ~(0xffu | (1u << rs_rARM_PC.GetRegNum()))) == 0u) {
556 // Unspilling only low regs and/or PC, use 16-bit POP.
557 constexpr int pc_bit_shift = rs_rARM_PC.GetRegNum() - 8;
558 NewLIR1(kThumbPop,
559 (core_spill_mask_ & ~(1u << rs_rARM_PC.GetRegNum())) |
560 ((core_spill_mask_ & (1u << rs_rARM_PC.GetRegNum())) >> pc_bit_shift));
561 } else if (IsPowerOfTwo(core_spill_mask_)) {
562 // kThumb2Pop cannot be used to unspill a single register.
563 NewLIR1(kThumb2Pop1, CTZ(core_spill_mask_));
564 } else {
565 NewLIR1(kThumb2Pop, core_spill_mask_);
566 }
567 // If we pop to PC, there is no further epilogue code.
568 if (!unspill_LR_to_PC) {
569 cfi_.AdjustCFAOffset(-num_core_spills_ * kArmPointerSize);
570 cfi_.RestoreMany(DwarfCoreReg(0), core_spill_mask_);
571 DCHECK_EQ(cfi_.GetCurrentCFAOffset(), 0); // empty stack.
572 }
Vladimir Marko9d5c25a2014-11-26 15:42:32 +0000573 }
David Srbecky1109fb32015-04-07 20:21:06 +0100574 if (!unspill_LR_to_PC) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700575 /* We didn't pop to rARM_PC, so must do a bv rARM_LR */
buzbee091cc402014-03-31 10:14:40 -0700576 NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700577 }
David Srbecky1109fb32015-04-07 20:21:06 +0100578 // The CFI should be restored for any code that follows the exit block.
579 cfi_.RestoreState();
580 cfi_.DefCFAOffset(frame_size_);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700581}
582
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800583void ArmMir2Lir::GenSpecialExitSequence() {
buzbee091cc402014-03-31 10:14:40 -0700584 NewLIR1(kThumbBx, rs_rARM_LR.GetReg());
Razvan A Lupusoru3bc01742014-02-06 13:18:43 -0800585}
586
Vladimir Marko6ce3eba2015-02-16 13:05:59 +0000587void ArmMir2Lir::GenSpecialEntryForSuspend() {
588 // Keep 16-byte stack alignment - push r0, i.e. ArtMethod*, r5, r6, lr.
589 DCHECK(!IsTemp(rs_r5));
590 DCHECK(!IsTemp(rs_r6));
591 core_spill_mask_ =
592 (1u << rs_r5.GetRegNum()) | (1u << rs_r6.GetRegNum()) | (1u << rs_rARM_LR.GetRegNum());
593 num_core_spills_ = 3u;
594 fp_spill_mask_ = 0u;
595 num_fp_spills_ = 0u;
596 frame_size_ = 16u;
597 core_vmap_table_.clear();
598 fp_vmap_table_.clear();
599 NewLIR1(kThumbPush, (1u << rs_r0.GetRegNum()) | // ArtMethod*
600 (core_spill_mask_ & ~(1u << rs_rARM_LR.GetRegNum())) | // Spills other than LR.
601 (1u << 8)); // LR encoded for 16-bit push.
David Srbecky1109fb32015-04-07 20:21:06 +0100602 cfi_.AdjustCFAOffset(frame_size_);
603 // Do not generate CFI for scratch register r0.
604 cfi_.RelOffsetForMany(DwarfCoreReg(0), 4, core_spill_mask_, kArmPointerSize);
Vladimir Marko6ce3eba2015-02-16 13:05:59 +0000605}
606
607void ArmMir2Lir::GenSpecialExitForSuspend() {
608 // Pop the frame. (ArtMethod* no longer needed but restore it anyway.)
609 NewLIR1(kThumb2Pop, (1u << rs_r0.GetRegNum()) | core_spill_mask_); // 32-bit because of LR.
David Srbecky1109fb32015-04-07 20:21:06 +0100610 cfi_.AdjustCFAOffset(-frame_size_);
611 cfi_.RestoreMany(DwarfCoreReg(0), core_spill_mask_);
Vladimir Marko6ce3eba2015-02-16 13:05:59 +0000612}
613
Vladimir Markof4da6752014-08-01 19:04:18 +0100614static bool ArmUseRelativeCall(CompilationUnit* cu, const MethodReference& target_method) {
615 // Emit relative calls only within a dex file due to the limited range of the BL insn.
616 return cu->dex_file == target_method.dex_file;
617}
618
619/*
620 * Bit of a hack here - in the absence of a real scheduling pass,
621 * emit the next instruction in static & direct invoke sequences.
622 */
Jeff Hao848f70a2014-01-15 13:49:50 -0800623int ArmMir2Lir::ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info,
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100624 int state, const MethodReference& target_method,
625 uint32_t unused_idx ATTRIBUTE_UNUSED,
626 uintptr_t direct_code, uintptr_t direct_method,
627 InvokeType type) {
628 ArmMir2Lir* cg = static_cast<ArmMir2Lir*>(cu->cg.get());
Jeff Hao848f70a2014-01-15 13:49:50 -0800629 if (info->string_init_offset != 0) {
630 RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
631 switch (state) {
632 case 0: { // Grab target method* from thread pointer
633 cg->LoadRefDisp(rs_rARM_SELF, info->string_init_offset, arg0_ref, kNotVolatile);
634 break;
635 }
636 case 1: // Grab the code from the method*
637 if (direct_code == 0) {
638 // kInvokeTgt := arg0_ref->entrypoint
639 cg->LoadWordDisp(arg0_ref,
Mathieu Chartiere401d142015-04-22 13:56:20 -0700640 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Jeff Hao848f70a2014-01-15 13:49:50 -0800641 kArmPointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt));
642 }
643 break;
644 default:
645 return -1;
646 }
647 } else if (direct_code != 0 && direct_method != 0) {
Vladimir Markof4da6752014-08-01 19:04:18 +0100648 switch (state) {
649 case 0: // Get the current Method* [sets kArg0]
650 if (direct_code != static_cast<uintptr_t>(-1)) {
651 cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
652 } else if (ArmUseRelativeCall(cu, target_method)) {
653 // Defer to linker patch.
654 } else {
655 cg->LoadCodeAddress(target_method, type, kInvokeTgt);
656 }
657 if (direct_method != static_cast<uintptr_t>(-1)) {
658 cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method);
659 } else {
660 cg->LoadMethodAddress(target_method, type, kArg0);
661 }
662 break;
663 default:
664 return -1;
665 }
666 } else {
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100667 bool use_pc_rel = cg->CanUseOpPcRelDexCacheArrayLoad();
Vladimir Markof4da6752014-08-01 19:04:18 +0100668 RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
669 switch (state) {
670 case 0: // Get the current Method* [sets kArg0]
671 // TUNING: we can save a reg copy if Method* has been promoted.
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100672 if (!use_pc_rel) {
673 cg->LoadCurrMethodDirect(arg0_ref);
674 break;
675 }
676 ++state;
677 FALLTHROUGH_INTENDED;
Vladimir Markof4da6752014-08-01 19:04:18 +0100678 case 1: // Get method->dex_cache_resolved_methods_
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100679 if (!use_pc_rel) {
680 cg->LoadRefDisp(arg0_ref,
Mathieu Chartiere401d142015-04-22 13:56:20 -0700681 ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100682 arg0_ref,
683 kNotVolatile);
684 }
Vladimir Markof4da6752014-08-01 19:04:18 +0100685 // Set up direct code if known.
686 if (direct_code != 0) {
687 if (direct_code != static_cast<uintptr_t>(-1)) {
688 cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
689 } else if (ArmUseRelativeCall(cu, target_method)) {
690 // Defer to linker patch.
691 } else {
692 CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
693 cg->LoadCodeAddress(target_method, type, kInvokeTgt);
694 }
695 }
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100696 if (!use_pc_rel || direct_code != 0) {
697 break;
698 }
699 ++state;
700 FALLTHROUGH_INTENDED;
Vladimir Markof4da6752014-08-01 19:04:18 +0100701 case 2: // Grab target method*
702 CHECK_EQ(cu->dex_file, target_method.dex_file);
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100703 if (!use_pc_rel) {
704 cg->LoadRefDisp(arg0_ref,
705 mirror::ObjectArray<mirror::Object>::OffsetOfElement(
706 target_method.dex_method_index).Int32Value(),
707 arg0_ref,
708 kNotVolatile);
709 } else {
710 size_t offset = cg->dex_cache_arrays_layout_.MethodOffset(target_method.dex_method_index);
Mathieu Chartiere401d142015-04-22 13:56:20 -0700711 cg->OpPcRelDexCacheArrayLoad(cu->dex_file, offset, arg0_ref, false);
Vladimir Markoe5c76c52015-04-06 12:10:19 +0100712 }
Vladimir Markof4da6752014-08-01 19:04:18 +0100713 break;
714 case 3: // Grab the code from the method*
715 if (direct_code == 0) {
716 // kInvokeTgt := arg0_ref->entrypoint
717 cg->LoadWordDisp(arg0_ref,
Mathieu Chartiere401d142015-04-22 13:56:20 -0700718 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Mathieu Chartier2d721012014-11-10 11:08:06 -0800719 kArmPointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt));
Vladimir Markof4da6752014-08-01 19:04:18 +0100720 }
721 break;
722 default:
723 return -1;
724 }
725 }
726 return state + 1;
727}
728
729NextCallInsn ArmMir2Lir::GetNextSDCallInsn() {
730 return ArmNextSDCallInsn;
731}
732
733LIR* ArmMir2Lir::CallWithLinkerFixup(const MethodReference& target_method, InvokeType type) {
734 // For ARM, just generate a relative BL instruction that will be filled in at 'link time'.
735 // If the target turns out to be too far, the linker will generate a thunk for dispatch.
736 int target_method_idx = target_method.dex_method_index;
737 const DexFile* target_dex_file = target_method.dex_file;
738
739 // Generate the call instruction and save index, dex_file, and type.
740 // NOTE: Method deduplication takes linker patches into account, so we can just pass 0
741 // as a placeholder for the offset.
742 LIR* call = RawLIR(current_dalvik_offset_, kThumb2Bl, 0,
Vladimir Markof6737f72015-03-23 17:05:14 +0000743 target_method_idx, WrapPointer(target_dex_file), type);
Vladimir Markof4da6752014-08-01 19:04:18 +0100744 AppendLIR(call);
745 call_method_insns_.push_back(call);
746 return call;
747}
748
749LIR* ArmMir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info) {
750 LIR* call_insn;
751 if (method_info.FastPath() && ArmUseRelativeCall(cu_, method_info.GetTargetMethod()) &&
752 (method_info.GetSharpType() == kDirect || method_info.GetSharpType() == kStatic) &&
753 method_info.DirectCode() == static_cast<uintptr_t>(-1)) {
754 call_insn = CallWithLinkerFixup(method_info.GetTargetMethod(), method_info.GetSharpType());
755 } else {
756 call_insn = OpReg(kOpBlx, TargetPtrReg(kInvokeTgt));
757 }
758 return call_insn;
759}
760
Brian Carlstrom7940e442013-07-12 13:46:57 -0700761} // namespace art