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