blob: 20d683a947bb1e20980b8fcef19d53634e419b28 [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"
18#include "dex_file-inl.h"
Ian Rogers166db042013-07-26 12:05:57 -070019#include "entrypoints/quick/quick_entrypoints.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070020#include "invoke_type.h"
21#include "mirror/array.h"
22#include "mirror/string.h"
23#include "mir_to_lir-inl.h"
Brian Carlstrom7940e442013-07-12 13:46:57 -070024#include "x86/codegen_x86.h"
25
26namespace art {
27
28/*
29 * This source files contains "gen" codegen routines that should
30 * be applicable to most targets. Only mid-level support utilities
31 * and "op" calls may be used here.
32 */
33
34/*
35 * To save scheduling time, helper calls are broken into two parts: generation of
36 * the helper target address, and the actuall call to the helper. Because x86
37 * has a memory call operation, part 1 is a NOP for x86. For other targets,
38 * load arguments between the two parts.
39 */
Ian Rogers848871b2013-08-05 10:56:33 -070040int Mir2Lir::CallHelperSetup(ThreadOffset helper_offset) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070041 return (cu_->instruction_set == kX86) ? 0 : LoadHelper(helper_offset);
42}
43
44/* NOTE: if r_tgt is a temp, it will be freed following use */
Ian Rogers848871b2013-08-05 10:56:33 -070045LIR* Mir2Lir::CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070046 LIR* call_inst;
47 if (cu_->instruction_set == kX86) {
48 call_inst = OpThreadMem(kOpBlx, helper_offset);
49 } else {
50 call_inst = OpReg(kOpBlx, r_tgt);
51 FreeTemp(r_tgt);
52 }
53 if (safepoint_pc) {
54 MarkSafepointPC(call_inst);
55 }
56 return call_inst;
57}
58
Ian Rogers848871b2013-08-05 10:56:33 -070059void Mir2Lir::CallRuntimeHelperImm(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070060 int r_tgt = CallHelperSetup(helper_offset);
61 LoadConstant(TargetReg(kArg0), arg0);
62 ClobberCalleeSave();
63 CallHelper(r_tgt, helper_offset, safepoint_pc);
64}
65
Ian Rogers848871b2013-08-05 10:56:33 -070066void Mir2Lir::CallRuntimeHelperReg(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070067 int r_tgt = CallHelperSetup(helper_offset);
68 OpRegCopy(TargetReg(kArg0), arg0);
69 ClobberCalleeSave();
70 CallHelper(r_tgt, helper_offset, safepoint_pc);
71}
72
Ian Rogers848871b2013-08-05 10:56:33 -070073void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset helper_offset, RegLocation arg0,
74 bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -070075 int r_tgt = CallHelperSetup(helper_offset);
76 if (arg0.wide == 0) {
77 LoadValueDirectFixed(arg0, TargetReg(kArg0));
78 } else {
79 LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
80 }
81 ClobberCalleeSave();
82 CallHelper(r_tgt, helper_offset, safepoint_pc);
83}
84
Ian Rogers848871b2013-08-05 10:56:33 -070085void Mir2Lir::CallRuntimeHelperImmImm(ThreadOffset helper_offset, int arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -070086 bool safepoint_pc) {
87 int r_tgt = CallHelperSetup(helper_offset);
88 LoadConstant(TargetReg(kArg0), arg0);
89 LoadConstant(TargetReg(kArg1), arg1);
90 ClobberCalleeSave();
91 CallHelper(r_tgt, helper_offset, safepoint_pc);
92}
93
Ian Rogers848871b2013-08-05 10:56:33 -070094void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset helper_offset, int arg0,
Brian Carlstrom7940e442013-07-12 13:46:57 -070095 RegLocation arg1, bool safepoint_pc) {
96 int r_tgt = CallHelperSetup(helper_offset);
97 if (arg1.wide == 0) {
98 LoadValueDirectFixed(arg1, TargetReg(kArg1));
99 } else {
100 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
101 }
102 LoadConstant(TargetReg(kArg0), arg0);
103 ClobberCalleeSave();
104 CallHelper(r_tgt, helper_offset, safepoint_pc);
105}
106
Ian Rogers848871b2013-08-05 10:56:33 -0700107void Mir2Lir::CallRuntimeHelperRegLocationImm(ThreadOffset helper_offset, RegLocation arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700108 bool safepoint_pc) {
109 int r_tgt = CallHelperSetup(helper_offset);
110 LoadValueDirectFixed(arg0, TargetReg(kArg0));
111 LoadConstant(TargetReg(kArg1), arg1);
112 ClobberCalleeSave();
113 CallHelper(r_tgt, helper_offset, safepoint_pc);
114}
115
Ian Rogers848871b2013-08-05 10:56:33 -0700116void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset helper_offset, int arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700117 bool safepoint_pc) {
118 int r_tgt = CallHelperSetup(helper_offset);
119 OpRegCopy(TargetReg(kArg1), arg1);
120 LoadConstant(TargetReg(kArg0), arg0);
121 ClobberCalleeSave();
122 CallHelper(r_tgt, helper_offset, safepoint_pc);
123}
124
Ian Rogers848871b2013-08-05 10:56:33 -0700125void Mir2Lir::CallRuntimeHelperRegImm(ThreadOffset helper_offset, int arg0, int arg1,
126 bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700127 int r_tgt = CallHelperSetup(helper_offset);
128 OpRegCopy(TargetReg(kArg0), arg0);
129 LoadConstant(TargetReg(kArg1), arg1);
130 ClobberCalleeSave();
131 CallHelper(r_tgt, helper_offset, safepoint_pc);
132}
133
Ian Rogers848871b2013-08-05 10:56:33 -0700134void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700135 int r_tgt = CallHelperSetup(helper_offset);
136 LoadCurrMethodDirect(TargetReg(kArg1));
137 LoadConstant(TargetReg(kArg0), arg0);
138 ClobberCalleeSave();
139 CallHelper(r_tgt, helper_offset, safepoint_pc);
140}
141
Ian Rogers848871b2013-08-05 10:56:33 -0700142void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700143 RegLocation arg1, bool safepoint_pc) {
144 int r_tgt = CallHelperSetup(helper_offset);
145 if (arg0.wide == 0) {
146 LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
147 if (arg1.wide == 0) {
148 if (cu_->instruction_set == kMips) {
149 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
150 } else {
151 LoadValueDirectFixed(arg1, TargetReg(kArg1));
152 }
153 } else {
154 if (cu_->instruction_set == kMips) {
155 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
156 } else {
157 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
158 }
159 }
160 } else {
161 LoadValueDirectWideFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
162 if (arg1.wide == 0) {
163 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
164 } else {
165 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
166 }
167 }
168 ClobberCalleeSave();
169 CallHelper(r_tgt, helper_offset, safepoint_pc);
170}
171
Ian Rogers848871b2013-08-05 10:56:33 -0700172void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset helper_offset, int arg0, int arg1,
173 bool safepoint_pc) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700174 int r_tgt = CallHelperSetup(helper_offset);
175 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
176 OpRegCopy(TargetReg(kArg0), arg0);
177 OpRegCopy(TargetReg(kArg1), arg1);
178 ClobberCalleeSave();
179 CallHelper(r_tgt, helper_offset, safepoint_pc);
180}
181
Ian Rogers848871b2013-08-05 10:56:33 -0700182void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset helper_offset, int arg0, int arg1,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700183 int arg2, bool safepoint_pc) {
184 int r_tgt = CallHelperSetup(helper_offset);
185 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
186 OpRegCopy(TargetReg(kArg0), arg0);
187 OpRegCopy(TargetReg(kArg1), arg1);
188 LoadConstant(TargetReg(kArg2), arg2);
189 ClobberCalleeSave();
190 CallHelper(r_tgt, helper_offset, safepoint_pc);
191}
192
Ian Rogers848871b2013-08-05 10:56:33 -0700193void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset helper_offset,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700194 int arg0, RegLocation arg2, bool safepoint_pc) {
195 int r_tgt = CallHelperSetup(helper_offset);
196 LoadValueDirectFixed(arg2, TargetReg(kArg2));
197 LoadCurrMethodDirect(TargetReg(kArg1));
198 LoadConstant(TargetReg(kArg0), arg0);
199 ClobberCalleeSave();
200 CallHelper(r_tgt, helper_offset, safepoint_pc);
201}
202
Ian Rogers848871b2013-08-05 10:56:33 -0700203void Mir2Lir::CallRuntimeHelperImmMethodImm(ThreadOffset helper_offset, int arg0,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700204 int arg2, bool safepoint_pc) {
205 int r_tgt = CallHelperSetup(helper_offset);
206 LoadCurrMethodDirect(TargetReg(kArg1));
207 LoadConstant(TargetReg(kArg2), arg2);
208 LoadConstant(TargetReg(kArg0), arg0);
209 ClobberCalleeSave();
210 CallHelper(r_tgt, helper_offset, safepoint_pc);
211}
212
Ian Rogers848871b2013-08-05 10:56:33 -0700213void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset helper_offset,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700214 int arg0, RegLocation arg1,
215 RegLocation arg2, bool safepoint_pc) {
216 int r_tgt = CallHelperSetup(helper_offset);
217 LoadValueDirectFixed(arg1, TargetReg(kArg1));
218 if (arg2.wide == 0) {
219 LoadValueDirectFixed(arg2, TargetReg(kArg2));
220 } else {
221 LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
222 }
223 LoadConstant(TargetReg(kArg0), arg0);
224 ClobberCalleeSave();
225 CallHelper(r_tgt, helper_offset, safepoint_pc);
226}
227
228/*
229 * If there are any ins passed in registers that have not been promoted
230 * to a callee-save register, flush them to the frame. Perform intial
231 * assignment of promoted arguments.
232 *
233 * ArgLocs is an array of location records describing the incoming arguments
234 * with one location record per word of argument.
235 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700236void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700237 /*
238 * Dummy up a RegLocation for the incoming Method*
239 * It will attempt to keep kArg0 live (or copy it to home location
240 * if promoted).
241 */
242 RegLocation rl_src = rl_method;
243 rl_src.location = kLocPhysReg;
244 rl_src.low_reg = TargetReg(kArg0);
245 rl_src.home = false;
246 MarkLive(rl_src.low_reg, rl_src.s_reg_low);
247 StoreValue(rl_method, rl_src);
248 // If Method* has been promoted, explicitly flush
249 if (rl_method.location == kLocPhysReg) {
250 StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
251 }
252
253 if (cu_->num_ins == 0)
254 return;
255 const int num_arg_regs = 3;
256 static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
257 int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
258 /*
259 * Copy incoming arguments to their proper home locations.
260 * NOTE: an older version of dx had an issue in which
261 * it would reuse static method argument registers.
262 * This could result in the same Dalvik virtual register
263 * being promoted to both core and fp regs. To account for this,
264 * we only copy to the corresponding promoted physical register
265 * if it matches the type of the SSA name for the incoming
266 * argument. It is also possible that long and double arguments
267 * end up half-promoted. In those cases, we must flush the promoted
268 * half to memory as well.
269 */
270 for (int i = 0; i < cu_->num_ins; i++) {
271 PromotionMap* v_map = &promotion_map_[start_vreg + i];
272 if (i < num_arg_regs) {
273 // If arriving in register
274 bool need_flush = true;
275 RegLocation* t_loc = &ArgLocs[i];
276 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
277 OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
278 need_flush = false;
279 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
280 OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
281 need_flush = false;
282 } else {
283 need_flush = true;
284 }
285
286 // For wide args, force flush if only half is promoted
287 if (t_loc->wide) {
288 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
289 need_flush |= (p_map->core_location != v_map->core_location) ||
290 (p_map->fp_location != v_map->fp_location);
291 }
292 if (need_flush) {
293 StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
294 TargetReg(arg_regs[i]), kWord);
295 }
296 } else {
297 // If arriving in frame & promoted
298 if (v_map->core_location == kLocPhysReg) {
299 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
300 v_map->core_reg);
301 }
302 if (v_map->fp_location == kLocPhysReg) {
303 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
304 v_map->FpReg);
305 }
306 }
307 }
308}
309
310/*
311 * Bit of a hack here - in the absence of a real scheduling pass,
312 * emit the next instruction in static & direct invoke sequences.
313 */
314static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
315 int state, const MethodReference& target_method,
316 uint32_t unused,
317 uintptr_t direct_code, uintptr_t direct_method,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700318 InvokeType type) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700319 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
320 if (cu->instruction_set != kThumb2) {
321 // Disable sharpening
322 direct_code = 0;
323 direct_method = 0;
324 }
325 if (direct_code != 0 && direct_method != 0) {
326 switch (state) {
327 case 0: // Get the current Method* [sets kArg0]
328 if (direct_code != static_cast<unsigned int>(-1)) {
329 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
330 } else {
331 CHECK_EQ(cu->dex_file, target_method.dex_file);
332 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
333 target_method.dex_method_index, 0);
334 if (data_target == NULL) {
335 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
336 data_target->operands[1] = type;
337 }
338 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
339 cg->AppendLIR(load_pc_rel);
340 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
341 }
342 if (direct_method != static_cast<unsigned int>(-1)) {
343 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
344 } else {
345 CHECK_EQ(cu->dex_file, target_method.dex_file);
346 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
347 target_method.dex_method_index, 0);
348 if (data_target == NULL) {
349 data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
350 data_target->operands[1] = type;
351 }
352 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
353 cg->AppendLIR(load_pc_rel);
354 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
355 }
356 break;
357 default:
358 return -1;
359 }
360 } else {
361 switch (state) {
362 case 0: // Get the current Method* [sets kArg0]
363 // TUNING: we can save a reg copy if Method* has been promoted.
364 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
365 break;
366 case 1: // Get method->dex_cache_resolved_methods_
367 cg->LoadWordDisp(cg->TargetReg(kArg0),
368 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
369 // Set up direct code if known.
370 if (direct_code != 0) {
371 if (direct_code != static_cast<unsigned int>(-1)) {
372 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
373 } else {
374 CHECK_EQ(cu->dex_file, target_method.dex_file);
375 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
376 target_method.dex_method_index, 0);
377 if (data_target == NULL) {
378 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
379 data_target->operands[1] = type;
380 }
381 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
382 cg->AppendLIR(load_pc_rel);
383 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
384 }
385 }
386 break;
387 case 2: // Grab target method*
388 CHECK_EQ(cu->dex_file, target_method.dex_file);
389 cg->LoadWordDisp(cg->TargetReg(kArg0),
390 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
391 (target_method.dex_method_index * 4),
392 cg-> TargetReg(kArg0));
393 break;
394 case 3: // Grab the code from the method*
395 if (cu->instruction_set != kX86) {
396 if (direct_code == 0) {
397 cg->LoadWordDisp(cg->TargetReg(kArg0),
398 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
399 cg->TargetReg(kInvokeTgt));
400 }
401 break;
402 }
403 // Intentional fallthrough for x86
404 default:
405 return -1;
406 }
407 }
408 return state + 1;
409}
410
411/*
412 * Bit of a hack here - in the absence of a real scheduling pass,
413 * emit the next instruction in a virtual invoke sequence.
414 * We can use kLr as a temp prior to target address loading
415 * Note also that we'll load the first argument ("this") into
416 * kArg1 here rather than the standard LoadArgRegs.
417 */
418static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
419 int state, const MethodReference& target_method,
420 uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700421 InvokeType unused3) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700422 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
423 /*
424 * This is the fast path in which the target virtual method is
425 * fully resolved at compile time.
426 */
427 switch (state) {
428 case 0: { // Get "this" [set kArg1]
429 RegLocation rl_arg = info->args[0];
430 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
431 break;
432 }
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700433 case 1: // Is "this" null? [use kArg1]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700434 cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
435 // get this->klass_ [use kArg1, set kInvokeTgt]
436 cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
437 cg->TargetReg(kInvokeTgt));
438 break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700439 case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700440 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
441 cg->TargetReg(kInvokeTgt));
442 break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700443 case 3: // Get target method [use kInvokeTgt, set kArg0]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700444 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
445 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
446 cg->TargetReg(kArg0));
447 break;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700448 case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
Brian Carlstrom7940e442013-07-12 13:46:57 -0700449 if (cu->instruction_set != kX86) {
450 cg->LoadWordDisp(cg->TargetReg(kArg0),
451 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
452 cg->TargetReg(kInvokeTgt));
453 break;
454 }
455 // Intentional fallthrough for X86
456 default:
457 return -1;
458 }
459 return state + 1;
460}
461
462/*
463 * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline,
464 * which will locate the target and continue on via a tail call.
465 */
466static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
467 const MethodReference& target_method,
468 uint32_t unused, uintptr_t unused2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700469 uintptr_t direct_method, InvokeType unused4) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700470 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
471 if (cu->instruction_set != kThumb2) {
472 // Disable sharpening
473 direct_method = 0;
474 }
Ian Rogers848871b2013-08-05 10:56:33 -0700475 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700476
477 if (direct_method != 0) {
478 switch (state) {
479 case 0: // Load the trampoline target [sets kInvokeTgt].
480 if (cu->instruction_set != kX86) {
Ian Rogers848871b2013-08-05 10:56:33 -0700481 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(),
482 cg->TargetReg(kInvokeTgt));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700483 }
484 // Get the interface Method* [sets kArg0]
485 if (direct_method != static_cast<unsigned int>(-1)) {
486 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
487 } else {
488 CHECK_EQ(cu->dex_file, target_method.dex_file);
489 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
490 target_method.dex_method_index, 0);
491 if (data_target == NULL) {
492 data_target = cg->AddWordData(&cg->method_literal_list_,
493 target_method.dex_method_index);
494 data_target->operands[1] = kInterface;
495 }
496 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
497 cg->AppendLIR(load_pc_rel);
498 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
499 }
500 break;
501 default:
502 return -1;
503 }
504 } else {
505 switch (state) {
506 case 0:
507 // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted.
508 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
509 // Load the trampoline target [sets kInvokeTgt].
510 if (cu->instruction_set != kX86) {
Ian Rogers848871b2013-08-05 10:56:33 -0700511 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(),
512 cg->TargetReg(kInvokeTgt));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700513 }
514 break;
515 case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0]
516 cg->LoadWordDisp(cg->TargetReg(kArg0),
517 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
518 cg->TargetReg(kArg0));
519 break;
520 case 2: // Grab target method* [set/use kArg0]
521 CHECK_EQ(cu->dex_file, target_method.dex_file);
522 cg->LoadWordDisp(cg->TargetReg(kArg0),
523 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
524 (target_method.dex_method_index * 4),
525 cg->TargetReg(kArg0));
526 break;
527 default:
528 return -1;
529 }
530 }
531 return state + 1;
532}
533
Ian Rogers848871b2013-08-05 10:56:33 -0700534static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, ThreadOffset trampoline,
Brian Carlstrom7940e442013-07-12 13:46:57 -0700535 int state, const MethodReference& target_method,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700536 uint32_t method_idx) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700537 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
538 /*
539 * This handles the case in which the base method is not fully
540 * resolved at compile time, we bail to a runtime helper.
541 */
542 if (state == 0) {
543 if (cu->instruction_set != kX86) {
544 // Load trampoline target
Ian Rogers848871b2013-08-05 10:56:33 -0700545 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(), cg->TargetReg(kInvokeTgt));
Brian Carlstrom7940e442013-07-12 13:46:57 -0700546 }
547 // Load kArg0 with method index
548 CHECK_EQ(cu->dex_file, target_method.dex_file);
549 cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
550 return 1;
551 }
552 return -1;
553}
554
555static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
556 int state,
557 const MethodReference& target_method,
558 uint32_t method_idx,
559 uintptr_t unused, uintptr_t unused2,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700560 InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700561 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700562 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
563}
564
565static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
566 const MethodReference& target_method,
567 uint32_t method_idx, uintptr_t unused,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700568 uintptr_t unused2, InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700569 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700570 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
571}
572
573static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
574 const MethodReference& target_method,
575 uint32_t method_idx, uintptr_t unused,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700576 uintptr_t unused2, InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700577 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700578 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
579}
580
581static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
582 const MethodReference& target_method,
583 uint32_t method_idx, uintptr_t unused,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700584 uintptr_t unused2, InvokeType unused3) {
Ian Rogers848871b2013-08-05 10:56:33 -0700585 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700586 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
587}
588
589static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
590 CallInfo* info, int state,
591 const MethodReference& target_method,
592 uint32_t unused,
593 uintptr_t unused2, uintptr_t unused3,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700594 InvokeType unused4) {
Ian Rogers848871b2013-08-05 10:56:33 -0700595 ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -0700596 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
597}
598
599int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
600 NextCallInsn next_call_insn,
601 const MethodReference& target_method,
602 uint32_t vtable_idx, uintptr_t direct_code,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700603 uintptr_t direct_method, InvokeType type, bool skip_this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700604 int last_arg_reg = TargetReg(kArg3);
605 int next_reg = TargetReg(kArg1);
606 int next_arg = 0;
607 if (skip_this) {
608 next_reg++;
609 next_arg++;
610 }
611 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
612 RegLocation rl_arg = info->args[next_arg++];
613 rl_arg = UpdateRawLoc(rl_arg);
614 if (rl_arg.wide && (next_reg <= TargetReg(kArg2))) {
615 LoadValueDirectWideFixed(rl_arg, next_reg, next_reg + 1);
616 next_reg++;
617 next_arg++;
618 } else {
619 if (rl_arg.wide) {
620 rl_arg.wide = false;
621 rl_arg.is_const = false;
622 }
623 LoadValueDirectFixed(rl_arg, next_reg);
624 }
625 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
626 direct_code, direct_method, type);
627 }
628 return call_state;
629}
630
631/*
632 * Load up to 5 arguments, the first three of which will be in
633 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer,
634 * and as part of the load sequence, it must be replaced with
635 * the target method pointer. Note, this may also be called
636 * for "range" variants if the number of arguments is 5 or fewer.
637 */
638int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
639 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
640 const MethodReference& target_method,
641 uint32_t vtable_idx, uintptr_t direct_code,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700642 uintptr_t direct_method, InvokeType type, bool skip_this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700643 RegLocation rl_arg;
644
645 /* If no arguments, just return */
646 if (info->num_arg_words == 0)
647 return call_state;
648
649 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
650 direct_code, direct_method, type);
651
652 DCHECK_LE(info->num_arg_words, 5);
653 if (info->num_arg_words > 3) {
654 int32_t next_use = 3;
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700655 // Detect special case of wide arg spanning arg3/arg4
Brian Carlstrom7940e442013-07-12 13:46:57 -0700656 RegLocation rl_use0 = info->args[0];
657 RegLocation rl_use1 = info->args[1];
658 RegLocation rl_use2 = info->args[2];
659 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
660 rl_use2.wide) {
661 int reg = -1;
662 // Wide spans, we need the 2nd half of uses[2].
663 rl_arg = UpdateLocWide(rl_use2);
664 if (rl_arg.location == kLocPhysReg) {
665 reg = rl_arg.high_reg;
666 } else {
667 // kArg2 & rArg3 can safely be used here
668 reg = TargetReg(kArg3);
669 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
670 call_state = next_call_insn(cu_, info, call_state, target_method,
671 vtable_idx, direct_code, direct_method, type);
672 }
673 StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
674 StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
675 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
676 direct_code, direct_method, type);
677 next_use++;
678 }
679 // Loop through the rest
680 while (next_use < info->num_arg_words) {
681 int low_reg;
682 int high_reg = -1;
683 rl_arg = info->args[next_use];
684 rl_arg = UpdateRawLoc(rl_arg);
685 if (rl_arg.location == kLocPhysReg) {
686 low_reg = rl_arg.low_reg;
687 high_reg = rl_arg.high_reg;
688 } else {
689 low_reg = TargetReg(kArg2);
690 if (rl_arg.wide) {
691 high_reg = TargetReg(kArg3);
692 LoadValueDirectWideFixed(rl_arg, low_reg, high_reg);
693 } else {
694 LoadValueDirectFixed(rl_arg, low_reg);
695 }
696 call_state = next_call_insn(cu_, info, call_state, target_method,
697 vtable_idx, direct_code, direct_method, type);
698 }
699 int outs_offset = (next_use + 1) * 4;
700 if (rl_arg.wide) {
701 StoreBaseDispWide(TargetReg(kSp), outs_offset, low_reg, high_reg);
702 next_use += 2;
703 } else {
704 StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
705 next_use++;
706 }
707 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
708 direct_code, direct_method, type);
709 }
710 }
711
712 call_state = LoadArgRegs(info, call_state, next_call_insn,
713 target_method, vtable_idx, direct_code, direct_method,
714 type, skip_this);
715
716 if (pcrLabel) {
717 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
718 }
719 return call_state;
720}
721
722/*
723 * May have 0+ arguments (also used for jumbo). Note that
724 * source virtual registers may be in physical registers, so may
725 * need to be flushed to home location before copying. This
726 * applies to arg3 and above (see below).
727 *
728 * Two general strategies:
729 * If < 20 arguments
730 * Pass args 3-18 using vldm/vstm block copy
731 * Pass arg0, arg1 & arg2 in kArg1-kArg3
732 * If 20+ arguments
733 * Pass args arg19+ using memcpy block copy
734 * Pass arg0, arg1 & arg2 in kArg1-kArg3
735 *
736 */
737int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
738 LIR** pcrLabel, NextCallInsn next_call_insn,
739 const MethodReference& target_method,
740 uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700741 InvokeType type, bool skip_this) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700742 // If we can treat it as non-range (Jumbo ops will use range form)
743 if (info->num_arg_words <= 5)
744 return GenDalvikArgsNoRange(info, call_state, pcrLabel,
745 next_call_insn, target_method, vtable_idx,
746 direct_code, direct_method, type, skip_this);
747 /*
748 * First load the non-register arguments. Both forms expect all
749 * of the source arguments to be in their home frame location, so
750 * scan the s_reg names and flush any that have been promoted to
751 * frame backing storage.
752 */
753 // Scan the rest of the args - if in phys_reg flush to memory
754 for (int next_arg = 0; next_arg < info->num_arg_words;) {
755 RegLocation loc = info->args[next_arg];
756 if (loc.wide) {
757 loc = UpdateLocWide(loc);
758 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
759 StoreBaseDispWide(TargetReg(kSp), SRegOffset(loc.s_reg_low),
760 loc.low_reg, loc.high_reg);
761 }
762 next_arg += 2;
763 } else {
764 loc = UpdateLoc(loc);
765 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
766 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
767 loc.low_reg, kWord);
768 }
769 next_arg++;
770 }
771 }
772
773 int start_offset = SRegOffset(info->args[3].s_reg_low);
774 int outs_offset = 4 /* Method* */ + (3 * 4);
775 if (cu_->instruction_set != kThumb2) {
776 // Generate memcpy
777 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
778 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
Ian Rogers7655f292013-07-29 11:07:13 -0700779 CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700780 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
781 } else {
782 if (info->num_arg_words >= 20) {
783 // Generate memcpy
784 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
785 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
Ian Rogers7655f292013-07-29 11:07:13 -0700786 CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
Brian Carlstrom7940e442013-07-12 13:46:57 -0700787 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
788 } else {
789 // Use vldm/vstm pair using kArg3 as a temp
790 int regs_left = std::min(info->num_arg_words - 3, 16);
791 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
792 direct_code, direct_method, type);
793 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
794 LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700795 // TUNING: loosen barrier
Brian Carlstrom7940e442013-07-12 13:46:57 -0700796 ld->def_mask = ENCODE_ALL;
797 SetMemRefType(ld, true /* is_load */, kDalvikReg);
798 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
799 direct_code, direct_method, type);
800 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
801 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
802 direct_code, direct_method, type);
803 LIR* st = OpVstm(TargetReg(kArg3), regs_left);
804 SetMemRefType(st, false /* is_load */, kDalvikReg);
805 st->def_mask = ENCODE_ALL;
806 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
807 direct_code, direct_method, type);
808 }
809 }
810
811 call_state = LoadArgRegs(info, call_state, next_call_insn,
812 target_method, vtable_idx, direct_code, direct_method,
813 type, skip_this);
814
815 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
816 direct_code, direct_method, type);
817 if (pcrLabel) {
818 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
819 }
820 return call_state;
821}
822
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700823RegLocation Mir2Lir::InlineTarget(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700824 RegLocation res;
825 if (info->result.location == kLocInvalid) {
826 res = GetReturn(false);
827 } else {
828 res = info->result;
829 }
830 return res;
831}
832
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700833RegLocation Mir2Lir::InlineTargetWide(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700834 RegLocation res;
835 if (info->result.location == kLocInvalid) {
836 res = GetReturnWide(false);
837 } else {
838 res = info->result;
839 }
840 return res;
841}
842
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700843bool Mir2Lir::GenInlinedCharAt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700844 if (cu_->instruction_set == kMips) {
845 // TODO - add Mips implementation
846 return false;
847 }
848 // Location of reference to data array
849 int value_offset = mirror::String::ValueOffset().Int32Value();
850 // Location of count
851 int count_offset = mirror::String::CountOffset().Int32Value();
852 // Starting offset within data array
853 int offset_offset = mirror::String::OffsetOffset().Int32Value();
854 // Start of char data with array_
855 int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
856
857 RegLocation rl_obj = info->args[0];
858 RegLocation rl_idx = info->args[1];
859 rl_obj = LoadValue(rl_obj, kCoreReg);
860 rl_idx = LoadValue(rl_idx, kCoreReg);
861 int reg_max;
862 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
863 bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
864 LIR* launch_pad = NULL;
865 int reg_off = INVALID_REG;
866 int reg_ptr = INVALID_REG;
867 if (cu_->instruction_set != kX86) {
868 reg_off = AllocTemp();
869 reg_ptr = AllocTemp();
870 if (range_check) {
871 reg_max = AllocTemp();
872 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
873 }
874 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
875 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
876 if (range_check) {
877 // Set up a launch pad to allow retry in case of bounds violation */
878 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
879 intrinsic_launchpads_.Insert(launch_pad);
880 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
881 FreeTemp(reg_max);
882 OpCondBranch(kCondCs, launch_pad);
Brian Carlstrom6f485c62013-07-18 15:35:35 -0700883 }
Brian Carlstrom7940e442013-07-12 13:46:57 -0700884 } else {
885 if (range_check) {
886 reg_max = AllocTemp();
887 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
888 // Set up a launch pad to allow retry in case of bounds violation */
889 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
890 intrinsic_launchpads_.Insert(launch_pad);
891 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
892 FreeTemp(reg_max);
893 OpCondBranch(kCondCc, launch_pad);
894 }
895 reg_off = AllocTemp();
896 reg_ptr = AllocTemp();
897 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
898 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
899 }
900 OpRegImm(kOpAdd, reg_ptr, data_offset);
901 OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
902 FreeTemp(rl_obj.low_reg);
903 FreeTemp(rl_idx.low_reg);
904 RegLocation rl_dest = InlineTarget(info);
905 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
906 LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
907 FreeTemp(reg_off);
908 FreeTemp(reg_ptr);
909 StoreValue(rl_dest, rl_result);
910 if (range_check) {
911 launch_pad->operands[2] = 0; // no resumption
912 }
913 // Record that we've already inlined & null checked
914 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
915 return true;
916}
917
918// Generates an inlined String.is_empty or String.length.
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700919bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700920 if (cu_->instruction_set == kMips) {
921 // TODO - add Mips implementation
922 return false;
923 }
924 // dst = src.length();
925 RegLocation rl_obj = info->args[0];
926 rl_obj = LoadValue(rl_obj, kCoreReg);
927 RegLocation rl_dest = InlineTarget(info);
928 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
929 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
930 LoadWordDisp(rl_obj.low_reg, mirror::String::CountOffset().Int32Value(), rl_result.low_reg);
931 if (is_empty) {
932 // dst = (dst == 0);
933 if (cu_->instruction_set == kThumb2) {
934 int t_reg = AllocTemp();
935 OpRegReg(kOpNeg, t_reg, rl_result.low_reg);
936 OpRegRegReg(kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
937 } else {
938 DCHECK_EQ(cu_->instruction_set, kX86);
939 OpRegImm(kOpSub, rl_result.low_reg, 1);
940 OpRegImm(kOpLsr, rl_result.low_reg, 31);
941 }
942 }
943 StoreValue(rl_dest, rl_result);
944 return true;
945}
946
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700947bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700948 if (cu_->instruction_set == kMips) {
949 // TODO - add Mips implementation
950 return false;
951 }
952 RegLocation rl_src = info->args[0];
953 rl_src = LoadValue(rl_src, kCoreReg);
954 RegLocation rl_dest = InlineTarget(info);
955 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
956 int sign_reg = AllocTemp();
957 // abs(x) = y<=x>>31, (x+y)^y.
958 OpRegRegImm(kOpAsr, sign_reg, rl_src.low_reg, 31);
959 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
960 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
961 StoreValue(rl_dest, rl_result);
962 return true;
963}
964
Brian Carlstrom2ce745c2013-07-17 17:44:30 -0700965bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -0700966 if (cu_->instruction_set == kMips) {
967 // TODO - add Mips implementation
968 return false;
969 }
970 if (cu_->instruction_set == kThumb2) {
971 RegLocation rl_src = info->args[0];
972 rl_src = LoadValueWide(rl_src, kCoreReg);
973 RegLocation rl_dest = InlineTargetWide(info);
974 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
975 int sign_reg = AllocTemp();
976 // abs(x) = y<=x>>31, (x+y)^y.
977 OpRegRegImm(kOpAsr, sign_reg, rl_src.high_reg, 31);
978 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
979 OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
980 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
981 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
982 StoreValueWide(rl_dest, rl_result);
983 return true;
984 } else {
985 DCHECK_EQ(cu_->instruction_set, kX86);
986 // Reuse source registers to avoid running out of temps
987 RegLocation rl_src = info->args[0];
988 rl_src = LoadValueWide(rl_src, kCoreReg);
989 RegLocation rl_dest = InlineTargetWide(info);
990 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
991 OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
992 FreeTemp(rl_src.low_reg);
993 FreeTemp(rl_src.high_reg);
994 int sign_reg = AllocTemp();
995 // abs(x) = y<=x>>31, (x+y)^y.
996 OpRegRegImm(kOpAsr, sign_reg, rl_result.high_reg, 31);
997 OpRegReg(kOpAdd, rl_result.low_reg, sign_reg);
998 OpRegReg(kOpAdc, rl_result.high_reg, sign_reg);
999 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1000 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1001 StoreValueWide(rl_dest, rl_result);
1002 return true;
1003 }
1004}
1005
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001006bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001007 if (cu_->instruction_set == kMips) {
1008 // TODO - add Mips implementation
1009 return false;
1010 }
1011 RegLocation rl_src = info->args[0];
1012 RegLocation rl_dest = InlineTarget(info);
1013 StoreValue(rl_dest, rl_src);
1014 return true;
1015}
1016
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001017bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001018 if (cu_->instruction_set == kMips) {
1019 // TODO - add Mips implementation
1020 return false;
1021 }
1022 RegLocation rl_src = info->args[0];
1023 RegLocation rl_dest = InlineTargetWide(info);
1024 StoreValueWide(rl_dest, rl_src);
1025 return true;
1026}
1027
1028/*
1029 * Fast string.index_of(I) & (II). Tests for simple case of char <= 0xffff,
1030 * otherwise bails to standard library code.
1031 */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001032bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001033 if (cu_->instruction_set == kMips) {
1034 // TODO - add Mips implementation
1035 return false;
1036 }
1037 ClobberCalleeSave();
1038 LockCallTemps(); // Using fixed registers
1039 int reg_ptr = TargetReg(kArg0);
1040 int reg_char = TargetReg(kArg1);
1041 int reg_start = TargetReg(kArg2);
1042
1043 RegLocation rl_obj = info->args[0];
1044 RegLocation rl_char = info->args[1];
1045 RegLocation rl_start = info->args[2];
1046 LoadValueDirectFixed(rl_obj, reg_ptr);
1047 LoadValueDirectFixed(rl_char, reg_char);
1048 if (zero_based) {
1049 LoadConstant(reg_start, 0);
1050 } else {
1051 LoadValueDirectFixed(rl_start, reg_start);
1052 }
Ian Rogers7655f292013-07-29 11:07:13 -07001053 int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(QUICK_ENTRYPOINT_OFFSET(pIndexOf)) : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001054 GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
1055 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
1056 intrinsic_launchpads_.Insert(launch_pad);
1057 OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
1058 // NOTE: not a safepoint
1059 if (cu_->instruction_set != kX86) {
1060 OpReg(kOpBlx, r_tgt);
1061 } else {
Ian Rogers7655f292013-07-29 11:07:13 -07001062 OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pIndexOf));
Brian Carlstrom7940e442013-07-12 13:46:57 -07001063 }
1064 LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
1065 launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt);
1066 // Record that we've already inlined & null checked
1067 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1068 RegLocation rl_return = GetReturn(false);
1069 RegLocation rl_dest = InlineTarget(info);
1070 StoreValue(rl_dest, rl_return);
1071 return true;
1072}
1073
1074/* Fast string.compareTo(Ljava/lang/string;)I. */
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001075bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001076 if (cu_->instruction_set == kMips) {
1077 // TODO - add Mips implementation
1078 return false;
1079 }
1080 ClobberCalleeSave();
1081 LockCallTemps(); // Using fixed registers
1082 int reg_this = TargetReg(kArg0);
1083 int reg_cmp = TargetReg(kArg1);
1084
1085 RegLocation rl_this = info->args[0];
1086 RegLocation rl_cmp = info->args[1];
1087 LoadValueDirectFixed(rl_this, reg_this);
1088 LoadValueDirectFixed(rl_cmp, reg_cmp);
1089 int r_tgt = (cu_->instruction_set != kX86) ?
Ian Rogers7655f292013-07-29 11:07:13 -07001090 LoadHelper(QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
Brian Carlstrom7940e442013-07-12 13:46:57 -07001091 GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
Brian Carlstrom7934ac22013-07-26 10:54:15 -07001092 // TUNING: check if rl_cmp.s_reg_low is already null checked
Brian Carlstrom7940e442013-07-12 13:46:57 -07001093 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
1094 intrinsic_launchpads_.Insert(launch_pad);
1095 OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
1096 // NOTE: not a safepoint
1097 if (cu_->instruction_set != kX86) {
1098 OpReg(kOpBlx, r_tgt);
1099 } else {
Ian Rogers7655f292013-07-29 11:07:13 -07001100 OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pStringCompareTo));
Brian Carlstrom7940e442013-07-12 13:46:57 -07001101 }
1102 launch_pad->operands[2] = 0; // No return possible
1103 // Record that we've already inlined & null checked
1104 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1105 RegLocation rl_return = GetReturn(false);
1106 RegLocation rl_dest = InlineTarget(info);
1107 StoreValue(rl_dest, rl_return);
1108 return true;
1109}
1110
1111bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1112 RegLocation rl_dest = InlineTarget(info);
1113 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Ian Rogers848871b2013-08-05 10:56:33 -07001114 ThreadOffset offset = Thread::PeerOffset();
Brian Carlstrom7940e442013-07-12 13:46:57 -07001115 if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
Ian Rogers848871b2013-08-05 10:56:33 -07001116 LoadWordDisp(TargetReg(kSelf), offset.Int32Value(), rl_result.low_reg);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001117 } else {
1118 CHECK(cu_->instruction_set == kX86);
Brian Carlstrom2d888622013-07-18 17:02:00 -07001119 reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.low_reg, offset);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001120 }
1121 StoreValue(rl_dest, rl_result);
1122 return true;
1123}
1124
1125bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
1126 bool is_long, bool is_volatile) {
1127 if (cu_->instruction_set == kMips) {
1128 // TODO - add Mips implementation
1129 return false;
1130 }
1131 // Unused - RegLocation rl_src_unsafe = info->args[0];
1132 RegLocation rl_src_obj = info->args[1]; // Object
1133 RegLocation rl_src_offset = info->args[2]; // long low
1134 rl_src_offset.wide = 0; // ignore high half in info->args[3]
1135 RegLocation rl_dest = InlineTarget(info); // result reg
1136 if (is_volatile) {
1137 GenMemBarrier(kLoadLoad);
1138 }
1139 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1140 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1141 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1142 if (is_long) {
1143 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1144 LoadBaseDispWide(rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
1145 StoreValueWide(rl_dest, rl_result);
1146 } else {
1147 LoadBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
1148 StoreValue(rl_dest, rl_result);
1149 }
1150 return true;
1151}
1152
1153bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
1154 bool is_object, bool is_volatile, bool is_ordered) {
1155 if (cu_->instruction_set == kMips) {
1156 // TODO - add Mips implementation
1157 return false;
1158 }
1159 if (cu_->instruction_set == kX86 && is_object) {
1160 // TODO: fix X86, it exhausts registers for card marking.
1161 return false;
1162 }
1163 // Unused - RegLocation rl_src_unsafe = info->args[0];
1164 RegLocation rl_src_obj = info->args[1]; // Object
1165 RegLocation rl_src_offset = info->args[2]; // long low
1166 rl_src_offset.wide = 0; // ignore high half in info->args[3]
1167 RegLocation rl_src_value = info->args[4]; // value to store
1168 if (is_volatile || is_ordered) {
1169 GenMemBarrier(kStoreStore);
1170 }
1171 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1172 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1173 RegLocation rl_value;
1174 if (is_long) {
1175 rl_value = LoadValueWide(rl_src_value, kCoreReg);
1176 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1177 StoreBaseDispWide(rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
1178 } else {
1179 rl_value = LoadValue(rl_src_value, kCoreReg);
1180 StoreBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
1181 }
1182 if (is_volatile) {
1183 GenMemBarrier(kStoreLoad);
1184 }
1185 if (is_object) {
1186 MarkGCCard(rl_value.low_reg, rl_object.low_reg);
1187 }
1188 return true;
1189}
1190
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001191bool Mir2Lir::GenIntrinsic(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001192 if (info->opt_flags & MIR_INLINED) {
1193 return false;
1194 }
1195 /*
1196 * TODO: move these to a target-specific structured constant array
1197 * and use a generic match function. The list of intrinsics may be
1198 * slightly different depending on target.
1199 * TODO: Fold this into a matching function that runs during
1200 * basic block building. This should be part of the action for
1201 * small method inlining and recognition of the special object init
1202 * method. By doing this during basic block construction, we can also
1203 * take advantage of/generate new useful dataflow info.
1204 */
1205 StringPiece tgt_methods_declaring_class(
1206 cu_->dex_file->GetMethodDeclaringClassDescriptor(cu_->dex_file->GetMethodId(info->index)));
1207 if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) {
1208 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
1209 if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
1210 return GenInlinedDoubleCvt(info);
1211 }
1212 if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
1213 return GenInlinedDoubleCvt(info);
1214 }
1215 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Float;")) {
1216 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
1217 if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
1218 return GenInlinedFloatCvt(info);
1219 }
1220 if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
1221 return GenInlinedFloatCvt(info);
1222 }
1223 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Math;") ||
1224 tgt_methods_declaring_class.starts_with("Ljava/lang/StrictMath;")) {
1225 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
1226 if (tgt_method == "int java.lang.Math.abs(int)" ||
1227 tgt_method == "int java.lang.StrictMath.abs(int)") {
1228 return GenInlinedAbsInt(info);
1229 }
1230 if (tgt_method == "long java.lang.Math.abs(long)" ||
1231 tgt_method == "long java.lang.StrictMath.abs(long)") {
1232 return GenInlinedAbsLong(info);
1233 }
1234 if (tgt_method == "int java.lang.Math.max(int, int)" ||
1235 tgt_method == "int java.lang.StrictMath.max(int, int)") {
1236 return GenInlinedMinMaxInt(info, false /* is_min */);
1237 }
1238 if (tgt_method == "int java.lang.Math.min(int, int)" ||
1239 tgt_method == "int java.lang.StrictMath.min(int, int)") {
1240 return GenInlinedMinMaxInt(info, true /* is_min */);
1241 }
1242 if (tgt_method == "double java.lang.Math.sqrt(double)" ||
1243 tgt_method == "double java.lang.StrictMath.sqrt(double)") {
1244 return GenInlinedSqrt(info);
1245 }
1246 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/String;")) {
1247 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
1248 if (tgt_method == "char java.lang.String.charAt(int)") {
1249 return GenInlinedCharAt(info);
1250 }
1251 if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
1252 return GenInlinedStringCompareTo(info);
1253 }
1254 if (tgt_method == "boolean java.lang.String.is_empty()") {
1255 return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
1256 }
1257 if (tgt_method == "int java.lang.String.index_of(int, int)") {
1258 return GenInlinedIndexOf(info, false /* base 0 */);
1259 }
1260 if (tgt_method == "int java.lang.String.index_of(int)") {
1261 return GenInlinedIndexOf(info, true /* base 0 */);
1262 }
1263 if (tgt_method == "int java.lang.String.length()") {
1264 return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
1265 }
1266 } else if (tgt_methods_declaring_class.starts_with("Ljava/lang/Thread;")) {
1267 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
1268 if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
1269 return GenInlinedCurrentThread(info);
1270 }
1271 } else if (tgt_methods_declaring_class.starts_with("Lsun/misc/Unsafe;")) {
1272 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
1273 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
1274 return GenInlinedCas32(info, false);
1275 }
1276 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
1277 return GenInlinedCas32(info, true);
1278 }
1279 if (tgt_method == "int sun.misc.Unsafe.getInt(java.lang.Object, long)") {
1280 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
1281 }
1282 if (tgt_method == "int sun.misc.Unsafe.getIntVolatile(java.lang.Object, long)") {
1283 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
1284 }
1285 if (tgt_method == "void sun.misc.Unsafe.putInt(java.lang.Object, long, int)") {
1286 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
1287 false /* is_volatile */, false /* is_ordered */);
1288 }
1289 if (tgt_method == "void sun.misc.Unsafe.putIntVolatile(java.lang.Object, long, int)") {
1290 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
1291 true /* is_volatile */, false /* is_ordered */);
1292 }
1293 if (tgt_method == "void sun.misc.Unsafe.putOrderedInt(java.lang.Object, long, int)") {
1294 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
1295 false /* is_volatile */, true /* is_ordered */);
1296 }
1297 if (tgt_method == "long sun.misc.Unsafe.getLong(java.lang.Object, long)") {
1298 return GenInlinedUnsafeGet(info, true /* is_long */, false /* is_volatile */);
1299 }
1300 if (tgt_method == "long sun.misc.Unsafe.getLongVolatile(java.lang.Object, long)") {
1301 return GenInlinedUnsafeGet(info, true /* is_long */, true /* is_volatile */);
1302 }
1303 if (tgt_method == "void sun.misc.Unsafe.putLong(java.lang.Object, long, long)") {
1304 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
1305 false /* is_volatile */, false /* is_ordered */);
1306 }
1307 if (tgt_method == "void sun.misc.Unsafe.putLongVolatile(java.lang.Object, long, long)") {
1308 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
1309 true /* is_volatile */, false /* is_ordered */);
1310 }
1311 if (tgt_method == "void sun.misc.Unsafe.putOrderedLong(java.lang.Object, long, long)") {
1312 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
1313 false /* is_volatile */, true /* is_ordered */);
1314 }
1315 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObject(java.lang.Object, long)") {
1316 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
1317 }
1318 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") {
1319 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
1320 }
1321 if (tgt_method == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
1322 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
1323 false /* is_volatile */, false /* is_ordered */);
1324 }
1325 if (tgt_method == "void sun.misc.Unsafe.putObjectVolatile(java.lang.Object, long, java.lang.Object)") {
1326 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
1327 true /* is_volatile */, false /* is_ordered */);
1328 }
1329 if (tgt_method == "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") {
1330 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
1331 false /* is_volatile */, true /* is_ordered */);
1332 }
1333 }
1334 return false;
1335}
1336
Brian Carlstrom2ce745c2013-07-17 17:44:30 -07001337void Mir2Lir::GenInvoke(CallInfo* info) {
Brian Carlstrom7940e442013-07-12 13:46:57 -07001338 if (GenIntrinsic(info)) {
1339 return;
1340 }
1341 InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
1342 int call_state = 0;
1343 LIR* null_ck;
1344 LIR** p_null_ck = NULL;
1345 NextCallInsn next_call_insn;
1346 FlushAllRegs(); /* Everything to home location */
1347 // Explicit register usage
1348 LockCallTemps();
1349
1350 DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
1351 MethodReference target_method(cUnit->GetDexFile(), info->index);
1352 int vtable_idx;
1353 uintptr_t direct_code;
1354 uintptr_t direct_method;
1355 bool skip_this;
1356 bool fast_path =
1357 cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
1358 current_dalvik_offset_,
1359 info->type, target_method,
1360 vtable_idx,
1361 direct_code, direct_method,
1362 true) && !SLOW_INVOKE_PATH;
1363 if (info->type == kInterface) {
1364 if (fast_path) {
1365 p_null_ck = &null_ck;
1366 }
1367 next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
1368 skip_this = false;
1369 } else if (info->type == kDirect) {
1370 if (fast_path) {
1371 p_null_ck = &null_ck;
1372 }
1373 next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1374 skip_this = false;
1375 } else if (info->type == kStatic) {
1376 next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1377 skip_this = false;
1378 } else if (info->type == kSuper) {
1379 DCHECK(!fast_path); // Fast path is a direct call.
1380 next_call_insn = NextSuperCallInsnSP;
1381 skip_this = false;
1382 } else {
1383 DCHECK_EQ(info->type, kVirtual);
1384 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1385 skip_this = fast_path;
1386 }
1387 if (!info->is_range) {
1388 call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
1389 next_call_insn, target_method,
1390 vtable_idx, direct_code, direct_method,
1391 original_type, skip_this);
1392 } else {
1393 call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
1394 next_call_insn, target_method, vtable_idx,
1395 direct_code, direct_method, original_type,
1396 skip_this);
1397 }
1398 // Finish up any of the call sequence not interleaved in arg loading
1399 while (call_state >= 0) {
1400 call_state = next_call_insn(cu_, info, call_state, target_method,
1401 vtable_idx, direct_code, direct_method,
1402 original_type);
1403 }
1404 LIR* call_inst;
1405 if (cu_->instruction_set != kX86) {
1406 call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
1407 } else {
1408 if (fast_path && info->type != kInterface) {
1409 call_inst = OpMem(kOpBlx, TargetReg(kArg0),
1410 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value());
1411 } else {
Ian Rogers848871b2013-08-05 10:56:33 -07001412 ThreadOffset trampoline(-1);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001413 switch (info->type) {
1414 case kInterface:
Ian Rogers7655f292013-07-29 11:07:13 -07001415 trampoline = fast_path ? QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
1416 : QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001417 break;
1418 case kDirect:
Ian Rogers7655f292013-07-29 11:07:13 -07001419 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001420 break;
1421 case kStatic:
Ian Rogers7655f292013-07-29 11:07:13 -07001422 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001423 break;
1424 case kSuper:
Ian Rogers7655f292013-07-29 11:07:13 -07001425 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001426 break;
1427 case kVirtual:
Ian Rogers7655f292013-07-29 11:07:13 -07001428 trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
Brian Carlstrom7940e442013-07-12 13:46:57 -07001429 break;
1430 default:
1431 LOG(FATAL) << "Unexpected invoke type";
1432 }
1433 call_inst = OpThreadMem(kOpBlx, trampoline);
1434 }
1435 }
1436 MarkSafepointPC(call_inst);
1437
1438 ClobberCalleeSave();
1439 if (info->result.location != kLocInvalid) {
1440 // We have a following MOVE_RESULT - do it now.
1441 if (info->result.wide) {
1442 RegLocation ret_loc = GetReturnWide(info->result.fp);
1443 StoreValueWide(info->result, ret_loc);
1444 } else {
1445 RegLocation ret_loc = GetReturn(info->result.fp);
1446 StoreValue(info->result, ret_loc);
1447 }
1448 }
1449}
1450
1451} // namespace art