blob: eeecb3c69cb1ce30aaffc986851c184f29fa64ea [file] [log] [blame]
Brian Carlstrom7940e442013-07-12 13:46:57 -07001/*
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
17#include "dex/compiler_ir.h"
Vladimir Marko5c96e6b2013-11-14 15:34:17 +000018#include "dex/frontend.h"
19#include "dex/quick/dex_file_method_inliner.h"
20#include "dex/quick/dex_file_to_method_inliner_map.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070021#include "dex_file-inl.h"
Ian Rogers166db042013-07-26 12:05:57 -070022#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070023#include "invoke_type.h"
24#include "mirror/array.h"
25#include "mirror/string.h"
26#include "mir_to_lir-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070027#include "x86/codegen_x86.h"
28
29namespace art {
30
31/*
32 * This source files contains "gen" codegen routines that should
33 * be applicable to most targets. Only mid-level support utilities
34 * and "op" calls may be used here.
35 */
36
37/*
38 * To save scheduling time, helper calls are broken into two parts: generation of
39 * the helper target address, and the actuall call to the helper. Because x86
40 * has a memory call operation, part 1 is a NOP for x86. For other targets,
41 * load arguments between the two parts.
42 */
Ian Rogers848871b2013-08-05 10:56:33 -070043int Mir2Lir::CallHelperSetup(ThreadOffset helper_offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070044 return (cu_->instruction_set == kX86) ? 0 : LoadHelper(helper_offset);
45}
46
47/* NOTE: if r_tgt is a temp, it will be freed following use */
Ian Rogers848871b2013-08-05 10:56:33 -070048LIR* Mir2Lir::CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070049 LIR* call_inst;
50 if (cu_->instruction_set == kX86) {
51 call_inst = OpThreadMem(kOpBlx, helper_offset);
52 } else {
53 call_inst = OpReg(kOpBlx, r_tgt);
54 FreeTemp(r_tgt);
55 }
56 if (safepoint_pc) {
57 MarkSafepointPC(call_inst);
58 }
59 return call_inst;
60}
61
Ian Rogers848871b2013-08-05 10:56:33 -070062void Mir2Lir::CallRuntimeHelperImm(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070063 int r_tgt = CallHelperSetup(helper_offset);
64 LoadConstant(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +000065 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -070066 CallHelper(r_tgt, helper_offset, safepoint_pc);
67}
68
Ian Rogers848871b2013-08-05 10:56:33 -070069void Mir2Lir::CallRuntimeHelperReg(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070070 int r_tgt = CallHelperSetup(helper_offset);
71 OpRegCopy(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +000072 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -070073 CallHelper(r_tgt, helper_offset, safepoint_pc);
74}
75
Ian Rogers848871b2013-08-05 10:56:33 -070076void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset helper_offset, RegLocation arg0,
77 bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070078 int r_tgt = CallHelperSetup(helper_offset);
79 if (arg0.wide == 0) {
80 LoadValueDirectFixed(arg0, TargetReg(kArg0));
81 } else {
82 LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
83 }
Vladimir Marko31c2aac2013-12-09 16:31:19 +000084 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -070085 CallHelper(r_tgt, helper_offset, safepoint_pc);
86}
87
Ian Rogers848871b2013-08-05 10:56:33 -070088void Mir2Lir::CallRuntimeHelperImmImm(ThreadOffset helper_offset, int arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -070089 bool safepoint_pc) {
90 int r_tgt = CallHelperSetup(helper_offset);
91 LoadConstant(TargetReg(kArg0), arg0);
92 LoadConstant(TargetReg(kArg1), arg1);
Vladimir Marko31c2aac2013-12-09 16:31:19 +000093 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -070094 CallHelper(r_tgt, helper_offset, safepoint_pc);
95}
96
Ian Rogers848871b2013-08-05 10:56:33 -070097void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset helper_offset, int arg0,
Brian Carlstrom7940e442013-07-12 13:46:57 -070098 RegLocation arg1, bool safepoint_pc) {
99 int r_tgt = CallHelperSetup(helper_offset);
100 if (arg1.wide == 0) {
101 LoadValueDirectFixed(arg1, TargetReg(kArg1));
102 } else {
103 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
104 }
105 LoadConstant(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000106 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700107 CallHelper(r_tgt, helper_offset, safepoint_pc);
108}
109
Ian Rogers848871b2013-08-05 10:56:33 -0700110void Mir2Lir::CallRuntimeHelperRegLocationImm(ThreadOffset helper_offset, RegLocation arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700111 bool safepoint_pc) {
112 int r_tgt = CallHelperSetup(helper_offset);
113 LoadValueDirectFixed(arg0, TargetReg(kArg0));
114 LoadConstant(TargetReg(kArg1), arg1);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000115 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700116 CallHelper(r_tgt, helper_offset, safepoint_pc);
117}
118
Ian Rogers848871b2013-08-05 10:56:33 -0700119void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset helper_offset, int arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700120 bool safepoint_pc) {
121 int r_tgt = CallHelperSetup(helper_offset);
122 OpRegCopy(TargetReg(kArg1), arg1);
123 LoadConstant(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000124 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700125 CallHelper(r_tgt, helper_offset, safepoint_pc);
126}
127
Ian Rogers848871b2013-08-05 10:56:33 -0700128void Mir2Lir::CallRuntimeHelperRegImm(ThreadOffset helper_offset, int arg0, int arg1,
129 bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700130 int r_tgt = CallHelperSetup(helper_offset);
131 OpRegCopy(TargetReg(kArg0), arg0);
132 LoadConstant(TargetReg(kArg1), arg1);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000133 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700134 CallHelper(r_tgt, helper_offset, safepoint_pc);
135}
136
Ian Rogers848871b2013-08-05 10:56:33 -0700137void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700138 int r_tgt = CallHelperSetup(helper_offset);
139 LoadCurrMethodDirect(TargetReg(kArg1));
140 LoadConstant(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000141 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700142 CallHelper(r_tgt, helper_offset, safepoint_pc);
143}
144
Hiroshi Yamauchibe1ca552014-01-15 11:46:48 -0800145void Mir2Lir::CallRuntimeHelperRegMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
146 int r_tgt = CallHelperSetup(helper_offset);
147 DCHECK_NE(TargetReg(kArg1), arg0);
148 if (TargetReg(kArg0) != arg0) {
149 OpRegCopy(TargetReg(kArg0), arg0);
150 }
151 LoadCurrMethodDirect(TargetReg(kArg1));
152 ClobberCallerSave();
153 CallHelper(r_tgt, helper_offset, safepoint_pc);
154}
155
Ian Rogers848871b2013-08-05 10:56:33 -0700156void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700157 RegLocation arg1, bool safepoint_pc) {
158 int r_tgt = CallHelperSetup(helper_offset);
159 if (arg0.wide == 0) {
160 LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
161 if (arg1.wide == 0) {
162 if (cu_->instruction_set == kMips) {
163 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
164 } else {
165 LoadValueDirectFixed(arg1, TargetReg(kArg1));
166 }
167 } else {
168 if (cu_->instruction_set == kMips) {
169 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
170 } else {
171 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
172 }
173 }
174 } else {
175 LoadValueDirectWideFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
176 if (arg1.wide == 0) {
177 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
178 } else {
179 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
180 }
181 }
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000182 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700183 CallHelper(r_tgt, helper_offset, safepoint_pc);
184}
185
Ian Rogers848871b2013-08-05 10:56:33 -0700186void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset helper_offset, int arg0, int arg1,
187 bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700188 int r_tgt = CallHelperSetup(helper_offset);
189 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
190 OpRegCopy(TargetReg(kArg0), arg0);
191 OpRegCopy(TargetReg(kArg1), arg1);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000192 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700193 CallHelper(r_tgt, helper_offset, safepoint_pc);
194}
195
Ian Rogers848871b2013-08-05 10:56:33 -0700196void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset helper_offset, int arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700197 int arg2, bool safepoint_pc) {
198 int r_tgt = CallHelperSetup(helper_offset);
199 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
200 OpRegCopy(TargetReg(kArg0), arg0);
201 OpRegCopy(TargetReg(kArg1), arg1);
202 LoadConstant(TargetReg(kArg2), arg2);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000203 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 CallHelper(r_tgt, helper_offset, safepoint_pc);
205}
206
Ian Rogers848871b2013-08-05 10:56:33 -0700207void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset helper_offset,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700208 int arg0, RegLocation arg2, bool safepoint_pc) {
209 int r_tgt = CallHelperSetup(helper_offset);
210 LoadValueDirectFixed(arg2, TargetReg(kArg2));
211 LoadCurrMethodDirect(TargetReg(kArg1));
212 LoadConstant(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000213 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 CallHelper(r_tgt, helper_offset, safepoint_pc);
215}
216
Ian Rogers848871b2013-08-05 10:56:33 -0700217void Mir2Lir::CallRuntimeHelperImmMethodImm(ThreadOffset helper_offset, int arg0,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700218 int arg2, bool safepoint_pc) {
219 int r_tgt = CallHelperSetup(helper_offset);
220 LoadCurrMethodDirect(TargetReg(kArg1));
221 LoadConstant(TargetReg(kArg2), arg2);
222 LoadConstant(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000223 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700224 CallHelper(r_tgt, helper_offset, safepoint_pc);
225}
226
Ian Rogers848871b2013-08-05 10:56:33 -0700227void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset helper_offset,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700228 int arg0, RegLocation arg1,
229 RegLocation arg2, bool safepoint_pc) {
230 int r_tgt = CallHelperSetup(helper_offset);
Ian Rogersa9a82542013-10-04 11:17:26 -0700231 DCHECK_EQ(arg1.wide, 0U);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700232 LoadValueDirectFixed(arg1, TargetReg(kArg1));
233 if (arg2.wide == 0) {
234 LoadValueDirectFixed(arg2, TargetReg(kArg2));
235 } else {
236 LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
237 }
238 LoadConstant(TargetReg(kArg0), arg0);
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000239 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -0700240 CallHelper(r_tgt, helper_offset, safepoint_pc);
241}
242
Ian Rogersa9a82542013-10-04 11:17:26 -0700243void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset helper_offset,
244 RegLocation arg0, RegLocation arg1,
245 RegLocation arg2,
246 bool safepoint_pc) {
247 int r_tgt = CallHelperSetup(helper_offset);
248 DCHECK_EQ(arg0.wide, 0U);
249 LoadValueDirectFixed(arg0, TargetReg(kArg0));
250 DCHECK_EQ(arg1.wide, 0U);
251 LoadValueDirectFixed(arg1, TargetReg(kArg1));
252 DCHECK_EQ(arg1.wide, 0U);
253 LoadValueDirectFixed(arg2, TargetReg(kArg2));
Vladimir Marko31c2aac2013-12-09 16:31:19 +0000254 ClobberCallerSave();
Ian Rogersa9a82542013-10-04 11:17:26 -0700255 CallHelper(r_tgt, helper_offset, safepoint_pc);
256}
257
Brian Carlstrom7940e442013-07-12 13:46:57 -0700258/*
259 * If there are any ins passed in registers that have not been promoted
260 * to a callee-save register, flush them to the frame. Perform intial
261 * assignment of promoted arguments.
262 *
263 * ArgLocs is an array of location records describing the incoming arguments
264 * with one location record per word of argument.
265 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700266void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700267 /*
268 * Dummy up a RegLocation for the incoming Method*
269 * It will attempt to keep kArg0 live (or copy it to home location
270 * if promoted).
271 */
272 RegLocation rl_src = rl_method;
273 rl_src.location = kLocPhysReg;
274 rl_src.low_reg = TargetReg(kArg0);
275 rl_src.home = false;
276 MarkLive(rl_src.low_reg, rl_src.s_reg_low);
277 StoreValue(rl_method, rl_src);
278 // If Method* has been promoted, explicitly flush
279 if (rl_method.location == kLocPhysReg) {
280 StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
281 }
282
283 if (cu_->num_ins == 0)
284 return;
285 const int num_arg_regs = 3;
286 static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
287 int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
288 /*
289 * Copy incoming arguments to their proper home locations.
290 * NOTE: an older version of dx had an issue in which
291 * it would reuse static method argument registers.
292 * This could result in the same Dalvik virtual register
293 * being promoted to both core and fp regs. To account for this,
294 * we only copy to the corresponding promoted physical register
295 * if it matches the type of the SSA name for the incoming
296 * argument. It is also possible that long and double arguments
297 * end up half-promoted. In those cases, we must flush the promoted
298 * half to memory as well.
299 */
300 for (int i = 0; i < cu_->num_ins; i++) {
301 PromotionMap* v_map = &promotion_map_[start_vreg + i];
302 if (i < num_arg_regs) {
303 // If arriving in register
304 bool need_flush = true;
305 RegLocation* t_loc = &ArgLocs[i];
306 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
307 OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
308 need_flush = false;
309 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
310 OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
311 need_flush = false;
312 } else {
313 need_flush = true;
314 }
315
buzbeed0a03b82013-09-14 08:21:05 -0700316 // For wide args, force flush if not fully promoted
Brian Carlstrom7940e442013-07-12 13:46:57 -0700317 if (t_loc->wide) {
318 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
buzbeed0a03b82013-09-14 08:21:05 -0700319 // Is only half promoted?
Brian Carlstrom7940e442013-07-12 13:46:57 -0700320 need_flush |= (p_map->core_location != v_map->core_location) ||
321 (p_map->fp_location != v_map->fp_location);
buzbeed0a03b82013-09-14 08:21:05 -0700322 if ((cu_->instruction_set == kThumb2) && t_loc->fp && !need_flush) {
323 /*
324 * In Arm, a double is represented as a pair of consecutive single float
325 * registers starting at an even number. It's possible that both Dalvik vRegs
326 * representing the incoming double were independently promoted as singles - but
327 * not in a form usable as a double. If so, we need to flush - even though the
328 * incoming arg appears fully in register. At this point in the code, both
329 * halves of the double are promoted. Make sure they are in a usable form.
330 */
331 int lowreg_index = start_vreg + i + (t_loc->high_word ? -1 : 0);
332 int low_reg = promotion_map_[lowreg_index].FpReg;
333 int high_reg = promotion_map_[lowreg_index + 1].FpReg;
334 if (((low_reg & 0x1) != 0) || (high_reg != (low_reg + 1))) {
335 need_flush = true;
336 }
337 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700338 }
339 if (need_flush) {
340 StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
341 TargetReg(arg_regs[i]), kWord);
342 }
343 } else {
344 // If arriving in frame & promoted
345 if (v_map->core_location == kLocPhysReg) {
346 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
347 v_map->core_reg);
348 }
349 if (v_map->fp_location == kLocPhysReg) {
350 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
351 v_map->FpReg);
352 }
353 }
354 }
355}
356
357/*
358 * Bit of a hack here - in the absence of a real scheduling pass,
359 * emit the next instruction in static & direct invoke sequences.
360 */
361static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
362 int state, const MethodReference& target_method,
363 uint32_t unused,
364 uintptr_t direct_code, uintptr_t direct_method,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700365 InvokeType type) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700366 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700367 if (direct_code != 0 && direct_method != 0) {
368 switch (state) {
369 case 0: // Get the current Method* [sets kArg0]
370 if (direct_code != static_cast<unsigned int>(-1)) {
Ian Rogers83883d72013-10-21 21:07:24 -0700371 if (cu->instruction_set != kX86) {
372 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
373 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700374 } else {
375 CHECK_EQ(cu->dex_file, target_method.dex_file);
376 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
377 target_method.dex_method_index, 0);
378 if (data_target == NULL) {
379 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
380 data_target->operands[1] = type;
381 }
382 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
383 cg->AppendLIR(load_pc_rel);
384 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
385 }
386 if (direct_method != static_cast<unsigned int>(-1)) {
387 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
388 } else {
389 CHECK_EQ(cu->dex_file, target_method.dex_file);
390 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
391 target_method.dex_method_index, 0);
392 if (data_target == NULL) {
393 data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
394 data_target->operands[1] = type;
395 }
396 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
397 cg->AppendLIR(load_pc_rel);
398 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
399 }
400 break;
401 default:
402 return -1;
403 }
404 } else {
405 switch (state) {
406 case 0: // Get the current Method* [sets kArg0]
407 // TUNING: we can save a reg copy if Method* has been promoted.
408 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
409 break;
410 case 1: // Get method->dex_cache_resolved_methods_
411 cg->LoadWordDisp(cg->TargetReg(kArg0),
Brian Carlstromea46f952013-07-30 01:26:50 -0700412 mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700413 // Set up direct code if known.
414 if (direct_code != 0) {
415 if (direct_code != static_cast<unsigned int>(-1)) {
416 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
417 } else {
418 CHECK_EQ(cu->dex_file, target_method.dex_file);
Ian Rogers83883d72013-10-21 21:07:24 -0700419 CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700420 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
421 target_method.dex_method_index, 0);
422 if (data_target == NULL) {
423 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
424 data_target->operands[1] = type;
425 }
426 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
427 cg->AppendLIR(load_pc_rel);
428 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
429 }
430 }
431 break;
432 case 2: // Grab target method*
433 CHECK_EQ(cu->dex_file, target_method.dex_file);
434 cg->LoadWordDisp(cg->TargetReg(kArg0),
435 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
436 (target_method.dex_method_index * 4),
437 cg-> TargetReg(kArg0));
438 break;
439 case 3: // Grab the code from the method*
440 if (cu->instruction_set != kX86) {
441 if (direct_code == 0) {
442 cg->LoadWordDisp(cg->TargetReg(kArg0),
Brian Carlstromea46f952013-07-30 01:26:50 -0700443 mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444 cg->TargetReg(kInvokeTgt));
445 }
446 break;
447 }
448 // Intentional fallthrough for x86
449 default:
450 return -1;
451 }
452 }
453 return state + 1;
454}
455
456/*
457 * Bit of a hack here - in the absence of a real scheduling pass,
458 * emit the next instruction in a virtual invoke sequence.
459 * We can use kLr as a temp prior to target address loading
460 * Note also that we'll load the first argument ("this") into
461 * kArg1 here rather than the standard LoadArgRegs.
462 */
463static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
464 int state, const MethodReference& target_method,
465 uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700466 InvokeType unused3) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700467 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
468 /*
469 * This is the fast path in which the target virtual method is
470 * fully resolved at compile time.
471 */
472 switch (state) {
473 case 0: { // Get "this" [set kArg1]
474 RegLocation rl_arg = info->args[0];
475 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
476 break;
477 }
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700478 case 1: // Is "this" null? [use kArg1]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700479 cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
480 // get this->klass_ [use kArg1, set kInvokeTgt]
481 cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
482 cg->TargetReg(kInvokeTgt));
483 break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700484 case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700485 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
486 cg->TargetReg(kInvokeTgt));
487 break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700488 case 3: // Get target method [use kInvokeTgt, set kArg0]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700489 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
490 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
491 cg->TargetReg(kArg0));
492 break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700493 case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700494 if (cu->instruction_set != kX86) {
495 cg->LoadWordDisp(cg->TargetReg(kArg0),
Brian Carlstromea46f952013-07-30 01:26:50 -0700496 mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700497 cg->TargetReg(kInvokeTgt));
498 break;
499 }
500 // Intentional fallthrough for X86
501 default:
502 return -1;
503 }
504 return state + 1;
505}
506
507/*
Jeff Hao88474b42013-10-23 16:24:40 -0700508 * Emit the next instruction in an invoke interface sequence. This will do a lookup in the
509 * class's IMT, calling either the actual method or art_quick_imt_conflict_trampoline if
510 * more than one interface method map to the same index. Note also that we'll load the first
511 * argument ("this") into kArg1 here rather than the standard LoadArgRegs.
Brian Carlstrom7940e442013-07-12 13:46:57 -0700512 */
513static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
514 const MethodReference& target_method,
Jeff Hao88474b42013-10-23 16:24:40 -0700515 uint32_t method_idx, uintptr_t unused,
516 uintptr_t direct_method, InvokeType unused2) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700517 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Brian Carlstrom7940e442013-07-12 13:46:57 -0700518
Jeff Hao88474b42013-10-23 16:24:40 -0700519 switch (state) {
520 case 0: // Set target method index in case of conflict [set kHiddenArg, kHiddenFpArg (x86)]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700521 CHECK_EQ(cu->dex_file, target_method.dex_file);
Jeff Hao88474b42013-10-23 16:24:40 -0700522 CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
523 cg->LoadConstant(cg->TargetReg(kHiddenArg), target_method.dex_method_index);
524 if (cu->instruction_set == kX86) {
525 cg->OpRegCopy(cg->TargetReg(kHiddenFpArg), cg->TargetReg(kHiddenArg));
526 }
527 break;
528 case 1: { // Get "this" [set kArg1]
529 RegLocation rl_arg = info->args[0];
530 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
531 break;
532 }
533 case 2: // Is "this" null? [use kArg1]
534 cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
535 // Get this->klass_ [use kArg1, set kInvokeTgt]
536 cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
537 cg->TargetReg(kInvokeTgt));
538 break;
539 case 3: // Get this->klass_->imtable [use kInvokeTgt, set kInvokeTgt]
540 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::ImTableOffset().Int32Value(),
541 cg->TargetReg(kInvokeTgt));
542 break;
543 case 4: // Get target method [use kInvokeTgt, set kArg0]
544 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), ((method_idx % ClassLinker::kImtSize) * 4) +
545 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700546 cg->TargetReg(kArg0));
547 break;
Jeff Hao88474b42013-10-23 16:24:40 -0700548 case 5: // Get the compiled code address [use kArg0, set kInvokeTgt]
549 if (cu->instruction_set != kX86) {
550 cg->LoadWordDisp(cg->TargetReg(kArg0),
551 mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
552 cg->TargetReg(kInvokeTgt));
553 break;
554 }
555 // Intentional fallthrough for X86
Brian Carlstrom7940e442013-07-12 13:46:57 -0700556 default:
557 return -1;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700558 }
559 return state + 1;
560}
561
Ian Rogers848871b2013-08-05 10:56:33 -0700562static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, ThreadOffset trampoline,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700563 int state, const MethodReference& target_method,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700564 uint32_t method_idx) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700565 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
566 /*
567 * This handles the case in which the base method is not fully
568 * resolved at compile time, we bail to a runtime helper.
569 */
570 if (state == 0) {
571 if (cu->instruction_set != kX86) {
572 // Load trampoline target
Ian Rogers848871b2013-08-05 10:56:33 -0700573 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(), cg->TargetReg(kInvokeTgt));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700574 }
575 // Load kArg0 with method index
576 CHECK_EQ(cu->dex_file, target_method.dex_file);
577 cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
578 return 1;
579 }
580 return -1;
581}
582
583static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
584 int state,
585 const MethodReference& target_method,
586 uint32_t method_idx,
587 uintptr_t unused, uintptr_t unused2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700588 InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700589 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700590 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
591}
592
593static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
594 const MethodReference& target_method,
595 uint32_t method_idx, uintptr_t unused,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700596 uintptr_t unused2, InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700597 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700598 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
599}
600
601static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
602 const MethodReference& target_method,
603 uint32_t method_idx, uintptr_t unused,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700604 uintptr_t unused2, InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700605 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700606 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
607}
608
609static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
610 const MethodReference& target_method,
611 uint32_t method_idx, uintptr_t unused,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700612 uintptr_t unused2, InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700613 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700614 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
615}
616
617static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
618 CallInfo* info, int state,
619 const MethodReference& target_method,
620 uint32_t unused,
621 uintptr_t unused2, uintptr_t unused3,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700622 InvokeType unused4) {
Ian Rogers848871b2013-08-05 10:56:33 -0700623 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700624 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
625}
626
627int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
628 NextCallInsn next_call_insn,
629 const MethodReference& target_method,
630 uint32_t vtable_idx, uintptr_t direct_code,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700631 uintptr_t direct_method, InvokeType type, bool skip_this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700632 int last_arg_reg = TargetReg(kArg3);
633 int next_reg = TargetReg(kArg1);
634 int next_arg = 0;
635 if (skip_this) {
636 next_reg++;
637 next_arg++;
638 }
639 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
640 RegLocation rl_arg = info->args[next_arg++];
641 rl_arg = UpdateRawLoc(rl_arg);
642 if (rl_arg.wide && (next_reg <= TargetReg(kArg2))) {
643 LoadValueDirectWideFixed(rl_arg, next_reg, next_reg + 1);
644 next_reg++;
645 next_arg++;
646 } else {
647 if (rl_arg.wide) {
648 rl_arg.wide = false;
649 rl_arg.is_const = false;
650 }
651 LoadValueDirectFixed(rl_arg, next_reg);
652 }
653 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
654 direct_code, direct_method, type);
655 }
656 return call_state;
657}
658
659/*
660 * Load up to 5 arguments, the first three of which will be in
661 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer,
662 * and as part of the load sequence, it must be replaced with
663 * the target method pointer. Note, this may also be called
664 * for "range" variants if the number of arguments is 5 or fewer.
665 */
666int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
667 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
668 const MethodReference& target_method,
669 uint32_t vtable_idx, uintptr_t direct_code,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700670 uintptr_t direct_method, InvokeType type, bool skip_this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700671 RegLocation rl_arg;
672
673 /* If no arguments, just return */
674 if (info->num_arg_words == 0)
675 return call_state;
676
677 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
678 direct_code, direct_method, type);
679
680 DCHECK_LE(info->num_arg_words, 5);
681 if (info->num_arg_words > 3) {
682 int32_t next_use = 3;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700683 // Detect special case of wide arg spanning arg3/arg4
Brian Carlstrom7940e442013-07-12 13:46:57 -0700684 RegLocation rl_use0 = info->args[0];
685 RegLocation rl_use1 = info->args[1];
686 RegLocation rl_use2 = info->args[2];
687 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
688 rl_use2.wide) {
689 int reg = -1;
690 // Wide spans, we need the 2nd half of uses[2].
691 rl_arg = UpdateLocWide(rl_use2);
692 if (rl_arg.location == kLocPhysReg) {
693 reg = rl_arg.high_reg;
694 } else {
695 // kArg2 & rArg3 can safely be used here
696 reg = TargetReg(kArg3);
697 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
698 call_state = next_call_insn(cu_, info, call_state, target_method,
699 vtable_idx, direct_code, direct_method, type);
700 }
701 StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
702 StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
703 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
704 direct_code, direct_method, type);
705 next_use++;
706 }
707 // Loop through the rest
708 while (next_use < info->num_arg_words) {
709 int low_reg;
710 int high_reg = -1;
711 rl_arg = info->args[next_use];
712 rl_arg = UpdateRawLoc(rl_arg);
713 if (rl_arg.location == kLocPhysReg) {
714 low_reg = rl_arg.low_reg;
715 high_reg = rl_arg.high_reg;
716 } else {
717 low_reg = TargetReg(kArg2);
718 if (rl_arg.wide) {
719 high_reg = TargetReg(kArg3);
720 LoadValueDirectWideFixed(rl_arg, low_reg, high_reg);
721 } else {
722 LoadValueDirectFixed(rl_arg, low_reg);
723 }
724 call_state = next_call_insn(cu_, info, call_state, target_method,
725 vtable_idx, direct_code, direct_method, type);
726 }
727 int outs_offset = (next_use + 1) * 4;
728 if (rl_arg.wide) {
729 StoreBaseDispWide(TargetReg(kSp), outs_offset, low_reg, high_reg);
730 next_use += 2;
731 } else {
732 StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
733 next_use++;
734 }
735 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
736 direct_code, direct_method, type);
737 }
738 }
739
740 call_state = LoadArgRegs(info, call_state, next_call_insn,
741 target_method, vtable_idx, direct_code, direct_method,
742 type, skip_this);
743
744 if (pcrLabel) {
745 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
746 }
747 return call_state;
748}
749
750/*
751 * May have 0+ arguments (also used for jumbo). Note that
752 * source virtual registers may be in physical registers, so may
753 * need to be flushed to home location before copying. This
754 * applies to arg3 and above (see below).
755 *
756 * Two general strategies:
757 * If < 20 arguments
758 * Pass args 3-18 using vldm/vstm block copy
759 * Pass arg0, arg1 & arg2 in kArg1-kArg3
760 * If 20+ arguments
761 * Pass args arg19+ using memcpy block copy
762 * Pass arg0, arg1 & arg2 in kArg1-kArg3
763 *
764 */
765int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
766 LIR** pcrLabel, NextCallInsn next_call_insn,
767 const MethodReference& target_method,
768 uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700769 InvokeType type, bool skip_this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700770 // If we can treat it as non-range (Jumbo ops will use range form)
771 if (info->num_arg_words <= 5)
772 return GenDalvikArgsNoRange(info, call_state, pcrLabel,
773 next_call_insn, target_method, vtable_idx,
774 direct_code, direct_method, type, skip_this);
775 /*
776 * First load the non-register arguments. Both forms expect all
777 * of the source arguments to be in their home frame location, so
778 * scan the s_reg names and flush any that have been promoted to
779 * frame backing storage.
780 */
781 // Scan the rest of the args - if in phys_reg flush to memory
782 for (int next_arg = 0; next_arg < info->num_arg_words;) {
783 RegLocation loc = info->args[next_arg];
784 if (loc.wide) {
785 loc = UpdateLocWide(loc);
786 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
787 StoreBaseDispWide(TargetReg(kSp), SRegOffset(loc.s_reg_low),
788 loc.low_reg, loc.high_reg);
789 }
790 next_arg += 2;
791 } else {
792 loc = UpdateLoc(loc);
793 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
794 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
795 loc.low_reg, kWord);
796 }
797 next_arg++;
798 }
799 }
800
801 int start_offset = SRegOffset(info->args[3].s_reg_low);
802 int outs_offset = 4 /* Method* */ + (3 * 4);
803 if (cu_->instruction_set != kThumb2) {
804 // Generate memcpy
805 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
806 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
Ian Rogers7655f292013-07-29 11:07:13 -0700807 CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700808 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
809 } else {
810 if (info->num_arg_words >= 20) {
811 // Generate memcpy
812 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
813 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
Ian Rogers7655f292013-07-29 11:07:13 -0700814 CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700815 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
816 } else {
817 // Use vldm/vstm pair using kArg3 as a temp
818 int regs_left = std::min(info->num_arg_words - 3, 16);
819 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
820 direct_code, direct_method, type);
821 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
822 LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700823 // TUNING: loosen barrier
buzbeeb48819d2013-09-14 16:15:25 -0700824 ld->u.m.def_mask = ENCODE_ALL;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700825 SetMemRefType(ld, true /* is_load */, kDalvikReg);
826 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
827 direct_code, direct_method, type);
828 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
829 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
830 direct_code, direct_method, type);
831 LIR* st = OpVstm(TargetReg(kArg3), regs_left);
832 SetMemRefType(st, false /* is_load */, kDalvikReg);
buzbeeb48819d2013-09-14 16:15:25 -0700833 st->u.m.def_mask = ENCODE_ALL;
Brian Carlstrom7940e442013-07-12 13:46:57 -0700834 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
835 direct_code, direct_method, type);
836 }
837 }
838
839 call_state = LoadArgRegs(info, call_state, next_call_insn,
840 target_method, vtable_idx, direct_code, direct_method,
841 type, skip_this);
842
843 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
844 direct_code, direct_method, type);
845 if (pcrLabel) {
846 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
847 }
848 return call_state;
849}
850
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700851RegLocation Mir2Lir::InlineTarget(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700852 RegLocation res;
853 if (info->result.location == kLocInvalid) {
854 res = GetReturn(false);
855 } else {
856 res = info->result;
857 }
858 return res;
859}
860
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700861RegLocation Mir2Lir::InlineTargetWide(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700862 RegLocation res;
863 if (info->result.location == kLocInvalid) {
864 res = GetReturnWide(false);
865 } else {
866 res = info->result;
867 }
868 return res;
869}
870
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700871bool Mir2Lir::GenInlinedCharAt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700872 if (cu_->instruction_set == kMips) {
873 // TODO - add Mips implementation
874 return false;
875 }
876 // Location of reference to data array
877 int value_offset = mirror::String::ValueOffset().Int32Value();
878 // Location of count
879 int count_offset = mirror::String::CountOffset().Int32Value();
880 // Starting offset within data array
881 int offset_offset = mirror::String::OffsetOffset().Int32Value();
882 // Start of char data with array_
883 int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
884
885 RegLocation rl_obj = info->args[0];
886 RegLocation rl_idx = info->args[1];
887 rl_obj = LoadValue(rl_obj, kCoreReg);
888 rl_idx = LoadValue(rl_idx, kCoreReg);
889 int reg_max;
890 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
891 bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
892 LIR* launch_pad = NULL;
893 int reg_off = INVALID_REG;
894 int reg_ptr = INVALID_REG;
895 if (cu_->instruction_set != kX86) {
896 reg_off = AllocTemp();
897 reg_ptr = AllocTemp();
898 if (range_check) {
899 reg_max = AllocTemp();
900 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
901 }
902 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
903 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
904 if (range_check) {
905 // Set up a launch pad to allow retry in case of bounds violation */
buzbee0d829482013-10-11 15:24:55 -0700906 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700907 intrinsic_launchpads_.Insert(launch_pad);
908 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
909 FreeTemp(reg_max);
Vladimir Marko58af1f92013-12-19 13:31:15 +0000910 OpCondBranch(kCondUge, launch_pad);
Brian Carlstrom6f485c62013-07-18 15:35:35 -0700911 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700912 } else {
913 if (range_check) {
914 reg_max = AllocTemp();
915 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
916 // Set up a launch pad to allow retry in case of bounds violation */
buzbee0d829482013-10-11 15:24:55 -0700917 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700918 intrinsic_launchpads_.Insert(launch_pad);
919 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
920 FreeTemp(reg_max);
Vladimir Marko58af1f92013-12-19 13:31:15 +0000921 OpCondBranch(kCondUge, launch_pad);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700922 }
923 reg_off = AllocTemp();
924 reg_ptr = AllocTemp();
925 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
926 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
927 }
928 OpRegImm(kOpAdd, reg_ptr, data_offset);
929 OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
930 FreeTemp(rl_obj.low_reg);
931 FreeTemp(rl_idx.low_reg);
932 RegLocation rl_dest = InlineTarget(info);
933 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
934 LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
935 FreeTemp(reg_off);
936 FreeTemp(reg_ptr);
937 StoreValue(rl_dest, rl_result);
938 if (range_check) {
939 launch_pad->operands[2] = 0; // no resumption
940 }
941 // Record that we've already inlined & null checked
942 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
943 return true;
944}
945
946// Generates an inlined String.is_empty or String.length.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700947bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700948 if (cu_->instruction_set == kMips) {
949 // TODO - add Mips implementation
950 return false;
951 }
952 // dst = src.length();
953 RegLocation rl_obj = info->args[0];
954 rl_obj = LoadValue(rl_obj, kCoreReg);
955 RegLocation rl_dest = InlineTarget(info);
956 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
957 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
958 LoadWordDisp(rl_obj.low_reg, mirror::String::CountOffset().Int32Value(), rl_result.low_reg);
959 if (is_empty) {
960 // dst = (dst == 0);
961 if (cu_->instruction_set == kThumb2) {
962 int t_reg = AllocTemp();
963 OpRegReg(kOpNeg, t_reg, rl_result.low_reg);
964 OpRegRegReg(kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
965 } else {
966 DCHECK_EQ(cu_->instruction_set, kX86);
967 OpRegImm(kOpSub, rl_result.low_reg, 1);
968 OpRegImm(kOpLsr, rl_result.low_reg, 31);
969 }
970 }
971 StoreValue(rl_dest, rl_result);
972 return true;
973}
974
Vladimir Marko6bdf1ff2013-10-29 17:40:46 +0000975bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) {
976 if (cu_->instruction_set == kMips) {
977 // TODO - add Mips implementation
978 return false;
979 }
980 RegLocation rl_src_i = info->args[0];
981 RegLocation rl_dest = InlineTarget(info); // result reg
982 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
983 if (size == kLong) {
984 RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg);
Vladimir Markof246af22013-11-27 12:30:15 +0000985 int r_i_low = rl_i.low_reg;
986 if (rl_i.low_reg == rl_result.low_reg) {
987 // First REV shall clobber rl_result.low_reg, save the value in a temp for the second REV.
988 r_i_low = AllocTemp();
989 OpRegCopy(r_i_low, rl_i.low_reg);
990 }
Vladimir Marko6bdf1ff2013-10-29 17:40:46 +0000991 OpRegReg(kOpRev, rl_result.low_reg, rl_i.high_reg);
Vladimir Markof246af22013-11-27 12:30:15 +0000992 OpRegReg(kOpRev, rl_result.high_reg, r_i_low);
993 if (rl_i.low_reg == rl_result.low_reg) {
994 FreeTemp(r_i_low);
995 }
Vladimir Marko6bdf1ff2013-10-29 17:40:46 +0000996 StoreValueWide(rl_dest, rl_result);
997 } else {
998 DCHECK(size == kWord || size == kSignedHalf);
999 OpKind op = (size == kWord) ? kOpRev : kOpRevsh;
1000 RegLocation rl_i = LoadValue(rl_src_i, kCoreReg);
1001 OpRegReg(op, rl_result.low_reg, rl_i.low_reg);
1002 StoreValue(rl_dest, rl_result);
1003 }
1004 return true;
1005}
1006
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001007bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001008 if (cu_->instruction_set == kMips) {
1009 // TODO - add Mips implementation
1010 return false;
1011 }
1012 RegLocation rl_src = info->args[0];
1013 rl_src = LoadValue(rl_src, kCoreReg);
1014 RegLocation rl_dest = InlineTarget(info);
1015 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1016 int sign_reg = AllocTemp();
1017 // abs(x) = y<=x>>31, (x+y)^y.
1018 OpRegRegImm(kOpAsr, sign_reg, rl_src.low_reg, 31);
1019 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
1020 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1021 StoreValue(rl_dest, rl_result);
1022 return true;
1023}
1024
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001025bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001026 if (cu_->instruction_set == kMips) {
1027 // TODO - add Mips implementation
1028 return false;
1029 }
1030 if (cu_->instruction_set == kThumb2) {
1031 RegLocation rl_src = info->args[0];
1032 rl_src = LoadValueWide(rl_src, kCoreReg);
1033 RegLocation rl_dest = InlineTargetWide(info);
1034 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1035 int sign_reg = AllocTemp();
1036 // abs(x) = y<=x>>31, (x+y)^y.
1037 OpRegRegImm(kOpAsr, sign_reg, rl_src.high_reg, 31);
1038 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
1039 OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
1040 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1041 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1042 StoreValueWide(rl_dest, rl_result);
1043 return true;
1044 } else {
1045 DCHECK_EQ(cu_->instruction_set, kX86);
1046 // Reuse source registers to avoid running out of temps
1047 RegLocation rl_src = info->args[0];
1048 rl_src = LoadValueWide(rl_src, kCoreReg);
1049 RegLocation rl_dest = InlineTargetWide(info);
1050 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1051 OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
1052 FreeTemp(rl_src.low_reg);
1053 FreeTemp(rl_src.high_reg);
1054 int sign_reg = AllocTemp();
1055 // abs(x) = y<=x>>31, (x+y)^y.
1056 OpRegRegImm(kOpAsr, sign_reg, rl_result.high_reg, 31);
1057 OpRegReg(kOpAdd, rl_result.low_reg, sign_reg);
1058 OpRegReg(kOpAdc, rl_result.high_reg, sign_reg);
1059 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1060 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1061 StoreValueWide(rl_dest, rl_result);
1062 return true;
1063 }
1064}
1065
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001066bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001067 if (cu_->instruction_set == kMips) {
1068 // TODO - add Mips implementation
1069 return false;
1070 }
1071 RegLocation rl_src = info->args[0];
1072 RegLocation rl_dest = InlineTarget(info);
1073 StoreValue(rl_dest, rl_src);
1074 return true;
1075}
1076
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001077bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001078 if (cu_->instruction_set == kMips) {
1079 // TODO - add Mips implementation
1080 return false;
1081 }
1082 RegLocation rl_src = info->args[0];
1083 RegLocation rl_dest = InlineTargetWide(info);
1084 StoreValueWide(rl_dest, rl_src);
1085 return true;
1086}
1087
1088/*
1089 * Fast string.index_of(I) & (II). Tests for simple case of char <= 0xffff,
1090 * otherwise bails to standard library code.
1091 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001092bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001093 if (cu_->instruction_set == kMips) {
1094 // TODO - add Mips implementation
1095 return false;
1096 }
Vladimir Marko31c2aac2013-12-09 16:31:19 +00001097 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001098 LockCallTemps(); // Using fixed registers
1099 int reg_ptr = TargetReg(kArg0);
1100 int reg_char = TargetReg(kArg1);
1101 int reg_start = TargetReg(kArg2);
1102
1103 RegLocation rl_obj = info->args[0];
1104 RegLocation rl_char = info->args[1];
1105 RegLocation rl_start = info->args[2];
1106 LoadValueDirectFixed(rl_obj, reg_ptr);
1107 LoadValueDirectFixed(rl_char, reg_char);
1108 if (zero_based) {
1109 LoadConstant(reg_start, 0);
1110 } else {
1111 LoadValueDirectFixed(rl_start, reg_start);
1112 }
Ian Rogers7655f292013-07-29 11:07:13 -07001113 int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(QUICK_ENTRYPOINT_OFFSET(pIndexOf)) : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001114 GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
buzbee0d829482013-10-11 15:24:55 -07001115 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
Brian Carlstrom7940e442013-07-12 13:46:57 -07001116 intrinsic_launchpads_.Insert(launch_pad);
1117 OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
1118 // NOTE: not a safepoint
1119 if (cu_->instruction_set != kX86) {
1120 OpReg(kOpBlx, r_tgt);
1121 } else {
Ian Rogers7655f292013-07-29 11:07:13 -07001122 OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pIndexOf));
Brian Carlstrom7940e442013-07-12 13:46:57 -07001123 }
1124 LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
buzbee0d829482013-10-11 15:24:55 -07001125 launch_pad->operands[2] = WrapPointer(resume_tgt);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001126 // Record that we've already inlined & null checked
1127 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1128 RegLocation rl_return = GetReturn(false);
1129 RegLocation rl_dest = InlineTarget(info);
1130 StoreValue(rl_dest, rl_return);
1131 return true;
1132}
1133
1134/* Fast string.compareTo(Ljava/lang/string;)I. */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001135bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001136 if (cu_->instruction_set == kMips) {
1137 // TODO - add Mips implementation
1138 return false;
1139 }
Vladimir Marko31c2aac2013-12-09 16:31:19 +00001140 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001141 LockCallTemps(); // Using fixed registers
1142 int reg_this = TargetReg(kArg0);
1143 int reg_cmp = TargetReg(kArg1);
1144
1145 RegLocation rl_this = info->args[0];
1146 RegLocation rl_cmp = info->args[1];
1147 LoadValueDirectFixed(rl_this, reg_this);
1148 LoadValueDirectFixed(rl_cmp, reg_cmp);
1149 int r_tgt = (cu_->instruction_set != kX86) ?
Ian Rogers7655f292013-07-29 11:07:13 -07001150 LoadHelper(QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001151 GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
Brian Carlstrom7934ac22013-07-26 10:54:15 -07001152 // TUNING: check if rl_cmp.s_reg_low is already null checked
buzbee0d829482013-10-11 15:24:55 -07001153 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
Brian Carlstrom7940e442013-07-12 13:46:57 -07001154 intrinsic_launchpads_.Insert(launch_pad);
1155 OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
1156 // NOTE: not a safepoint
1157 if (cu_->instruction_set != kX86) {
1158 OpReg(kOpBlx, r_tgt);
1159 } else {
Ian Rogers7655f292013-07-29 11:07:13 -07001160 OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pStringCompareTo));
Brian Carlstrom7940e442013-07-12 13:46:57 -07001161 }
1162 launch_pad->operands[2] = 0; // No return possible
1163 // Record that we've already inlined & null checked
1164 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1165 RegLocation rl_return = GetReturn(false);
1166 RegLocation rl_dest = InlineTarget(info);
1167 StoreValue(rl_dest, rl_return);
1168 return true;
1169}
1170
1171bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1172 RegLocation rl_dest = InlineTarget(info);
1173 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Ian Rogers848871b2013-08-05 10:56:33 -07001174 ThreadOffset offset = Thread::PeerOffset();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001175 if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
Ian Rogers848871b2013-08-05 10:56:33 -07001176 LoadWordDisp(TargetReg(kSelf), offset.Int32Value(), rl_result.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001177 } else {
1178 CHECK(cu_->instruction_set == kX86);
Brian Carlstrom2d888622013-07-18 17:02:00 -07001179 reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.low_reg, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001180 }
1181 StoreValue(rl_dest, rl_result);
1182 return true;
1183}
1184
1185bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
1186 bool is_long, bool is_volatile) {
1187 if (cu_->instruction_set == kMips) {
1188 // TODO - add Mips implementation
1189 return false;
1190 }
1191 // Unused - RegLocation rl_src_unsafe = info->args[0];
1192 RegLocation rl_src_obj = info->args[1]; // Object
1193 RegLocation rl_src_offset = info->args[2]; // long low
1194 rl_src_offset.wide = 0; // ignore high half in info->args[3]
1195 RegLocation rl_dest = InlineTarget(info); // result reg
1196 if (is_volatile) {
1197 GenMemBarrier(kLoadLoad);
1198 }
1199 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1200 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1201 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1202 if (is_long) {
1203 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1204 LoadBaseDispWide(rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
1205 StoreValueWide(rl_dest, rl_result);
1206 } else {
1207 LoadBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
1208 StoreValue(rl_dest, rl_result);
1209 }
1210 return true;
1211}
1212
1213bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
1214 bool is_object, bool is_volatile, bool is_ordered) {
1215 if (cu_->instruction_set == kMips) {
1216 // TODO - add Mips implementation
1217 return false;
1218 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001219 // Unused - RegLocation rl_src_unsafe = info->args[0];
1220 RegLocation rl_src_obj = info->args[1]; // Object
1221 RegLocation rl_src_offset = info->args[2]; // long low
1222 rl_src_offset.wide = 0; // ignore high half in info->args[3]
1223 RegLocation rl_src_value = info->args[4]; // value to store
1224 if (is_volatile || is_ordered) {
1225 GenMemBarrier(kStoreStore);
1226 }
1227 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1228 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1229 RegLocation rl_value;
1230 if (is_long) {
1231 rl_value = LoadValueWide(rl_src_value, kCoreReg);
1232 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1233 StoreBaseDispWide(rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
1234 } else {
1235 rl_value = LoadValue(rl_src_value, kCoreReg);
1236 StoreBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
1237 }
Mark Mendelldf8ee2e2014-01-27 16:37:47 -08001238
1239 // Free up the temp early, to ensure x86 doesn't run out of temporaries in MarkGCCard.
1240 FreeTemp(rl_offset.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001241 if (is_volatile) {
1242 GenMemBarrier(kStoreLoad);
1243 }
1244 if (is_object) {
1245 MarkGCCard(rl_value.low_reg, rl_object.low_reg);
1246 }
1247 return true;
1248}
1249
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001250void Mir2Lir::GenInvoke(CallInfo* info) {
Vladimir Marko5c96e6b2013-11-14 15:34:17 +00001251 if (!(info->opt_flags & MIR_INLINED)) {
Vladimir Marko5816ed42013-11-27 17:04:20 +00001252 DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
1253 if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
1254 ->GenIntrinsic(this, info)) {
Vladimir Marko5c96e6b2013-11-14 15:34:17 +00001255 return;
1256 }
Brian Carlstrom7940e442013-07-12 13:46:57 -07001257 }
1258 InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
1259 int call_state = 0;
1260 LIR* null_ck;
1261 LIR** p_null_ck = NULL;
1262 NextCallInsn next_call_insn;
1263 FlushAllRegs(); /* Everything to home location */
1264 // Explicit register usage
1265 LockCallTemps();
1266
1267 DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
1268 MethodReference target_method(cUnit->GetDexFile(), info->index);
1269 int vtable_idx;
1270 uintptr_t direct_code;
1271 uintptr_t direct_method;
1272 bool skip_this;
1273 bool fast_path =
1274 cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
1275 current_dalvik_offset_,
Ian Rogers65ec92c2013-09-06 10:49:58 -07001276 true, true,
1277 &info->type, &target_method,
1278 &vtable_idx,
1279 &direct_code, &direct_method) && !SLOW_INVOKE_PATH;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001280 if (info->type == kInterface) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001281 next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
Jeff Hao88474b42013-10-23 16:24:40 -07001282 skip_this = fast_path;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001283 } else if (info->type == kDirect) {
1284 if (fast_path) {
1285 p_null_ck = &null_ck;
1286 }
1287 next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1288 skip_this = false;
1289 } else if (info->type == kStatic) {
1290 next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1291 skip_this = false;
1292 } else if (info->type == kSuper) {
1293 DCHECK(!fast_path); // Fast path is a direct call.
1294 next_call_insn = NextSuperCallInsnSP;
1295 skip_this = false;
1296 } else {
1297 DCHECK_EQ(info->type, kVirtual);
1298 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1299 skip_this = fast_path;
1300 }
1301 if (!info->is_range) {
1302 call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
1303 next_call_insn, target_method,
1304 vtable_idx, direct_code, direct_method,
1305 original_type, skip_this);
1306 } else {
1307 call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
1308 next_call_insn, target_method, vtable_idx,
1309 direct_code, direct_method, original_type,
1310 skip_this);
1311 }
1312 // Finish up any of the call sequence not interleaved in arg loading
1313 while (call_state >= 0) {
1314 call_state = next_call_insn(cu_, info, call_state, target_method,
1315 vtable_idx, direct_code, direct_method,
1316 original_type);
1317 }
1318 LIR* call_inst;
1319 if (cu_->instruction_set != kX86) {
1320 call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
1321 } else {
Jeff Hao88474b42013-10-23 16:24:40 -07001322 if (fast_path) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001323 call_inst = OpMem(kOpBlx, TargetReg(kArg0),
Brian Carlstromea46f952013-07-30 01:26:50 -07001324 mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value());
Brian Carlstrom7940e442013-07-12 13:46:57 -07001325 } else {
Ian Rogers848871b2013-08-05 10:56:33 -07001326 ThreadOffset trampoline(-1);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001327 switch (info->type) {
1328 case kInterface:
Jeff Hao88474b42013-10-23 16:24:40 -07001329 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001330 break;
1331 case kDirect:
Ian Rogers7655f292013-07-29 11:07:13 -07001332 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001333 break;
1334 case kStatic:
Ian Rogers7655f292013-07-29 11:07:13 -07001335 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001336 break;
1337 case kSuper:
Ian Rogers7655f292013-07-29 11:07:13 -07001338 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001339 break;
1340 case kVirtual:
Ian Rogers7655f292013-07-29 11:07:13 -07001341 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001342 break;
1343 default:
1344 LOG(FATAL) << "Unexpected invoke type";
1345 }
1346 call_inst = OpThreadMem(kOpBlx, trampoline);
1347 }
1348 }
1349 MarkSafepointPC(call_inst);
1350
Vladimir Marko31c2aac2013-12-09 16:31:19 +00001351 ClobberCallerSave();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001352 if (info->result.location != kLocInvalid) {
1353 // We have a following MOVE_RESULT - do it now.
1354 if (info->result.wide) {
1355 RegLocation ret_loc = GetReturnWide(info->result.fp);
1356 StoreValueWide(info->result, ret_loc);
1357 } else {
1358 RegLocation ret_loc = GetReturn(info->result.fp);
1359 StoreValue(info->result, ret_loc);
1360 }
1361 }
1362}
1363
1364} // namespace art