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