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