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