blob: 53278a7fb4b80711dd74d2cc36d1d9ef1c3392f9 [file] [log] [blame]
Ben Cheng7a2697d2010-06-07 13:44:23 -07001/*
2 * Copyright (C) 2010 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 "Dalvik.h"
18#include "Dataflow.h"
Dan Bornsteindf4daaf2010-12-01 14:23:44 -080019#include "libdex/DexOpcodes.h"
Ben Cheng7a2697d2010-06-07 13:44:23 -070020
21/* Convert the reg id from the callee to the original id passed by the caller */
22static inline u4 convertRegId(const DecodedInstruction *invoke,
23 const Method *calleeMethod,
24 int calleeRegId, bool isRange)
25{
26 /* The order in the original arg passing list */
27 int rank = calleeRegId -
28 (calleeMethod->registersSize - calleeMethod->insSize);
29 assert(rank >= 0);
30 if (!isRange) {
31 return invoke->arg[rank];
32 } else {
33 return invoke->vC + rank;
34 }
35}
36
Ben Chengcfdeca32011-01-14 11:36:46 -080037static bool inlineGetter(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -070038 const Method *calleeMethod,
39 MIR *invokeMIR,
40 BasicBlock *invokeBB,
41 bool isPredicted,
42 bool isRange)
43{
44 BasicBlock *moveResultBB = invokeBB->fallThrough;
45 MIR *moveResultMIR = moveResultBB->firstMIRInsn;
Carl Shapirofc75f3e2010-12-07 11:43:38 -080046 MIR *newGetterMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -070047 DecodedInstruction getterInsn;
48
Ben Chenga18e6d12011-12-01 12:24:49 -080049 /*
50 * Not all getter instructions have vC but vC will be read by
51 * dvmCompilerGetDalvikDisassembly unconditionally.
52 * Initialize it here to get Valgrind happy.
53 */
54 getterInsn.vC = 0;
55
Dan Bornstein54322392010-11-17 14:16:56 -080056 dexDecodeInstruction(calleeMethod->insns, &getterInsn);
Ben Cheng7a2697d2010-06-07 13:44:23 -070057
58 if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
Ben Chengcfdeca32011-01-14 11:36:46 -080059 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -070060
61 /*
62 * Some getters (especially invoked through interface) are not followed
63 * by a move result.
64 */
65 if ((moveResultMIR == NULL) ||
Dan Bornstein9a1f8162010-12-01 17:02:26 -080066 (moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT &&
67 moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_OBJECT &&
68 moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_WIDE)) {
Ben Chengcfdeca32011-01-14 11:36:46 -080069 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -070070 }
71
Dan Bornstein9a1f8162010-12-01 17:02:26 -080072 int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opcode];
Ben Cheng7a2697d2010-06-07 13:44:23 -070073
74 /* Expecting vA to be the destination register */
Ben Cheng52d4cd22010-08-16 14:08:49 -070075 if (dfFlags & (DF_UA | DF_UA_WIDE)) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -080076 LOGE("opcode %d has DF_UA set (not expected)", getterInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -070077 dvmAbort();
78 }
79
80 if (dfFlags & DF_UB) {
81 getterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
82 getterInsn.vB, isRange);
83 }
84
85 if (dfFlags & DF_UC) {
86 getterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
87 getterInsn.vC, isRange);
88 }
89
90 getterInsn.vA = moveResultMIR->dalvikInsn.vA;
91
92 /* Now setup the Dalvik instruction with converted src/dst registers */
93 newGetterMIR->dalvikInsn = getterInsn;
94
Dan Bornsteine4852762010-12-02 12:45:00 -080095 newGetterMIR->width = dexGetWidthFromOpcode(getterInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -070096
97 newGetterMIR->OptimizationFlags |= MIR_CALLEE;
98
99 /*
100 * If the getter instruction is about to raise any exception, punt to the
101 * interpreter and re-execute the invoke.
102 */
103 newGetterMIR->offset = invokeMIR->offset;
104
105 newGetterMIR->meta.calleeMethod = calleeMethod;
106
107 dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newGetterMIR);
108
109 if (isPredicted) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800110 MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700111 *invokeMIRSlow = *invokeMIR;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700112 invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700113
114 /* Use vC to denote the first argument (ie this) */
115 if (!isRange) {
116 invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
117 }
118
119 moveResultMIR->OptimizationFlags |= MIR_INLINED_PRED;
120
121 dvmCompilerInsertMIRAfter(invokeBB, newGetterMIR, invokeMIRSlow);
122 invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
123#if defined(WITH_JIT_TUNING)
124 gDvmJit.invokePolyGetterInlined++;
125#endif
126 } else {
127 invokeMIR->OptimizationFlags |= MIR_INLINED;
128 moveResultMIR->OptimizationFlags |= MIR_INLINED;
129#if defined(WITH_JIT_TUNING)
130 gDvmJit.invokeMonoGetterInlined++;
131#endif
132 }
133
Ben Chengcfdeca32011-01-14 11:36:46 -0800134 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700135}
136
Ben Chengcfdeca32011-01-14 11:36:46 -0800137static bool inlineSetter(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700138 const Method *calleeMethod,
139 MIR *invokeMIR,
140 BasicBlock *invokeBB,
141 bool isPredicted,
142 bool isRange)
143{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800144 MIR *newSetterMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700145 DecodedInstruction setterInsn;
146
Ben Chenga18e6d12011-12-01 12:24:49 -0800147 /*
148 * Not all setter instructions have vC but vC will be read by
149 * dvmCompilerGetDalvikDisassembly unconditionally.
150 * Initialize it here to get Valgrind happy.
151 */
152 setterInsn.vC = 0;
153
Dan Bornstein54322392010-11-17 14:16:56 -0800154 dexDecodeInstruction(calleeMethod->insns, &setterInsn);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700155
156 if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
Ben Chengcfdeca32011-01-14 11:36:46 -0800157 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700158
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800159 int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opcode];
Ben Cheng7a2697d2010-06-07 13:44:23 -0700160
Ben Cheng52d4cd22010-08-16 14:08:49 -0700161 if (dfFlags & (DF_UA | DF_UA_WIDE)) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700162 setterInsn.vA = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
163 setterInsn.vA, isRange);
164
165 }
166
167 if (dfFlags & DF_UB) {
168 setterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
169 setterInsn.vB, isRange);
170
171 }
172
173 if (dfFlags & DF_UC) {
174 setterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
175 setterInsn.vC, isRange);
176 }
177
178 /* Now setup the Dalvik instruction with converted src/dst registers */
179 newSetterMIR->dalvikInsn = setterInsn;
180
Dan Bornsteine4852762010-12-02 12:45:00 -0800181 newSetterMIR->width = dexGetWidthFromOpcode(setterInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700182
183 newSetterMIR->OptimizationFlags |= MIR_CALLEE;
184
185 /*
186 * If the setter instruction is about to raise any exception, punt to the
187 * interpreter and re-execute the invoke.
188 */
189 newSetterMIR->offset = invokeMIR->offset;
190
191 newSetterMIR->meta.calleeMethod = calleeMethod;
192
193 dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newSetterMIR);
194
195 if (isPredicted) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800196 MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700197 *invokeMIRSlow = *invokeMIR;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700198 invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700199
200 /* Use vC to denote the first argument (ie this) */
201 if (!isRange) {
202 invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
203 }
204
205 dvmCompilerInsertMIRAfter(invokeBB, newSetterMIR, invokeMIRSlow);
206 invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
207#if defined(WITH_JIT_TUNING)
208 gDvmJit.invokePolySetterInlined++;
209#endif
210 } else {
Ben Cheng33c1cf92010-08-03 12:54:00 -0700211 /*
212 * The invoke becomes no-op so it needs an explicit branch to jump to
213 * the chaining cell.
214 */
215 invokeBB->needFallThroughBranch = true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700216 invokeMIR->OptimizationFlags |= MIR_INLINED;
217#if defined(WITH_JIT_TUNING)
218 gDvmJit.invokeMonoSetterInlined++;
219#endif
220 }
221
Ben Chengcfdeca32011-01-14 11:36:46 -0800222 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700223}
224
Ben Chengcfdeca32011-01-14 11:36:46 -0800225static bool tryInlineSingletonCallsite(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700226 const Method *calleeMethod,
227 MIR *invokeMIR,
228 BasicBlock *invokeBB,
229 bool isRange)
230{
231 /* Not a Java method */
Ben Chengcfdeca32011-01-14 11:36:46 -0800232 if (dvmIsNativeMethod(calleeMethod)) return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700233
234 CompilerMethodStats *methodStats =
235 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
236
237 /* Empty callee - do nothing */
238 if (methodStats->attributes & METHOD_IS_EMPTY) {
239 /* The original invoke instruction is effectively turned into NOP */
240 invokeMIR->OptimizationFlags |= MIR_INLINED;
Ben Cheng23608ab2010-09-10 17:11:11 -0700241 /*
242 * Need to insert an explicit branch to catch the falling knife (into
243 * the PC reconstruction or chaining cell).
244 */
245 invokeBB->needFallThroughBranch = true;
Ben Chengcfdeca32011-01-14 11:36:46 -0800246 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700247 }
248
249 if (methodStats->attributes & METHOD_IS_GETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800250 return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
251 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700252 } else if (methodStats->attributes & METHOD_IS_SETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800253 return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
254 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700255 }
Ben Chengcfdeca32011-01-14 11:36:46 -0800256 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700257}
258
Ben Chengcfdeca32011-01-14 11:36:46 -0800259static bool inlineEmptyVirtualCallee(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700260 const Method *calleeMethod,
261 MIR *invokeMIR,
262 BasicBlock *invokeBB)
263{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800264 MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700265 *invokeMIRSlow = *invokeMIR;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700266 invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700267
268 dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
269 invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
Ben Chengcfdeca32011-01-14 11:36:46 -0800270 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700271}
272
Ben Chengcfdeca32011-01-14 11:36:46 -0800273static bool tryInlineVirtualCallsite(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700274 const Method *calleeMethod,
275 MIR *invokeMIR,
276 BasicBlock *invokeBB,
277 bool isRange)
278{
279 /* Not a Java method */
Ben Chengcfdeca32011-01-14 11:36:46 -0800280 if (dvmIsNativeMethod(calleeMethod)) return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700281
282 CompilerMethodStats *methodStats =
283 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
284
285 /* Empty callee - do nothing by checking the clazz pointer */
286 if (methodStats->attributes & METHOD_IS_EMPTY) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800287 return inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR,
288 invokeBB);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700289 }
290
291 if (methodStats->attributes & METHOD_IS_GETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800292 return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
293 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700294 } else if (methodStats->attributes & METHOD_IS_SETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800295 return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
296 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700297 }
Ben Chengcfdeca32011-01-14 11:36:46 -0800298 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700299}
300
301
Ben Chengcfdeca32011-01-14 11:36:46 -0800302void dvmCompilerInlineMIR(CompilationUnit *cUnit, JitTranslationInfo *info)
Ben Cheng7a2697d2010-06-07 13:44:23 -0700303{
Ben Cheng7a2697d2010-06-07 13:44:23 -0700304 bool isRange = false;
Ben Cheng00603072010-10-28 11:13:58 -0700305 GrowableListIterator iterator;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700306
Ben Cheng00603072010-10-28 11:13:58 -0700307 dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700308 /*
309 * Analyze the basic block containing an invoke to see if it can be inlined
310 */
Ben Cheng00603072010-10-28 11:13:58 -0700311 while (true) {
312 BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
313 if (bb == NULL) break;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700314 if (bb->blockType != kDalvikByteCode)
315 continue;
316 MIR *lastMIRInsn = bb->lastMIRInsn;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700317 Opcode opcode = lastMIRInsn->dalvikInsn.opcode;
318 int flags = (int)dexGetFlagsFromOpcode(opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700319
320 /* No invoke - continue */
321 if ((flags & kInstrInvoke) == 0)
322 continue;
323
buzbee18fba342011-01-19 15:31:15 -0800324 /* Disable inlining when doing method tracing */
325 if (gDvmJit.methodTraceSupport)
326 continue;
327
Ben Cheng7eb3f7a2010-08-26 14:56:31 -0700328 /*
329 * If the invoke itself is selected for single stepping, don't bother
330 * to inline it.
331 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800332 if (SINGLE_STEP_OP(opcode))
Ben Cheng7eb3f7a2010-08-26 14:56:31 -0700333 continue;
334
Ben Cheng7a2697d2010-06-07 13:44:23 -0700335 const Method *calleeMethod;
336
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800337 switch (opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700338 case OP_INVOKE_SUPER:
339 case OP_INVOKE_DIRECT:
340 case OP_INVOKE_STATIC:
341 case OP_INVOKE_SUPER_QUICK:
342 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
343 break;
344 case OP_INVOKE_SUPER_RANGE:
345 case OP_INVOKE_DIRECT_RANGE:
346 case OP_INVOKE_STATIC_RANGE:
347 case OP_INVOKE_SUPER_QUICK_RANGE:
348 isRange = true;
349 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
350 break;
351 default:
352 calleeMethod = NULL;
353 break;
354 }
355
356 if (calleeMethod) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800357 bool inlined = tryInlineSingletonCallsite(cUnit, calleeMethod,
358 lastMIRInsn, bb, isRange);
359 if (!inlined &&
360 !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
361 !dvmIsNativeMethod(calleeMethod)) {
362 CompilerMethodStats *methodStats =
363 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
364 if ((methodStats->attributes & METHOD_IS_LEAF) &&
365 !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
366 /* Callee has been previously compiled */
367 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
368 lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
369 } else {
370 /* Compile the callee first */
371 dvmCompileMethod(calleeMethod, info);
372 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
373 lastMIRInsn->OptimizationFlags |=
374 MIR_INVOKE_METHOD_JIT;
375 } else {
376 methodStats->attributes |= METHOD_CANNOT_COMPILE;
377 }
378 }
379 }
380 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700381 return;
382 }
383
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800384 switch (opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700385 case OP_INVOKE_VIRTUAL:
386 case OP_INVOKE_VIRTUAL_QUICK:
387 case OP_INVOKE_INTERFACE:
388 isRange = false;
389 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
390 break;
391 case OP_INVOKE_VIRTUAL_RANGE:
392 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
393 case OP_INVOKE_INTERFACE_RANGE:
394 isRange = true;
395 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
396 break;
397 default:
398 break;
399 }
400
401 if (calleeMethod) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800402 bool inlined = tryInlineVirtualCallsite(cUnit, calleeMethod,
403 lastMIRInsn, bb, isRange);
404 if (!inlined &&
405 !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
406 !dvmIsNativeMethod(calleeMethod)) {
407 CompilerMethodStats *methodStats =
408 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
409 if ((methodStats->attributes & METHOD_IS_LEAF) &&
410 !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
411 /* Callee has been previously compiled */
412 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
413 lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
414 } else {
415 /* Compile the callee first */
416 dvmCompileMethod(calleeMethod, info);
417 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
418 lastMIRInsn->OptimizationFlags |=
419 MIR_INVOKE_METHOD_JIT;
420 } else {
421 methodStats->attributes |= METHOD_CANNOT_COMPILE;
422 }
423 }
424 }
425 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700426 return;
427 }
428 }
429}