2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Perform some simple bytecode optimizations, chiefly "quickening" of
22 #include "libdex/InstrUtils.h"
29 * Virtual/direct calls to "method" are replaced with an execute-inline
30 * instruction with index "idx".
39 static void optimizeMethod(Method* method, bool essentialOnly);
40 static bool rewriteInstField(Method* method, u2* insns, OpCode quickOpc,
42 static bool rewriteStaticField(Method* method, u2* insns, OpCode volatileOpc);
43 static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc);
44 static bool rewriteEmptyDirectInvoke(Method* method, u2* insns);
45 static bool rewriteExecuteInline(Method* method, u2* insns,
46 MethodType methodType);
47 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
48 MethodType methodType);
49 static void rewriteReturnVoid(Method* method, u2* insns);
50 static bool needsReturnBarrier(Method* method);
54 * Create a table of inline substitutions.
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.
59 InlineSub* dvmCreateInlineSubsTable(void)
61 const InlineOperation* ops = dvmGetInlineOpsTable();
62 const int count = dvmGetInlineOpsTableLength();
69 * Allocate for optimism: one slot per entry, plus an end-of-list marker.
71 table = malloc(sizeof(InlineSub) * (count+1));
74 for (i = 0; i < count; i++) {
75 clazz = dvmFindClassNoInit(ops[i].classDescriptor, NULL);
77 LOGV("DexOpt: can't inline for class '%s': not found\n",
78 ops[i].classDescriptor);
79 dvmClearOptException(dvmThreadSelf());
82 * Method could be virtual or direct. Try both. Don't use
83 * the "hier" versions.
85 method = dvmFindDirectMethodByDescriptor(clazz, ops[i].methodName,
86 ops[i].methodSignature);
88 method = dvmFindVirtualMethodByDescriptor(clazz, ops[i].methodName,
89 ops[i].methodSignature);
91 LOGW("DexOpt: can't inline %s.%s %s: method not found\n",
92 ops[i].classDescriptor, ops[i].methodName,
93 ops[i].methodSignature);
95 if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
96 LOGW("DexOpt: WARNING: inline op on non-final class/method "
98 clazz->descriptor, method->name);
101 if (dvmIsSynchronizedMethod(method) ||
102 dvmIsDeclaredSynchronizedMethod(method))
104 LOGW("DexOpt: WARNING: inline op on synchronized method "
106 clazz->descriptor, method->name);
110 table[tableIndex].method = method;
111 table[tableIndex].inlineIdx = i;
114 LOGV("DexOpt: will inline %d: %s.%s %s\n", i,
115 ops[i].classDescriptor, ops[i].methodName,
116 ops[i].methodSignature);
121 /* mark end of table */
122 table[tableIndex].method = NULL;
123 LOGV("DexOpt: inline table has %d entries\n", tableIndex);
129 * Release inline sub data structure.
131 void dvmFreeInlineSubsTable(InlineSub* inlineSubs)
138 * Optimize the specified class.
140 * If "essentialOnly" is true, we only do essential optimizations. For
141 * example, accesses to volatile 64-bit fields must be replaced with
142 * "-wide-volatile" instructions or the program could behave incorrectly.
143 * (Skipping non-essential optimizations makes us a little bit faster, and
144 * more importantly avoids dirtying DEX pages.)
146 void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
150 for (i = 0; i < clazz->directMethodCount; i++) {
151 optimizeMethod(&clazz->directMethods[i], essentialOnly);
153 for (i = 0; i < clazz->virtualMethodCount; i++) {
154 optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
159 * Optimize instructions in a method.
161 * This does a single pass through the code, examining each instruction.
163 * This is not expected to fail if the class was successfully verified.
164 * The only significant failure modes occur when an "essential" update fails,
165 * but we can't generally identify those: if we can't look up a field,
166 * we can't know if the field access was supposed to be handled as volatile.
168 * Instead, we give it our best effort, and hope for the best. For 100%
169 * reliability, only optimize a class after verification succeeds.
171 static void optimizeMethod(Method* method, bool essentialOnly)
177 if (!gDvm.optimizing && !essentialOnly) {
178 /* unexpected; will force copy-on-write of a lot of pages */
179 LOGD("NOTE: doing full bytecode optimization outside dexopt\n");
182 if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
185 /* compute this once per method */
186 bool needRetBar = needsReturnBarrier(method);
188 insns = (u2*) method->insns;
189 assert(insns != NULL);
190 insnsSize = dvmGetMethodInsnsSize(method);
192 while (insnsSize > 0) {
193 OpCode quickOpc, volatileOpc = OP_NOP;
195 bool notMatched = false;
197 inst = *insns & 0xff;
199 /* "essential" substitutions, always checked */
202 case OP_IGET_BOOLEAN:
206 quickOpc = OP_IGET_QUICK;
207 if (gDvm.dexOptForSmp)
208 volatileOpc = OP_IGET_VOLATILE;
209 goto rewrite_inst_field;
211 quickOpc = OP_IGET_WIDE_QUICK;
212 volatileOpc = OP_IGET_WIDE_VOLATILE;
213 goto rewrite_inst_field;
215 quickOpc = OP_IGET_OBJECT_QUICK;
216 if (gDvm.dexOptForSmp)
217 volatileOpc = OP_IGET_OBJECT_VOLATILE;
218 goto rewrite_inst_field;
220 case OP_IPUT_BOOLEAN:
224 quickOpc = OP_IPUT_QUICK;
225 if (gDvm.dexOptForSmp)
226 volatileOpc = OP_IPUT_VOLATILE;
227 goto rewrite_inst_field;
229 quickOpc = OP_IPUT_WIDE_QUICK;
230 volatileOpc = OP_IPUT_WIDE_VOLATILE;
231 goto rewrite_inst_field;
233 quickOpc = OP_IPUT_OBJECT_QUICK;
234 if (gDvm.dexOptForSmp)
235 volatileOpc = OP_IPUT_OBJECT_VOLATILE;
239 if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
240 rewriteInstField(method, insns, quickOpc, volatileOpc);
244 volatileOpc = OP_SGET_WIDE_VOLATILE;
245 goto rewrite_static_field;
247 volatileOpc = OP_SPUT_WIDE_VOLATILE;
248 rewrite_static_field:
249 rewriteStaticField(method, insns, volatileOpc);
256 if (notMatched && gDvm.dexOptForSmp) {
257 /* additional "essential" substitutions for an SMP device */
260 case OP_SGET_BOOLEAN:
264 volatileOpc = OP_SGET_VOLATILE;
265 goto rewrite_static_field2;
267 volatileOpc = OP_SGET_OBJECT_VOLATILE;
268 goto rewrite_static_field2;
270 case OP_SPUT_BOOLEAN:
274 volatileOpc = OP_SPUT_VOLATILE;
275 goto rewrite_static_field2;
277 volatileOpc = OP_SPUT_OBJECT_VOLATILE;
278 rewrite_static_field2:
279 rewriteStaticField(method, insns, volatileOpc);
284 rewriteReturnVoid(method, insns);
293 /* non-essential substitutions */
294 if (notMatched && !essentialOnly) {
296 case OP_INVOKE_VIRTUAL:
297 if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
298 rewriteVirtualInvoke(method, insns,
299 OP_INVOKE_VIRTUAL_QUICK);
302 case OP_INVOKE_VIRTUAL_RANGE:
303 if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
304 rewriteVirtualInvoke(method, insns,
305 OP_INVOKE_VIRTUAL_QUICK_RANGE);
308 case OP_INVOKE_SUPER:
309 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
311 case OP_INVOKE_SUPER_RANGE:
312 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
315 case OP_INVOKE_DIRECT:
316 if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) {
317 rewriteEmptyDirectInvoke(method, insns);
320 case OP_INVOKE_DIRECT_RANGE:
321 rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
324 case OP_INVOKE_STATIC:
325 rewriteExecuteInline(method, insns, METHOD_STATIC);
327 case OP_INVOKE_STATIC_RANGE:
328 rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
332 /* nothing to do for this instruction */
337 width = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, insns);
344 assert(insnsSize == 0);
348 * Update a 16-bit code unit in "meth".
350 static inline void updateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
352 if (gDvm.optimizing) {
353 /* dexopt time, alter the output directly */
356 /* runtime, toggle the page read/write status */
357 dvmDexChangeDex2(meth->clazz->pDvmDex, ptr, newVal);
362 * Update the 8-bit opcode portion of a 16-bit code unit in "meth".
364 static inline void updateOpCode(const Method* meth, u2* ptr, OpCode opCode)
366 updateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opCode);
370 * If "referrer" and "resClass" don't come from the same DEX file, and
371 * the DEX we're working on is not destined for the bootstrap class path,
372 * tweak the class loader so package-access checks work correctly.
374 * Only do this if we're doing pre-verification or optimization.
376 static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
378 if (!gDvm.optimizing)
380 assert(referrer->classLoader == NULL);
381 assert(resClass->classLoader == NULL);
383 if (!gDvm.optimizingBootstrapClass) {
384 /* class loader for an array class comes from element type */
385 if (dvmIsArrayClass(resClass))
386 resClass = resClass->elementClass;
387 if (referrer->pDvmDex != resClass->pDvmDex)
388 resClass->classLoader = (Object*) 0xdead3333;
393 * Undo the effects of tweakLoader.
395 static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
397 if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
400 if (dvmIsArrayClass(resClass))
401 resClass = resClass->elementClass;
402 resClass->classLoader = NULL;
407 * Alternate version of dvmResolveClass for use with verification and
408 * optimization. Performs access checks on every resolve, and refuses
409 * to acknowledge the existence of classes defined in more than one DEX
412 * Exceptions caused by failures are cleared before returning.
414 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
416 ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
417 VerifyError* pFailure)
419 DvmDex* pDvmDex = referrer->pDvmDex;
420 ClassObject* resClass;
423 * Check the table first. If not there, do the lookup by name.
425 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
426 if (resClass == NULL) {
427 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
428 if (className[0] != '\0' && className[1] == '\0') {
430 resClass = dvmFindPrimitiveClass(className[0]);
432 resClass = dvmFindClassNoInit(className, referrer->classLoader);
434 if (resClass == NULL) {
435 /* not found, exception should be raised */
436 LOGV("DexOpt: class %d (%s) not found\n",
438 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
439 if (pFailure != NULL) {
440 /* dig through the wrappers to find the original failure */
441 Object* excep = dvmGetException(dvmThreadSelf());
443 Object* cause = dvmGetExceptionCause(excep);
448 if (strcmp(excep->clazz->descriptor,
449 "Ljava/lang/IncompatibleClassChangeError;") == 0)
451 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
453 *pFailure = VERIFY_ERROR_NO_CLASS;
456 dvmClearOptException(dvmThreadSelf());
461 * Add it to the resolved table so we're faster on the next lookup.
463 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
466 /* multiple definitions? */
467 if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
468 LOGI("DexOpt: not resolving ambiguous class '%s'\n",
469 resClass->descriptor);
470 if (pFailure != NULL)
471 *pFailure = VERIFY_ERROR_NO_CLASS;
475 /* access allowed? */
476 tweakLoader(referrer, resClass);
477 bool allowed = dvmCheckClassAccess(referrer, resClass);
478 untweakLoader(referrer, resClass);
480 LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
481 referrer->descriptor, resClass->descriptor);
482 if (pFailure != NULL)
483 *pFailure = VERIFY_ERROR_ACCESS_CLASS;
491 * Alternate version of dvmResolveInstField().
493 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
495 InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
496 VerifyError* pFailure)
498 DvmDex* pDvmDex = referrer->pDvmDex;
501 resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
502 if (resField == NULL) {
503 const DexFieldId* pFieldId;
504 ClassObject* resClass;
506 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
509 * Find the field's class.
511 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
512 if (resClass == NULL) {
513 //dvmClearOptException(dvmThreadSelf());
514 assert(!dvmCheckException(dvmThreadSelf()));
515 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
519 resField = (InstField*)dvmFindFieldHier(resClass,
520 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
521 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
522 if (resField == NULL) {
523 LOGD("DexOpt: couldn't find field %s.%s\n",
524 resClass->descriptor,
525 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
526 if (pFailure != NULL)
527 *pFailure = VERIFY_ERROR_NO_FIELD;
530 if (dvmIsStaticField(&resField->field)) {
531 LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
532 resClass->descriptor,
533 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
534 if (pFailure != NULL)
535 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
540 * Add it to the resolved table so we're faster on the next lookup.
542 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
545 /* access allowed? */
546 tweakLoader(referrer, resField->field.clazz);
547 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
548 untweakLoader(referrer, resField->field.clazz);
550 LOGI("DexOpt: access denied from %s to field %s.%s\n",
551 referrer->descriptor, resField->field.clazz->descriptor,
552 resField->field.name);
553 if (pFailure != NULL)
554 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
562 * Alternate version of dvmResolveStaticField().
564 * Does not force initialization of the resolved field's class.
566 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
568 StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
569 VerifyError* pFailure)
571 DvmDex* pDvmDex = referrer->pDvmDex;
572 StaticField* resField;
574 resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
575 if (resField == NULL) {
576 const DexFieldId* pFieldId;
577 ClassObject* resClass;
579 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
582 * Find the field's class.
584 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
585 if (resClass == NULL) {
586 //dvmClearOptException(dvmThreadSelf());
587 assert(!dvmCheckException(dvmThreadSelf()));
588 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
592 resField = (StaticField*)dvmFindFieldHier(resClass,
593 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
594 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
595 if (resField == NULL) {
596 LOGD("DexOpt: couldn't find static field\n");
597 if (pFailure != NULL)
598 *pFailure = VERIFY_ERROR_NO_FIELD;
601 if (!dvmIsStaticField(&resField->field)) {
602 LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
603 resClass->descriptor,
604 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
605 if (pFailure != NULL)
606 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
611 * Add it to the resolved table so we're faster on the next lookup.
613 * We can only do this if we're in "dexopt", because the presence
614 * of a valid value in the resolution table implies that the class
615 * containing the static field has been initialized.
618 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
621 /* access allowed? */
622 tweakLoader(referrer, resField->field.clazz);
623 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
624 untweakLoader(referrer, resField->field.clazz);
626 LOGI("DexOpt: access denied from %s to field %s.%s\n",
627 referrer->descriptor, resField->field.clazz->descriptor,
628 resField->field.name);
629 if (pFailure != NULL)
630 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
639 * Rewrite an iget/iput instruction. These all have the form:
640 * op vA, vB, field@CCCC
642 * Where vA holds the value, vB holds the object reference, and CCCC is
643 * the field reference constant pool offset. For a non-volatile field,
644 * we want to replace the opcode with "quickOpc" and replace CCCC with
645 * the byte offset from the start of the object. For a volatile field,
646 * we just want to replace the opcode with "volatileOpc".
648 * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
649 * field. If "quickOpc" is OP_NOP, and this is a non-volatile field,
650 * we don't do anything.
652 * "method" is the referring method.
654 static bool rewriteInstField(Method* method, u2* insns, OpCode quickOpc,
657 ClassObject* clazz = method->clazz;
658 u2 fieldIdx = insns[1];
659 InstField* instField;
661 instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
662 if (instField == NULL) {
663 LOGI("DexOpt: unable to optimize instance field ref "
664 "0x%04x at 0x%02x in %s.%s\n",
665 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
670 if (instField->byteOffset >= 65536) {
671 LOGI("DexOpt: field offset exceeds 64K (%d)\n", instField->byteOffset);
675 if (volatileOpc != OP_NOP && dvmIsVolatileField(&instField->field)) {
676 updateOpCode(method, insns, volatileOpc);
677 LOGV("DexOpt: rewrote ifield access %s.%s --> volatile\n",
678 instField->field.clazz->descriptor, instField->field.name);
679 } else if (quickOpc != OP_NOP) {
680 updateOpCode(method, insns, quickOpc);
681 updateCodeUnit(method, insns+1, (u2) instField->byteOffset);
682 LOGV("DexOpt: rewrote ifield access %s.%s --> %d\n",
683 instField->field.clazz->descriptor, instField->field.name,
684 instField->byteOffset);
686 LOGV("DexOpt: no rewrite of ifield access %s.%s\n",
687 instField->field.clazz->descriptor, instField->field.name);
694 * Rewrite an sget/sput instruction. These all have the form:
697 * Where vAA holds the value, and BBBB is the field reference constant
698 * pool offset. There is no "quick" form of static field accesses, so
699 * this is only useful for volatile fields.
701 * "method" is the referring method.
703 static bool rewriteStaticField(Method* method, u2* insns, OpCode volatileOpc)
705 ClassObject* clazz = method->clazz;
706 u2 fieldIdx = insns[1];
707 StaticField* staticField;
709 assert(volatileOpc != OP_NOP);
711 staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
712 if (staticField == NULL) {
713 LOGI("DexOpt: unable to optimize static field ref "
714 "0x%04x at 0x%02x in %s.%s\n",
715 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
720 if (dvmIsVolatileField(&staticField->field)) {
721 updateOpCode(method, insns, volatileOpc);
722 LOGV("DexOpt: rewrote sfield access %s.%s --> volatile\n",
723 staticField->field.clazz->descriptor, staticField->field.name);
730 * Alternate version of dvmResolveMethod().
732 * Doesn't throw exceptions, and checks access on every lookup.
734 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
736 Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
737 MethodType methodType, VerifyError* pFailure)
739 DvmDex* pDvmDex = referrer->pDvmDex;
742 assert(methodType == METHOD_DIRECT ||
743 methodType == METHOD_VIRTUAL ||
744 methodType == METHOD_STATIC);
746 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
747 referrer->descriptor);
749 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
750 if (resMethod == NULL) {
751 const DexMethodId* pMethodId;
752 ClassObject* resClass;
754 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
756 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
757 if (resClass == NULL) {
759 * Can't find the class that the method is a part of, or don't
760 * have permission to access the class.
762 LOGV("DexOpt: can't find called method's class (?.%s)\n",
763 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
764 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
767 if (dvmIsInterfaceClass(resClass)) {
768 /* method is part of an interface; this is wrong method for that */
769 LOGW("DexOpt: method is in an interface\n");
770 if (pFailure != NULL)
771 *pFailure = VERIFY_ERROR_GENERIC;
776 * We need to chase up the class hierarchy to find methods defined
777 * in super-classes. (We only want to check the current class
778 * if we're looking for a constructor.)
781 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
783 if (methodType == METHOD_DIRECT) {
784 resMethod = dvmFindDirectMethod(resClass,
785 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
787 /* METHOD_STATIC or METHOD_VIRTUAL */
788 resMethod = dvmFindMethodHier(resClass,
789 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
792 if (resMethod == NULL) {
793 LOGV("DexOpt: couldn't find method '%s'\n",
794 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
795 if (pFailure != NULL)
796 *pFailure = VERIFY_ERROR_NO_METHOD;
799 if (methodType == METHOD_STATIC) {
800 if (!dvmIsStaticMethod(resMethod)) {
801 LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
802 resClass->descriptor, resMethod->name);
803 if (pFailure != NULL)
804 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
807 } else if (methodType == METHOD_VIRTUAL) {
808 if (dvmIsStaticMethod(resMethod)) {
809 LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
810 resClass->descriptor, resMethod->name);
811 if (pFailure != NULL)
812 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
817 /* see if this is a pure-abstract method */
818 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
819 LOGW("DexOpt: pure-abstract method '%s' in %s\n",
820 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
821 resClass->descriptor);
822 if (pFailure != NULL)
823 *pFailure = VERIFY_ERROR_GENERIC;
828 * Add it to the resolved table so we're faster on the next lookup.
830 * We can only do this for static methods if we're not in "dexopt",
831 * because the presence of a valid value in the resolution table
832 * implies that the class containing the static field has been
835 if (methodType != METHOD_STATIC || gDvm.optimizing)
836 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
839 LOGVV("--- found method %d (%s.%s)\n",
840 methodIdx, resMethod->clazz->descriptor, resMethod->name);
842 /* access allowed? */
843 tweakLoader(referrer, resMethod->clazz);
844 bool allowed = dvmCheckMethodAccess(referrer, resMethod);
845 untweakLoader(referrer, resMethod->clazz);
848 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
849 LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
850 resMethod->clazz->descriptor, resMethod->name, desc,
851 referrer->descriptor);
854 if (pFailure != NULL)
855 *pFailure = VERIFY_ERROR_ACCESS_METHOD;
863 * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
864 * invoke-super/range. These all have the form:
865 * op vAA, meth@BBBB, reg stuff @CCCC
867 * We want to replace the method constant pool index BBBB with the
870 static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
872 ClassObject* clazz = method->clazz;
874 u2 methodIdx = insns[1];
876 baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
877 if (baseMethod == NULL) {
878 LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
880 (int) (insns - method->insns), clazz->descriptor,
885 assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
886 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
887 (insns[0] & 0xff) == OP_INVOKE_SUPER ||
888 (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
891 * Note: Method->methodIndex is a u2 and is range checked during the
894 updateOpCode(method, insns, newOpc);
895 updateCodeUnit(method, insns+1, baseMethod->methodIndex);
897 //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
898 // method->clazz->descriptor, method->name,
899 // baseMethod->clazz->descriptor, baseMethod->name);
905 * Rewrite invoke-direct, which has the form:
906 * op vAA, meth@BBBB, reg stuff @CCCC
908 * There isn't a lot we can do to make this faster, but in some situations
909 * we can make it go away entirely.
911 * This must only be used when the invoked method does nothing and has
912 * no return value (the latter being very important for verification).
914 static bool rewriteEmptyDirectInvoke(Method* method, u2* insns)
916 ClassObject* clazz = method->clazz;
917 Method* calledMethod;
918 u2 methodIdx = insns[1];
920 calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
921 if (calledMethod == NULL) {
922 LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
924 (int) (insns - method->insns), clazz->descriptor,
929 /* TODO: verify that java.lang.Object() is actually empty! */
930 if (calledMethod->clazz == gDvm.classJavaLangObject &&
931 dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
934 * Replace with "empty" instruction. DO NOT disturb anything
935 * else about it, as we want it to function the same as
936 * OP_INVOKE_DIRECT when debugging is enabled.
938 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
939 updateOpCode(method, insns, OP_INVOKE_DIRECT_EMPTY);
941 //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
942 // method->clazz->descriptor, method->name,
943 // calledMethod->clazz->descriptor, calledMethod->name);
950 * Resolve an interface method reference.
952 * No method access check here -- interface methods are always public.
954 * Returns NULL if the method was not found. Does not throw an exception.
956 Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
958 DvmDex* pDvmDex = referrer->pDvmDex;
962 LOGVV("--- resolving interface method %d (referrer=%s)\n",
963 methodIdx, referrer->descriptor);
965 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
966 if (resMethod == NULL) {
967 const DexMethodId* pMethodId;
968 ClassObject* resClass;
970 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
972 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
973 if (resClass == NULL) {
974 /* can't find the class that the method is a part of */
975 dvmClearOptException(dvmThreadSelf());
978 if (!dvmIsInterfaceClass(resClass)) {
980 LOGI("Interface method not part of interface class\n");
984 const char* methodName =
985 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
987 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
989 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
990 methodName, methodSig, resClass->descriptor);
991 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
992 if (resMethod == NULL) {
993 /* scan superinterfaces and superclass interfaces */
994 LOGVV("+++ did not resolve immediately\n");
995 for (i = 0; i < resClass->iftableCount; i++) {
996 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
998 if (resMethod != NULL)
1002 if (resMethod == NULL) {
1003 LOGVV("+++ unable to resolve method %s\n", methodName);
1007 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
1008 resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
1011 /* we're expecting this to be abstract */
1012 if (!dvmIsAbstractMethod(resMethod)) {
1013 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1014 LOGW("Found non-abstract interface method %s.%s %s\n",
1015 resMethod->clazz->descriptor, resMethod->name, desc);
1021 * Add it to the resolved table so we're faster on the next lookup.
1023 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
1026 LOGVV("--- found interface method %d (%s.%s)\n",
1027 methodIdx, resMethod->clazz->descriptor, resMethod->name);
1029 /* interface methods are always public; no need to check access */
1035 * See if the method being called can be rewritten as an inline operation.
1036 * Works for invoke-virtual, invoke-direct, and invoke-static.
1038 * Returns "true" if we replace it.
1040 static bool rewriteExecuteInline(Method* method, u2* insns,
1041 MethodType methodType)
1043 const InlineSub* inlineSubs = gDvm.inlineSubs;
1044 ClassObject* clazz = method->clazz;
1045 Method* calledMethod;
1046 u2 methodIdx = insns[1];
1050 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1051 if (calledMethod == NULL) {
1052 LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
1056 while (inlineSubs->method != NULL) {
1059 LOGI("comparing %p vs %p %s.%s %s\n",
1060 inlineSubs->method, calledMethod,
1061 inlineSubs->method->clazz->descriptor,
1062 inlineSubs->method->name,
1063 inlineSubs->method->signature);
1066 if (inlineSubs->method == calledMethod) {
1067 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
1068 (insns[0] & 0xff) == OP_INVOKE_STATIC ||
1069 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
1070 updateOpCode(method, insns, OP_EXECUTE_INLINE);
1071 updateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
1073 //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
1074 // method->clazz->descriptor, method->name,
1075 // calledMethod->clazz->descriptor, calledMethod->name);
1086 * See if the method being called can be rewritten as an inline operation.
1087 * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
1089 * Returns "true" if we replace it.
1091 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
1092 MethodType methodType)
1094 const InlineSub* inlineSubs = gDvm.inlineSubs;
1095 ClassObject* clazz = method->clazz;
1096 Method* calledMethod;
1097 u2 methodIdx = insns[1];
1099 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1100 if (calledMethod == NULL) {
1101 LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
1105 while (inlineSubs->method != NULL) {
1106 if (inlineSubs->method == calledMethod) {
1107 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
1108 (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
1109 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
1110 updateOpCode(method, insns, OP_EXECUTE_INLINE_RANGE);
1111 updateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
1113 //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
1114 // method->clazz->descriptor, method->name,
1115 // calledMethod->clazz->descriptor, calledMethod->name);
1126 * Returns "true" if the return-void instructions in this method should
1127 * be converted to return-void-barrier.
1129 * This is needed to satisfy a Java Memory Model requirement regarding
1130 * the construction of objects with final fields. (This does not apply
1131 * to <clinit> or static fields, since appropriate barriers are guaranteed
1132 * by the class initialization process.)
1134 static bool needsReturnBarrier(Method* method)
1136 if (!gDvm.dexOptForSmp)
1138 if (strcmp(method->name, "<init>") != 0)
1142 * Check to see if the class has any final fields. If not, we don't
1143 * need to generate a barrier instruction.
1145 const ClassObject* clazz = method->clazz;
1146 int idx = clazz->ifieldCount;
1147 while (--idx >= 0) {
1148 if (dvmIsFinalField(&clazz->ifields[idx].field))
1155 * In theory, we only need to do this if the method actually modifies
1156 * a final field. In practice, non-constructor methods are allowed
1157 * to modify final fields by the VM, and there are tools that rely on
1158 * this behavior. (The compiler does not allow it.)
1160 * If we alter the verifier to restrict final-field updates to
1161 * constructors, we can tighten this up as well.
1168 * Convert a return-void to a return-void-barrier.
1170 static void rewriteReturnVoid(Method* method, u2* insns)
1172 assert((insns[0] & 0xff) == OP_RETURN_VOID);
1173 updateOpCode(method, insns, OP_RETURN_VOID_BARRIER);