blob: afcd9efb7d677ea97f9f0da6f608a119f3d65cce [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"
Brian Carlstrom265091e2013-01-30 14:08:26 -080018#include "invoke_type.h"
Ian Rogers33e95662013-05-20 20:29:14 -070019#include "mirror/array.h"
20#include "mirror/string.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080021#include "oat/runtime/oat_support_entrypoints.h"
Ian Rogers07ec8e12012-12-01 01:26:51 -080022#include "x86/codegen_x86.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070023
buzbee31a4a6f2012-02-28 15:36:15 -080024namespace art {
25
26/*
27 * This source files contains "gen" codegen routines that should
28 * be applicable to most targets. Only mid-level support utilities
29 * and "op" calls may be used here.
30 */
31
buzbee31a4a6f2012-02-28 15:36:15 -080032/*
buzbee02031b12012-11-23 09:41:35 -080033 * To save scheduling time, helper calls are broken into two parts: generation of
34 * the helper target address, and the actuall call to the helper. Because x86
35 * has a memory call operation, part 1 is a NOP for x86. For other targets,
36 * load arguments between the two parts.
37 */
buzbee1fd33462013-03-25 13:40:45 -070038int Mir2Lir::CallHelperSetup(int helper_offset)
buzbee02031b12012-11-23 09:41:35 -080039{
buzbee1fd33462013-03-25 13:40:45 -070040 return (cu_->instruction_set == kX86) ? 0 : LoadHelper(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080041}
42
43/* NOTE: if r_tgt is a temp, it will be freed following use */
buzbee1fd33462013-03-25 13:40:45 -070044LIR* Mir2Lir::CallHelper(int r_tgt, int helper_offset, bool safepoint_pc)
buzbee02031b12012-11-23 09:41:35 -080045{
46 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -070047 if (cu_->instruction_set == kX86) {
48 call_inst = OpThreadMem(kOpBlx, helper_offset);
buzbee02031b12012-11-23 09:41:35 -080049 } else {
buzbee1fd33462013-03-25 13:40:45 -070050 call_inst = OpReg(kOpBlx, r_tgt);
51 FreeTemp(r_tgt);
buzbee02031b12012-11-23 09:41:35 -080052 }
53 if (safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070054 MarkSafepointPC(call_inst);
buzbee02031b12012-11-23 09:41:35 -080055 }
56 return call_inst;
57}
58
buzbee1fd33462013-03-25 13:40:45 -070059void Mir2Lir::CallRuntimeHelperImm(int helper_offset, int arg0, bool safepoint_pc) {
60 int r_tgt = CallHelperSetup(helper_offset);
61 LoadConstant(TargetReg(kArg0), arg0);
62 ClobberCalleeSave();
63 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080064}
65
buzbee1fd33462013-03-25 13:40:45 -070066void Mir2Lir::CallRuntimeHelperReg(int helper_offset, int arg0, bool safepoint_pc) {
67 int r_tgt = CallHelperSetup(helper_offset);
68 OpRegCopy(TargetReg(kArg0), arg0);
69 ClobberCalleeSave();
70 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080071}
72
buzbee1fd33462013-03-25 13:40:45 -070073void Mir2Lir::CallRuntimeHelperRegLocation(int helper_offset, RegLocation arg0, bool safepoint_pc) {
74 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080075 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070076 LoadValueDirectFixed(arg0, TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -080077 } else {
buzbee1fd33462013-03-25 13:40:45 -070078 LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080079 }
buzbee1fd33462013-03-25 13:40:45 -070080 ClobberCalleeSave();
81 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080082}
83
buzbee1fd33462013-03-25 13:40:45 -070084void Mir2Lir::CallRuntimeHelperImmImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -080085 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070086 int r_tgt = CallHelperSetup(helper_offset);
87 LoadConstant(TargetReg(kArg0), arg0);
88 LoadConstant(TargetReg(kArg1), arg1);
89 ClobberCalleeSave();
90 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080091}
92
buzbee1fd33462013-03-25 13:40:45 -070093void Mir2Lir::CallRuntimeHelperImmRegLocation(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -080094 RegLocation arg1, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070095 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080096 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070097 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080098 } else {
buzbee1fd33462013-03-25 13:40:45 -070099 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800100 }
buzbee1fd33462013-03-25 13:40:45 -0700101 LoadConstant(TargetReg(kArg0), arg0);
102 ClobberCalleeSave();
103 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800104}
105
buzbee1fd33462013-03-25 13:40:45 -0700106void Mir2Lir::CallRuntimeHelperRegLocationImm(int helper_offset, RegLocation arg0, int arg1,
107 bool safepoint_pc) {
108 int r_tgt = CallHelperSetup(helper_offset);
109 LoadValueDirectFixed(arg0, TargetReg(kArg0));
110 LoadConstant(TargetReg(kArg1), arg1);
111 ClobberCalleeSave();
112 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800113}
114
buzbee1fd33462013-03-25 13:40:45 -0700115void Mir2Lir::CallRuntimeHelperImmReg(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800116 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700117 int r_tgt = CallHelperSetup(helper_offset);
118 OpRegCopy(TargetReg(kArg1), arg1);
119 LoadConstant(TargetReg(kArg0), arg0);
120 ClobberCalleeSave();
121 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800122}
123
buzbee1fd33462013-03-25 13:40:45 -0700124void Mir2Lir::CallRuntimeHelperRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800125 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700126 int r_tgt = CallHelperSetup(helper_offset);
127 OpRegCopy(TargetReg(kArg0), arg0);
128 LoadConstant(TargetReg(kArg1), arg1);
129 ClobberCalleeSave();
130 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800131}
132
buzbee1fd33462013-03-25 13:40:45 -0700133void Mir2Lir::CallRuntimeHelperImmMethod(int helper_offset, int arg0, bool safepoint_pc) {
134 int r_tgt = CallHelperSetup(helper_offset);
135 LoadCurrMethodDirect(TargetReg(kArg1));
136 LoadConstant(TargetReg(kArg0), arg0);
137 ClobberCalleeSave();
138 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800139}
140
buzbee1fd33462013-03-25 13:40:45 -0700141void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(int helper_offset, RegLocation arg0,
142 RegLocation arg1, bool safepoint_pc) {
143 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800144 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700145 LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -0800146 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700147 if (cu_->instruction_set == kMips) {
148 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800149 } else {
buzbee1fd33462013-03-25 13:40:45 -0700150 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800151 }
152 } else {
buzbee1fd33462013-03-25 13:40:45 -0700153 if (cu_->instruction_set == kMips) {
154 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800155 } else {
buzbee1fd33462013-03-25 13:40:45 -0700156 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800157 }
158 }
159 } else {
buzbee1fd33462013-03-25 13:40:45 -0700160 LoadValueDirectWideFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800161 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700162 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800163 } else {
buzbee1fd33462013-03-25 13:40:45 -0700164 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800165 }
166 }
buzbee1fd33462013-03-25 13:40:45 -0700167 ClobberCalleeSave();
168 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800169}
170
buzbee1fd33462013-03-25 13:40:45 -0700171void Mir2Lir::CallRuntimeHelperRegReg(int helper_offset, int arg0, int arg1, bool safepoint_pc) {
172 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800173 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700174 OpRegCopy(TargetReg(kArg0), arg0);
175 OpRegCopy(TargetReg(kArg1), arg1);
176 ClobberCalleeSave();
177 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800178}
179
buzbee1fd33462013-03-25 13:40:45 -0700180void Mir2Lir::CallRuntimeHelperRegRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800181 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700182 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800183 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700184 OpRegCopy(TargetReg(kArg0), arg0);
185 OpRegCopy(TargetReg(kArg1), arg1);
186 LoadConstant(TargetReg(kArg2), arg2);
187 ClobberCalleeSave();
188 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800189}
190
buzbee1fd33462013-03-25 13:40:45 -0700191void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800192 int arg0, RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700193 int r_tgt = CallHelperSetup(helper_offset);
194 LoadValueDirectFixed(arg2, TargetReg(kArg2));
195 LoadCurrMethodDirect(TargetReg(kArg1));
196 LoadConstant(TargetReg(kArg0), arg0);
197 ClobberCalleeSave();
198 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800199}
200
buzbee1fd33462013-03-25 13:40:45 -0700201void Mir2Lir::CallRuntimeHelperImmMethodImm(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -0800202 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700203 int r_tgt = CallHelperSetup(helper_offset);
204 LoadCurrMethodDirect(TargetReg(kArg1));
205 LoadConstant(TargetReg(kArg2), arg2);
206 LoadConstant(TargetReg(kArg0), arg0);
207 ClobberCalleeSave();
208 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800209}
210
buzbee1fd33462013-03-25 13:40:45 -0700211void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800212 int arg0, RegLocation arg1,
213 RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700214 int r_tgt = CallHelperSetup(helper_offset);
215 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800216 if (arg2.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700217 LoadValueDirectFixed(arg2, TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800218 } else {
buzbee1fd33462013-03-25 13:40:45 -0700219 LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800220 }
buzbee1fd33462013-03-25 13:40:45 -0700221 LoadConstant(TargetReg(kArg0), arg0);
222 ClobberCalleeSave();
223 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800224}
225
226/*
buzbee31a4a6f2012-02-28 15:36:15 -0800227 * If there are any ins passed in registers that have not been promoted
228 * to a callee-save register, flush them to the frame. Perform intial
229 * assignment of promoted arguments.
buzbeead8f15e2012-06-18 14:49:45 -0700230 *
buzbee52a77fc2012-11-20 19:50:46 -0800231 * ArgLocs is an array of location records describing the incoming arguments
buzbeead8f15e2012-06-18 14:49:45 -0700232 * with one location record per word of argument.
buzbee31a4a6f2012-02-28 15:36:15 -0800233 */
buzbee1fd33462013-03-25 13:40:45 -0700234void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method)
buzbee31a4a6f2012-02-28 15:36:15 -0800235{
Bill Buzbeea114add2012-05-03 15:00:40 -0700236 /*
237 * Dummy up a RegLocation for the incoming Method*
buzbeef0504cd2012-11-13 16:31:10 -0800238 * It will attempt to keep kArg0 live (or copy it to home location
Bill Buzbeea114add2012-05-03 15:00:40 -0700239 * if promoted).
240 */
buzbeefa57c472012-11-21 12:06:18 -0800241 RegLocation rl_src = rl_method;
242 rl_src.location = kLocPhysReg;
243 rl_src.low_reg = TargetReg(kArg0);
244 rl_src.home = false;
buzbee1fd33462013-03-25 13:40:45 -0700245 MarkLive(rl_src.low_reg, rl_src.s_reg_low);
246 StoreValue(rl_method, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700247 // If Method* has been promoted, explicitly flush
buzbeefa57c472012-11-21 12:06:18 -0800248 if (rl_method.location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700249 StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700250 }
buzbee9c044ce2012-03-18 13:24:07 -0700251
buzbee1fd33462013-03-25 13:40:45 -0700252 if (cu_->num_ins == 0)
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 return;
buzbeefa57c472012-11-21 12:06:18 -0800254 const int num_arg_regs = 3;
255 static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
buzbee1fd33462013-03-25 13:40:45 -0700256 int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
Bill Buzbeea114add2012-05-03 15:00:40 -0700257 /*
258 * Copy incoming arguments to their proper home locations.
259 * NOTE: an older version of dx had an issue in which
260 * it would reuse static method argument registers.
261 * This could result in the same Dalvik virtual register
262 * being promoted to both core and fp regs. To account for this,
263 * we only copy to the corresponding promoted physical register
264 * if it matches the type of the SSA name for the incoming
265 * argument. It is also possible that long and double arguments
266 * end up half-promoted. In those cases, we must flush the promoted
267 * half to memory as well.
268 */
buzbee1fd33462013-03-25 13:40:45 -0700269 for (int i = 0; i < cu_->num_ins; i++) {
270 PromotionMap* v_map = &promotion_map_[start_vreg + i];
buzbeefa57c472012-11-21 12:06:18 -0800271 if (i < num_arg_regs) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700272 // If arriving in register
buzbeefa57c472012-11-21 12:06:18 -0800273 bool need_flush = true;
274 RegLocation* t_loc = &ArgLocs[i];
275 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700276 OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800277 need_flush = false;
278 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700279 OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800280 need_flush = false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700281 } else {
buzbeefa57c472012-11-21 12:06:18 -0800282 need_flush = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700283 }
buzbee86a4bce2012-03-06 18:15:00 -0800284
Bill Buzbeea114add2012-05-03 15:00:40 -0700285 // For wide args, force flush if only half is promoted
buzbeefa57c472012-11-21 12:06:18 -0800286 if (t_loc->wide) {
287 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
288 need_flush |= (p_map->core_location != v_map->core_location) ||
289 (p_map->fp_location != v_map->fp_location);
Bill Buzbeea114add2012-05-03 15:00:40 -0700290 }
buzbeefa57c472012-11-21 12:06:18 -0800291 if (need_flush) {
buzbee1fd33462013-03-25 13:40:45 -0700292 StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800293 TargetReg(arg_regs[i]), kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700294 }
295 } else {
296 // If arriving in frame & promoted
buzbeefa57c472012-11-21 12:06:18 -0800297 if (v_map->core_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700298 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800299 v_map->core_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700300 }
buzbeefa57c472012-11-21 12:06:18 -0800301 if (v_map->fp_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700302 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800303 v_map->FpReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700304 }
buzbee31a4a6f2012-02-28 15:36:15 -0800305 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700306 }
buzbee31a4a6f2012-02-28 15:36:15 -0800307}
308
309/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700310 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800311 * emit the next instruction in static & direct invoke sequences.
312 */
buzbeefa57c472012-11-21 12:06:18 -0800313static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
314 int state, uint32_t dex_idx, uint32_t unused,
315 uintptr_t direct_code, uintptr_t direct_method,
buzbeeaad94382012-11-21 07:40:50 -0800316 InvokeType type)
buzbee31a4a6f2012-02-28 15:36:15 -0800317{
buzbee1fd33462013-03-25 13:40:45 -0700318 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800319 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700320 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800321 direct_code = 0;
322 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700323 }
buzbeefa57c472012-11-21 12:06:18 -0800324 if (direct_code != 0 && direct_method != 0) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700325 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800326 case 0: // Get the current Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800327 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700328 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700329 } else {
buzbee1fd33462013-03-25 13:40:45 -0700330 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800331 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700332 data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800333 data_target->operands[1] = type;
Ian Rogers2ed3b952012-03-17 11:49:39 -0700334 }
buzbee1fd33462013-03-25 13:40:45 -0700335 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
336 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800337 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700338 }
buzbeefa57c472012-11-21 12:06:18 -0800339 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700340 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Bill Buzbeea114add2012-05-03 15:00:40 -0700341 } else {
buzbee1fd33462013-03-25 13:40:45 -0700342 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800343 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700344 data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800345 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700346 }
buzbee1fd33462013-03-25 13:40:45 -0700347 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
348 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800349 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700350 }
351 break;
352 default:
353 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800354 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700355 } else {
356 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800357 case 0: // Get the current Method* [sets kArg0]
Ian Rogers137e88f2012-10-08 17:46:47 -0700358 // TUNING: we can save a reg copy if Method* has been promoted.
buzbee1fd33462013-03-25 13:40:45 -0700359 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700360 break;
361 case 1: // Get method->dex_cache_resolved_methods_
buzbee1fd33462013-03-25 13:40:45 -0700362 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800363 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700364 // Set up direct code if known.
buzbeefa57c472012-11-21 12:06:18 -0800365 if (direct_code != 0) {
366 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700367 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700368 } else {
buzbee1fd33462013-03-25 13:40:45 -0700369 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800370 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700371 data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800372 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700373 }
buzbee1fd33462013-03-25 13:40:45 -0700374 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
375 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800376 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700377 }
378 }
379 break;
380 case 2: // Grab target method*
buzbee1fd33462013-03-25 13:40:45 -0700381 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800382 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
buzbee02031b12012-11-23 09:41:35 -0800383 cg-> TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700384 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700385 case 3: // Grab the code from the method*
buzbeefa57c472012-11-21 12:06:18 -0800386 if (cu->instruction_set != kX86) {
387 if (direct_code == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700388 cg->LoadWordDisp(cg->TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -0700389 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800390 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700391 }
392 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700393 }
buzbeeb046e162012-10-30 15:48:42 -0700394 // Intentional fallthrough for x86
Bill Buzbeea114add2012-05-03 15:00:40 -0700395 default:
396 return -1;
397 }
398 }
399 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800400}
401
402/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700403 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800404 * emit the next instruction in a virtual invoke sequence.
buzbeef0504cd2012-11-13 16:31:10 -0800405 * We can use kLr as a temp prior to target address loading
buzbee31a4a6f2012-02-28 15:36:15 -0800406 * Note also that we'll load the first argument ("this") into
buzbee52a77fc2012-11-20 19:50:46 -0800407 * kArg1 here rather than the standard LoadArgRegs.
buzbee31a4a6f2012-02-28 15:36:15 -0800408 */
buzbeefa57c472012-11-21 12:06:18 -0800409static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
410 int state, uint32_t dex_idx, uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800411 uintptr_t unused, uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800412{
buzbee1fd33462013-03-25 13:40:45 -0700413 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700414 /*
415 * This is the fast path in which the target virtual method is
416 * fully resolved at compile time.
417 */
418 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800419 case 0: { // Get "this" [set kArg1]
buzbeefa57c472012-11-21 12:06:18 -0800420 RegLocation rl_arg = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700421 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700422 break;
Ian Rogers137e88f2012-10-08 17:46:47 -0700423 }
buzbeef0504cd2012-11-13 16:31:10 -0800424 case 1: // Is "this" null? [use kArg1]
buzbee1fd33462013-03-25 13:40:45 -0700425 cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
buzbeef0504cd2012-11-13 16:31:10 -0800426 // get this->klass_ [use kArg1, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700427 cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800428 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700429 break;
buzbeef0504cd2012-11-13 16:31:10 -0800430 case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700431 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800432 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700433 break;
buzbeef0504cd2012-11-13 16:31:10 -0800434 case 3: // Get target method [use kInvokeTgt, set kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700435 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800436 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
437 cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700438 break;
buzbeef0504cd2012-11-13 16:31:10 -0800439 case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
buzbeefa57c472012-11-21 12:06:18 -0800440 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700441 cg->LoadWordDisp(cg->TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -0700442 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800443 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700444 break;
445 }
446 // Intentional fallthrough for X86
Bill Buzbeea114add2012-05-03 15:00:40 -0700447 default:
448 return -1;
449 }
450 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800451}
452
Ian Rogers137e88f2012-10-08 17:46:47 -0700453/*
Logan Chien8dbb7082013-01-25 20:31:17 +0800454 * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline,
Ian Rogers137e88f2012-10-08 17:46:47 -0700455 * which will locate the target and continue on via a tail call.
456 */
buzbeefa57c472012-11-21 12:06:18 -0800457static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
458 uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
459 uintptr_t direct_method, InvokeType unused4)
Ian Rogers137e88f2012-10-08 17:46:47 -0700460{
buzbee1fd33462013-03-25 13:40:45 -0700461 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800462 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700463 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800464 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700465 }
buzbeefa57c472012-11-21 12:06:18 -0800466 int trampoline = (cu->instruction_set == kX86) ? 0
buzbeeb046e162012-10-30 15:48:42 -0700467 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
Ian Rogers137e88f2012-10-08 17:46:47 -0700468
buzbeefa57c472012-11-21 12:06:18 -0800469 if (direct_method != 0) {
Ian Rogers137e88f2012-10-08 17:46:47 -0700470 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800471 case 0: // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800472 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700473 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700474 }
buzbeef0504cd2012-11-13 16:31:10 -0800475 // Get the interface Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800476 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700477 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Ian Rogers137e88f2012-10-08 17:46:47 -0700478 } else {
buzbee1fd33462013-03-25 13:40:45 -0700479 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800480 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700481 data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800482 data_target->operands[1] = kInterface;
Ian Rogers137e88f2012-10-08 17:46:47 -0700483 }
buzbee1fd33462013-03-25 13:40:45 -0700484 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
485 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800486 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Ian Rogers137e88f2012-10-08 17:46:47 -0700487 }
488 break;
489 default:
490 return -1;
491 }
492 } else {
493 switch (state) {
494 case 0:
buzbeef0504cd2012-11-13 16:31:10 -0800495 // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted.
buzbee1fd33462013-03-25 13:40:45 -0700496 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800497 // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800498 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700499 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700500 }
Ian Rogers137e88f2012-10-08 17:46:47 -0700501 break;
buzbeef0504cd2012-11-13 16:31:10 -0800502 case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700503 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800504 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800505 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700506 break;
buzbeef0504cd2012-11-13 16:31:10 -0800507 case 2: // Grab target method* [set/use kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700508 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800509 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
buzbee02031b12012-11-23 09:41:35 -0800510 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700511 break;
512 default:
513 return -1;
514 }
515 }
516 return state + 1;
517}
518
buzbeefa57c472012-11-21 12:06:18 -0800519static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
520 int state, uint32_t dex_idx, uint32_t method_idx)
buzbee31a4a6f2012-02-28 15:36:15 -0800521{
buzbee1fd33462013-03-25 13:40:45 -0700522 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700523 /*
524 * This handles the case in which the base method is not fully
525 * resolved at compile time, we bail to a runtime helper.
526 */
527 if (state == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800528 if (cu->instruction_set != kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700529 // Load trampoline target
buzbee1fd33462013-03-25 13:40:45 -0700530 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700531 }
buzbeef0504cd2012-11-13 16:31:10 -0800532 // Load kArg0 with method index
buzbee1fd33462013-03-25 13:40:45 -0700533 cg->LoadConstant(cg->TargetReg(kArg0), dex_idx);
Bill Buzbeea114add2012-05-03 15:00:40 -0700534 return 1;
535 }
536 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800537}
538
buzbeefa57c472012-11-21 12:06:18 -0800539static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
540 int state, uint32_t dex_idx, uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800541 uintptr_t unused, uintptr_t unused2,
Brian Carlstromf5822582012-03-19 22:34:31 -0700542 InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800543{
Ian Rogers57b86d42012-03-27 16:05:41 -0700544 int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800545 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800546}
547
buzbeefa57c472012-11-21 12:06:18 -0800548static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
549 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800550 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800551{
Ian Rogers57b86d42012-03-27 16:05:41 -0700552 int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800553 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800554}
555
buzbeefa57c472012-11-21 12:06:18 -0800556static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
557 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
Brian Carlstromf5822582012-03-19 22:34:31 -0700558 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800559{
Ian Rogers57b86d42012-03-27 16:05:41 -0700560 int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800561 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800562}
563
buzbeefa57c472012-11-21 12:06:18 -0800564static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
565 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800566 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800567{
Ian Rogers57b86d42012-03-27 16:05:41 -0700568 int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800569 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800570}
571
buzbeefa57c472012-11-21 12:06:18 -0800572static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
buzbeeaad94382012-11-21 07:40:50 -0800573 CallInfo* info, int state,
buzbeefa57c472012-11-21 12:06:18 -0800574 uint32_t dex_idx, uint32_t unused,
buzbee15bf9802012-06-12 17:49:27 -0700575 uintptr_t unused2, uintptr_t unused3,
576 InvokeType unused4)
buzbee31a4a6f2012-02-28 15:36:15 -0800577{
Ian Rogers57b86d42012-03-27 16:05:41 -0700578 int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800579 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800580}
581
buzbee1fd33462013-03-25 13:40:45 -0700582int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
583 NextCallInsn next_call_insn, uint32_t dex_idx,
584 uint32_t method_idx, uintptr_t direct_code,
585 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800586{
buzbee1fd33462013-03-25 13:40:45 -0700587 int last_arg_reg = TargetReg(kArg3);
588 int next_reg = TargetReg(kArg1);
buzbeefa57c472012-11-21 12:06:18 -0800589 int next_arg = 0;
590 if (skip_this) {
591 next_reg++;
592 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700593 }
buzbeefa57c472012-11-21 12:06:18 -0800594 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
595 RegLocation rl_arg = info->args[next_arg++];
buzbee1fd33462013-03-25 13:40:45 -0700596 rl_arg = UpdateRawLoc(rl_arg);
597 if (rl_arg.wide && (next_reg <= TargetReg(kArg2))) {
598 LoadValueDirectWideFixed(rl_arg, next_reg, next_reg + 1);
buzbeefa57c472012-11-21 12:06:18 -0800599 next_reg++;
600 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700601 } else {
buzbeee6285f92012-12-06 15:57:46 -0800602 if (rl_arg.wide) {
603 rl_arg.wide = false;
604 rl_arg.is_const = false;
605 }
buzbee1fd33462013-03-25 13:40:45 -0700606 LoadValueDirectFixed(rl_arg, next_reg);
buzbee31a4a6f2012-02-28 15:36:15 -0800607 }
buzbee1fd33462013-03-25 13:40:45 -0700608 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800609 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700610 }
buzbeefa57c472012-11-21 12:06:18 -0800611 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800612}
613
614/*
615 * Load up to 5 arguments, the first three of which will be in
buzbeef0504cd2012-11-13 16:31:10 -0800616 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer,
buzbee31a4a6f2012-02-28 15:36:15 -0800617 * and as part of the load sequence, it must be replaced with
618 * the target method pointer. Note, this may also be called
619 * for "range" variants if the number of arguments is 5 or fewer.
620 */
buzbee1fd33462013-03-25 13:40:45 -0700621int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
buzbee02031b12012-11-23 09:41:35 -0800622 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
623 uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
624 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800625{
buzbeefa57c472012-11-21 12:06:18 -0800626 RegLocation rl_arg;
buzbee31a4a6f2012-02-28 15:36:15 -0800627
Bill Buzbeea114add2012-05-03 15:00:40 -0700628 /* If no arguments, just return */
buzbeefa57c472012-11-21 12:06:18 -0800629 if (info->num_arg_words == 0)
630 return call_state;
Bill Buzbeea114add2012-05-03 15:00:40 -0700631
buzbee1fd33462013-03-25 13:40:45 -0700632 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800633 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700634
buzbeefa57c472012-11-21 12:06:18 -0800635 DCHECK_LE(info->num_arg_words, 5);
636 if (info->num_arg_words > 3) {
637 int32_t next_use = 3;
Bill Buzbeea114add2012-05-03 15:00:40 -0700638 //Detect special case of wide arg spanning arg3/arg4
buzbeefa57c472012-11-21 12:06:18 -0800639 RegLocation rl_use0 = info->args[0];
640 RegLocation rl_use1 = info->args[1];
641 RegLocation rl_use2 = info->args[2];
642 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
643 rl_use2.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700644 int reg = -1;
645 // Wide spans, we need the 2nd half of uses[2].
buzbee1fd33462013-03-25 13:40:45 -0700646 rl_arg = UpdateLocWide(rl_use2);
buzbeefa57c472012-11-21 12:06:18 -0800647 if (rl_arg.location == kLocPhysReg) {
648 reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700649 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800650 // kArg2 & rArg3 can safely be used here
buzbee52a77fc2012-11-20 19:50:46 -0800651 reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700652 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
653 call_state = next_call_insn(cu_, info, call_state, dex_idx,
buzbeefa57c472012-11-21 12:06:18 -0800654 method_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700655 }
buzbee1fd33462013-03-25 13:40:45 -0700656 StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
657 StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
658 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800659 direct_code, direct_method, type);
660 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700661 }
662 // Loop through the rest
buzbeefa57c472012-11-21 12:06:18 -0800663 while (next_use < info->num_arg_words) {
664 int low_reg;
665 int high_reg = -1;
666 rl_arg = info->args[next_use];
buzbee1fd33462013-03-25 13:40:45 -0700667 rl_arg = UpdateRawLoc(rl_arg);
buzbeefa57c472012-11-21 12:06:18 -0800668 if (rl_arg.location == kLocPhysReg) {
669 low_reg = rl_arg.low_reg;
670 high_reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700671 } else {
buzbeefa57c472012-11-21 12:06:18 -0800672 low_reg = TargetReg(kArg2);
673 if (rl_arg.wide) {
674 high_reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700675 LoadValueDirectWideFixed(rl_arg, low_reg, high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700676 } else {
buzbee1fd33462013-03-25 13:40:45 -0700677 LoadValueDirectFixed(rl_arg, low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700678 }
buzbee1fd33462013-03-25 13:40:45 -0700679 call_state = next_call_insn(cu_, info, call_state, dex_idx,
buzbeefa57c472012-11-21 12:06:18 -0800680 method_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700681 }
buzbeefa57c472012-11-21 12:06:18 -0800682 int outs_offset = (next_use + 1) * 4;
683 if (rl_arg.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700684 StoreBaseDispWide(TargetReg(kSp), outs_offset, low_reg, high_reg);
buzbeefa57c472012-11-21 12:06:18 -0800685 next_use += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700686 } else {
buzbee1fd33462013-03-25 13:40:45 -0700687 StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800688 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700689 }
buzbee1fd33462013-03-25 13:40:45 -0700690 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800691 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700692 }
693 }
694
buzbee1fd33462013-03-25 13:40:45 -0700695 call_state = LoadArgRegs(info, call_state, next_call_insn,
buzbeefa57c472012-11-21 12:06:18 -0800696 dex_idx, method_idx, direct_code, direct_method,
697 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700698
699 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700700 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700701 }
buzbeefa57c472012-11-21 12:06:18 -0800702 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800703}
704
705/*
706 * May have 0+ arguments (also used for jumbo). Note that
707 * source virtual registers may be in physical registers, so may
708 * need to be flushed to home location before copying. This
709 * applies to arg3 and above (see below).
710 *
711 * Two general strategies:
712 * If < 20 arguments
713 * Pass args 3-18 using vldm/vstm block copy
buzbeef0504cd2012-11-13 16:31:10 -0800714 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800715 * If 20+ arguments
716 * Pass args arg19+ using memcpy block copy
buzbeef0504cd2012-11-13 16:31:10 -0800717 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800718 *
719 */
buzbee1fd33462013-03-25 13:40:45 -0700720int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
buzbee02031b12012-11-23 09:41:35 -0800721 LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
722 uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
723 InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800724{
buzbee31a4a6f2012-02-28 15:36:15 -0800725
Bill Buzbeea114add2012-05-03 15:00:40 -0700726 // If we can treat it as non-range (Jumbo ops will use range form)
buzbeefa57c472012-11-21 12:06:18 -0800727 if (info->num_arg_words <= 5)
buzbee1fd33462013-03-25 13:40:45 -0700728 return GenDalvikArgsNoRange(info, call_state, pcrLabel,
buzbeefa57c472012-11-21 12:06:18 -0800729 next_call_insn, dex_idx, method_idx,
730 direct_code, direct_method, type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700731 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700732 * First load the non-register arguments. Both forms expect all
733 * of the source arguments to be in their home frame location, so
buzbeefa57c472012-11-21 12:06:18 -0800734 * scan the s_reg names and flush any that have been promoted to
Bill Buzbeea114add2012-05-03 15:00:40 -0700735 * frame backing storage.
736 */
buzbeefa57c472012-11-21 12:06:18 -0800737 // Scan the rest of the args - if in phys_reg flush to memory
738 for (int next_arg = 0; next_arg < info->num_arg_words;) {
739 RegLocation loc = info->args[next_arg];
Bill Buzbeea114add2012-05-03 15:00:40 -0700740 if (loc.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700741 loc = UpdateLocWide(loc);
buzbeefa57c472012-11-21 12:06:18 -0800742 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700743 StoreBaseDispWide(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800744 loc.low_reg, loc.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700745 }
buzbeefa57c472012-11-21 12:06:18 -0800746 next_arg += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700747 } else {
buzbee1fd33462013-03-25 13:40:45 -0700748 loc = UpdateLoc(loc);
buzbeefa57c472012-11-21 12:06:18 -0800749 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700750 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800751 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700752 }
buzbeefa57c472012-11-21 12:06:18 -0800753 next_arg++;
buzbee31a4a6f2012-02-28 15:36:15 -0800754 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700755 }
buzbee31a4a6f2012-02-28 15:36:15 -0800756
buzbee1fd33462013-03-25 13:40:45 -0700757 int start_offset = SRegOffset(info->args[3].s_reg_low);
buzbeefa57c472012-11-21 12:06:18 -0800758 int outs_offset = 4 /* Method* */ + (3 * 4);
buzbee1fd33462013-03-25 13:40:45 -0700759 if (cu_->instruction_set != kThumb2) {
buzbee31a4a6f2012-02-28 15:36:15 -0800760 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700761 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
762 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
763 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800764 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700765 } else {
buzbeefa57c472012-11-21 12:06:18 -0800766 if (info->num_arg_words >= 20) {
buzbeeb046e162012-10-30 15:48:42 -0700767 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700768 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
769 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
770 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800771 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
buzbeeb046e162012-10-30 15:48:42 -0700772 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800773 // Use vldm/vstm pair using kArg3 as a temp
buzbeefa57c472012-11-21 12:06:18 -0800774 int regs_left = std::min(info->num_arg_words - 3, 16);
buzbee1fd33462013-03-25 13:40:45 -0700775 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800776 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700777 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
778 LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
buzbeeb046e162012-10-30 15:48:42 -0700779 //TUNING: loosen barrier
buzbeefa57c472012-11-21 12:06:18 -0800780 ld->def_mask = ENCODE_ALL;
buzbee1fd33462013-03-25 13:40:45 -0700781 SetMemRefType(ld, true /* is_load */, kDalvikReg);
782 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800783 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700784 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
785 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800786 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700787 LIR* st = OpVstm(TargetReg(kArg3), regs_left);
788 SetMemRefType(st, false /* is_load */, kDalvikReg);
buzbeefa57c472012-11-21 12:06:18 -0800789 st->def_mask = ENCODE_ALL;
buzbee1fd33462013-03-25 13:40:45 -0700790 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800791 direct_code, direct_method, type);
buzbeeb046e162012-10-30 15:48:42 -0700792 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700793 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700794
buzbee1fd33462013-03-25 13:40:45 -0700795 call_state = LoadArgRegs(info, call_state, next_call_insn,
buzbeefa57c472012-11-21 12:06:18 -0800796 dex_idx, method_idx, direct_code, direct_method,
797 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700798
buzbee1fd33462013-03-25 13:40:45 -0700799 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800800 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700801 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700802 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700803 }
buzbeefa57c472012-11-21 12:06:18 -0800804 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800805}
806
buzbee1fd33462013-03-25 13:40:45 -0700807RegLocation Mir2Lir::InlineTarget(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700808{
Bill Buzbeea114add2012-05-03 15:00:40 -0700809 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700810 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700811 res = GetReturn(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700812 } else {
buzbee15bf9802012-06-12 17:49:27 -0700813 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700814 }
815 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700816}
817
buzbee1fd33462013-03-25 13:40:45 -0700818RegLocation Mir2Lir::InlineTargetWide(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700819{
Bill Buzbeea114add2012-05-03 15:00:40 -0700820 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700821 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700822 res = GetReturnWide(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700823 } else {
buzbee15bf9802012-06-12 17:49:27 -0700824 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700825 }
826 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700827}
828
buzbee1fd33462013-03-25 13:40:45 -0700829bool Mir2Lir::GenInlinedCharAt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700830{
buzbee1fd33462013-03-25 13:40:45 -0700831 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700832 // TODO - add Mips implementation
833 return false;
834 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700835 // Location of reference to data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800836 int value_offset = mirror::String::ValueOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700837 // Location of count
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800838 int count_offset = mirror::String::CountOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700839 // Starting offset within data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800840 int offset_offset = mirror::String::OffsetOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700841 // Start of char data with array_
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800842 int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
buzbeefc9e6fa2012-03-23 15:14:29 -0700843
buzbeefa57c472012-11-21 12:06:18 -0800844 RegLocation rl_obj = info->args[0];
845 RegLocation rl_idx = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -0700846 rl_obj = LoadValue(rl_obj, kCoreReg);
847 rl_idx = LoadValue(rl_idx, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800848 int reg_max;
buzbee1fd33462013-03-25 13:40:45 -0700849 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -0800850 bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
851 LIR* launch_pad = NULL;
852 int reg_off = INVALID_REG;
853 int reg_ptr = INVALID_REG;
buzbee1fd33462013-03-25 13:40:45 -0700854 if (cu_->instruction_set != kX86) {
855 reg_off = AllocTemp();
856 reg_ptr = AllocTemp();
buzbeefa57c472012-11-21 12:06:18 -0800857 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700858 reg_max = AllocTemp();
859 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700860 }
buzbee1fd33462013-03-25 13:40:45 -0700861 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
862 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
buzbeefa57c472012-11-21 12:06:18 -0800863 if (range_check) {
buzbeeb046e162012-10-30 15:48:42 -0700864 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700865 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700866 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700867 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
868 FreeTemp(reg_max);
869 OpCondBranch(kCondCs, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700870 }
871 } else {
buzbeefa57c472012-11-21 12:06:18 -0800872 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700873 reg_max = AllocTemp();
874 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700875 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700876 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700877 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700878 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
879 FreeTemp(reg_max);
880 OpCondBranch(kCondCc, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700881 }
buzbee1fd33462013-03-25 13:40:45 -0700882 reg_off = AllocTemp();
883 reg_ptr = AllocTemp();
884 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
885 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700886 }
buzbee1fd33462013-03-25 13:40:45 -0700887 OpRegImm(kOpAdd, reg_ptr, data_offset);
888 OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
889 FreeTemp(rl_obj.low_reg);
890 FreeTemp(rl_idx.low_reg);
891 RegLocation rl_dest = InlineTarget(info);
892 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
893 LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
894 FreeTemp(reg_off);
895 FreeTemp(reg_ptr);
896 StoreValue(rl_dest, rl_result);
buzbeefa57c472012-11-21 12:06:18 -0800897 if (range_check) {
898 launch_pad->operands[2] = 0; // no resumption
Bill Buzbeea114add2012-05-03 15:00:40 -0700899 }
900 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -0800901 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
Bill Buzbeea114add2012-05-03 15:00:40 -0700902 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700903}
904
buzbeefa57c472012-11-21 12:06:18 -0800905// Generates an inlined String.is_empty or String.length.
buzbee1fd33462013-03-25 13:40:45 -0700906bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty)
buzbeefc9e6fa2012-03-23 15:14:29 -0700907{
buzbee1fd33462013-03-25 13:40:45 -0700908 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700909 // TODO - add Mips implementation
910 return false;
911 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700912 // dst = src.length();
buzbeefa57c472012-11-21 12:06:18 -0800913 RegLocation rl_obj = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700914 rl_obj = LoadValue(rl_obj, kCoreReg);
915 RegLocation rl_dest = InlineTarget(info);
916 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
917 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
918 LoadWordDisp(rl_obj.low_reg, mirror::String::CountOffset().Int32Value(), rl_result.low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800919 if (is_empty) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700920 // dst = (dst == 0);
buzbee1fd33462013-03-25 13:40:45 -0700921 if (cu_->instruction_set == kThumb2) {
922 int t_reg = AllocTemp();
923 OpRegReg(kOpNeg, t_reg, rl_result.low_reg);
924 OpRegRegReg(kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
buzbeeb046e162012-10-30 15:48:42 -0700925 } else {
buzbee1fd33462013-03-25 13:40:45 -0700926 DCHECK_EQ(cu_->instruction_set, kX86);
927 OpRegImm(kOpSub, rl_result.low_reg, 1);
928 OpRegImm(kOpLsr, rl_result.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -0700929 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700930 }
buzbee1fd33462013-03-25 13:40:45 -0700931 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700932 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700933}
934
buzbee1fd33462013-03-25 13:40:45 -0700935bool Mir2Lir::GenInlinedAbsInt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700936{
buzbee1fd33462013-03-25 13:40:45 -0700937 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700938 // TODO - add Mips implementation
939 return false;
940 }
buzbeefa57c472012-11-21 12:06:18 -0800941 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700942 rl_src = LoadValue(rl_src, kCoreReg);
943 RegLocation rl_dest = InlineTarget(info);
944 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
945 int sign_reg = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -0700946 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700947 OpRegRegImm(kOpAsr, sign_reg, rl_src.low_reg, 31);
948 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
949 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
950 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700951 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700952}
953
buzbee1fd33462013-03-25 13:40:45 -0700954bool Mir2Lir::GenInlinedAbsLong(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700955{
buzbee1fd33462013-03-25 13:40:45 -0700956 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700957 // TODO - add Mips implementation
958 return false;
959 }
buzbee1fd33462013-03-25 13:40:45 -0700960 if (cu_->instruction_set == kThumb2) {
buzbeefa57c472012-11-21 12:06:18 -0800961 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700962 rl_src = LoadValueWide(rl_src, kCoreReg);
963 RegLocation rl_dest = InlineTargetWide(info);
964 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
965 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700966 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700967 OpRegRegImm(kOpAsr, sign_reg, rl_src.high_reg, 31);
968 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
969 OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
970 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
971 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
972 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -0700973 return true;
974 } else {
buzbee1fd33462013-03-25 13:40:45 -0700975 DCHECK_EQ(cu_->instruction_set, kX86);
buzbeeb046e162012-10-30 15:48:42 -0700976 // Reuse source registers to avoid running out of temps
buzbeefa57c472012-11-21 12:06:18 -0800977 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700978 rl_src = LoadValueWide(rl_src, kCoreReg);
979 RegLocation rl_dest = InlineTargetWide(info);
980 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
981 OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
982 FreeTemp(rl_src.low_reg);
983 FreeTemp(rl_src.high_reg);
984 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700985 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700986 OpRegRegImm(kOpAsr, sign_reg, rl_result.high_reg, 31);
987 OpRegReg(kOpAdd, rl_result.low_reg, sign_reg);
988 OpRegReg(kOpAdc, rl_result.high_reg, sign_reg);
989 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
990 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
991 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -0700992 return true;
993 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700994}
995
buzbee1fd33462013-03-25 13:40:45 -0700996bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700997{
buzbee1fd33462013-03-25 13:40:45 -0700998 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700999 // TODO - add Mips implementation
1000 return false;
1001 }
buzbeefa57c472012-11-21 12:06:18 -08001002 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001003 RegLocation rl_dest = InlineTarget(info);
1004 StoreValue(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001005 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001006}
1007
buzbee1fd33462013-03-25 13:40:45 -07001008bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001009{
buzbee1fd33462013-03-25 13:40:45 -07001010 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001011 // TODO - add Mips implementation
1012 return false;
1013 }
buzbeefa57c472012-11-21 12:06:18 -08001014 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001015 RegLocation rl_dest = InlineTargetWide(info);
1016 StoreValueWide(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001017 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001018}
1019
1020/*
buzbeefa57c472012-11-21 12:06:18 -08001021 * Fast string.index_of(I) & (II). Tests for simple case of char <= 0xffff,
buzbeefc9e6fa2012-03-23 15:14:29 -07001022 * otherwise bails to standard library code.
1023 */
buzbee1fd33462013-03-25 13:40:45 -07001024bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based)
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 }
buzbee1fd33462013-03-25 13:40:45 -07001030 ClobberCalleeSave();
1031 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001032 int reg_ptr = TargetReg(kArg0);
1033 int reg_char = TargetReg(kArg1);
1034 int reg_start = TargetReg(kArg2);
buzbeefc9e6fa2012-03-23 15:14:29 -07001035
buzbeefa57c472012-11-21 12:06:18 -08001036 RegLocation rl_obj = info->args[0];
1037 RegLocation rl_char = info->args[1];
1038 RegLocation rl_start = info->args[2];
buzbee1fd33462013-03-25 13:40:45 -07001039 LoadValueDirectFixed(rl_obj, reg_ptr);
1040 LoadValueDirectFixed(rl_char, reg_char);
buzbeefa57c472012-11-21 12:06:18 -08001041 if (zero_based) {
buzbee1fd33462013-03-25 13:40:45 -07001042 LoadConstant(reg_start, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001043 } else {
buzbee1fd33462013-03-25 13:40:45 -07001044 LoadValueDirectFixed(rl_start, reg_start);
Bill Buzbeea114add2012-05-03 15:00:40 -07001045 }
buzbee1fd33462013-03-25 13:40:45 -07001046 int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(ENTRYPOINT_OFFSET(pIndexOf)) : 0;
1047 GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
1048 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001049 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001050 OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001051 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001052 if (cu_->instruction_set != kX86) {
1053 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001054 } else {
buzbee1fd33462013-03-25 13:40:45 -07001055 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pIndexOf));
buzbeeb046e162012-10-30 15:48:42 -07001056 }
buzbee1fd33462013-03-25 13:40:45 -07001057 LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -08001058 launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -07001059 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001060 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001061 RegLocation rl_return = GetReturn(false);
1062 RegLocation rl_dest = InlineTarget(info);
1063 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001064 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001065}
1066
1067/* Fast string.compareTo(Ljava/lang/string;)I. */
buzbee1fd33462013-03-25 13:40:45 -07001068bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001069{
buzbee1fd33462013-03-25 13:40:45 -07001070 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001071 // TODO - add Mips implementation
1072 return false;
1073 }
buzbee1fd33462013-03-25 13:40:45 -07001074 ClobberCalleeSave();
1075 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001076 int reg_this = TargetReg(kArg0);
1077 int reg_cmp = TargetReg(kArg1);
buzbeefc9e6fa2012-03-23 15:14:29 -07001078
buzbeefa57c472012-11-21 12:06:18 -08001079 RegLocation rl_this = info->args[0];
1080 RegLocation rl_cmp = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -07001081 LoadValueDirectFixed(rl_this, reg_this);
1082 LoadValueDirectFixed(rl_cmp, reg_cmp);
1083 int r_tgt = (cu_->instruction_set != kX86) ?
1084 LoadHelper(ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
1085 GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -08001086 //TUNING: check if rl_cmp.s_reg_low is already null checked
buzbee1fd33462013-03-25 13:40:45 -07001087 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001088 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001089 OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001090 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001091 if (cu_->instruction_set != kX86) {
1092 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001093 } else {
buzbee1fd33462013-03-25 13:40:45 -07001094 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo));
buzbeeb046e162012-10-30 15:48:42 -07001095 }
buzbeefa57c472012-11-21 12:06:18 -08001096 launch_pad->operands[2] = 0; // No return possible
Bill Buzbeea114add2012-05-03 15:00:40 -07001097 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001098 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001099 RegLocation rl_return = GetReturn(false);
1100 RegLocation rl_dest = InlineTarget(info);
1101 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001102 return true;
Ian Rogers0183dd72012-09-17 23:06:51 -07001103}
1104
buzbee1fd33462013-03-25 13:40:45 -07001105bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1106 RegLocation rl_dest = InlineTarget(info);
1107 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001108 int offset = Thread::PeerOffset().Int32Value();
buzbee1fd33462013-03-25 13:40:45 -07001109 if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
1110 LoadWordDisp(TargetReg(kSelf), offset, rl_result.low_reg);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001111 } else {
buzbee1fd33462013-03-25 13:40:45 -07001112 CHECK(cu_->instruction_set == kX86);
1113 ((X86Mir2Lir*)this)->OpRegThreadMem(kOpMov, rl_result.low_reg, offset);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001114 }
buzbee1fd33462013-03-25 13:40:45 -07001115 StoreValue(rl_dest, rl_result);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001116 return true;
1117}
1118
buzbee1fd33462013-03-25 13:40:45 -07001119bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001120 bool is_long, bool is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001121 if (cu_->instruction_set == kMips) {
Jeff Hao9bd02812013-02-08 14:29:50 -08001122 // TODO - add Mips implementation
Jeff Hao5a70fe82013-02-07 15:02:10 -08001123 return false;
1124 }
1125 // Unused - RegLocation rl_src_unsafe = info->args[0];
1126 RegLocation rl_src_obj = info->args[1]; // Object
1127 RegLocation rl_src_offset = info->args[2]; // long low
1128 rl_src_offset.wide = 0; // ignore high half in info->args[3]
buzbee1fd33462013-03-25 13:40:45 -07001129 RegLocation rl_dest = InlineTarget(info); // result reg
Jeff Hao5a70fe82013-02-07 15:02:10 -08001130 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001131 GenMemBarrier(kLoadLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001132 }
buzbee1fd33462013-03-25 13:40:45 -07001133 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1134 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1135 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001136 if (is_long) {
buzbee1fd33462013-03-25 13:40:45 -07001137 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1138 LoadBaseDispWide(rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
1139 StoreValueWide(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001140 } else {
buzbee1fd33462013-03-25 13:40:45 -07001141 LoadBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
1142 StoreValue(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001143 }
1144 return true;
1145}
1146
buzbee1fd33462013-03-25 13:40:45 -07001147bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001148 bool is_object, bool is_volatile, bool is_ordered) {
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]
1157 RegLocation rl_src_value = info->args[4]; // value to store
1158 if (is_volatile || is_ordered) {
buzbee1fd33462013-03-25 13:40:45 -07001159 GenMemBarrier(kStoreStore);
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);
buzbeea5abf702013-04-12 14:39:29 -07001163 RegLocation rl_value;
Jeff Hao5a70fe82013-02-07 15:02:10 -08001164 if (is_long) {
buzbeea5abf702013-04-12 14:39:29 -07001165 rl_value = LoadValueWide(rl_src_value, kCoreReg);
buzbee1fd33462013-03-25 13:40:45 -07001166 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1167 StoreBaseDispWide(rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001168 } else {
buzbeea5abf702013-04-12 14:39:29 -07001169 rl_value = LoadValue(rl_src_value, kCoreReg);
buzbee1fd33462013-03-25 13:40:45 -07001170 StoreBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001171 }
1172 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001173 GenMemBarrier(kStoreLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001174 }
1175 if (is_object) {
buzbee1fd33462013-03-25 13:40:45 -07001176 MarkGCCard(rl_value.low_reg, rl_object.low_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001177 }
1178 return true;
1179}
1180
buzbee1fd33462013-03-25 13:40:45 -07001181bool Mir2Lir::GenIntrinsic(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001182{
buzbeefa57c472012-11-21 12:06:18 -08001183 if (info->opt_flags & MIR_INLINED) {
buzbeefc9e6fa2012-03-23 15:14:29 -07001184 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001185 }
1186 /*
1187 * TODO: move these to a target-specific structured constant array
1188 * and use a generic match function. The list of intrinsics may be
1189 * slightly different depending on target.
1190 * TODO: Fold this into a matching function that runs during
1191 * basic block building. This should be part of the action for
1192 * small method inlining and recognition of the special object init
1193 * method. By doing this during basic block construction, we can also
1194 * take advantage of/generate new useful dataflow info.
1195 */
buzbee1fd33462013-03-25 13:40:45 -07001196 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001197 if (tgt_method.find(" java.lang") != std::string::npos) {
1198 if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001199 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001200 }
buzbeefa57c472012-11-21 12:06:18 -08001201 if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001202 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001203 }
buzbeefa57c472012-11-21 12:06:18 -08001204 if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
buzbee1fd33462013-03-25 13:40:45 -07001205 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001206 }
buzbeefa57c472012-11-21 12:06:18 -08001207 if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001208 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001209 }
buzbeefa57c472012-11-21 12:06:18 -08001210 if (tgt_method == "int java.lang.Math.abs(int)" ||
1211 tgt_method == "int java.lang.StrictMath.abs(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001212 return GenInlinedAbsInt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001213 }
buzbeefa57c472012-11-21 12:06:18 -08001214 if (tgt_method == "long java.lang.Math.abs(long)" ||
1215 tgt_method == "long java.lang.StrictMath.abs(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001216 return GenInlinedAbsLong(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001217 }
buzbeefa57c472012-11-21 12:06:18 -08001218 if (tgt_method == "int java.lang.Math.max(int, int)" ||
1219 tgt_method == "int java.lang.StrictMath.max(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001220 return GenInlinedMinMaxInt(info, false /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001221 }
buzbeefa57c472012-11-21 12:06:18 -08001222 if (tgt_method == "int java.lang.Math.min(int, int)" ||
1223 tgt_method == "int java.lang.StrictMath.min(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001224 return GenInlinedMinMaxInt(info, true /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001225 }
buzbeefa57c472012-11-21 12:06:18 -08001226 if (tgt_method == "double java.lang.Math.sqrt(double)" ||
1227 tgt_method == "double java.lang.StrictMath.sqrt(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001228 return GenInlinedSqrt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001229 }
buzbeefa57c472012-11-21 12:06:18 -08001230 if (tgt_method == "char java.lang.String.charAt(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001231 return GenInlinedCharAt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001232 }
buzbeefa57c472012-11-21 12:06:18 -08001233 if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
buzbee1fd33462013-03-25 13:40:45 -07001234 return GenInlinedStringCompareTo(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001235 }
buzbeefa57c472012-11-21 12:06:18 -08001236 if (tgt_method == "boolean java.lang.String.is_empty()") {
buzbee1fd33462013-03-25 13:40:45 -07001237 return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001238 }
buzbeefa57c472012-11-21 12:06:18 -08001239 if (tgt_method == "int java.lang.String.index_of(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001240 return GenInlinedIndexOf(info, false /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001241 }
buzbeefa57c472012-11-21 12:06:18 -08001242 if (tgt_method == "int java.lang.String.index_of(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001243 return GenInlinedIndexOf(info, true /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001244 }
buzbeefa57c472012-11-21 12:06:18 -08001245 if (tgt_method == "int java.lang.String.length()") {
buzbee1fd33462013-03-25 13:40:45 -07001246 return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001247 }
Ian Rogers07ec8e12012-12-01 01:26:51 -08001248 if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
buzbee1fd33462013-03-25 13:40:45 -07001249 return GenInlinedCurrentThread(info);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001250 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001251 } else if (tgt_method.find(" sun.misc.Unsafe") != std::string::npos) {
buzbeefa57c472012-11-21 12:06:18 -08001252 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001253 return GenInlinedCas32(info, false);
Ian Rogers0183dd72012-09-17 23:06:51 -07001254 }
buzbeefa57c472012-11-21 12:06:18 -08001255 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001256 return GenInlinedCas32(info, true);
Ian Rogers0183dd72012-09-17 23:06:51 -07001257 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001258 if (tgt_method == "int sun.misc.Unsafe.getInt(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001259 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001260 }
1261 if (tgt_method == "int sun.misc.Unsafe.getIntVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001262 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001263 }
1264 if (tgt_method == "void sun.misc.Unsafe.putInt(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001265 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001266 false /* is_volatile */, false /* is_ordered */);
1267 }
1268 if (tgt_method == "void sun.misc.Unsafe.putIntVolatile(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001269 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001270 true /* is_volatile */, false /* is_ordered */);
1271 }
1272 if (tgt_method == "void sun.misc.Unsafe.putOrderedInt(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001273 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001274 false /* is_volatile */, true /* is_ordered */);
1275 }
1276 if (tgt_method == "long sun.misc.Unsafe.getLong(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001277 return GenInlinedUnsafeGet(info, true /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001278 }
1279 if (tgt_method == "long sun.misc.Unsafe.getLongVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001280 return GenInlinedUnsafeGet(info, true /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001281 }
1282 if (tgt_method == "void sun.misc.Unsafe.putLong(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001283 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001284 false /* is_volatile */, false /* is_ordered */);
1285 }
1286 if (tgt_method == "void sun.misc.Unsafe.putLongVolatile(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001287 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001288 true /* is_volatile */, false /* is_ordered */);
1289 }
1290 if (tgt_method == "void sun.misc.Unsafe.putOrderedLong(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001291 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001292 false /* is_volatile */, true /* is_ordered */);
1293 }
1294 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObject(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001295 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001296 }
1297 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001298 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001299 }
1300 if (tgt_method == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001301 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001302 false /* is_volatile */, false /* is_ordered */);
1303 }
1304 if (tgt_method == "void sun.misc.Unsafe.putObjectVolatile(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001305 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001306 true /* is_volatile */, false /* is_ordered */);
1307 }
1308 if (tgt_method == "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001309 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001310 false /* is_volatile */, true /* is_ordered */);
1311 }
Ian Rogerse13eafa2012-09-07 11:24:27 -07001312 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001313 return false;
buzbeefc9e6fa2012-03-23 15:14:29 -07001314}
1315
buzbee1fd33462013-03-25 13:40:45 -07001316void Mir2Lir::GenInvoke(CallInfo* info)
buzbee1bc37c62012-11-20 13:35:41 -08001317{
buzbee1fd33462013-03-25 13:40:45 -07001318 if (GenIntrinsic(info)) {
buzbee1bc37c62012-11-20 13:35:41 -08001319 return;
1320 }
buzbeefa57c472012-11-21 12:06:18 -08001321 InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
1322 int call_state = 0;
1323 LIR* null_ck;
1324 LIR** p_null_ck = NULL;
1325 NextCallInsn next_call_insn;
buzbee1fd33462013-03-25 13:40:45 -07001326 FlushAllRegs(); /* Everything to home location */
buzbee1bc37c62012-11-20 13:35:41 -08001327 // Explicit register usage
buzbee1fd33462013-03-25 13:40:45 -07001328 LockCallTemps();
buzbee1bc37c62012-11-20 13:35:41 -08001329
buzbeefa57c472012-11-21 12:06:18 -08001330 uint32_t dex_method_idx = info->index;
1331 int vtable_idx;
1332 uintptr_t direct_code;
1333 uintptr_t direct_method;
1334 bool skip_this;
buzbee1fd33462013-03-25 13:40:45 -07001335 bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
Sameer Abu Asal02c42232013-04-30 12:09:45 -07001336 dex_method_idx, current_dalvik_offset_, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
buzbee311ca162013-02-28 15:56:43 -08001337 direct_code, direct_method) && !SLOW_INVOKE_PATH;
buzbee1bc37c62012-11-20 13:35:41 -08001338 if (info->type == kInterface) {
buzbeefa57c472012-11-21 12:06:18 -08001339 if (fast_path) {
1340 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001341 }
buzbeefa57c472012-11-21 12:06:18 -08001342 next_call_insn = fast_path ? NextInterfaceCallInsn
buzbee52a77fc2012-11-20 19:50:46 -08001343 : NextInterfaceCallInsnWithAccessCheck;
buzbeefa57c472012-11-21 12:06:18 -08001344 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001345 } else if (info->type == kDirect) {
buzbeefa57c472012-11-21 12:06:18 -08001346 if (fast_path) {
1347 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001348 }
buzbeefa57c472012-11-21 12:06:18 -08001349 next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1350 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001351 } else if (info->type == kStatic) {
buzbeefa57c472012-11-21 12:06:18 -08001352 next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1353 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001354 } else if (info->type == kSuper) {
buzbeefa57c472012-11-21 12:06:18 -08001355 DCHECK(!fast_path); // Fast path is a direct call.
1356 next_call_insn = NextSuperCallInsnSP;
1357 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001358 } else {
1359 DCHECK_EQ(info->type, kVirtual);
buzbeefa57c472012-11-21 12:06:18 -08001360 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1361 skip_this = fast_path;
buzbee1bc37c62012-11-20 13:35:41 -08001362 }
buzbeefa57c472012-11-21 12:06:18 -08001363 if (!info->is_range) {
buzbee1fd33462013-03-25 13:40:45 -07001364 call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
buzbeefa57c472012-11-21 12:06:18 -08001365 next_call_insn, dex_method_idx,
1366 vtable_idx, direct_code, direct_method,
1367 original_type, skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001368 } else {
buzbee1fd33462013-03-25 13:40:45 -07001369 call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
buzbeefa57c472012-11-21 12:06:18 -08001370 next_call_insn, dex_method_idx, vtable_idx,
1371 direct_code, direct_method, original_type,
1372 skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001373 }
1374 // Finish up any of the call sequence not interleaved in arg loading
buzbeefa57c472012-11-21 12:06:18 -08001375 while (call_state >= 0) {
buzbee1fd33462013-03-25 13:40:45 -07001376 call_state = next_call_insn(cu_, info, call_state, dex_method_idx,
buzbeefa57c472012-11-21 12:06:18 -08001377 vtable_idx, direct_code, direct_method,
1378 original_type);
buzbee1bc37c62012-11-20 13:35:41 -08001379 }
buzbeefa57c472012-11-21 12:06:18 -08001380 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -07001381 if (cu_->instruction_set != kX86) {
1382 call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
buzbee1bc37c62012-11-20 13:35:41 -08001383 } else {
buzbeefa57c472012-11-21 12:06:18 -08001384 if (fast_path && info->type != kInterface) {
buzbee1fd33462013-03-25 13:40:45 -07001385 call_inst = OpMem(kOpBlx, TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -07001386 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value());
buzbee1bc37c62012-11-20 13:35:41 -08001387 } else {
1388 int trampoline = 0;
1389 switch (info->type) {
1390 case kInterface:
buzbeefa57c472012-11-21 12:06:18 -08001391 trampoline = fast_path ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
buzbee1bc37c62012-11-20 13:35:41 -08001392 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
1393 break;
1394 case kDirect:
1395 trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
1396 break;
1397 case kStatic:
1398 trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
1399 break;
1400 case kSuper:
1401 trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
1402 break;
1403 case kVirtual:
1404 trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
1405 break;
1406 default:
1407 LOG(FATAL) << "Unexpected invoke type";
1408 }
buzbee1fd33462013-03-25 13:40:45 -07001409 call_inst = OpThreadMem(kOpBlx, trampoline);
buzbee1bc37c62012-11-20 13:35:41 -08001410 }
1411 }
buzbee1fd33462013-03-25 13:40:45 -07001412 MarkSafepointPC(call_inst);
buzbee1bc37c62012-11-20 13:35:41 -08001413
buzbee1fd33462013-03-25 13:40:45 -07001414 ClobberCalleeSave();
buzbee1bc37c62012-11-20 13:35:41 -08001415 if (info->result.location != kLocInvalid) {
1416 // We have a following MOVE_RESULT - do it now.
1417 if (info->result.wide) {
buzbee1fd33462013-03-25 13:40:45 -07001418 RegLocation ret_loc = GetReturnWide(info->result.fp);
1419 StoreValueWide(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001420 } else {
buzbee1fd33462013-03-25 13:40:45 -07001421 RegLocation ret_loc = GetReturn(info->result.fp);
1422 StoreValue(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001423 }
1424 }
1425}
1426
buzbee31a4a6f2012-02-28 15:36:15 -08001427} // namespace art