gen_invoke.cc revision bb8f0ab736b61db8f543e433859272e83f96ee9b
1/*
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/frontend.h"
19#include "dex/quick/dex_file_method_inliner.h"
20#include "dex/quick/dex_file_to_method_inliner_map.h"
21#include "dex_file-inl.h"
22#include "entrypoints/quick/quick_entrypoints.h"
23#include "invoke_type.h"
24#include "mirror/array.h"
25#include "mirror/string.h"
26#include "mir_to_lir-inl.h"
27#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 */
43int Mir2Lir::CallHelperSetup(ThreadOffset helper_offset) {
44  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 */
48LIR* Mir2Lir::CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_pc) {
49  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
62void Mir2Lir::CallRuntimeHelperImm(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
63  int r_tgt = CallHelperSetup(helper_offset);
64  LoadConstant(TargetReg(kArg0), arg0);
65  ClobberCallerSave();
66  CallHelper(r_tgt, helper_offset, safepoint_pc);
67}
68
69void Mir2Lir::CallRuntimeHelperReg(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
70  int r_tgt = CallHelperSetup(helper_offset);
71  OpRegCopy(TargetReg(kArg0), arg0);
72  ClobberCallerSave();
73  CallHelper(r_tgt, helper_offset, safepoint_pc);
74}
75
76void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset helper_offset, RegLocation arg0,
77                                           bool safepoint_pc) {
78  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  }
84  ClobberCallerSave();
85  CallHelper(r_tgt, helper_offset, safepoint_pc);
86}
87
88void Mir2Lir::CallRuntimeHelperImmImm(ThreadOffset helper_offset, int arg0, int arg1,
89                                      bool safepoint_pc) {
90  int r_tgt = CallHelperSetup(helper_offset);
91  LoadConstant(TargetReg(kArg0), arg0);
92  LoadConstant(TargetReg(kArg1), arg1);
93  ClobberCallerSave();
94  CallHelper(r_tgt, helper_offset, safepoint_pc);
95}
96
97void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset helper_offset, int arg0,
98                                              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);
106  ClobberCallerSave();
107  CallHelper(r_tgt, helper_offset, safepoint_pc);
108}
109
110void Mir2Lir::CallRuntimeHelperRegLocationImm(ThreadOffset helper_offset, RegLocation arg0, int arg1,
111                                              bool safepoint_pc) {
112  int r_tgt = CallHelperSetup(helper_offset);
113  LoadValueDirectFixed(arg0, TargetReg(kArg0));
114  LoadConstant(TargetReg(kArg1), arg1);
115  ClobberCallerSave();
116  CallHelper(r_tgt, helper_offset, safepoint_pc);
117}
118
119void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset helper_offset, int arg0, int arg1,
120                                      bool safepoint_pc) {
121  int r_tgt = CallHelperSetup(helper_offset);
122  OpRegCopy(TargetReg(kArg1), arg1);
123  LoadConstant(TargetReg(kArg0), arg0);
124  ClobberCallerSave();
125  CallHelper(r_tgt, helper_offset, safepoint_pc);
126}
127
128void Mir2Lir::CallRuntimeHelperRegImm(ThreadOffset helper_offset, int arg0, int arg1,
129                                      bool safepoint_pc) {
130  int r_tgt = CallHelperSetup(helper_offset);
131  OpRegCopy(TargetReg(kArg0), arg0);
132  LoadConstant(TargetReg(kArg1), arg1);
133  ClobberCallerSave();
134  CallHelper(r_tgt, helper_offset, safepoint_pc);
135}
136
137void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
138  int r_tgt = CallHelperSetup(helper_offset);
139  LoadCurrMethodDirect(TargetReg(kArg1));
140  LoadConstant(TargetReg(kArg0), arg0);
141  ClobberCallerSave();
142  CallHelper(r_tgt, helper_offset, safepoint_pc);
143}
144
145void 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
156void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(ThreadOffset helper_offset, int arg0,
157                                                    RegLocation arg2, bool safepoint_pc) {
158  int r_tgt = CallHelperSetup(helper_offset);
159  DCHECK_NE(TargetReg(kArg1), arg0);
160  if (TargetReg(kArg0) != arg0) {
161    OpRegCopy(TargetReg(kArg0), arg0);
162  }
163  LoadCurrMethodDirect(TargetReg(kArg1));
164  LoadValueDirectFixed(arg2, TargetReg(kArg2));
165  ClobberCallerSave();
166  CallHelper(r_tgt, helper_offset, safepoint_pc);
167}
168
169void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset, RegLocation arg0,
170                                                      RegLocation arg1, bool safepoint_pc) {
171  int r_tgt = CallHelperSetup(helper_offset);
172  if (arg0.wide == 0) {
173    LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
174    if (arg1.wide == 0) {
175      if (cu_->instruction_set == kMips) {
176        LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
177      } else {
178        LoadValueDirectFixed(arg1, TargetReg(kArg1));
179      }
180    } else {
181      if (cu_->instruction_set == kMips) {
182        LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
183      } else {
184        LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
185      }
186    }
187  } else {
188    LoadValueDirectWideFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
189    if (arg1.wide == 0) {
190      LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
191    } else {
192      LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
193    }
194  }
195  ClobberCallerSave();
196  CallHelper(r_tgt, helper_offset, safepoint_pc);
197}
198
199void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset helper_offset, int arg0, int arg1,
200                                      bool safepoint_pc) {
201  int r_tgt = CallHelperSetup(helper_offset);
202  DCHECK_NE(TargetReg(kArg0), arg1);  // check copy into arg0 won't clobber arg1
203  OpRegCopy(TargetReg(kArg0), arg0);
204  OpRegCopy(TargetReg(kArg1), arg1);
205  ClobberCallerSave();
206  CallHelper(r_tgt, helper_offset, safepoint_pc);
207}
208
209void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset helper_offset, int arg0, int arg1,
210                                         int arg2, bool safepoint_pc) {
211  int r_tgt = CallHelperSetup(helper_offset);
212  DCHECK_NE(TargetReg(kArg0), arg1);  // check copy into arg0 won't clobber arg1
213  OpRegCopy(TargetReg(kArg0), arg0);
214  OpRegCopy(TargetReg(kArg1), arg1);
215  LoadConstant(TargetReg(kArg2), arg2);
216  ClobberCallerSave();
217  CallHelper(r_tgt, helper_offset, safepoint_pc);
218}
219
220void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset helper_offset,
221                                                    int arg0, RegLocation arg2, bool safepoint_pc) {
222  int r_tgt = CallHelperSetup(helper_offset);
223  LoadValueDirectFixed(arg2, TargetReg(kArg2));
224  LoadCurrMethodDirect(TargetReg(kArg1));
225  LoadConstant(TargetReg(kArg0), arg0);
226  ClobberCallerSave();
227  CallHelper(r_tgt, helper_offset, safepoint_pc);
228}
229
230void Mir2Lir::CallRuntimeHelperImmMethodImm(ThreadOffset helper_offset, int arg0,
231                                            int arg2, bool safepoint_pc) {
232  int r_tgt = CallHelperSetup(helper_offset);
233  LoadCurrMethodDirect(TargetReg(kArg1));
234  LoadConstant(TargetReg(kArg2), arg2);
235  LoadConstant(TargetReg(kArg0), arg0);
236  ClobberCallerSave();
237  CallHelper(r_tgt, helper_offset, safepoint_pc);
238}
239
240void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset helper_offset,
241                                                         int arg0, RegLocation arg1,
242                                                         RegLocation arg2, bool safepoint_pc) {
243  int r_tgt = CallHelperSetup(helper_offset);
244  DCHECK_EQ(arg1.wide, 0U);
245  LoadValueDirectFixed(arg1, TargetReg(kArg1));
246  if (arg2.wide == 0) {
247    LoadValueDirectFixed(arg2, TargetReg(kArg2));
248  } else {
249    LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
250  }
251  LoadConstant(TargetReg(kArg0), arg0);
252  ClobberCallerSave();
253  CallHelper(r_tgt, helper_offset, safepoint_pc);
254}
255
256void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset helper_offset,
257                                                                 RegLocation arg0, RegLocation arg1,
258                                                                 RegLocation arg2,
259                                                                 bool safepoint_pc) {
260  int r_tgt = CallHelperSetup(helper_offset);
261  DCHECK_EQ(arg0.wide, 0U);
262  LoadValueDirectFixed(arg0, TargetReg(kArg0));
263  DCHECK_EQ(arg1.wide, 0U);
264  LoadValueDirectFixed(arg1, TargetReg(kArg1));
265  DCHECK_EQ(arg1.wide, 0U);
266  LoadValueDirectFixed(arg2, TargetReg(kArg2));
267  ClobberCallerSave();
268  CallHelper(r_tgt, helper_offset, safepoint_pc);
269}
270
271/*
272 * If there are any ins passed in registers that have not been promoted
273 * to a callee-save register, flush them to the frame.  Perform intial
274 * assignment of promoted arguments.
275 *
276 * ArgLocs is an array of location records describing the incoming arguments
277 * with one location record per word of argument.
278 */
279void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
280  /*
281   * Dummy up a RegLocation for the incoming Method*
282   * It will attempt to keep kArg0 live (or copy it to home location
283   * if promoted).
284   */
285  RegLocation rl_src = rl_method;
286  rl_src.location = kLocPhysReg;
287  rl_src.low_reg = TargetReg(kArg0);
288  rl_src.home = false;
289  MarkLive(rl_src.low_reg, rl_src.s_reg_low);
290  StoreValue(rl_method, rl_src);
291  // If Method* has been promoted, explicitly flush
292  if (rl_method.location == kLocPhysReg) {
293    StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
294  }
295
296  if (cu_->num_ins == 0)
297    return;
298  const int num_arg_regs = 3;
299  static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
300  int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
301  /*
302   * Copy incoming arguments to their proper home locations.
303   * NOTE: an older version of dx had an issue in which
304   * it would reuse static method argument registers.
305   * This could result in the same Dalvik virtual register
306   * being promoted to both core and fp regs. To account for this,
307   * we only copy to the corresponding promoted physical register
308   * if it matches the type of the SSA name for the incoming
309   * argument.  It is also possible that long and double arguments
310   * end up half-promoted.  In those cases, we must flush the promoted
311   * half to memory as well.
312   */
313  for (int i = 0; i < cu_->num_ins; i++) {
314    PromotionMap* v_map = &promotion_map_[start_vreg + i];
315    if (i < num_arg_regs) {
316      // If arriving in register
317      bool need_flush = true;
318      RegLocation* t_loc = &ArgLocs[i];
319      if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
320        OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
321        need_flush = false;
322      } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
323        OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
324        need_flush = false;
325      } else {
326        need_flush = true;
327      }
328
329      // For wide args, force flush if not fully promoted
330      if (t_loc->wide) {
331        PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
332        // Is only half promoted?
333        need_flush |= (p_map->core_location != v_map->core_location) ||
334            (p_map->fp_location != v_map->fp_location);
335        if ((cu_->instruction_set == kThumb2) && t_loc->fp && !need_flush) {
336          /*
337           * In Arm, a double is represented as a pair of consecutive single float
338           * registers starting at an even number.  It's possible that both Dalvik vRegs
339           * representing the incoming double were independently promoted as singles - but
340           * not in a form usable as a double.  If so, we need to flush - even though the
341           * incoming arg appears fully in register.  At this point in the code, both
342           * halves of the double are promoted.  Make sure they are in a usable form.
343           */
344          int lowreg_index = start_vreg + i + (t_loc->high_word ? -1 : 0);
345          int low_reg = promotion_map_[lowreg_index].FpReg;
346          int high_reg = promotion_map_[lowreg_index + 1].FpReg;
347          if (((low_reg & 0x1) != 0) || (high_reg != (low_reg + 1))) {
348            need_flush = true;
349          }
350        }
351      }
352      if (need_flush) {
353        StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
354                      TargetReg(arg_regs[i]), kWord);
355      }
356    } else {
357      // If arriving in frame & promoted
358      if (v_map->core_location == kLocPhysReg) {
359        LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
360                     v_map->core_reg);
361      }
362      if (v_map->fp_location == kLocPhysReg) {
363        LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
364                     v_map->FpReg);
365      }
366    }
367  }
368}
369
370/*
371 * Bit of a hack here - in the absence of a real scheduling pass,
372 * emit the next instruction in static & direct invoke sequences.
373 */
374static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
375                          int state, const MethodReference& target_method,
376                          uint32_t unused,
377                          uintptr_t direct_code, uintptr_t direct_method,
378                          InvokeType type) {
379  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
380  if (direct_code != 0 && direct_method != 0) {
381    switch (state) {
382    case 0:  // Get the current Method* [sets kArg0]
383      if (direct_code != static_cast<unsigned int>(-1)) {
384        if (cu->instruction_set != kX86) {
385          cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
386        }
387      } else {
388        CHECK_EQ(cu->dex_file, target_method.dex_file);
389        LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
390                                               target_method.dex_method_index, 0);
391        if (data_target == NULL) {
392          data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
393          data_target->operands[1] = type;
394        }
395        LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
396        cg->AppendLIR(load_pc_rel);
397        DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
398      }
399      if (direct_method != static_cast<unsigned int>(-1)) {
400        cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
401      } else {
402        CHECK_EQ(cu->dex_file, target_method.dex_file);
403        LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
404                                               target_method.dex_method_index, 0);
405        if (data_target == NULL) {
406          data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
407          data_target->operands[1] = type;
408        }
409        LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
410        cg->AppendLIR(load_pc_rel);
411        DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
412      }
413      break;
414    default:
415      return -1;
416    }
417  } else {
418    switch (state) {
419    case 0:  // Get the current Method* [sets kArg0]
420      // TUNING: we can save a reg copy if Method* has been promoted.
421      cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
422      break;
423    case 1:  // Get method->dex_cache_resolved_methods_
424      cg->LoadWordDisp(cg->TargetReg(kArg0),
425        mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
426      // Set up direct code if known.
427      if (direct_code != 0) {
428        if (direct_code != static_cast<unsigned int>(-1)) {
429          cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
430        } else {
431          CHECK_EQ(cu->dex_file, target_method.dex_file);
432          CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
433          LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
434                                                 target_method.dex_method_index, 0);
435          if (data_target == NULL) {
436            data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
437            data_target->operands[1] = type;
438          }
439          LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
440          cg->AppendLIR(load_pc_rel);
441          DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
442        }
443      }
444      break;
445    case 2:  // Grab target method*
446      CHECK_EQ(cu->dex_file, target_method.dex_file);
447      cg->LoadWordDisp(cg->TargetReg(kArg0),
448                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
449                           (target_method.dex_method_index * 4),
450                       cg-> TargetReg(kArg0));
451      break;
452    case 3:  // Grab the code from the method*
453      if (cu->instruction_set != kX86) {
454        if (direct_code == 0) {
455          cg->LoadWordDisp(cg->TargetReg(kArg0),
456                           mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
457                           cg->TargetReg(kInvokeTgt));
458        }
459        break;
460      }
461      // Intentional fallthrough for x86
462    default:
463      return -1;
464    }
465  }
466  return state + 1;
467}
468
469/*
470 * Bit of a hack here - in the absence of a real scheduling pass,
471 * emit the next instruction in a virtual invoke sequence.
472 * We can use kLr as a temp prior to target address loading
473 * Note also that we'll load the first argument ("this") into
474 * kArg1 here rather than the standard LoadArgRegs.
475 */
476static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
477                         int state, const MethodReference& target_method,
478                         uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
479                         InvokeType unused3) {
480  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
481  /*
482   * This is the fast path in which the target virtual method is
483   * fully resolved at compile time.
484   */
485  switch (state) {
486    case 0: {  // Get "this" [set kArg1]
487      RegLocation  rl_arg = info->args[0];
488      cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
489      break;
490    }
491    case 1:  // Is "this" null? [use kArg1]
492      cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
493      // get this->klass_ [use kArg1, set kInvokeTgt]
494      cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
495                       cg->TargetReg(kInvokeTgt));
496      break;
497    case 2:  // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
498      cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
499                       cg->TargetReg(kInvokeTgt));
500      break;
501    case 3:  // Get target method [use kInvokeTgt, set kArg0]
502      cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
503                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
504                       cg->TargetReg(kArg0));
505      break;
506    case 4:  // Get the compiled code address [uses kArg0, sets kInvokeTgt]
507      if (cu->instruction_set != kX86) {
508        cg->LoadWordDisp(cg->TargetReg(kArg0),
509                         mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
510                         cg->TargetReg(kInvokeTgt));
511        break;
512      }
513      // Intentional fallthrough for X86
514    default:
515      return -1;
516  }
517  return state + 1;
518}
519
520/*
521 * Emit the next instruction in an invoke interface sequence. This will do a lookup in the
522 * class's IMT, calling either the actual method or art_quick_imt_conflict_trampoline if
523 * more than one interface method map to the same index. Note also that we'll load the first
524 * argument ("this") into kArg1 here rather than the standard LoadArgRegs.
525 */
526static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
527                                 const MethodReference& target_method,
528                                 uint32_t method_idx, uintptr_t unused,
529                                 uintptr_t direct_method, InvokeType unused2) {
530  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
531
532  switch (state) {
533    case 0:  // Set target method index in case of conflict [set kHiddenArg, kHiddenFpArg (x86)]
534      CHECK_EQ(cu->dex_file, target_method.dex_file);
535      CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
536      cg->LoadConstant(cg->TargetReg(kHiddenArg), target_method.dex_method_index);
537      if (cu->instruction_set == kX86) {
538        cg->OpRegCopy(cg->TargetReg(kHiddenFpArg), cg->TargetReg(kHiddenArg));
539      }
540      break;
541    case 1: {  // Get "this" [set kArg1]
542      RegLocation  rl_arg = info->args[0];
543      cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
544      break;
545    }
546    case 2:  // Is "this" null? [use kArg1]
547      cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
548      // Get this->klass_ [use kArg1, set kInvokeTgt]
549      cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
550                       cg->TargetReg(kInvokeTgt));
551      break;
552    case 3:  // Get this->klass_->imtable [use kInvokeTgt, set kInvokeTgt]
553      cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::ImTableOffset().Int32Value(),
554                       cg->TargetReg(kInvokeTgt));
555      break;
556    case 4:  // Get target method [use kInvokeTgt, set kArg0]
557      cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), ((method_idx % ClassLinker::kImtSize) * 4) +
558                       mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
559                       cg->TargetReg(kArg0));
560      break;
561    case 5:  // Get the compiled code address [use kArg0, set kInvokeTgt]
562      if (cu->instruction_set != kX86) {
563        cg->LoadWordDisp(cg->TargetReg(kArg0),
564                         mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
565                         cg->TargetReg(kInvokeTgt));
566        break;
567      }
568      // Intentional fallthrough for X86
569    default:
570      return -1;
571  }
572  return state + 1;
573}
574
575static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, ThreadOffset trampoline,
576                            int state, const MethodReference& target_method,
577                            uint32_t method_idx) {
578  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
579  /*
580   * This handles the case in which the base method is not fully
581   * resolved at compile time, we bail to a runtime helper.
582   */
583  if (state == 0) {
584    if (cu->instruction_set != kX86) {
585      // Load trampoline target
586      cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(), cg->TargetReg(kInvokeTgt));
587    }
588    // Load kArg0 with method index
589    CHECK_EQ(cu->dex_file, target_method.dex_file);
590    cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
591    return 1;
592  }
593  return -1;
594}
595
596static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
597                                int state,
598                                const MethodReference& target_method,
599                                uint32_t method_idx,
600                                uintptr_t unused, uintptr_t unused2,
601                                InvokeType unused3) {
602  ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
603  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
604}
605
606static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
607                                const MethodReference& target_method,
608                                uint32_t method_idx, uintptr_t unused,
609                                uintptr_t unused2, InvokeType unused3) {
610  ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
611  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
612}
613
614static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
615                               const MethodReference& target_method,
616                               uint32_t method_idx, uintptr_t unused,
617                               uintptr_t unused2, InvokeType unused3) {
618  ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
619  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
620}
621
622static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
623                           const MethodReference& target_method,
624                           uint32_t method_idx, uintptr_t unused,
625                           uintptr_t unused2, InvokeType unused3) {
626  ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
627  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
628}
629
630static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
631                                                CallInfo* info, int state,
632                                                const MethodReference& target_method,
633                                                uint32_t unused,
634                                                uintptr_t unused2, uintptr_t unused3,
635                                                InvokeType unused4) {
636  ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
637  return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
638}
639
640int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
641                         NextCallInsn next_call_insn,
642                         const MethodReference& target_method,
643                         uint32_t vtable_idx, uintptr_t direct_code,
644                         uintptr_t direct_method, InvokeType type, bool skip_this) {
645  int last_arg_reg = TargetReg(kArg3);
646  int next_reg = TargetReg(kArg1);
647  int next_arg = 0;
648  if (skip_this) {
649    next_reg++;
650    next_arg++;
651  }
652  for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
653    RegLocation rl_arg = info->args[next_arg++];
654    rl_arg = UpdateRawLoc(rl_arg);
655    if (rl_arg.wide && (next_reg <= TargetReg(kArg2))) {
656      LoadValueDirectWideFixed(rl_arg, next_reg, next_reg + 1);
657      next_reg++;
658      next_arg++;
659    } else {
660      if (rl_arg.wide) {
661        rl_arg.wide = false;
662        rl_arg.is_const = false;
663      }
664      LoadValueDirectFixed(rl_arg, next_reg);
665    }
666    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
667                                direct_code, direct_method, type);
668  }
669  return call_state;
670}
671
672/*
673 * Load up to 5 arguments, the first three of which will be in
674 * kArg1 .. kArg3.  On entry kArg0 contains the current method pointer,
675 * and as part of the load sequence, it must be replaced with
676 * the target method pointer.  Note, this may also be called
677 * for "range" variants if the number of arguments is 5 or fewer.
678 */
679int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
680                                  int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
681                                  const MethodReference& target_method,
682                                  uint32_t vtable_idx, uintptr_t direct_code,
683                                  uintptr_t direct_method, InvokeType type, bool skip_this) {
684  RegLocation rl_arg;
685
686  /* If no arguments, just return */
687  if (info->num_arg_words == 0)
688    return call_state;
689
690  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
691                              direct_code, direct_method, type);
692
693  DCHECK_LE(info->num_arg_words, 5);
694  if (info->num_arg_words > 3) {
695    int32_t next_use = 3;
696    // Detect special case of wide arg spanning arg3/arg4
697    RegLocation rl_use0 = info->args[0];
698    RegLocation rl_use1 = info->args[1];
699    RegLocation rl_use2 = info->args[2];
700    if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
701      rl_use2.wide) {
702      int reg = -1;
703      // Wide spans, we need the 2nd half of uses[2].
704      rl_arg = UpdateLocWide(rl_use2);
705      if (rl_arg.location == kLocPhysReg) {
706        reg = rl_arg.high_reg;
707      } else {
708        // kArg2 & rArg3 can safely be used here
709        reg = TargetReg(kArg3);
710        LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
711        call_state = next_call_insn(cu_, info, call_state, target_method,
712                                    vtable_idx, direct_code, direct_method, type);
713      }
714      StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
715      StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
716      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
717                                  direct_code, direct_method, type);
718      next_use++;
719    }
720    // Loop through the rest
721    while (next_use < info->num_arg_words) {
722      int low_reg;
723      int high_reg = -1;
724      rl_arg = info->args[next_use];
725      rl_arg = UpdateRawLoc(rl_arg);
726      if (rl_arg.location == kLocPhysReg) {
727        low_reg = rl_arg.low_reg;
728        high_reg = rl_arg.high_reg;
729      } else {
730        low_reg = TargetReg(kArg2);
731        if (rl_arg.wide) {
732          high_reg = TargetReg(kArg3);
733          LoadValueDirectWideFixed(rl_arg, low_reg, high_reg);
734        } else {
735          LoadValueDirectFixed(rl_arg, low_reg);
736        }
737        call_state = next_call_insn(cu_, info, call_state, target_method,
738                                    vtable_idx, direct_code, direct_method, type);
739      }
740      int outs_offset = (next_use + 1) * 4;
741      if (rl_arg.wide) {
742        StoreBaseDispWide(TargetReg(kSp), outs_offset, low_reg, high_reg);
743        next_use += 2;
744      } else {
745        StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
746        next_use++;
747      }
748      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
749                               direct_code, direct_method, type);
750    }
751  }
752
753  call_state = LoadArgRegs(info, call_state, next_call_insn,
754                           target_method, vtable_idx, direct_code, direct_method,
755                           type, skip_this);
756
757  if (pcrLabel) {
758    *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
759  }
760  return call_state;
761}
762
763/*
764 * May have 0+ arguments (also used for jumbo).  Note that
765 * source virtual registers may be in physical registers, so may
766 * need to be flushed to home location before copying.  This
767 * applies to arg3 and above (see below).
768 *
769 * Two general strategies:
770 *    If < 20 arguments
771 *       Pass args 3-18 using vldm/vstm block copy
772 *       Pass arg0, arg1 & arg2 in kArg1-kArg3
773 *    If 20+ arguments
774 *       Pass args arg19+ using memcpy block copy
775 *       Pass arg0, arg1 & arg2 in kArg1-kArg3
776 *
777 */
778int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
779                                LIR** pcrLabel, NextCallInsn next_call_insn,
780                                const MethodReference& target_method,
781                                uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
782                                InvokeType type, bool skip_this) {
783  // If we can treat it as non-range (Jumbo ops will use range form)
784  if (info->num_arg_words <= 5)
785    return GenDalvikArgsNoRange(info, call_state, pcrLabel,
786                                next_call_insn, target_method, vtable_idx,
787                                direct_code, direct_method, type, skip_this);
788  /*
789   * First load the non-register arguments.  Both forms expect all
790   * of the source arguments to be in their home frame location, so
791   * scan the s_reg names and flush any that have been promoted to
792   * frame backing storage.
793   */
794  // Scan the rest of the args - if in phys_reg flush to memory
795  for (int next_arg = 0; next_arg < info->num_arg_words;) {
796    RegLocation loc = info->args[next_arg];
797    if (loc.wide) {
798      loc = UpdateLocWide(loc);
799      if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
800        StoreBaseDispWide(TargetReg(kSp), SRegOffset(loc.s_reg_low),
801                          loc.low_reg, loc.high_reg);
802      }
803      next_arg += 2;
804    } else {
805      loc = UpdateLoc(loc);
806      if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
807        StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
808                      loc.low_reg, kWord);
809      }
810      next_arg++;
811    }
812  }
813
814  int start_offset = SRegOffset(info->args[3].s_reg_low);
815  int outs_offset = 4 /* Method* */ + (3 * 4);
816  if (cu_->instruction_set != kThumb2) {
817    // Generate memcpy
818    OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
819    OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
820    CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
821                               TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
822  } else {
823    if (info->num_arg_words >= 20) {
824      // Generate memcpy
825      OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
826      OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
827      CallRuntimeHelperRegRegImm(QUICK_ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
828                                 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
829    } else {
830      // Use vldm/vstm pair using kArg3 as a temp
831      int regs_left = std::min(info->num_arg_words - 3, 16);
832      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
833                               direct_code, direct_method, type);
834      OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
835      LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
836      // TUNING: loosen barrier
837      ld->u.m.def_mask = ENCODE_ALL;
838      SetMemRefType(ld, true /* is_load */, kDalvikReg);
839      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
840                               direct_code, direct_method, type);
841      OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
842      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
843                               direct_code, direct_method, type);
844      LIR* st = OpVstm(TargetReg(kArg3), regs_left);
845      SetMemRefType(st, false /* is_load */, kDalvikReg);
846      st->u.m.def_mask = ENCODE_ALL;
847      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
848                               direct_code, direct_method, type);
849    }
850  }
851
852  call_state = LoadArgRegs(info, call_state, next_call_insn,
853                           target_method, vtable_idx, direct_code, direct_method,
854                           type, skip_this);
855
856  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
857                           direct_code, direct_method, type);
858  if (pcrLabel) {
859    *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
860  }
861  return call_state;
862}
863
864RegLocation Mir2Lir::InlineTarget(CallInfo* info) {
865  RegLocation res;
866  if (info->result.location == kLocInvalid) {
867    res = GetReturn(false);
868  } else {
869    res = info->result;
870  }
871  return res;
872}
873
874RegLocation Mir2Lir::InlineTargetWide(CallInfo* info) {
875  RegLocation res;
876  if (info->result.location == kLocInvalid) {
877    res = GetReturnWide(false);
878  } else {
879    res = info->result;
880  }
881  return res;
882}
883
884bool Mir2Lir::GenInlinedCharAt(CallInfo* info) {
885  if (cu_->instruction_set == kMips) {
886    // TODO - add Mips implementation
887    return false;
888  }
889  // Location of reference to data array
890  int value_offset = mirror::String::ValueOffset().Int32Value();
891  // Location of count
892  int count_offset = mirror::String::CountOffset().Int32Value();
893  // Starting offset within data array
894  int offset_offset = mirror::String::OffsetOffset().Int32Value();
895  // Start of char data with array_
896  int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
897
898  RegLocation rl_obj = info->args[0];
899  RegLocation rl_idx = info->args[1];
900  rl_obj = LoadValue(rl_obj, kCoreReg);
901  rl_idx = LoadValue(rl_idx, kCoreReg);
902  int reg_max;
903  GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
904  bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
905  LIR* launch_pad = NULL;
906  int reg_off = INVALID_REG;
907  int reg_ptr = INVALID_REG;
908  if (cu_->instruction_set != kX86) {
909    reg_off = AllocTemp();
910    reg_ptr = AllocTemp();
911    if (range_check) {
912      reg_max = AllocTemp();
913      LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
914    }
915    LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
916    LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
917    if (range_check) {
918      // Set up a launch pad to allow retry in case of bounds violation */
919      launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
920      intrinsic_launchpads_.Insert(launch_pad);
921      OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
922      FreeTemp(reg_max);
923      OpCondBranch(kCondUge, launch_pad);
924    }
925  } else {
926    if (range_check) {
927      reg_max = AllocTemp();
928      LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
929      // Set up a launch pad to allow retry in case of bounds violation */
930      launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
931      intrinsic_launchpads_.Insert(launch_pad);
932      OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
933      FreeTemp(reg_max);
934      OpCondBranch(kCondUge, launch_pad);
935    }
936    reg_off = AllocTemp();
937    reg_ptr = AllocTemp();
938    LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
939    LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
940  }
941  OpRegImm(kOpAdd, reg_ptr, data_offset);
942  OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
943  FreeTemp(rl_obj.low_reg);
944  FreeTemp(rl_idx.low_reg);
945  RegLocation rl_dest = InlineTarget(info);
946  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
947  LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
948  FreeTemp(reg_off);
949  FreeTemp(reg_ptr);
950  StoreValue(rl_dest, rl_result);
951  if (range_check) {
952    launch_pad->operands[2] = 0;  // no resumption
953  }
954  // Record that we've already inlined & null checked
955  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
956  return true;
957}
958
959// Generates an inlined String.is_empty or String.length.
960bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) {
961  if (cu_->instruction_set == kMips) {
962    // TODO - add Mips implementation
963    return false;
964  }
965  // dst = src.length();
966  RegLocation rl_obj = info->args[0];
967  rl_obj = LoadValue(rl_obj, kCoreReg);
968  RegLocation rl_dest = InlineTarget(info);
969  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
970  GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
971  LoadWordDisp(rl_obj.low_reg, mirror::String::CountOffset().Int32Value(), rl_result.low_reg);
972  if (is_empty) {
973    // dst = (dst == 0);
974    if (cu_->instruction_set == kThumb2) {
975      int t_reg = AllocTemp();
976      OpRegReg(kOpNeg, t_reg, rl_result.low_reg);
977      OpRegRegReg(kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
978    } else {
979      DCHECK_EQ(cu_->instruction_set, kX86);
980      OpRegImm(kOpSub, rl_result.low_reg, 1);
981      OpRegImm(kOpLsr, rl_result.low_reg, 31);
982    }
983  }
984  StoreValue(rl_dest, rl_result);
985  return true;
986}
987
988bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) {
989  if (cu_->instruction_set == kMips) {
990    // TODO - add Mips implementation
991    return false;
992  }
993  RegLocation rl_src_i = info->args[0];
994  RegLocation rl_dest = InlineTarget(info);  // result reg
995  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
996  if (size == kLong) {
997    RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg);
998    int r_i_low = rl_i.low_reg;
999    if (rl_i.low_reg == rl_result.low_reg) {
1000      // First REV shall clobber rl_result.low_reg, save the value in a temp for the second REV.
1001      r_i_low = AllocTemp();
1002      OpRegCopy(r_i_low, rl_i.low_reg);
1003    }
1004    OpRegReg(kOpRev, rl_result.low_reg, rl_i.high_reg);
1005    OpRegReg(kOpRev, rl_result.high_reg, r_i_low);
1006    if (rl_i.low_reg == rl_result.low_reg) {
1007      FreeTemp(r_i_low);
1008    }
1009    StoreValueWide(rl_dest, rl_result);
1010  } else {
1011    DCHECK(size == kWord || size == kSignedHalf);
1012    OpKind op = (size == kWord) ? kOpRev : kOpRevsh;
1013    RegLocation rl_i = LoadValue(rl_src_i, kCoreReg);
1014    OpRegReg(op, rl_result.low_reg, rl_i.low_reg);
1015    StoreValue(rl_dest, rl_result);
1016  }
1017  return true;
1018}
1019
1020bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) {
1021  if (cu_->instruction_set == kMips) {
1022    // TODO - add Mips implementation
1023    return false;
1024  }
1025  RegLocation rl_src = info->args[0];
1026  rl_src = LoadValue(rl_src, kCoreReg);
1027  RegLocation rl_dest = InlineTarget(info);
1028  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1029  int sign_reg = AllocTemp();
1030  // abs(x) = y<=x>>31, (x+y)^y.
1031  OpRegRegImm(kOpAsr, sign_reg, rl_src.low_reg, 31);
1032  OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
1033  OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1034  StoreValue(rl_dest, rl_result);
1035  return true;
1036}
1037
1038bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
1039  if (cu_->instruction_set == kMips) {
1040    // TODO - add Mips implementation
1041    return false;
1042  }
1043  if (cu_->instruction_set == kThumb2) {
1044    RegLocation rl_src = info->args[0];
1045    rl_src = LoadValueWide(rl_src, kCoreReg);
1046    RegLocation rl_dest = InlineTargetWide(info);
1047    RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1048    int sign_reg = AllocTemp();
1049    // abs(x) = y<=x>>31, (x+y)^y.
1050    OpRegRegImm(kOpAsr, sign_reg, rl_src.high_reg, 31);
1051    OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
1052    OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
1053    OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1054    OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1055    StoreValueWide(rl_dest, rl_result);
1056    return true;
1057  } else {
1058    DCHECK_EQ(cu_->instruction_set, kX86);
1059    // Reuse source registers to avoid running out of temps
1060    RegLocation rl_src = info->args[0];
1061    rl_src = LoadValueWide(rl_src, kCoreReg);
1062    RegLocation rl_dest = InlineTargetWide(info);
1063    RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1064    OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
1065    FreeTemp(rl_src.low_reg);
1066    FreeTemp(rl_src.high_reg);
1067    int sign_reg = AllocTemp();
1068    // abs(x) = y<=x>>31, (x+y)^y.
1069    OpRegRegImm(kOpAsr, sign_reg, rl_result.high_reg, 31);
1070    OpRegReg(kOpAdd, rl_result.low_reg, sign_reg);
1071    OpRegReg(kOpAdc, rl_result.high_reg, sign_reg);
1072    OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1073    OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1074    StoreValueWide(rl_dest, rl_result);
1075    return true;
1076  }
1077}
1078
1079bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) {
1080  if (cu_->instruction_set == kMips) {
1081    // TODO - add Mips implementation
1082    return false;
1083  }
1084  RegLocation rl_src = info->args[0];
1085  RegLocation rl_dest = InlineTarget(info);
1086  StoreValue(rl_dest, rl_src);
1087  return true;
1088}
1089
1090bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info) {
1091  if (cu_->instruction_set == kMips) {
1092    // TODO - add Mips implementation
1093    return false;
1094  }
1095  RegLocation rl_src = info->args[0];
1096  RegLocation rl_dest = InlineTargetWide(info);
1097  StoreValueWide(rl_dest, rl_src);
1098  return true;
1099}
1100
1101/*
1102 * Fast string.index_of(I) & (II).  Tests for simple case of char <= 0xffff,
1103 * otherwise bails to standard library code.
1104 */
1105bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
1106  if (cu_->instruction_set == kMips) {
1107    // TODO - add Mips implementation
1108    return false;
1109  }
1110  ClobberCallerSave();
1111  LockCallTemps();  // Using fixed registers
1112  int reg_ptr = TargetReg(kArg0);
1113  int reg_char = TargetReg(kArg1);
1114  int reg_start = TargetReg(kArg2);
1115
1116  RegLocation rl_obj = info->args[0];
1117  RegLocation rl_char = info->args[1];
1118  RegLocation rl_start = info->args[2];
1119  LoadValueDirectFixed(rl_obj, reg_ptr);
1120  LoadValueDirectFixed(rl_char, reg_char);
1121  if (zero_based) {
1122    LoadConstant(reg_start, 0);
1123  } else {
1124    LoadValueDirectFixed(rl_start, reg_start);
1125  }
1126  int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(QUICK_ENTRYPOINT_OFFSET(pIndexOf)) : 0;
1127  GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
1128  LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
1129  intrinsic_launchpads_.Insert(launch_pad);
1130  OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
1131  // NOTE: not a safepoint
1132  if (cu_->instruction_set != kX86) {
1133    OpReg(kOpBlx, r_tgt);
1134  } else {
1135    OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pIndexOf));
1136  }
1137  LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
1138  launch_pad->operands[2] = WrapPointer(resume_tgt);
1139  // Record that we've already inlined & null checked
1140  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1141  RegLocation rl_return = GetReturn(false);
1142  RegLocation rl_dest = InlineTarget(info);
1143  StoreValue(rl_dest, rl_return);
1144  return true;
1145}
1146
1147/* Fast string.compareTo(Ljava/lang/string;)I. */
1148bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) {
1149  if (cu_->instruction_set == kMips) {
1150    // TODO - add Mips implementation
1151    return false;
1152  }
1153  ClobberCallerSave();
1154  LockCallTemps();  // Using fixed registers
1155  int reg_this = TargetReg(kArg0);
1156  int reg_cmp = TargetReg(kArg1);
1157
1158  RegLocation rl_this = info->args[0];
1159  RegLocation rl_cmp = info->args[1];
1160  LoadValueDirectFixed(rl_this, reg_this);
1161  LoadValueDirectFixed(rl_cmp, reg_cmp);
1162  int r_tgt = (cu_->instruction_set != kX86) ?
1163      LoadHelper(QUICK_ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
1164  GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
1165  // TUNING: check if rl_cmp.s_reg_low is already null checked
1166  LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info));
1167  intrinsic_launchpads_.Insert(launch_pad);
1168  OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
1169  // NOTE: not a safepoint
1170  if (cu_->instruction_set != kX86) {
1171    OpReg(kOpBlx, r_tgt);
1172  } else {
1173    OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pStringCompareTo));
1174  }
1175  launch_pad->operands[2] = 0;  // No return possible
1176  // Record that we've already inlined & null checked
1177  info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
1178  RegLocation rl_return = GetReturn(false);
1179  RegLocation rl_dest = InlineTarget(info);
1180  StoreValue(rl_dest, rl_return);
1181  return true;
1182}
1183
1184bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1185  RegLocation rl_dest = InlineTarget(info);
1186  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1187  ThreadOffset offset = Thread::PeerOffset();
1188  if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
1189    LoadWordDisp(TargetReg(kSelf), offset.Int32Value(), rl_result.low_reg);
1190  } else {
1191    CHECK(cu_->instruction_set == kX86);
1192    reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.low_reg, offset);
1193  }
1194  StoreValue(rl_dest, rl_result);
1195  return true;
1196}
1197
1198bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
1199                                  bool is_long, bool is_volatile) {
1200  if (cu_->instruction_set == kMips) {
1201    // TODO - add Mips implementation
1202    return false;
1203  }
1204  // Unused - RegLocation rl_src_unsafe = info->args[0];
1205  RegLocation rl_src_obj = info->args[1];  // Object
1206  RegLocation rl_src_offset = info->args[2];  // long low
1207  rl_src_offset.wide = 0;  // ignore high half in info->args[3]
1208  RegLocation rl_dest = InlineTarget(info);  // result reg
1209  if (is_volatile) {
1210    GenMemBarrier(kLoadLoad);
1211  }
1212  RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1213  RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1214  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1215  if (is_long) {
1216    OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1217    LoadBaseDispWide(rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
1218    StoreValueWide(rl_dest, rl_result);
1219  } else {
1220    LoadBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
1221    StoreValue(rl_dest, rl_result);
1222  }
1223  return true;
1224}
1225
1226bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
1227                                  bool is_object, bool is_volatile, bool is_ordered) {
1228  if (cu_->instruction_set == kMips) {
1229    // TODO - add Mips implementation
1230    return false;
1231  }
1232  if (cu_->instruction_set == kX86 && is_object) {
1233    // TODO: fix X86, it exhausts registers for card marking.
1234    return false;
1235  }
1236  // Unused - RegLocation rl_src_unsafe = info->args[0];
1237  RegLocation rl_src_obj = info->args[1];  // Object
1238  RegLocation rl_src_offset = info->args[2];  // long low
1239  rl_src_offset.wide = 0;  // ignore high half in info->args[3]
1240  RegLocation rl_src_value = info->args[4];  // value to store
1241  if (is_volatile || is_ordered) {
1242    GenMemBarrier(kStoreStore);
1243  }
1244  RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1245  RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1246  RegLocation rl_value;
1247  if (is_long) {
1248    rl_value = LoadValueWide(rl_src_value, kCoreReg);
1249    OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1250    StoreBaseDispWide(rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
1251  } else {
1252    rl_value = LoadValue(rl_src_value, kCoreReg);
1253    StoreBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
1254  }
1255  if (is_volatile) {
1256    GenMemBarrier(kStoreLoad);
1257  }
1258  if (is_object) {
1259    MarkGCCard(rl_value.low_reg, rl_object.low_reg);
1260  }
1261  return true;
1262}
1263
1264void Mir2Lir::GenInvoke(CallInfo* info) {
1265  if (!(info->opt_flags & MIR_INLINED)) {
1266    DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
1267    if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
1268        ->GenIntrinsic(this, info)) {
1269      return;
1270    }
1271  }
1272  InvokeType original_type = info->type;  // avoiding mutation by ComputeInvokeInfo
1273  int call_state = 0;
1274  LIR* null_ck;
1275  LIR** p_null_ck = NULL;
1276  NextCallInsn next_call_insn;
1277  FlushAllRegs();  /* Everything to home location */
1278  // Explicit register usage
1279  LockCallTemps();
1280
1281  DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
1282  MethodReference target_method(cUnit->GetDexFile(), info->index);
1283  int vtable_idx;
1284  uintptr_t direct_code;
1285  uintptr_t direct_method;
1286  bool skip_this;
1287  bool fast_path =
1288      cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
1289                                              current_dalvik_offset_,
1290                                              true, true,
1291                                              &info->type, &target_method,
1292                                              &vtable_idx,
1293                                              &direct_code, &direct_method) && !SLOW_INVOKE_PATH;
1294  if (info->type == kInterface) {
1295    next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
1296    skip_this = fast_path;
1297  } else if (info->type == kDirect) {
1298    if (fast_path) {
1299      p_null_ck = &null_ck;
1300    }
1301    next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1302    skip_this = false;
1303  } else if (info->type == kStatic) {
1304    next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1305    skip_this = false;
1306  } else if (info->type == kSuper) {
1307    DCHECK(!fast_path);  // Fast path is a direct call.
1308    next_call_insn = NextSuperCallInsnSP;
1309    skip_this = false;
1310  } else {
1311    DCHECK_EQ(info->type, kVirtual);
1312    next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1313    skip_this = fast_path;
1314  }
1315  if (!info->is_range) {
1316    call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
1317                                      next_call_insn, target_method,
1318                                      vtable_idx, direct_code, direct_method,
1319                                      original_type, skip_this);
1320  } else {
1321    call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
1322                                    next_call_insn, target_method, vtable_idx,
1323                                    direct_code, direct_method, original_type,
1324                                    skip_this);
1325  }
1326  // Finish up any of the call sequence not interleaved in arg loading
1327  while (call_state >= 0) {
1328    call_state = next_call_insn(cu_, info, call_state, target_method,
1329                                vtable_idx, direct_code, direct_method,
1330                                original_type);
1331  }
1332  LIR* call_inst;
1333  if (cu_->instruction_set != kX86) {
1334    call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
1335  } else {
1336    if (fast_path) {
1337      call_inst = OpMem(kOpBlx, TargetReg(kArg0),
1338                        mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value());
1339    } else {
1340      ThreadOffset trampoline(-1);
1341      switch (info->type) {
1342      case kInterface:
1343        trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
1344        break;
1345      case kDirect:
1346        trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
1347        break;
1348      case kStatic:
1349        trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
1350        break;
1351      case kSuper:
1352        trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
1353        break;
1354      case kVirtual:
1355        trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
1356        break;
1357      default:
1358        LOG(FATAL) << "Unexpected invoke type";
1359      }
1360      call_inst = OpThreadMem(kOpBlx, trampoline);
1361    }
1362  }
1363  MarkSafepointPC(call_inst);
1364
1365  ClobberCallerSave();
1366  if (info->result.location != kLocInvalid) {
1367    // We have a following MOVE_RESULT - do it now.
1368    if (info->result.wide) {
1369      RegLocation ret_loc = GetReturnWide(info->result.fp);
1370      StoreValueWide(info->result, ret_loc);
1371    } else {
1372      RegLocation ret_loc = GetReturn(info->result.fp);
1373      StoreValue(info->result, ret_loc);
1374    }
1375  }
1376}
1377
1378}  // namespace art
1379