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