blob: d74c33f91bb7b0dc7f56ab27d0b6674be2d1b517 [file] [log] [blame]
buzbee31a4a6f2012-02-28 15:36:15 -08001/*
2 * Copyright (C) 2012 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
buzbee395116c2013-02-27 14:30:25 -080017#include "compiler/dex/compiler_ir.h"
Ian Rogers1bf8d4d2013-05-30 00:18:49 -070018#include "dex_file-inl.h"
Brian Carlstrom265091e2013-01-30 14:08:26 -080019#include "invoke_type.h"
Ian Rogers33e95662013-05-20 20:29:14 -070020#include "mirror/array.h"
21#include "mirror/string.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080022#include "oat/runtime/oat_support_entrypoints.h"
Ian Rogers07ec8e12012-12-01 01:26:51 -080023#include "x86/codegen_x86.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070024
buzbee31a4a6f2012-02-28 15:36:15 -080025namespace art {
26
27/*
28 * This source files contains "gen" codegen routines that should
29 * be applicable to most targets. Only mid-level support utilities
30 * and "op" calls may be used here.
31 */
32
buzbee31a4a6f2012-02-28 15:36:15 -080033/*
buzbee02031b12012-11-23 09:41:35 -080034 * To save scheduling time, helper calls are broken into two parts: generation of
35 * the helper target address, and the actuall call to the helper. Because x86
36 * has a memory call operation, part 1 is a NOP for x86. For other targets,
37 * load arguments between the two parts.
38 */
buzbee1fd33462013-03-25 13:40:45 -070039int Mir2Lir::CallHelperSetup(int helper_offset)
buzbee02031b12012-11-23 09:41:35 -080040{
buzbee1fd33462013-03-25 13:40:45 -070041 return (cu_->instruction_set == kX86) ? 0 : LoadHelper(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080042}
43
44/* NOTE: if r_tgt is a temp, it will be freed following use */
buzbee1fd33462013-03-25 13:40:45 -070045LIR* Mir2Lir::CallHelper(int r_tgt, int helper_offset, bool safepoint_pc)
buzbee02031b12012-11-23 09:41:35 -080046{
47 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -070048 if (cu_->instruction_set == kX86) {
49 call_inst = OpThreadMem(kOpBlx, helper_offset);
buzbee02031b12012-11-23 09:41:35 -080050 } else {
buzbee1fd33462013-03-25 13:40:45 -070051 call_inst = OpReg(kOpBlx, r_tgt);
52 FreeTemp(r_tgt);
buzbee02031b12012-11-23 09:41:35 -080053 }
54 if (safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070055 MarkSafepointPC(call_inst);
buzbee02031b12012-11-23 09:41:35 -080056 }
57 return call_inst;
58}
59
buzbee1fd33462013-03-25 13:40:45 -070060void Mir2Lir::CallRuntimeHelperImm(int helper_offset, int arg0, bool safepoint_pc) {
61 int r_tgt = CallHelperSetup(helper_offset);
62 LoadConstant(TargetReg(kArg0), arg0);
63 ClobberCalleeSave();
64 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080065}
66
buzbee1fd33462013-03-25 13:40:45 -070067void Mir2Lir::CallRuntimeHelperReg(int helper_offset, int arg0, bool safepoint_pc) {
68 int r_tgt = CallHelperSetup(helper_offset);
69 OpRegCopy(TargetReg(kArg0), arg0);
70 ClobberCalleeSave();
71 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080072}
73
buzbee1fd33462013-03-25 13:40:45 -070074void Mir2Lir::CallRuntimeHelperRegLocation(int helper_offset, RegLocation arg0, bool safepoint_pc) {
75 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080076 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070077 LoadValueDirectFixed(arg0, TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -080078 } else {
buzbee1fd33462013-03-25 13:40:45 -070079 LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080080 }
buzbee1fd33462013-03-25 13:40:45 -070081 ClobberCalleeSave();
82 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080083}
84
buzbee1fd33462013-03-25 13:40:45 -070085void Mir2Lir::CallRuntimeHelperImmImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -080086 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070087 int r_tgt = CallHelperSetup(helper_offset);
88 LoadConstant(TargetReg(kArg0), arg0);
89 LoadConstant(TargetReg(kArg1), arg1);
90 ClobberCalleeSave();
91 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080092}
93
buzbee1fd33462013-03-25 13:40:45 -070094void Mir2Lir::CallRuntimeHelperImmRegLocation(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -080095 RegLocation arg1, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070096 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080097 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070098 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080099 } else {
buzbee1fd33462013-03-25 13:40:45 -0700100 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800101 }
buzbee1fd33462013-03-25 13:40:45 -0700102 LoadConstant(TargetReg(kArg0), arg0);
103 ClobberCalleeSave();
104 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800105}
106
buzbee1fd33462013-03-25 13:40:45 -0700107void Mir2Lir::CallRuntimeHelperRegLocationImm(int helper_offset, RegLocation arg0, int arg1,
108 bool safepoint_pc) {
109 int r_tgt = CallHelperSetup(helper_offset);
110 LoadValueDirectFixed(arg0, TargetReg(kArg0));
111 LoadConstant(TargetReg(kArg1), arg1);
112 ClobberCalleeSave();
113 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800114}
115
buzbee1fd33462013-03-25 13:40:45 -0700116void Mir2Lir::CallRuntimeHelperImmReg(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800117 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700118 int r_tgt = CallHelperSetup(helper_offset);
119 OpRegCopy(TargetReg(kArg1), arg1);
120 LoadConstant(TargetReg(kArg0), arg0);
121 ClobberCalleeSave();
122 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800123}
124
buzbee1fd33462013-03-25 13:40:45 -0700125void Mir2Lir::CallRuntimeHelperRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800126 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700127 int r_tgt = CallHelperSetup(helper_offset);
128 OpRegCopy(TargetReg(kArg0), arg0);
129 LoadConstant(TargetReg(kArg1), arg1);
130 ClobberCalleeSave();
131 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800132}
133
buzbee1fd33462013-03-25 13:40:45 -0700134void Mir2Lir::CallRuntimeHelperImmMethod(int helper_offset, int arg0, bool safepoint_pc) {
135 int r_tgt = CallHelperSetup(helper_offset);
136 LoadCurrMethodDirect(TargetReg(kArg1));
137 LoadConstant(TargetReg(kArg0), arg0);
138 ClobberCalleeSave();
139 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800140}
141
buzbee1fd33462013-03-25 13:40:45 -0700142void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(int helper_offset, RegLocation arg0,
143 RegLocation arg1, bool safepoint_pc) {
144 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800145 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700146 LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -0800147 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700148 if (cu_->instruction_set == kMips) {
149 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800150 } else {
buzbee1fd33462013-03-25 13:40:45 -0700151 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800152 }
153 } else {
buzbee1fd33462013-03-25 13:40:45 -0700154 if (cu_->instruction_set == kMips) {
155 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800156 } else {
buzbee1fd33462013-03-25 13:40:45 -0700157 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800158 }
159 }
160 } else {
buzbee1fd33462013-03-25 13:40:45 -0700161 LoadValueDirectWideFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800162 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700163 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800164 } else {
buzbee1fd33462013-03-25 13:40:45 -0700165 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800166 }
167 }
buzbee1fd33462013-03-25 13:40:45 -0700168 ClobberCalleeSave();
169 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800170}
171
buzbee1fd33462013-03-25 13:40:45 -0700172void Mir2Lir::CallRuntimeHelperRegReg(int helper_offset, int arg0, int arg1, bool safepoint_pc) {
173 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800174 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700175 OpRegCopy(TargetReg(kArg0), arg0);
176 OpRegCopy(TargetReg(kArg1), arg1);
177 ClobberCalleeSave();
178 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800179}
180
buzbee1fd33462013-03-25 13:40:45 -0700181void Mir2Lir::CallRuntimeHelperRegRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800182 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700183 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800184 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700185 OpRegCopy(TargetReg(kArg0), arg0);
186 OpRegCopy(TargetReg(kArg1), arg1);
187 LoadConstant(TargetReg(kArg2), arg2);
188 ClobberCalleeSave();
189 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800190}
191
buzbee1fd33462013-03-25 13:40:45 -0700192void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800193 int arg0, RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700194 int r_tgt = CallHelperSetup(helper_offset);
195 LoadValueDirectFixed(arg2, TargetReg(kArg2));
196 LoadCurrMethodDirect(TargetReg(kArg1));
197 LoadConstant(TargetReg(kArg0), arg0);
198 ClobberCalleeSave();
199 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800200}
201
buzbee1fd33462013-03-25 13:40:45 -0700202void Mir2Lir::CallRuntimeHelperImmMethodImm(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -0800203 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700204 int r_tgt = CallHelperSetup(helper_offset);
205 LoadCurrMethodDirect(TargetReg(kArg1));
206 LoadConstant(TargetReg(kArg2), arg2);
207 LoadConstant(TargetReg(kArg0), arg0);
208 ClobberCalleeSave();
209 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800210}
211
buzbee1fd33462013-03-25 13:40:45 -0700212void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800213 int arg0, RegLocation arg1,
214 RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700215 int r_tgt = CallHelperSetup(helper_offset);
216 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800217 if (arg2.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700218 LoadValueDirectFixed(arg2, TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800219 } else {
buzbee1fd33462013-03-25 13:40:45 -0700220 LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800221 }
buzbee1fd33462013-03-25 13:40:45 -0700222 LoadConstant(TargetReg(kArg0), arg0);
223 ClobberCalleeSave();
224 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800225}
226
227/*
buzbee31a4a6f2012-02-28 15:36:15 -0800228 * If there are any ins passed in registers that have not been promoted
229 * to a callee-save register, flush them to the frame. Perform intial
230 * assignment of promoted arguments.
buzbeead8f15e2012-06-18 14:49:45 -0700231 *
buzbee52a77fc2012-11-20 19:50:46 -0800232 * ArgLocs is an array of location records describing the incoming arguments
buzbeead8f15e2012-06-18 14:49:45 -0700233 * with one location record per word of argument.
buzbee31a4a6f2012-02-28 15:36:15 -0800234 */
buzbee1fd33462013-03-25 13:40:45 -0700235void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method)
buzbee31a4a6f2012-02-28 15:36:15 -0800236{
Bill Buzbeea114add2012-05-03 15:00:40 -0700237 /*
238 * Dummy up a RegLocation for the incoming Method*
buzbeef0504cd2012-11-13 16:31:10 -0800239 * It will attempt to keep kArg0 live (or copy it to home location
Bill Buzbeea114add2012-05-03 15:00:40 -0700240 * if promoted).
241 */
buzbeefa57c472012-11-21 12:06:18 -0800242 RegLocation rl_src = rl_method;
243 rl_src.location = kLocPhysReg;
244 rl_src.low_reg = TargetReg(kArg0);
245 rl_src.home = false;
buzbee1fd33462013-03-25 13:40:45 -0700246 MarkLive(rl_src.low_reg, rl_src.s_reg_low);
247 StoreValue(rl_method, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700248 // If Method* has been promoted, explicitly flush
buzbeefa57c472012-11-21 12:06:18 -0800249 if (rl_method.location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700250 StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 }
buzbee9c044ce2012-03-18 13:24:07 -0700252
buzbee1fd33462013-03-25 13:40:45 -0700253 if (cu_->num_ins == 0)
Bill Buzbeea114add2012-05-03 15:00:40 -0700254 return;
buzbeefa57c472012-11-21 12:06:18 -0800255 const int num_arg_regs = 3;
256 static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
buzbee1fd33462013-03-25 13:40:45 -0700257 int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
Bill Buzbeea114add2012-05-03 15:00:40 -0700258 /*
259 * Copy incoming arguments to their proper home locations.
260 * NOTE: an older version of dx had an issue in which
261 * it would reuse static method argument registers.
262 * This could result in the same Dalvik virtual register
263 * being promoted to both core and fp regs. To account for this,
264 * we only copy to the corresponding promoted physical register
265 * if it matches the type of the SSA name for the incoming
266 * argument. It is also possible that long and double arguments
267 * end up half-promoted. In those cases, we must flush the promoted
268 * half to memory as well.
269 */
buzbee1fd33462013-03-25 13:40:45 -0700270 for (int i = 0; i < cu_->num_ins; i++) {
271 PromotionMap* v_map = &promotion_map_[start_vreg + i];
buzbeefa57c472012-11-21 12:06:18 -0800272 if (i < num_arg_regs) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700273 // If arriving in register
buzbeefa57c472012-11-21 12:06:18 -0800274 bool need_flush = true;
275 RegLocation* t_loc = &ArgLocs[i];
276 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700277 OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800278 need_flush = false;
279 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700280 OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800281 need_flush = false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700282 } else {
buzbeefa57c472012-11-21 12:06:18 -0800283 need_flush = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700284 }
buzbee86a4bce2012-03-06 18:15:00 -0800285
Bill Buzbeea114add2012-05-03 15:00:40 -0700286 // For wide args, force flush if only half is promoted
buzbeefa57c472012-11-21 12:06:18 -0800287 if (t_loc->wide) {
288 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
289 need_flush |= (p_map->core_location != v_map->core_location) ||
290 (p_map->fp_location != v_map->fp_location);
Bill Buzbeea114add2012-05-03 15:00:40 -0700291 }
buzbeefa57c472012-11-21 12:06:18 -0800292 if (need_flush) {
buzbee1fd33462013-03-25 13:40:45 -0700293 StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800294 TargetReg(arg_regs[i]), kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700295 }
296 } else {
297 // If arriving in frame & promoted
buzbeefa57c472012-11-21 12:06:18 -0800298 if (v_map->core_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700299 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800300 v_map->core_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700301 }
buzbeefa57c472012-11-21 12:06:18 -0800302 if (v_map->fp_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700303 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800304 v_map->FpReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700305 }
buzbee31a4a6f2012-02-28 15:36:15 -0800306 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700307 }
buzbee31a4a6f2012-02-28 15:36:15 -0800308}
309
310/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700311 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800312 * emit the next instruction in static & direct invoke sequences.
313 */
buzbeefa57c472012-11-21 12:06:18 -0800314static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700315 int state, const CompilerDriver::MethodReference& target_method,
316 uint32_t unused,
buzbeefa57c472012-11-21 12:06:18 -0800317 uintptr_t direct_code, uintptr_t direct_method,
buzbeeaad94382012-11-21 07:40:50 -0800318 InvokeType type)
buzbee31a4a6f2012-02-28 15:36:15 -0800319{
buzbee1fd33462013-03-25 13:40:45 -0700320 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800321 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700322 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800323 direct_code = 0;
324 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700325 }
buzbeefa57c472012-11-21 12:06:18 -0800326 if (direct_code != 0 && direct_method != 0) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700327 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800328 case 0: // Get the current Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800329 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700330 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700331 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700332 CHECK_EQ(cu->dex_file, target_method.dex_file);
333 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
334 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800335 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700336 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800337 data_target->operands[1] = type;
Ian Rogers2ed3b952012-03-17 11:49:39 -0700338 }
buzbee1fd33462013-03-25 13:40:45 -0700339 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
340 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800341 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700342 }
buzbeefa57c472012-11-21 12:06:18 -0800343 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700344 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Bill Buzbeea114add2012-05-03 15:00:40 -0700345 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700346 CHECK_EQ(cu->dex_file, target_method.dex_file);
347 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
348 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800349 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700350 data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800351 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700352 }
buzbee1fd33462013-03-25 13:40:45 -0700353 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
354 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800355 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700356 }
357 break;
358 default:
359 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800360 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700361 } else {
362 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800363 case 0: // Get the current Method* [sets kArg0]
Ian Rogers137e88f2012-10-08 17:46:47 -0700364 // TUNING: we can save a reg copy if Method* has been promoted.
buzbee1fd33462013-03-25 13:40:45 -0700365 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700366 break;
367 case 1: // Get method->dex_cache_resolved_methods_
buzbee1fd33462013-03-25 13:40:45 -0700368 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800369 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700370 // Set up direct code if known.
buzbeefa57c472012-11-21 12:06:18 -0800371 if (direct_code != 0) {
372 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700373 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700374 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700375 CHECK_EQ(cu->dex_file, target_method.dex_file);
376 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
377 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800378 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700379 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800380 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700381 }
buzbee1fd33462013-03-25 13:40:45 -0700382 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
383 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800384 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 }
386 }
387 break;
388 case 2: // Grab target method*
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700389 CHECK_EQ(cu->dex_file, target_method.dex_file);
buzbee1fd33462013-03-25 13:40:45 -0700390 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700391 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
392 (target_method.dex_method_index * 4),
buzbee02031b12012-11-23 09:41:35 -0800393 cg-> TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700394 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700395 case 3: // Grab the code from the method*
buzbeefa57c472012-11-21 12:06:18 -0800396 if (cu->instruction_set != kX86) {
397 if (direct_code == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700398 cg->LoadWordDisp(cg->TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -0700399 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800400 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700401 }
402 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700403 }
buzbeeb046e162012-10-30 15:48:42 -0700404 // Intentional fallthrough for x86
Bill Buzbeea114add2012-05-03 15:00:40 -0700405 default:
406 return -1;
407 }
408 }
409 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800410}
411
412/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700413 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800414 * emit the next instruction in a virtual invoke sequence.
buzbeef0504cd2012-11-13 16:31:10 -0800415 * We can use kLr as a temp prior to target address loading
buzbee31a4a6f2012-02-28 15:36:15 -0800416 * Note also that we'll load the first argument ("this") into
buzbee52a77fc2012-11-20 19:50:46 -0800417 * kArg1 here rather than the standard LoadArgRegs.
buzbee31a4a6f2012-02-28 15:36:15 -0800418 */
buzbeefa57c472012-11-21 12:06:18 -0800419static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700420 int state, const CompilerDriver::MethodReference& target_method,
421 uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
422 InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800423{
buzbee1fd33462013-03-25 13:40:45 -0700424 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700425 /*
426 * This is the fast path in which the target virtual method is
427 * fully resolved at compile time.
428 */
429 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800430 case 0: { // Get "this" [set kArg1]
buzbeefa57c472012-11-21 12:06:18 -0800431 RegLocation rl_arg = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700432 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700433 break;
Ian Rogers137e88f2012-10-08 17:46:47 -0700434 }
buzbeef0504cd2012-11-13 16:31:10 -0800435 case 1: // Is "this" null? [use kArg1]
buzbee1fd33462013-03-25 13:40:45 -0700436 cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
buzbeef0504cd2012-11-13 16:31:10 -0800437 // get this->klass_ [use kArg1, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700438 cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800439 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700440 break;
buzbeef0504cd2012-11-13 16:31:10 -0800441 case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700442 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800443 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700444 break;
buzbeef0504cd2012-11-13 16:31:10 -0800445 case 3: // Get target method [use kInvokeTgt, set kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700446 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800447 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
448 cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700449 break;
buzbeef0504cd2012-11-13 16:31:10 -0800450 case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
buzbeefa57c472012-11-21 12:06:18 -0800451 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700452 cg->LoadWordDisp(cg->TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -0700453 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800454 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700455 break;
456 }
457 // Intentional fallthrough for X86
Bill Buzbeea114add2012-05-03 15:00:40 -0700458 default:
459 return -1;
460 }
461 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800462}
463
Ian Rogers137e88f2012-10-08 17:46:47 -0700464/*
Logan Chien8dbb7082013-01-25 20:31:17 +0800465 * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline,
Ian Rogers137e88f2012-10-08 17:46:47 -0700466 * which will locate the target and continue on via a tail call.
467 */
buzbeefa57c472012-11-21 12:06:18 -0800468static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700469 const CompilerDriver::MethodReference& target_method,
470 uint32_t unused, uintptr_t unused2,
buzbeefa57c472012-11-21 12:06:18 -0800471 uintptr_t direct_method, InvokeType unused4)
Ian Rogers137e88f2012-10-08 17:46:47 -0700472{
buzbee1fd33462013-03-25 13:40:45 -0700473 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800474 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700475 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800476 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700477 }
buzbeefa57c472012-11-21 12:06:18 -0800478 int trampoline = (cu->instruction_set == kX86) ? 0
buzbeeb046e162012-10-30 15:48:42 -0700479 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
Ian Rogers137e88f2012-10-08 17:46:47 -0700480
buzbeefa57c472012-11-21 12:06:18 -0800481 if (direct_method != 0) {
Ian Rogers137e88f2012-10-08 17:46:47 -0700482 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800483 case 0: // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800484 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700485 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700486 }
buzbeef0504cd2012-11-13 16:31:10 -0800487 // Get the interface Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800488 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700489 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Ian Rogers137e88f2012-10-08 17:46:47 -0700490 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700491 CHECK_EQ(cu->dex_file, target_method.dex_file);
492 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
493 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800494 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700495 data_target = cg->AddWordData(&cg->method_literal_list_,
496 target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800497 data_target->operands[1] = kInterface;
Ian Rogers137e88f2012-10-08 17:46:47 -0700498 }
buzbee1fd33462013-03-25 13:40:45 -0700499 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
500 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800501 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Ian Rogers137e88f2012-10-08 17:46:47 -0700502 }
503 break;
504 default:
505 return -1;
506 }
507 } else {
508 switch (state) {
509 case 0:
buzbeef0504cd2012-11-13 16:31:10 -0800510 // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted.
buzbee1fd33462013-03-25 13:40:45 -0700511 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800512 // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800513 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700514 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700515 }
Ian Rogers137e88f2012-10-08 17:46:47 -0700516 break;
buzbeef0504cd2012-11-13 16:31:10 -0800517 case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700518 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800519 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800520 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700521 break;
buzbeef0504cd2012-11-13 16:31:10 -0800522 case 2: // Grab target method* [set/use kArg0]
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700523 CHECK_EQ(cu->dex_file, target_method.dex_file);
buzbee1fd33462013-03-25 13:40:45 -0700524 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700525 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
526 (target_method.dex_method_index * 4),
buzbee02031b12012-11-23 09:41:35 -0800527 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700528 break;
529 default:
530 return -1;
531 }
532 }
533 return state + 1;
534}
535
buzbeefa57c472012-11-21 12:06:18 -0800536static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700537 int state, const CompilerDriver::MethodReference& target_method,
538 uint32_t method_idx)
buzbee31a4a6f2012-02-28 15:36:15 -0800539{
buzbee1fd33462013-03-25 13:40:45 -0700540 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700541 /*
542 * This handles the case in which the base method is not fully
543 * resolved at compile time, we bail to a runtime helper.
544 */
545 if (state == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800546 if (cu->instruction_set != kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700547 // Load trampoline target
buzbee1fd33462013-03-25 13:40:45 -0700548 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700549 }
buzbeef0504cd2012-11-13 16:31:10 -0800550 // Load kArg0 with method index
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700551 CHECK_EQ(cu->dex_file, target_method.dex_file);
552 cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
Bill Buzbeea114add2012-05-03 15:00:40 -0700553 return 1;
554 }
555 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800556}
557
buzbeefa57c472012-11-21 12:06:18 -0800558static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700559 int state,
560 const CompilerDriver::MethodReference& target_method,
561 uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800562 uintptr_t unused, uintptr_t unused2,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700563 InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800564{
Ian Rogers57b86d42012-03-27 16:05:41 -0700565 int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700566 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800567}
568
buzbeefa57c472012-11-21 12:06:18 -0800569static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700570 const CompilerDriver::MethodReference& target_method,
571 uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800572 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800573{
Ian Rogers57b86d42012-03-27 16:05:41 -0700574 int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700575 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800576}
577
buzbeefa57c472012-11-21 12:06:18 -0800578static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700579 const CompilerDriver::MethodReference& target_method,
580 uint32_t method_idx, uintptr_t unused,
581 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800582{
Ian Rogers57b86d42012-03-27 16:05:41 -0700583 int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700584 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800585}
586
buzbeefa57c472012-11-21 12:06:18 -0800587static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700588 const CompilerDriver::MethodReference& target_method,
589 uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800590 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800591{
Ian Rogers57b86d42012-03-27 16:05:41 -0700592 int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700593 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800594}
595
buzbeefa57c472012-11-21 12:06:18 -0800596static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
buzbeeaad94382012-11-21 07:40:50 -0800597 CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700598 const CompilerDriver::MethodReference& target_method,
599 uint32_t unused,
600 uintptr_t unused2, uintptr_t unused3,
601 InvokeType unused4)
buzbee31a4a6f2012-02-28 15:36:15 -0800602{
Ian Rogers57b86d42012-03-27 16:05:41 -0700603 int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700604 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800605}
606
buzbee1fd33462013-03-25 13:40:45 -0700607int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700608 NextCallInsn next_call_insn,
609 const CompilerDriver::MethodReference& target_method,
610 uint32_t vtable_idx, uintptr_t direct_code,
buzbee1fd33462013-03-25 13:40:45 -0700611 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800612{
buzbee1fd33462013-03-25 13:40:45 -0700613 int last_arg_reg = TargetReg(kArg3);
614 int next_reg = TargetReg(kArg1);
buzbeefa57c472012-11-21 12:06:18 -0800615 int next_arg = 0;
616 if (skip_this) {
617 next_reg++;
618 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700619 }
buzbeefa57c472012-11-21 12:06:18 -0800620 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
621 RegLocation rl_arg = info->args[next_arg++];
buzbee1fd33462013-03-25 13:40:45 -0700622 rl_arg = UpdateRawLoc(rl_arg);
623 if (rl_arg.wide && (next_reg <= TargetReg(kArg2))) {
624 LoadValueDirectWideFixed(rl_arg, next_reg, next_reg + 1);
buzbeefa57c472012-11-21 12:06:18 -0800625 next_reg++;
626 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700627 } else {
buzbeee6285f92012-12-06 15:57:46 -0800628 if (rl_arg.wide) {
629 rl_arg.wide = false;
630 rl_arg.is_const = false;
631 }
buzbee1fd33462013-03-25 13:40:45 -0700632 LoadValueDirectFixed(rl_arg, next_reg);
buzbee31a4a6f2012-02-28 15:36:15 -0800633 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700634 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
635 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700636 }
buzbeefa57c472012-11-21 12:06:18 -0800637 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800638}
639
640/*
641 * Load up to 5 arguments, the first three of which will be in
buzbeef0504cd2012-11-13 16:31:10 -0800642 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer,
buzbee31a4a6f2012-02-28 15:36:15 -0800643 * and as part of the load sequence, it must be replaced with
644 * the target method pointer. Note, this may also be called
645 * for "range" variants if the number of arguments is 5 or fewer.
646 */
buzbee1fd33462013-03-25 13:40:45 -0700647int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
buzbee02031b12012-11-23 09:41:35 -0800648 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700649 const CompilerDriver::MethodReference& target_method,
650 uint32_t vtable_idx, uintptr_t direct_code,
buzbee02031b12012-11-23 09:41:35 -0800651 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800652{
buzbeefa57c472012-11-21 12:06:18 -0800653 RegLocation rl_arg;
buzbee31a4a6f2012-02-28 15:36:15 -0800654
Bill Buzbeea114add2012-05-03 15:00:40 -0700655 /* If no arguments, just return */
buzbeefa57c472012-11-21 12:06:18 -0800656 if (info->num_arg_words == 0)
657 return call_state;
Bill Buzbeea114add2012-05-03 15:00:40 -0700658
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700659 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
660 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700661
buzbeefa57c472012-11-21 12:06:18 -0800662 DCHECK_LE(info->num_arg_words, 5);
663 if (info->num_arg_words > 3) {
664 int32_t next_use = 3;
Bill Buzbeea114add2012-05-03 15:00:40 -0700665 //Detect special case of wide arg spanning arg3/arg4
buzbeefa57c472012-11-21 12:06:18 -0800666 RegLocation rl_use0 = info->args[0];
667 RegLocation rl_use1 = info->args[1];
668 RegLocation rl_use2 = info->args[2];
669 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
670 rl_use2.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700671 int reg = -1;
672 // Wide spans, we need the 2nd half of uses[2].
buzbee1fd33462013-03-25 13:40:45 -0700673 rl_arg = UpdateLocWide(rl_use2);
buzbeefa57c472012-11-21 12:06:18 -0800674 if (rl_arg.location == kLocPhysReg) {
675 reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700676 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800677 // kArg2 & rArg3 can safely be used here
buzbee52a77fc2012-11-20 19:50:46 -0800678 reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700679 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700680 call_state = next_call_insn(cu_, info, call_state, target_method,
681 vtable_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700682 }
buzbee1fd33462013-03-25 13:40:45 -0700683 StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
684 StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700685 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
686 direct_code, direct_method, type);
buzbeefa57c472012-11-21 12:06:18 -0800687 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700688 }
689 // Loop through the rest
buzbeefa57c472012-11-21 12:06:18 -0800690 while (next_use < info->num_arg_words) {
691 int low_reg;
692 int high_reg = -1;
693 rl_arg = info->args[next_use];
buzbee1fd33462013-03-25 13:40:45 -0700694 rl_arg = UpdateRawLoc(rl_arg);
buzbeefa57c472012-11-21 12:06:18 -0800695 if (rl_arg.location == kLocPhysReg) {
696 low_reg = rl_arg.low_reg;
697 high_reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700698 } else {
buzbeefa57c472012-11-21 12:06:18 -0800699 low_reg = TargetReg(kArg2);
700 if (rl_arg.wide) {
701 high_reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700702 LoadValueDirectWideFixed(rl_arg, low_reg, high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700703 } else {
buzbee1fd33462013-03-25 13:40:45 -0700704 LoadValueDirectFixed(rl_arg, low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700705 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700706 call_state = next_call_insn(cu_, info, call_state, target_method,
707 vtable_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700708 }
buzbeefa57c472012-11-21 12:06:18 -0800709 int outs_offset = (next_use + 1) * 4;
710 if (rl_arg.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700711 StoreBaseDispWide(TargetReg(kSp), outs_offset, low_reg, high_reg);
buzbeefa57c472012-11-21 12:06:18 -0800712 next_use += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700713 } else {
buzbee1fd33462013-03-25 13:40:45 -0700714 StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800715 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700716 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700717 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800718 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700719 }
720 }
721
buzbee1fd33462013-03-25 13:40:45 -0700722 call_state = LoadArgRegs(info, call_state, next_call_insn,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700723 target_method, vtable_idx, direct_code, direct_method,
724 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700725
726 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700727 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700728 }
buzbeefa57c472012-11-21 12:06:18 -0800729 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800730}
731
732/*
733 * May have 0+ arguments (also used for jumbo). Note that
734 * source virtual registers may be in physical registers, so may
735 * need to be flushed to home location before copying. This
736 * applies to arg3 and above (see below).
737 *
738 * Two general strategies:
739 * If < 20 arguments
740 * Pass args 3-18 using vldm/vstm block copy
buzbeef0504cd2012-11-13 16:31:10 -0800741 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800742 * If 20+ arguments
743 * Pass args arg19+ using memcpy block copy
buzbeef0504cd2012-11-13 16:31:10 -0800744 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800745 *
746 */
buzbee1fd33462013-03-25 13:40:45 -0700747int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700748 LIR** pcrLabel, NextCallInsn next_call_insn,
749 const CompilerDriver::MethodReference& target_method,
750 uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
buzbee02031b12012-11-23 09:41:35 -0800751 InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800752{
buzbee31a4a6f2012-02-28 15:36:15 -0800753
Bill Buzbeea114add2012-05-03 15:00:40 -0700754 // If we can treat it as non-range (Jumbo ops will use range form)
buzbeefa57c472012-11-21 12:06:18 -0800755 if (info->num_arg_words <= 5)
buzbee1fd33462013-03-25 13:40:45 -0700756 return GenDalvikArgsNoRange(info, call_state, pcrLabel,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700757 next_call_insn, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800758 direct_code, direct_method, type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700759 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700760 * First load the non-register arguments. Both forms expect all
761 * of the source arguments to be in their home frame location, so
buzbeefa57c472012-11-21 12:06:18 -0800762 * scan the s_reg names and flush any that have been promoted to
Bill Buzbeea114add2012-05-03 15:00:40 -0700763 * frame backing storage.
764 */
buzbeefa57c472012-11-21 12:06:18 -0800765 // Scan the rest of the args - if in phys_reg flush to memory
766 for (int next_arg = 0; next_arg < info->num_arg_words;) {
767 RegLocation loc = info->args[next_arg];
Bill Buzbeea114add2012-05-03 15:00:40 -0700768 if (loc.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700769 loc = UpdateLocWide(loc);
buzbeefa57c472012-11-21 12:06:18 -0800770 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700771 StoreBaseDispWide(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800772 loc.low_reg, loc.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700773 }
buzbeefa57c472012-11-21 12:06:18 -0800774 next_arg += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700775 } else {
buzbee1fd33462013-03-25 13:40:45 -0700776 loc = UpdateLoc(loc);
buzbeefa57c472012-11-21 12:06:18 -0800777 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700778 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800779 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700780 }
buzbeefa57c472012-11-21 12:06:18 -0800781 next_arg++;
buzbee31a4a6f2012-02-28 15:36:15 -0800782 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700783 }
buzbee31a4a6f2012-02-28 15:36:15 -0800784
buzbee1fd33462013-03-25 13:40:45 -0700785 int start_offset = SRegOffset(info->args[3].s_reg_low);
buzbeefa57c472012-11-21 12:06:18 -0800786 int outs_offset = 4 /* Method* */ + (3 * 4);
buzbee1fd33462013-03-25 13:40:45 -0700787 if (cu_->instruction_set != kThumb2) {
buzbee31a4a6f2012-02-28 15:36:15 -0800788 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700789 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
790 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
791 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800792 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700793 } else {
buzbeefa57c472012-11-21 12:06:18 -0800794 if (info->num_arg_words >= 20) {
buzbeeb046e162012-10-30 15:48:42 -0700795 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700796 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
797 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
798 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800799 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
buzbeeb046e162012-10-30 15:48:42 -0700800 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800801 // Use vldm/vstm pair using kArg3 as a temp
buzbeefa57c472012-11-21 12:06:18 -0800802 int regs_left = std::min(info->num_arg_words - 3, 16);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700803 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800804 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700805 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
806 LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
buzbeeb046e162012-10-30 15:48:42 -0700807 //TUNING: loosen barrier
buzbeefa57c472012-11-21 12:06:18 -0800808 ld->def_mask = ENCODE_ALL;
buzbee1fd33462013-03-25 13:40:45 -0700809 SetMemRefType(ld, true /* is_load */, kDalvikReg);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700810 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800811 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700812 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700813 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800814 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700815 LIR* st = OpVstm(TargetReg(kArg3), regs_left);
816 SetMemRefType(st, false /* is_load */, kDalvikReg);
buzbeefa57c472012-11-21 12:06:18 -0800817 st->def_mask = ENCODE_ALL;
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700818 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800819 direct_code, direct_method, type);
buzbeeb046e162012-10-30 15:48:42 -0700820 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700821 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700822
buzbee1fd33462013-03-25 13:40:45 -0700823 call_state = LoadArgRegs(info, call_state, next_call_insn,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700824 target_method, vtable_idx, direct_code, direct_method,
825 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700826
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700827 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800828 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700829 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700830 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700831 }
buzbeefa57c472012-11-21 12:06:18 -0800832 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800833}
834
buzbee1fd33462013-03-25 13:40:45 -0700835RegLocation Mir2Lir::InlineTarget(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700836{
Bill Buzbeea114add2012-05-03 15:00:40 -0700837 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700838 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700839 res = GetReturn(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700840 } else {
buzbee15bf9802012-06-12 17:49:27 -0700841 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700842 }
843 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700844}
845
buzbee1fd33462013-03-25 13:40:45 -0700846RegLocation Mir2Lir::InlineTargetWide(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700847{
Bill Buzbeea114add2012-05-03 15:00:40 -0700848 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700849 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700850 res = GetReturnWide(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700851 } else {
buzbee15bf9802012-06-12 17:49:27 -0700852 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700853 }
854 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700855}
856
buzbee1fd33462013-03-25 13:40:45 -0700857bool Mir2Lir::GenInlinedCharAt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700858{
buzbee1fd33462013-03-25 13:40:45 -0700859 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700860 // TODO - add Mips implementation
861 return false;
862 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700863 // Location of reference to data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800864 int value_offset = mirror::String::ValueOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700865 // Location of count
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800866 int count_offset = mirror::String::CountOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700867 // Starting offset within data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800868 int offset_offset = mirror::String::OffsetOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700869 // Start of char data with array_
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800870 int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
buzbeefc9e6fa2012-03-23 15:14:29 -0700871
buzbeefa57c472012-11-21 12:06:18 -0800872 RegLocation rl_obj = info->args[0];
873 RegLocation rl_idx = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -0700874 rl_obj = LoadValue(rl_obj, kCoreReg);
875 rl_idx = LoadValue(rl_idx, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800876 int reg_max;
buzbee1fd33462013-03-25 13:40:45 -0700877 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -0800878 bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
879 LIR* launch_pad = NULL;
880 int reg_off = INVALID_REG;
881 int reg_ptr = INVALID_REG;
buzbee1fd33462013-03-25 13:40:45 -0700882 if (cu_->instruction_set != kX86) {
883 reg_off = AllocTemp();
884 reg_ptr = AllocTemp();
buzbeefa57c472012-11-21 12:06:18 -0800885 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700886 reg_max = AllocTemp();
887 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700888 }
buzbee1fd33462013-03-25 13:40:45 -0700889 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
890 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
buzbeefa57c472012-11-21 12:06:18 -0800891 if (range_check) {
buzbeeb046e162012-10-30 15:48:42 -0700892 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700893 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700894 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700895 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
896 FreeTemp(reg_max);
897 OpCondBranch(kCondCs, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700898 }
899 } else {
buzbeefa57c472012-11-21 12:06:18 -0800900 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700901 reg_max = AllocTemp();
902 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700903 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700904 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700905 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700906 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
907 FreeTemp(reg_max);
908 OpCondBranch(kCondCc, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700909 }
buzbee1fd33462013-03-25 13:40:45 -0700910 reg_off = AllocTemp();
911 reg_ptr = AllocTemp();
912 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
913 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700914 }
buzbee1fd33462013-03-25 13:40:45 -0700915 OpRegImm(kOpAdd, reg_ptr, data_offset);
916 OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
917 FreeTemp(rl_obj.low_reg);
918 FreeTemp(rl_idx.low_reg);
919 RegLocation rl_dest = InlineTarget(info);
920 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
921 LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
922 FreeTemp(reg_off);
923 FreeTemp(reg_ptr);
924 StoreValue(rl_dest, rl_result);
buzbeefa57c472012-11-21 12:06:18 -0800925 if (range_check) {
926 launch_pad->operands[2] = 0; // no resumption
Bill Buzbeea114add2012-05-03 15:00:40 -0700927 }
928 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -0800929 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
Bill Buzbeea114add2012-05-03 15:00:40 -0700930 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700931}
932
buzbeefa57c472012-11-21 12:06:18 -0800933// Generates an inlined String.is_empty or String.length.
buzbee1fd33462013-03-25 13:40:45 -0700934bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty)
buzbeefc9e6fa2012-03-23 15:14:29 -0700935{
buzbee1fd33462013-03-25 13:40:45 -0700936 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700937 // TODO - add Mips implementation
938 return false;
939 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700940 // dst = src.length();
buzbeefa57c472012-11-21 12:06:18 -0800941 RegLocation rl_obj = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700942 rl_obj = LoadValue(rl_obj, kCoreReg);
943 RegLocation rl_dest = InlineTarget(info);
944 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
945 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
946 LoadWordDisp(rl_obj.low_reg, mirror::String::CountOffset().Int32Value(), rl_result.low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800947 if (is_empty) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700948 // dst = (dst == 0);
buzbee1fd33462013-03-25 13:40:45 -0700949 if (cu_->instruction_set == kThumb2) {
950 int t_reg = AllocTemp();
951 OpRegReg(kOpNeg, t_reg, rl_result.low_reg);
952 OpRegRegReg(kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
buzbeeb046e162012-10-30 15:48:42 -0700953 } else {
buzbee1fd33462013-03-25 13:40:45 -0700954 DCHECK_EQ(cu_->instruction_set, kX86);
955 OpRegImm(kOpSub, rl_result.low_reg, 1);
956 OpRegImm(kOpLsr, rl_result.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -0700957 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700958 }
buzbee1fd33462013-03-25 13:40:45 -0700959 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700960 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700961}
962
buzbee1fd33462013-03-25 13:40:45 -0700963bool Mir2Lir::GenInlinedAbsInt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700964{
buzbee1fd33462013-03-25 13:40:45 -0700965 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700966 // TODO - add Mips implementation
967 return false;
968 }
buzbeefa57c472012-11-21 12:06:18 -0800969 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700970 rl_src = LoadValue(rl_src, kCoreReg);
971 RegLocation rl_dest = InlineTarget(info);
972 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
973 int sign_reg = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -0700974 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700975 OpRegRegImm(kOpAsr, sign_reg, rl_src.low_reg, 31);
976 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
977 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
978 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700979 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700980}
981
buzbee1fd33462013-03-25 13:40:45 -0700982bool Mir2Lir::GenInlinedAbsLong(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700983{
buzbee1fd33462013-03-25 13:40:45 -0700984 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700985 // TODO - add Mips implementation
986 return false;
987 }
buzbee1fd33462013-03-25 13:40:45 -0700988 if (cu_->instruction_set == kThumb2) {
buzbeefa57c472012-11-21 12:06:18 -0800989 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700990 rl_src = LoadValueWide(rl_src, kCoreReg);
991 RegLocation rl_dest = InlineTargetWide(info);
992 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
993 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700994 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700995 OpRegRegImm(kOpAsr, sign_reg, rl_src.high_reg, 31);
996 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
997 OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
998 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
999 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1000 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001001 return true;
1002 } else {
buzbee1fd33462013-03-25 13:40:45 -07001003 DCHECK_EQ(cu_->instruction_set, kX86);
buzbeeb046e162012-10-30 15:48:42 -07001004 // Reuse source registers to avoid running out of temps
buzbeefa57c472012-11-21 12:06:18 -08001005 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001006 rl_src = LoadValueWide(rl_src, kCoreReg);
1007 RegLocation rl_dest = InlineTargetWide(info);
1008 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1009 OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
1010 FreeTemp(rl_src.low_reg);
1011 FreeTemp(rl_src.high_reg);
1012 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -07001013 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -07001014 OpRegRegImm(kOpAsr, sign_reg, rl_result.high_reg, 31);
1015 OpRegReg(kOpAdd, rl_result.low_reg, sign_reg);
1016 OpRegReg(kOpAdc, rl_result.high_reg, sign_reg);
1017 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1018 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1019 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001020 return true;
1021 }
buzbeefc9e6fa2012-03-23 15:14:29 -07001022}
1023
buzbee1fd33462013-03-25 13:40:45 -07001024bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001025{
buzbee1fd33462013-03-25 13:40:45 -07001026 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001027 // TODO - add Mips implementation
1028 return false;
1029 }
buzbeefa57c472012-11-21 12:06:18 -08001030 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001031 RegLocation rl_dest = InlineTarget(info);
1032 StoreValue(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001033 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001034}
1035
buzbee1fd33462013-03-25 13:40:45 -07001036bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001037{
buzbee1fd33462013-03-25 13:40:45 -07001038 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001039 // TODO - add Mips implementation
1040 return false;
1041 }
buzbeefa57c472012-11-21 12:06:18 -08001042 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001043 RegLocation rl_dest = InlineTargetWide(info);
1044 StoreValueWide(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001045 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001046}
1047
1048/*
buzbeefa57c472012-11-21 12:06:18 -08001049 * Fast string.index_of(I) & (II). Tests for simple case of char <= 0xffff,
buzbeefc9e6fa2012-03-23 15:14:29 -07001050 * otherwise bails to standard library code.
1051 */
buzbee1fd33462013-03-25 13:40:45 -07001052bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based)
buzbeefc9e6fa2012-03-23 15:14:29 -07001053{
buzbee1fd33462013-03-25 13:40:45 -07001054 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001055 // TODO - add Mips implementation
1056 return false;
1057 }
buzbee1fd33462013-03-25 13:40:45 -07001058 ClobberCalleeSave();
1059 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001060 int reg_ptr = TargetReg(kArg0);
1061 int reg_char = TargetReg(kArg1);
1062 int reg_start = TargetReg(kArg2);
buzbeefc9e6fa2012-03-23 15:14:29 -07001063
buzbeefa57c472012-11-21 12:06:18 -08001064 RegLocation rl_obj = info->args[0];
1065 RegLocation rl_char = info->args[1];
1066 RegLocation rl_start = info->args[2];
buzbee1fd33462013-03-25 13:40:45 -07001067 LoadValueDirectFixed(rl_obj, reg_ptr);
1068 LoadValueDirectFixed(rl_char, reg_char);
buzbeefa57c472012-11-21 12:06:18 -08001069 if (zero_based) {
buzbee1fd33462013-03-25 13:40:45 -07001070 LoadConstant(reg_start, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001071 } else {
buzbee1fd33462013-03-25 13:40:45 -07001072 LoadValueDirectFixed(rl_start, reg_start);
Bill Buzbeea114add2012-05-03 15:00:40 -07001073 }
buzbee1fd33462013-03-25 13:40:45 -07001074 int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(ENTRYPOINT_OFFSET(pIndexOf)) : 0;
1075 GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
1076 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001077 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001078 OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001079 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001080 if (cu_->instruction_set != kX86) {
1081 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001082 } else {
buzbee1fd33462013-03-25 13:40:45 -07001083 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pIndexOf));
buzbeeb046e162012-10-30 15:48:42 -07001084 }
buzbee1fd33462013-03-25 13:40:45 -07001085 LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -08001086 launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -07001087 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001088 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001089 RegLocation rl_return = GetReturn(false);
1090 RegLocation rl_dest = InlineTarget(info);
1091 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001092 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001093}
1094
1095/* Fast string.compareTo(Ljava/lang/string;)I. */
buzbee1fd33462013-03-25 13:40:45 -07001096bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001097{
buzbee1fd33462013-03-25 13:40:45 -07001098 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001099 // TODO - add Mips implementation
1100 return false;
1101 }
buzbee1fd33462013-03-25 13:40:45 -07001102 ClobberCalleeSave();
1103 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001104 int reg_this = TargetReg(kArg0);
1105 int reg_cmp = TargetReg(kArg1);
buzbeefc9e6fa2012-03-23 15:14:29 -07001106
buzbeefa57c472012-11-21 12:06:18 -08001107 RegLocation rl_this = info->args[0];
1108 RegLocation rl_cmp = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -07001109 LoadValueDirectFixed(rl_this, reg_this);
1110 LoadValueDirectFixed(rl_cmp, reg_cmp);
1111 int r_tgt = (cu_->instruction_set != kX86) ?
1112 LoadHelper(ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
1113 GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -08001114 //TUNING: check if rl_cmp.s_reg_low is already null checked
buzbee1fd33462013-03-25 13:40:45 -07001115 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001116 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001117 OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001118 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001119 if (cu_->instruction_set != kX86) {
1120 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001121 } else {
buzbee1fd33462013-03-25 13:40:45 -07001122 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo));
buzbeeb046e162012-10-30 15:48:42 -07001123 }
buzbeefa57c472012-11-21 12:06:18 -08001124 launch_pad->operands[2] = 0; // No return possible
Bill Buzbeea114add2012-05-03 15:00:40 -07001125 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001126 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001127 RegLocation rl_return = GetReturn(false);
1128 RegLocation rl_dest = InlineTarget(info);
1129 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001130 return true;
Ian Rogers0183dd72012-09-17 23:06:51 -07001131}
1132
buzbee1fd33462013-03-25 13:40:45 -07001133bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1134 RegLocation rl_dest = InlineTarget(info);
1135 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001136 int offset = Thread::PeerOffset().Int32Value();
buzbee1fd33462013-03-25 13:40:45 -07001137 if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
1138 LoadWordDisp(TargetReg(kSelf), offset, rl_result.low_reg);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001139 } else {
buzbee1fd33462013-03-25 13:40:45 -07001140 CHECK(cu_->instruction_set == kX86);
1141 ((X86Mir2Lir*)this)->OpRegThreadMem(kOpMov, rl_result.low_reg, offset);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001142 }
buzbee1fd33462013-03-25 13:40:45 -07001143 StoreValue(rl_dest, rl_result);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001144 return true;
1145}
1146
buzbee1fd33462013-03-25 13:40:45 -07001147bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001148 bool is_long, bool is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001149 if (cu_->instruction_set == kMips) {
Jeff Hao9bd02812013-02-08 14:29:50 -08001150 // TODO - add Mips implementation
Jeff Hao5a70fe82013-02-07 15:02:10 -08001151 return false;
1152 }
1153 // Unused - RegLocation rl_src_unsafe = info->args[0];
1154 RegLocation rl_src_obj = info->args[1]; // Object
1155 RegLocation rl_src_offset = info->args[2]; // long low
1156 rl_src_offset.wide = 0; // ignore high half in info->args[3]
buzbee1fd33462013-03-25 13:40:45 -07001157 RegLocation rl_dest = InlineTarget(info); // result reg
Jeff Hao5a70fe82013-02-07 15:02:10 -08001158 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001159 GenMemBarrier(kLoadLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001160 }
buzbee1fd33462013-03-25 13:40:45 -07001161 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1162 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1163 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001164 if (is_long) {
buzbee1fd33462013-03-25 13:40:45 -07001165 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1166 LoadBaseDispWide(rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
1167 StoreValueWide(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001168 } else {
buzbee1fd33462013-03-25 13:40:45 -07001169 LoadBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
1170 StoreValue(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001171 }
1172 return true;
1173}
1174
buzbee1fd33462013-03-25 13:40:45 -07001175bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001176 bool is_object, bool is_volatile, bool is_ordered) {
buzbee1fd33462013-03-25 13:40:45 -07001177 if (cu_->instruction_set == kMips) {
Jeff Hao9bd02812013-02-08 14:29:50 -08001178 // TODO - add Mips implementation
Jeff Hao5a70fe82013-02-07 15:02:10 -08001179 return false;
1180 }
Ian Rogers1bf8d4d2013-05-30 00:18:49 -07001181 if (cu_->instruction_set == kX86 && is_object) {
1182 // TODO: fix X86, it exhausts registers for card marking.
1183 return false;
1184 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001185 // Unused - RegLocation rl_src_unsafe = info->args[0];
1186 RegLocation rl_src_obj = info->args[1]; // Object
1187 RegLocation rl_src_offset = info->args[2]; // long low
1188 rl_src_offset.wide = 0; // ignore high half in info->args[3]
1189 RegLocation rl_src_value = info->args[4]; // value to store
1190 if (is_volatile || is_ordered) {
buzbee1fd33462013-03-25 13:40:45 -07001191 GenMemBarrier(kStoreStore);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001192 }
buzbee1fd33462013-03-25 13:40:45 -07001193 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1194 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
buzbeea5abf702013-04-12 14:39:29 -07001195 RegLocation rl_value;
Jeff Hao5a70fe82013-02-07 15:02:10 -08001196 if (is_long) {
buzbeea5abf702013-04-12 14:39:29 -07001197 rl_value = LoadValueWide(rl_src_value, kCoreReg);
buzbee1fd33462013-03-25 13:40:45 -07001198 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1199 StoreBaseDispWide(rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001200 } else {
buzbeea5abf702013-04-12 14:39:29 -07001201 rl_value = LoadValue(rl_src_value, kCoreReg);
buzbee1fd33462013-03-25 13:40:45 -07001202 StoreBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001203 }
1204 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001205 GenMemBarrier(kStoreLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001206 }
1207 if (is_object) {
buzbee1fd33462013-03-25 13:40:45 -07001208 MarkGCCard(rl_value.low_reg, rl_object.low_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001209 }
1210 return true;
1211}
1212
buzbee1fd33462013-03-25 13:40:45 -07001213bool Mir2Lir::GenIntrinsic(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001214{
buzbeefa57c472012-11-21 12:06:18 -08001215 if (info->opt_flags & MIR_INLINED) {
buzbeefc9e6fa2012-03-23 15:14:29 -07001216 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001217 }
1218 /*
1219 * TODO: move these to a target-specific structured constant array
1220 * and use a generic match function. The list of intrinsics may be
1221 * slightly different depending on target.
1222 * TODO: Fold this into a matching function that runs during
1223 * basic block building. This should be part of the action for
1224 * small method inlining and recognition of the special object init
1225 * method. By doing this during basic block construction, we can also
1226 * take advantage of/generate new useful dataflow info.
1227 */
Ian Rogers637c65b2013-05-31 11:46:00 -07001228 StringPiece tgt_methods_declaring_class(
1229 cu_->dex_file->GetMethodDeclaringClassDescriptor(cu_->dex_file->GetMethodId(info->index)));
1230 if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) {
Ian Rogers1bf8d4d2013-05-30 00:18:49 -07001231 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001232 if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001233 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001234 }
buzbeefa57c472012-11-21 12:06:18 -08001235 if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001236 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001237 }
Ian Rogers637c65b2013-05-31 11:46:00 -07001238 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Float;")) {
1239 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001240 if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
buzbee1fd33462013-03-25 13:40:45 -07001241 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001242 }
buzbeefa57c472012-11-21 12:06:18 -08001243 if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001244 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001245 }
Ian Rogers637c65b2013-05-31 11:46:00 -07001246 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Math;") ||
1247 tgt_methods_declaring_class.starts_with("Ljava/lang/StrictMath;")) {
1248 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001249 if (tgt_method == "int java.lang.Math.abs(int)" ||
1250 tgt_method == "int java.lang.StrictMath.abs(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001251 return GenInlinedAbsInt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001252 }
buzbeefa57c472012-11-21 12:06:18 -08001253 if (tgt_method == "long java.lang.Math.abs(long)" ||
1254 tgt_method == "long java.lang.StrictMath.abs(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001255 return GenInlinedAbsLong(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001256 }
buzbeefa57c472012-11-21 12:06:18 -08001257 if (tgt_method == "int java.lang.Math.max(int, int)" ||
1258 tgt_method == "int java.lang.StrictMath.max(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001259 return GenInlinedMinMaxInt(info, false /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001260 }
buzbeefa57c472012-11-21 12:06:18 -08001261 if (tgt_method == "int java.lang.Math.min(int, int)" ||
1262 tgt_method == "int java.lang.StrictMath.min(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001263 return GenInlinedMinMaxInt(info, true /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001264 }
buzbeefa57c472012-11-21 12:06:18 -08001265 if (tgt_method == "double java.lang.Math.sqrt(double)" ||
1266 tgt_method == "double java.lang.StrictMath.sqrt(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001267 return GenInlinedSqrt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001268 }
Ian Rogers637c65b2013-05-31 11:46:00 -07001269 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/String;")) {
1270 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001271 if (tgt_method == "char java.lang.String.charAt(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001272 return GenInlinedCharAt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001273 }
buzbeefa57c472012-11-21 12:06:18 -08001274 if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
buzbee1fd33462013-03-25 13:40:45 -07001275 return GenInlinedStringCompareTo(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001276 }
buzbeefa57c472012-11-21 12:06:18 -08001277 if (tgt_method == "boolean java.lang.String.is_empty()") {
buzbee1fd33462013-03-25 13:40:45 -07001278 return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001279 }
buzbeefa57c472012-11-21 12:06:18 -08001280 if (tgt_method == "int java.lang.String.index_of(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001281 return GenInlinedIndexOf(info, false /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001282 }
buzbeefa57c472012-11-21 12:06:18 -08001283 if (tgt_method == "int java.lang.String.index_of(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001284 return GenInlinedIndexOf(info, true /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001285 }
buzbeefa57c472012-11-21 12:06:18 -08001286 if (tgt_method == "int java.lang.String.length()") {
buzbee1fd33462013-03-25 13:40:45 -07001287 return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001288 }
Ian Rogers637c65b2013-05-31 11:46:00 -07001289 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Thread;")) {
1290 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
Ian Rogers07ec8e12012-12-01 01:26:51 -08001291 if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
buzbee1fd33462013-03-25 13:40:45 -07001292 return GenInlinedCurrentThread(info);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001293 }
Ian Rogers637c65b2013-05-31 11:46:00 -07001294 } else if (tgt_methods_declaring_class.starts_with("Lsun/misc/Unsafe;")) {
Ian Rogers1bf8d4d2013-05-30 00:18:49 -07001295 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001296 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001297 return GenInlinedCas32(info, false);
Ian Rogers0183dd72012-09-17 23:06:51 -07001298 }
buzbeefa57c472012-11-21 12:06:18 -08001299 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001300 return GenInlinedCas32(info, true);
Ian Rogers0183dd72012-09-17 23:06:51 -07001301 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001302 if (tgt_method == "int sun.misc.Unsafe.getInt(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001303 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001304 }
1305 if (tgt_method == "int sun.misc.Unsafe.getIntVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001306 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001307 }
1308 if (tgt_method == "void sun.misc.Unsafe.putInt(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001309 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001310 false /* is_volatile */, false /* is_ordered */);
1311 }
1312 if (tgt_method == "void sun.misc.Unsafe.putIntVolatile(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001313 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001314 true /* is_volatile */, false /* is_ordered */);
1315 }
1316 if (tgt_method == "void sun.misc.Unsafe.putOrderedInt(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001317 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001318 false /* is_volatile */, true /* is_ordered */);
1319 }
1320 if (tgt_method == "long sun.misc.Unsafe.getLong(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001321 return GenInlinedUnsafeGet(info, true /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001322 }
1323 if (tgt_method == "long sun.misc.Unsafe.getLongVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001324 return GenInlinedUnsafeGet(info, true /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001325 }
1326 if (tgt_method == "void sun.misc.Unsafe.putLong(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001327 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001328 false /* is_volatile */, false /* is_ordered */);
1329 }
1330 if (tgt_method == "void sun.misc.Unsafe.putLongVolatile(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001331 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001332 true /* is_volatile */, false /* is_ordered */);
1333 }
1334 if (tgt_method == "void sun.misc.Unsafe.putOrderedLong(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001335 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001336 false /* is_volatile */, true /* is_ordered */);
1337 }
1338 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObject(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001339 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001340 }
1341 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001342 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001343 }
1344 if (tgt_method == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001345 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001346 false /* is_volatile */, false /* is_ordered */);
1347 }
1348 if (tgt_method == "void sun.misc.Unsafe.putObjectVolatile(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001349 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001350 true /* is_volatile */, false /* is_ordered */);
1351 }
1352 if (tgt_method == "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001353 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001354 false /* is_volatile */, true /* is_ordered */);
1355 }
Ian Rogerse13eafa2012-09-07 11:24:27 -07001356 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001357 return false;
buzbeefc9e6fa2012-03-23 15:14:29 -07001358}
1359
buzbee1fd33462013-03-25 13:40:45 -07001360void Mir2Lir::GenInvoke(CallInfo* info)
buzbee1bc37c62012-11-20 13:35:41 -08001361{
buzbee1fd33462013-03-25 13:40:45 -07001362 if (GenIntrinsic(info)) {
buzbee1bc37c62012-11-20 13:35:41 -08001363 return;
1364 }
buzbeefa57c472012-11-21 12:06:18 -08001365 InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
1366 int call_state = 0;
1367 LIR* null_ck;
1368 LIR** p_null_ck = NULL;
1369 NextCallInsn next_call_insn;
buzbee1fd33462013-03-25 13:40:45 -07001370 FlushAllRegs(); /* Everything to home location */
buzbee1bc37c62012-11-20 13:35:41 -08001371 // Explicit register usage
buzbee1fd33462013-03-25 13:40:45 -07001372 LockCallTemps();
buzbee1bc37c62012-11-20 13:35:41 -08001373
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001374 DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
1375 CompilerDriver::MethodReference target_method(cUnit->GetDexFile(), info->index);
buzbeefa57c472012-11-21 12:06:18 -08001376 int vtable_idx;
1377 uintptr_t direct_code;
1378 uintptr_t direct_method;
1379 bool skip_this;
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001380 bool fast_path =
1381 cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
1382 current_dalvik_offset_,
1383 info->type, target_method,
1384 vtable_idx,
1385 direct_code, direct_method,
1386 true) && !SLOW_INVOKE_PATH;
buzbee1bc37c62012-11-20 13:35:41 -08001387 if (info->type == kInterface) {
buzbeefa57c472012-11-21 12:06:18 -08001388 if (fast_path) {
1389 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001390 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001391 next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
buzbeefa57c472012-11-21 12:06:18 -08001392 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001393 } else if (info->type == kDirect) {
buzbeefa57c472012-11-21 12:06:18 -08001394 if (fast_path) {
1395 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001396 }
buzbeefa57c472012-11-21 12:06:18 -08001397 next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1398 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001399 } else if (info->type == kStatic) {
buzbeefa57c472012-11-21 12:06:18 -08001400 next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1401 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001402 } else if (info->type == kSuper) {
buzbeefa57c472012-11-21 12:06:18 -08001403 DCHECK(!fast_path); // Fast path is a direct call.
1404 next_call_insn = NextSuperCallInsnSP;
1405 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001406 } else {
1407 DCHECK_EQ(info->type, kVirtual);
buzbeefa57c472012-11-21 12:06:18 -08001408 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1409 skip_this = fast_path;
buzbee1bc37c62012-11-20 13:35:41 -08001410 }
buzbeefa57c472012-11-21 12:06:18 -08001411 if (!info->is_range) {
buzbee1fd33462013-03-25 13:40:45 -07001412 call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001413 next_call_insn, target_method,
1414 vtable_idx, direct_code, direct_method,
1415 original_type, skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001416 } else {
buzbee1fd33462013-03-25 13:40:45 -07001417 call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001418 next_call_insn, target_method, vtable_idx,
1419 direct_code, direct_method, original_type,
1420 skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001421 }
1422 // Finish up any of the call sequence not interleaved in arg loading
buzbeefa57c472012-11-21 12:06:18 -08001423 while (call_state >= 0) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001424 call_state = next_call_insn(cu_, info, call_state, target_method,
1425 vtable_idx, direct_code, direct_method,
1426 original_type);
buzbee1bc37c62012-11-20 13:35:41 -08001427 }
buzbeefa57c472012-11-21 12:06:18 -08001428 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -07001429 if (cu_->instruction_set != kX86) {
1430 call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
buzbee1bc37c62012-11-20 13:35:41 -08001431 } else {
buzbeefa57c472012-11-21 12:06:18 -08001432 if (fast_path && info->type != kInterface) {
buzbee1fd33462013-03-25 13:40:45 -07001433 call_inst = OpMem(kOpBlx, TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -07001434 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value());
buzbee1bc37c62012-11-20 13:35:41 -08001435 } else {
1436 int trampoline = 0;
1437 switch (info->type) {
1438 case kInterface:
buzbeefa57c472012-11-21 12:06:18 -08001439 trampoline = fast_path ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
buzbee1bc37c62012-11-20 13:35:41 -08001440 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
1441 break;
1442 case kDirect:
1443 trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
1444 break;
1445 case kStatic:
1446 trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
1447 break;
1448 case kSuper:
1449 trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
1450 break;
1451 case kVirtual:
1452 trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
1453 break;
1454 default:
1455 LOG(FATAL) << "Unexpected invoke type";
1456 }
buzbee1fd33462013-03-25 13:40:45 -07001457 call_inst = OpThreadMem(kOpBlx, trampoline);
buzbee1bc37c62012-11-20 13:35:41 -08001458 }
1459 }
buzbee1fd33462013-03-25 13:40:45 -07001460 MarkSafepointPC(call_inst);
buzbee1bc37c62012-11-20 13:35:41 -08001461
buzbee1fd33462013-03-25 13:40:45 -07001462 ClobberCalleeSave();
buzbee1bc37c62012-11-20 13:35:41 -08001463 if (info->result.location != kLocInvalid) {
1464 // We have a following MOVE_RESULT - do it now.
1465 if (info->result.wide) {
buzbee1fd33462013-03-25 13:40:45 -07001466 RegLocation ret_loc = GetReturnWide(info->result.fp);
1467 StoreValueWide(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001468 } else {
buzbee1fd33462013-03-25 13:40:45 -07001469 RegLocation ret_loc = GetReturn(info->result.fp);
1470 StoreValue(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001471 }
1472 }
1473}
1474
buzbee31a4a6f2012-02-28 15:36:15 -08001475} // namespace art