blob: f44272a6416ef494efd505126877cb6e5ea8437f [file] [log] [blame]
buzbee31a4a6f2012-02-28 15:36:15 -08001/*
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
buzbee395116c2013-02-27 14:30:25 -080017#include "compiler/dex/compiler_ir.h"
Brian Carlstrom265091e2013-01-30 14:08:26 -080018#include "invoke_type.h"
Ian Rogers33e95662013-05-20 20:29:14 -070019#include "mirror/array.h"
20#include "mirror/string.h"
Brian Carlstrom641ce032013-01-31 15:21:37 -080021#include "oat/runtime/oat_support_entrypoints.h"
Ian Rogers07ec8e12012-12-01 01:26:51 -080022#include "x86/codegen_x86.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070023
buzbee31a4a6f2012-02-28 15:36:15 -080024namespace art {
25
26/*
27 * This source files contains "gen" codegen routines that should
28 * be applicable to most targets. Only mid-level support utilities
29 * and "op" calls may be used here.
30 */
31
buzbee31a4a6f2012-02-28 15:36:15 -080032/*
buzbee02031b12012-11-23 09:41:35 -080033 * To save scheduling time, helper calls are broken into two parts: generation of
34 * the helper target address, and the actuall call to the helper. Because x86
35 * has a memory call operation, part 1 is a NOP for x86. For other targets,
36 * load arguments between the two parts.
37 */
buzbee1fd33462013-03-25 13:40:45 -070038int Mir2Lir::CallHelperSetup(int helper_offset)
buzbee02031b12012-11-23 09:41:35 -080039{
buzbee1fd33462013-03-25 13:40:45 -070040 return (cu_->instruction_set == kX86) ? 0 : LoadHelper(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080041}
42
43/* NOTE: if r_tgt is a temp, it will be freed following use */
buzbee1fd33462013-03-25 13:40:45 -070044LIR* Mir2Lir::CallHelper(int r_tgt, int helper_offset, bool safepoint_pc)
buzbee02031b12012-11-23 09:41:35 -080045{
46 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -070047 if (cu_->instruction_set == kX86) {
48 call_inst = OpThreadMem(kOpBlx, helper_offset);
buzbee02031b12012-11-23 09:41:35 -080049 } else {
buzbee1fd33462013-03-25 13:40:45 -070050 call_inst = OpReg(kOpBlx, r_tgt);
51 FreeTemp(r_tgt);
buzbee02031b12012-11-23 09:41:35 -080052 }
53 if (safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070054 MarkSafepointPC(call_inst);
buzbee02031b12012-11-23 09:41:35 -080055 }
56 return call_inst;
57}
58
buzbee1fd33462013-03-25 13:40:45 -070059void Mir2Lir::CallRuntimeHelperImm(int helper_offset, int arg0, bool safepoint_pc) {
60 int r_tgt = CallHelperSetup(helper_offset);
61 LoadConstant(TargetReg(kArg0), arg0);
62 ClobberCalleeSave();
63 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080064}
65
buzbee1fd33462013-03-25 13:40:45 -070066void Mir2Lir::CallRuntimeHelperReg(int helper_offset, int arg0, bool safepoint_pc) {
67 int r_tgt = CallHelperSetup(helper_offset);
68 OpRegCopy(TargetReg(kArg0), arg0);
69 ClobberCalleeSave();
70 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080071}
72
buzbee1fd33462013-03-25 13:40:45 -070073void Mir2Lir::CallRuntimeHelperRegLocation(int helper_offset, RegLocation arg0, bool safepoint_pc) {
74 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080075 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070076 LoadValueDirectFixed(arg0, TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -080077 } else {
buzbee1fd33462013-03-25 13:40:45 -070078 LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080079 }
buzbee1fd33462013-03-25 13:40:45 -070080 ClobberCalleeSave();
81 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080082}
83
buzbee1fd33462013-03-25 13:40:45 -070084void Mir2Lir::CallRuntimeHelperImmImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -080085 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070086 int r_tgt = CallHelperSetup(helper_offset);
87 LoadConstant(TargetReg(kArg0), arg0);
88 LoadConstant(TargetReg(kArg1), arg1);
89 ClobberCalleeSave();
90 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -080091}
92
buzbee1fd33462013-03-25 13:40:45 -070093void Mir2Lir::CallRuntimeHelperImmRegLocation(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -080094 RegLocation arg1, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -070095 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -080096 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -070097 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -080098 } else {
buzbee1fd33462013-03-25 13:40:45 -070099 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800100 }
buzbee1fd33462013-03-25 13:40:45 -0700101 LoadConstant(TargetReg(kArg0), arg0);
102 ClobberCalleeSave();
103 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800104}
105
buzbee1fd33462013-03-25 13:40:45 -0700106void Mir2Lir::CallRuntimeHelperRegLocationImm(int helper_offset, RegLocation arg0, int arg1,
107 bool safepoint_pc) {
108 int r_tgt = CallHelperSetup(helper_offset);
109 LoadValueDirectFixed(arg0, TargetReg(kArg0));
110 LoadConstant(TargetReg(kArg1), arg1);
111 ClobberCalleeSave();
112 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800113}
114
buzbee1fd33462013-03-25 13:40:45 -0700115void Mir2Lir::CallRuntimeHelperImmReg(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800116 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700117 int r_tgt = CallHelperSetup(helper_offset);
118 OpRegCopy(TargetReg(kArg1), arg1);
119 LoadConstant(TargetReg(kArg0), arg0);
120 ClobberCalleeSave();
121 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800122}
123
buzbee1fd33462013-03-25 13:40:45 -0700124void Mir2Lir::CallRuntimeHelperRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800125 bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700126 int r_tgt = CallHelperSetup(helper_offset);
127 OpRegCopy(TargetReg(kArg0), arg0);
128 LoadConstant(TargetReg(kArg1), arg1);
129 ClobberCalleeSave();
130 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800131}
132
buzbee1fd33462013-03-25 13:40:45 -0700133void Mir2Lir::CallRuntimeHelperImmMethod(int helper_offset, int arg0, bool safepoint_pc) {
134 int r_tgt = CallHelperSetup(helper_offset);
135 LoadCurrMethodDirect(TargetReg(kArg1));
136 LoadConstant(TargetReg(kArg0), arg0);
137 ClobberCalleeSave();
138 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800139}
140
buzbee1fd33462013-03-25 13:40:45 -0700141void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(int helper_offset, RegLocation arg0,
142 RegLocation arg1, bool safepoint_pc) {
143 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800144 if (arg0.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700145 LoadValueDirectFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0));
buzbee02031b12012-11-23 09:41:35 -0800146 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700147 if (cu_->instruction_set == kMips) {
148 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800149 } else {
buzbee1fd33462013-03-25 13:40:45 -0700150 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800151 }
152 } else {
buzbee1fd33462013-03-25 13:40:45 -0700153 if (cu_->instruction_set == kMips) {
154 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg1), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800155 } else {
buzbee1fd33462013-03-25 13:40:45 -0700156 LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800157 }
158 }
159 } else {
buzbee1fd33462013-03-25 13:40:45 -0700160 LoadValueDirectWideFixed(arg0, arg0.fp ? TargetReg(kFArg0) : TargetReg(kArg0), arg0.fp ? TargetReg(kFArg1) : TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800161 if (arg1.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700162 LoadValueDirectFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800163 } else {
buzbee1fd33462013-03-25 13:40:45 -0700164 LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800165 }
166 }
buzbee1fd33462013-03-25 13:40:45 -0700167 ClobberCalleeSave();
168 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800169}
170
buzbee1fd33462013-03-25 13:40:45 -0700171void Mir2Lir::CallRuntimeHelperRegReg(int helper_offset, int arg0, int arg1, bool safepoint_pc) {
172 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800173 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700174 OpRegCopy(TargetReg(kArg0), arg0);
175 OpRegCopy(TargetReg(kArg1), arg1);
176 ClobberCalleeSave();
177 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800178}
179
buzbee1fd33462013-03-25 13:40:45 -0700180void Mir2Lir::CallRuntimeHelperRegRegImm(int helper_offset, int arg0, int arg1,
buzbee02031b12012-11-23 09:41:35 -0800181 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700182 int r_tgt = CallHelperSetup(helper_offset);
buzbee02031b12012-11-23 09:41:35 -0800183 DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1
buzbee1fd33462013-03-25 13:40:45 -0700184 OpRegCopy(TargetReg(kArg0), arg0);
185 OpRegCopy(TargetReg(kArg1), arg1);
186 LoadConstant(TargetReg(kArg2), arg2);
187 ClobberCalleeSave();
188 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800189}
190
buzbee1fd33462013-03-25 13:40:45 -0700191void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800192 int arg0, RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700193 int r_tgt = CallHelperSetup(helper_offset);
194 LoadValueDirectFixed(arg2, TargetReg(kArg2));
195 LoadCurrMethodDirect(TargetReg(kArg1));
196 LoadConstant(TargetReg(kArg0), arg0);
197 ClobberCalleeSave();
198 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800199}
200
buzbee1fd33462013-03-25 13:40:45 -0700201void Mir2Lir::CallRuntimeHelperImmMethodImm(int helper_offset, int arg0,
buzbee02031b12012-11-23 09:41:35 -0800202 int arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700203 int r_tgt = CallHelperSetup(helper_offset);
204 LoadCurrMethodDirect(TargetReg(kArg1));
205 LoadConstant(TargetReg(kArg2), arg2);
206 LoadConstant(TargetReg(kArg0), arg0);
207 ClobberCalleeSave();
208 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800209}
210
buzbee1fd33462013-03-25 13:40:45 -0700211void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(int helper_offset,
buzbee02031b12012-11-23 09:41:35 -0800212 int arg0, RegLocation arg1,
213 RegLocation arg2, bool safepoint_pc) {
buzbee1fd33462013-03-25 13:40:45 -0700214 int r_tgt = CallHelperSetup(helper_offset);
215 LoadValueDirectFixed(arg1, TargetReg(kArg1));
buzbee02031b12012-11-23 09:41:35 -0800216 if (arg2.wide == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700217 LoadValueDirectFixed(arg2, TargetReg(kArg2));
buzbee02031b12012-11-23 09:41:35 -0800218 } else {
buzbee1fd33462013-03-25 13:40:45 -0700219 LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
buzbee02031b12012-11-23 09:41:35 -0800220 }
buzbee1fd33462013-03-25 13:40:45 -0700221 LoadConstant(TargetReg(kArg0), arg0);
222 ClobberCalleeSave();
223 CallHelper(r_tgt, helper_offset, safepoint_pc);
buzbee02031b12012-11-23 09:41:35 -0800224}
225
226/*
buzbee31a4a6f2012-02-28 15:36:15 -0800227 * If there are any ins passed in registers that have not been promoted
228 * to a callee-save register, flush them to the frame. Perform intial
229 * assignment of promoted arguments.
buzbeead8f15e2012-06-18 14:49:45 -0700230 *
buzbee52a77fc2012-11-20 19:50:46 -0800231 * ArgLocs is an array of location records describing the incoming arguments
buzbeead8f15e2012-06-18 14:49:45 -0700232 * with one location record per word of argument.
buzbee31a4a6f2012-02-28 15:36:15 -0800233 */
buzbee1fd33462013-03-25 13:40:45 -0700234void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method)
buzbee31a4a6f2012-02-28 15:36:15 -0800235{
Bill Buzbeea114add2012-05-03 15:00:40 -0700236 /*
237 * Dummy up a RegLocation for the incoming Method*
buzbeef0504cd2012-11-13 16:31:10 -0800238 * It will attempt to keep kArg0 live (or copy it to home location
Bill Buzbeea114add2012-05-03 15:00:40 -0700239 * if promoted).
240 */
buzbeefa57c472012-11-21 12:06:18 -0800241 RegLocation rl_src = rl_method;
242 rl_src.location = kLocPhysReg;
243 rl_src.low_reg = TargetReg(kArg0);
244 rl_src.home = false;
buzbee1fd33462013-03-25 13:40:45 -0700245 MarkLive(rl_src.low_reg, rl_src.s_reg_low);
246 StoreValue(rl_method, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -0700247 // If Method* has been promoted, explicitly flush
buzbeefa57c472012-11-21 12:06:18 -0800248 if (rl_method.location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700249 StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700250 }
buzbee9c044ce2012-03-18 13:24:07 -0700251
buzbee1fd33462013-03-25 13:40:45 -0700252 if (cu_->num_ins == 0)
Bill Buzbeea114add2012-05-03 15:00:40 -0700253 return;
buzbeefa57c472012-11-21 12:06:18 -0800254 const int num_arg_regs = 3;
255 static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
buzbee1fd33462013-03-25 13:40:45 -0700256 int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
Bill Buzbeea114add2012-05-03 15:00:40 -0700257 /*
258 * Copy incoming arguments to their proper home locations.
259 * NOTE: an older version of dx had an issue in which
260 * it would reuse static method argument registers.
261 * This could result in the same Dalvik virtual register
262 * being promoted to both core and fp regs. To account for this,
263 * we only copy to the corresponding promoted physical register
264 * if it matches the type of the SSA name for the incoming
265 * argument. It is also possible that long and double arguments
266 * end up half-promoted. In those cases, we must flush the promoted
267 * half to memory as well.
268 */
buzbee1fd33462013-03-25 13:40:45 -0700269 for (int i = 0; i < cu_->num_ins; i++) {
270 PromotionMap* v_map = &promotion_map_[start_vreg + i];
buzbeefa57c472012-11-21 12:06:18 -0800271 if (i < num_arg_regs) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700272 // If arriving in register
buzbeefa57c472012-11-21 12:06:18 -0800273 bool need_flush = true;
274 RegLocation* t_loc = &ArgLocs[i];
275 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700276 OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800277 need_flush = false;
278 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
buzbee1fd33462013-03-25 13:40:45 -0700279 OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
buzbeefa57c472012-11-21 12:06:18 -0800280 need_flush = false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700281 } else {
buzbeefa57c472012-11-21 12:06:18 -0800282 need_flush = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700283 }
buzbee86a4bce2012-03-06 18:15:00 -0800284
Bill Buzbeea114add2012-05-03 15:00:40 -0700285 // For wide args, force flush if only half is promoted
buzbeefa57c472012-11-21 12:06:18 -0800286 if (t_loc->wide) {
287 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1);
288 need_flush |= (p_map->core_location != v_map->core_location) ||
289 (p_map->fp_location != v_map->fp_location);
Bill Buzbeea114add2012-05-03 15:00:40 -0700290 }
buzbeefa57c472012-11-21 12:06:18 -0800291 if (need_flush) {
buzbee1fd33462013-03-25 13:40:45 -0700292 StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800293 TargetReg(arg_regs[i]), kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700294 }
295 } else {
296 // If arriving in frame & promoted
buzbeefa57c472012-11-21 12:06:18 -0800297 if (v_map->core_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700298 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800299 v_map->core_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700300 }
buzbeefa57c472012-11-21 12:06:18 -0800301 if (v_map->fp_location == kLocPhysReg) {
buzbee1fd33462013-03-25 13:40:45 -0700302 LoadWordDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
buzbeefa57c472012-11-21 12:06:18 -0800303 v_map->FpReg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700304 }
buzbee31a4a6f2012-02-28 15:36:15 -0800305 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700306 }
buzbee31a4a6f2012-02-28 15:36:15 -0800307}
308
309/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700310 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800311 * emit the next instruction in static & direct invoke sequences.
312 */
buzbeefa57c472012-11-21 12:06:18 -0800313static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700314 int state, const CompilerDriver::MethodReference& target_method,
315 uint32_t unused,
buzbeefa57c472012-11-21 12:06:18 -0800316 uintptr_t direct_code, uintptr_t direct_method,
buzbeeaad94382012-11-21 07:40:50 -0800317 InvokeType type)
buzbee31a4a6f2012-02-28 15:36:15 -0800318{
buzbee1fd33462013-03-25 13:40:45 -0700319 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800320 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700321 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800322 direct_code = 0;
323 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700324 }
buzbeefa57c472012-11-21 12:06:18 -0800325 if (direct_code != 0 && direct_method != 0) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700326 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800327 case 0: // Get the current Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800328 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700329 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700330 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700331 CHECK_EQ(cu->dex_file, target_method.dex_file);
332 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
333 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800334 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700335 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800336 data_target->operands[1] = type;
Ian Rogers2ed3b952012-03-17 11:49:39 -0700337 }
buzbee1fd33462013-03-25 13:40:45 -0700338 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
339 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800340 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700341 }
buzbeefa57c472012-11-21 12:06:18 -0800342 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700343 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Bill Buzbeea114add2012-05-03 15:00:40 -0700344 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700345 CHECK_EQ(cu->dex_file, target_method.dex_file);
346 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
347 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800348 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700349 data_target = cg->AddWordData(&cg->method_literal_list_, target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800350 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700351 }
buzbee1fd33462013-03-25 13:40:45 -0700352 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
353 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800354 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700355 }
356 break;
357 default:
358 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800359 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700360 } else {
361 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800362 case 0: // Get the current Method* [sets kArg0]
Ian Rogers137e88f2012-10-08 17:46:47 -0700363 // TUNING: we can save a reg copy if Method* has been promoted.
buzbee1fd33462013-03-25 13:40:45 -0700364 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700365 break;
366 case 1: // Get method->dex_cache_resolved_methods_
buzbee1fd33462013-03-25 13:40:45 -0700367 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800368 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700369 // Set up direct code if known.
buzbeefa57c472012-11-21 12:06:18 -0800370 if (direct_code != 0) {
371 if (direct_code != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700372 cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code);
Bill Buzbeea114add2012-05-03 15:00:40 -0700373 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700374 CHECK_EQ(cu->dex_file, target_method.dex_file);
375 LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_,
376 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800377 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700378 data_target = cg->AddWordData(&cg->code_literal_list_, target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800379 data_target->operands[1] = type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700380 }
buzbee1fd33462013-03-25 13:40:45 -0700381 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kInvokeTgt), data_target);
382 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800383 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Bill Buzbeea114add2012-05-03 15:00:40 -0700384 }
385 }
386 break;
387 case 2: // Grab target method*
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700388 CHECK_EQ(cu->dex_file, target_method.dex_file);
buzbee1fd33462013-03-25 13:40:45 -0700389 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700390 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
391 (target_method.dex_method_index * 4),
buzbee02031b12012-11-23 09:41:35 -0800392 cg-> TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700393 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700394 case 3: // Grab the code from the method*
buzbeefa57c472012-11-21 12:06:18 -0800395 if (cu->instruction_set != kX86) {
396 if (direct_code == 0) {
buzbee1fd33462013-03-25 13:40:45 -0700397 cg->LoadWordDisp(cg->TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -0700398 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800399 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700400 }
401 break;
Bill Buzbeea114add2012-05-03 15:00:40 -0700402 }
buzbeeb046e162012-10-30 15:48:42 -0700403 // Intentional fallthrough for x86
Bill Buzbeea114add2012-05-03 15:00:40 -0700404 default:
405 return -1;
406 }
407 }
408 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800409}
410
411/*
Elliott Hughesbdf6c3d2012-03-20 13:43:53 -0700412 * Bit of a hack here - in the absence of a real scheduling pass,
buzbee31a4a6f2012-02-28 15:36:15 -0800413 * emit the next instruction in a virtual invoke sequence.
buzbeef0504cd2012-11-13 16:31:10 -0800414 * We can use kLr as a temp prior to target address loading
buzbee31a4a6f2012-02-28 15:36:15 -0800415 * Note also that we'll load the first argument ("this") into
buzbee52a77fc2012-11-20 19:50:46 -0800416 * kArg1 here rather than the standard LoadArgRegs.
buzbee31a4a6f2012-02-28 15:36:15 -0800417 */
buzbeefa57c472012-11-21 12:06:18 -0800418static int NextVCallInsn(CompilationUnit* cu, CallInfo* info,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700419 int state, const CompilerDriver::MethodReference& target_method,
420 uint32_t method_idx, uintptr_t unused, uintptr_t unused2,
421 InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800422{
buzbee1fd33462013-03-25 13:40:45 -0700423 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700424 /*
425 * This is the fast path in which the target virtual method is
426 * fully resolved at compile time.
427 */
428 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800429 case 0: { // Get "this" [set kArg1]
buzbeefa57c472012-11-21 12:06:18 -0800430 RegLocation rl_arg = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700431 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700432 break;
Ian Rogers137e88f2012-10-08 17:46:47 -0700433 }
buzbeef0504cd2012-11-13 16:31:10 -0800434 case 1: // Is "this" null? [use kArg1]
buzbee1fd33462013-03-25 13:40:45 -0700435 cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags);
buzbeef0504cd2012-11-13 16:31:10 -0800436 // get this->klass_ [use kArg1, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700437 cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800438 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700439 break;
buzbeef0504cd2012-11-13 16:31:10 -0800440 case 2: // Get this->klass_->vtable [usr kInvokeTgt, set kInvokeTgt]
buzbee1fd33462013-03-25 13:40:45 -0700441 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::VTableOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800442 cg->TargetReg(kInvokeTgt));
Bill Buzbeea114add2012-05-03 15:00:40 -0700443 break;
buzbeef0504cd2012-11-13 16:31:10 -0800444 case 3: // Get target method [use kInvokeTgt, set kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700445 cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), (method_idx * 4) +
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800446 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(),
447 cg->TargetReg(kArg0));
Bill Buzbeea114add2012-05-03 15:00:40 -0700448 break;
buzbeef0504cd2012-11-13 16:31:10 -0800449 case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt]
buzbeefa57c472012-11-21 12:06:18 -0800450 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700451 cg->LoadWordDisp(cg->TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -0700452 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800453 cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700454 break;
455 }
456 // Intentional fallthrough for X86
Bill Buzbeea114add2012-05-03 15:00:40 -0700457 default:
458 return -1;
459 }
460 return state + 1;
buzbee31a4a6f2012-02-28 15:36:15 -0800461}
462
Ian Rogers137e88f2012-10-08 17:46:47 -0700463/*
Logan Chien8dbb7082013-01-25 20:31:17 +0800464 * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline,
Ian Rogers137e88f2012-10-08 17:46:47 -0700465 * which will locate the target and continue on via a tail call.
466 */
buzbeefa57c472012-11-21 12:06:18 -0800467static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700468 const CompilerDriver::MethodReference& target_method,
469 uint32_t unused, uintptr_t unused2,
buzbeefa57c472012-11-21 12:06:18 -0800470 uintptr_t direct_method, InvokeType unused4)
Ian Rogers137e88f2012-10-08 17:46:47 -0700471{
buzbee1fd33462013-03-25 13:40:45 -0700472 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
buzbeefa57c472012-11-21 12:06:18 -0800473 if (cu->instruction_set != kThumb2) {
buzbeeb046e162012-10-30 15:48:42 -0700474 // Disable sharpening
buzbeefa57c472012-11-21 12:06:18 -0800475 direct_method = 0;
buzbeeb046e162012-10-30 15:48:42 -0700476 }
buzbeefa57c472012-11-21 12:06:18 -0800477 int trampoline = (cu->instruction_set == kX86) ? 0
buzbeeb046e162012-10-30 15:48:42 -0700478 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
Ian Rogers137e88f2012-10-08 17:46:47 -0700479
buzbeefa57c472012-11-21 12:06:18 -0800480 if (direct_method != 0) {
Ian Rogers137e88f2012-10-08 17:46:47 -0700481 switch (state) {
buzbeef0504cd2012-11-13 16:31:10 -0800482 case 0: // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800483 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700484 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700485 }
buzbeef0504cd2012-11-13 16:31:10 -0800486 // Get the interface Method* [sets kArg0]
buzbeefa57c472012-11-21 12:06:18 -0800487 if (direct_method != static_cast<unsigned int>(-1)) {
buzbee1fd33462013-03-25 13:40:45 -0700488 cg->LoadConstant(cg->TargetReg(kArg0), direct_method);
Ian Rogers137e88f2012-10-08 17:46:47 -0700489 } else {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700490 CHECK_EQ(cu->dex_file, target_method.dex_file);
491 LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_,
492 target_method.dex_method_index, 0);
buzbeefa57c472012-11-21 12:06:18 -0800493 if (data_target == NULL) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700494 data_target = cg->AddWordData(&cg->method_literal_list_,
495 target_method.dex_method_index);
buzbeefa57c472012-11-21 12:06:18 -0800496 data_target->operands[1] = kInterface;
Ian Rogers137e88f2012-10-08 17:46:47 -0700497 }
buzbee1fd33462013-03-25 13:40:45 -0700498 LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target);
499 cg->AppendLIR(load_pc_rel);
buzbeefa57c472012-11-21 12:06:18 -0800500 DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target);
Ian Rogers137e88f2012-10-08 17:46:47 -0700501 }
502 break;
503 default:
504 return -1;
505 }
506 } else {
507 switch (state) {
508 case 0:
buzbeef0504cd2012-11-13 16:31:10 -0800509 // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted.
buzbee1fd33462013-03-25 13:40:45 -0700510 cg->LoadCurrMethodDirect(cg->TargetReg(kArg0));
buzbeef0504cd2012-11-13 16:31:10 -0800511 // Load the trampoline target [sets kInvokeTgt].
buzbeefa57c472012-11-21 12:06:18 -0800512 if (cu->instruction_set != kX86) {
buzbee1fd33462013-03-25 13:40:45 -0700513 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700514 }
Ian Rogers137e88f2012-10-08 17:46:47 -0700515 break;
buzbeef0504cd2012-11-13 16:31:10 -0800516 case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0]
buzbee1fd33462013-03-25 13:40:45 -0700517 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800518 mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
buzbee02031b12012-11-23 09:41:35 -0800519 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700520 break;
buzbeef0504cd2012-11-13 16:31:10 -0800521 case 2: // Grab target method* [set/use kArg0]
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700522 CHECK_EQ(cu->dex_file, target_method.dex_file);
buzbee1fd33462013-03-25 13:40:45 -0700523 cg->LoadWordDisp(cg->TargetReg(kArg0),
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700524 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
525 (target_method.dex_method_index * 4),
buzbee02031b12012-11-23 09:41:35 -0800526 cg->TargetReg(kArg0));
Ian Rogers137e88f2012-10-08 17:46:47 -0700527 break;
528 default:
529 return -1;
530 }
531 }
532 return state + 1;
533}
534
buzbeefa57c472012-11-21 12:06:18 -0800535static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, int trampoline,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700536 int state, const CompilerDriver::MethodReference& target_method,
537 uint32_t method_idx)
buzbee31a4a6f2012-02-28 15:36:15 -0800538{
buzbee1fd33462013-03-25 13:40:45 -0700539 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get());
Bill Buzbeea114add2012-05-03 15:00:40 -0700540 /*
541 * This handles the case in which the base method is not fully
542 * resolved at compile time, we bail to a runtime helper.
543 */
544 if (state == 0) {
buzbeefa57c472012-11-21 12:06:18 -0800545 if (cu->instruction_set != kX86) {
buzbeeb046e162012-10-30 15:48:42 -0700546 // Load trampoline target
buzbee1fd33462013-03-25 13:40:45 -0700547 cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline, cg->TargetReg(kInvokeTgt));
buzbeeb046e162012-10-30 15:48:42 -0700548 }
buzbeef0504cd2012-11-13 16:31:10 -0800549 // Load kArg0 with method index
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700550 CHECK_EQ(cu->dex_file, target_method.dex_file);
551 cg->LoadConstant(cg->TargetReg(kArg0), target_method.dex_method_index);
Bill Buzbeea114add2012-05-03 15:00:40 -0700552 return 1;
553 }
554 return -1;
buzbee31a4a6f2012-02-28 15:36:15 -0800555}
556
buzbeefa57c472012-11-21 12:06:18 -0800557static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700558 int state,
559 const CompilerDriver::MethodReference& target_method,
560 uint32_t method_idx,
buzbeeaad94382012-11-21 07:40:50 -0800561 uintptr_t unused, uintptr_t unused2,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700562 InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800563{
Ian Rogers57b86d42012-03-27 16:05:41 -0700564 int trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700565 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800566}
567
buzbeefa57c472012-11-21 12:06:18 -0800568static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700569 const CompilerDriver::MethodReference& target_method,
570 uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800571 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800572{
Ian Rogers57b86d42012-03-27 16:05:41 -0700573 int trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700574 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800575}
576
buzbeefa57c472012-11-21 12:06:18 -0800577static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700578 const CompilerDriver::MethodReference& target_method,
579 uint32_t method_idx, uintptr_t unused,
580 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800581{
Ian Rogers57b86d42012-03-27 16:05:41 -0700582 int trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700583 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800584}
585
buzbeefa57c472012-11-21 12:06:18 -0800586static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700587 const CompilerDriver::MethodReference& target_method,
588 uint32_t method_idx, uintptr_t unused,
buzbeeaad94382012-11-21 07:40:50 -0800589 uintptr_t unused2, InvokeType unused3)
buzbee31a4a6f2012-02-28 15:36:15 -0800590{
Ian Rogers57b86d42012-03-27 16:05:41 -0700591 int trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700592 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800593}
594
buzbeefa57c472012-11-21 12:06:18 -0800595static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu,
buzbeeaad94382012-11-21 07:40:50 -0800596 CallInfo* info, int state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700597 const CompilerDriver::MethodReference& target_method,
598 uint32_t unused,
599 uintptr_t unused2, uintptr_t unused3,
600 InvokeType unused4)
buzbee31a4a6f2012-02-28 15:36:15 -0800601{
Ian Rogers57b86d42012-03-27 16:05:41 -0700602 int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700603 return NextInvokeInsnSP(cu, info, trampoline, state, target_method, 0);
buzbee31a4a6f2012-02-28 15:36:15 -0800604}
605
buzbee1fd33462013-03-25 13:40:45 -0700606int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700607 NextCallInsn next_call_insn,
608 const CompilerDriver::MethodReference& target_method,
609 uint32_t vtable_idx, uintptr_t direct_code,
buzbee1fd33462013-03-25 13:40:45 -0700610 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800611{
buzbee1fd33462013-03-25 13:40:45 -0700612 int last_arg_reg = TargetReg(kArg3);
613 int next_reg = TargetReg(kArg1);
buzbeefa57c472012-11-21 12:06:18 -0800614 int next_arg = 0;
615 if (skip_this) {
616 next_reg++;
617 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700618 }
buzbeefa57c472012-11-21 12:06:18 -0800619 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) {
620 RegLocation rl_arg = info->args[next_arg++];
buzbee1fd33462013-03-25 13:40:45 -0700621 rl_arg = UpdateRawLoc(rl_arg);
622 if (rl_arg.wide && (next_reg <= TargetReg(kArg2))) {
623 LoadValueDirectWideFixed(rl_arg, next_reg, next_reg + 1);
buzbeefa57c472012-11-21 12:06:18 -0800624 next_reg++;
625 next_arg++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700626 } else {
buzbeee6285f92012-12-06 15:57:46 -0800627 if (rl_arg.wide) {
628 rl_arg.wide = false;
629 rl_arg.is_const = false;
630 }
buzbee1fd33462013-03-25 13:40:45 -0700631 LoadValueDirectFixed(rl_arg, next_reg);
buzbee31a4a6f2012-02-28 15:36:15 -0800632 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700633 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
634 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700635 }
buzbeefa57c472012-11-21 12:06:18 -0800636 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800637}
638
639/*
640 * Load up to 5 arguments, the first three of which will be in
buzbeef0504cd2012-11-13 16:31:10 -0800641 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer,
buzbee31a4a6f2012-02-28 15:36:15 -0800642 * and as part of the load sequence, it must be replaced with
643 * the target method pointer. Note, this may also be called
644 * for "range" variants if the number of arguments is 5 or fewer.
645 */
buzbee1fd33462013-03-25 13:40:45 -0700646int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
buzbee02031b12012-11-23 09:41:35 -0800647 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700648 const CompilerDriver::MethodReference& target_method,
649 uint32_t vtable_idx, uintptr_t direct_code,
buzbee02031b12012-11-23 09:41:35 -0800650 uintptr_t direct_method, InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800651{
buzbeefa57c472012-11-21 12:06:18 -0800652 RegLocation rl_arg;
buzbee31a4a6f2012-02-28 15:36:15 -0800653
Bill Buzbeea114add2012-05-03 15:00:40 -0700654 /* If no arguments, just return */
buzbeefa57c472012-11-21 12:06:18 -0800655 if (info->num_arg_words == 0)
656 return call_state;
Bill Buzbeea114add2012-05-03 15:00:40 -0700657
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700658 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
659 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700660
buzbeefa57c472012-11-21 12:06:18 -0800661 DCHECK_LE(info->num_arg_words, 5);
662 if (info->num_arg_words > 3) {
663 int32_t next_use = 3;
Bill Buzbeea114add2012-05-03 15:00:40 -0700664 //Detect special case of wide arg spanning arg3/arg4
buzbeefa57c472012-11-21 12:06:18 -0800665 RegLocation rl_use0 = info->args[0];
666 RegLocation rl_use1 = info->args[1];
667 RegLocation rl_use2 = info->args[2];
668 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) &&
669 rl_use2.wide) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700670 int reg = -1;
671 // Wide spans, we need the 2nd half of uses[2].
buzbee1fd33462013-03-25 13:40:45 -0700672 rl_arg = UpdateLocWide(rl_use2);
buzbeefa57c472012-11-21 12:06:18 -0800673 if (rl_arg.location == kLocPhysReg) {
674 reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700675 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800676 // kArg2 & rArg3 can safely be used here
buzbee52a77fc2012-11-20 19:50:46 -0800677 reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700678 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700679 call_state = next_call_insn(cu_, info, call_state, target_method,
680 vtable_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700681 }
buzbee1fd33462013-03-25 13:40:45 -0700682 StoreBaseDisp(TargetReg(kSp), (next_use + 1) * 4, reg, kWord);
683 StoreBaseDisp(TargetReg(kSp), 16 /* (3+1)*4 */, reg, kWord);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700684 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
685 direct_code, direct_method, type);
buzbeefa57c472012-11-21 12:06:18 -0800686 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700687 }
688 // Loop through the rest
buzbeefa57c472012-11-21 12:06:18 -0800689 while (next_use < info->num_arg_words) {
690 int low_reg;
691 int high_reg = -1;
692 rl_arg = info->args[next_use];
buzbee1fd33462013-03-25 13:40:45 -0700693 rl_arg = UpdateRawLoc(rl_arg);
buzbeefa57c472012-11-21 12:06:18 -0800694 if (rl_arg.location == kLocPhysReg) {
695 low_reg = rl_arg.low_reg;
696 high_reg = rl_arg.high_reg;
Bill Buzbeea114add2012-05-03 15:00:40 -0700697 } else {
buzbeefa57c472012-11-21 12:06:18 -0800698 low_reg = TargetReg(kArg2);
699 if (rl_arg.wide) {
700 high_reg = TargetReg(kArg3);
buzbee1fd33462013-03-25 13:40:45 -0700701 LoadValueDirectWideFixed(rl_arg, low_reg, high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700702 } else {
buzbee1fd33462013-03-25 13:40:45 -0700703 LoadValueDirectFixed(rl_arg, low_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700704 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700705 call_state = next_call_insn(cu_, info, call_state, target_method,
706 vtable_idx, direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700707 }
buzbeefa57c472012-11-21 12:06:18 -0800708 int outs_offset = (next_use + 1) * 4;
709 if (rl_arg.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700710 StoreBaseDispWide(TargetReg(kSp), outs_offset, low_reg, high_reg);
buzbeefa57c472012-11-21 12:06:18 -0800711 next_use += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700712 } else {
buzbee1fd33462013-03-25 13:40:45 -0700713 StoreWordDisp(TargetReg(kSp), outs_offset, low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800714 next_use++;
Bill Buzbeea114add2012-05-03 15:00:40 -0700715 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700716 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800717 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700718 }
719 }
720
buzbee1fd33462013-03-25 13:40:45 -0700721 call_state = LoadArgRegs(info, call_state, next_call_insn,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700722 target_method, vtable_idx, direct_code, direct_method,
723 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700724
725 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700726 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700727 }
buzbeefa57c472012-11-21 12:06:18 -0800728 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800729}
730
731/*
732 * May have 0+ arguments (also used for jumbo). Note that
733 * source virtual registers may be in physical registers, so may
734 * need to be flushed to home location before copying. This
735 * applies to arg3 and above (see below).
736 *
737 * Two general strategies:
738 * If < 20 arguments
739 * Pass args 3-18 using vldm/vstm block copy
buzbeef0504cd2012-11-13 16:31:10 -0800740 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800741 * If 20+ arguments
742 * Pass args arg19+ using memcpy block copy
buzbeef0504cd2012-11-13 16:31:10 -0800743 * Pass arg0, arg1 & arg2 in kArg1-kArg3
buzbee31a4a6f2012-02-28 15:36:15 -0800744 *
745 */
buzbee1fd33462013-03-25 13:40:45 -0700746int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700747 LIR** pcrLabel, NextCallInsn next_call_insn,
748 const CompilerDriver::MethodReference& target_method,
749 uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method,
buzbee02031b12012-11-23 09:41:35 -0800750 InvokeType type, bool skip_this)
buzbee31a4a6f2012-02-28 15:36:15 -0800751{
buzbee31a4a6f2012-02-28 15:36:15 -0800752
Bill Buzbeea114add2012-05-03 15:00:40 -0700753 // If we can treat it as non-range (Jumbo ops will use range form)
buzbeefa57c472012-11-21 12:06:18 -0800754 if (info->num_arg_words <= 5)
buzbee1fd33462013-03-25 13:40:45 -0700755 return GenDalvikArgsNoRange(info, call_state, pcrLabel,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700756 next_call_insn, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800757 direct_code, direct_method, type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700758 /*
Bill Buzbeea114add2012-05-03 15:00:40 -0700759 * First load the non-register arguments. Both forms expect all
760 * of the source arguments to be in their home frame location, so
buzbeefa57c472012-11-21 12:06:18 -0800761 * scan the s_reg names and flush any that have been promoted to
Bill Buzbeea114add2012-05-03 15:00:40 -0700762 * frame backing storage.
763 */
buzbeefa57c472012-11-21 12:06:18 -0800764 // Scan the rest of the args - if in phys_reg flush to memory
765 for (int next_arg = 0; next_arg < info->num_arg_words;) {
766 RegLocation loc = info->args[next_arg];
Bill Buzbeea114add2012-05-03 15:00:40 -0700767 if (loc.wide) {
buzbee1fd33462013-03-25 13:40:45 -0700768 loc = UpdateLocWide(loc);
buzbeefa57c472012-11-21 12:06:18 -0800769 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700770 StoreBaseDispWide(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800771 loc.low_reg, loc.high_reg);
Bill Buzbeea114add2012-05-03 15:00:40 -0700772 }
buzbeefa57c472012-11-21 12:06:18 -0800773 next_arg += 2;
Bill Buzbeea114add2012-05-03 15:00:40 -0700774 } else {
buzbee1fd33462013-03-25 13:40:45 -0700775 loc = UpdateLoc(loc);
buzbeefa57c472012-11-21 12:06:18 -0800776 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1fd33462013-03-25 13:40:45 -0700777 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low),
buzbeefa57c472012-11-21 12:06:18 -0800778 loc.low_reg, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700779 }
buzbeefa57c472012-11-21 12:06:18 -0800780 next_arg++;
buzbee31a4a6f2012-02-28 15:36:15 -0800781 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700782 }
buzbee31a4a6f2012-02-28 15:36:15 -0800783
buzbee1fd33462013-03-25 13:40:45 -0700784 int start_offset = SRegOffset(info->args[3].s_reg_low);
buzbeefa57c472012-11-21 12:06:18 -0800785 int outs_offset = 4 /* Method* */ + (3 * 4);
buzbee1fd33462013-03-25 13:40:45 -0700786 if (cu_->instruction_set != kThumb2) {
buzbee31a4a6f2012-02-28 15:36:15 -0800787 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700788 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
789 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
790 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800791 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700792 } else {
buzbeefa57c472012-11-21 12:06:18 -0800793 if (info->num_arg_words >= 20) {
buzbeeb046e162012-10-30 15:48:42 -0700794 // Generate memcpy
buzbee1fd33462013-03-25 13:40:45 -0700795 OpRegRegImm(kOpAdd, TargetReg(kArg0), TargetReg(kSp), outs_offset);
796 OpRegRegImm(kOpAdd, TargetReg(kArg1), TargetReg(kSp), start_offset);
797 CallRuntimeHelperRegRegImm(ENTRYPOINT_OFFSET(pMemcpy), TargetReg(kArg0),
buzbeefa57c472012-11-21 12:06:18 -0800798 TargetReg(kArg1), (info->num_arg_words - 3) * 4, false);
buzbeeb046e162012-10-30 15:48:42 -0700799 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800800 // Use vldm/vstm pair using kArg3 as a temp
buzbeefa57c472012-11-21 12:06:18 -0800801 int regs_left = std::min(info->num_arg_words - 3, 16);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700802 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800803 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700804 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), start_offset);
805 LIR* ld = OpVldm(TargetReg(kArg3), regs_left);
buzbeeb046e162012-10-30 15:48:42 -0700806 //TUNING: loosen barrier
buzbeefa57c472012-11-21 12:06:18 -0800807 ld->def_mask = ENCODE_ALL;
buzbee1fd33462013-03-25 13:40:45 -0700808 SetMemRefType(ld, true /* is_load */, kDalvikReg);
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700809 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800810 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700811 OpRegRegImm(kOpAdd, TargetReg(kArg3), TargetReg(kSp), 4 /* Method* */ + (3 * 4));
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700812 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800813 direct_code, direct_method, type);
buzbee1fd33462013-03-25 13:40:45 -0700814 LIR* st = OpVstm(TargetReg(kArg3), regs_left);
815 SetMemRefType(st, false /* is_load */, kDalvikReg);
buzbeefa57c472012-11-21 12:06:18 -0800816 st->def_mask = ENCODE_ALL;
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700817 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800818 direct_code, direct_method, type);
buzbeeb046e162012-10-30 15:48:42 -0700819 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700820 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700821
buzbee1fd33462013-03-25 13:40:45 -0700822 call_state = LoadArgRegs(info, call_state, next_call_insn,
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700823 target_method, vtable_idx, direct_code, direct_method,
824 type, skip_this);
Bill Buzbeea114add2012-05-03 15:00:40 -0700825
Ian Rogerse3cd2f02013-05-24 15:32:56 -0700826 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
buzbeefa57c472012-11-21 12:06:18 -0800827 direct_code, direct_method, type);
Bill Buzbeea114add2012-05-03 15:00:40 -0700828 if (pcrLabel) {
buzbee1fd33462013-03-25 13:40:45 -0700829 *pcrLabel = GenNullCheck(info->args[0].s_reg_low, TargetReg(kArg1), info->opt_flags);
Bill Buzbeea114add2012-05-03 15:00:40 -0700830 }
buzbeefa57c472012-11-21 12:06:18 -0800831 return call_state;
buzbee31a4a6f2012-02-28 15:36:15 -0800832}
833
buzbee1fd33462013-03-25 13:40:45 -0700834RegLocation Mir2Lir::InlineTarget(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700835{
Bill Buzbeea114add2012-05-03 15:00:40 -0700836 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700837 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700838 res = GetReturn(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700839 } else {
buzbee15bf9802012-06-12 17:49:27 -0700840 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700841 }
842 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700843}
844
buzbee1fd33462013-03-25 13:40:45 -0700845RegLocation Mir2Lir::InlineTargetWide(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700846{
Bill Buzbeea114add2012-05-03 15:00:40 -0700847 RegLocation res;
buzbee15bf9802012-06-12 17:49:27 -0700848 if (info->result.location == kLocInvalid) {
buzbee1fd33462013-03-25 13:40:45 -0700849 res = GetReturnWide(false);
Bill Buzbeea114add2012-05-03 15:00:40 -0700850 } else {
buzbee15bf9802012-06-12 17:49:27 -0700851 res = info->result;
Bill Buzbeea114add2012-05-03 15:00:40 -0700852 }
853 return res;
buzbeefc9e6fa2012-03-23 15:14:29 -0700854}
855
buzbee1fd33462013-03-25 13:40:45 -0700856bool Mir2Lir::GenInlinedCharAt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700857{
buzbee1fd33462013-03-25 13:40:45 -0700858 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700859 // TODO - add Mips implementation
860 return false;
861 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700862 // Location of reference to data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800863 int value_offset = mirror::String::ValueOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700864 // Location of count
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800865 int count_offset = mirror::String::CountOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700866 // Starting offset within data array
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800867 int offset_offset = mirror::String::OffsetOffset().Int32Value();
Bill Buzbeea114add2012-05-03 15:00:40 -0700868 // Start of char data with array_
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800869 int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value();
buzbeefc9e6fa2012-03-23 15:14:29 -0700870
buzbeefa57c472012-11-21 12:06:18 -0800871 RegLocation rl_obj = info->args[0];
872 RegLocation rl_idx = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -0700873 rl_obj = LoadValue(rl_obj, kCoreReg);
874 rl_idx = LoadValue(rl_idx, kCoreReg);
buzbeefa57c472012-11-21 12:06:18 -0800875 int reg_max;
buzbee1fd33462013-03-25 13:40:45 -0700876 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -0800877 bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK));
878 LIR* launch_pad = NULL;
879 int reg_off = INVALID_REG;
880 int reg_ptr = INVALID_REG;
buzbee1fd33462013-03-25 13:40:45 -0700881 if (cu_->instruction_set != kX86) {
882 reg_off = AllocTemp();
883 reg_ptr = AllocTemp();
buzbeefa57c472012-11-21 12:06:18 -0800884 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700885 reg_max = AllocTemp();
886 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700887 }
buzbee1fd33462013-03-25 13:40:45 -0700888 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
889 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
buzbeefa57c472012-11-21 12:06:18 -0800890 if (range_check) {
buzbeeb046e162012-10-30 15:48:42 -0700891 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700892 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700893 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700894 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
895 FreeTemp(reg_max);
896 OpCondBranch(kCondCs, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700897 }
898 } else {
buzbeefa57c472012-11-21 12:06:18 -0800899 if (range_check) {
buzbee1fd33462013-03-25 13:40:45 -0700900 reg_max = AllocTemp();
901 LoadWordDisp(rl_obj.low_reg, count_offset, reg_max);
buzbeeb046e162012-10-30 15:48:42 -0700902 // Set up a launch pad to allow retry in case of bounds violation */
buzbee1fd33462013-03-25 13:40:45 -0700903 launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -0700904 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -0700905 OpRegReg(kOpCmp, rl_idx.low_reg, reg_max);
906 FreeTemp(reg_max);
907 OpCondBranch(kCondCc, launch_pad);
buzbeeb046e162012-10-30 15:48:42 -0700908 }
buzbee1fd33462013-03-25 13:40:45 -0700909 reg_off = AllocTemp();
910 reg_ptr = AllocTemp();
911 LoadWordDisp(rl_obj.low_reg, offset_offset, reg_off);
912 LoadWordDisp(rl_obj.low_reg, value_offset, reg_ptr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700913 }
buzbee1fd33462013-03-25 13:40:45 -0700914 OpRegImm(kOpAdd, reg_ptr, data_offset);
915 OpRegReg(kOpAdd, reg_off, rl_idx.low_reg);
916 FreeTemp(rl_obj.low_reg);
917 FreeTemp(rl_idx.low_reg);
918 RegLocation rl_dest = InlineTarget(info);
919 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
920 LoadBaseIndexed(reg_ptr, reg_off, rl_result.low_reg, 1, kUnsignedHalf);
921 FreeTemp(reg_off);
922 FreeTemp(reg_ptr);
923 StoreValue(rl_dest, rl_result);
buzbeefa57c472012-11-21 12:06:18 -0800924 if (range_check) {
925 launch_pad->operands[2] = 0; // no resumption
Bill Buzbeea114add2012-05-03 15:00:40 -0700926 }
927 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -0800928 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
Bill Buzbeea114add2012-05-03 15:00:40 -0700929 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700930}
931
buzbeefa57c472012-11-21 12:06:18 -0800932// Generates an inlined String.is_empty or String.length.
buzbee1fd33462013-03-25 13:40:45 -0700933bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty)
buzbeefc9e6fa2012-03-23 15:14:29 -0700934{
buzbee1fd33462013-03-25 13:40:45 -0700935 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700936 // TODO - add Mips implementation
937 return false;
938 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700939 // dst = src.length();
buzbeefa57c472012-11-21 12:06:18 -0800940 RegLocation rl_obj = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700941 rl_obj = LoadValue(rl_obj, kCoreReg);
942 RegLocation rl_dest = InlineTarget(info);
943 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
944 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, info->opt_flags);
945 LoadWordDisp(rl_obj.low_reg, mirror::String::CountOffset().Int32Value(), rl_result.low_reg);
buzbeefa57c472012-11-21 12:06:18 -0800946 if (is_empty) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700947 // dst = (dst == 0);
buzbee1fd33462013-03-25 13:40:45 -0700948 if (cu_->instruction_set == kThumb2) {
949 int t_reg = AllocTemp();
950 OpRegReg(kOpNeg, t_reg, rl_result.low_reg);
951 OpRegRegReg(kOpAdc, rl_result.low_reg, rl_result.low_reg, t_reg);
buzbeeb046e162012-10-30 15:48:42 -0700952 } else {
buzbee1fd33462013-03-25 13:40:45 -0700953 DCHECK_EQ(cu_->instruction_set, kX86);
954 OpRegImm(kOpSub, rl_result.low_reg, 1);
955 OpRegImm(kOpLsr, rl_result.low_reg, 31);
buzbeeb046e162012-10-30 15:48:42 -0700956 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700957 }
buzbee1fd33462013-03-25 13:40:45 -0700958 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700959 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700960}
961
buzbee1fd33462013-03-25 13:40:45 -0700962bool Mir2Lir::GenInlinedAbsInt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700963{
buzbee1fd33462013-03-25 13:40:45 -0700964 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700965 // TODO - add Mips implementation
966 return false;
967 }
buzbeefa57c472012-11-21 12:06:18 -0800968 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700969 rl_src = LoadValue(rl_src, kCoreReg);
970 RegLocation rl_dest = InlineTarget(info);
971 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
972 int sign_reg = AllocTemp();
Bill Buzbeea114add2012-05-03 15:00:40 -0700973 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700974 OpRegRegImm(kOpAsr, sign_reg, rl_src.low_reg, 31);
975 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
976 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
977 StoreValue(rl_dest, rl_result);
Bill Buzbeea114add2012-05-03 15:00:40 -0700978 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -0700979}
980
buzbee1fd33462013-03-25 13:40:45 -0700981bool Mir2Lir::GenInlinedAbsLong(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -0700982{
buzbee1fd33462013-03-25 13:40:45 -0700983 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -0700984 // TODO - add Mips implementation
985 return false;
986 }
buzbee1fd33462013-03-25 13:40:45 -0700987 if (cu_->instruction_set == kThumb2) {
buzbeefa57c472012-11-21 12:06:18 -0800988 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -0700989 rl_src = LoadValueWide(rl_src, kCoreReg);
990 RegLocation rl_dest = InlineTargetWide(info);
991 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
992 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -0700993 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -0700994 OpRegRegImm(kOpAsr, sign_reg, rl_src.high_reg, 31);
995 OpRegRegReg(kOpAdd, rl_result.low_reg, rl_src.low_reg, sign_reg);
996 OpRegRegReg(kOpAdc, rl_result.high_reg, rl_src.high_reg, sign_reg);
997 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
998 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
999 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001000 return true;
1001 } else {
buzbee1fd33462013-03-25 13:40:45 -07001002 DCHECK_EQ(cu_->instruction_set, kX86);
buzbeeb046e162012-10-30 15:48:42 -07001003 // Reuse source registers to avoid running out of temps
buzbeefa57c472012-11-21 12:06:18 -08001004 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001005 rl_src = LoadValueWide(rl_src, kCoreReg);
1006 RegLocation rl_dest = InlineTargetWide(info);
1007 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
1008 OpRegCopyWide(rl_result.low_reg, rl_result.high_reg, rl_src.low_reg, rl_src.high_reg);
1009 FreeTemp(rl_src.low_reg);
1010 FreeTemp(rl_src.high_reg);
1011 int sign_reg = AllocTemp();
buzbeeb046e162012-10-30 15:48:42 -07001012 // abs(x) = y<=x>>31, (x+y)^y.
buzbee1fd33462013-03-25 13:40:45 -07001013 OpRegRegImm(kOpAsr, sign_reg, rl_result.high_reg, 31);
1014 OpRegReg(kOpAdd, rl_result.low_reg, sign_reg);
1015 OpRegReg(kOpAdc, rl_result.high_reg, sign_reg);
1016 OpRegReg(kOpXor, rl_result.low_reg, sign_reg);
1017 OpRegReg(kOpXor, rl_result.high_reg, sign_reg);
1018 StoreValueWide(rl_dest, rl_result);
buzbeeb046e162012-10-30 15:48:42 -07001019 return true;
1020 }
buzbeefc9e6fa2012-03-23 15:14:29 -07001021}
1022
buzbee1fd33462013-03-25 13:40:45 -07001023bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001024{
buzbee1fd33462013-03-25 13:40:45 -07001025 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001026 // TODO - add Mips implementation
1027 return false;
1028 }
buzbeefa57c472012-11-21 12:06:18 -08001029 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001030 RegLocation rl_dest = InlineTarget(info);
1031 StoreValue(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001032 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001033}
1034
buzbee1fd33462013-03-25 13:40:45 -07001035bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001036{
buzbee1fd33462013-03-25 13:40:45 -07001037 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001038 // TODO - add Mips implementation
1039 return false;
1040 }
buzbeefa57c472012-11-21 12:06:18 -08001041 RegLocation rl_src = info->args[0];
buzbee1fd33462013-03-25 13:40:45 -07001042 RegLocation rl_dest = InlineTargetWide(info);
1043 StoreValueWide(rl_dest, rl_src);
Bill Buzbeea114add2012-05-03 15:00:40 -07001044 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001045}
1046
1047/*
buzbeefa57c472012-11-21 12:06:18 -08001048 * Fast string.index_of(I) & (II). Tests for simple case of char <= 0xffff,
buzbeefc9e6fa2012-03-23 15:14:29 -07001049 * otherwise bails to standard library code.
1050 */
buzbee1fd33462013-03-25 13:40:45 -07001051bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based)
buzbeefc9e6fa2012-03-23 15:14:29 -07001052{
buzbee1fd33462013-03-25 13:40:45 -07001053 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001054 // TODO - add Mips implementation
1055 return false;
1056 }
buzbee1fd33462013-03-25 13:40:45 -07001057 ClobberCalleeSave();
1058 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001059 int reg_ptr = TargetReg(kArg0);
1060 int reg_char = TargetReg(kArg1);
1061 int reg_start = TargetReg(kArg2);
buzbeefc9e6fa2012-03-23 15:14:29 -07001062
buzbeefa57c472012-11-21 12:06:18 -08001063 RegLocation rl_obj = info->args[0];
1064 RegLocation rl_char = info->args[1];
1065 RegLocation rl_start = info->args[2];
buzbee1fd33462013-03-25 13:40:45 -07001066 LoadValueDirectFixed(rl_obj, reg_ptr);
1067 LoadValueDirectFixed(rl_char, reg_char);
buzbeefa57c472012-11-21 12:06:18 -08001068 if (zero_based) {
buzbee1fd33462013-03-25 13:40:45 -07001069 LoadConstant(reg_start, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -07001070 } else {
buzbee1fd33462013-03-25 13:40:45 -07001071 LoadValueDirectFixed(rl_start, reg_start);
Bill Buzbeea114add2012-05-03 15:00:40 -07001072 }
buzbee1fd33462013-03-25 13:40:45 -07001073 int r_tgt = (cu_->instruction_set != kX86) ? LoadHelper(ENTRYPOINT_OFFSET(pIndexOf)) : 0;
1074 GenNullCheck(rl_obj.s_reg_low, reg_ptr, info->opt_flags);
1075 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001076 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001077 OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001078 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001079 if (cu_->instruction_set != kX86) {
1080 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001081 } else {
buzbee1fd33462013-03-25 13:40:45 -07001082 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pIndexOf));
buzbeeb046e162012-10-30 15:48:42 -07001083 }
buzbee1fd33462013-03-25 13:40:45 -07001084 LIR* resume_tgt = NewLIR0(kPseudoTargetLabel);
buzbeefa57c472012-11-21 12:06:18 -08001085 launch_pad->operands[2] = reinterpret_cast<uintptr_t>(resume_tgt);
Bill Buzbeea114add2012-05-03 15:00:40 -07001086 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001087 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001088 RegLocation rl_return = GetReturn(false);
1089 RegLocation rl_dest = InlineTarget(info);
1090 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001091 return true;
buzbeefc9e6fa2012-03-23 15:14:29 -07001092}
1093
1094/* Fast string.compareTo(Ljava/lang/string;)I. */
buzbee1fd33462013-03-25 13:40:45 -07001095bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001096{
buzbee1fd33462013-03-25 13:40:45 -07001097 if (cu_->instruction_set == kMips) {
buzbeeb046e162012-10-30 15:48:42 -07001098 // TODO - add Mips implementation
1099 return false;
1100 }
buzbee1fd33462013-03-25 13:40:45 -07001101 ClobberCalleeSave();
1102 LockCallTemps(); // Using fixed registers
buzbeefa57c472012-11-21 12:06:18 -08001103 int reg_this = TargetReg(kArg0);
1104 int reg_cmp = TargetReg(kArg1);
buzbeefc9e6fa2012-03-23 15:14:29 -07001105
buzbeefa57c472012-11-21 12:06:18 -08001106 RegLocation rl_this = info->args[0];
1107 RegLocation rl_cmp = info->args[1];
buzbee1fd33462013-03-25 13:40:45 -07001108 LoadValueDirectFixed(rl_this, reg_this);
1109 LoadValueDirectFixed(rl_cmp, reg_cmp);
1110 int r_tgt = (cu_->instruction_set != kX86) ?
1111 LoadHelper(ENTRYPOINT_OFFSET(pStringCompareTo)) : 0;
1112 GenNullCheck(rl_this.s_reg_low, reg_this, info->opt_flags);
buzbeefa57c472012-11-21 12:06:18 -08001113 //TUNING: check if rl_cmp.s_reg_low is already null checked
buzbee1fd33462013-03-25 13:40:45 -07001114 LIR* launch_pad = RawLIR(0, kPseudoIntrinsicRetry, reinterpret_cast<uintptr_t>(info));
buzbee862a7602013-04-05 10:58:54 -07001115 intrinsic_launchpads_.Insert(launch_pad);
buzbee1fd33462013-03-25 13:40:45 -07001116 OpCmpImmBranch(kCondEq, reg_cmp, 0, launch_pad);
buzbee8320f382012-09-11 16:29:42 -07001117 // NOTE: not a safepoint
buzbee1fd33462013-03-25 13:40:45 -07001118 if (cu_->instruction_set != kX86) {
1119 OpReg(kOpBlx, r_tgt);
buzbeeb046e162012-10-30 15:48:42 -07001120 } else {
buzbee1fd33462013-03-25 13:40:45 -07001121 OpThreadMem(kOpBlx, ENTRYPOINT_OFFSET(pStringCompareTo));
buzbeeb046e162012-10-30 15:48:42 -07001122 }
buzbeefa57c472012-11-21 12:06:18 -08001123 launch_pad->operands[2] = 0; // No return possible
Bill Buzbeea114add2012-05-03 15:00:40 -07001124 // Record that we've already inlined & null checked
buzbeefa57c472012-11-21 12:06:18 -08001125 info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK);
buzbee1fd33462013-03-25 13:40:45 -07001126 RegLocation rl_return = GetReturn(false);
1127 RegLocation rl_dest = InlineTarget(info);
1128 StoreValue(rl_dest, rl_return);
Bill Buzbeea114add2012-05-03 15:00:40 -07001129 return true;
Ian Rogers0183dd72012-09-17 23:06:51 -07001130}
1131
buzbee1fd33462013-03-25 13:40:45 -07001132bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) {
1133 RegLocation rl_dest = InlineTarget(info);
1134 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001135 int offset = Thread::PeerOffset().Int32Value();
buzbee1fd33462013-03-25 13:40:45 -07001136 if (cu_->instruction_set == kThumb2 || cu_->instruction_set == kMips) {
1137 LoadWordDisp(TargetReg(kSelf), offset, rl_result.low_reg);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001138 } else {
buzbee1fd33462013-03-25 13:40:45 -07001139 CHECK(cu_->instruction_set == kX86);
1140 ((X86Mir2Lir*)this)->OpRegThreadMem(kOpMov, rl_result.low_reg, offset);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001141 }
buzbee1fd33462013-03-25 13:40:45 -07001142 StoreValue(rl_dest, rl_result);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001143 return true;
1144}
1145
buzbee1fd33462013-03-25 13:40:45 -07001146bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001147 bool is_long, bool is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001148 if (cu_->instruction_set == kMips) {
Jeff Hao9bd02812013-02-08 14:29:50 -08001149 // TODO - add Mips implementation
Jeff Hao5a70fe82013-02-07 15:02:10 -08001150 return false;
1151 }
1152 // Unused - RegLocation rl_src_unsafe = info->args[0];
1153 RegLocation rl_src_obj = info->args[1]; // Object
1154 RegLocation rl_src_offset = info->args[2]; // long low
1155 rl_src_offset.wide = 0; // ignore high half in info->args[3]
buzbee1fd33462013-03-25 13:40:45 -07001156 RegLocation rl_dest = InlineTarget(info); // result reg
Jeff Hao5a70fe82013-02-07 15:02:10 -08001157 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001158 GenMemBarrier(kLoadLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001159 }
buzbee1fd33462013-03-25 13:40:45 -07001160 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1161 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
1162 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001163 if (is_long) {
buzbee1fd33462013-03-25 13:40:45 -07001164 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1165 LoadBaseDispWide(rl_object.low_reg, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG);
1166 StoreValueWide(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001167 } else {
buzbee1fd33462013-03-25 13:40:45 -07001168 LoadBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_result.low_reg, 0, kWord);
1169 StoreValue(rl_dest, rl_result);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001170 }
1171 return true;
1172}
1173
buzbee1fd33462013-03-25 13:40:45 -07001174bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001175 bool is_object, bool is_volatile, bool is_ordered) {
buzbee1fd33462013-03-25 13:40:45 -07001176 if (cu_->instruction_set == kMips) {
Jeff Hao9bd02812013-02-08 14:29:50 -08001177 // TODO - add Mips implementation
Jeff Hao5a70fe82013-02-07 15:02:10 -08001178 return false;
1179 }
1180 // Unused - RegLocation rl_src_unsafe = info->args[0];
1181 RegLocation rl_src_obj = info->args[1]; // Object
1182 RegLocation rl_src_offset = info->args[2]; // long low
1183 rl_src_offset.wide = 0; // ignore high half in info->args[3]
1184 RegLocation rl_src_value = info->args[4]; // value to store
1185 if (is_volatile || is_ordered) {
buzbee1fd33462013-03-25 13:40:45 -07001186 GenMemBarrier(kStoreStore);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001187 }
buzbee1fd33462013-03-25 13:40:45 -07001188 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
1189 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
buzbeea5abf702013-04-12 14:39:29 -07001190 RegLocation rl_value;
Jeff Hao5a70fe82013-02-07 15:02:10 -08001191 if (is_long) {
buzbeea5abf702013-04-12 14:39:29 -07001192 rl_value = LoadValueWide(rl_src_value, kCoreReg);
buzbee1fd33462013-03-25 13:40:45 -07001193 OpRegReg(kOpAdd, rl_object.low_reg, rl_offset.low_reg);
1194 StoreBaseDispWide(rl_object.low_reg, 0, rl_value.low_reg, rl_value.high_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001195 } else {
buzbeea5abf702013-04-12 14:39:29 -07001196 rl_value = LoadValue(rl_src_value, kCoreReg);
buzbee1fd33462013-03-25 13:40:45 -07001197 StoreBaseIndexed(rl_object.low_reg, rl_offset.low_reg, rl_value.low_reg, 0, kWord);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001198 }
1199 if (is_volatile) {
buzbee1fd33462013-03-25 13:40:45 -07001200 GenMemBarrier(kStoreLoad);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001201 }
1202 if (is_object) {
buzbee1fd33462013-03-25 13:40:45 -07001203 MarkGCCard(rl_value.low_reg, rl_object.low_reg);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001204 }
1205 return true;
1206}
1207
buzbee1fd33462013-03-25 13:40:45 -07001208bool Mir2Lir::GenIntrinsic(CallInfo* info)
buzbeefc9e6fa2012-03-23 15:14:29 -07001209{
buzbeefa57c472012-11-21 12:06:18 -08001210 if (info->opt_flags & MIR_INLINED) {
buzbeefc9e6fa2012-03-23 15:14:29 -07001211 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -07001212 }
1213 /*
1214 * TODO: move these to a target-specific structured constant array
1215 * and use a generic match function. The list of intrinsics may be
1216 * slightly different depending on target.
1217 * TODO: Fold this into a matching function that runs during
1218 * basic block building. This should be part of the action for
1219 * small method inlining and recognition of the special object init
1220 * method. By doing this during basic block construction, we can also
1221 * take advantage of/generate new useful dataflow info.
1222 */
buzbee1fd33462013-03-25 13:40:45 -07001223 std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
buzbeefa57c472012-11-21 12:06:18 -08001224 if (tgt_method.find(" java.lang") != std::string::npos) {
1225 if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001226 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001227 }
buzbeefa57c472012-11-21 12:06:18 -08001228 if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001229 return GenInlinedDoubleCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001230 }
buzbeefa57c472012-11-21 12:06:18 -08001231 if (tgt_method == "int java.lang.Float.float_to_raw_int_bits(float)") {
buzbee1fd33462013-03-25 13:40:45 -07001232 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001233 }
buzbeefa57c472012-11-21 12:06:18 -08001234 if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001235 return GenInlinedFloatCvt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001236 }
buzbeefa57c472012-11-21 12:06:18 -08001237 if (tgt_method == "int java.lang.Math.abs(int)" ||
1238 tgt_method == "int java.lang.StrictMath.abs(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001239 return GenInlinedAbsInt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001240 }
buzbeefa57c472012-11-21 12:06:18 -08001241 if (tgt_method == "long java.lang.Math.abs(long)" ||
1242 tgt_method == "long java.lang.StrictMath.abs(long)") {
buzbee1fd33462013-03-25 13:40:45 -07001243 return GenInlinedAbsLong(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001244 }
buzbeefa57c472012-11-21 12:06:18 -08001245 if (tgt_method == "int java.lang.Math.max(int, int)" ||
1246 tgt_method == "int java.lang.StrictMath.max(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001247 return GenInlinedMinMaxInt(info, false /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001248 }
buzbeefa57c472012-11-21 12:06:18 -08001249 if (tgt_method == "int java.lang.Math.min(int, int)" ||
1250 tgt_method == "int java.lang.StrictMath.min(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001251 return GenInlinedMinMaxInt(info, true /* is_min */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001252 }
buzbeefa57c472012-11-21 12:06:18 -08001253 if (tgt_method == "double java.lang.Math.sqrt(double)" ||
1254 tgt_method == "double java.lang.StrictMath.sqrt(double)") {
buzbee1fd33462013-03-25 13:40:45 -07001255 return GenInlinedSqrt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001256 }
buzbeefa57c472012-11-21 12:06:18 -08001257 if (tgt_method == "char java.lang.String.charAt(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001258 return GenInlinedCharAt(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001259 }
buzbeefa57c472012-11-21 12:06:18 -08001260 if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
buzbee1fd33462013-03-25 13:40:45 -07001261 return GenInlinedStringCompareTo(info);
Ian Rogers0183dd72012-09-17 23:06:51 -07001262 }
buzbeefa57c472012-11-21 12:06:18 -08001263 if (tgt_method == "boolean java.lang.String.is_empty()") {
buzbee1fd33462013-03-25 13:40:45 -07001264 return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001265 }
buzbeefa57c472012-11-21 12:06:18 -08001266 if (tgt_method == "int java.lang.String.index_of(int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001267 return GenInlinedIndexOf(info, false /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001268 }
buzbeefa57c472012-11-21 12:06:18 -08001269 if (tgt_method == "int java.lang.String.index_of(int)") {
buzbee1fd33462013-03-25 13:40:45 -07001270 return GenInlinedIndexOf(info, true /* base 0 */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001271 }
buzbeefa57c472012-11-21 12:06:18 -08001272 if (tgt_method == "int java.lang.String.length()") {
buzbee1fd33462013-03-25 13:40:45 -07001273 return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
Ian Rogers0183dd72012-09-17 23:06:51 -07001274 }
Ian Rogers07ec8e12012-12-01 01:26:51 -08001275 if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
buzbee1fd33462013-03-25 13:40:45 -07001276 return GenInlinedCurrentThread(info);
Ian Rogers07ec8e12012-12-01 01:26:51 -08001277 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001278 } else if (tgt_method.find(" sun.misc.Unsafe") != std::string::npos) {
buzbeefa57c472012-11-21 12:06:18 -08001279 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001280 return GenInlinedCas32(info, false);
Ian Rogers0183dd72012-09-17 23:06:51 -07001281 }
buzbeefa57c472012-11-21 12:06:18 -08001282 if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001283 return GenInlinedCas32(info, true);
Ian Rogers0183dd72012-09-17 23:06:51 -07001284 }
Jeff Hao5a70fe82013-02-07 15:02:10 -08001285 if (tgt_method == "int sun.misc.Unsafe.getInt(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001286 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001287 }
1288 if (tgt_method == "int sun.misc.Unsafe.getIntVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001289 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001290 }
1291 if (tgt_method == "void sun.misc.Unsafe.putInt(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001292 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001293 false /* is_volatile */, false /* is_ordered */);
1294 }
1295 if (tgt_method == "void sun.misc.Unsafe.putIntVolatile(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001296 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001297 true /* is_volatile */, false /* is_ordered */);
1298 }
1299 if (tgt_method == "void sun.misc.Unsafe.putOrderedInt(java.lang.Object, long, int)") {
buzbee1fd33462013-03-25 13:40:45 -07001300 return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001301 false /* is_volatile */, true /* is_ordered */);
1302 }
1303 if (tgt_method == "long sun.misc.Unsafe.getLong(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001304 return GenInlinedUnsafeGet(info, true /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001305 }
1306 if (tgt_method == "long sun.misc.Unsafe.getLongVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001307 return GenInlinedUnsafeGet(info, true /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001308 }
1309 if (tgt_method == "void sun.misc.Unsafe.putLong(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001310 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001311 false /* is_volatile */, false /* is_ordered */);
1312 }
1313 if (tgt_method == "void sun.misc.Unsafe.putLongVolatile(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001314 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001315 true /* is_volatile */, false /* is_ordered */);
1316 }
1317 if (tgt_method == "void sun.misc.Unsafe.putOrderedLong(java.lang.Object, long, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001318 return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001319 false /* is_volatile */, true /* is_ordered */);
1320 }
1321 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObject(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001322 return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001323 }
1324 if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") {
buzbee1fd33462013-03-25 13:40:45 -07001325 return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
Jeff Hao5a70fe82013-02-07 15:02:10 -08001326 }
1327 if (tgt_method == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001328 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001329 false /* is_volatile */, false /* is_ordered */);
1330 }
1331 if (tgt_method == "void sun.misc.Unsafe.putObjectVolatile(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001332 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001333 true /* is_volatile */, false /* is_ordered */);
1334 }
1335 if (tgt_method == "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") {
buzbee1fd33462013-03-25 13:40:45 -07001336 return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
Jeff Hao5a70fe82013-02-07 15:02:10 -08001337 false /* is_volatile */, true /* is_ordered */);
1338 }
Ian Rogerse13eafa2012-09-07 11:24:27 -07001339 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001340 return false;
buzbeefc9e6fa2012-03-23 15:14:29 -07001341}
1342
buzbee1fd33462013-03-25 13:40:45 -07001343void Mir2Lir::GenInvoke(CallInfo* info)
buzbee1bc37c62012-11-20 13:35:41 -08001344{
buzbee1fd33462013-03-25 13:40:45 -07001345 if (GenIntrinsic(info)) {
buzbee1bc37c62012-11-20 13:35:41 -08001346 return;
1347 }
buzbeefa57c472012-11-21 12:06:18 -08001348 InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
1349 int call_state = 0;
1350 LIR* null_ck;
1351 LIR** p_null_ck = NULL;
1352 NextCallInsn next_call_insn;
buzbee1fd33462013-03-25 13:40:45 -07001353 FlushAllRegs(); /* Everything to home location */
buzbee1bc37c62012-11-20 13:35:41 -08001354 // Explicit register usage
buzbee1fd33462013-03-25 13:40:45 -07001355 LockCallTemps();
buzbee1bc37c62012-11-20 13:35:41 -08001356
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001357 DexCompilationUnit* cUnit = mir_graph_->GetCurrentDexCompilationUnit();
1358 CompilerDriver::MethodReference target_method(cUnit->GetDexFile(), info->index);
buzbeefa57c472012-11-21 12:06:18 -08001359 int vtable_idx;
1360 uintptr_t direct_code;
1361 uintptr_t direct_method;
1362 bool skip_this;
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001363 bool fast_path =
1364 cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(),
1365 current_dalvik_offset_,
1366 info->type, target_method,
1367 vtable_idx,
1368 direct_code, direct_method,
1369 true) && !SLOW_INVOKE_PATH;
buzbee1bc37c62012-11-20 13:35:41 -08001370 if (info->type == kInterface) {
buzbeefa57c472012-11-21 12:06:18 -08001371 if (fast_path) {
1372 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001373 }
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001374 next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck;
buzbeefa57c472012-11-21 12:06:18 -08001375 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001376 } else if (info->type == kDirect) {
buzbeefa57c472012-11-21 12:06:18 -08001377 if (fast_path) {
1378 p_null_ck = &null_ck;
buzbee1bc37c62012-11-20 13:35:41 -08001379 }
buzbeefa57c472012-11-21 12:06:18 -08001380 next_call_insn = fast_path ? NextSDCallInsn : NextDirectCallInsnSP;
1381 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001382 } else if (info->type == kStatic) {
buzbeefa57c472012-11-21 12:06:18 -08001383 next_call_insn = fast_path ? NextSDCallInsn : NextStaticCallInsnSP;
1384 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001385 } else if (info->type == kSuper) {
buzbeefa57c472012-11-21 12:06:18 -08001386 DCHECK(!fast_path); // Fast path is a direct call.
1387 next_call_insn = NextSuperCallInsnSP;
1388 skip_this = false;
buzbee1bc37c62012-11-20 13:35:41 -08001389 } else {
1390 DCHECK_EQ(info->type, kVirtual);
buzbeefa57c472012-11-21 12:06:18 -08001391 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP;
1392 skip_this = fast_path;
buzbee1bc37c62012-11-20 13:35:41 -08001393 }
buzbeefa57c472012-11-21 12:06:18 -08001394 if (!info->is_range) {
buzbee1fd33462013-03-25 13:40:45 -07001395 call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck,
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001396 next_call_insn, target_method,
1397 vtable_idx, direct_code, direct_method,
1398 original_type, skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001399 } else {
buzbee1fd33462013-03-25 13:40:45 -07001400 call_state = GenDalvikArgsRange(info, call_state, p_null_ck,
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001401 next_call_insn, target_method, vtable_idx,
1402 direct_code, direct_method, original_type,
1403 skip_this);
buzbee1bc37c62012-11-20 13:35:41 -08001404 }
1405 // Finish up any of the call sequence not interleaved in arg loading
buzbeefa57c472012-11-21 12:06:18 -08001406 while (call_state >= 0) {
Ian Rogerse3cd2f02013-05-24 15:32:56 -07001407 call_state = next_call_insn(cu_, info, call_state, target_method,
1408 vtable_idx, direct_code, direct_method,
1409 original_type);
buzbee1bc37c62012-11-20 13:35:41 -08001410 }
buzbeefa57c472012-11-21 12:06:18 -08001411 LIR* call_inst;
buzbee1fd33462013-03-25 13:40:45 -07001412 if (cu_->instruction_set != kX86) {
1413 call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt));
buzbee1bc37c62012-11-20 13:35:41 -08001414 } else {
buzbeefa57c472012-11-21 12:06:18 -08001415 if (fast_path && info->type != kInterface) {
buzbee1fd33462013-03-25 13:40:45 -07001416 call_inst = OpMem(kOpBlx, TargetReg(kArg0),
Jeff Haoaa4a7932013-05-13 11:28:27 -07001417 mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value());
buzbee1bc37c62012-11-20 13:35:41 -08001418 } else {
1419 int trampoline = 0;
1420 switch (info->type) {
1421 case kInterface:
buzbeefa57c472012-11-21 12:06:18 -08001422 trampoline = fast_path ? ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline)
buzbee1bc37c62012-11-20 13:35:41 -08001423 : ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck);
1424 break;
1425 case kDirect:
1426 trampoline = ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck);
1427 break;
1428 case kStatic:
1429 trampoline = ENTRYPOINT_OFFSET(pInvokeStaticTrampolineWithAccessCheck);
1430 break;
1431 case kSuper:
1432 trampoline = ENTRYPOINT_OFFSET(pInvokeSuperTrampolineWithAccessCheck);
1433 break;
1434 case kVirtual:
1435 trampoline = ENTRYPOINT_OFFSET(pInvokeVirtualTrampolineWithAccessCheck);
1436 break;
1437 default:
1438 LOG(FATAL) << "Unexpected invoke type";
1439 }
buzbee1fd33462013-03-25 13:40:45 -07001440 call_inst = OpThreadMem(kOpBlx, trampoline);
buzbee1bc37c62012-11-20 13:35:41 -08001441 }
1442 }
buzbee1fd33462013-03-25 13:40:45 -07001443 MarkSafepointPC(call_inst);
buzbee1bc37c62012-11-20 13:35:41 -08001444
buzbee1fd33462013-03-25 13:40:45 -07001445 ClobberCalleeSave();
buzbee1bc37c62012-11-20 13:35:41 -08001446 if (info->result.location != kLocInvalid) {
1447 // We have a following MOVE_RESULT - do it now.
1448 if (info->result.wide) {
buzbee1fd33462013-03-25 13:40:45 -07001449 RegLocation ret_loc = GetReturnWide(info->result.fp);
1450 StoreValueWide(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001451 } else {
buzbee1fd33462013-03-25 13:40:45 -07001452 RegLocation ret_loc = GetReturn(info->result.fp);
1453 StoreValue(info->result, ret_loc);
buzbee1bc37c62012-11-20 13:35:41 -08001454 }
1455 }
1456}
1457
buzbee31a4a6f2012-02-28 15:36:15 -08001458} // namespace art