blob: 52040965b9fa6ed3bb86af8a04e4ee820f4173bc [file] [log] [blame]
Andy McFadden2e1ee502010-03-24 13:25:53 -07001/*
2 * Copyright (C) 2008 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/*
18 * Perform some simple bytecode optimizations, chiefly "quickening" of
19 * opcodes.
20 */
21#include "Dalvik.h"
22#include "libdex/InstrUtils.h"
23
24#include <zlib.h>
25
26#include <stdlib.h>
27
28/*
29 * Virtual/direct calls to "method" are replaced with an execute-inline
30 * instruction with index "idx".
31 */
Andy McFaddencb3c5422010-04-07 15:56:16 -070032struct InlineSub {
Andy McFadden2e1ee502010-03-24 13:25:53 -070033 Method* method;
34 int inlineIdx;
Andy McFaddencb3c5422010-04-07 15:56:16 -070035};
Andy McFadden2e1ee502010-03-24 13:25:53 -070036
37
38/* fwd */
Andy McFaddenfb119e62010-06-28 16:21:20 -070039static void optimizeMethod(Method* method, bool essentialOnly);
40static bool rewriteInstField(Method* method, u2* insns, OpCode quickOpc,
41 OpCode volatileOpc);
42static bool rewriteStaticField(Method* method, u2* insns, OpCode volatileOpc);
Andy McFadden2e1ee502010-03-24 13:25:53 -070043static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc);
44static bool rewriteEmptyDirectInvoke(Method* method, u2* insns);
45static bool rewriteExecuteInline(Method* method, u2* insns,
Andy McFaddencb3c5422010-04-07 15:56:16 -070046 MethodType methodType);
Andy McFadden2e1ee502010-03-24 13:25:53 -070047static bool rewriteExecuteInlineRange(Method* method, u2* insns,
Andy McFaddencb3c5422010-04-07 15:56:16 -070048 MethodType methodType);
Andy McFadden3f4b63f2010-09-13 14:04:02 -070049static void rewriteReturnVoid(Method* method, u2* insns);
50static bool needsReturnBarrier(Method* method);
Andy McFadden2e1ee502010-03-24 13:25:53 -070051
52
53/*
54 * Create a table of inline substitutions.
55 *
56 * TODO: this is currently just a linear array. We will want to put this
57 * into a hash table as the list size increases.
58 */
Andy McFaddencb3c5422010-04-07 15:56:16 -070059InlineSub* dvmCreateInlineSubsTable(void)
Andy McFadden2e1ee502010-03-24 13:25:53 -070060{
61 const InlineOperation* ops = dvmGetInlineOpsTable();
62 const int count = dvmGetInlineOpsTableLength();
63 InlineSub* table;
Andy McFadden2e1ee502010-03-24 13:25:53 -070064 int i, tableIndex;
65
66 /*
67 * Allocate for optimism: one slot per entry, plus an end-of-list marker.
68 */
Elliott Hughesfe700262010-09-14 17:42:07 -070069 table = calloc(count + 1, sizeof(InlineSub));
Andy McFadden2e1ee502010-03-24 13:25:53 -070070
71 tableIndex = 0;
72 for (i = 0; i < count; i++) {
Elliott Hughesfe700262010-09-14 17:42:07 -070073 Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
74 ops[i].methodName, ops[i].methodSignature);
75 if (method != NULL) {
76 table[tableIndex].method = method;
77 table[tableIndex].inlineIdx = i;
78 tableIndex++;
Andy McFadden2e1ee502010-03-24 13:25:53 -070079
Elliott Hughesfe700262010-09-14 17:42:07 -070080 LOGV("DexOpt: will inline %d: %s.%s %s\n", i,
81 ops[i].classDescriptor, ops[i].methodName,
82 ops[i].methodSignature);
Andy McFadden2e1ee502010-03-24 13:25:53 -070083 }
84 }
85
86 /* mark end of table */
87 table[tableIndex].method = NULL;
88 LOGV("DexOpt: inline table has %d entries\n", tableIndex);
89
90 return table;
91}
92
93/*
Andy McFaddencb3c5422010-04-07 15:56:16 -070094 * Release inline sub data structure.
Andy McFadden2e1ee502010-03-24 13:25:53 -070095 */
Andy McFaddencb3c5422010-04-07 15:56:16 -070096void dvmFreeInlineSubsTable(InlineSub* inlineSubs)
Andy McFadden2e1ee502010-03-24 13:25:53 -070097{
Andy McFadden2e1ee502010-03-24 13:25:53 -070098 free(inlineSubs);
99}
100
Andy McFaddencb3c5422010-04-07 15:56:16 -0700101
Andy McFadden2e1ee502010-03-24 13:25:53 -0700102/*
103 * Optimize the specified class.
Andy McFaddenfb119e62010-06-28 16:21:20 -0700104 *
105 * If "essentialOnly" is true, we only do essential optimizations. For
106 * example, accesses to volatile 64-bit fields must be replaced with
107 * "-wide-volatile" instructions or the program could behave incorrectly.
108 * (Skipping non-essential optimizations makes us a little bit faster, and
109 * more importantly avoids dirtying DEX pages.)
Andy McFadden2e1ee502010-03-24 13:25:53 -0700110 */
Andy McFaddenfb119e62010-06-28 16:21:20 -0700111void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
Andy McFadden2e1ee502010-03-24 13:25:53 -0700112{
113 int i;
114
115 for (i = 0; i < clazz->directMethodCount; i++) {
Andy McFaddenfb119e62010-06-28 16:21:20 -0700116 optimizeMethod(&clazz->directMethods[i], essentialOnly);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700117 }
118 for (i = 0; i < clazz->virtualMethodCount; i++) {
Andy McFaddenfb119e62010-06-28 16:21:20 -0700119 optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700120 }
Andy McFadden2e1ee502010-03-24 13:25:53 -0700121}
122
123/*
124 * Optimize instructions in a method.
125 *
Andy McFadden228a6b02010-05-04 15:02:32 -0700126 * This does a single pass through the code, examining each instruction.
127 *
Andy McFaddenfb119e62010-06-28 16:21:20 -0700128 * This is not expected to fail if the class was successfully verified.
129 * The only significant failure modes occur when an "essential" update fails,
130 * but we can't generally identify those: if we can't look up a field,
131 * we can't know if the field access was supposed to be handled as volatile.
132 *
133 * Instead, we give it our best effort, and hope for the best. For 100%
134 * reliability, only optimize a class after verification succeeds.
Andy McFadden2e1ee502010-03-24 13:25:53 -0700135 */
Andy McFaddenfb119e62010-06-28 16:21:20 -0700136static void optimizeMethod(Method* method, bool essentialOnly)
Andy McFadden2e1ee502010-03-24 13:25:53 -0700137{
138 u4 insnsSize;
139 u2* insns;
140 u2 inst;
141
Andy McFaddenfb119e62010-06-28 16:21:20 -0700142 if (!gDvm.optimizing && !essentialOnly) {
143 /* unexpected; will force copy-on-write of a lot of pages */
144 LOGD("NOTE: doing full bytecode optimization outside dexopt\n");
145 }
146
Andy McFadden2e1ee502010-03-24 13:25:53 -0700147 if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
Andy McFaddenfb119e62010-06-28 16:21:20 -0700148 return;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700149
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700150 /* compute this once per method */
151 bool needRetBar = needsReturnBarrier(method);
152
Andy McFadden2e1ee502010-03-24 13:25:53 -0700153 insns = (u2*) method->insns;
154 assert(insns != NULL);
155 insnsSize = dvmGetMethodInsnsSize(method);
156
157 while (insnsSize > 0) {
Andy McFadden139516e2010-07-07 14:09:09 -0700158 OpCode quickOpc, volatileOpc = OP_NOP;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700159 int width;
Andy McFadden139516e2010-07-07 14:09:09 -0700160 bool notMatched = false;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700161
162 inst = *insns & 0xff;
163
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700164 /* "essential" substitutions, always checked */
Andy McFadden2e1ee502010-03-24 13:25:53 -0700165 switch (inst) {
166 case OP_IGET:
167 case OP_IGET_BOOLEAN:
168 case OP_IGET_BYTE:
169 case OP_IGET_CHAR:
170 case OP_IGET_SHORT:
Andy McFaddenfb119e62010-06-28 16:21:20 -0700171 quickOpc = OP_IGET_QUICK;
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700172 if (gDvm.dexOptForSmp)
Andy McFadden139516e2010-07-07 14:09:09 -0700173 volatileOpc = OP_IGET_VOLATILE;
Andy McFaddenfb119e62010-06-28 16:21:20 -0700174 goto rewrite_inst_field;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700175 case OP_IGET_WIDE:
Andy McFaddenfb119e62010-06-28 16:21:20 -0700176 quickOpc = OP_IGET_WIDE_QUICK;
177 volatileOpc = OP_IGET_WIDE_VOLATILE;
178 goto rewrite_inst_field;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700179 case OP_IGET_OBJECT:
Andy McFaddenfb119e62010-06-28 16:21:20 -0700180 quickOpc = OP_IGET_OBJECT_QUICK;
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700181 if (gDvm.dexOptForSmp)
Andy McFadden139516e2010-07-07 14:09:09 -0700182 volatileOpc = OP_IGET_OBJECT_VOLATILE;
Andy McFaddenfb119e62010-06-28 16:21:20 -0700183 goto rewrite_inst_field;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700184 case OP_IPUT:
185 case OP_IPUT_BOOLEAN:
186 case OP_IPUT_BYTE:
187 case OP_IPUT_CHAR:
188 case OP_IPUT_SHORT:
Andy McFaddenfb119e62010-06-28 16:21:20 -0700189 quickOpc = OP_IPUT_QUICK;
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700190 if (gDvm.dexOptForSmp)
Andy McFadden139516e2010-07-07 14:09:09 -0700191 volatileOpc = OP_IPUT_VOLATILE;
Andy McFaddenfb119e62010-06-28 16:21:20 -0700192 goto rewrite_inst_field;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700193 case OP_IPUT_WIDE:
Andy McFaddenfb119e62010-06-28 16:21:20 -0700194 quickOpc = OP_IPUT_WIDE_QUICK;
195 volatileOpc = OP_IPUT_WIDE_VOLATILE;
196 goto rewrite_inst_field;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700197 case OP_IPUT_OBJECT:
Andy McFaddenfb119e62010-06-28 16:21:20 -0700198 quickOpc = OP_IPUT_OBJECT_QUICK;
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700199 if (gDvm.dexOptForSmp)
Andy McFadden139516e2010-07-07 14:09:09 -0700200 volatileOpc = OP_IPUT_OBJECT_VOLATILE;
Andy McFaddenfb119e62010-06-28 16:21:20 -0700201rewrite_inst_field:
202 if (essentialOnly)
203 quickOpc = OP_NOP;
Andy McFadden139516e2010-07-07 14:09:09 -0700204 if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
205 rewriteInstField(method, insns, quickOpc, volatileOpc);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700206 break;
207
Andy McFadden139516e2010-07-07 14:09:09 -0700208 case OP_SGET_WIDE:
209 volatileOpc = OP_SGET_WIDE_VOLATILE;
210 goto rewrite_static_field;
211 case OP_SPUT_WIDE:
212 volatileOpc = OP_SPUT_WIDE_VOLATILE;
Andy McFaddenfb119e62010-06-28 16:21:20 -0700213rewrite_static_field:
214 rewriteStaticField(method, insns, volatileOpc);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700215 break;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700216 default:
Andy McFaddenfb119e62010-06-28 16:21:20 -0700217 notMatched = true;
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700218 break;
Andy McFaddenfb119e62010-06-28 16:21:20 -0700219 }
220
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700221 if (notMatched && gDvm.dexOptForSmp) {
222 /* additional "essential" substitutions for an SMP device */
223 switch (inst) {
224 case OP_SGET:
225 case OP_SGET_BOOLEAN:
226 case OP_SGET_BYTE:
227 case OP_SGET_CHAR:
228 case OP_SGET_SHORT:
229 volatileOpc = OP_SGET_VOLATILE;
230 goto rewrite_static_field2;
231 case OP_SGET_OBJECT:
232 volatileOpc = OP_SGET_OBJECT_VOLATILE;
233 goto rewrite_static_field2;
234 case OP_SPUT:
235 case OP_SPUT_BOOLEAN:
236 case OP_SPUT_BYTE:
237 case OP_SPUT_CHAR:
238 case OP_SPUT_SHORT:
239 volatileOpc = OP_SPUT_VOLATILE;
240 goto rewrite_static_field2;
241 case OP_SPUT_OBJECT:
242 volatileOpc = OP_SPUT_OBJECT_VOLATILE;
243rewrite_static_field2:
244 rewriteStaticField(method, insns, volatileOpc);
245 notMatched = false;
246 break;
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700247 case OP_RETURN_VOID:
248 if (needRetBar)
249 rewriteReturnVoid(method, insns);
250 notMatched = false;
251 break;
Andy McFaddenc58b9ef2010-09-09 12:54:43 -0700252 default:
253 assert(notMatched);
254 break;
255 }
256 }
257
258 /* non-essential substitutions */
Andy McFaddenfb119e62010-06-28 16:21:20 -0700259 if (notMatched && !essentialOnly) {
260 switch (inst) {
261 case OP_INVOKE_VIRTUAL:
262 if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
263 rewriteVirtualInvoke(method, insns,
264 OP_INVOKE_VIRTUAL_QUICK);
265 }
266 break;
267 case OP_INVOKE_VIRTUAL_RANGE:
268 if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
269 rewriteVirtualInvoke(method, insns,
270 OP_INVOKE_VIRTUAL_QUICK_RANGE);
271 }
272 break;
273 case OP_INVOKE_SUPER:
274 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
275 break;
276 case OP_INVOKE_SUPER_RANGE:
277 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
278 break;
279
280 case OP_INVOKE_DIRECT:
281 if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) {
282 rewriteEmptyDirectInvoke(method, insns);
283 }
284 break;
285 case OP_INVOKE_DIRECT_RANGE:
286 rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
287 break;
288
289 case OP_INVOKE_STATIC:
290 rewriteExecuteInline(method, insns, METHOD_STATIC);
291 break;
292 case OP_INVOKE_STATIC_RANGE:
293 rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
294 break;
295
296 default:
297 /* nothing to do for this instruction */
298 ;
299 }
Andy McFadden2e1ee502010-03-24 13:25:53 -0700300 }
301
Dan Bornstein54322392010-11-17 14:16:56 -0800302 width = dexGetInstrOrTableWidth(insns);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700303 assert(width > 0);
304
305 insns += width;
306 insnsSize -= width;
307 }
308
309 assert(insnsSize == 0);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700310}
311
Andy McFaddenfb119e62010-06-28 16:21:20 -0700312/*
313 * Update a 16-bit code unit in "meth".
314 */
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700315static inline void updateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
Andy McFaddenfb119e62010-06-28 16:21:20 -0700316{
317 if (gDvm.optimizing) {
318 /* dexopt time, alter the output directly */
319 *ptr = newVal;
320 } else {
321 /* runtime, toggle the page read/write status */
322 dvmDexChangeDex2(meth->clazz->pDvmDex, ptr, newVal);
323 }
324}
Andy McFadden2e1ee502010-03-24 13:25:53 -0700325
326/*
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700327 * Update the 8-bit opcode portion of a 16-bit code unit in "meth".
328 */
329static inline void updateOpCode(const Method* meth, u2* ptr, OpCode opCode)
330{
331 updateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opCode);
332}
333
334/*
Andy McFadden2e1ee502010-03-24 13:25:53 -0700335 * If "referrer" and "resClass" don't come from the same DEX file, and
336 * the DEX we're working on is not destined for the bootstrap class path,
337 * tweak the class loader so package-access checks work correctly.
338 *
339 * Only do this if we're doing pre-verification or optimization.
340 */
341static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
342{
343 if (!gDvm.optimizing)
344 return;
345 assert(referrer->classLoader == NULL);
346 assert(resClass->classLoader == NULL);
347
348 if (!gDvm.optimizingBootstrapClass) {
349 /* class loader for an array class comes from element type */
350 if (dvmIsArrayClass(resClass))
351 resClass = resClass->elementClass;
352 if (referrer->pDvmDex != resClass->pDvmDex)
353 resClass->classLoader = (Object*) 0xdead3333;
354 }
355}
356
357/*
358 * Undo the effects of tweakLoader.
359 */
360static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
361{
362 if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
363 return;
364
365 if (dvmIsArrayClass(resClass))
366 resClass = resClass->elementClass;
367 resClass->classLoader = NULL;
368}
369
370
371/*
372 * Alternate version of dvmResolveClass for use with verification and
373 * optimization. Performs access checks on every resolve, and refuses
374 * to acknowledge the existence of classes defined in more than one DEX
375 * file.
376 *
377 * Exceptions caused by failures are cleared before returning.
378 *
379 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
380 */
381ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
382 VerifyError* pFailure)
383{
384 DvmDex* pDvmDex = referrer->pDvmDex;
385 ClassObject* resClass;
386
387 /*
388 * Check the table first. If not there, do the lookup by name.
389 */
390 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
391 if (resClass == NULL) {
392 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
393 if (className[0] != '\0' && className[1] == '\0') {
394 /* primitive type */
395 resClass = dvmFindPrimitiveClass(className[0]);
396 } else {
397 resClass = dvmFindClassNoInit(className, referrer->classLoader);
398 }
399 if (resClass == NULL) {
400 /* not found, exception should be raised */
401 LOGV("DexOpt: class %d (%s) not found\n",
402 classIdx,
403 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
404 if (pFailure != NULL) {
405 /* dig through the wrappers to find the original failure */
406 Object* excep = dvmGetException(dvmThreadSelf());
407 while (true) {
408 Object* cause = dvmGetExceptionCause(excep);
409 if (cause == NULL)
410 break;
411 excep = cause;
412 }
413 if (strcmp(excep->clazz->descriptor,
414 "Ljava/lang/IncompatibleClassChangeError;") == 0)
415 {
416 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
417 } else {
418 *pFailure = VERIFY_ERROR_NO_CLASS;
419 }
420 }
421 dvmClearOptException(dvmThreadSelf());
422 return NULL;
423 }
424
425 /*
426 * Add it to the resolved table so we're faster on the next lookup.
427 */
428 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
429 }
430
431 /* multiple definitions? */
432 if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
433 LOGI("DexOpt: not resolving ambiguous class '%s'\n",
434 resClass->descriptor);
435 if (pFailure != NULL)
436 *pFailure = VERIFY_ERROR_NO_CLASS;
437 return NULL;
438 }
439
440 /* access allowed? */
441 tweakLoader(referrer, resClass);
442 bool allowed = dvmCheckClassAccess(referrer, resClass);
443 untweakLoader(referrer, resClass);
444 if (!allowed) {
445 LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
446 referrer->descriptor, resClass->descriptor);
447 if (pFailure != NULL)
448 *pFailure = VERIFY_ERROR_ACCESS_CLASS;
449 return NULL;
450 }
451
452 return resClass;
453}
454
455/*
456 * Alternate version of dvmResolveInstField().
457 *
458 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
459 */
460InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
461 VerifyError* pFailure)
462{
463 DvmDex* pDvmDex = referrer->pDvmDex;
464 InstField* resField;
465
466 resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
467 if (resField == NULL) {
468 const DexFieldId* pFieldId;
469 ClassObject* resClass;
470
471 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
472
473 /*
474 * Find the field's class.
475 */
476 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
477 if (resClass == NULL) {
478 //dvmClearOptException(dvmThreadSelf());
479 assert(!dvmCheckException(dvmThreadSelf()));
480 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
481 return NULL;
482 }
483
484 resField = (InstField*)dvmFindFieldHier(resClass,
485 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
486 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
487 if (resField == NULL) {
488 LOGD("DexOpt: couldn't find field %s.%s\n",
489 resClass->descriptor,
490 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
491 if (pFailure != NULL)
492 *pFailure = VERIFY_ERROR_NO_FIELD;
493 return NULL;
494 }
495 if (dvmIsStaticField(&resField->field)) {
496 LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
497 resClass->descriptor,
498 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
499 if (pFailure != NULL)
500 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
501 return NULL;
502 }
503
504 /*
505 * Add it to the resolved table so we're faster on the next lookup.
506 */
507 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
508 }
509
510 /* access allowed? */
511 tweakLoader(referrer, resField->field.clazz);
512 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
513 untweakLoader(referrer, resField->field.clazz);
514 if (!allowed) {
515 LOGI("DexOpt: access denied from %s to field %s.%s\n",
516 referrer->descriptor, resField->field.clazz->descriptor,
517 resField->field.name);
518 if (pFailure != NULL)
519 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
520 return NULL;
521 }
522
523 return resField;
524}
525
526/*
527 * Alternate version of dvmResolveStaticField().
528 *
529 * Does not force initialization of the resolved field's class.
530 *
531 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
532 */
533StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
534 VerifyError* pFailure)
535{
536 DvmDex* pDvmDex = referrer->pDvmDex;
537 StaticField* resField;
538
539 resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
540 if (resField == NULL) {
541 const DexFieldId* pFieldId;
542 ClassObject* resClass;
543
544 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
545
546 /*
547 * Find the field's class.
548 */
549 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
550 if (resClass == NULL) {
551 //dvmClearOptException(dvmThreadSelf());
552 assert(!dvmCheckException(dvmThreadSelf()));
553 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
554 return NULL;
555 }
556
557 resField = (StaticField*)dvmFindFieldHier(resClass,
558 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
559 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
560 if (resField == NULL) {
561 LOGD("DexOpt: couldn't find static field\n");
562 if (pFailure != NULL)
563 *pFailure = VERIFY_ERROR_NO_FIELD;
564 return NULL;
565 }
566 if (!dvmIsStaticField(&resField->field)) {
567 LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
568 resClass->descriptor,
569 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
570 if (pFailure != NULL)
571 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
572 return NULL;
573 }
574
575 /*
576 * Add it to the resolved table so we're faster on the next lookup.
577 *
578 * We can only do this if we're in "dexopt", because the presence
579 * of a valid value in the resolution table implies that the class
580 * containing the static field has been initialized.
581 */
582 if (gDvm.optimizing)
583 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
584 }
585
586 /* access allowed? */
587 tweakLoader(referrer, resField->field.clazz);
588 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
589 untweakLoader(referrer, resField->field.clazz);
590 if (!allowed) {
591 LOGI("DexOpt: access denied from %s to field %s.%s\n",
592 referrer->descriptor, resField->field.clazz->descriptor,
593 resField->field.name);
594 if (pFailure != NULL)
595 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
596 return NULL;
597 }
598
599 return resField;
600}
601
602
603/*
604 * Rewrite an iget/iput instruction. These all have the form:
605 * op vA, vB, field@CCCC
606 *
607 * Where vA holds the value, vB holds the object reference, and CCCC is
Andy McFaddenfb119e62010-06-28 16:21:20 -0700608 * the field reference constant pool offset. For a non-volatile field,
609 * we want to replace the opcode with "quickOpc" and replace CCCC with
610 * the byte offset from the start of the object. For a volatile field,
611 * we just want to replace the opcode with "volatileOpc".
Andy McFadden2e1ee502010-03-24 13:25:53 -0700612 *
Andy McFadden139516e2010-07-07 14:09:09 -0700613 * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
614 * field. If "quickOpc" is OP_NOP, and this is a non-volatile field,
615 * we don't do anything.
Andy McFaddenfb119e62010-06-28 16:21:20 -0700616 *
617 * "method" is the referring method.
Andy McFadden2e1ee502010-03-24 13:25:53 -0700618 */
Andy McFaddenfb119e62010-06-28 16:21:20 -0700619static bool rewriteInstField(Method* method, u2* insns, OpCode quickOpc,
620 OpCode volatileOpc)
Andy McFadden2e1ee502010-03-24 13:25:53 -0700621{
622 ClassObject* clazz = method->clazz;
623 u2 fieldIdx = insns[1];
Andy McFaddenfb119e62010-06-28 16:21:20 -0700624 InstField* instField;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700625
Andy McFaddenfb119e62010-06-28 16:21:20 -0700626 instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
627 if (instField == NULL) {
628 LOGI("DexOpt: unable to optimize instance field ref "
629 "0x%04x at 0x%02x in %s.%s\n",
Andy McFadden2e1ee502010-03-24 13:25:53 -0700630 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
631 method->name);
Andy McFaddenfb119e62010-06-28 16:21:20 -0700632 return false;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700633 }
634
Andy McFaddenfb119e62010-06-28 16:21:20 -0700635 if (instField->byteOffset >= 65536) {
636 LOGI("DexOpt: field offset exceeds 64K (%d)\n", instField->byteOffset);
637 return false;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700638 }
639
Andy McFadden139516e2010-07-07 14:09:09 -0700640 if (volatileOpc != OP_NOP && dvmIsVolatileField(&instField->field)) {
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700641 updateOpCode(method, insns, volatileOpc);
Andy McFaddenfb119e62010-06-28 16:21:20 -0700642 LOGV("DexOpt: rewrote ifield access %s.%s --> volatile\n",
643 instField->field.clazz->descriptor, instField->field.name);
644 } else if (quickOpc != OP_NOP) {
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700645 updateOpCode(method, insns, quickOpc);
646 updateCodeUnit(method, insns+1, (u2) instField->byteOffset);
Andy McFaddenfb119e62010-06-28 16:21:20 -0700647 LOGV("DexOpt: rewrote ifield access %s.%s --> %d\n",
648 instField->field.clazz->descriptor, instField->field.name,
649 instField->byteOffset);
650 } else {
651 LOGV("DexOpt: no rewrite of ifield access %s.%s\n",
652 instField->field.clazz->descriptor, instField->field.name);
653 }
654
655 return true;
656}
657
658/*
659 * Rewrite an sget/sput instruction. These all have the form:
660 * op vAA, field@BBBB
661 *
662 * Where vAA holds the value, and BBBB is the field reference constant
663 * pool offset. There is no "quick" form of static field accesses, so
664 * this is only useful for volatile fields.
665 *
666 * "method" is the referring method.
667 */
668static bool rewriteStaticField(Method* method, u2* insns, OpCode volatileOpc)
669{
670 ClassObject* clazz = method->clazz;
671 u2 fieldIdx = insns[1];
672 StaticField* staticField;
673
Andy McFadden139516e2010-07-07 14:09:09 -0700674 assert(volatileOpc != OP_NOP);
675
Andy McFaddenfb119e62010-06-28 16:21:20 -0700676 staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
677 if (staticField == NULL) {
678 LOGI("DexOpt: unable to optimize static field ref "
679 "0x%04x at 0x%02x in %s.%s\n",
680 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
681 method->name);
682 return false;
683 }
684
685 if (dvmIsVolatileField(&staticField->field)) {
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700686 updateOpCode(method, insns, volatileOpc);
Andy McFaddenfb119e62010-06-28 16:21:20 -0700687 LOGV("DexOpt: rewrote sfield access %s.%s --> volatile\n",
688 staticField->field.clazz->descriptor, staticField->field.name);
689 }
690
691 return true;
Andy McFadden2e1ee502010-03-24 13:25:53 -0700692}
693
694/*
695 * Alternate version of dvmResolveMethod().
696 *
697 * Doesn't throw exceptions, and checks access on every lookup.
698 *
699 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
700 */
701Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
702 MethodType methodType, VerifyError* pFailure)
703{
704 DvmDex* pDvmDex = referrer->pDvmDex;
705 Method* resMethod;
706
707 assert(methodType == METHOD_DIRECT ||
708 methodType == METHOD_VIRTUAL ||
709 methodType == METHOD_STATIC);
710
711 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
712 referrer->descriptor);
713
714 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
715 if (resMethod == NULL) {
716 const DexMethodId* pMethodId;
717 ClassObject* resClass;
718
719 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
720
721 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
722 if (resClass == NULL) {
723 /*
724 * Can't find the class that the method is a part of, or don't
725 * have permission to access the class.
726 */
727 LOGV("DexOpt: can't find called method's class (?.%s)\n",
728 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
729 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
730 return NULL;
731 }
732 if (dvmIsInterfaceClass(resClass)) {
733 /* method is part of an interface; this is wrong method for that */
734 LOGW("DexOpt: method is in an interface\n");
735 if (pFailure != NULL)
736 *pFailure = VERIFY_ERROR_GENERIC;
737 return NULL;
738 }
739
740 /*
741 * We need to chase up the class hierarchy to find methods defined
742 * in super-classes. (We only want to check the current class
743 * if we're looking for a constructor.)
744 */
745 DexProto proto;
746 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
747
748 if (methodType == METHOD_DIRECT) {
749 resMethod = dvmFindDirectMethod(resClass,
750 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
751 } else {
752 /* METHOD_STATIC or METHOD_VIRTUAL */
753 resMethod = dvmFindMethodHier(resClass,
754 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
755 }
756
757 if (resMethod == NULL) {
758 LOGV("DexOpt: couldn't find method '%s'\n",
759 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
760 if (pFailure != NULL)
761 *pFailure = VERIFY_ERROR_NO_METHOD;
762 return NULL;
763 }
764 if (methodType == METHOD_STATIC) {
765 if (!dvmIsStaticMethod(resMethod)) {
766 LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
767 resClass->descriptor, resMethod->name);
768 if (pFailure != NULL)
769 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
770 return NULL;
771 }
772 } else if (methodType == METHOD_VIRTUAL) {
773 if (dvmIsStaticMethod(resMethod)) {
774 LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
775 resClass->descriptor, resMethod->name);
776 if (pFailure != NULL)
777 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
778 return NULL;
779 }
780 }
781
782 /* see if this is a pure-abstract method */
783 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
784 LOGW("DexOpt: pure-abstract method '%s' in %s\n",
785 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
786 resClass->descriptor);
787 if (pFailure != NULL)
788 *pFailure = VERIFY_ERROR_GENERIC;
789 return NULL;
790 }
791
792 /*
793 * Add it to the resolved table so we're faster on the next lookup.
794 *
795 * We can only do this for static methods if we're not in "dexopt",
796 * because the presence of a valid value in the resolution table
797 * implies that the class containing the static field has been
798 * initialized.
799 */
800 if (methodType != METHOD_STATIC || gDvm.optimizing)
801 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
802 }
803
804 LOGVV("--- found method %d (%s.%s)\n",
805 methodIdx, resMethod->clazz->descriptor, resMethod->name);
806
807 /* access allowed? */
808 tweakLoader(referrer, resMethod->clazz);
809 bool allowed = dvmCheckMethodAccess(referrer, resMethod);
810 untweakLoader(referrer, resMethod->clazz);
811 if (!allowed) {
812 IF_LOGI() {
813 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
814 LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
815 resMethod->clazz->descriptor, resMethod->name, desc,
816 referrer->descriptor);
817 free(desc);
818 }
819 if (pFailure != NULL)
820 *pFailure = VERIFY_ERROR_ACCESS_METHOD;
821 return NULL;
822 }
823
824 return resMethod;
825}
826
827/*
828 * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
829 * invoke-super/range. These all have the form:
830 * op vAA, meth@BBBB, reg stuff @CCCC
831 *
832 * We want to replace the method constant pool index BBBB with the
833 * vtable index.
834 */
835static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
836{
837 ClassObject* clazz = method->clazz;
838 Method* baseMethod;
839 u2 methodIdx = insns[1];
840
841 baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
842 if (baseMethod == NULL) {
843 LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
844 methodIdx,
845 (int) (insns - method->insns), clazz->descriptor,
846 method->name);
847 return false;
848 }
849
850 assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
851 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
852 (insns[0] & 0xff) == OP_INVOKE_SUPER ||
853 (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
854
855 /*
856 * Note: Method->methodIndex is a u2 and is range checked during the
857 * initial load.
858 */
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700859 updateOpCode(method, insns, newOpc);
860 updateCodeUnit(method, insns+1, baseMethod->methodIndex);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700861
862 //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
863 // method->clazz->descriptor, method->name,
864 // baseMethod->clazz->descriptor, baseMethod->name);
865
866 return true;
867}
868
869/*
870 * Rewrite invoke-direct, which has the form:
871 * op vAA, meth@BBBB, reg stuff @CCCC
872 *
873 * There isn't a lot we can do to make this faster, but in some situations
874 * we can make it go away entirely.
875 *
876 * This must only be used when the invoked method does nothing and has
877 * no return value (the latter being very important for verification).
878 */
879static bool rewriteEmptyDirectInvoke(Method* method, u2* insns)
880{
881 ClassObject* clazz = method->clazz;
882 Method* calledMethod;
883 u2 methodIdx = insns[1];
884
885 calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
886 if (calledMethod == NULL) {
887 LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
888 methodIdx,
889 (int) (insns - method->insns), clazz->descriptor,
890 method->name);
891 return false;
892 }
893
894 /* TODO: verify that java.lang.Object() is actually empty! */
895 if (calledMethod->clazz == gDvm.classJavaLangObject &&
896 dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
897 {
898 /*
899 * Replace with "empty" instruction. DO NOT disturb anything
900 * else about it, as we want it to function the same as
901 * OP_INVOKE_DIRECT when debugging is enabled.
902 */
903 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
Andy McFadden3f4b63f2010-09-13 14:04:02 -0700904 updateOpCode(method, insns, OP_INVOKE_DIRECT_EMPTY);
Andy McFadden2e1ee502010-03-24 13:25:53 -0700905
906 //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
907 // method->clazz->descriptor, method->name,
908 // calledMethod->clazz->descriptor, calledMethod->name);
909 }
910
911 return true;
912}
913
914/*
915 * Resolve an interface method reference.
916 *
917 * No method access check here -- interface methods are always public.
918 *
919 * Returns NULL if the method was not found. Does not throw an exception.
920 */
921Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
922{
923 DvmDex* pDvmDex = referrer->pDvmDex;
924 Method* resMethod;
925 int i;
926
927 LOGVV("--- resolving interface method %d (referrer=%s)\n",
928 methodIdx, referrer->descriptor);
929
930 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
931 if (resMethod == NULL) {
932 const DexMethodId* pMethodId;
933 ClassObject* resClass;
934
935 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
936
937 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
938 if (resClass == NULL) {
939 /* can't find the class that the method is a part of */
940 dvmClearOptException(dvmThreadSelf());
941 return NULL;
942 }
943 if (!dvmIsInterfaceClass(resClass)) {
944 /* whoops */
945 LOGI("Interface method not part of interface class\n");
946 return NULL;
947 }
948
949 const char* methodName =
950 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
951 DexProto proto;
952 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
953
954 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
955 methodName, methodSig, resClass->descriptor);
956 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
957 if (resMethod == NULL) {
958 /* scan superinterfaces and superclass interfaces */
959 LOGVV("+++ did not resolve immediately\n");
960 for (i = 0; i < resClass->iftableCount; i++) {
961 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
962 methodName, &proto);
963 if (resMethod != NULL)
964 break;
965 }
966
967 if (resMethod == NULL) {
968 LOGVV("+++ unable to resolve method %s\n", methodName);
969 return NULL;
970 }
971 } else {
972 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
973 resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
974 }
975
976 /* we're expecting this to be abstract */
977 if (!dvmIsAbstractMethod(resMethod)) {
978 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
979 LOGW("Found non-abstract interface method %s.%s %s\n",
980 resMethod->clazz->descriptor, resMethod->name, desc);
981 free(desc);
982 return NULL;
983 }
984
985 /*
986 * Add it to the resolved table so we're faster on the next lookup.
987 */
988 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
989 }
990
991 LOGVV("--- found interface method %d (%s.%s)\n",
992 methodIdx, resMethod->clazz->descriptor, resMethod->name);
993
994 /* interface methods are always public; no need to check access */
995
996 return resMethod;
997}
998
999/*
1000 * See if the method being called can be rewritten as an inline operation.
1001 * Works for invoke-virtual, invoke-direct, and invoke-static.
1002 *
1003 * Returns "true" if we replace it.
1004 */
1005static bool rewriteExecuteInline(Method* method, u2* insns,
Andy McFaddencb3c5422010-04-07 15:56:16 -07001006 MethodType methodType)
Andy McFadden2e1ee502010-03-24 13:25:53 -07001007{
Andy McFaddencb3c5422010-04-07 15:56:16 -07001008 const InlineSub* inlineSubs = gDvm.inlineSubs;
Andy McFadden2e1ee502010-03-24 13:25:53 -07001009 ClassObject* clazz = method->clazz;
1010 Method* calledMethod;
1011 u2 methodIdx = insns[1];
1012
1013 //return false;
1014
1015 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1016 if (calledMethod == NULL) {
1017 LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
1018 return false;
1019 }
1020
1021 while (inlineSubs->method != NULL) {
1022 /*
1023 if (extra) {
1024 LOGI("comparing %p vs %p %s.%s %s\n",
1025 inlineSubs->method, calledMethod,
1026 inlineSubs->method->clazz->descriptor,
1027 inlineSubs->method->name,
1028 inlineSubs->method->signature);
1029 }
1030 */
1031 if (inlineSubs->method == calledMethod) {
1032 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
1033 (insns[0] & 0xff) == OP_INVOKE_STATIC ||
1034 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
Andy McFadden3f4b63f2010-09-13 14:04:02 -07001035 updateOpCode(method, insns, OP_EXECUTE_INLINE);
1036 updateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
Andy McFadden2e1ee502010-03-24 13:25:53 -07001037
1038 //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
1039 // method->clazz->descriptor, method->name,
1040 // calledMethod->clazz->descriptor, calledMethod->name);
1041 return true;
1042 }
1043
1044 inlineSubs++;
1045 }
1046
1047 return false;
1048}
1049
1050/*
1051 * See if the method being called can be rewritten as an inline operation.
1052 * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
1053 *
1054 * Returns "true" if we replace it.
1055 */
1056static bool rewriteExecuteInlineRange(Method* method, u2* insns,
Andy McFaddencb3c5422010-04-07 15:56:16 -07001057 MethodType methodType)
Andy McFadden2e1ee502010-03-24 13:25:53 -07001058{
Andy McFaddencb3c5422010-04-07 15:56:16 -07001059 const InlineSub* inlineSubs = gDvm.inlineSubs;
Andy McFadden2e1ee502010-03-24 13:25:53 -07001060 ClassObject* clazz = method->clazz;
1061 Method* calledMethod;
1062 u2 methodIdx = insns[1];
1063
1064 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1065 if (calledMethod == NULL) {
1066 LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
1067 return false;
1068 }
1069
1070 while (inlineSubs->method != NULL) {
1071 if (inlineSubs->method == calledMethod) {
1072 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
1073 (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
1074 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
Andy McFadden3f4b63f2010-09-13 14:04:02 -07001075 updateOpCode(method, insns, OP_EXECUTE_INLINE_RANGE);
1076 updateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
Andy McFadden2e1ee502010-03-24 13:25:53 -07001077
1078 //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
1079 // method->clazz->descriptor, method->name,
1080 // calledMethod->clazz->descriptor, calledMethod->name);
1081 return true;
1082 }
1083
1084 inlineSubs++;
1085 }
1086
1087 return false;
1088}
Andy McFadden3f4b63f2010-09-13 14:04:02 -07001089
1090/*
1091 * Returns "true" if the return-void instructions in this method should
1092 * be converted to return-void-barrier.
1093 *
1094 * This is needed to satisfy a Java Memory Model requirement regarding
1095 * the construction of objects with final fields. (This does not apply
1096 * to <clinit> or static fields, since appropriate barriers are guaranteed
1097 * by the class initialization process.)
1098 */
1099static bool needsReturnBarrier(Method* method)
1100{
1101 if (!gDvm.dexOptForSmp)
1102 return false;
1103 if (strcmp(method->name, "<init>") != 0)
1104 return false;
1105
1106 /*
1107 * Check to see if the class has any final fields. If not, we don't
1108 * need to generate a barrier instruction.
1109 */
1110 const ClassObject* clazz = method->clazz;
1111 int idx = clazz->ifieldCount;
1112 while (--idx >= 0) {
1113 if (dvmIsFinalField(&clazz->ifields[idx].field))
1114 break;
1115 }
1116 if (idx < 0)
1117 return false;
1118
1119 /*
1120 * In theory, we only need to do this if the method actually modifies
1121 * a final field. In practice, non-constructor methods are allowed
1122 * to modify final fields by the VM, and there are tools that rely on
1123 * this behavior. (The compiler does not allow it.)
1124 *
1125 * If we alter the verifier to restrict final-field updates to
1126 * constructors, we can tighten this up as well.
1127 */
1128
1129 return true;
1130}
1131
1132/*
1133 * Convert a return-void to a return-void-barrier.
1134 */
1135static void rewriteReturnVoid(Method* method, u2* insns)
1136{
1137 assert((insns[0] & 0xff) == OP_RETURN_VOID);
1138 updateOpCode(method, insns, OP_RETURN_VOID_BARRIER);
1139}