blob: 2eab673e2c77a0470de78c9d891a5749cdb7c778 [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"
Brian Carlstrom641ce032013-01-31 15:21:37 -080019#include "oat/runtime/oat_support_entrypoints.h"
Ian Rogers07ec8e12012-12-01 01:26:51 -080020#include "x86/codegen_x86.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070021
buzbee31a4a6f2012-02-28 15:36:15 -080022namespace art {
23
24/*
25 * This source files contains "gen" codegen routines that should
26 * be applicable to most targets. Only mid-level support utilities
27 * and "op" calls may be used here.
28 */
29
buzbee31a4a6f2012-02-28 15:36:15 -080030/*
buzbee02031b12012-11-23 09:41:35 -080031 * To save scheduling time, helper calls are broken into two parts: generation of
32 * the helper target address, and the actuall call to the helper. Because x86
33 * has a memory call operation, part 1 is a NOP for x86. For other targets,
34 * load arguments between the two parts.
35 */
buzbee1fd33462013-03-25 13:40:45 -070036int Mir2Lir::CallHelperSetup(int helper_offset)
buzbee02031b12012-11-23 09:41:35 -080037{
buzbee1fd33462013-03-25 13:40:45 -070038 return (cu_->instruction_set == kX86) ? 0 : LoadHelper(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080039}
40
41/* NOTE: if r_tgt is a temp, it will be freed following use */
buzbee1fd33462013-03-25 13:40:45 -070042LIR* Mir2Lir::CallHelper(int r_tgt, int helper_offset, bool safepoint_pc)
buzbee02031b12012-11-23 09:41:35 -080043{
44 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -070045 if (cu_->instruction_set == kX86) {
46 call_inst = OpThreadMem(kOpBlx, helper_offset);
buzbee02031b12012-11-23 09:41:35 -080047 } else {
buzbee1fd33462013-03-25 13:40:45 -070048 call_inst = OpReg(kOpBlx, r_tgt);
49 FreeTemp(r_tgt);
buzbee02031b12012-11-23 09:41:35 -080050 }
51 if (safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070052 MarkSafepointPC(call_inst);
buzbee02031b12012-11-23 09:41:35 -080053 }
54 return call_inst;
55}
56
buzbee1fd33462013-03-25 13:40:45 -070057void Mir2Lir::CallRuntimeHelperImm(int helper_offset, int arg0, bool safepoint_pc) {
58 int r_tgt = CallHelperSetup(helper_offset);
59 LoadConstant(TargetReg(kArg0), arg0);
60 ClobberCalleeSave();
61 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080062}
63
buzbee1fd33462013-03-25 13:40:45 -070064void Mir2Lir::CallRuntimeHelperReg(int helper_offset, int arg0, bool safepoint_pc) {
65 int r_tgt = CallHelperSetup(helper_offset);
66 OpRegCopy(TargetReg(kArg0), arg0);
67 ClobberCalleeSave();
68 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080069}
70
buzbee1fd33462013-03-25 13:40:45 -070071void Mir2Lir::CallRuntimeHelperRegLocation(int helper_offset, RegLocation arg0, bool safepoint_pc) {
72 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080073 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070074 LoadValueDirectFixed(arg0, TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -080075 } else {
buzbee1fd33462013-03-25 13:40:45 -070076 LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080077 }
buzbee1fd33462013-03-25 13:40:45 -070078 ClobberCalleeSave();
79 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080080}
81
buzbee1fd33462013-03-25 13:40:45 -070082void Mir2Lir::CallRuntimeHelperImmImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -080083 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070084 int r_tgt = CallHelperSetup(helper_offset);
85 LoadConstant(TargetReg(kArg0), arg0);
86 LoadConstant(TargetReg(kArg1), arg1);
87 ClobberCalleeSave();
88 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080089}
90
buzbee1fd33462013-03-25 13:40:45 -070091void Mir2Lir::CallRuntimeHelperImmRegLocation(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -080092 RegLocation arg1, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070093 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080094 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070095 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080096 } else {
buzbee1fd33462013-03-25 13:40:45 -070097 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -080098 }
buzbee1fd33462013-03-25 13:40:45 -070099 LoadConstant(TargetReg(kArg0), arg0);
100 ClobberCalleeSave();
101 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800102}
103
buzbee1fd33462013-03-25 13:40:45 -0700104void Mir2Lir::CallRuntimeHelperRegLocationImm(int helper_offset, RegLocation arg0, int arg1,
105 bool safepoint_pc) {
106 int r_tgt = CallHelperSetup(helper_offset);
107 LoadValueDirectFixed(arg0, TargetReg(kArg0));
108 LoadConstant(TargetReg(kArg1), arg1);
109 ClobberCalleeSave();
110 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800111}
112
buzbee1fd33462013-03-25 13:40:45 -0700113void Mir2Lir::CallRuntimeHelperImmReg(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800114 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700115 int r_tgt = CallHelperSetup(helper_offset);
116 OpRegCopy(TargetReg(kArg1), arg1);
117 LoadConstant(TargetReg(kArg0), arg0);
118 ClobberCalleeSave();
119 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800120}
121
buzbee1fd33462013-03-25 13:40:45 -0700122void Mir2Lir::CallRuntimeHelperRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800123 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700124 int r_tgt = CallHelperSetup(helper_offset);
125 OpRegCopy(TargetReg(kArg0), arg0);
126 LoadConstant(TargetReg(kArg1), arg1);
127 ClobberCalleeSave();
128 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800129}
130
buzbee1fd33462013-03-25 13:40:45 -0700131void Mir2Lir::CallRuntimeHelperImmMethod(int helper_offset, int arg0, bool safepoint_pc) {
132 int r_tgt = CallHelperSetup(helper_offset);
133 LoadCurrMethodDirect(TargetReg(kArg1));
134 LoadConstant(TargetReg(kArg0), arg0);
135 ClobberCalleeSave();
136 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800137}
138
buzbee1fd33462013-03-25 13:40:45 -0700139void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(int helper_offset, RegLocation arg0,
140 RegLocation arg1, bool safepoint_pc) {
141 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800142 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700143 LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -0800144 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700145 if (cu_->instruction_set == kMips) {
146 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800147 } else {
buzbee1fd33462013-03-25 13:40:45 -0700148 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800149 }
150 } else {
buzbee1fd33462013-03-25 13:40:45 -0700151 if (cu_->instruction_set == kMips) {
152 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800153 } else {
buzbee1fd33462013-03-25 13:40:45 -0700154 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800155 }
156 }
157 } else {
buzbee1fd33462013-03-25 13:40:45 -0700158 LoadValueDirectWideFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800159 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700160 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800161 } else {
buzbee1fd33462013-03-25 13:40:45 -0700162 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800163 }
164 }
buzbee1fd33462013-03-25 13:40:45 -0700165 ClobberCalleeSave();
166 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800167}
168
buzbee1fd33462013-03-25 13:40:45 -0700169void Mir2Lir::CallRuntimeHelperRegReg(int helper_offset, int arg0, int arg1, bool safepoint_pc) {
170 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800171 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700172 OpRegCopy(TargetReg(kArg0), arg0);
173 OpRegCopy(TargetReg(kArg1), arg1);
174 ClobberCalleeSave();
175 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800176}
177
buzbee1fd33462013-03-25 13:40:45 -0700178void Mir2Lir::CallRuntimeHelperRegRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800179 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700180 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800181 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700182 OpRegCopy(TargetReg(kArg0), arg0);
183 OpRegCopy(TargetReg(kArg1), arg1);
184 LoadConstant(TargetReg(kArg2), arg2);
185 ClobberCalleeSave();
186 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800187}
188
buzbee1fd33462013-03-25 13:40:45 -0700189void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800190 int arg0, RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700191 int r_tgt = CallHelperSetup(helper_offset);
192 LoadValueDirectFixed(arg2, TargetReg(kArg2));
193 LoadCurrMethodDirect(TargetReg(kArg1));
194 LoadConstant(TargetReg(kArg0), arg0);
195 ClobberCalleeSave();
196 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800197}
198
buzbee1fd33462013-03-25 13:40:45 -0700199void Mir2Lir::CallRuntimeHelperImmMethodImm(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -0800200 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700201 int r_tgt = CallHelperSetup(helper_offset);
202 LoadCurrMethodDirect(TargetReg(kArg1));
203 LoadConstant(TargetReg(kArg2), arg2);
204 LoadConstant(TargetReg(kArg0), arg0);
205 ClobberCalleeSave();
206 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800207}
208
buzbee1fd33462013-03-25 13:40:45 -0700209void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800210 int arg0, RegLocation arg1,
211 RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700212 int r_tgt = CallHelperSetup(helper_offset);
213 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800214 if (arg2.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700215 LoadValueDirectFixed(arg2, TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800216 } else {
buzbee1fd33462013-03-25 13:40:45 -0700217 LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800218 }
buzbee1fd33462013-03-25 13:40:45 -0700219 LoadConstant(TargetReg(kArg0), arg0);
220 ClobberCalleeSave();
221 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800222}
223
224/*
buzbee31a4a6f2012-02-28 15:36:15 -0800225 * If there are any ins passed in registers that have not been promoted
226 * to a callee-save register, flush them to the frame. Perform intial
227 * assignment of promoted arguments.
buzbeead8f15e2012-06-18 14:49:45 -0700228 *
buzbee52a77fc2012-11-20 19:50:46 -0800229 * ArgLocs is an array of location records describing the incoming arguments
buzbeead8f15e2012-06-18 14:49:45 -0700230 * with one location record per word of argument.
buzbee31a4a6f2012-02-28 15:36:15 -0800231 */
buzbee1fd33462013-03-25 13:40:45 -0700232void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method)
buzbee31a4a6f2012-02-28 15:36:15 -0800233{
Bill Buzbeea114add2012-05-03 15:00:40 -0700234 /*
235 * Dummy up a RegLocation for the incoming Method*
buzbeef0504cd2012-11-13 16:31:10 -0800236 * It will attempt to keep kArg0 live (or copy it to home location
Bill Buzbeea114add2012-05-03 15:00:40 -0700237 * if promoted).
238 */
buzbeefa57c472012-11-21 12:06:18 -0800239 RegLocation rl_src = rl_method;
240 rl_src.location = kLocPhysReg;
241 rl_src.low_reg = TargetReg(kArg0);
242 rl_src.home = false;
buzbee1fd33462013-03-25 13:40:45 -0700243 MarkLive(rl_src.low_reg, rl_src.s_reg_low);
244 StoreValue(rl_method, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700245 // If Method* has been promoted, explicitly flush
buzbeefa57c472012-11-21 12:06:18 -0800246 if (rl_method.location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700247 StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700248 }
buzbee9c044ce2012-03-18 13:24:07 -0700249
buzbee1fd33462013-03-25 13:40:45 -0700250 if (cu_->num_ins == 0)
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 return;
buzbeefa57c472012-11-21 12:06:18 -0800252 const int num_arg_regs = 3;
253 static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
buzbee1fd33462013-03-25 13:40:45 -0700254 int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
Bill Buzbeea114add2012-05-03 15:00:40 -0700255 /*
256 * Copy incoming arguments to their proper home locations.
257 * NOTE: an older version of dx had an issue in which
258 * it would reuse static method argument registers.
259 * This could result in the same Dalvik virtual register
260 * being promoted to both core and fp regs. To account for this,
261 * we only copy to the corresponding promoted physical register
262 * if it matches the type of the SSA name for the incoming
263 * argument. It is also possible that long and double arguments
264 * end up half-promoted. In those cases, we must flush the promoted
265 * half to memory as well.
266 */
buzbee1fd33462013-03-25 13:40:45 -0700267 for (int i = 0; i < cu_->num_ins; i++) {
268 PromotionMap* v_map = &promotion_map_[start_vreg + i];
buzbeefa57c472012-11-21 12:06:18 -0800269 if (i < num_arg_regs) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700270 // If arriving in register
buzbeefa57c472012-11-21 12:06:18 -0800271 bool need_flush = true;
272 RegLocation* t_loc = &ArgLocs[i];
273 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700274 OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800275 need_flush = false;
276 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700277 OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800278 need_flush = false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700279 } else {
buzbeefa57c472012-11-21 12:06:18 -0800280 need_flush = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700281 }
buzbee86a4bce2012-03-06 18:15:00 -0800282
Bill Buzbeea114add2012-05-03 15:00:40 -0700283 // For wide args, force flush if only half is promoted
buzbeefa57c472012-11-21 12:06:18 -0800284 if (t_loc->wide) {
285 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
286 need_flush |= (p_map->core_location != v_map->core_location) ||
287 (p_map->fp_location != v_map->fp_location);
Bill Buzbeea114add2012-05-03 15:00:40 -0700288 }
buzbeefa57c472012-11-21 12:06:18 -0800289 if (need_flush) {
buzbee1fd33462013-03-25 13:40:45 -0700290 StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800291 TargetReg(arg_regs[i]), kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700292 }
293 } else {
294 // If arriving in frame & promoted
buzbeefa57c472012-11-21 12:06:18 -0800295 if (v_map->core_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700296 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800297 v_map->core_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700298 }
buzbeefa57c472012-11-21 12:06:18 -0800299 if (v_map->fp_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700300 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800301 v_map->FpReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700302 }
buzbee31a4a6f2012-02-28 15:36:15 -0800303 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700304 }
buzbee31a4a6f2012-02-28 15:36:15 -0800305}
306
307/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700308 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800309 * emit the next instruction in static & direct invoke sequences.
310 */
buzbeefa57c472012-11-21 12:06:18 -0800311static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
312 int state, uint32_t dex_idx, uint32_t unused,
313 uintptr_t direct_code, uintptr_t direct_method,
buzbeeaad94382012-11-21 07:40:50 -0800314 InvokeType type)
buzbee31a4a6f2012-02-28 15:36:15 -0800315{
buzbee1fd33462013-03-25 13:40:45 -0700316 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800317 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700318 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800319 direct_code = 0;
320 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700321 }
buzbeefa57c472012-11-21 12:06:18 -0800322 if (direct_code != 0 && direct_method != 0) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700323 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800324 case 0: // Get the current Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800325 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700326 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700327 } else {
buzbee1fd33462013-03-25 13:40:45 -0700328 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800329 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700330 data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800331 data_target->operands[1] = type;
Ian Rogers2ed3b952012-03-17 11:49:39 -0700332 }
buzbee1fd33462013-03-25 13:40:45 -0700333 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
334 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800335 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700336 }
buzbeefa57c472012-11-21 12:06:18 -0800337 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700338 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Bill Buzbeea114add2012-05-03 15:00:40 -0700339 } else {
buzbee1fd33462013-03-25 13:40:45 -0700340 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800341 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700342 data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800343 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700344 }
buzbee1fd33462013-03-25 13:40:45 -0700345 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
346 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800347 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700348 }
349 break;
350 default:
351 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800352 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700353 } else {
354 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800355 case 0: // Get the current Method* [sets kArg0]
Ian Rogers137e88f2012-10-08 17:46:47 -0700356 // TUNING: we can save a reg copy if Method* has been promoted.
buzbee1fd33462013-03-25 13:40:45 -0700357 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700358 break;
359 case 1: // Get method->dex_cache_resolved_methods_
buzbee1fd33462013-03-25 13:40:45 -0700360 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800361 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700362 // Set up direct code if known.
buzbeefa57c472012-11-21 12:06:18 -0800363 if (direct_code != 0) {
364 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700365 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700366 } else {
buzbee1fd33462013-03-25 13:40:45 -0700367 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800368 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700369 data_target = cg->AddWordData(&cg->code_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800370 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700371 }
buzbee1fd33462013-03-25 13:40:45 -0700372 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
373 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800374 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700375 }
376 }
377 break;
378 case 2: // Grab target method*
buzbee1fd33462013-03-25 13:40:45 -0700379 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800380 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
buzbee02031b12012-11-23 09:41:35 -0800381 cg-> TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700382 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700383 case 3: // Grab the code from the method*
buzbeefa57c472012-11-21 12:06:18 -0800384 if (cu->instruction_set != kX86) {
385 if (direct_code == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700386 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800387 mirror::AbstractMethod::GetCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800388 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700389 }
390 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700391 }
buzbeeb046e162012-10-30 15:48:42 -0700392 // Intentional fallthrough for x86
Bill Buzbeea114add2012-05-03 15:00:40 -0700393 default:
394 return -1;
395 }
396 }
397 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800398}
399
400/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700401 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800402 * emit the next instruction in a virtual invoke sequence.
buzbeef0504cd2012-11-13 16:31:10 -0800403 * We can use kLr as a temp prior to target address loading
buzbee31a4a6f2012-02-28 15:36:15 -0800404 * Note also that we'll load the first argument ("this") into
buzbee52a77fc2012-11-20 19:50:46 -0800405 * kArg1 here rather than the standard LoadArgRegs.
buzbee31a4a6f2012-02-28 15:36:15 -0800406 */
buzbeefa57c472012-11-21 12:06:18 -0800407static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
408 int state, uint32_t dex_idx, uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800409 uintptr_t unused, uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800410{
buzbee1fd33462013-03-25 13:40:45 -0700411 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700412 /*
413 * This is the fast path in which the target virtual method is
414 * fully resolved at compile time.
415 */
416 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800417 case 0: { // Get "this" [set kArg1]
buzbeefa57c472012-11-21 12:06:18 -0800418 RegLocation rl_arg = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700419 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700420 break;
Ian Rogers137e88f2012-10-08 17:46:47 -0700421 }
buzbeef0504cd2012-11-13 16:31:10 -0800422 case 1: // Is "this" null? [use kArg1]
buzbee1fd33462013-03-25 13:40:45 -0700423 cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
buzbeef0504cd2012-11-13 16:31:10 -0800424 // get this->klass_ [use kArg1, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700425 cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800426 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700427 break;
buzbeef0504cd2012-11-13 16:31:10 -0800428 case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700429 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800430 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700431 break;
buzbeef0504cd2012-11-13 16:31:10 -0800432 case 3: // Get target method [use kInvokeTgt, set kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700433 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800434 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
435 cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700436 break;
buzbeef0504cd2012-11-13 16:31:10 -0800437 case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
buzbeefa57c472012-11-21 12:06:18 -0800438 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700439 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800440 mirror::AbstractMethod::GetCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800441 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700442 break;
443 }
444 // Intentional fallthrough for X86
Bill Buzbeea114add2012-05-03 15:00:40 -0700445 default:
446 return -1;
447 }
448 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800449}
450
Ian Rogers137e88f2012-10-08 17:46:47 -0700451/*
Logan Chien8dbb7082013-01-25 20:31:17 +0800452 * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline,
Ian Rogers137e88f2012-10-08 17:46:47 -0700453 * which will locate the target and continue on via a tail call.
454 */
buzbeefa57c472012-11-21 12:06:18 -0800455static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
456 uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
457 uintptr_t direct_method, InvokeType unused4)
Ian Rogers137e88f2012-10-08 17:46:47 -0700458{
buzbee1fd33462013-03-25 13:40:45 -0700459 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800460 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700461 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800462 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700463 }
buzbeefa57c472012-11-21 12:06:18 -0800464 int trampoline = (cu->instruction_set == kX86) ? 0
buzbeeb046e162012-10-30 15:48:42 -0700465 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
Ian Rogers137e88f2012-10-08 17:46:47 -0700466
buzbeefa57c472012-11-21 12:06:18 -0800467 if (direct_method != 0) {
Ian Rogers137e88f2012-10-08 17:46:47 -0700468 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800469 case 0: // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800470 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700471 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700472 }
buzbeef0504cd2012-11-13 16:31:10 -0800473 // Get the interface Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800474 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700475 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Ian Rogers137e88f2012-10-08 17:46:47 -0700476 } else {
buzbee1fd33462013-03-25 13:40:45 -0700477 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, dex_idx, 0);
buzbeefa57c472012-11-21 12:06:18 -0800478 if (data_target == NULL) {
buzbee1fd33462013-03-25 13:40:45 -0700479 data_target = cg->AddWordData(&cg->method_literal_list_, dex_idx);
buzbeefa57c472012-11-21 12:06:18 -0800480 data_target->operands[1] = kInterface;
Ian Rogers137e88f2012-10-08 17:46:47 -0700481 }
buzbee1fd33462013-03-25 13:40:45 -0700482 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
483 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800484 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Ian Rogers137e88f2012-10-08 17:46:47 -0700485 }
486 break;
487 default:
488 return -1;
489 }
490 } else {
491 switch (state) {
492 case 0:
buzbeef0504cd2012-11-13 16:31:10 -0800493 // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted.
buzbee1fd33462013-03-25 13:40:45 -0700494 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800495 // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800496 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700497 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700498 }
Ian Rogers137e88f2012-10-08 17:46:47 -0700499 break;
buzbeef0504cd2012-11-13 16:31:10 -0800500 case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700501 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800502 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800503 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700504 break;
buzbeef0504cd2012-11-13 16:31:10 -0800505 case 2: // Grab target method* [set/use kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700506 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800507 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + dex_idx * 4,
buzbee02031b12012-11-23 09:41:35 -0800508 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700509 break;
510 default:
511 return -1;
512 }
513 }
514 return state + 1;
515}
516
buzbeefa57c472012-11-21 12:06:18 -0800517static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
518 int state, uint32_t dex_idx, uint32_t method_idx)
buzbee31a4a6f2012-02-28 15:36:15 -0800519{
buzbee1fd33462013-03-25 13:40:45 -0700520 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700521 /*
522 * This handles the case in which the base method is not fully
523 * resolved at compile time, we bail to a runtime helper.
524 */
525 if (state == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800526 if (cu->instruction_set != kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700527 // Load trampoline target
buzbee1fd33462013-03-25 13:40:45 -0700528 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700529 }
buzbeef0504cd2012-11-13 16:31:10 -0800530 // Load kArg0 with method index
buzbee1fd33462013-03-25 13:40:45 -0700531 cg->LoadConstant(cg->TargetReg(kArg0), dex_idx);
Bill Buzbeea114add2012-05-03 15:00:40 -0700532 return 1;
533 }
534 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800535}
536
buzbeefa57c472012-11-21 12:06:18 -0800537static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
538 int state, uint32_t dex_idx, uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800539 uintptr_t unused, uintptr_t unused2,
Brian Carlstromf5822582012-03-19 22:34:31 -0700540 InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800541{
Ian Rogers57b86d42012-03-27 16:05:41 -0700542 int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800543 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800544}
545
buzbeefa57c472012-11-21 12:06:18 -0800546static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
547 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800548 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800549{
Ian Rogers57b86d42012-03-27 16:05:41 -0700550 int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800551 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800552}
553
buzbeefa57c472012-11-21 12:06:18 -0800554static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
555 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
Brian Carlstromf5822582012-03-19 22:34:31 -0700556 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800557{
Ian Rogers57b86d42012-03-27 16:05:41 -0700558 int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800559 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800560}
561
buzbeefa57c472012-11-21 12:06:18 -0800562static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
563 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800564 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800565{
Ian Rogers57b86d42012-03-27 16:05:41 -0700566 int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800567 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800568}
569
buzbeefa57c472012-11-21 12:06:18 -0800570static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
buzbeeaad94382012-11-21 07:40:50 -0800571 CallInfo* info, int state,
buzbeefa57c472012-11-21 12:06:18 -0800572 uint32_t dex_idx, uint32_t unused,
buzbee15bf9802012-06-12 17:49:27 -0700573 uintptr_t unused2, uintptr_t unused3,
574 InvokeType unused4)
buzbee31a4a6f2012-02-28 15:36:15 -0800575{
Ian Rogers57b86d42012-03-27 16:05:41 -0700576 int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800577 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800578}
579
buzbee1fd33462013-03-25 13:40:45 -0700580int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
581 NextCallInsn next_call_insn, uint32_t dex_idx,
582 uint32_t method_idx, uintptr_t direct_code,
583 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800584{
buzbee1fd33462013-03-25 13:40:45 -0700585 int last_arg_reg = TargetReg(kArg3);
586 int next_reg = TargetReg(kArg1);
buzbeefa57c472012-11-21 12:06:18 -0800587 int next_arg = 0;
588 if (skip_this) {
589 next_reg++;
590 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700591 }
buzbeefa57c472012-11-21 12:06:18 -0800592 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
593 RegLocation rl_arg = info->args[next_arg++];
buzbee1fd33462013-03-25 13:40:45 -0700594 rl_arg = UpdateRawLoc(rl_arg);
595 if (rl_arg.wide && (next_reg <= TargetReg(kArg2))) {
596 LoadValueDirectWideFixed(rl_arg, next_reg, next_reg + 1);
buzbeefa57c472012-11-21 12:06:18 -0800597 next_reg++;
598 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700599 } else {
buzbeee6285f92012-12-06 15:57:46 -0800600 if (rl_arg.wide) {
601 rl_arg.wide = false;
602 rl_arg.is_const = false;
603 }
buzbee1fd33462013-03-25 13:40:45 -0700604 LoadValueDirectFixed(rl_arg, next_reg);
buzbee31a4a6f2012-02-28 15:36:15 -0800605 }
buzbee1fd33462013-03-25 13:40:45 -0700606 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800607 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700608 }
buzbeefa57c472012-11-21 12:06:18 -0800609 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800610}
611
612/*
613 * Load up to 5 arguments, the first three of which will be in
buzbeef0504cd2012-11-13 16:31:10 -0800614 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer,
buzbee31a4a6f2012-02-28 15:36:15 -0800615 * and as part of the load sequence, it must be replaced with
616 * the target method pointer. Note, this may also be called
617 * for "range" variants if the number of arguments is 5 or fewer.
618 */
buzbee1fd33462013-03-25 13:40:45 -0700619int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
buzbee02031b12012-11-23 09:41:35 -0800620 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
621 uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
622 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800623{
buzbeefa57c472012-11-21 12:06:18 -0800624 RegLocation rl_arg;
buzbee31a4a6f2012-02-28 15:36:15 -0800625
Bill Buzbeea114add2012-05-03 15:00:40 -0700626 /* If no arguments, just return */
buzbeefa57c472012-11-21 12:06:18 -0800627 if (info->num_arg_words == 0)
628 return call_state;
Bill Buzbeea114add2012-05-03 15:00:40 -0700629
buzbee1fd33462013-03-25 13:40:45 -0700630 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800631 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700632
buzbeefa57c472012-11-21 12:06:18 -0800633 DCHECK_LE(info->num_arg_words, 5);
634 if (info->num_arg_words > 3) {
635 int32_t next_use = 3;
Bill Buzbeea114add2012-05-03 15:00:40 -0700636 //Detect special case of wide arg spanning arg3/arg4
buzbeefa57c472012-11-21 12:06:18 -0800637 RegLocation rl_use0 = info->args[0];
638 RegLocation rl_use1 = info->args[1];
639 RegLocation rl_use2 = info->args[2];
640 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
641 rl_use2.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700642 int reg = -1;
643 // Wide spans, we need the 2nd half of uses[2].
buzbee1fd33462013-03-25 13:40:45 -0700644 rl_arg = UpdateLocWide(rl_use2);
buzbeefa57c472012-11-21 12:06:18 -0800645 if (rl_arg.location == kLocPhysReg) {
646 reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700647 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800648 // kArg2 & rArg3 can safely be used here
buzbee52a77fc2012-11-20 19:50:46 -0800649 reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700650 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
651 call_state = next_call_insn(cu_, info, call_state, dex_idx,
buzbeefa57c472012-11-21 12:06:18 -0800652 method_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700653 }
buzbee1fd33462013-03-25 13:40:45 -0700654 StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
655 StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
656 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800657 direct_code, direct_method, type);
658 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700659 }
660 // Loop through the rest
buzbeefa57c472012-11-21 12:06:18 -0800661 while (next_use < info->num_arg_words) {
662 int low_reg;
663 int high_reg = -1;
664 rl_arg = info->args[next_use];
buzbee1fd33462013-03-25 13:40:45 -0700665 rl_arg = UpdateRawLoc(rl_arg);
buzbeefa57c472012-11-21 12:06:18 -0800666 if (rl_arg.location == kLocPhysReg) {
667 low_reg = rl_arg.low_reg;
668 high_reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700669 } else {
buzbeefa57c472012-11-21 12:06:18 -0800670 low_reg = TargetReg(kArg2);
671 if (rl_arg.wide) {
672 high_reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700673 LoadValueDirectWideFixed(rl_arg, low_reg, high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700674 } else {
buzbee1fd33462013-03-25 13:40:45 -0700675 LoadValueDirectFixed(rl_arg, low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700676 }
buzbee1fd33462013-03-25 13:40:45 -0700677 call_state = next_call_insn(cu_, info, call_state, dex_idx,
buzbeefa57c472012-11-21 12:06:18 -0800678 method_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700679 }
buzbeefa57c472012-11-21 12:06:18 -0800680 int outs_offset = (next_use + 1) * 4;
681 if (rl_arg.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700682 StoreBaseDispWide(TargetReg(kSp), outs_offset, low_reg, high_reg);
buzbeefa57c472012-11-21 12:06:18 -0800683 next_use += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700684 } else {
buzbee1fd33462013-03-25 13:40:45 -0700685 StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800686 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700687 }
buzbee1fd33462013-03-25 13:40:45 -0700688 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800689 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700690 }
691 }
692
buzbee1fd33462013-03-25 13:40:45 -0700693 call_state = LoadArgRegs(info, call_state, next_call_insn,
buzbeefa57c472012-11-21 12:06:18 -0800694 dex_idx, method_idx, direct_code, direct_method,
695 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700696
697 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700698 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700699 }
buzbeefa57c472012-11-21 12:06:18 -0800700 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800701}
702
703/*
704 * May have 0+ arguments (also used for jumbo). Note that
705 * source virtual registers may be in physical registers, so may
706 * need to be flushed to home location before copying. This
707 * applies to arg3 and above (see below).
708 *
709 * Two general strategies:
710 * If < 20 arguments
711 * Pass args 3-18 using vldm/vstm block copy
buzbeef0504cd2012-11-13 16:31:10 -0800712 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800713 * If 20+ arguments
714 * Pass args arg19+ using memcpy block copy
buzbeef0504cd2012-11-13 16:31:10 -0800715 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800716 *
717 */
buzbee1fd33462013-03-25 13:40:45 -0700718int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
buzbee02031b12012-11-23 09:41:35 -0800719 LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
720 uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
721 InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800722{
buzbee31a4a6f2012-02-28 15:36:15 -0800723
Bill Buzbeea114add2012-05-03 15:00:40 -0700724 // If we can treat it as non-range (Jumbo ops will use range form)
buzbeefa57c472012-11-21 12:06:18 -0800725 if (info->num_arg_words <= 5)
buzbee1fd33462013-03-25 13:40:45 -0700726 return GenDalvikArgsNoRange(info, call_state, pcrLabel,
buzbeefa57c472012-11-21 12:06:18 -0800727 next_call_insn, dex_idx, method_idx,
728 direct_code, direct_method, type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700729 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700730 * First load the non-register arguments. Both forms expect all
731 * of the source arguments to be in their home frame location, so
buzbeefa57c472012-11-21 12:06:18 -0800732 * scan the s_reg names and flush any that have been promoted to
Bill Buzbeea114add2012-05-03 15:00:40 -0700733 * frame backing storage.
734 */
buzbeefa57c472012-11-21 12:06:18 -0800735 // Scan the rest of the args - if in phys_reg flush to memory
736 for (int next_arg = 0; next_arg < info->num_arg_words;) {
737 RegLocation loc = info->args[next_arg];
Bill Buzbeea114add2012-05-03 15:00:40 -0700738 if (loc.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700739 loc = UpdateLocWide(loc);
buzbeefa57c472012-11-21 12:06:18 -0800740 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700741 StoreBaseDispWide(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800742 loc.low_reg, loc.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700743 }
buzbeefa57c472012-11-21 12:06:18 -0800744 next_arg += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700745 } else {
buzbee1fd33462013-03-25 13:40:45 -0700746 loc = UpdateLoc(loc);
buzbeefa57c472012-11-21 12:06:18 -0800747 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700748 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800749 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700750 }
buzbeefa57c472012-11-21 12:06:18 -0800751 next_arg++;
buzbee31a4a6f2012-02-28 15:36:15 -0800752 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700753 }
buzbee31a4a6f2012-02-28 15:36:15 -0800754
buzbee1fd33462013-03-25 13:40:45 -0700755 int start_offset = SRegOffset(info->args[3].s_reg_low);
buzbeefa57c472012-11-21 12:06:18 -0800756 int outs_offset = 4 /* Method* */ + (3 * 4);
buzbee1fd33462013-03-25 13:40:45 -0700757 if (cu_->instruction_set != kThumb2) {
buzbee31a4a6f2012-02-28 15:36:15 -0800758 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700759 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
760 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
761 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800762 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700763 } else {
buzbeefa57c472012-11-21 12:06:18 -0800764 if (info->num_arg_words >= 20) {
buzbeeb046e162012-10-30 15:48:42 -0700765 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700766 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
767 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
768 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800769 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
buzbeeb046e162012-10-30 15:48:42 -0700770 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800771 // Use vldm/vstm pair using kArg3 as a temp
buzbeefa57c472012-11-21 12:06:18 -0800772 int regs_left = std::min(info->num_arg_words - 3, 16);
buzbee1fd33462013-03-25 13:40:45 -0700773 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800774 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700775 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
776 LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
buzbeeb046e162012-10-30 15:48:42 -0700777 //TUNING: loosen barrier
buzbeefa57c472012-11-21 12:06:18 -0800778 ld->def_mask = ENCODE_ALL;
buzbee1fd33462013-03-25 13:40:45 -0700779 SetMemRefType(ld, true /* is_load */, kDalvikReg);
780 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800781 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700782 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
783 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800784 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700785 LIR* st = OpVstm(TargetReg(kArg3), regs_left);
786 SetMemRefType(st, false /* is_load */, kDalvikReg);
buzbeefa57c472012-11-21 12:06:18 -0800787 st->def_mask = ENCODE_ALL;
buzbee1fd33462013-03-25 13:40:45 -0700788 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800789 direct_code, direct_method, type);
buzbeeb046e162012-10-30 15:48:42 -0700790 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700791 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700792
buzbee1fd33462013-03-25 13:40:45 -0700793 call_state = LoadArgRegs(info, call_state, next_call_insn,
buzbeefa57c472012-11-21 12:06:18 -0800794 dex_idx, method_idx, direct_code, direct_method,
795 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700796
buzbee1fd33462013-03-25 13:40:45 -0700797 call_state = next_call_insn(cu_, info, call_state, dex_idx, method_idx,
buzbeefa57c472012-11-21 12:06:18 -0800798 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700799 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700800 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700801 }
buzbeefa57c472012-11-21 12:06:18 -0800802 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800803}
804
buzbee1fd33462013-03-25 13:40:45 -0700805RegLocation Mir2Lir::InlineTarget(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700806{
Bill Buzbeea114add2012-05-03 15:00:40 -0700807 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700808 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700809 res = GetReturn(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700810 } else {
buzbee15bf9802012-06-12 17:49:27 -0700811 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700812 }
813 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700814}
815
buzbee1fd33462013-03-25 13:40:45 -0700816RegLocation Mir2Lir::InlineTargetWide(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700817{
Bill Buzbeea114add2012-05-03 15:00:40 -0700818 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700819 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700820 res = GetReturnWide(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700821 } else {
buzbee15bf9802012-06-12 17:49:27 -0700822 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700823 }
824 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700825}
826
buzbee1fd33462013-03-25 13:40:45 -0700827bool Mir2Lir::GenInlinedCharAt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700828{
buzbee1fd33462013-03-25 13:40:45 -0700829 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700830 // TODO - add Mips implementation
831 return false;
832 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700833 // Location of reference to data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800834 int value_offset = mirror::String::ValueOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700835 // Location of count
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800836 int count_offset = mirror::String::CountOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700837 // Starting offset within data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800838 int offset_offset = mirror::String::OffsetOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700839 // Start of char data with array_
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800840 int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
buzbeefc9e6fa2012-03-23 15:14:29 -0700841
buzbeefa57c472012-11-21 12:06:18 -0800842 RegLocation rl_obj = info->args[0];
843 RegLocation rl_idx = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -0700844 rl_obj = LoadValue(rl_obj, kCoreReg);
845 rl_idx = LoadValue(rl_idx, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800846 int reg_max;
buzbee1fd33462013-03-25 13:40:45 -0700847 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -0800848 bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
849 LIR* launch_pad = NULL;
850 int reg_off = INVALID_REG;
851 int reg_ptr = INVALID_REG;
buzbee1fd33462013-03-25 13:40:45 -0700852 if (cu_->instruction_set != kX86) {
853 reg_off = AllocTemp();
854 reg_ptr = AllocTemp();
buzbeefa57c472012-11-21 12:06:18 -0800855 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700856 reg_max = AllocTemp();
857 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700858 }
buzbee1fd33462013-03-25 13:40:45 -0700859 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
860 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
buzbeefa57c472012-11-21 12:06:18 -0800861 if (range_check) {
buzbeeb046e162012-10-30 15:48:42 -0700862 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700863 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700864 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700865 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
866 FreeTemp(reg_max);
867 OpCondBranch(kCondCs, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700868 }
869 } else {
buzbeefa57c472012-11-21 12:06:18 -0800870 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700871 reg_max = AllocTemp();
872 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700873 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700874 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700875 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700876 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
877 FreeTemp(reg_max);
878 OpCondBranch(kCondCc, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700879 }
buzbee1fd33462013-03-25 13:40:45 -0700880 reg_off = AllocTemp();
881 reg_ptr = AllocTemp();
882 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
883 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700884 }
buzbee1fd33462013-03-25 13:40:45 -0700885 OpRegImm(kOpAdd, reg_ptr, data_offset);
886 OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
887 FreeTemp(rl_obj.low_reg);
888 FreeTemp(rl_idx.low_reg);
889 RegLocation rl_dest = InlineTarget(info);
890 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
891 LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
892 FreeTemp(reg_off);
893 FreeTemp(reg_ptr);
894 StoreValue(rl_dest, rl_result);
buzbeefa57c472012-11-21 12:06:18 -0800895 if (range_check) {
896 launch_pad->operands[2] = 0; // no resumption
Bill Buzbeea114add2012-05-03 15:00:40 -0700897 }
898 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -0800899 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
Bill Buzbeea114add2012-05-03 15:00:40 -0700900 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700901}
902
buzbeefa57c472012-11-21 12:06:18 -0800903// Generates an inlined String.is_empty or String.length.
buzbee1fd33462013-03-25 13:40:45 -0700904bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty)
buzbeefc9e6fa2012-03-23 15:14:29 -0700905{
buzbee1fd33462013-03-25 13:40:45 -0700906 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700907 // TODO - add Mips implementation
908 return false;
909 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700910 // dst = src.length();
buzbeefa57c472012-11-21 12:06:18 -0800911 RegLocation rl_obj = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700912 rl_obj = LoadValue(rl_obj, kCoreReg);
913 RegLocation rl_dest = InlineTarget(info);
914 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
915 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
916 LoadWordDisp(rl_obj.low_reg, mirror::String::CountOffset().Int32Value(), rl_result.low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800917 if (is_empty) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700918 // dst = (dst == 0);
buzbee1fd33462013-03-25 13:40:45 -0700919 if (cu_->instruction_set == kThumb2) {
920 int t_reg = AllocTemp();
921 OpRegReg(kOpNeg, t_reg, rl_result.low_reg);
922 OpRegRegReg(kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
buzbeeb046e162012-10-30 15:48:42 -0700923 } else {
buzbee1fd33462013-03-25 13:40:45 -0700924 DCHECK_EQ(cu_->instruction_set, kX86);
925 OpRegImm(kOpSub, rl_result.low_reg, 1);
926 OpRegImm(kOpLsr, rl_result.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -0700927 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700928 }
buzbee1fd33462013-03-25 13:40:45 -0700929 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700930 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700931}
932
buzbee1fd33462013-03-25 13:40:45 -0700933bool Mir2Lir::GenInlinedAbsInt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700934{
buzbee1fd33462013-03-25 13:40:45 -0700935 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700936 // TODO - add Mips implementation
937 return false;
938 }
buzbeefa57c472012-11-21 12:06:18 -0800939 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700940 rl_src = LoadValue(rl_src, kCoreReg);
941 RegLocation rl_dest = InlineTarget(info);
942 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
943 int sign_reg = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -0700944 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700945 OpRegRegImm(kOpAsr, sign_reg, rl_src.low_reg, 31);
946 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
947 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
948 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700949 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700950}
951
buzbee1fd33462013-03-25 13:40:45 -0700952bool Mir2Lir::GenInlinedAbsLong(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700953{
buzbee1fd33462013-03-25 13:40:45 -0700954 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700955 // TODO - add Mips implementation
956 return false;
957 }
buzbee1fd33462013-03-25 13:40:45 -0700958 if (cu_->instruction_set == kThumb2) {
buzbeefa57c472012-11-21 12:06:18 -0800959 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700960 rl_src = LoadValueWide(rl_src, kCoreReg);
961 RegLocation rl_dest = InlineTargetWide(info);
962 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
963 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700964 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700965 OpRegRegImm(kOpAsr, sign_reg, rl_src.high_reg, 31);
966 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
967 OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
968 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
969 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
970 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -0700971 return true;
972 } else {
buzbee1fd33462013-03-25 13:40:45 -0700973 DCHECK_EQ(cu_->instruction_set, kX86);
buzbeeb046e162012-10-30 15:48:42 -0700974 // Reuse source registers to avoid running out of temps
buzbeefa57c472012-11-21 12:06:18 -0800975 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700976 rl_src = LoadValueWide(rl_src, kCoreReg);
977 RegLocation rl_dest = InlineTargetWide(info);
978 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
979 OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
980 FreeTemp(rl_src.low_reg);
981 FreeTemp(rl_src.high_reg);
982 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700983 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700984 OpRegRegImm(kOpAsr, sign_reg, rl_result.high_reg, 31);
985 OpRegReg(kOpAdd, rl_result.low_reg, sign_reg);
986 OpRegReg(kOpAdc, rl_result.high_reg, sign_reg);
987 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
988 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
989 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -0700990 return true;
991 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700992}
993
buzbee1fd33462013-03-25 13:40:45 -0700994bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700995{
buzbee1fd33462013-03-25 13:40:45 -0700996 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700997 // TODO - add Mips implementation
998 return false;
999 }
buzbeefa57c472012-11-21 12:06:18 -08001000 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001001 RegLocation rl_dest = InlineTarget(info);
1002 StoreValue(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001003 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001004}
1005
buzbee1fd33462013-03-25 13:40:45 -07001006bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001007{
buzbee1fd33462013-03-25 13:40:45 -07001008 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001009 // TODO - add Mips implementation
1010 return false;
1011 }
buzbeefa57c472012-11-21 12:06:18 -08001012 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001013 RegLocation rl_dest = InlineTargetWide(info);
1014 StoreValueWide(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001015 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001016}
1017
1018/*
buzbeefa57c472012-11-21 12:06:18 -08001019 * Fast string.index_of(I) & (II). Tests for simple case of char <= 0xffff,
buzbeefc9e6fa2012-03-23 15:14:29 -07001020 * otherwise bails to standard library code.
1021 */
buzbee1fd33462013-03-25 13:40:45 -07001022bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based)
buzbeefc9e6fa2012-03-23 15:14:29 -07001023{
buzbee1fd33462013-03-25 13:40:45 -07001024 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001025 // TODO - add Mips implementation
1026 return false;
1027 }
buzbee1fd33462013-03-25 13:40:45 -07001028 ClobberCalleeSave();
1029 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001030 int reg_ptr = TargetReg(kArg0);
1031 int reg_char = TargetReg(kArg1);
1032 int reg_start = TargetReg(kArg2);
buzbeefc9e6fa2012-03-23 15:14:29 -07001033
buzbeefa57c472012-11-21 12:06:18 -08001034 RegLocation rl_obj = info->args[0];
1035 RegLocation rl_char = info->args[1];
1036 RegLocation rl_start = info->args[2];
buzbee1fd33462013-03-25 13:40:45 -07001037 LoadValueDirectFixed(rl_obj, reg_ptr);
1038 LoadValueDirectFixed(rl_char, reg_char);
buzbeefa57c472012-11-21 12:06:18 -08001039 if (zero_based) {
buzbee1fd33462013-03-25 13:40:45 -07001040 LoadConstant(reg_start, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001041 } else {
buzbee1fd33462013-03-25 13:40:45 -07001042 LoadValueDirectFixed(rl_start, reg_start);
Bill Buzbeea114add2012-05-03 15:00:40 -07001043 }
buzbee1fd33462013-03-25 13:40:45 -07001044 int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(ENTRYPOINT_OFFSET(pIndexOf)) : 0;
1045 GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
1046 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001047 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001048 OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001049 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001050 if (cu_->instruction_set != kX86) {
1051 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001052 } else {
buzbee1fd33462013-03-25 13:40:45 -07001053 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pIndexOf));
buzbeeb046e162012-10-30 15:48:42 -07001054 }
buzbee1fd33462013-03-25 13:40:45 -07001055 LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -08001056 launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -07001057 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001058 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001059 RegLocation rl_return = GetReturn(false);
1060 RegLocation rl_dest = InlineTarget(info);
1061 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001062 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001063}
1064
1065/* Fast string.compareTo(Ljava/lang/string;)I. */
buzbee1fd33462013-03-25 13:40:45 -07001066bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001067{
buzbee1fd33462013-03-25 13:40:45 -07001068 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001069 // TODO - add Mips implementation
1070 return false;
1071 }
buzbee1fd33462013-03-25 13:40:45 -07001072 ClobberCalleeSave();
1073 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001074 int reg_this = TargetReg(kArg0);
1075 int reg_cmp = TargetReg(kArg1);
buzbeefc9e6fa2012-03-23 15:14:29 -07001076
buzbeefa57c472012-11-21 12:06:18 -08001077 RegLocation rl_this = info->args[0];
1078 RegLocation rl_cmp = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -07001079 LoadValueDirectFixed(rl_this, reg_this);
1080 LoadValueDirectFixed(rl_cmp, reg_cmp);
1081 int r_tgt = (cu_->instruction_set != kX86) ?
1082 LoadHelper(ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
1083 GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -08001084 //TUNING: check if rl_cmp.s_reg_low is already null checked
buzbee1fd33462013-03-25 13:40:45 -07001085 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001086 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001087 OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001088 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001089 if (cu_->instruction_set != kX86) {
1090 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001091 } else {
buzbee1fd33462013-03-25 13:40:45 -07001092 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo));
buzbeeb046e162012-10-30 15:48:42 -07001093 }
buzbeefa57c472012-11-21 12:06:18 -08001094 launch_pad->operands[2] = 0; // No return possible
Bill Buzbeea114add2012-05-03 15:00:40 -07001095 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001096 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001097 RegLocation rl_return = GetReturn(false);
1098 RegLocation rl_dest = InlineTarget(info);
1099 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001100 return true;
Ian Rogers0183dd72012-09-17 23:06:51 -07001101}
1102
buzbee1fd33462013-03-25 13:40:45 -07001103bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1104 RegLocation rl_dest = InlineTarget(info);
1105 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001106 int offset = Thread::PeerOffset().Int32Value();
buzbee1fd33462013-03-25 13:40:45 -07001107 if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
1108 LoadWordDisp(TargetReg(kSelf), offset, rl_result.low_reg);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001109 } else {
buzbee1fd33462013-03-25 13:40:45 -07001110 CHECK(cu_->instruction_set == kX86);
1111 ((X86Mir2Lir*)this)->OpRegThreadMem(kOpMov, rl_result.low_reg, offset);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001112 }
buzbee1fd33462013-03-25 13:40:45 -07001113 StoreValue(rl_dest, rl_result);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001114 return true;
1115}
1116
buzbee1fd33462013-03-25 13:40:45 -07001117bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001118 bool is_long, bool is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001119 if (cu_->instruction_set == kMips) {
Jeff Hao9bd02812013-02-08 14:29:50 -08001120 // TODO - add Mips implementation
Jeff Hao5a70fe82013-02-07 15:02:10 -08001121 return false;
1122 }
1123 // Unused - RegLocation rl_src_unsafe = info->args[0];
1124 RegLocation rl_src_obj = info->args[1]; // Object
1125 RegLocation rl_src_offset = info->args[2]; // long low
1126 rl_src_offset.wide = 0; // ignore high half in info->args[3]
buzbee1fd33462013-03-25 13:40:45 -07001127 RegLocation rl_dest = InlineTarget(info); // result reg
Jeff Hao5a70fe82013-02-07 15:02:10 -08001128 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001129 GenMemBarrier(kLoadLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001130 }
buzbee1fd33462013-03-25 13:40:45 -07001131 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1132 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1133 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001134 if (is_long) {
buzbee1fd33462013-03-25 13:40:45 -07001135 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1136 LoadBaseDispWide(rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
1137 StoreValueWide(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001138 } else {
buzbee1fd33462013-03-25 13:40:45 -07001139 LoadBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
1140 StoreValue(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001141 }
1142 return true;
1143}
1144
buzbee1fd33462013-03-25 13:40:45 -07001145bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001146 bool is_object, bool is_volatile, bool is_ordered) {
buzbee1fd33462013-03-25 13:40:45 -07001147 if (cu_->instruction_set == kMips) {
Jeff Hao9bd02812013-02-08 14:29:50 -08001148 // TODO - add Mips implementation
Jeff Hao5a70fe82013-02-07 15:02:10 -08001149 return false;
1150 }
1151 // Unused - RegLocation rl_src_unsafe = info->args[0];
1152 RegLocation rl_src_obj = info->args[1]; // Object
1153 RegLocation rl_src_offset = info->args[2]; // long low
1154 rl_src_offset.wide = 0; // ignore high half in info->args[3]
1155 RegLocation rl_src_value = info->args[4]; // value to store
1156 if (is_volatile || is_ordered) {
buzbee1fd33462013-03-25 13:40:45 -07001157 GenMemBarrier(kStoreStore);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001158 }
buzbee1fd33462013-03-25 13:40:45 -07001159 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1160 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1161 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001162 if (is_long) {
buzbee1fd33462013-03-25 13:40:45 -07001163 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1164 StoreBaseDispWide(rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001165 } else {
buzbee1fd33462013-03-25 13:40:45 -07001166 StoreBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001167 }
1168 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001169 GenMemBarrier(kStoreLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001170 }
1171 if (is_object) {
buzbee1fd33462013-03-25 13:40:45 -07001172 MarkGCCard(rl_value.low_reg, rl_object.low_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001173 }
1174 return true;
1175}
1176
buzbee1fd33462013-03-25 13:40:45 -07001177bool Mir2Lir::GenIntrinsic(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001178{
buzbeefa57c472012-11-21 12:06:18 -08001179 if (info->opt_flags & MIR_INLINED) {
buzbeefc9e6fa2012-03-23 15:14:29 -07001180 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001181 }
1182 /*
1183 * TODO: move these to a target-specific structured constant array
1184 * and use a generic match function. The list of intrinsics may be
1185 * slightly different depending on target.
1186 * TODO: Fold this into a matching function that runs during
1187 * basic block building. This should be part of the action for
1188 * small method inlining and recognition of the special object init
1189 * method. By doing this during basic block construction, we can also
1190 * take advantage of/generate new useful dataflow info.
1191 */
buzbee1fd33462013-03-25 13:40:45 -07001192 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001193 if (tgt_method.find(" java.lang") != std::string::npos) {
1194 if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001195 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001196 }
buzbeefa57c472012-11-21 12:06:18 -08001197 if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001198 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001199 }
buzbeefa57c472012-11-21 12:06:18 -08001200 if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
buzbee1fd33462013-03-25 13:40:45 -07001201 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001202 }
buzbeefa57c472012-11-21 12:06:18 -08001203 if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001204 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001205 }
buzbeefa57c472012-11-21 12:06:18 -08001206 if (tgt_method == "int java.lang.Math.abs(int)" ||
1207 tgt_method == "int java.lang.StrictMath.abs(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001208 return GenInlinedAbsInt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001209 }
buzbeefa57c472012-11-21 12:06:18 -08001210 if (tgt_method == "long java.lang.Math.abs(long)" ||
1211 tgt_method == "long java.lang.StrictMath.abs(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001212 return GenInlinedAbsLong(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001213 }
buzbeefa57c472012-11-21 12:06:18 -08001214 if (tgt_method == "int java.lang.Math.max(int, int)" ||
1215 tgt_method == "int java.lang.StrictMath.max(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001216 return GenInlinedMinMaxInt(info, false /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001217 }
buzbeefa57c472012-11-21 12:06:18 -08001218 if (tgt_method == "int java.lang.Math.min(int, int)" ||
1219 tgt_method == "int java.lang.StrictMath.min(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001220 return GenInlinedMinMaxInt(info, true /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001221 }
buzbeefa57c472012-11-21 12:06:18 -08001222 if (tgt_method == "double java.lang.Math.sqrt(double)" ||
1223 tgt_method == "double java.lang.StrictMath.sqrt(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001224 return GenInlinedSqrt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001225 }
buzbeefa57c472012-11-21 12:06:18 -08001226 if (tgt_method == "char java.lang.String.charAt(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001227 return GenInlinedCharAt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001228 }
buzbeefa57c472012-11-21 12:06:18 -08001229 if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
buzbee1fd33462013-03-25 13:40:45 -07001230 return GenInlinedStringCompareTo(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001231 }
buzbeefa57c472012-11-21 12:06:18 -08001232 if (tgt_method == "boolean java.lang.String.is_empty()") {
buzbee1fd33462013-03-25 13:40:45 -07001233 return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001234 }
buzbeefa57c472012-11-21 12:06:18 -08001235 if (tgt_method == "int java.lang.String.index_of(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001236 return GenInlinedIndexOf(info, false /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001237 }
buzbeefa57c472012-11-21 12:06:18 -08001238 if (tgt_method == "int java.lang.String.index_of(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001239 return GenInlinedIndexOf(info, true /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001240 }
buzbeefa57c472012-11-21 12:06:18 -08001241 if (tgt_method == "int java.lang.String.length()") {
buzbee1fd33462013-03-25 13:40:45 -07001242 return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001243 }
Ian Rogers07ec8e12012-12-01 01:26:51 -08001244 if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
buzbee1fd33462013-03-25 13:40:45 -07001245 return GenInlinedCurrentThread(info);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001246 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001247 } else if (tgt_method.find(" sun.misc.Unsafe") != std::string::npos) {
buzbeefa57c472012-11-21 12:06:18 -08001248 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001249 return GenInlinedCas32(info, false);
Ian Rogers0183dd72012-09-17 23:06:51 -07001250 }
buzbeefa57c472012-11-21 12:06:18 -08001251 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001252 return GenInlinedCas32(info, true);
Ian Rogers0183dd72012-09-17 23:06:51 -07001253 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001254 if (tgt_method == "int sun.misc.Unsafe.getInt(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001255 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001256 }
1257 if (tgt_method == "int sun.misc.Unsafe.getIntVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001258 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001259 }
1260 if (tgt_method == "void sun.misc.Unsafe.putInt(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001261 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001262 false /* is_volatile */, false /* is_ordered */);
1263 }
1264 if (tgt_method == "void sun.misc.Unsafe.putIntVolatile(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 true /* is_volatile */, false /* is_ordered */);
1267 }
1268 if (tgt_method == "void sun.misc.Unsafe.putOrderedInt(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 false /* is_volatile */, true /* is_ordered */);
1271 }
1272 if (tgt_method == "long sun.misc.Unsafe.getLong(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001273 return GenInlinedUnsafeGet(info, true /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001274 }
1275 if (tgt_method == "long sun.misc.Unsafe.getLongVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001276 return GenInlinedUnsafeGet(info, true /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001277 }
1278 if (tgt_method == "void sun.misc.Unsafe.putLong(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001279 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001280 false /* is_volatile */, false /* is_ordered */);
1281 }
1282 if (tgt_method == "void sun.misc.Unsafe.putLongVolatile(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 true /* is_volatile */, false /* is_ordered */);
1285 }
1286 if (tgt_method == "void sun.misc.Unsafe.putOrderedLong(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 false /* is_volatile */, true /* is_ordered */);
1289 }
1290 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObject(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001291 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001292 }
1293 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001294 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001295 }
1296 if (tgt_method == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001297 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001298 false /* is_volatile */, false /* is_ordered */);
1299 }
1300 if (tgt_method == "void sun.misc.Unsafe.putObjectVolatile(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 true /* is_volatile */, false /* is_ordered */);
1303 }
1304 if (tgt_method == "void sun.misc.Unsafe.putOrderedObject(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 false /* is_volatile */, true /* is_ordered */);
1307 }
Ian Rogerse13eafa2012-09-07 11:24:27 -07001308 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001309 return false;
buzbeefc9e6fa2012-03-23 15:14:29 -07001310}
1311
buzbee1fd33462013-03-25 13:40:45 -07001312void Mir2Lir::GenInvoke(CallInfo* info)
buzbee1bc37c62012-11-20 13:35:41 -08001313{
buzbee1fd33462013-03-25 13:40:45 -07001314 if (GenIntrinsic(info)) {
buzbee1bc37c62012-11-20 13:35:41 -08001315 return;
1316 }
buzbeefa57c472012-11-21 12:06:18 -08001317 InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
1318 int call_state = 0;
1319 LIR* null_ck;
1320 LIR** p_null_ck = NULL;
1321 NextCallInsn next_call_insn;
buzbee1fd33462013-03-25 13:40:45 -07001322 FlushAllRegs(); /* Everything to home location */
buzbee1bc37c62012-11-20 13:35:41 -08001323 // Explicit register usage
buzbee1fd33462013-03-25 13:40:45 -07001324 LockCallTemps();
buzbee1bc37c62012-11-20 13:35:41 -08001325
buzbeefa57c472012-11-21 12:06:18 -08001326 uint32_t dex_method_idx = info->index;
1327 int vtable_idx;
1328 uintptr_t direct_code;
1329 uintptr_t direct_method;
1330 bool skip_this;
buzbee1fd33462013-03-25 13:40:45 -07001331 bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(
1332 dex_method_idx, mir_graph_->GetCurrentDexCompilationUnit(), info->type, vtable_idx,
buzbee311ca162013-02-28 15:56:43 -08001333 direct_code, direct_method) && !SLOW_INVOKE_PATH;
buzbee1bc37c62012-11-20 13:35:41 -08001334 if (info->type == kInterface) {
buzbeefa57c472012-11-21 12:06:18 -08001335 if (fast_path) {
1336 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001337 }
buzbeefa57c472012-11-21 12:06:18 -08001338 next_call_insn = fast_path ? NextInterfaceCallInsn
buzbee52a77fc2012-11-20 19:50:46 -08001339 : NextInterfaceCallInsnWithAccessCheck;
buzbeefa57c472012-11-21 12:06:18 -08001340 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001341 } else if (info->type == kDirect) {
buzbeefa57c472012-11-21 12:06:18 -08001342 if (fast_path) {
1343 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001344 }
buzbeefa57c472012-11-21 12:06:18 -08001345 next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1346 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001347 } else if (info->type == kStatic) {
buzbeefa57c472012-11-21 12:06:18 -08001348 next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1349 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001350 } else if (info->type == kSuper) {
buzbeefa57c472012-11-21 12:06:18 -08001351 DCHECK(!fast_path); // Fast path is a direct call.
1352 next_call_insn = NextSuperCallInsnSP;
1353 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001354 } else {
1355 DCHECK_EQ(info->type, kVirtual);
buzbeefa57c472012-11-21 12:06:18 -08001356 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1357 skip_this = fast_path;
buzbee1bc37c62012-11-20 13:35:41 -08001358 }
buzbeefa57c472012-11-21 12:06:18 -08001359 if (!info->is_range) {
buzbee1fd33462013-03-25 13:40:45 -07001360 call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
buzbeefa57c472012-11-21 12:06:18 -08001361 next_call_insn, dex_method_idx,
1362 vtable_idx, direct_code, direct_method,
1363 original_type, skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001364 } else {
buzbee1fd33462013-03-25 13:40:45 -07001365 call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
buzbeefa57c472012-11-21 12:06:18 -08001366 next_call_insn, dex_method_idx, vtable_idx,
1367 direct_code, direct_method, original_type,
1368 skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001369 }
1370 // Finish up any of the call sequence not interleaved in arg loading
buzbeefa57c472012-11-21 12:06:18 -08001371 while (call_state >= 0) {
buzbee1fd33462013-03-25 13:40:45 -07001372 call_state = next_call_insn(cu_, info, call_state, dex_method_idx,
buzbeefa57c472012-11-21 12:06:18 -08001373 vtable_idx, direct_code, direct_method,
1374 original_type);
buzbee1bc37c62012-11-20 13:35:41 -08001375 }
buzbeefa57c472012-11-21 12:06:18 -08001376 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -07001377 if (cu_->instruction_set != kX86) {
1378 call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
buzbee1bc37c62012-11-20 13:35:41 -08001379 } else {
buzbeefa57c472012-11-21 12:06:18 -08001380 if (fast_path && info->type != kInterface) {
buzbee1fd33462013-03-25 13:40:45 -07001381 call_inst = OpMem(kOpBlx, TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -08001382 mirror::AbstractMethod::GetCodeOffset().Int32Value());
buzbee1bc37c62012-11-20 13:35:41 -08001383 } else {
1384 int trampoline = 0;
1385 switch (info->type) {
1386 case kInterface:
buzbeefa57c472012-11-21 12:06:18 -08001387 trampoline = fast_path ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
buzbee1bc37c62012-11-20 13:35:41 -08001388 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
1389 break;
1390 case kDirect:
1391 trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
1392 break;
1393 case kStatic:
1394 trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
1395 break;
1396 case kSuper:
1397 trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
1398 break;
1399 case kVirtual:
1400 trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
1401 break;
1402 default:
1403 LOG(FATAL) << "Unexpected invoke type";
1404 }
buzbee1fd33462013-03-25 13:40:45 -07001405 call_inst = OpThreadMem(kOpBlx, trampoline);
buzbee1bc37c62012-11-20 13:35:41 -08001406 }
1407 }
buzbee1fd33462013-03-25 13:40:45 -07001408 MarkSafepointPC(call_inst);
buzbee1bc37c62012-11-20 13:35:41 -08001409
buzbee1fd33462013-03-25 13:40:45 -07001410 ClobberCalleeSave();
buzbee1bc37c62012-11-20 13:35:41 -08001411 if (info->result.location != kLocInvalid) {
1412 // We have a following MOVE_RESULT - do it now.
1413 if (info->result.wide) {
buzbee1fd33462013-03-25 13:40:45 -07001414 RegLocation ret_loc = GetReturnWide(info->result.fp);
1415 StoreValueWide(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001416 } else {
buzbee1fd33462013-03-25 13:40:45 -07001417 RegLocation ret_loc = GetReturn(info->result.fp);
1418 StoreValue(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001419 }
1420 }
1421}
1422
buzbee31a4a6f2012-02-28 15:36:15 -08001423} // namespace art