gen_invoke.cc revision 984305917bf57b3f8d92965e4715a0370cc5bcfb
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/class-inl.h"
26#include "mirror/dex_cache.h"
27#include "mirror/object_array-inl.h"
28#include "mirror/reference-inl.h"
29#include "mirror/string.h"
30#include "mir_to_lir-inl.h"
31#include "scoped_thread_state_change.h"
32#include "x86/codegen_x86.h"
33
34namespace art {
35
36// Shortcuts to repeatedly used long types.
37typedef mirror::ObjectArray<mirror::Object> ObjArray;
38
39/*
40 * This source files contains "gen" codegen routines that should
41 * be applicable to most targets.  Only mid-level support utilities
42 * and "op" calls may be used here.
43 */
44
45void Mir2Lir::AddIntrinsicSlowPath(CallInfo* info, LIR* branch, LIR* resume) {
46  class IntrinsicSlowPathPath : public Mir2Lir::LIRSlowPath {
47   public:
48    IntrinsicSlowPathPath(Mir2Lir* m2l, CallInfo* info, LIR* branch, LIR* resume = nullptr)
49        : LIRSlowPath(m2l, info->offset, branch, resume), info_(info) {
50    }
51
52    void Compile() {
53      m2l_->ResetRegPool();
54      m2l_->ResetDefTracking();
55      GenerateTargetLabel(kPseudoIntrinsicRetry);
56      // NOTE: GenInvokeNoInline() handles MarkSafepointPC.
57      m2l_->GenInvokeNoInline(info_);
58      if (cont_ != nullptr) {
59        m2l_->OpUnconditionalBranch(cont_);
60      }
61    }
62
63   private:
64    CallInfo* const info_;
65  };
66
67  AddSlowPath(new (arena_) IntrinsicSlowPathPath(this, info, branch, resume));
68}
69
70/*
71 * To save scheduling time, helper calls are broken into two parts: generation of
72 * the helper target address, and the actual call to the helper.  Because x86
73 * has a memory call operation, part 1 is a NOP for x86.  For other targets,
74 * load arguments between the two parts.
75 */
76// template <size_t pointer_size>
77RegStorage Mir2Lir::CallHelperSetup(QuickEntrypointEnum trampoline) {
78  if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
79    return RegStorage::InvalidReg();
80  } else {
81    return LoadHelper(trampoline);
82  }
83}
84
85LIR* Mir2Lir::CallHelper(RegStorage r_tgt, QuickEntrypointEnum trampoline, bool safepoint_pc,
86                         bool use_link) {
87  LIR* call_inst = InvokeTrampoline(use_link ? kOpBlx : kOpBx, r_tgt, trampoline);
88
89  if (r_tgt.Valid()) {
90    FreeTemp(r_tgt);
91  }
92
93  if (safepoint_pc) {
94    MarkSafepointPC(call_inst);
95  }
96  return call_inst;
97}
98
99void Mir2Lir::CallRuntimeHelper(QuickEntrypointEnum trampoline, bool safepoint_pc) {
100  RegStorage r_tgt = CallHelperSetup(trampoline);
101  ClobberCallerSave();
102  CallHelper(r_tgt, trampoline, safepoint_pc);
103}
104
105void Mir2Lir::CallRuntimeHelperImm(QuickEntrypointEnum trampoline, int arg0, bool safepoint_pc) {
106  RegStorage r_tgt = CallHelperSetup(trampoline);
107  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
108  ClobberCallerSave();
109  CallHelper(r_tgt, trampoline, safepoint_pc);
110}
111
112void Mir2Lir::CallRuntimeHelperReg(QuickEntrypointEnum trampoline, RegStorage arg0,
113                                   bool safepoint_pc) {
114  RegStorage r_tgt = CallHelperSetup(trampoline);
115  OpRegCopy(TargetReg(kArg0, arg0.GetWideKind()), arg0);
116  ClobberCallerSave();
117  CallHelper(r_tgt, trampoline, safepoint_pc);
118}
119
120void Mir2Lir::CallRuntimeHelperRegLocation(QuickEntrypointEnum trampoline, RegLocation arg0,
121                                           bool safepoint_pc) {
122  RegStorage r_tgt = CallHelperSetup(trampoline);
123  if (arg0.wide == 0) {
124    LoadValueDirectFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, arg0));
125  } else {
126    LoadValueDirectWideFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, kWide));
127  }
128  ClobberCallerSave();
129  CallHelper(r_tgt, trampoline, safepoint_pc);
130}
131
132void Mir2Lir::CallRuntimeHelperImmImm(QuickEntrypointEnum trampoline, int arg0, int arg1,
133                                      bool safepoint_pc) {
134  RegStorage r_tgt = CallHelperSetup(trampoline);
135  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
136  LoadConstant(TargetReg(kArg1, kNotWide), arg1);
137  ClobberCallerSave();
138  CallHelper(r_tgt, trampoline, safepoint_pc);
139}
140
141void Mir2Lir::CallRuntimeHelperImmRegLocation(QuickEntrypointEnum trampoline, int arg0,
142                                              RegLocation arg1, bool safepoint_pc) {
143  RegStorage r_tgt = CallHelperSetup(trampoline);
144  DCHECK(!arg1.fp);
145  if (arg1.wide == 0) {
146    LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1));
147  } else {
148    RegStorage r_tmp = TargetReg(cu_->instruction_set == kMips ? kArg2 : kArg1, kWide);
149    LoadValueDirectWideFixed(arg1, r_tmp);
150  }
151  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
152  ClobberCallerSave();
153  CallHelper(r_tgt, trampoline, safepoint_pc);
154}
155
156void Mir2Lir::CallRuntimeHelperRegLocationImm(QuickEntrypointEnum trampoline, RegLocation arg0,
157                                              int arg1, bool safepoint_pc) {
158  RegStorage r_tgt = CallHelperSetup(trampoline);
159  DCHECK(!arg0.wide);
160  LoadValueDirectFixed(arg0, TargetReg(kArg0, arg0));
161  LoadConstant(TargetReg(kArg1, kNotWide), arg1);
162  ClobberCallerSave();
163  CallHelper(r_tgt, trampoline, safepoint_pc);
164}
165
166void Mir2Lir::CallRuntimeHelperImmReg(QuickEntrypointEnum trampoline, int arg0, RegStorage arg1,
167                                      bool safepoint_pc) {
168  RegStorage r_tgt = CallHelperSetup(trampoline);
169  OpRegCopy(TargetReg(kArg1, arg1.GetWideKind()), arg1);
170  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
171  ClobberCallerSave();
172  CallHelper(r_tgt, trampoline, safepoint_pc);
173}
174
175void Mir2Lir::CallRuntimeHelperRegImm(QuickEntrypointEnum trampoline, RegStorage arg0, int arg1,
176                                      bool safepoint_pc) {
177  RegStorage r_tgt = CallHelperSetup(trampoline);
178  OpRegCopy(TargetReg(kArg0, arg0.GetWideKind()), arg0);
179  LoadConstant(TargetReg(kArg1, kNotWide), arg1);
180  ClobberCallerSave();
181  CallHelper(r_tgt, trampoline, safepoint_pc);
182}
183
184void Mir2Lir::CallRuntimeHelperImmMethod(QuickEntrypointEnum trampoline, int arg0,
185                                         bool safepoint_pc) {
186  RegStorage r_tgt = CallHelperSetup(trampoline);
187  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
188  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
189  ClobberCallerSave();
190  CallHelper(r_tgt, trampoline, safepoint_pc);
191}
192
193void Mir2Lir::CallRuntimeHelperRegMethod(QuickEntrypointEnum trampoline, RegStorage arg0,
194                                         bool safepoint_pc) {
195  RegStorage r_tgt = CallHelperSetup(trampoline);
196  DCHECK(!IsSameReg(TargetReg(kArg1, arg0.GetWideKind()), arg0));
197  RegStorage r_tmp = TargetReg(kArg0, arg0.GetWideKind());
198  if (r_tmp.NotExactlyEquals(arg0)) {
199    OpRegCopy(r_tmp, arg0);
200  }
201  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
202  ClobberCallerSave();
203  CallHelper(r_tgt, trampoline, safepoint_pc);
204}
205
206void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(QuickEntrypointEnum trampoline, RegStorage arg0,
207                                                    RegLocation arg2, bool safepoint_pc) {
208  RegStorage r_tgt = CallHelperSetup(trampoline);
209  DCHECK(!IsSameReg(TargetReg(kArg1, arg0.GetWideKind()), arg0));
210  RegStorage r_tmp = TargetReg(kArg0, arg0.GetWideKind());
211  if (r_tmp.NotExactlyEquals(arg0)) {
212    OpRegCopy(r_tmp, arg0);
213  }
214  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
215  LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
216  ClobberCallerSave();
217  CallHelper(r_tgt, trampoline, safepoint_pc);
218}
219
220void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(QuickEntrypointEnum trampoline,
221                                                      RegLocation arg0, RegLocation arg1,
222                                                      bool safepoint_pc) {
223  RegStorage r_tgt = CallHelperSetup(trampoline);
224  if (cu_->instruction_set == kArm64 || cu_->instruction_set == kX86_64) {
225    RegStorage arg0_reg = TargetReg((arg0.fp) ? kFArg0 : kArg0, arg0);
226
227    RegStorage arg1_reg;
228    if (arg1.fp == arg0.fp) {
229      arg1_reg = TargetReg((arg1.fp) ? kFArg1 : kArg1, arg1);
230    } else {
231      arg1_reg = TargetReg((arg1.fp) ? kFArg0 : kArg0, arg1);
232    }
233
234    if (arg0.wide == 0) {
235      LoadValueDirectFixed(arg0, arg0_reg);
236    } else {
237      LoadValueDirectWideFixed(arg0, arg0_reg);
238    }
239
240    if (arg1.wide == 0) {
241      LoadValueDirectFixed(arg1, arg1_reg);
242    } else {
243      LoadValueDirectWideFixed(arg1, arg1_reg);
244    }
245  } else {
246    DCHECK(!cu_->target64);
247    if (arg0.wide == 0) {
248      LoadValueDirectFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, kNotWide));
249      if (arg1.wide == 0) {
250        if (cu_->instruction_set == kMips) {
251          LoadValueDirectFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg1, kNotWide));
252        } else {
253          LoadValueDirectFixed(arg1, TargetReg(kArg1, kNotWide));
254        }
255      } else {
256        if (cu_->instruction_set == kMips) {
257          LoadValueDirectWideFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg2, kWide));
258        } else {
259          LoadValueDirectWideFixed(arg1, TargetReg(kArg1, kWide));
260        }
261      }
262    } else {
263      LoadValueDirectWideFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, kWide));
264      if (arg1.wide == 0) {
265        LoadValueDirectFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg2, kNotWide));
266      } else {
267        LoadValueDirectWideFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg2, kWide));
268      }
269    }
270  }
271  ClobberCallerSave();
272  CallHelper(r_tgt, trampoline, safepoint_pc);
273}
274
275void Mir2Lir::CopyToArgumentRegs(RegStorage arg0, RegStorage arg1) {
276  WideKind arg0_kind = arg0.GetWideKind();
277  WideKind arg1_kind = arg1.GetWideKind();
278  if (IsSameReg(arg1, TargetReg(kArg0, arg1_kind))) {
279    if (IsSameReg(arg0, TargetReg(kArg1, arg0_kind))) {
280      // Swap kArg0 and kArg1 with kArg2 as temp.
281      OpRegCopy(TargetReg(kArg2, arg1_kind), arg1);
282      OpRegCopy(TargetReg(kArg0, arg0_kind), arg0);
283      OpRegCopy(TargetReg(kArg1, arg1_kind), TargetReg(kArg2, arg1_kind));
284    } else {
285      OpRegCopy(TargetReg(kArg1, arg1_kind), arg1);
286      OpRegCopy(TargetReg(kArg0, arg0_kind), arg0);
287    }
288  } else {
289    OpRegCopy(TargetReg(kArg0, arg0_kind), arg0);
290    OpRegCopy(TargetReg(kArg1, arg1_kind), arg1);
291  }
292}
293
294void Mir2Lir::CallRuntimeHelperRegReg(QuickEntrypointEnum trampoline, RegStorage arg0,
295                                      RegStorage arg1, bool safepoint_pc) {
296  RegStorage r_tgt = CallHelperSetup(trampoline);
297  CopyToArgumentRegs(arg0, arg1);
298  ClobberCallerSave();
299  CallHelper(r_tgt, trampoline, safepoint_pc);
300}
301
302void Mir2Lir::CallRuntimeHelperRegRegImm(QuickEntrypointEnum trampoline, RegStorage arg0,
303                                         RegStorage arg1, int arg2, bool safepoint_pc) {
304  RegStorage r_tgt = CallHelperSetup(trampoline);
305  CopyToArgumentRegs(arg0, arg1);
306  LoadConstant(TargetReg(kArg2, kNotWide), arg2);
307  ClobberCallerSave();
308  CallHelper(r_tgt, trampoline, safepoint_pc);
309}
310
311void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(QuickEntrypointEnum trampoline, int arg0,
312                                                    RegLocation arg2, bool safepoint_pc) {
313  RegStorage r_tgt = CallHelperSetup(trampoline);
314  LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
315  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
316  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
317  ClobberCallerSave();
318  CallHelper(r_tgt, trampoline, safepoint_pc);
319}
320
321void Mir2Lir::CallRuntimeHelperImmMethodImm(QuickEntrypointEnum trampoline, int arg0, int arg2,
322                                            bool safepoint_pc) {
323  RegStorage r_tgt = CallHelperSetup(trampoline);
324  LoadCurrMethodDirect(TargetReg(kArg1, kRef));
325  LoadConstant(TargetReg(kArg2, kNotWide), arg2);
326  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
327  ClobberCallerSave();
328  CallHelper(r_tgt, trampoline, safepoint_pc);
329}
330
331void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(QuickEntrypointEnum trampoline, int arg0,
332                                                         RegLocation arg1,
333                                                         RegLocation arg2, bool safepoint_pc) {
334  RegStorage r_tgt = CallHelperSetup(trampoline);
335  DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U);  // The static_cast works around an
336                                                        // instantiation bug in GCC.
337  LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1));
338  if (arg2.wide == 0) {
339    LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
340  } else {
341    LoadValueDirectWideFixed(arg2, TargetReg(kArg2, kWide));
342  }
343  LoadConstant(TargetReg(kArg0, kNotWide), arg0);
344  ClobberCallerSave();
345  CallHelper(r_tgt, trampoline, safepoint_pc);
346}
347
348void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(
349    QuickEntrypointEnum trampoline,
350    RegLocation arg0,
351    RegLocation arg1,
352    RegLocation arg2,
353    bool safepoint_pc) {
354  RegStorage r_tgt = CallHelperSetup(trampoline);
355  LoadValueDirectFixed(arg0, TargetReg(kArg0, arg0));
356  LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1));
357  LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2));
358  ClobberCallerSave();
359  CallHelper(r_tgt, trampoline, safepoint_pc);
360}
361
362/*
363 * If there are any ins passed in registers that have not been promoted
364 * to a callee-save register, flush them to the frame.  Perform initial
365 * assignment of promoted arguments.
366 *
367 * ArgLocs is an array of location records describing the incoming arguments
368 * with one location record per word of argument.
369 */
370void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) {
371  /*
372   * Dummy up a RegLocation for the incoming StackReference<mirror::ArtMethod>
373   * It will attempt to keep kArg0 live (or copy it to home location
374   * if promoted).
375   */
376  RegLocation rl_src = rl_method;
377  rl_src.location = kLocPhysReg;
378  rl_src.reg = TargetReg(kArg0, kRef);
379  rl_src.home = false;
380  MarkLive(rl_src);
381  StoreValue(rl_method, rl_src);
382  // If Method* has been promoted, explicitly flush
383  if (rl_method.location == kLocPhysReg) {
384    StoreRefDisp(TargetPtrReg(kSp), 0, rl_src.reg, kNotVolatile);
385  }
386
387  if (cu_->num_ins == 0) {
388    return;
389  }
390
391  int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
392  /*
393   * Copy incoming arguments to their proper home locations.
394   * NOTE: an older version of dx had an issue in which
395   * it would reuse static method argument registers.
396   * This could result in the same Dalvik virtual register
397   * being promoted to both core and fp regs. To account for this,
398   * we only copy to the corresponding promoted physical register
399   * if it matches the type of the SSA name for the incoming
400   * argument.  It is also possible that long and double arguments
401   * end up half-promoted.  In those cases, we must flush the promoted
402   * half to memory as well.
403   */
404  ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
405  for (int i = 0; i < cu_->num_ins; i++) {
406    PromotionMap* v_map = &promotion_map_[start_vreg + i];
407    RegStorage reg = GetArgMappingToPhysicalReg(i);
408
409    if (reg.Valid()) {
410      // If arriving in register
411      bool need_flush = true;
412      RegLocation* t_loc = &ArgLocs[i];
413      if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
414        OpRegCopy(RegStorage::Solo32(v_map->core_reg), reg);
415        need_flush = false;
416      } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
417        OpRegCopy(RegStorage::Solo32(v_map->fp_reg), reg);
418        need_flush = false;
419      } else {
420        need_flush = true;
421      }
422
423      // For wide args, force flush if not fully promoted
424      if (t_loc->wide) {
425        PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
426        // Is only half promoted?
427        need_flush |= (p_map->core_location != v_map->core_location) ||
428            (p_map->fp_location != v_map->fp_location);
429        if ((cu_->instruction_set == kThumb2) && t_loc->fp && !need_flush) {
430          /*
431           * In Arm, a double is represented as a pair of consecutive single float
432           * registers starting at an even number.  It's possible that both Dalvik vRegs
433           * representing the incoming double were independently promoted as singles - but
434           * not in a form usable as a double.  If so, we need to flush - even though the
435           * incoming arg appears fully in register.  At this point in the code, both
436           * halves of the double are promoted.  Make sure they are in a usable form.
437           */
438          int lowreg_index = start_vreg + i + (t_loc->high_word ? -1 : 0);
439          int low_reg = promotion_map_[lowreg_index].fp_reg;
440          int high_reg = promotion_map_[lowreg_index + 1].fp_reg;
441          if (((low_reg & 0x1) != 0) || (high_reg != (low_reg + 1))) {
442            need_flush = true;
443          }
444        }
445      }
446      if (need_flush) {
447        Store32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), reg);
448      }
449    } else {
450      // If arriving in frame & promoted
451      if (v_map->core_location == kLocPhysReg) {
452        Load32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i),
453                   RegStorage::Solo32(v_map->core_reg));
454      }
455      if (v_map->fp_location == kLocPhysReg) {
456        Load32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i),
457                   RegStorage::Solo32(v_map->fp_reg));
458      }
459    }
460  }
461}
462
463static void CommonCallCodeLoadThisIntoArg1(const CallInfo* info, Mir2Lir* cg) {
464  RegLocation rl_arg = info->args[0];
465  cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1, kRef));
466}
467
468static void CommonCallCodeLoadClassIntoArg0(const CallInfo* info, Mir2Lir* cg) {
469  cg->GenNullCheck(cg->TargetReg(kArg1, kRef), info->opt_flags);
470  // get this->klass_ [use kArg1, set kArg0]
471  cg->LoadRefDisp(cg->TargetReg(kArg1, kRef), mirror::Object::ClassOffset().Int32Value(),
472                  cg->TargetReg(kArg0, kRef),
473                  kNotVolatile);
474  cg->MarkPossibleNullPointerException(info->opt_flags);
475}
476
477static bool CommonCallCodeLoadCodePointerIntoInvokeTgt(const CallInfo* info,
478                                                       const RegStorage* alt_from,
479                                                       const CompilationUnit* cu, Mir2Lir* cg) {
480  if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
481    // Get the compiled code address [use *alt_from or kArg0, set kInvokeTgt]
482    cg->LoadWordDisp(alt_from == nullptr ? cg->TargetReg(kArg0, kRef) : *alt_from,
483                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(),
484                     cg->TargetPtrReg(kInvokeTgt));
485    return true;
486  }
487  return false;
488}
489
490/*
491 * Bit of a hack here - in the absence of a real scheduling pass,
492 * emit the next instruction in static & direct invoke sequences.
493 */
494static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
495                          int state, const MethodReference& target_method,
496                          uint32_t unused,
497                          uintptr_t direct_code, uintptr_t direct_method,
498                          InvokeType type) {
499  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
500  if (direct_code != 0 && direct_method != 0) {
501    switch (state) {
502    case 0:  // Get the current Method* [sets kArg0]
503      if (direct_code != static_cast<uintptr_t>(-1)) {
504        if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
505          cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
506        }
507      } else if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
508        cg->LoadCodeAddress(target_method, type, kInvokeTgt);
509      }
510      if (direct_method != static_cast<uintptr_t>(-1)) {
511        cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method);
512      } else {
513        cg->LoadMethodAddress(target_method, type, kArg0);
514      }
515      break;
516    default:
517      return -1;
518    }
519  } else {
520    RegStorage arg0_ref = cg->TargetReg(kArg0, kRef);
521    switch (state) {
522    case 0:  // Get the current Method* [sets kArg0]
523      // TUNING: we can save a reg copy if Method* has been promoted.
524      cg->LoadCurrMethodDirect(arg0_ref);
525      break;
526    case 1:  // Get method->dex_cache_resolved_methods_
527      cg->LoadRefDisp(arg0_ref,
528                      mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(),
529                      arg0_ref,
530                      kNotVolatile);
531      // Set up direct code if known.
532      if (direct_code != 0) {
533        if (direct_code != static_cast<uintptr_t>(-1)) {
534          cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code);
535        } else if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
536          CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
537          cg->LoadCodeAddress(target_method, type, kInvokeTgt);
538        }
539      }
540      break;
541    case 2:  // Grab target method*
542      CHECK_EQ(cu->dex_file, target_method.dex_file);
543      cg->LoadRefDisp(arg0_ref,
544                      ObjArray::OffsetOfElement(target_method.dex_method_index).Int32Value(),
545                      arg0_ref,
546                      kNotVolatile);
547      break;
548    case 3:  // Grab the code from the method*
549      if (direct_code == 0) {
550        if (CommonCallCodeLoadCodePointerIntoInvokeTgt(info, &arg0_ref, cu, cg)) {
551          break;                                    // kInvokeTgt := arg0_ref->entrypoint
552        }
553      } else if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
554        break;
555      }
556      // Intentional fallthrough for x86
557    default:
558      return -1;
559    }
560  }
561  return state + 1;
562}
563
564/*
565 * Bit of a hack here - in the absence of a real scheduling pass,
566 * emit the next instruction in a virtual invoke sequence.
567 * We can use kLr as a temp prior to target address loading
568 * Note also that we'll load the first argument ("this") into
569 * kArg1 here rather than the standard LoadArgRegs.
570 */
571static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
572                         int state, const MethodReference& target_method,
573                         uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
574                         InvokeType unused3) {
575  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
576  /*
577   * This is the fast path in which the target virtual method is
578   * fully resolved at compile time.
579   */
580  switch (state) {
581    case 0:
582      CommonCallCodeLoadThisIntoArg1(info, cg);   // kArg1 := this
583      break;
584    case 1:
585      CommonCallCodeLoadClassIntoArg0(info, cg);  // kArg0 := kArg1->class
586                                                  // Includes a null-check.
587      break;
588    case 2: {
589      // Get this->klass_.embedded_vtable[method_idx] [usr kArg0, set kArg0]
590      int32_t offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
591          method_idx * sizeof(mirror::Class::VTableEntry);
592      // Load target method from embedded vtable to kArg0 [use kArg0, set kArg0]
593      cg->LoadRefDisp(cg->TargetReg(kArg0, kRef), offset, cg->TargetReg(kArg0, kRef), kNotVolatile);
594      break;
595    }
596    case 3:
597      if (CommonCallCodeLoadCodePointerIntoInvokeTgt(info, nullptr, cu, cg)) {
598        break;                                    // kInvokeTgt := kArg0->entrypoint
599      }
600      // Intentional fallthrough for X86
601    default:
602      return -1;
603  }
604  return state + 1;
605}
606
607/*
608 * Emit the next instruction in an invoke interface sequence. This will do a lookup in the
609 * class's IMT, calling either the actual method or art_quick_imt_conflict_trampoline if
610 * more than one interface method map to the same index. Note also that we'll load the first
611 * argument ("this") into kArg1 here rather than the standard LoadArgRegs.
612 */
613static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
614                                 const MethodReference& target_method,
615                                 uint32_t method_idx, uintptr_t unused,
616                                 uintptr_t direct_method, InvokeType unused2) {
617  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
618
619  switch (state) {
620    case 0:  // Set target method index in case of conflict [set kHiddenArg, kHiddenFpArg (x86)]
621      CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds());
622      cg->LoadConstant(cg->TargetReg(kHiddenArg, kNotWide), target_method.dex_method_index);
623      if (cu->instruction_set == kX86) {
624        cg->OpRegCopy(cg->TargetReg(kHiddenFpArg, kNotWide), cg->TargetReg(kHiddenArg, kNotWide));
625      }
626      break;
627    case 1:
628      CommonCallCodeLoadThisIntoArg1(info, cg);   // kArg1 := this
629      break;
630    case 2:
631      CommonCallCodeLoadClassIntoArg0(info, cg);  // kArg0 := kArg1->class
632                                                  // Includes a null-check.
633      break;
634    case 3: {  // Get target method [use kInvokeTgt, set kArg0]
635      int32_t offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
636          (method_idx % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
637      // Load target method from embedded imtable to kArg0 [use kArg0, set kArg0]
638      cg->LoadRefDisp(cg->TargetReg(kArg0, kRef), offset, cg->TargetReg(kArg0, kRef), kNotVolatile);
639      break;
640    }
641    case 4:
642      if (CommonCallCodeLoadCodePointerIntoInvokeTgt(info, nullptr, cu, cg)) {
643        break;                                    // kInvokeTgt := kArg0->entrypoint
644      }
645      // Intentional fallthrough for X86
646    default:
647      return -1;
648  }
649  return state + 1;
650}
651
652static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info,
653                            QuickEntrypointEnum trampoline, int state,
654                            const MethodReference& target_method, uint32_t method_idx) {
655  Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
656
657
658  /*
659   * This handles the case in which the base method is not fully
660   * resolved at compile time, we bail to a runtime helper.
661   */
662  if (state == 0) {
663    if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) {
664      // Load trampoline target
665      int32_t disp;
666      if (cu->target64) {
667        disp = GetThreadOffset<8>(trampoline).Int32Value();
668      } else {
669        disp = GetThreadOffset<4>(trampoline).Int32Value();
670      }
671      cg->LoadWordDisp(cg->TargetPtrReg(kSelf), disp, cg->TargetPtrReg(kInvokeTgt));
672    }
673    // Load kArg0 with method index
674    CHECK_EQ(cu->dex_file, target_method.dex_file);
675    cg->LoadConstant(cg->TargetReg(kArg0, kNotWide), target_method.dex_method_index);
676    return 1;
677  }
678  return -1;
679}
680
681static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
682                                int state,
683                                const MethodReference& target_method,
684                                uint32_t unused, uintptr_t unused2,
685                                uintptr_t unused3, InvokeType unused4) {
686  return NextInvokeInsnSP(cu, info, kQuickInvokeStaticTrampolineWithAccessCheck, state,
687                          target_method, 0);
688}
689
690static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
691                                const MethodReference& target_method,
692                                uint32_t unused, uintptr_t unused2,
693                                uintptr_t unused3, InvokeType unused4) {
694  return NextInvokeInsnSP(cu, info, kQuickInvokeDirectTrampolineWithAccessCheck, state,
695                          target_method, 0);
696}
697
698static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
699                               const MethodReference& target_method,
700                               uint32_t unused, uintptr_t unused2,
701                               uintptr_t unused3, InvokeType unused4) {
702  return NextInvokeInsnSP(cu, info, kQuickInvokeSuperTrampolineWithAccessCheck, state,
703                          target_method, 0);
704}
705
706static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
707                           const MethodReference& target_method,
708                           uint32_t unused, uintptr_t unused2,
709                           uintptr_t unused3, InvokeType unused4) {
710  return NextInvokeInsnSP(cu, info, kQuickInvokeVirtualTrampolineWithAccessCheck, state,
711                          target_method, 0);
712}
713
714static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
715                                                CallInfo* info, int state,
716                                                const MethodReference& target_method,
717                                                uint32_t unused, uintptr_t unused2,
718                                                uintptr_t unused3, InvokeType unused4) {
719  return NextInvokeInsnSP(cu, info, kQuickInvokeInterfaceTrampolineWithAccessCheck, state,
720                          target_method, 0);
721}
722
723int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
724                         NextCallInsn next_call_insn,
725                         const MethodReference& target_method,
726                         uint32_t vtable_idx, uintptr_t direct_code,
727                         uintptr_t direct_method, InvokeType type, bool skip_this) {
728  int last_arg_reg = 3 - 1;
729  int arg_regs[3] = {TargetReg(kArg1, kNotWide).GetReg(), TargetReg(kArg2, kNotWide).GetReg(),
730                     TargetReg(kArg3, kNotWide).GetReg()};
731
732  int next_reg = 0;
733  int next_arg = 0;
734  if (skip_this) {
735    next_reg++;
736    next_arg++;
737  }
738  for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
739    RegLocation rl_arg = info->args[next_arg++];
740    rl_arg = UpdateRawLoc(rl_arg);
741    if (rl_arg.wide && (next_reg <= last_arg_reg - 1)) {
742      RegStorage r_tmp(RegStorage::k64BitPair, arg_regs[next_reg], arg_regs[next_reg + 1]);
743      LoadValueDirectWideFixed(rl_arg, r_tmp);
744      next_reg++;
745      next_arg++;
746    } else {
747      if (rl_arg.wide) {
748        rl_arg = NarrowRegLoc(rl_arg);
749        rl_arg.is_const = false;
750      }
751      LoadValueDirectFixed(rl_arg, RegStorage::Solo32(arg_regs[next_reg]));
752    }
753    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
754                                direct_code, direct_method, type);
755  }
756  return call_state;
757}
758
759/*
760 * Load up to 5 arguments, the first three of which will be in
761 * kArg1 .. kArg3.  On entry kArg0 contains the current method pointer,
762 * and as part of the load sequence, it must be replaced with
763 * the target method pointer.  Note, this may also be called
764 * for "range" variants if the number of arguments is 5 or fewer.
765 */
766int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
767                                  int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
768                                  const MethodReference& target_method,
769                                  uint32_t vtable_idx, uintptr_t direct_code,
770                                  uintptr_t direct_method, InvokeType type, bool skip_this) {
771  RegLocation rl_arg;
772
773  /* If no arguments, just return */
774  if (info->num_arg_words == 0)
775    return call_state;
776
777  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
778                              direct_code, direct_method, type);
779
780  DCHECK_LE(info->num_arg_words, 5);
781  if (info->num_arg_words > 3) {
782    int32_t next_use = 3;
783    // Detect special case of wide arg spanning arg3/arg4
784    RegLocation rl_use0 = info->args[0];
785    RegLocation rl_use1 = info->args[1];
786    RegLocation rl_use2 = info->args[2];
787    if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) && rl_use2.wide) {
788      RegStorage reg;
789      // Wide spans, we need the 2nd half of uses[2].
790      rl_arg = UpdateLocWide(rl_use2);
791      if (rl_arg.location == kLocPhysReg) {
792        if (rl_arg.reg.IsPair()) {
793          reg = rl_arg.reg.GetHigh();
794        } else {
795          RegisterInfo* info = GetRegInfo(rl_arg.reg);
796          info = info->FindMatchingView(RegisterInfo::kHighSingleStorageMask);
797          if (info == nullptr) {
798            // NOTE: For hard float convention we won't split arguments across reg/mem.
799            UNIMPLEMENTED(FATAL) << "Needs hard float api.";
800          }
801          reg = info->GetReg();
802        }
803      } else {
804        // kArg2 & rArg3 can safely be used here
805        reg = TargetReg(kArg3, kNotWide);
806        {
807          ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
808          Load32Disp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
809        }
810        call_state = next_call_insn(cu_, info, call_state, target_method,
811                                    vtable_idx, direct_code, direct_method, type);
812      }
813      {
814        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
815        Store32Disp(TargetPtrReg(kSp), (next_use + 1) * 4, reg);
816      }
817      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
818                                  direct_code, direct_method, type);
819      next_use++;
820    }
821    // Loop through the rest
822    while (next_use < info->num_arg_words) {
823      RegStorage arg_reg;
824      rl_arg = info->args[next_use];
825      rl_arg = UpdateRawLoc(rl_arg);
826      if (rl_arg.location == kLocPhysReg) {
827        arg_reg = rl_arg.reg;
828      } else {
829        arg_reg = TargetReg(kArg2, rl_arg.wide ? kWide : kNotWide);
830        if (rl_arg.wide) {
831          LoadValueDirectWideFixed(rl_arg, arg_reg);
832        } else {
833          LoadValueDirectFixed(rl_arg, arg_reg);
834        }
835        call_state = next_call_insn(cu_, info, call_state, target_method,
836                                    vtable_idx, direct_code, direct_method, type);
837      }
838      int outs_offset = (next_use + 1) * 4;
839      {
840        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
841        if (rl_arg.wide) {
842          StoreBaseDisp(TargetPtrReg(kSp), outs_offset, arg_reg, k64, kNotVolatile);
843          next_use += 2;
844        } else {
845          Store32Disp(TargetPtrReg(kSp), outs_offset, arg_reg);
846          next_use++;
847        }
848      }
849      call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
850                               direct_code, direct_method, type);
851    }
852  }
853
854  call_state = LoadArgRegs(info, call_state, next_call_insn,
855                           target_method, vtable_idx, direct_code, direct_method,
856                           type, skip_this);
857
858  if (pcrLabel) {
859    if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
860      *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
861    } else {
862      *pcrLabel = nullptr;
863      if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
864          (info->opt_flags & MIR_IGNORE_NULL_CHECK)) {
865        return call_state;
866      }
867      // In lieu of generating a check for kArg1 being null, we need to
868      // perform a load when doing implicit checks.
869      GenImplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
870    }
871  }
872  return call_state;
873}
874
875// Default implementation of implicit null pointer check.
876// Overridden by arch specific as necessary.
877void Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) {
878  if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
879    return;
880  }
881  RegStorage tmp = AllocTemp();
882  Load32Disp(reg, 0, tmp);
883  MarkPossibleNullPointerException(opt_flags);
884  FreeTemp(tmp);
885}
886
887
888/*
889 * May have 0+ arguments (also used for jumbo).  Note that
890 * source virtual registers may be in physical registers, so may
891 * need to be flushed to home location before copying.  This
892 * applies to arg3 and above (see below).
893 *
894 * Two general strategies:
895 *    If < 20 arguments
896 *       Pass args 3-18 using vldm/vstm block copy
897 *       Pass arg0, arg1 & arg2 in kArg1-kArg3
898 *    If 20+ arguments
899 *       Pass args arg19+ using memcpy block copy
900 *       Pass arg0, arg1 & arg2 in kArg1-kArg3
901 *
902 */
903int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
904                                LIR** pcrLabel, NextCallInsn next_call_insn,
905                                const MethodReference& target_method,
906                                uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
907                                InvokeType type, bool skip_this) {
908  // If we can treat it as non-range (Jumbo ops will use range form)
909  if (info->num_arg_words <= 5)
910    return GenDalvikArgsNoRange(info, call_state, pcrLabel,
911                                next_call_insn, target_method, vtable_idx,
912                                direct_code, direct_method, type, skip_this);
913  /*
914   * First load the non-register arguments.  Both forms expect all
915   * of the source arguments to be in their home frame location, so
916   * scan the s_reg names and flush any that have been promoted to
917   * frame backing storage.
918   */
919  // Scan the rest of the args - if in phys_reg flush to memory
920  for (int next_arg = 0; next_arg < info->num_arg_words;) {
921    RegLocation loc = info->args[next_arg];
922    if (loc.wide) {
923      loc = UpdateLocWide(loc);
924      if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
925        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
926        StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile);
927      }
928      next_arg += 2;
929    } else {
930      loc = UpdateLoc(loc);
931      if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
932        ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
933        Store32Disp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg);
934      }
935      next_arg++;
936    }
937  }
938
939  // Logic below assumes that Method pointer is at offset zero from SP.
940  DCHECK_EQ(VRegOffset(static_cast<int>(kVRegMethodPtrBaseReg)), 0);
941
942  // The first 3 arguments are passed via registers.
943  // TODO: For 64-bit, instead of hardcoding 4 for Method* size, we should either
944  // get size of uintptr_t or size of object reference according to model being used.
945  int outs_offset = 4 /* Method* */ + (3 * sizeof(uint32_t));
946  int start_offset = SRegOffset(info->args[3].s_reg_low);
947  int regs_left_to_pass_via_stack = info->num_arg_words - 3;
948  DCHECK_GT(regs_left_to_pass_via_stack, 0);
949
950  if (cu_->instruction_set == kThumb2 && regs_left_to_pass_via_stack <= 16) {
951    // Use vldm/vstm pair using kArg3 as a temp
952    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
953                             direct_code, direct_method, type);
954    OpRegRegImm(kOpAdd, TargetReg(kArg3, kRef), TargetPtrReg(kSp), start_offset);
955    LIR* ld = nullptr;
956    {
957      ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
958      ld = OpVldm(TargetReg(kArg3, kRef), regs_left_to_pass_via_stack);
959    }
960    // TUNING: loosen barrier
961    ld->u.m.def_mask = &kEncodeAll;
962    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
963                             direct_code, direct_method, type);
964    OpRegRegImm(kOpAdd, TargetReg(kArg3, kRef), TargetPtrReg(kSp), 4 /* Method* */ + (3 * 4));
965    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
966                             direct_code, direct_method, type);
967    LIR* st = nullptr;
968    {
969      ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
970      st = OpVstm(TargetReg(kArg3, kRef), regs_left_to_pass_via_stack);
971    }
972    st->u.m.def_mask = &kEncodeAll;
973    call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
974                             direct_code, direct_method, type);
975  } else if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) {
976    int current_src_offset = start_offset;
977    int current_dest_offset = outs_offset;
978
979    // Only davik regs are accessed in this loop; no next_call_insn() calls.
980    ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
981    while (regs_left_to_pass_via_stack > 0) {
982      // This is based on the knowledge that the stack itself is 16-byte aligned.
983      bool src_is_16b_aligned = (current_src_offset & 0xF) == 0;
984      bool dest_is_16b_aligned = (current_dest_offset & 0xF) == 0;
985      size_t bytes_to_move;
986
987      /*
988       * The amount to move defaults to 32-bit. If there are 4 registers left to move, then do a
989       * a 128-bit move because we won't get the chance to try to aligned. If there are more than
990       * 4 registers left to move, consider doing a 128-bit only if either src or dest are aligned.
991       * We do this because we could potentially do a smaller move to align.
992       */
993      if (regs_left_to_pass_via_stack == 4 ||
994          (regs_left_to_pass_via_stack > 4 && (src_is_16b_aligned || dest_is_16b_aligned))) {
995        // Moving 128-bits via xmm register.
996        bytes_to_move = sizeof(uint32_t) * 4;
997
998        // Allocate a free xmm temp. Since we are working through the calling sequence,
999        // we expect to have an xmm temporary available.  AllocTempDouble will abort if
1000        // there are no free registers.
1001        RegStorage temp = AllocTempDouble();
1002
1003        LIR* ld1 = nullptr;
1004        LIR* ld2 = nullptr;
1005        LIR* st1 = nullptr;
1006        LIR* st2 = nullptr;
1007
1008        /*
1009         * The logic is similar for both loads and stores. If we have 16-byte alignment,
1010         * do an aligned move. If we have 8-byte alignment, then do the move in two
1011         * parts. This approach prevents possible cache line splits. Finally, fall back
1012         * to doing an unaligned move. In most cases we likely won't split the cache
1013         * line but we cannot prove it and thus take a conservative approach.
1014         */
1015        bool src_is_8b_aligned = (current_src_offset & 0x7) == 0;
1016        bool dest_is_8b_aligned = (current_dest_offset & 0x7) == 0;
1017
1018        if (src_is_16b_aligned) {
1019          ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovA128FP);
1020        } else if (src_is_8b_aligned) {
1021          ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovLo128FP);
1022          ld2 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset + (bytes_to_move >> 1),
1023                            kMovHi128FP);
1024        } else {
1025          ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovU128FP);
1026        }
1027
1028        if (dest_is_16b_aligned) {
1029          st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovA128FP);
1030        } else if (dest_is_8b_aligned) {
1031          st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovLo128FP);
1032          st2 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset + (bytes_to_move >> 1),
1033                            temp, kMovHi128FP);
1034        } else {
1035          st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovU128FP);
1036        }
1037
1038        // TODO If we could keep track of aliasing information for memory accesses that are wider
1039        // than 64-bit, we wouldn't need to set up a barrier.
1040        if (ld1 != nullptr) {
1041          if (ld2 != nullptr) {
1042            // For 64-bit load we can actually set up the aliasing information.
1043            AnnotateDalvikRegAccess(ld1, current_src_offset >> 2, true, true);
1044            AnnotateDalvikRegAccess(ld2, (current_src_offset + (bytes_to_move >> 1)) >> 2, true,
1045                                    true);
1046          } else {
1047            // Set barrier for 128-bit load.
1048            ld1->u.m.def_mask = &kEncodeAll;
1049          }
1050        }
1051        if (st1 != nullptr) {
1052          if (st2 != nullptr) {
1053            // For 64-bit store we can actually set up the aliasing information.
1054            AnnotateDalvikRegAccess(st1, current_dest_offset >> 2, false, true);
1055            AnnotateDalvikRegAccess(st2, (current_dest_offset + (bytes_to_move >> 1)) >> 2, false,
1056                                    true);
1057          } else {
1058            // Set barrier for 128-bit store.
1059            st1->u.m.def_mask = &kEncodeAll;
1060          }
1061        }
1062
1063        // Free the temporary used for the data movement.
1064        FreeTemp(temp);
1065      } else {
1066        // Moving 32-bits via general purpose register.
1067        bytes_to_move = sizeof(uint32_t);
1068
1069        // Instead of allocating a new temp, simply reuse one of the registers being used
1070        // for argument passing.
1071        RegStorage temp = TargetReg(kArg3, kNotWide);
1072
1073        // Now load the argument VR and store to the outs.
1074        Load32Disp(TargetPtrReg(kSp), current_src_offset, temp);
1075        Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp);
1076      }
1077
1078      current_src_offset += bytes_to_move;
1079      current_dest_offset += bytes_to_move;
1080      regs_left_to_pass_via_stack -= (bytes_to_move >> 2);
1081    }
1082  } else {
1083    // Generate memcpy
1084    OpRegRegImm(kOpAdd, TargetReg(kArg0, kRef), TargetPtrReg(kSp), outs_offset);
1085    OpRegRegImm(kOpAdd, TargetReg(kArg1, kRef), TargetPtrReg(kSp), start_offset);
1086    CallRuntimeHelperRegRegImm(kQuickMemcpy, TargetReg(kArg0, kRef), TargetReg(kArg1, kRef),
1087                               (info->num_arg_words - 3) * 4, false);
1088  }
1089
1090  call_state = LoadArgRegs(info, call_state, next_call_insn,
1091                           target_method, vtable_idx, direct_code, direct_method,
1092                           type, skip_this);
1093
1094  call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
1095                           direct_code, direct_method, type);
1096  if (pcrLabel) {
1097    if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
1098      *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
1099    } else {
1100      *pcrLabel = nullptr;
1101      if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
1102          (info->opt_flags & MIR_IGNORE_NULL_CHECK)) {
1103        return call_state;
1104      }
1105      // In lieu of generating a check for kArg1 being null, we need to
1106      // perform a load when doing implicit checks.
1107      GenImplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags);
1108    }
1109  }
1110  return call_state;
1111}
1112
1113RegLocation Mir2Lir::InlineTarget(CallInfo* info) {
1114  RegLocation res;
1115  if (info->result.location == kLocInvalid) {
1116    res = GetReturn(LocToRegClass(info->result));
1117  } else {
1118    res = info->result;
1119  }
1120  return res;
1121}
1122
1123RegLocation Mir2Lir::InlineTargetWide(CallInfo* info) {
1124  RegLocation res;
1125  if (info->result.location == kLocInvalid) {
1126    res = GetReturnWide(kCoreReg);
1127  } else {
1128    res = info->result;
1129  }
1130  return res;
1131}
1132
1133bool Mir2Lir::GenInlinedGet(CallInfo* info) {
1134  if (cu_->instruction_set == kMips) {
1135    // TODO - add Mips implementation
1136    return false;
1137  }
1138
1139  // the refrence class is stored in the image dex file which might not be the same as the cu's
1140  // dex file. Query the reference class for the image dex file then reset to starting dex file
1141  // in after loading class type.
1142  uint16_t type_idx = 0;
1143  const DexFile* ref_dex_file = nullptr;
1144  {
1145    ScopedObjectAccess soa(Thread::Current());
1146    type_idx = mirror::Reference::GetJavaLangRefReference()->GetDexTypeIndex();
1147    ref_dex_file = mirror::Reference::GetJavaLangRefReference()->GetDexCache()->GetDexFile();
1148  }
1149  CHECK(LIKELY(ref_dex_file != nullptr));
1150
1151  // address is either static within the image file, or needs to be patched up after compilation.
1152  bool unused_type_initialized;
1153  bool use_direct_type_ptr;
1154  uintptr_t direct_type_ptr;
1155  bool is_finalizable;
1156  const DexFile* old_dex = cu_->dex_file;
1157  cu_->dex_file = ref_dex_file;
1158  RegStorage reg_class = TargetReg(kArg1, kRef);
1159  Clobber(reg_class);
1160  LockTemp(reg_class);
1161  if (!cu_->compiler_driver->CanEmbedTypeInCode(*ref_dex_file, type_idx, &unused_type_initialized,
1162                                                &use_direct_type_ptr, &direct_type_ptr,
1163                                                &is_finalizable) || is_finalizable) {
1164    cu_->dex_file = old_dex;
1165    // address is not known and post-compile patch is not possible, cannot insert intrinsic.
1166    return false;
1167  }
1168  if (use_direct_type_ptr) {
1169    LoadConstant(reg_class, direct_type_ptr);
1170  } else {
1171    LoadClassType(type_idx, kArg1);
1172  }
1173  cu_->dex_file = old_dex;
1174
1175  // get the offset for flags in reference class.
1176  uint32_t slow_path_flag_offset = 0;
1177  uint32_t disable_flag_offset = 0;
1178  {
1179    ScopedObjectAccess soa(Thread::Current());
1180    mirror::Class* reference_class = mirror::Reference::GetJavaLangRefReference();
1181    slow_path_flag_offset = reference_class->GetSlowPathFlagOffset().Uint32Value();
1182    disable_flag_offset = reference_class->GetDisableIntrinsicFlagOffset().Uint32Value();
1183  }
1184  CHECK(slow_path_flag_offset && disable_flag_offset &&
1185        (slow_path_flag_offset != disable_flag_offset));
1186
1187  // intrinsic logic start.
1188  RegLocation rl_obj = info->args[0];
1189  rl_obj = LoadValue(rl_obj);
1190
1191  RegStorage reg_slow_path = AllocTemp();
1192  RegStorage reg_disabled = AllocTemp();
1193  Load32Disp(reg_class, slow_path_flag_offset, reg_slow_path);
1194  Load32Disp(reg_class, disable_flag_offset, reg_disabled);
1195  FreeTemp(reg_class);
1196  LIR* or_inst = OpRegRegReg(kOpOr, reg_slow_path, reg_slow_path, reg_disabled);
1197  FreeTemp(reg_disabled);
1198
1199  // if slow path, jump to JNI path target
1200  LIR* slow_path_branch;
1201  if (or_inst->u.m.def_mask->HasBit(ResourceMask::kCCode)) {
1202    // Generate conditional branch only, as the OR set a condition state (we are interested in a 'Z' flag).
1203    slow_path_branch = OpCondBranch(kCondNe, nullptr);
1204  } else {
1205    // Generate compare and branch.
1206    slow_path_branch = OpCmpImmBranch(kCondNe, reg_slow_path, 0, nullptr);
1207  }
1208  FreeTemp(reg_slow_path);
1209
1210  // slow path not enabled, simply load the referent of the reference object
1211  RegLocation rl_dest = InlineTarget(info);
1212  RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
1213  GenNullCheck(rl_obj.reg, info->opt_flags);
1214  LoadRefDisp(rl_obj.reg, mirror::Reference::ReferentOffset().Int32Value(), rl_result.reg,
1215      kNotVolatile);
1216  MarkPossibleNullPointerException(info->opt_flags);
1217  StoreValue(rl_dest, rl_result);
1218
1219  LIR* intrinsic_finish = NewLIR0(kPseudoTargetLabel);
1220  AddIntrinsicSlowPath(info, slow_path_branch, intrinsic_finish);
1221
1222  return true;
1223}
1224
1225bool Mir2Lir::GenInlinedCharAt(CallInfo* info) {
1226  if (cu_->instruction_set == kMips) {
1227    // TODO - add Mips implementation
1228    return false;
1229  }
1230  // Location of reference to data array
1231  int value_offset = mirror::String::ValueOffset().Int32Value();
1232  // Location of count
1233  int count_offset = mirror::String::CountOffset().Int32Value();
1234  // Starting offset within data array
1235  int offset_offset = mirror::String::OffsetOffset().Int32Value();
1236  // Start of char data with array_
1237  int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
1238
1239  RegLocation rl_obj = info->args[0];
1240  RegLocation rl_idx = info->args[1];
1241  rl_obj = LoadValue(rl_obj, kRefReg);
1242  rl_idx = LoadValue(rl_idx, kCoreReg);
1243  RegStorage reg_max;
1244  GenNullCheck(rl_obj.reg, info->opt_flags);
1245  bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
1246  LIR* range_check_branch = nullptr;
1247  RegStorage reg_off;
1248  RegStorage reg_ptr;
1249  reg_off = AllocTemp();
1250  reg_ptr = AllocTempRef();
1251  if (range_check) {
1252    reg_max = AllocTemp();
1253    Load32Disp(rl_obj.reg, count_offset, reg_max);
1254    MarkPossibleNullPointerException(info->opt_flags);
1255  }
1256  Load32Disp(rl_obj.reg, offset_offset, reg_off);
1257  MarkPossibleNullPointerException(info->opt_flags);
1258  LoadRefDisp(rl_obj.reg, value_offset, reg_ptr, kNotVolatile);
1259  if (range_check) {
1260    // Set up a slow path to allow retry in case of bounds violation */
1261    OpRegReg(kOpCmp, rl_idx.reg, reg_max);
1262    FreeTemp(reg_max);
1263    range_check_branch = OpCondBranch(kCondUge, nullptr);
1264  }
1265  OpRegImm(kOpAdd, reg_ptr, data_offset);
1266  if (rl_idx.is_const) {
1267    OpRegImm(kOpAdd, reg_off, mir_graph_->ConstantValue(rl_idx.orig_sreg));
1268  } else {
1269    OpRegReg(kOpAdd, reg_off, rl_idx.reg);
1270  }
1271  FreeTemp(rl_obj.reg);
1272  if (rl_idx.location == kLocPhysReg) {
1273    FreeTemp(rl_idx.reg);
1274  }
1275  RegLocation rl_dest = InlineTarget(info);
1276  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1277  LoadBaseIndexed(reg_ptr, reg_off, rl_result.reg, 1, kUnsignedHalf);
1278  FreeTemp(reg_off);
1279  FreeTemp(reg_ptr);
1280  StoreValue(rl_dest, rl_result);
1281  if (range_check) {
1282    DCHECK(range_check_branch != nullptr);
1283    info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've already null checked.
1284    AddIntrinsicSlowPath(info, range_check_branch);
1285  }
1286  return true;
1287}
1288
1289// Generates an inlined String.is_empty or String.length.
1290bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) {
1291  if (cu_->instruction_set == kMips) {
1292    // TODO - add Mips implementation
1293    return false;
1294  }
1295  // dst = src.length();
1296  RegLocation rl_obj = info->args[0];
1297  rl_obj = LoadValue(rl_obj, kRefReg);
1298  RegLocation rl_dest = InlineTarget(info);
1299  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1300  GenNullCheck(rl_obj.reg, info->opt_flags);
1301  Load32Disp(rl_obj.reg, mirror::String::CountOffset().Int32Value(), rl_result.reg);
1302  MarkPossibleNullPointerException(info->opt_flags);
1303  if (is_empty) {
1304    // dst = (dst == 0);
1305    if (cu_->instruction_set == kThumb2) {
1306      RegStorage t_reg = AllocTemp();
1307      OpRegReg(kOpNeg, t_reg, rl_result.reg);
1308      OpRegRegReg(kOpAdc, rl_result.reg, rl_result.reg, t_reg);
1309    } else if (cu_->instruction_set == kArm64) {
1310      OpRegImm(kOpSub, rl_result.reg, 1);
1311      OpRegRegImm(kOpLsr, rl_result.reg, rl_result.reg, 31);
1312    } else {
1313      DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
1314      OpRegImm(kOpSub, rl_result.reg, 1);
1315      OpRegImm(kOpLsr, rl_result.reg, 31);
1316    }
1317  }
1318  StoreValue(rl_dest, rl_result);
1319  return true;
1320}
1321
1322bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) {
1323  if (cu_->instruction_set == kMips) {
1324    // TODO - add Mips implementation.
1325    return false;
1326  }
1327  RegLocation rl_src_i = info->args[0];
1328  RegLocation rl_i = (size == k64) ? LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg);
1329  RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info);  // result reg
1330  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1331  if (size == k64) {
1332    if (cu_->instruction_set == kArm64 || cu_->instruction_set == kX86_64) {
1333      OpRegReg(kOpRev, rl_result.reg, rl_i.reg);
1334      StoreValueWide(rl_dest, rl_result);
1335      return true;
1336    }
1337    RegStorage r_i_low = rl_i.reg.GetLow();
1338    if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) {
1339      // First REV shall clobber rl_result.reg.GetReg(), save the value in a temp for the second REV.
1340      r_i_low = AllocTemp();
1341      OpRegCopy(r_i_low, rl_i.reg);
1342    }
1343    OpRegReg(kOpRev, rl_result.reg.GetLow(), rl_i.reg.GetHigh());
1344    OpRegReg(kOpRev, rl_result.reg.GetHigh(), r_i_low);
1345    if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) {
1346      FreeTemp(r_i_low);
1347    }
1348    StoreValueWide(rl_dest, rl_result);
1349  } else {
1350    DCHECK(size == k32 || size == kSignedHalf);
1351    OpKind op = (size == k32) ? kOpRev : kOpRevsh;
1352    OpRegReg(op, rl_result.reg, rl_i.reg);
1353    StoreValue(rl_dest, rl_result);
1354  }
1355  return true;
1356}
1357
1358bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) {
1359  if (cu_->instruction_set == kMips) {
1360    // TODO - add Mips implementation
1361    return false;
1362  }
1363  RegLocation rl_src = info->args[0];
1364  rl_src = LoadValue(rl_src, kCoreReg);
1365  RegLocation rl_dest = InlineTarget(info);
1366  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1367  RegStorage sign_reg = AllocTemp();
1368  // abs(x) = y<=x>>31, (x+y)^y.
1369  OpRegRegImm(kOpAsr, sign_reg, rl_src.reg, 31);
1370  OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, sign_reg);
1371  OpRegReg(kOpXor, rl_result.reg, sign_reg);
1372  StoreValue(rl_dest, rl_result);
1373  return true;
1374}
1375
1376bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
1377  if (cu_->instruction_set == kMips) {
1378    // TODO - add Mips implementation
1379    return false;
1380  }
1381  RegLocation rl_src = info->args[0];
1382  rl_src = LoadValueWide(rl_src, kCoreReg);
1383  RegLocation rl_dest = InlineTargetWide(info);
1384  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1385
1386  // If on x86 or if we would clobber a register needed later, just copy the source first.
1387  if (cu_->instruction_set != kX86_64 &&
1388      (cu_->instruction_set == kX86 ||
1389       rl_result.reg.GetLowReg() == rl_src.reg.GetHighReg())) {
1390    OpRegCopyWide(rl_result.reg, rl_src.reg);
1391    if (rl_result.reg.GetLowReg() != rl_src.reg.GetLowReg() &&
1392        rl_result.reg.GetLowReg() != rl_src.reg.GetHighReg() &&
1393        rl_result.reg.GetHighReg() != rl_src.reg.GetLowReg() &&
1394        rl_result.reg.GetHighReg() != rl_src.reg.GetHighReg()) {
1395      // Reuse source registers to avoid running out of temps.
1396      FreeTemp(rl_src.reg);
1397    }
1398    rl_src = rl_result;
1399  }
1400
1401  // abs(x) = y<=x>>31, (x+y)^y.
1402  RegStorage sign_reg;
1403  if (cu_->instruction_set == kX86_64) {
1404    sign_reg = AllocTempWide();
1405    OpRegRegImm(kOpAsr, sign_reg, rl_src.reg, 63);
1406    OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, sign_reg);
1407    OpRegReg(kOpXor, rl_result.reg, sign_reg);
1408  } else {
1409    sign_reg = AllocTemp();
1410    OpRegRegImm(kOpAsr, sign_reg, rl_src.reg.GetHigh(), 31);
1411    OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src.reg.GetLow(), sign_reg);
1412    OpRegRegReg(kOpAdc, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), sign_reg);
1413    OpRegReg(kOpXor, rl_result.reg.GetLow(), sign_reg);
1414    OpRegReg(kOpXor, rl_result.reg.GetHigh(), sign_reg);
1415  }
1416  FreeTemp(sign_reg);
1417  StoreValueWide(rl_dest, rl_result);
1418  return true;
1419}
1420
1421bool Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
1422  // Currently implemented only for ARM64
1423  return false;
1424}
1425
1426bool Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
1427  // Currently implemented only for ARM64
1428  return false;
1429}
1430
1431bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) {
1432  if (cu_->instruction_set == kMips) {
1433    // TODO - add Mips implementation
1434    return false;
1435  }
1436  RegLocation rl_src = info->args[0];
1437  RegLocation rl_dest = InlineTarget(info);
1438  StoreValue(rl_dest, rl_src);
1439  return true;
1440}
1441
1442bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info) {
1443  if (cu_->instruction_set == kMips) {
1444    // TODO - add Mips implementation
1445    return false;
1446  }
1447  RegLocation rl_src = info->args[0];
1448  RegLocation rl_dest = InlineTargetWide(info);
1449  StoreValueWide(rl_dest, rl_src);
1450  return true;
1451}
1452
1453bool Mir2Lir::GenInlinedArrayCopyCharArray(CallInfo* info) {
1454  return false;
1455}
1456
1457
1458/*
1459 * Fast String.indexOf(I) & (II).  Tests for simple case of char <= 0xFFFF,
1460 * otherwise bails to standard library code.
1461 */
1462bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
1463  if (cu_->instruction_set == kMips) {
1464    // TODO - add Mips implementation
1465    return false;
1466  }
1467  if (cu_->instruction_set == kX86_64) {
1468    // TODO - add kX86_64 implementation
1469    return false;
1470  }
1471  RegLocation rl_obj = info->args[0];
1472  RegLocation rl_char = info->args[1];
1473  if (rl_char.is_const && (mir_graph_->ConstantValue(rl_char) & ~0xFFFF) != 0) {
1474    // Code point beyond 0xFFFF. Punt to the real String.indexOf().
1475    return false;
1476  }
1477
1478  ClobberCallerSave();
1479  LockCallTemps();  // Using fixed registers
1480  RegStorage reg_ptr = TargetReg(kArg0, kRef);
1481  RegStorage reg_char = TargetReg(kArg1, kNotWide);
1482  RegStorage reg_start = TargetReg(kArg2, kNotWide);
1483
1484  LoadValueDirectFixed(rl_obj, reg_ptr);
1485  LoadValueDirectFixed(rl_char, reg_char);
1486  if (zero_based) {
1487    LoadConstant(reg_start, 0);
1488  } else {
1489    RegLocation rl_start = info->args[2];     // 3rd arg only present in III flavor of IndexOf.
1490    LoadValueDirectFixed(rl_start, reg_start);
1491  }
1492  RegStorage r_tgt = LoadHelper(kQuickIndexOf);
1493  GenExplicitNullCheck(reg_ptr, info->opt_flags);
1494  LIR* high_code_point_branch =
1495      rl_char.is_const ? nullptr : OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, nullptr);
1496  // NOTE: not a safepoint
1497  OpReg(kOpBlx, r_tgt);
1498  if (!rl_char.is_const) {
1499    // Add the slow path for code points beyond 0xFFFF.
1500    DCHECK(high_code_point_branch != nullptr);
1501    LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
1502    info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've null checked.
1503    AddIntrinsicSlowPath(info, high_code_point_branch, resume_tgt);
1504  } else {
1505    DCHECK_EQ(mir_graph_->ConstantValue(rl_char) & ~0xFFFF, 0);
1506    DCHECK(high_code_point_branch == nullptr);
1507  }
1508  RegLocation rl_return = GetReturn(kCoreReg);
1509  RegLocation rl_dest = InlineTarget(info);
1510  StoreValue(rl_dest, rl_return);
1511  return true;
1512}
1513
1514/* Fast string.compareTo(Ljava/lang/string;)I. */
1515bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) {
1516  if (cu_->instruction_set == kMips) {
1517    // TODO - add Mips implementation
1518    return false;
1519  }
1520  ClobberCallerSave();
1521  LockCallTemps();  // Using fixed registers
1522  RegStorage reg_this = TargetReg(kArg0, kRef);
1523  RegStorage reg_cmp = TargetReg(kArg1, kRef);
1524
1525  RegLocation rl_this = info->args[0];
1526  RegLocation rl_cmp = info->args[1];
1527  LoadValueDirectFixed(rl_this, reg_this);
1528  LoadValueDirectFixed(rl_cmp, reg_cmp);
1529  RegStorage r_tgt;
1530  if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) {
1531    r_tgt = LoadHelper(kQuickStringCompareTo);
1532  } else {
1533    r_tgt = RegStorage::InvalidReg();
1534  }
1535  GenExplicitNullCheck(reg_this, info->opt_flags);
1536  info->opt_flags |= MIR_IGNORE_NULL_CHECK;  // Record that we've null checked.
1537  // TUNING: check if rl_cmp.s_reg_low is already null checked
1538  LIR* cmp_null_check_branch = OpCmpImmBranch(kCondEq, reg_cmp, 0, nullptr);
1539  AddIntrinsicSlowPath(info, cmp_null_check_branch);
1540  // NOTE: not a safepoint
1541  CallHelper(r_tgt, kQuickStringCompareTo, false, true);
1542  RegLocation rl_return = GetReturn(kCoreReg);
1543  RegLocation rl_dest = InlineTarget(info);
1544  StoreValue(rl_dest, rl_return);
1545  return true;
1546}
1547
1548bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1549  RegLocation rl_dest = InlineTarget(info);
1550
1551  // Early exit if the result is unused.
1552  if (rl_dest.orig_sreg < 0) {
1553    return true;
1554  }
1555
1556  RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true);
1557
1558  switch (cu_->instruction_set) {
1559    case kArm:
1560      // Fall-through.
1561    case kThumb2:
1562      // Fall-through.
1563    case kMips:
1564      Load32Disp(TargetPtrReg(kSelf), Thread::PeerOffset<4>().Int32Value(), rl_result.reg);
1565      break;
1566
1567    case kArm64:
1568      LoadRefDisp(TargetPtrReg(kSelf), Thread::PeerOffset<8>().Int32Value(), rl_result.reg,
1569                  kNotVolatile);
1570      break;
1571
1572    case kX86:
1573      reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg,
1574                                                          Thread::PeerOffset<4>());
1575      break;
1576
1577    case kX86_64:
1578      reinterpret_cast<X86Mir2Lir*>(this)->OpRegThreadMem(kOpMov, rl_result.reg,
1579                                                          Thread::PeerOffset<8>());
1580      break;
1581
1582    default:
1583      LOG(FATAL) << "Unexpected isa " << cu_->instruction_set;
1584  }
1585  StoreValue(rl_dest, rl_result);
1586  return true;
1587}
1588
1589bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
1590                                  bool is_long, bool is_volatile) {
1591  if (cu_->instruction_set == kMips) {
1592    // TODO - add Mips implementation
1593    return false;
1594  }
1595  // Unused - RegLocation rl_src_unsafe = info->args[0];
1596  RegLocation rl_src_obj = info->args[1];  // Object
1597  RegLocation rl_src_offset = info->args[2];  // long low
1598  rl_src_offset = NarrowRegLoc(rl_src_offset);  // ignore high half in info->args[3]
1599  RegLocation rl_dest = is_long ? InlineTargetWide(info) : InlineTarget(info);  // result reg
1600
1601  RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
1602  RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1603  RegLocation rl_result = EvalLoc(rl_dest, LocToRegClass(rl_dest), true);
1604  if (is_long) {
1605    if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64
1606        || cu_->instruction_set == kArm64) {
1607      LoadBaseIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0, k64);
1608    } else {
1609      RegStorage rl_temp_offset = AllocTemp();
1610      OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
1611      LoadBaseDisp(rl_temp_offset, 0, rl_result.reg, k64, kNotVolatile);
1612      FreeTemp(rl_temp_offset);
1613    }
1614  } else {
1615    if (rl_result.ref) {
1616      LoadRefIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0);
1617    } else {
1618      LoadBaseIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0, k32);
1619    }
1620  }
1621
1622  if (is_volatile) {
1623    GenMemBarrier(kLoadAny);
1624  }
1625
1626  if (is_long) {
1627    StoreValueWide(rl_dest, rl_result);
1628  } else {
1629    StoreValue(rl_dest, rl_result);
1630  }
1631  return true;
1632}
1633
1634bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
1635                                  bool is_object, bool is_volatile, bool is_ordered) {
1636  if (cu_->instruction_set == kMips) {
1637    // TODO - add Mips implementation
1638    return false;
1639  }
1640  // Unused - RegLocation rl_src_unsafe = info->args[0];
1641  RegLocation rl_src_obj = info->args[1];  // Object
1642  RegLocation rl_src_offset = info->args[2];  // long low
1643  rl_src_offset = NarrowRegLoc(rl_src_offset);  // ignore high half in info->args[3]
1644  RegLocation rl_src_value = info->args[4];  // value to store
1645  if (is_volatile || is_ordered) {
1646    GenMemBarrier(kAnyStore);
1647  }
1648  RegLocation rl_object = LoadValue(rl_src_obj, kRefReg);
1649  RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1650  RegLocation rl_value;
1651  if (is_long) {
1652    rl_value = LoadValueWide(rl_src_value, kCoreReg);
1653    if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64
1654        || cu_->instruction_set == kArm64) {
1655      StoreBaseIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0, k64);
1656    } else {
1657      RegStorage rl_temp_offset = AllocTemp();
1658      OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg);
1659      StoreBaseDisp(rl_temp_offset, 0, rl_value.reg, k64, kNotVolatile);
1660      FreeTemp(rl_temp_offset);
1661    }
1662  } else {
1663    rl_value = LoadValue(rl_src_value);
1664    if (rl_value.ref) {
1665      StoreRefIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0);
1666    } else {
1667      StoreBaseIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0, k32);
1668    }
1669  }
1670
1671  // Free up the temp early, to ensure x86 doesn't run out of temporaries in MarkGCCard.
1672  FreeTemp(rl_offset.reg);
1673
1674  if (is_volatile) {
1675    // Prevent reordering with a subsequent volatile load.
1676    // May also be needed to address store atomicity issues.
1677    GenMemBarrier(kAnyAny);
1678  }
1679  if (is_object) {
1680    MarkGCCard(rl_value.reg, rl_object.reg);
1681  }
1682  return true;
1683}
1684
1685void Mir2Lir::GenInvoke(CallInfo* info) {
1686  if ((info->opt_flags & MIR_INLINED) != 0) {
1687    // Already inlined but we may still need the null check.
1688    if (info->type != kStatic &&
1689        ((cu_->disable_opt & (1 << kNullCheckElimination)) != 0 ||
1690         (info->opt_flags & MIR_IGNORE_NULL_CHECK) == 0))  {
1691      RegLocation rl_obj = LoadValue(info->args[0], kRefReg);
1692      GenNullCheck(rl_obj.reg);
1693    }
1694    return;
1695  }
1696  DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
1697  if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
1698      ->GenIntrinsic(this, info)) {
1699    return;
1700  }
1701  GenInvokeNoInline(info);
1702}
1703
1704static LIR* GenInvokeNoInlineCall(Mir2Lir* mir_to_lir, InvokeType type) {
1705  QuickEntrypointEnum trampoline;
1706  switch (type) {
1707    case kInterface:
1708      trampoline = kQuickInvokeInterfaceTrampolineWithAccessCheck;
1709      break;
1710    case kDirect:
1711      trampoline = kQuickInvokeDirectTrampolineWithAccessCheck;
1712      break;
1713    case kStatic:
1714      trampoline = kQuickInvokeStaticTrampolineWithAccessCheck;
1715      break;
1716    case kSuper:
1717      trampoline = kQuickInvokeSuperTrampolineWithAccessCheck;
1718      break;
1719    case kVirtual:
1720      trampoline = kQuickInvokeVirtualTrampolineWithAccessCheck;
1721      break;
1722    default:
1723      LOG(FATAL) << "Unexpected invoke type";
1724      trampoline = kQuickInvokeInterfaceTrampolineWithAccessCheck;
1725  }
1726  return mir_to_lir->InvokeTrampoline(kOpBlx, RegStorage::InvalidReg(), trampoline);
1727}
1728
1729void Mir2Lir::GenInvokeNoInline(CallInfo* info) {
1730  int call_state = 0;
1731  LIR* null_ck;
1732  LIR** p_null_ck = NULL;
1733  NextCallInsn next_call_insn;
1734  FlushAllRegs();  /* Everything to home location */
1735  // Explicit register usage
1736  LockCallTemps();
1737
1738  const MirMethodLoweringInfo& method_info = mir_graph_->GetMethodLoweringInfo(info->mir);
1739  cu_->compiler_driver->ProcessedInvoke(method_info.GetInvokeType(), method_info.StatsFlags());
1740  BeginInvoke(info);
1741  InvokeType original_type = static_cast<InvokeType>(method_info.GetInvokeType());
1742  info->type = static_cast<InvokeType>(method_info.GetSharpType());
1743  bool fast_path = method_info.FastPath();
1744  bool skip_this;
1745  if (info->type == kInterface) {
1746    next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
1747    skip_this = fast_path;
1748  } else if (info->type == kDirect) {
1749    if (fast_path) {
1750      p_null_ck = &null_ck;
1751    }
1752    next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1753    skip_this = false;
1754  } else if (info->type == kStatic) {
1755    next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1756    skip_this = false;
1757  } else if (info->type == kSuper) {
1758    DCHECK(!fast_path);  // Fast path is a direct call.
1759    next_call_insn = NextSuperCallInsnSP;
1760    skip_this = false;
1761  } else {
1762    DCHECK_EQ(info->type, kVirtual);
1763    next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1764    skip_this = fast_path;
1765  }
1766  MethodReference target_method = method_info.GetTargetMethod();
1767  if (!info->is_range) {
1768    call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
1769                                      next_call_insn, target_method, method_info.VTableIndex(),
1770                                      method_info.DirectCode(), method_info.DirectMethod(),
1771                                      original_type, skip_this);
1772  } else {
1773    call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
1774                                    next_call_insn, target_method, method_info.VTableIndex(),
1775                                    method_info.DirectCode(), method_info.DirectMethod(),
1776                                    original_type, skip_this);
1777  }
1778  // Finish up any of the call sequence not interleaved in arg loading
1779  while (call_state >= 0) {
1780    call_state = next_call_insn(cu_, info, call_state, target_method, method_info.VTableIndex(),
1781                                method_info.DirectCode(), method_info.DirectMethod(), original_type);
1782  }
1783  LIR* call_inst;
1784  if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) {
1785    call_inst = OpReg(kOpBlx, TargetPtrReg(kInvokeTgt));
1786  } else {
1787    if (fast_path) {
1788      if (method_info.DirectCode() == static_cast<uintptr_t>(-1)) {
1789        // We can have the linker fixup a call relative.
1790        call_inst =
1791          reinterpret_cast<X86Mir2Lir*>(this)->CallWithLinkerFixup(target_method, info->type);
1792      } else {
1793        call_inst = OpMem(kOpBlx, TargetReg(kArg0, kRef),
1794                          mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value());
1795      }
1796    } else {
1797      call_inst = GenInvokeNoInlineCall(this, info->type);
1798    }
1799  }
1800  EndInvoke(info);
1801  MarkSafepointPC(call_inst);
1802
1803  ClobberCallerSave();
1804  if (info->result.location != kLocInvalid) {
1805    // We have a following MOVE_RESULT - do it now.
1806    if (info->result.wide) {
1807      RegLocation ret_loc = GetReturnWide(LocToRegClass(info->result));
1808      StoreValueWide(info->result, ret_loc);
1809    } else {
1810      RegLocation ret_loc = GetReturn(LocToRegClass(info->result));
1811      StoreValue(info->result, ret_loc);
1812    }
1813  }
1814}
1815
1816}  // namespace art
1817