blob: 41924e228e04724caf62d420604d12fd593ce8ab [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
Ian Rogers57b86d42012-03-27 16:05:41 -070017#include "oat/runtime/oat_support_entrypoints.h"
buzbee1bc37c62012-11-20 13:35:41 -080018#include "../compiler_ir.h"
19#include "ralloc_util.h"
20#include "codegen_util.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 */
36int Codegen::CallHelperSetup(CompilationUnit* cu, int helper_offset)
37{
38 return (cu->instruction_set == kX86) ? 0 : LoadHelper(cu, helper_offset);
39}
40
41/* NOTE: if r_tgt is a temp, it will be freed following use */
42LIR* Codegen::CallHelper(CompilationUnit* cu, int r_tgt, int helper_offset, bool safepoint_pc)
43{
44 LIR* call_inst;
45 if (cu->instruction_set == kX86) {
46 call_inst = OpThreadMem(cu, kOpBlx, helper_offset);
47 } else {
48 call_inst = OpReg(cu, kOpBlx, r_tgt);
49 FreeTemp(cu, r_tgt);
50 }
51 if (safepoint_pc) {
52 MarkSafepointPC(cu, call_inst);
53 }
54 return call_inst;
55}
56
57void Codegen::CallRuntimeHelperImm(CompilationUnit* cu, int helper_offset, int arg0,
58 bool safepoint_pc) {
59 int r_tgt = CallHelperSetup(cu, helper_offset);
60 LoadConstant(cu, TargetReg(kArg0), arg0);
61 ClobberCalleeSave(cu);
62 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
63}
64
65void Codegen::CallRuntimeHelperReg(CompilationUnit* cu, int helper_offset, int arg0,
66 bool safepoint_pc) {
67 int r_tgt = CallHelperSetup(cu, helper_offset);
68 OpRegCopy(cu, TargetReg(kArg0), arg0);
69 ClobberCalleeSave(cu);
70 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
71}
72
73void Codegen::CallRuntimeHelperRegLocation(CompilationUnit* cu, int helper_offset, RegLocation arg0,
74 bool safepoint_pc) {
75 int r_tgt = CallHelperSetup(cu, helper_offset);
76 if (arg0.wide == 0) {
77 LoadValueDirectFixed(cu, arg0, TargetReg(kArg0));
78 } else {
79 LoadValueDirectWideFixed(cu, arg0, TargetReg(kArg0), TargetReg(kArg1));
80 }
81 ClobberCalleeSave(cu);
82 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
83}
84
85void Codegen::CallRuntimeHelperImmImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
86 bool safepoint_pc) {
87 int r_tgt = CallHelperSetup(cu, helper_offset);
88 LoadConstant(cu, TargetReg(kArg0), arg0);
89 LoadConstant(cu, TargetReg(kArg1), arg1);
90 ClobberCalleeSave(cu);
91 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
92}
93
94void Codegen::CallRuntimeHelperImmRegLocation(CompilationUnit* cu, int helper_offset, int arg0,
95 RegLocation arg1, bool safepoint_pc) {
96 int r_tgt = CallHelperSetup(cu, helper_offset);
97 if (arg1.wide == 0) {
98 LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
99 } else {
100 LoadValueDirectWideFixed(cu, arg1, TargetReg(kArg1), TargetReg(kArg2));
101 }
102 LoadConstant(cu, TargetReg(kArg0), arg0);
103 ClobberCalleeSave(cu);
104 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
105}
106
107void Codegen::CallRuntimeHelperRegLocationImm(CompilationUnit* cu, int helper_offset,
108 RegLocation arg0, int arg1, bool safepoint_pc) {
109 int r_tgt = CallHelperSetup(cu, helper_offset);
110 LoadValueDirectFixed(cu, arg0, TargetReg(kArg0));
111 LoadConstant(cu, TargetReg(kArg1), arg1);
112 ClobberCalleeSave(cu);
113 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
114}
115
116void Codegen::CallRuntimeHelperImmReg(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
117 bool safepoint_pc) {
118 int r_tgt = CallHelperSetup(cu, helper_offset);
119 OpRegCopy(cu, TargetReg(kArg1), arg1);
120 LoadConstant(cu, TargetReg(kArg0), arg0);
121 ClobberCalleeSave(cu);
122 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
123}
124
125void Codegen::CallRuntimeHelperRegImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
126 bool safepoint_pc) {
127 int r_tgt = CallHelperSetup(cu, helper_offset);
128 OpRegCopy(cu, TargetReg(kArg0), arg0);
129 LoadConstant(cu, TargetReg(kArg1), arg1);
130 ClobberCalleeSave(cu);
131 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
132}
133
134void Codegen::CallRuntimeHelperImmMethod(CompilationUnit* cu, int helper_offset, int arg0,
135 bool safepoint_pc) {
136 int r_tgt = CallHelperSetup(cu, helper_offset);
137 LoadCurrMethodDirect(cu, TargetReg(kArg1));
138 LoadConstant(cu, TargetReg(kArg0), arg0);
139 ClobberCalleeSave(cu);
140 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
141}
142
143void Codegen::CallRuntimeHelperRegLocationRegLocation(CompilationUnit* cu, int helper_offset,
144 RegLocation arg0, RegLocation arg1,
145 bool safepoint_pc) {
146 int r_tgt = CallHelperSetup(cu, helper_offset);
147 if (arg0.wide == 0) {
148 LoadValueDirectFixed(cu, arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
149 if (arg1.wide == 0) {
150 if (cu->instruction_set == kMips) {
151 LoadValueDirectFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
152 } else {
153 LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
154 }
155 } else {
156 if (cu->instruction_set == kMips) {
157 LoadValueDirectWideFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
158 } else {
159 LoadValueDirectWideFixed(cu, arg1, TargetReg(kArg1), TargetReg(kArg2));
160 }
161 }
162 } else {
163 LoadValueDirectWideFixed(cu, arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
164 if (arg1.wide == 0) {
165 LoadValueDirectFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
166 } else {
167 LoadValueDirectWideFixed(cu, arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
168 }
169 }
170 ClobberCalleeSave(cu);
171 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
172}
173
174void Codegen::CallRuntimeHelperRegReg(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
175 bool safepoint_pc) {
176 int r_tgt = CallHelperSetup(cu, helper_offset);
177 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
178 OpRegCopy(cu, TargetReg(kArg0), arg0);
179 OpRegCopy(cu, TargetReg(kArg1), arg1);
180 ClobberCalleeSave(cu);
181 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
182}
183
184void Codegen::CallRuntimeHelperRegRegImm(CompilationUnit* cu, int helper_offset, int arg0, int arg1,
185 int arg2, bool safepoint_pc) {
186 int r_tgt = CallHelperSetup(cu, helper_offset);
187 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
188 OpRegCopy(cu, TargetReg(kArg0), arg0);
189 OpRegCopy(cu, TargetReg(kArg1), arg1);
190 LoadConstant(cu, TargetReg(kArg2), arg2);
191 ClobberCalleeSave(cu);
192 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
193}
194
195void Codegen::CallRuntimeHelperImmMethodRegLocation(CompilationUnit* cu, int helper_offset,
196 int arg0, RegLocation arg2, bool safepoint_pc) {
197 int r_tgt = CallHelperSetup(cu, helper_offset);
198 LoadValueDirectFixed(cu, arg2, TargetReg(kArg2));
199 LoadCurrMethodDirect(cu, TargetReg(kArg1));
200 LoadConstant(cu, TargetReg(kArg0), arg0);
201 ClobberCalleeSave(cu);
202 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
203}
204
205void Codegen::CallRuntimeHelperImmMethodImm(CompilationUnit* cu, int helper_offset, int arg0,
206 int arg2, bool safepoint_pc) {
207 int r_tgt = CallHelperSetup(cu, helper_offset);
208 LoadCurrMethodDirect(cu, TargetReg(kArg1));
209 LoadConstant(cu, TargetReg(kArg2), arg2);
210 LoadConstant(cu, TargetReg(kArg0), arg0);
211 ClobberCalleeSave(cu);
212 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
213}
214
215void Codegen::CallRuntimeHelperImmRegLocationRegLocation(CompilationUnit* cu, int helper_offset,
216 int arg0, RegLocation arg1,
217 RegLocation arg2, bool safepoint_pc) {
218 int r_tgt = CallHelperSetup(cu, helper_offset);
219 LoadValueDirectFixed(cu, arg1, TargetReg(kArg1));
220 if (arg2.wide == 0) {
221 LoadValueDirectFixed(cu, arg2, TargetReg(kArg2));
222 } else {
223 LoadValueDirectWideFixed(cu, arg2, TargetReg(kArg2), TargetReg(kArg3));
224 }
225 LoadConstant(cu, TargetReg(kArg0), arg0);
226 ClobberCalleeSave(cu);
227 CallHelper(cu, r_tgt, helper_offset, safepoint_pc);
228}
229
230/*
buzbee31a4a6f2012-02-28 15:36:15 -0800231 * If there are any ins passed in registers that have not been promoted
232 * to a callee-save register, flush them to the frame. Perform intial
233 * assignment of promoted arguments.
buzbeead8f15e2012-06-18 14:49:45 -0700234 *
buzbee52a77fc2012-11-20 19:50:46 -0800235 * ArgLocs is an array of location records describing the incoming arguments
buzbeead8f15e2012-06-18 14:49:45 -0700236 * with one location record per word of argument.
buzbee31a4a6f2012-02-28 15:36:15 -0800237 */
buzbee02031b12012-11-23 09:41:35 -0800238void Codegen::FlushIns(CompilationUnit* cu, RegLocation* ArgLocs, RegLocation rl_method)
buzbee31a4a6f2012-02-28 15:36:15 -0800239{
Bill Buzbeea114add2012-05-03 15:00:40 -0700240 /*
241 * Dummy up a RegLocation for the incoming Method*
buzbeef0504cd2012-11-13 16:31:10 -0800242 * It will attempt to keep kArg0 live (or copy it to home location
Bill Buzbeea114add2012-05-03 15:00:40 -0700243 * if promoted).
244 */
buzbeefa57c472012-11-21 12:06:18 -0800245 RegLocation rl_src = rl_method;
246 rl_src.location = kLocPhysReg;
247 rl_src.low_reg = TargetReg(kArg0);
248 rl_src.home = false;
249 MarkLive(cu, rl_src.low_reg, rl_src.s_reg_low);
250 StoreValue(cu, rl_method, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700251 // If Method* has been promoted, explicitly flush
buzbeefa57c472012-11-21 12:06:18 -0800252 if (rl_method.location == kLocPhysReg) {
253 StoreWordDisp(cu, TargetReg(kSp), 0, TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700254 }
buzbee9c044ce2012-03-18 13:24:07 -0700255
buzbeefa57c472012-11-21 12:06:18 -0800256 if (cu->num_ins == 0)
Bill Buzbeea114add2012-05-03 15:00:40 -0700257 return;
buzbeefa57c472012-11-21 12:06:18 -0800258 const int num_arg_regs = 3;
259 static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
260 int start_vreg = cu->num_dalvik_registers - cu->num_ins;
Bill Buzbeea114add2012-05-03 15:00:40 -0700261 /*
262 * Copy incoming arguments to their proper home locations.
263 * NOTE: an older version of dx had an issue in which
264 * it would reuse static method argument registers.
265 * This could result in the same Dalvik virtual register
266 * being promoted to both core and fp regs. To account for this,
267 * we only copy to the corresponding promoted physical register
268 * if it matches the type of the SSA name for the incoming
269 * argument. It is also possible that long and double arguments
270 * end up half-promoted. In those cases, we must flush the promoted
271 * half to memory as well.
272 */
buzbeefa57c472012-11-21 12:06:18 -0800273 for (int i = 0; i < cu->num_ins; i++) {
274 PromotionMap* v_map = &cu->promotion_map[start_vreg + i];
275 if (i < num_arg_regs) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700276 // If arriving in register
buzbeefa57c472012-11-21 12:06:18 -0800277 bool need_flush = true;
278 RegLocation* t_loc = &ArgLocs[i];
279 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
280 OpRegCopy(cu, v_map->core_reg, TargetReg(arg_regs[i]));
281 need_flush = false;
282 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
283 OpRegCopy(cu, v_map->FpReg, TargetReg(arg_regs[i]));
284 need_flush = false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700285 } else {
buzbeefa57c472012-11-21 12:06:18 -0800286 need_flush = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700287 }
buzbee86a4bce2012-03-06 18:15:00 -0800288
Bill Buzbeea114add2012-05-03 15:00:40 -0700289 // For wide args, force flush if only half is promoted
buzbeefa57c472012-11-21 12:06:18 -0800290 if (t_loc->wide) {
291 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
292 need_flush |= (p_map->core_location != v_map->core_location) ||
293 (p_map->fp_location != v_map->fp_location);
Bill Buzbeea114add2012-05-03 15:00:40 -0700294 }
buzbeefa57c472012-11-21 12:06:18 -0800295 if (need_flush) {
296 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, start_vreg + i),
297 TargetReg(arg_regs[i]), kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700298 }
299 } else {
300 // If arriving in frame & promoted
buzbeefa57c472012-11-21 12:06:18 -0800301 if (v_map->core_location == kLocPhysReg) {
302 LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, start_vreg + i),
303 v_map->core_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700304 }
buzbeefa57c472012-11-21 12:06:18 -0800305 if (v_map->fp_location == kLocPhysReg) {
306 LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, start_vreg + i),
307 v_map->FpReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700308 }
buzbee31a4a6f2012-02-28 15:36:15 -0800309 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700310 }
buzbee31a4a6f2012-02-28 15:36:15 -0800311}
312
313/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700314 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800315 * emit the next instruction in static & direct invoke sequences.
316 */
buzbeefa57c472012-11-21 12:06:18 -0800317static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
318 int state, uint32_t dex_idx, uint32_t unused,
319 uintptr_t direct_code, uintptr_t direct_method,
buzbeeaad94382012-11-21 07:40:50 -0800320 InvokeType type)
buzbee31a4a6f2012-02-28 15:36:15 -0800321{
buzbee02031b12012-11-23 09:41:35 -0800322 Codegen* cg = cu->cg.get();
buzbeefa57c472012-11-21 12:06:18 -0800323 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700324 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800325 direct_code = 0;
326 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700327 }
buzbeefa57c472012-11-21 12:06:18 -0800328 if (direct_code != 0 && direct_method != 0) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700329 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800330 case 0: // Get the current Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800331 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee02031b12012-11-23 09:41:35 -0800332 cg->LoadConstant(cu, cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700333 } else {
buzbeefa57c472012-11-21 12:06:18 -0800334 LIR* data_target = ScanLiteralPool(cu->code_literal_list, dex_idx, 0);
335 if (data_target == NULL) {
336 data_target = AddWordData(cu, &cu->code_literal_list, dex_idx);
337 data_target->operands[1] = type;
Ian Rogers2ed3b952012-03-17 11:49:39 -0700338 }
buzbee02031b12012-11-23 09:41:35 -0800339 LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kInvokeTgt), data_target);
buzbeefa57c472012-11-21 12:06:18 -0800340 AppendLIR(cu, load_pc_rel);
341 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700342 }
buzbeefa57c472012-11-21 12:06:18 -0800343 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee02031b12012-11-23 09:41:35 -0800344 cg->LoadConstant(cu, cg->TargetReg(kArg0), direct_method);
Bill Buzbeea114add2012-05-03 15:00:40 -0700345 } else {
buzbeefa57c472012-11-21 12:06:18 -0800346 LIR* data_target = ScanLiteralPool(cu->method_literal_list, dex_idx, 0);
347 if (data_target == NULL) {
348 data_target = AddWordData(cu, &cu->method_literal_list, dex_idx);
349 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700350 }
buzbee02031b12012-11-23 09:41:35 -0800351 LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kArg0), data_target);
buzbeefa57c472012-11-21 12:06:18 -0800352 AppendLIR(cu, load_pc_rel);
353 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700354 }
355 break;
356 default:
357 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800358 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700359 } else {
360 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800361 case 0: // Get the current Method* [sets kArg0]
Ian Rogers137e88f2012-10-08 17:46:47 -0700362 // TUNING: we can save a reg copy if Method* has been promoted.
buzbee02031b12012-11-23 09:41:35 -0800363 cg->LoadCurrMethodDirect(cu, cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700364 break;
365 case 1: // Get method->dex_cache_resolved_methods_
buzbee02031b12012-11-23 09:41:35 -0800366 cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
367 AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700368 // Set up direct code if known.
buzbeefa57c472012-11-21 12:06:18 -0800369 if (direct_code != 0) {
370 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee02031b12012-11-23 09:41:35 -0800371 cg->LoadConstant(cu, cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700372 } else {
buzbeefa57c472012-11-21 12:06:18 -0800373 LIR* data_target = ScanLiteralPool(cu->code_literal_list, dex_idx, 0);
374 if (data_target == NULL) {
375 data_target = AddWordData(cu, &cu->code_literal_list, dex_idx);
376 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700377 }
buzbee02031b12012-11-23 09:41:35 -0800378 LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kInvokeTgt), data_target);
buzbeefa57c472012-11-21 12:06:18 -0800379 AppendLIR(cu, load_pc_rel);
380 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700381 }
382 }
383 break;
384 case 2: // Grab target method*
buzbee02031b12012-11-23 09:41:35 -0800385 cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
386 Array::DataOffset(sizeof(Object*)).Int32Value() + dex_idx * 4,
387 cg-> TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700388 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700389 case 3: // Grab the code from the method*
buzbeefa57c472012-11-21 12:06:18 -0800390 if (cu->instruction_set != kX86) {
391 if (direct_code == 0) {
buzbee02031b12012-11-23 09:41:35 -0800392 cg->LoadWordDisp(cu, cg->TargetReg(kArg0), AbstractMethod::GetCodeOffset().Int32Value(),
393 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700394 }
395 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700396 }
buzbeeb046e162012-10-30 15:48:42 -0700397 // Intentional fallthrough for x86
Bill Buzbeea114add2012-05-03 15:00:40 -0700398 default:
399 return -1;
400 }
401 }
402 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800403}
404
405/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700406 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800407 * emit the next instruction in a virtual invoke sequence.
buzbeef0504cd2012-11-13 16:31:10 -0800408 * We can use kLr as a temp prior to target address loading
buzbee31a4a6f2012-02-28 15:36:15 -0800409 * Note also that we'll load the first argument ("this") into
buzbee52a77fc2012-11-20 19:50:46 -0800410 * kArg1 here rather than the standard LoadArgRegs.
buzbee31a4a6f2012-02-28 15:36:15 -0800411 */
buzbeefa57c472012-11-21 12:06:18 -0800412static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
413 int state, uint32_t dex_idx, uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800414 uintptr_t unused, uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800415{
buzbee02031b12012-11-23 09:41:35 -0800416 Codegen* cg = cu->cg.get();
Bill Buzbeea114add2012-05-03 15:00:40 -0700417 /*
418 * This is the fast path in which the target virtual method is
419 * fully resolved at compile time.
420 */
421 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800422 case 0: { // Get "this" [set kArg1]
buzbeefa57c472012-11-21 12:06:18 -0800423 RegLocation rl_arg = info->args[0];
buzbee02031b12012-11-23 09:41:35 -0800424 cg->LoadValueDirectFixed(cu, rl_arg, cg->TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700425 break;
Ian Rogers137e88f2012-10-08 17:46:47 -0700426 }
buzbeef0504cd2012-11-13 16:31:10 -0800427 case 1: // Is "this" null? [use kArg1]
buzbee02031b12012-11-23 09:41:35 -0800428 cg->GenNullCheck(cu, info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
buzbeef0504cd2012-11-13 16:31:10 -0800429 // get this->klass_ [use kArg1, set kInvokeTgt]
buzbee02031b12012-11-23 09:41:35 -0800430 cg->LoadWordDisp(cu, cg->TargetReg(kArg1), Object::ClassOffset().Int32Value(),
431 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700432 break;
buzbeef0504cd2012-11-13 16:31:10 -0800433 case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
buzbee02031b12012-11-23 09:41:35 -0800434 cg->LoadWordDisp(cu, cg->TargetReg(kInvokeTgt), Class::VTableOffset().Int32Value(),
435 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700436 break;
buzbeef0504cd2012-11-13 16:31:10 -0800437 case 3: // Get target method [use kInvokeTgt, set kArg0]
buzbee02031b12012-11-23 09:41:35 -0800438 cg->LoadWordDisp(cu, cg->TargetReg(kInvokeTgt), (method_idx * 4) +
439 Array::DataOffset(sizeof(Object*)).Int32Value(), cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700440 break;
buzbeef0504cd2012-11-13 16:31:10 -0800441 case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
buzbeefa57c472012-11-21 12:06:18 -0800442 if (cu->instruction_set != kX86) {
buzbee02031b12012-11-23 09:41:35 -0800443 cg->LoadWordDisp(cu, cg->TargetReg(kArg0), AbstractMethod::GetCodeOffset().Int32Value(),
444 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700445 break;
446 }
447 // Intentional fallthrough for X86
Bill Buzbeea114add2012-05-03 15:00:40 -0700448 default:
449 return -1;
450 }
451 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800452}
453
Ian Rogers137e88f2012-10-08 17:46:47 -0700454/*
455 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
456 * which will locate the target and continue on via a tail call.
457 */
buzbeefa57c472012-11-21 12:06:18 -0800458static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
459 uint32_t dex_idx, uint32_t unused, uintptr_t unused2,
460 uintptr_t direct_method, InvokeType unused4)
Ian Rogers137e88f2012-10-08 17:46:47 -0700461{
buzbee02031b12012-11-23 09:41:35 -0800462 Codegen* cg = cu->cg.get();
buzbeefa57c472012-11-21 12:06:18 -0800463 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700464 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800465 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700466 }
buzbeefa57c472012-11-21 12:06:18 -0800467 int trampoline = (cu->instruction_set == kX86) ? 0
buzbeeb046e162012-10-30 15:48:42 -0700468 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
Ian Rogers137e88f2012-10-08 17:46:47 -0700469
buzbeefa57c472012-11-21 12:06:18 -0800470 if (direct_method != 0) {
Ian Rogers137e88f2012-10-08 17:46:47 -0700471 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800472 case 0: // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800473 if (cu->instruction_set != kX86) {
buzbee02031b12012-11-23 09:41:35 -0800474 cg->LoadWordDisp(cu, cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700475 }
buzbeef0504cd2012-11-13 16:31:10 -0800476 // Get the interface Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800477 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee02031b12012-11-23 09:41:35 -0800478 cg->LoadConstant(cu, cg->TargetReg(kArg0), direct_method);
Ian Rogers137e88f2012-10-08 17:46:47 -0700479 } else {
buzbeefa57c472012-11-21 12:06:18 -0800480 LIR* data_target = ScanLiteralPool(cu->method_literal_list, dex_idx, 0);
481 if (data_target == NULL) {
482 data_target = AddWordData(cu, &cu->method_literal_list, dex_idx);
483 data_target->operands[1] = kInterface;
Ian Rogers137e88f2012-10-08 17:46:47 -0700484 }
buzbee02031b12012-11-23 09:41:35 -0800485 LIR* load_pc_rel = cg->OpPcRelLoad(cu, cg->TargetReg(kArg0), data_target);
buzbeefa57c472012-11-21 12:06:18 -0800486 AppendLIR(cu, load_pc_rel);
487 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Ian Rogers137e88f2012-10-08 17:46:47 -0700488 }
489 break;
490 default:
491 return -1;
492 }
493 } else {
494 switch (state) {
495 case 0:
buzbeef0504cd2012-11-13 16:31:10 -0800496 // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted.
buzbee02031b12012-11-23 09:41:35 -0800497 cg->LoadCurrMethodDirect(cu, cg->TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800498 // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800499 if (cu->instruction_set != kX86) {
buzbee02031b12012-11-23 09:41:35 -0800500 cg->LoadWordDisp(cu, cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700501 }
Ian Rogers137e88f2012-10-08 17:46:47 -0700502 break;
buzbeef0504cd2012-11-13 16:31:10 -0800503 case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0]
buzbee02031b12012-11-23 09:41:35 -0800504 cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
505 AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
506 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700507 break;
buzbeef0504cd2012-11-13 16:31:10 -0800508 case 2: // Grab target method* [set/use kArg0]
buzbee02031b12012-11-23 09:41:35 -0800509 cg->LoadWordDisp(cu, cg->TargetReg(kArg0),
510 Array::DataOffset(sizeof(Object*)).Int32Value() + dex_idx * 4,
511 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700512 break;
513 default:
514 return -1;
515 }
516 }
517 return state + 1;
518}
519
buzbeefa57c472012-11-21 12:06:18 -0800520static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
521 int state, uint32_t dex_idx, uint32_t method_idx)
buzbee31a4a6f2012-02-28 15:36:15 -0800522{
buzbee02031b12012-11-23 09:41:35 -0800523 Codegen* cg = cu->cg.get();
Bill Buzbeea114add2012-05-03 15:00:40 -0700524 /*
525 * This handles the case in which the base method is not fully
526 * resolved at compile time, we bail to a runtime helper.
527 */
528 if (state == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800529 if (cu->instruction_set != kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700530 // Load trampoline target
buzbee02031b12012-11-23 09:41:35 -0800531 cg->LoadWordDisp(cu, cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700532 }
buzbeef0504cd2012-11-13 16:31:10 -0800533 // Load kArg0 with method index
buzbee02031b12012-11-23 09:41:35 -0800534 cg->LoadConstant(cu, cg->TargetReg(kArg0), dex_idx);
Bill Buzbeea114add2012-05-03 15:00:40 -0700535 return 1;
536 }
537 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800538}
539
buzbeefa57c472012-11-21 12:06:18 -0800540static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
541 int state, uint32_t dex_idx, uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800542 uintptr_t unused, uintptr_t unused2,
Brian Carlstromf5822582012-03-19 22:34:31 -0700543 InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800544{
Ian Rogers57b86d42012-03-27 16:05:41 -0700545 int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800546 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800547}
548
buzbeefa57c472012-11-21 12:06:18 -0800549static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
550 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800551 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800552{
Ian Rogers57b86d42012-03-27 16:05:41 -0700553 int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800554 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800555}
556
buzbeefa57c472012-11-21 12:06:18 -0800557static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
558 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
Brian Carlstromf5822582012-03-19 22:34:31 -0700559 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800560{
Ian Rogers57b86d42012-03-27 16:05:41 -0700561 int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800562 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800563}
564
buzbeefa57c472012-11-21 12:06:18 -0800565static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
566 uint32_t dex_idx, uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800567 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800568{
Ian Rogers57b86d42012-03-27 16:05:41 -0700569 int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800570 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800571}
572
buzbeefa57c472012-11-21 12:06:18 -0800573static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
buzbeeaad94382012-11-21 07:40:50 -0800574 CallInfo* info, int state,
buzbeefa57c472012-11-21 12:06:18 -0800575 uint32_t dex_idx, uint32_t unused,
buzbee15bf9802012-06-12 17:49:27 -0700576 uintptr_t unused2, uintptr_t unused3,
577 InvokeType unused4)
buzbee31a4a6f2012-02-28 15:36:15 -0800578{
Ian Rogers57b86d42012-03-27 16:05:41 -0700579 int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
buzbeefa57c472012-11-21 12:06:18 -0800580 return NextInvokeInsnSP(cu, info, trampoline, state, dex_idx, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800581}
582
buzbeefa57c472012-11-21 12:06:18 -0800583static int LoadArgRegs(CompilationUnit* cu, CallInfo* info, int call_state,
584 NextCallInsn next_call_insn, uint32_t dex_idx,
585 uint32_t method_idx, uintptr_t direct_code,
586 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800587{
buzbee02031b12012-11-23 09:41:35 -0800588 Codegen* cg = cu->cg.get();
589 int last_arg_reg = cg->TargetReg(kArg3);
590 int next_reg = cg->TargetReg(kArg1);
buzbeefa57c472012-11-21 12:06:18 -0800591 int next_arg = 0;
592 if (skip_this) {
593 next_reg++;
594 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700595 }
buzbeefa57c472012-11-21 12:06:18 -0800596 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
597 RegLocation rl_arg = info->args[next_arg++];
598 rl_arg = UpdateRawLoc(cu, rl_arg);
buzbee02031b12012-11-23 09:41:35 -0800599 if (rl_arg.wide && (next_reg <= cg->TargetReg(kArg2))) {
600 cg->LoadValueDirectWideFixed(cu, rl_arg, next_reg, next_reg + 1);
buzbeefa57c472012-11-21 12:06:18 -0800601 next_reg++;
602 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700603 } else {
buzbeefa57c472012-11-21 12:06:18 -0800604 rl_arg.wide = false;
buzbee02031b12012-11-23 09:41:35 -0800605 cg->LoadValueDirectFixed(cu, rl_arg, next_reg);
buzbee31a4a6f2012-02-28 15:36:15 -0800606 }
buzbeefa57c472012-11-21 12:06:18 -0800607 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
608 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700609 }
buzbeefa57c472012-11-21 12:06:18 -0800610 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800611}
612
613/*
614 * Load up to 5 arguments, the first three of which will be in
buzbeef0504cd2012-11-13 16:31:10 -0800615 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer,
buzbee31a4a6f2012-02-28 15:36:15 -0800616 * and as part of the load sequence, it must be replaced with
617 * the target method pointer. Note, this may also be called
618 * for "range" variants if the number of arguments is 5 or fewer.
619 */
buzbee02031b12012-11-23 09:41:35 -0800620int Codegen::GenDalvikArgsNoRange(CompilationUnit* cu, CallInfo* info,
621 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
622 uint32_t dex_idx, uint32_t method_idx, uintptr_t direct_code,
623 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800624{
buzbeefa57c472012-11-21 12:06:18 -0800625 RegLocation rl_arg;
buzbee31a4a6f2012-02-28 15:36:15 -0800626
Bill Buzbeea114add2012-05-03 15:00:40 -0700627 /* If no arguments, just return */
buzbeefa57c472012-11-21 12:06:18 -0800628 if (info->num_arg_words == 0)
629 return call_state;
Bill Buzbeea114add2012-05-03 15:00:40 -0700630
buzbeefa57c472012-11-21 12:06:18 -0800631 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
632 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700633
buzbeefa57c472012-11-21 12:06:18 -0800634 DCHECK_LE(info->num_arg_words, 5);
635 if (info->num_arg_words > 3) {
636 int32_t next_use = 3;
Bill Buzbeea114add2012-05-03 15:00:40 -0700637 //Detect special case of wide arg spanning arg3/arg4
buzbeefa57c472012-11-21 12:06:18 -0800638 RegLocation rl_use0 = info->args[0];
639 RegLocation rl_use1 = info->args[1];
640 RegLocation rl_use2 = info->args[2];
641 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
642 rl_use2.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700643 int reg = -1;
644 // Wide spans, we need the 2nd half of uses[2].
buzbeefa57c472012-11-21 12:06:18 -0800645 rl_arg = UpdateLocWide(cu, rl_use2);
646 if (rl_arg.location == kLocPhysReg) {
647 reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700648 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800649 // kArg2 & rArg3 can safely be used here
buzbee52a77fc2012-11-20 19:50:46 -0800650 reg = TargetReg(kArg3);
buzbeefa57c472012-11-21 12:06:18 -0800651 LoadWordDisp(cu, TargetReg(kSp), SRegOffset(cu, rl_arg.s_reg_low) + 4, reg);
652 call_state = next_call_insn(cu, info, call_state, dex_idx,
653 method_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700654 }
buzbeefa57c472012-11-21 12:06:18 -0800655 StoreBaseDisp(cu, TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
656 StoreBaseDisp(cu, TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
657 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
658 direct_code, direct_method, type);
659 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700660 }
661 // Loop through the rest
buzbeefa57c472012-11-21 12:06:18 -0800662 while (next_use < info->num_arg_words) {
663 int low_reg;
664 int high_reg = -1;
665 rl_arg = info->args[next_use];
666 rl_arg = UpdateRawLoc(cu, rl_arg);
667 if (rl_arg.location == kLocPhysReg) {
668 low_reg = rl_arg.low_reg;
669 high_reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700670 } else {
buzbeefa57c472012-11-21 12:06:18 -0800671 low_reg = TargetReg(kArg2);
672 if (rl_arg.wide) {
673 high_reg = TargetReg(kArg3);
674 LoadValueDirectWideFixed(cu, rl_arg, low_reg, high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700675 } else {
buzbeefa57c472012-11-21 12:06:18 -0800676 LoadValueDirectFixed(cu, rl_arg, low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700677 }
buzbeefa57c472012-11-21 12:06:18 -0800678 call_state = next_call_insn(cu, info, call_state, dex_idx,
679 method_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700680 }
buzbeefa57c472012-11-21 12:06:18 -0800681 int outs_offset = (next_use + 1) * 4;
682 if (rl_arg.wide) {
683 StoreBaseDispWide(cu, TargetReg(kSp), outs_offset, low_reg, high_reg);
684 next_use += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700685 } else {
buzbeefa57c472012-11-21 12:06:18 -0800686 StoreWordDisp(cu, TargetReg(kSp), outs_offset, low_reg);
687 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700688 }
buzbeefa57c472012-11-21 12:06:18 -0800689 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
690 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700691 }
692 }
693
buzbeefa57c472012-11-21 12:06:18 -0800694 call_state = LoadArgRegs(cu, info, call_state, next_call_insn,
695 dex_idx, method_idx, direct_code, direct_method,
696 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700697
698 if (pcrLabel) {
buzbeefa57c472012-11-21 12:06:18 -0800699 *pcrLabel = GenNullCheck(cu, info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700700 }
buzbeefa57c472012-11-21 12:06:18 -0800701 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800702}
703
704/*
705 * May have 0+ arguments (also used for jumbo). Note that
706 * source virtual registers may be in physical registers, so may
707 * need to be flushed to home location before copying. This
708 * applies to arg3 and above (see below).
709 *
710 * Two general strategies:
711 * If < 20 arguments
712 * Pass args 3-18 using vldm/vstm block copy
buzbeef0504cd2012-11-13 16:31:10 -0800713 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800714 * If 20+ arguments
715 * Pass args arg19+ using memcpy block copy
buzbeef0504cd2012-11-13 16:31:10 -0800716 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800717 *
718 */
buzbee02031b12012-11-23 09:41:35 -0800719int Codegen::GenDalvikArgsRange(CompilationUnit* cu, CallInfo* info, int call_state,
720 LIR** pcrLabel, NextCallInsn next_call_insn, uint32_t dex_idx,
721 uint32_t method_idx, uintptr_t direct_code, uintptr_t direct_method,
722 InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800723{
buzbee31a4a6f2012-02-28 15:36:15 -0800724
Bill Buzbeea114add2012-05-03 15:00:40 -0700725 // If we can treat it as non-range (Jumbo ops will use range form)
buzbeefa57c472012-11-21 12:06:18 -0800726 if (info->num_arg_words <= 5)
727 return GenDalvikArgsNoRange(cu, info, call_state, pcrLabel,
728 next_call_insn, dex_idx, method_idx,
729 direct_code, direct_method, type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700730 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700731 * First load the non-register arguments. Both forms expect all
732 * of the source arguments to be in their home frame location, so
buzbeefa57c472012-11-21 12:06:18 -0800733 * scan the s_reg names and flush any that have been promoted to
Bill Buzbeea114add2012-05-03 15:00:40 -0700734 * frame backing storage.
735 */
buzbeefa57c472012-11-21 12:06:18 -0800736 // Scan the rest of the args - if in phys_reg flush to memory
737 for (int next_arg = 0; next_arg < info->num_arg_words;) {
738 RegLocation loc = info->args[next_arg];
Bill Buzbeea114add2012-05-03 15:00:40 -0700739 if (loc.wide) {
buzbeefa57c472012-11-21 12:06:18 -0800740 loc = UpdateLocWide(cu, loc);
741 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
742 StoreBaseDispWide(cu, TargetReg(kSp), SRegOffset(cu, loc.s_reg_low),
743 loc.low_reg, loc.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700744 }
buzbeefa57c472012-11-21 12:06:18 -0800745 next_arg += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700746 } else {
buzbeefa57c472012-11-21 12:06:18 -0800747 loc = UpdateLoc(cu, loc);
748 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
749 StoreBaseDisp(cu, TargetReg(kSp), SRegOffset(cu, loc.s_reg_low),
750 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700751 }
buzbeefa57c472012-11-21 12:06:18 -0800752 next_arg++;
buzbee31a4a6f2012-02-28 15:36:15 -0800753 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700754 }
buzbee31a4a6f2012-02-28 15:36:15 -0800755
buzbeefa57c472012-11-21 12:06:18 -0800756 int start_offset = SRegOffset(cu, info->args[3].s_reg_low);
757 int outs_offset = 4 /* Method* */ + (3 * 4);
758 if (cu->instruction_set != kThumb2) {
buzbee31a4a6f2012-02-28 15:36:15 -0800759 // Generate memcpy
buzbeefa57c472012-11-21 12:06:18 -0800760 OpRegRegImm(cu, kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
761 OpRegRegImm(cu, kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
762 CallRuntimeHelperRegRegImm(cu, ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
763 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700764 } else {
buzbeefa57c472012-11-21 12:06:18 -0800765 if (info->num_arg_words >= 20) {
buzbeeb046e162012-10-30 15:48:42 -0700766 // Generate memcpy
buzbeefa57c472012-11-21 12:06:18 -0800767 OpRegRegImm(cu, kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
768 OpRegRegImm(cu, kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
769 CallRuntimeHelperRegRegImm(cu, ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
770 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
buzbeeb046e162012-10-30 15:48:42 -0700771 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800772 // Use vldm/vstm pair using kArg3 as a temp
buzbeefa57c472012-11-21 12:06:18 -0800773 int regs_left = std::min(info->num_arg_words - 3, 16);
774 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
775 direct_code, direct_method, type);
776 OpRegRegImm(cu, kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
777 LIR* ld = OpVldm(cu, TargetReg(kArg3), regs_left);
buzbeeb046e162012-10-30 15:48:42 -0700778 //TUNING: loosen barrier
buzbeefa57c472012-11-21 12:06:18 -0800779 ld->def_mask = ENCODE_ALL;
buzbee02031b12012-11-23 09:41:35 -0800780 SetMemRefType(cu, ld, true /* is_load */, kDalvikReg);
buzbeefa57c472012-11-21 12:06:18 -0800781 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
782 direct_code, direct_method, type);
783 OpRegRegImm(cu, kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
784 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
785 direct_code, direct_method, type);
786 LIR* st = OpVstm(cu, TargetReg(kArg3), regs_left);
buzbee02031b12012-11-23 09:41:35 -0800787 SetMemRefType(cu, st, false /* is_load */, kDalvikReg);
buzbeefa57c472012-11-21 12:06:18 -0800788 st->def_mask = ENCODE_ALL;
789 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
790 direct_code, direct_method, type);
buzbeeb046e162012-10-30 15:48:42 -0700791 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700792 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700793
buzbeefa57c472012-11-21 12:06:18 -0800794 call_state = LoadArgRegs(cu, info, call_state, next_call_insn,
795 dex_idx, method_idx, direct_code, direct_method,
796 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700797
buzbeefa57c472012-11-21 12:06:18 -0800798 call_state = next_call_insn(cu, info, call_state, dex_idx, method_idx,
799 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700800 if (pcrLabel) {
buzbeefa57c472012-11-21 12:06:18 -0800801 *pcrLabel = GenNullCheck(cu, info->args[0].s_reg_low, TargetReg(kArg1),
802 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
buzbee02031b12012-11-23 09:41:35 -0800807RegLocation Codegen::InlineTarget(CompilationUnit* cu, 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) {
buzbeefa57c472012-11-21 12:06:18 -0800811 res = GetReturn(cu, 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
buzbee02031b12012-11-23 09:41:35 -0800818RegLocation Codegen::InlineTargetWide(CompilationUnit* cu, 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) {
buzbeefa57c472012-11-21 12:06:18 -0800822 res = GetReturnWide(cu, 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
buzbee02031b12012-11-23 09:41:35 -0800829bool Codegen::GenInlinedCharAt(CompilationUnit* cu, CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700830{
buzbeefa57c472012-11-21 12:06:18 -0800831 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
buzbeefa57c472012-11-21 12:06:18 -0800836 int value_offset = String::ValueOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700837 // Location of count
buzbeefa57c472012-11-21 12:06:18 -0800838 int count_offset = String::CountOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700839 // Starting offset within data array
buzbeefa57c472012-11-21 12:06:18 -0800840 int offset_offset = String::OffsetOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700841 // Start of char data with array_
buzbeefa57c472012-11-21 12:06:18 -0800842 int data_offset = 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];
846 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
847 rl_idx = LoadValue(cu, rl_idx, kCoreReg);
848 int reg_max;
849 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
850 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;
854 if (cu->instruction_set != kX86) {
855 reg_off = AllocTemp(cu);
856 reg_ptr = AllocTemp(cu);
857 if (range_check) {
858 reg_max = AllocTemp(cu);
859 LoadWordDisp(cu, rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700860 }
buzbeefa57c472012-11-21 12:06:18 -0800861 LoadWordDisp(cu, rl_obj.low_reg, offset_offset, reg_off);
862 LoadWordDisp(cu, rl_obj.low_reg, value_offset, reg_ptr);
863 if (range_check) {
buzbeeb046e162012-10-30 15:48:42 -0700864 // Set up a launch pad to allow retry in case of bounds violation */
buzbeefa57c472012-11-21 12:06:18 -0800865 launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
866 InsertGrowableList(cu, &cu->intrinsic_launchpads,
867 reinterpret_cast<uintptr_t>(launch_pad));
868 OpRegReg(cu, kOpCmp, rl_idx.low_reg, reg_max);
869 FreeTemp(cu, reg_max);
870 OpCondBranch(cu, kCondCs, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700871 }
872 } else {
buzbeefa57c472012-11-21 12:06:18 -0800873 if (range_check) {
874 reg_max = AllocTemp(cu);
875 LoadWordDisp(cu, rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700876 // Set up a launch pad to allow retry in case of bounds violation */
buzbeefa57c472012-11-21 12:06:18 -0800877 launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
878 InsertGrowableList(cu, &cu->intrinsic_launchpads,
879 reinterpret_cast<uintptr_t>(launch_pad));
880 OpRegReg(cu, kOpCmp, rl_idx.low_reg, reg_max);
881 FreeTemp(cu, reg_max);
882 OpCondBranch(cu, kCondCc, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700883 }
buzbeefa57c472012-11-21 12:06:18 -0800884 reg_off = AllocTemp(cu);
885 reg_ptr = AllocTemp(cu);
886 LoadWordDisp(cu, rl_obj.low_reg, offset_offset, reg_off);
887 LoadWordDisp(cu, rl_obj.low_reg, value_offset, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700888 }
buzbeefa57c472012-11-21 12:06:18 -0800889 OpRegImm(cu, kOpAdd, reg_ptr, data_offset);
890 OpRegReg(cu, kOpAdd, reg_off, rl_idx.low_reg);
891 FreeTemp(cu, rl_obj.low_reg);
892 FreeTemp(cu, rl_idx.low_reg);
893 RegLocation rl_dest = InlineTarget(cu, info);
894 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
895 LoadBaseIndexed(cu, reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
896 FreeTemp(cu, reg_off);
897 FreeTemp(cu, reg_ptr);
898 StoreValue(cu, rl_dest, rl_result);
899 if (range_check) {
900 launch_pad->operands[2] = 0; // no resumption
Bill Buzbeea114add2012-05-03 15:00:40 -0700901 }
902 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -0800903 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
Bill Buzbeea114add2012-05-03 15:00:40 -0700904 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700905}
906
buzbeefa57c472012-11-21 12:06:18 -0800907// Generates an inlined String.is_empty or String.length.
buzbee02031b12012-11-23 09:41:35 -0800908bool Codegen::GenInlinedStringIsEmptyOrLength(CompilationUnit* cu, CallInfo* info, bool is_empty)
buzbeefc9e6fa2012-03-23 15:14:29 -0700909{
buzbeefa57c472012-11-21 12:06:18 -0800910 if (cu->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700911 // TODO - add Mips implementation
912 return false;
913 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700914 // dst = src.length();
buzbeefa57c472012-11-21 12:06:18 -0800915 RegLocation rl_obj = info->args[0];
916 rl_obj = LoadValue(cu, rl_obj, kCoreReg);
917 RegLocation rl_dest = InlineTarget(cu, info);
918 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
919 GenNullCheck(cu, rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
920 LoadWordDisp(cu, rl_obj.low_reg, String::CountOffset().Int32Value(),
921 rl_result.low_reg);
922 if (is_empty) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700923 // dst = (dst == 0);
buzbeefa57c472012-11-21 12:06:18 -0800924 if (cu->instruction_set == kThumb2) {
925 int t_reg = AllocTemp(cu);
926 OpRegReg(cu, kOpNeg, t_reg, rl_result.low_reg);
927 OpRegRegReg(cu, kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
buzbeeb046e162012-10-30 15:48:42 -0700928 } else {
buzbeefa57c472012-11-21 12:06:18 -0800929 DCHECK_EQ(cu->instruction_set, kX86);
930 OpRegImm(cu, kOpSub, rl_result.low_reg, 1);
931 OpRegImm(cu, kOpLsr, rl_result.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -0700932 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700933 }
buzbeefa57c472012-11-21 12:06:18 -0800934 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700935 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700936}
937
buzbee02031b12012-11-23 09:41:35 -0800938bool Codegen::GenInlinedAbsInt(CompilationUnit *cu, CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700939{
buzbeefa57c472012-11-21 12:06:18 -0800940 if (cu->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700941 // TODO - add Mips implementation
942 return false;
943 }
buzbeefa57c472012-11-21 12:06:18 -0800944 RegLocation rl_src = info->args[0];
945 rl_src = LoadValue(cu, rl_src, kCoreReg);
946 RegLocation rl_dest = InlineTarget(cu, info);
947 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
948 int sign_reg = AllocTemp(cu);
Bill Buzbeea114add2012-05-03 15:00:40 -0700949 // abs(x) = y<=x>>31, (x+y)^y.
buzbeefa57c472012-11-21 12:06:18 -0800950 OpRegRegImm(cu, kOpAsr, sign_reg, rl_src.low_reg, 31);
951 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
952 OpRegReg(cu, kOpXor, rl_result.low_reg, sign_reg);
953 StoreValue(cu, rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700954 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700955}
956
buzbee02031b12012-11-23 09:41:35 -0800957bool Codegen::GenInlinedAbsLong(CompilationUnit *cu, CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700958{
buzbeefa57c472012-11-21 12:06:18 -0800959 if (cu->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700960 // TODO - add Mips implementation
961 return false;
962 }
buzbeefa57c472012-11-21 12:06:18 -0800963 if (cu->instruction_set == kThumb2) {
964 RegLocation rl_src = info->args[0];
965 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
966 RegLocation rl_dest = InlineTargetWide(cu, info);
967 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
968 int sign_reg = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700969 // abs(x) = y<=x>>31, (x+y)^y.
buzbeefa57c472012-11-21 12:06:18 -0800970 OpRegRegImm(cu, kOpAsr, sign_reg, rl_src.high_reg, 31);
971 OpRegRegReg(cu, kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
972 OpRegRegReg(cu, kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
973 OpRegReg(cu, kOpXor, rl_result.low_reg, sign_reg);
974 OpRegReg(cu, kOpXor, rl_result.high_reg, sign_reg);
975 StoreValueWide(cu, rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -0700976 return true;
977 } else {
buzbeefa57c472012-11-21 12:06:18 -0800978 DCHECK_EQ(cu->instruction_set, kX86);
buzbeeb046e162012-10-30 15:48:42 -0700979 // Reuse source registers to avoid running out of temps
buzbeefa57c472012-11-21 12:06:18 -0800980 RegLocation rl_src = info->args[0];
981 rl_src = LoadValueWide(cu, rl_src, kCoreReg);
982 RegLocation rl_dest = InlineTargetWide(cu, info);
983 RegLocation rl_result = EvalLoc(cu, rl_dest, kCoreReg, true);
984 OpRegCopyWide(cu, rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
985 FreeTemp(cu, rl_src.low_reg);
986 FreeTemp(cu, rl_src.high_reg);
987 int sign_reg = AllocTemp(cu);
buzbeeb046e162012-10-30 15:48:42 -0700988 // abs(x) = y<=x>>31, (x+y)^y.
buzbeefa57c472012-11-21 12:06:18 -0800989 OpRegRegImm(cu, kOpAsr, sign_reg, rl_result.high_reg, 31);
990 OpRegReg(cu, kOpAdd, rl_result.low_reg, sign_reg);
991 OpRegReg(cu, kOpAdc, rl_result.high_reg, sign_reg);
992 OpRegReg(cu, kOpXor, rl_result.low_reg, sign_reg);
993 OpRegReg(cu, kOpXor, rl_result.high_reg, sign_reg);
994 StoreValueWide(cu, rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -0700995 return true;
996 }
buzbeefc9e6fa2012-03-23 15:14:29 -0700997}
998
buzbee02031b12012-11-23 09:41:35 -0800999bool Codegen::GenInlinedFloatCvt(CompilationUnit *cu, CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001000{
buzbeefa57c472012-11-21 12:06:18 -08001001 if (cu->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001002 // TODO - add Mips implementation
1003 return false;
1004 }
buzbeefa57c472012-11-21 12:06:18 -08001005 RegLocation rl_src = info->args[0];
1006 RegLocation rl_dest = InlineTarget(cu, info);
1007 StoreValue(cu, rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001008 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001009}
1010
buzbee02031b12012-11-23 09:41:35 -08001011bool Codegen::GenInlinedDoubleCvt(CompilationUnit *cu, CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001012{
buzbeefa57c472012-11-21 12:06:18 -08001013 if (cu->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001014 // TODO - add Mips implementation
1015 return false;
1016 }
buzbeefa57c472012-11-21 12:06:18 -08001017 RegLocation rl_src = info->args[0];
1018 RegLocation rl_dest = InlineTargetWide(cu, info);
1019 StoreValueWide(cu, rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001020 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001021}
1022
1023/*
buzbeefa57c472012-11-21 12:06:18 -08001024 * Fast string.index_of(I) & (II). Tests for simple case of char <= 0xffff,
buzbeefc9e6fa2012-03-23 15:14:29 -07001025 * otherwise bails to standard library code.
1026 */
buzbee02031b12012-11-23 09:41:35 -08001027bool Codegen::GenInlinedIndexOf(CompilationUnit* cu, CallInfo* info, bool zero_based)
buzbeefc9e6fa2012-03-23 15:14:29 -07001028{
buzbeefa57c472012-11-21 12:06:18 -08001029 if (cu->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001030 // TODO - add Mips implementation
1031 return false;
1032 }
buzbeefa57c472012-11-21 12:06:18 -08001033 ClobberCalleeSave(cu);
1034 LockCallTemps(cu); // Using fixed registers
1035 int reg_ptr = TargetReg(kArg0);
1036 int reg_char = TargetReg(kArg1);
1037 int reg_start = TargetReg(kArg2);
buzbeefc9e6fa2012-03-23 15:14:29 -07001038
buzbeefa57c472012-11-21 12:06:18 -08001039 RegLocation rl_obj = info->args[0];
1040 RegLocation rl_char = info->args[1];
1041 RegLocation rl_start = info->args[2];
1042 LoadValueDirectFixed(cu, rl_obj, reg_ptr);
1043 LoadValueDirectFixed(cu, rl_char, reg_char);
1044 if (zero_based) {
1045 LoadConstant(cu, reg_start, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001046 } else {
buzbeefa57c472012-11-21 12:06:18 -08001047 LoadValueDirectFixed(cu, rl_start, reg_start);
Bill Buzbeea114add2012-05-03 15:00:40 -07001048 }
buzbeefa57c472012-11-21 12:06:18 -08001049 int r_tgt = (cu->instruction_set != kX86) ? LoadHelper(cu, ENTRYPOINT_OFFSET(pIndexOf)) : 0;
1050 GenNullCheck(cu, rl_obj.s_reg_low, reg_ptr, info->opt_flags);
1051 LIR* launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
1052 InsertGrowableList(cu, &cu->intrinsic_launchpads, reinterpret_cast<uintptr_t>(launch_pad));
1053 OpCmpImmBranch(cu, kCondGt, reg_char, 0xFFFF, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001054 // NOTE: not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08001055 if (cu->instruction_set != kX86) {
1056 OpReg(cu, kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001057 } else {
buzbeefa57c472012-11-21 12:06:18 -08001058 OpThreadMem(cu, kOpBlx, ENTRYPOINT_OFFSET(pIndexOf));
buzbeeb046e162012-10-30 15:48:42 -07001059 }
buzbeefa57c472012-11-21 12:06:18 -08001060 LIR* resume_tgt = NewLIR0(cu, kPseudoTargetLabel);
1061 launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -07001062 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001063 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1064 RegLocation rl_return = GetReturn(cu, false);
1065 RegLocation rl_dest = InlineTarget(cu, info);
1066 StoreValue(cu, rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001067 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001068}
1069
1070/* Fast string.compareTo(Ljava/lang/string;)I. */
buzbee02031b12012-11-23 09:41:35 -08001071bool Codegen::GenInlinedStringCompareTo(CompilationUnit* cu, CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001072{
buzbeefa57c472012-11-21 12:06:18 -08001073 if (cu->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001074 // TODO - add Mips implementation
1075 return false;
1076 }
buzbeefa57c472012-11-21 12:06:18 -08001077 ClobberCalleeSave(cu);
1078 LockCallTemps(cu); // Using fixed registers
1079 int reg_this = TargetReg(kArg0);
1080 int reg_cmp = TargetReg(kArg1);
buzbeefc9e6fa2012-03-23 15:14:29 -07001081
buzbeefa57c472012-11-21 12:06:18 -08001082 RegLocation rl_this = info->args[0];
1083 RegLocation rl_cmp = info->args[1];
1084 LoadValueDirectFixed(cu, rl_this, reg_this);
1085 LoadValueDirectFixed(cu, rl_cmp, reg_cmp);
1086 int r_tgt = (cu->instruction_set != kX86) ?
1087 LoadHelper(cu, ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
1088 GenNullCheck(cu, rl_this.s_reg_low, reg_this, info->opt_flags);
1089 //TUNING: check if rl_cmp.s_reg_low is already null checked
1090 LIR* launch_pad = RawLIR(cu, 0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
1091 InsertGrowableList(cu, &cu->intrinsic_launchpads, reinterpret_cast<uintptr_t>(launch_pad));
1092 OpCmpImmBranch(cu, kCondEq, reg_cmp, 0, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001093 // NOTE: not a safepoint
buzbeefa57c472012-11-21 12:06:18 -08001094 if (cu->instruction_set != kX86) {
1095 OpReg(cu, kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001096 } else {
buzbeefa57c472012-11-21 12:06:18 -08001097 OpThreadMem(cu, kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo));
buzbeeb046e162012-10-30 15:48:42 -07001098 }
buzbeefa57c472012-11-21 12:06:18 -08001099 launch_pad->operands[2] = 0; // No return possible
Bill Buzbeea114add2012-05-03 15:00:40 -07001100 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001101 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1102 RegLocation rl_return = GetReturn(cu, false);
1103 RegLocation rl_dest = InlineTarget(cu, info);
1104 StoreValue(cu, rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001105 return true;
Ian Rogers0183dd72012-09-17 23:06:51 -07001106}
1107
buzbee02031b12012-11-23 09:41:35 -08001108bool Codegen::GenIntrinsic(CompilationUnit* cu, CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001109{
buzbeefa57c472012-11-21 12:06:18 -08001110 if (info->opt_flags & MIR_INLINED) {
buzbeefc9e6fa2012-03-23 15:14:29 -07001111 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001112 }
1113 /*
1114 * TODO: move these to a target-specific structured constant array
1115 * and use a generic match function. The list of intrinsics may be
1116 * slightly different depending on target.
1117 * TODO: Fold this into a matching function that runs during
1118 * basic block building. This should be part of the action for
1119 * small method inlining and recognition of the special object init
1120 * method. By doing this during basic block construction, we can also
1121 * take advantage of/generate new useful dataflow info.
1122 */
buzbeefa57c472012-11-21 12:06:18 -08001123 std::string tgt_method(PrettyMethod(info->index, *cu->dex_file));
1124 if (tgt_method.find(" java.lang") != std::string::npos) {
1125 if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
1126 return GenInlinedDoubleCvt(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001127 }
buzbeefa57c472012-11-21 12:06:18 -08001128 if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
1129 return GenInlinedDoubleCvt(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001130 }
buzbeefa57c472012-11-21 12:06:18 -08001131 if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
1132 return GenInlinedFloatCvt(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001133 }
buzbeefa57c472012-11-21 12:06:18 -08001134 if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
1135 return GenInlinedFloatCvt(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001136 }
buzbeefa57c472012-11-21 12:06:18 -08001137 if (tgt_method == "int java.lang.Math.abs(int)" ||
1138 tgt_method == "int java.lang.StrictMath.abs(int)") {
1139 return GenInlinedAbsInt(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001140 }
buzbeefa57c472012-11-21 12:06:18 -08001141 if (tgt_method == "long java.lang.Math.abs(long)" ||
1142 tgt_method == "long java.lang.StrictMath.abs(long)") {
1143 return GenInlinedAbsLong(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001144 }
buzbeefa57c472012-11-21 12:06:18 -08001145 if (tgt_method == "int java.lang.Math.max(int, int)" ||
1146 tgt_method == "int java.lang.StrictMath.max(int, int)") {
1147 return GenInlinedMinMaxInt(cu, info, false /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001148 }
buzbeefa57c472012-11-21 12:06:18 -08001149 if (tgt_method == "int java.lang.Math.min(int, int)" ||
1150 tgt_method == "int java.lang.StrictMath.min(int, int)") {
1151 return GenInlinedMinMaxInt(cu, info, true /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001152 }
buzbeefa57c472012-11-21 12:06:18 -08001153 if (tgt_method == "double java.lang.Math.sqrt(double)" ||
1154 tgt_method == "double java.lang.StrictMath.sqrt(double)") {
1155 return GenInlinedSqrt(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001156 }
buzbeefa57c472012-11-21 12:06:18 -08001157 if (tgt_method == "char java.lang.String.charAt(int)") {
1158 return GenInlinedCharAt(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001159 }
buzbeefa57c472012-11-21 12:06:18 -08001160 if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
1161 return GenInlinedStringCompareTo(cu, info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001162 }
buzbeefa57c472012-11-21 12:06:18 -08001163 if (tgt_method == "boolean java.lang.String.is_empty()") {
1164 return GenInlinedStringIsEmptyOrLength(cu, info, true /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001165 }
buzbeefa57c472012-11-21 12:06:18 -08001166 if (tgt_method == "int java.lang.String.index_of(int, int)") {
1167 return GenInlinedIndexOf(cu, info, false /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001168 }
buzbeefa57c472012-11-21 12:06:18 -08001169 if (tgt_method == "int java.lang.String.index_of(int)") {
1170 return GenInlinedIndexOf(cu, info, true /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001171 }
buzbeefa57c472012-11-21 12:06:18 -08001172 if (tgt_method == "int java.lang.String.length()") {
1173 return GenInlinedStringIsEmptyOrLength(cu, info, false /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001174 }
buzbeefa57c472012-11-21 12:06:18 -08001175 } else if (tgt_method.find("boolean sun.misc.Unsafe.compareAndSwap") != std::string::npos) {
1176 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
1177 return GenInlinedCas32(cu, info, false);
Ian Rogers0183dd72012-09-17 23:06:51 -07001178 }
buzbeefa57c472012-11-21 12:06:18 -08001179 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
1180 return GenInlinedCas32(cu, info, true);
Ian Rogers0183dd72012-09-17 23:06:51 -07001181 }
Ian Rogerse13eafa2012-09-07 11:24:27 -07001182 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001183 return false;
buzbeefc9e6fa2012-03-23 15:14:29 -07001184}
1185
buzbee02031b12012-11-23 09:41:35 -08001186void Codegen::GenInvoke(CompilationUnit* cu, CallInfo* info)
buzbee1bc37c62012-11-20 13:35:41 -08001187{
buzbeefa57c472012-11-21 12:06:18 -08001188 if (GenIntrinsic(cu, info)) {
buzbee1bc37c62012-11-20 13:35:41 -08001189 return;
1190 }
buzbeefa57c472012-11-21 12:06:18 -08001191 InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
1192 int call_state = 0;
1193 LIR* null_ck;
1194 LIR** p_null_ck = NULL;
1195 NextCallInsn next_call_insn;
1196 FlushAllRegs(cu); /* Everything to home location */
buzbee1bc37c62012-11-20 13:35:41 -08001197 // Explicit register usage
buzbeefa57c472012-11-21 12:06:18 -08001198 LockCallTemps(cu);
buzbee1bc37c62012-11-20 13:35:41 -08001199
buzbeefa57c472012-11-21 12:06:18 -08001200 OatCompilationUnit m_unit(cu->class_loader, cu->class_linker,
1201 *cu->dex_file,
1202 cu->code_item, cu->method_idx,
1203 cu->access_flags);
buzbee1bc37c62012-11-20 13:35:41 -08001204
buzbeefa57c472012-11-21 12:06:18 -08001205 uint32_t dex_method_idx = info->index;
1206 int vtable_idx;
1207 uintptr_t direct_code;
1208 uintptr_t direct_method;
1209 bool skip_this;
1210 bool fast_path =
1211 cu->compiler->ComputeInvokeInfo(dex_method_idx, &m_unit, info->type,
1212 vtable_idx, direct_code,
1213 direct_method)
buzbee1bc37c62012-11-20 13:35:41 -08001214 && !SLOW_INVOKE_PATH;
1215 if (info->type == kInterface) {
buzbeefa57c472012-11-21 12:06:18 -08001216 if (fast_path) {
1217 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001218 }
buzbeefa57c472012-11-21 12:06:18 -08001219 next_call_insn = fast_path ? NextInterfaceCallInsn
buzbee52a77fc2012-11-20 19:50:46 -08001220 : NextInterfaceCallInsnWithAccessCheck;
buzbeefa57c472012-11-21 12:06:18 -08001221 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001222 } else if (info->type == kDirect) {
buzbeefa57c472012-11-21 12:06:18 -08001223 if (fast_path) {
1224 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001225 }
buzbeefa57c472012-11-21 12:06:18 -08001226 next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1227 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001228 } else if (info->type == kStatic) {
buzbeefa57c472012-11-21 12:06:18 -08001229 next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1230 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001231 } else if (info->type == kSuper) {
buzbeefa57c472012-11-21 12:06:18 -08001232 DCHECK(!fast_path); // Fast path is a direct call.
1233 next_call_insn = NextSuperCallInsnSP;
1234 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001235 } else {
1236 DCHECK_EQ(info->type, kVirtual);
buzbeefa57c472012-11-21 12:06:18 -08001237 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1238 skip_this = fast_path;
buzbee1bc37c62012-11-20 13:35:41 -08001239 }
buzbeefa57c472012-11-21 12:06:18 -08001240 if (!info->is_range) {
1241 call_state = GenDalvikArgsNoRange(cu, info, call_state, p_null_ck,
1242 next_call_insn, dex_method_idx,
1243 vtable_idx, direct_code, direct_method,
1244 original_type, skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001245 } else {
buzbeefa57c472012-11-21 12:06:18 -08001246 call_state = GenDalvikArgsRange(cu, info, call_state, p_null_ck,
1247 next_call_insn, dex_method_idx, vtable_idx,
1248 direct_code, direct_method, original_type,
1249 skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001250 }
1251 // Finish up any of the call sequence not interleaved in arg loading
buzbeefa57c472012-11-21 12:06:18 -08001252 while (call_state >= 0) {
1253 call_state = next_call_insn(cu, info, call_state, dex_method_idx,
1254 vtable_idx, direct_code, direct_method,
1255 original_type);
buzbee1bc37c62012-11-20 13:35:41 -08001256 }
buzbeefa57c472012-11-21 12:06:18 -08001257 if (cu->enable_debug & (1 << kDebugDisplayMissingTargets)) {
1258 GenShowTarget(cu);
buzbee1bc37c62012-11-20 13:35:41 -08001259 }
buzbeefa57c472012-11-21 12:06:18 -08001260 LIR* call_inst;
1261 if (cu->instruction_set != kX86) {
1262 call_inst = OpReg(cu, kOpBlx, TargetReg(kInvokeTgt));
buzbee1bc37c62012-11-20 13:35:41 -08001263 } else {
buzbeefa57c472012-11-21 12:06:18 -08001264 if (fast_path && info->type != kInterface) {
1265 call_inst = OpMem(cu, kOpBlx, TargetReg(kArg0),
buzbee1bc37c62012-11-20 13:35:41 -08001266 AbstractMethod::GetCodeOffset().Int32Value());
1267 } else {
1268 int trampoline = 0;
1269 switch (info->type) {
1270 case kInterface:
buzbeefa57c472012-11-21 12:06:18 -08001271 trampoline = fast_path ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
buzbee1bc37c62012-11-20 13:35:41 -08001272 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
1273 break;
1274 case kDirect:
1275 trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
1276 break;
1277 case kStatic:
1278 trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
1279 break;
1280 case kSuper:
1281 trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
1282 break;
1283 case kVirtual:
1284 trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
1285 break;
1286 default:
1287 LOG(FATAL) << "Unexpected invoke type";
1288 }
buzbeefa57c472012-11-21 12:06:18 -08001289 call_inst = OpThreadMem(cu, kOpBlx, trampoline);
buzbee1bc37c62012-11-20 13:35:41 -08001290 }
1291 }
buzbeefa57c472012-11-21 12:06:18 -08001292 MarkSafepointPC(cu, call_inst);
buzbee1bc37c62012-11-20 13:35:41 -08001293
buzbeefa57c472012-11-21 12:06:18 -08001294 ClobberCalleeSave(cu);
buzbee1bc37c62012-11-20 13:35:41 -08001295 if (info->result.location != kLocInvalid) {
1296 // We have a following MOVE_RESULT - do it now.
1297 if (info->result.wide) {
buzbeefa57c472012-11-21 12:06:18 -08001298 RegLocation ret_loc = GetReturnWide(cu, info->result.fp);
1299 StoreValueWide(cu, info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001300 } else {
buzbeefa57c472012-11-21 12:06:18 -08001301 RegLocation ret_loc = GetReturn(cu, info->result.fp);
1302 StoreValue(cu, info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001303 }
1304 }
1305}
1306
1307/*
1308 * Build an array of location records for the incoming arguments.
1309 * Note: one location record per word of arguments, with dummy
1310 * high-word loc for wide arguments. Also pull up any following
1311 * MOVE_RESULT and incorporate it into the invoke.
1312 */
buzbee02031b12012-11-23 09:41:35 -08001313CallInfo* Codegen::NewMemCallInfo(CompilationUnit* cu, BasicBlock* bb, MIR* mir, InvokeType type,
1314 bool is_range)
buzbee1bc37c62012-11-20 13:35:41 -08001315{
buzbeefa57c472012-11-21 12:06:18 -08001316 CallInfo* info = static_cast<CallInfo*>(NewMem(cu, sizeof(CallInfo), true, kAllocMisc));
1317 MIR* move_result_mir = FindMoveResult(cu, bb, mir);
1318 if (move_result_mir == NULL) {
buzbee1bc37c62012-11-20 13:35:41 -08001319 info->result.location = kLocInvalid;
1320 } else {
buzbeefa57c472012-11-21 12:06:18 -08001321 info->result = GetRawDest(cu, move_result_mir);
1322 move_result_mir->dalvikInsn.opcode = Instruction::NOP;
buzbee1bc37c62012-11-20 13:35:41 -08001323 }
buzbeefa57c472012-11-21 12:06:18 -08001324 info->num_arg_words = mir->ssa_rep->num_uses;
1325 info->args = (info->num_arg_words == 0) ? NULL : static_cast<RegLocation*>
1326 (NewMem(cu, sizeof(RegLocation) * info->num_arg_words, false, kAllocMisc));
1327 for (int i = 0; i < info->num_arg_words; i++) {
1328 info->args[i] = GetRawSrc(cu, mir, i);
buzbee1bc37c62012-11-20 13:35:41 -08001329 }
buzbeefa57c472012-11-21 12:06:18 -08001330 info->opt_flags = mir->optimization_flags;
buzbee1bc37c62012-11-20 13:35:41 -08001331 info->type = type;
buzbeefa57c472012-11-21 12:06:18 -08001332 info->is_range = is_range;
buzbee1bc37c62012-11-20 13:35:41 -08001333 info->index = mir->dalvikInsn.vB;
1334 info->offset = mir->offset;
1335 return info;
1336}
1337
buzbee31a4a6f2012-02-28 15:36:15 -08001338} // namespace art