blob: 387dd6123d0c6c59229b981c6681a348f3c0f783 [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
Dan Bornstein54322392010-11-17 14:16:56 -080049 dexDecodeInstruction(calleeMethod->insns, &getterInsn);
Ben Cheng7a2697d2010-06-07 13:44:23 -070050
51 if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &getterInsn))
Ben Chengcfdeca32011-01-14 11:36:46 -080052 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -070053
54 /*
55 * Some getters (especially invoked through interface) are not followed
56 * by a move result.
57 */
58 if ((moveResultMIR == NULL) ||
Dan Bornstein9a1f8162010-12-01 17:02:26 -080059 (moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT &&
60 moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_OBJECT &&
61 moveResultMIR->dalvikInsn.opcode != OP_MOVE_RESULT_WIDE)) {
Ben Chengcfdeca32011-01-14 11:36:46 -080062 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -070063 }
64
Dan Bornstein9a1f8162010-12-01 17:02:26 -080065 int dfFlags = dvmCompilerDataFlowAttributes[getterInsn.opcode];
Ben Cheng7a2697d2010-06-07 13:44:23 -070066
67 /* Expecting vA to be the destination register */
Ben Cheng52d4cd22010-08-16 14:08:49 -070068 if (dfFlags & (DF_UA | DF_UA_WIDE)) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -080069 LOGE("opcode %d has DF_UA set (not expected)", getterInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -070070 dvmAbort();
71 }
72
73 if (dfFlags & DF_UB) {
74 getterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
75 getterInsn.vB, isRange);
76 }
77
78 if (dfFlags & DF_UC) {
79 getterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
80 getterInsn.vC, isRange);
81 }
82
83 getterInsn.vA = moveResultMIR->dalvikInsn.vA;
84
85 /* Now setup the Dalvik instruction with converted src/dst registers */
86 newGetterMIR->dalvikInsn = getterInsn;
87
Dan Bornsteine4852762010-12-02 12:45:00 -080088 newGetterMIR->width = dexGetWidthFromOpcode(getterInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -070089
90 newGetterMIR->OptimizationFlags |= MIR_CALLEE;
91
92 /*
93 * If the getter instruction is about to raise any exception, punt to the
94 * interpreter and re-execute the invoke.
95 */
96 newGetterMIR->offset = invokeMIR->offset;
97
98 newGetterMIR->meta.calleeMethod = calleeMethod;
99
100 dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newGetterMIR);
101
102 if (isPredicted) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800103 MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700104 *invokeMIRSlow = *invokeMIR;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700105 invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700106
107 /* Use vC to denote the first argument (ie this) */
108 if (!isRange) {
109 invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
110 }
111
112 moveResultMIR->OptimizationFlags |= MIR_INLINED_PRED;
113
114 dvmCompilerInsertMIRAfter(invokeBB, newGetterMIR, invokeMIRSlow);
115 invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
116#if defined(WITH_JIT_TUNING)
117 gDvmJit.invokePolyGetterInlined++;
118#endif
119 } else {
120 invokeMIR->OptimizationFlags |= MIR_INLINED;
121 moveResultMIR->OptimizationFlags |= MIR_INLINED;
122#if defined(WITH_JIT_TUNING)
123 gDvmJit.invokeMonoGetterInlined++;
124#endif
125 }
126
Ben Chengcfdeca32011-01-14 11:36:46 -0800127 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700128}
129
Ben Chengcfdeca32011-01-14 11:36:46 -0800130static bool inlineSetter(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700131 const Method *calleeMethod,
132 MIR *invokeMIR,
133 BasicBlock *invokeBB,
134 bool isPredicted,
135 bool isRange)
136{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800137 MIR *newSetterMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700138 DecodedInstruction setterInsn;
139
Dan Bornstein54322392010-11-17 14:16:56 -0800140 dexDecodeInstruction(calleeMethod->insns, &setterInsn);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700141
142 if (!dvmCompilerCanIncludeThisInstruction(calleeMethod, &setterInsn))
Ben Chengcfdeca32011-01-14 11:36:46 -0800143 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700144
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800145 int dfFlags = dvmCompilerDataFlowAttributes[setterInsn.opcode];
Ben Cheng7a2697d2010-06-07 13:44:23 -0700146
Ben Cheng52d4cd22010-08-16 14:08:49 -0700147 if (dfFlags & (DF_UA | DF_UA_WIDE)) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700148 setterInsn.vA = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
149 setterInsn.vA, isRange);
150
151 }
152
153 if (dfFlags & DF_UB) {
154 setterInsn.vB = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
155 setterInsn.vB, isRange);
156
157 }
158
159 if (dfFlags & DF_UC) {
160 setterInsn.vC = convertRegId(&invokeMIR->dalvikInsn, calleeMethod,
161 setterInsn.vC, isRange);
162 }
163
164 /* Now setup the Dalvik instruction with converted src/dst registers */
165 newSetterMIR->dalvikInsn = setterInsn;
166
Dan Bornsteine4852762010-12-02 12:45:00 -0800167 newSetterMIR->width = dexGetWidthFromOpcode(setterInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700168
169 newSetterMIR->OptimizationFlags |= MIR_CALLEE;
170
171 /*
172 * If the setter instruction is about to raise any exception, punt to the
173 * interpreter and re-execute the invoke.
174 */
175 newSetterMIR->offset = invokeMIR->offset;
176
177 newSetterMIR->meta.calleeMethod = calleeMethod;
178
179 dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, newSetterMIR);
180
181 if (isPredicted) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800182 MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700183 *invokeMIRSlow = *invokeMIR;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700184 invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700185
186 /* Use vC to denote the first argument (ie this) */
187 if (!isRange) {
188 invokeMIR->dalvikInsn.vC = invokeMIRSlow->dalvikInsn.arg[0];
189 }
190
191 dvmCompilerInsertMIRAfter(invokeBB, newSetterMIR, invokeMIRSlow);
192 invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
193#if defined(WITH_JIT_TUNING)
194 gDvmJit.invokePolySetterInlined++;
195#endif
196 } else {
Ben Cheng33c1cf92010-08-03 12:54:00 -0700197 /*
198 * The invoke becomes no-op so it needs an explicit branch to jump to
199 * the chaining cell.
200 */
201 invokeBB->needFallThroughBranch = true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700202 invokeMIR->OptimizationFlags |= MIR_INLINED;
203#if defined(WITH_JIT_TUNING)
204 gDvmJit.invokeMonoSetterInlined++;
205#endif
206 }
207
Ben Chengcfdeca32011-01-14 11:36:46 -0800208 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700209}
210
Ben Chengcfdeca32011-01-14 11:36:46 -0800211static bool tryInlineSingletonCallsite(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700212 const Method *calleeMethod,
213 MIR *invokeMIR,
214 BasicBlock *invokeBB,
215 bool isRange)
216{
217 /* Not a Java method */
Ben Chengcfdeca32011-01-14 11:36:46 -0800218 if (dvmIsNativeMethod(calleeMethod)) return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700219
220 CompilerMethodStats *methodStats =
221 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
222
223 /* Empty callee - do nothing */
224 if (methodStats->attributes & METHOD_IS_EMPTY) {
225 /* The original invoke instruction is effectively turned into NOP */
226 invokeMIR->OptimizationFlags |= MIR_INLINED;
Ben Cheng23608ab2010-09-10 17:11:11 -0700227 /*
228 * Need to insert an explicit branch to catch the falling knife (into
229 * the PC reconstruction or chaining cell).
230 */
231 invokeBB->needFallThroughBranch = true;
Ben Chengcfdeca32011-01-14 11:36:46 -0800232 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700233 }
234
235 if (methodStats->attributes & METHOD_IS_GETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800236 return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
237 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700238 } else if (methodStats->attributes & METHOD_IS_SETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800239 return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, false,
240 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700241 }
Ben Chengcfdeca32011-01-14 11:36:46 -0800242 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700243}
244
Ben Chengcfdeca32011-01-14 11:36:46 -0800245static bool inlineEmptyVirtualCallee(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700246 const Method *calleeMethod,
247 MIR *invokeMIR,
248 BasicBlock *invokeBB)
249{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800250 MIR *invokeMIRSlow = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700251 *invokeMIRSlow = *invokeMIR;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700252 invokeMIR->dalvikInsn.opcode = (Opcode)kMirOpCheckInlinePrediction;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700253
254 dvmCompilerInsertMIRAfter(invokeBB, invokeMIR, invokeMIRSlow);
255 invokeMIRSlow->OptimizationFlags |= MIR_INLINED_PRED;
Ben Chengcfdeca32011-01-14 11:36:46 -0800256 return true;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700257}
258
Ben Chengcfdeca32011-01-14 11:36:46 -0800259static bool tryInlineVirtualCallsite(CompilationUnit *cUnit,
Ben Cheng7a2697d2010-06-07 13:44:23 -0700260 const Method *calleeMethod,
261 MIR *invokeMIR,
262 BasicBlock *invokeBB,
263 bool isRange)
264{
265 /* Not a Java method */
Ben Chengcfdeca32011-01-14 11:36:46 -0800266 if (dvmIsNativeMethod(calleeMethod)) return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700267
268 CompilerMethodStats *methodStats =
269 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
270
271 /* Empty callee - do nothing by checking the clazz pointer */
272 if (methodStats->attributes & METHOD_IS_EMPTY) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800273 return inlineEmptyVirtualCallee(cUnit, calleeMethod, invokeMIR,
274 invokeBB);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700275 }
276
277 if (methodStats->attributes & METHOD_IS_GETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800278 return inlineGetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
279 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700280 } else if (methodStats->attributes & METHOD_IS_SETTER) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800281 return inlineSetter(cUnit, calleeMethod, invokeMIR, invokeBB, true,
282 isRange);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700283 }
Ben Chengcfdeca32011-01-14 11:36:46 -0800284 return false;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700285}
286
287
Ben Chengcfdeca32011-01-14 11:36:46 -0800288void dvmCompilerInlineMIR(CompilationUnit *cUnit, JitTranslationInfo *info)
Ben Cheng7a2697d2010-06-07 13:44:23 -0700289{
Ben Cheng7a2697d2010-06-07 13:44:23 -0700290 bool isRange = false;
Ben Cheng00603072010-10-28 11:13:58 -0700291 GrowableListIterator iterator;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700292
Ben Cheng00603072010-10-28 11:13:58 -0700293 dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700294 /*
295 * Analyze the basic block containing an invoke to see if it can be inlined
296 */
Ben Cheng00603072010-10-28 11:13:58 -0700297 while (true) {
298 BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
299 if (bb == NULL) break;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700300 if (bb->blockType != kDalvikByteCode)
301 continue;
302 MIR *lastMIRInsn = bb->lastMIRInsn;
Carl Shapiro5d5b94c2011-04-19 17:34:24 -0700303 Opcode opcode = lastMIRInsn->dalvikInsn.opcode;
304 int flags = (int)dexGetFlagsFromOpcode(opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700305
306 /* No invoke - continue */
307 if ((flags & kInstrInvoke) == 0)
308 continue;
309
buzbee18fba342011-01-19 15:31:15 -0800310 /* Disable inlining when doing method tracing */
311 if (gDvmJit.methodTraceSupport)
312 continue;
313
Ben Cheng7eb3f7a2010-08-26 14:56:31 -0700314 /*
315 * If the invoke itself is selected for single stepping, don't bother
316 * to inline it.
317 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800318 if (SINGLE_STEP_OP(opcode))
Ben Cheng7eb3f7a2010-08-26 14:56:31 -0700319 continue;
320
Ben Cheng7a2697d2010-06-07 13:44:23 -0700321 const Method *calleeMethod;
322
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800323 switch (opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700324 case OP_INVOKE_SUPER:
325 case OP_INVOKE_DIRECT:
326 case OP_INVOKE_STATIC:
327 case OP_INVOKE_SUPER_QUICK:
328 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
329 break;
330 case OP_INVOKE_SUPER_RANGE:
331 case OP_INVOKE_DIRECT_RANGE:
332 case OP_INVOKE_STATIC_RANGE:
333 case OP_INVOKE_SUPER_QUICK_RANGE:
334 isRange = true;
335 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
336 break;
337 default:
338 calleeMethod = NULL;
339 break;
340 }
341
342 if (calleeMethod) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800343 bool inlined = tryInlineSingletonCallsite(cUnit, calleeMethod,
344 lastMIRInsn, bb, isRange);
345 if (!inlined &&
346 !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
347 !dvmIsNativeMethod(calleeMethod)) {
348 CompilerMethodStats *methodStats =
349 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
350 if ((methodStats->attributes & METHOD_IS_LEAF) &&
351 !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
352 /* Callee has been previously compiled */
353 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
354 lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
355 } else {
356 /* Compile the callee first */
357 dvmCompileMethod(calleeMethod, info);
358 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
359 lastMIRInsn->OptimizationFlags |=
360 MIR_INVOKE_METHOD_JIT;
361 } else {
362 methodStats->attributes |= METHOD_CANNOT_COMPILE;
363 }
364 }
365 }
366 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700367 return;
368 }
369
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800370 switch (opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700371 case OP_INVOKE_VIRTUAL:
372 case OP_INVOKE_VIRTUAL_QUICK:
373 case OP_INVOKE_INTERFACE:
374 isRange = false;
375 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
376 break;
377 case OP_INVOKE_VIRTUAL_RANGE:
378 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
379 case OP_INVOKE_INTERFACE_RANGE:
380 isRange = true;
381 calleeMethod = lastMIRInsn->meta.callsiteInfo->method;
382 break;
383 default:
384 break;
385 }
386
387 if (calleeMethod) {
Ben Chengcfdeca32011-01-14 11:36:46 -0800388 bool inlined = tryInlineVirtualCallsite(cUnit, calleeMethod,
389 lastMIRInsn, bb, isRange);
390 if (!inlined &&
391 !(gDvmJit.disableOpt & (1 << kMethodJit)) &&
392 !dvmIsNativeMethod(calleeMethod)) {
393 CompilerMethodStats *methodStats =
394 dvmCompilerAnalyzeMethodBody(calleeMethod, true);
395 if ((methodStats->attributes & METHOD_IS_LEAF) &&
396 !(methodStats->attributes & METHOD_CANNOT_COMPILE)) {
397 /* Callee has been previously compiled */
398 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
399 lastMIRInsn->OptimizationFlags |= MIR_INVOKE_METHOD_JIT;
400 } else {
401 /* Compile the callee first */
402 dvmCompileMethod(calleeMethod, info);
403 if (dvmJitGetMethodAddr(calleeMethod->insns)) {
404 lastMIRInsn->OptimizationFlags |=
405 MIR_INVOKE_METHOD_JIT;
406 } else {
407 methodStats->attributes |= METHOD_CANNOT_COMPILE;
408 }
409 }
410 }
411 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700412 return;
413 }
414 }
415}