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 optimizeLoadedClasses(DexFile* pDexFile);
40 static void optimizeClass(ClassObject* clazz);
41 static bool optimizeMethod(Method* method);
42 static void rewriteInstField(Method* method, u2* insns, OpCode newOpc);
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);
52 * Create a table of inline substitutions.
54 * TODO: this is currently just a linear array. We will want to put this
55 * into a hash table as the list size increases.
57 InlineSub* dvmCreateInlineSubsTable(void)
59 const InlineOperation* ops = dvmGetInlineOpsTable();
60 const int count = dvmGetInlineOpsTableLength();
67 * Allocate for optimism: one slot per entry, plus an end-of-list marker.
69 table = malloc(sizeof(InlineSub) * (count+1));
72 for (i = 0; i < count; i++) {
73 clazz = dvmFindClassNoInit(ops[i].classDescriptor, NULL);
75 LOGV("DexOpt: can't inline for class '%s': not found\n",
76 ops[i].classDescriptor);
77 dvmClearOptException(dvmThreadSelf());
80 * Method could be virtual or direct. Try both. Don't use
81 * the "hier" versions.
83 method = dvmFindDirectMethodByDescriptor(clazz, ops[i].methodName,
84 ops[i].methodSignature);
86 method = dvmFindVirtualMethodByDescriptor(clazz, ops[i].methodName,
87 ops[i].methodSignature);
89 LOGW("DexOpt: can't inline %s.%s %s: method not found\n",
90 ops[i].classDescriptor, ops[i].methodName,
91 ops[i].methodSignature);
93 if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
94 LOGW("DexOpt: WARNING: inline op on non-final class/method "
96 clazz->descriptor, method->name);
99 if (dvmIsSynchronizedMethod(method) ||
100 dvmIsDeclaredSynchronizedMethod(method))
102 LOGW("DexOpt: WARNING: inline op on synchronized method "
104 clazz->descriptor, method->name);
108 table[tableIndex].method = method;
109 table[tableIndex].inlineIdx = i;
112 LOGV("DexOpt: will inline %d: %s.%s %s\n", i,
113 ops[i].classDescriptor, ops[i].methodName,
114 ops[i].methodSignature);
119 /* mark end of table */
120 table[tableIndex].method = NULL;
121 LOGV("DexOpt: inline table has %d entries\n", tableIndex);
127 * Release inline sub data structure.
129 void dvmFreeInlineSubsTable(InlineSub* inlineSubs)
136 * Optimize the specified class.
138 void dvmOptimizeClass(ClassObject* clazz)
142 for (i = 0; i < clazz->directMethodCount; i++) {
143 if (!optimizeMethod(&clazz->directMethods[i] ))
146 for (i = 0; i < clazz->virtualMethodCount; i++) {
147 if (!optimizeMethod(&clazz->virtualMethods[i]))
154 // TODO: show when in "verbose" mode
155 LOGV("DexOpt: ceasing optimization attempts on %s\n", clazz->descriptor);
159 * Optimize instructions in a method.
161 * Returns "true" if all went well, "false" if we bailed out early when
164 static bool optimizeMethod(Method* method)
170 if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
173 insns = (u2*) method->insns;
174 assert(insns != NULL);
175 insnsSize = dvmGetMethodInsnsSize(method);
177 while (insnsSize > 0) {
180 inst = *insns & 0xff;
183 #ifndef PROFILE_FIELD_ACCESS /* quickened instructions not instrumented */
185 case OP_IGET_BOOLEAN:
189 rewriteInstField(method, insns, OP_IGET_QUICK);
192 rewriteInstField(method, insns, OP_IGET_WIDE_QUICK);
195 rewriteInstField(method, insns, OP_IGET_OBJECT_QUICK);
198 case OP_IPUT_BOOLEAN:
202 rewriteInstField(method, insns, OP_IPUT_QUICK);
205 rewriteInstField(method, insns, OP_IPUT_WIDE_QUICK);
208 rewriteInstField(method, insns, OP_IPUT_OBJECT_QUICK);
212 case OP_INVOKE_VIRTUAL:
213 if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
214 if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK))
218 case OP_INVOKE_VIRTUAL_RANGE:
219 if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
220 if (!rewriteVirtualInvoke(method, insns,
221 OP_INVOKE_VIRTUAL_QUICK_RANGE))
227 case OP_INVOKE_SUPER:
228 if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK))
231 case OP_INVOKE_SUPER_RANGE:
232 if (!rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE))
236 case OP_INVOKE_DIRECT:
237 if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) {
238 if (!rewriteEmptyDirectInvoke(method, insns))
242 case OP_INVOKE_DIRECT_RANGE:
243 rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
246 case OP_INVOKE_STATIC:
247 rewriteExecuteInline(method, insns, METHOD_STATIC);
249 case OP_INVOKE_STATIC_RANGE:
250 rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
254 // ignore this instruction
258 if (*insns == kPackedSwitchSignature) {
259 width = 4 + insns[1] * 2;
260 } else if (*insns == kSparseSwitchSignature) {
261 width = 2 + insns[1] * 4;
262 } else if (*insns == kArrayDataSignature) {
263 u2 elemWidth = insns[1];
264 u4 len = insns[2] | (((u4)insns[3]) << 16);
265 width = 4 + (elemWidth * len + 1) / 2;
267 width = dexGetInstrWidthAbs(gDvm.instrWidth, inst);
275 assert(insnsSize == 0);
281 * If "referrer" and "resClass" don't come from the same DEX file, and
282 * the DEX we're working on is not destined for the bootstrap class path,
283 * tweak the class loader so package-access checks work correctly.
285 * Only do this if we're doing pre-verification or optimization.
287 static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
289 if (!gDvm.optimizing)
291 assert(referrer->classLoader == NULL);
292 assert(resClass->classLoader == NULL);
294 if (!gDvm.optimizingBootstrapClass) {
295 /* class loader for an array class comes from element type */
296 if (dvmIsArrayClass(resClass))
297 resClass = resClass->elementClass;
298 if (referrer->pDvmDex != resClass->pDvmDex)
299 resClass->classLoader = (Object*) 0xdead3333;
304 * Undo the effects of tweakLoader.
306 static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
308 if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
311 if (dvmIsArrayClass(resClass))
312 resClass = resClass->elementClass;
313 resClass->classLoader = NULL;
318 * Alternate version of dvmResolveClass for use with verification and
319 * optimization. Performs access checks on every resolve, and refuses
320 * to acknowledge the existence of classes defined in more than one DEX
323 * Exceptions caused by failures are cleared before returning.
325 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
327 ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
328 VerifyError* pFailure)
330 DvmDex* pDvmDex = referrer->pDvmDex;
331 ClassObject* resClass;
334 * Check the table first. If not there, do the lookup by name.
336 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
337 if (resClass == NULL) {
338 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
339 if (className[0] != '\0' && className[1] == '\0') {
341 resClass = dvmFindPrimitiveClass(className[0]);
343 resClass = dvmFindClassNoInit(className, referrer->classLoader);
345 if (resClass == NULL) {
346 /* not found, exception should be raised */
347 LOGV("DexOpt: class %d (%s) not found\n",
349 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
350 if (pFailure != NULL) {
351 /* dig through the wrappers to find the original failure */
352 Object* excep = dvmGetException(dvmThreadSelf());
354 Object* cause = dvmGetExceptionCause(excep);
359 if (strcmp(excep->clazz->descriptor,
360 "Ljava/lang/IncompatibleClassChangeError;") == 0)
362 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
364 *pFailure = VERIFY_ERROR_NO_CLASS;
367 dvmClearOptException(dvmThreadSelf());
372 * Add it to the resolved table so we're faster on the next lookup.
374 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
377 /* multiple definitions? */
378 if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
379 LOGI("DexOpt: not resolving ambiguous class '%s'\n",
380 resClass->descriptor);
381 if (pFailure != NULL)
382 *pFailure = VERIFY_ERROR_NO_CLASS;
386 /* access allowed? */
387 tweakLoader(referrer, resClass);
388 bool allowed = dvmCheckClassAccess(referrer, resClass);
389 untweakLoader(referrer, resClass);
391 LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
392 referrer->descriptor, resClass->descriptor);
393 if (pFailure != NULL)
394 *pFailure = VERIFY_ERROR_ACCESS_CLASS;
402 * Alternate version of dvmResolveInstField().
404 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
406 InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
407 VerifyError* pFailure)
409 DvmDex* pDvmDex = referrer->pDvmDex;
412 resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
413 if (resField == NULL) {
414 const DexFieldId* pFieldId;
415 ClassObject* resClass;
417 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
420 * Find the field's class.
422 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
423 if (resClass == NULL) {
424 //dvmClearOptException(dvmThreadSelf());
425 assert(!dvmCheckException(dvmThreadSelf()));
426 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
430 resField = (InstField*)dvmFindFieldHier(resClass,
431 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
432 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
433 if (resField == NULL) {
434 LOGD("DexOpt: couldn't find field %s.%s\n",
435 resClass->descriptor,
436 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
437 if (pFailure != NULL)
438 *pFailure = VERIFY_ERROR_NO_FIELD;
441 if (dvmIsStaticField(&resField->field)) {
442 LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
443 resClass->descriptor,
444 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
445 if (pFailure != NULL)
446 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
451 * Add it to the resolved table so we're faster on the next lookup.
453 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
456 /* access allowed? */
457 tweakLoader(referrer, resField->field.clazz);
458 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
459 untweakLoader(referrer, resField->field.clazz);
461 LOGI("DexOpt: access denied from %s to field %s.%s\n",
462 referrer->descriptor, resField->field.clazz->descriptor,
463 resField->field.name);
464 if (pFailure != NULL)
465 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
473 * Alternate version of dvmResolveStaticField().
475 * Does not force initialization of the resolved field's class.
477 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
479 StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
480 VerifyError* pFailure)
482 DvmDex* pDvmDex = referrer->pDvmDex;
483 StaticField* resField;
485 resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
486 if (resField == NULL) {
487 const DexFieldId* pFieldId;
488 ClassObject* resClass;
490 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
493 * Find the field's class.
495 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
496 if (resClass == NULL) {
497 //dvmClearOptException(dvmThreadSelf());
498 assert(!dvmCheckException(dvmThreadSelf()));
499 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
503 resField = (StaticField*)dvmFindFieldHier(resClass,
504 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
505 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
506 if (resField == NULL) {
507 LOGD("DexOpt: couldn't find static field\n");
508 if (pFailure != NULL)
509 *pFailure = VERIFY_ERROR_NO_FIELD;
512 if (!dvmIsStaticField(&resField->field)) {
513 LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
514 resClass->descriptor,
515 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
516 if (pFailure != NULL)
517 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
522 * Add it to the resolved table so we're faster on the next lookup.
524 * We can only do this if we're in "dexopt", because the presence
525 * of a valid value in the resolution table implies that the class
526 * containing the static field has been initialized.
529 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
532 /* access allowed? */
533 tweakLoader(referrer, resField->field.clazz);
534 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
535 untweakLoader(referrer, resField->field.clazz);
537 LOGI("DexOpt: access denied from %s to field %s.%s\n",
538 referrer->descriptor, resField->field.clazz->descriptor,
539 resField->field.name);
540 if (pFailure != NULL)
541 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
550 * Rewrite an iget/iput instruction. These all have the form:
551 * op vA, vB, field@CCCC
553 * Where vA holds the value, vB holds the object reference, and CCCC is
554 * the field reference constant pool offset. We want to replace CCCC
555 * with the byte offset from the start of the object.
557 * "clazz" is the referring class. We need this because we verify
558 * access rights here.
560 static void rewriteInstField(Method* method, u2* insns, OpCode newOpc)
562 ClassObject* clazz = method->clazz;
563 u2 fieldIdx = insns[1];
567 field = dvmOptResolveInstField(clazz, fieldIdx, NULL);
569 LOGI("DexOpt: unable to optimize field ref 0x%04x at 0x%02x in %s.%s\n",
570 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
575 if (field->byteOffset >= 65536) {
576 LOGI("DexOpt: field offset exceeds 64K (%d)\n", field->byteOffset);
580 insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
581 insns[1] = (u2) field->byteOffset;
582 LOGVV("DexOpt: rewrote access to %s.%s --> %d\n",
583 field->field.clazz->descriptor, field->field.name,
588 * Alternate version of dvmResolveMethod().
590 * Doesn't throw exceptions, and checks access on every lookup.
592 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
594 Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
595 MethodType methodType, VerifyError* pFailure)
597 DvmDex* pDvmDex = referrer->pDvmDex;
600 assert(methodType == METHOD_DIRECT ||
601 methodType == METHOD_VIRTUAL ||
602 methodType == METHOD_STATIC);
604 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
605 referrer->descriptor);
607 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
608 if (resMethod == NULL) {
609 const DexMethodId* pMethodId;
610 ClassObject* resClass;
612 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
614 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
615 if (resClass == NULL) {
617 * Can't find the class that the method is a part of, or don't
618 * have permission to access the class.
620 LOGV("DexOpt: can't find called method's class (?.%s)\n",
621 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
622 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
625 if (dvmIsInterfaceClass(resClass)) {
626 /* method is part of an interface; this is wrong method for that */
627 LOGW("DexOpt: method is in an interface\n");
628 if (pFailure != NULL)
629 *pFailure = VERIFY_ERROR_GENERIC;
634 * We need to chase up the class hierarchy to find methods defined
635 * in super-classes. (We only want to check the current class
636 * if we're looking for a constructor.)
639 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
641 if (methodType == METHOD_DIRECT) {
642 resMethod = dvmFindDirectMethod(resClass,
643 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
645 /* METHOD_STATIC or METHOD_VIRTUAL */
646 resMethod = dvmFindMethodHier(resClass,
647 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
650 if (resMethod == NULL) {
651 LOGV("DexOpt: couldn't find method '%s'\n",
652 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
653 if (pFailure != NULL)
654 *pFailure = VERIFY_ERROR_NO_METHOD;
657 if (methodType == METHOD_STATIC) {
658 if (!dvmIsStaticMethod(resMethod)) {
659 LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
660 resClass->descriptor, resMethod->name);
661 if (pFailure != NULL)
662 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
665 } else if (methodType == METHOD_VIRTUAL) {
666 if (dvmIsStaticMethod(resMethod)) {
667 LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
668 resClass->descriptor, resMethod->name);
669 if (pFailure != NULL)
670 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
675 /* see if this is a pure-abstract method */
676 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
677 LOGW("DexOpt: pure-abstract method '%s' in %s\n",
678 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
679 resClass->descriptor);
680 if (pFailure != NULL)
681 *pFailure = VERIFY_ERROR_GENERIC;
686 * Add it to the resolved table so we're faster on the next lookup.
688 * We can only do this for static methods if we're not in "dexopt",
689 * because the presence of a valid value in the resolution table
690 * implies that the class containing the static field has been
693 if (methodType != METHOD_STATIC || gDvm.optimizing)
694 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
697 LOGVV("--- found method %d (%s.%s)\n",
698 methodIdx, resMethod->clazz->descriptor, resMethod->name);
700 /* access allowed? */
701 tweakLoader(referrer, resMethod->clazz);
702 bool allowed = dvmCheckMethodAccess(referrer, resMethod);
703 untweakLoader(referrer, resMethod->clazz);
706 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
707 LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
708 resMethod->clazz->descriptor, resMethod->name, desc,
709 referrer->descriptor);
712 if (pFailure != NULL)
713 *pFailure = VERIFY_ERROR_ACCESS_METHOD;
721 * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
722 * invoke-super/range. These all have the form:
723 * op vAA, meth@BBBB, reg stuff @CCCC
725 * We want to replace the method constant pool index BBBB with the
728 static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
730 ClassObject* clazz = method->clazz;
732 u2 methodIdx = insns[1];
734 baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
735 if (baseMethod == NULL) {
736 LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
738 (int) (insns - method->insns), clazz->descriptor,
743 assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
744 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
745 (insns[0] & 0xff) == OP_INVOKE_SUPER ||
746 (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
749 * Note: Method->methodIndex is a u2 and is range checked during the
752 insns[0] = (insns[0] & 0xff00) | (u2) newOpc;
753 insns[1] = baseMethod->methodIndex;
755 //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
756 // method->clazz->descriptor, method->name,
757 // baseMethod->clazz->descriptor, baseMethod->name);
763 * Rewrite invoke-direct, which has the form:
764 * op vAA, meth@BBBB, reg stuff @CCCC
766 * There isn't a lot we can do to make this faster, but in some situations
767 * we can make it go away entirely.
769 * This must only be used when the invoked method does nothing and has
770 * no return value (the latter being very important for verification).
772 static bool rewriteEmptyDirectInvoke(Method* method, u2* insns)
774 ClassObject* clazz = method->clazz;
775 Method* calledMethod;
776 u2 methodIdx = insns[1];
778 calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
779 if (calledMethod == NULL) {
780 LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
782 (int) (insns - method->insns), clazz->descriptor,
787 /* TODO: verify that java.lang.Object() is actually empty! */
788 if (calledMethod->clazz == gDvm.classJavaLangObject &&
789 dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
792 * Replace with "empty" instruction. DO NOT disturb anything
793 * else about it, as we want it to function the same as
794 * OP_INVOKE_DIRECT when debugging is enabled.
796 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
797 insns[0] = (insns[0] & 0xff00) | (u2) OP_INVOKE_DIRECT_EMPTY;
799 //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
800 // method->clazz->descriptor, method->name,
801 // calledMethod->clazz->descriptor, calledMethod->name);
808 * Resolve an interface method reference.
810 * No method access check here -- interface methods are always public.
812 * Returns NULL if the method was not found. Does not throw an exception.
814 Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
816 DvmDex* pDvmDex = referrer->pDvmDex;
820 LOGVV("--- resolving interface method %d (referrer=%s)\n",
821 methodIdx, referrer->descriptor);
823 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
824 if (resMethod == NULL) {
825 const DexMethodId* pMethodId;
826 ClassObject* resClass;
828 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
830 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
831 if (resClass == NULL) {
832 /* can't find the class that the method is a part of */
833 dvmClearOptException(dvmThreadSelf());
836 if (!dvmIsInterfaceClass(resClass)) {
838 LOGI("Interface method not part of interface class\n");
842 const char* methodName =
843 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
845 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
847 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
848 methodName, methodSig, resClass->descriptor);
849 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
850 if (resMethod == NULL) {
851 /* scan superinterfaces and superclass interfaces */
852 LOGVV("+++ did not resolve immediately\n");
853 for (i = 0; i < resClass->iftableCount; i++) {
854 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
856 if (resMethod != NULL)
860 if (resMethod == NULL) {
861 LOGVV("+++ unable to resolve method %s\n", methodName);
865 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
866 resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
869 /* we're expecting this to be abstract */
870 if (!dvmIsAbstractMethod(resMethod)) {
871 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
872 LOGW("Found non-abstract interface method %s.%s %s\n",
873 resMethod->clazz->descriptor, resMethod->name, desc);
879 * Add it to the resolved table so we're faster on the next lookup.
881 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
884 LOGVV("--- found interface method %d (%s.%s)\n",
885 methodIdx, resMethod->clazz->descriptor, resMethod->name);
887 /* interface methods are always public; no need to check access */
893 * See if the method being called can be rewritten as an inline operation.
894 * Works for invoke-virtual, invoke-direct, and invoke-static.
896 * Returns "true" if we replace it.
898 static bool rewriteExecuteInline(Method* method, u2* insns,
899 MethodType methodType)
901 const InlineSub* inlineSubs = gDvm.inlineSubs;
902 ClassObject* clazz = method->clazz;
903 Method* calledMethod;
904 u2 methodIdx = insns[1];
908 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
909 if (calledMethod == NULL) {
910 LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
914 while (inlineSubs->method != NULL) {
917 LOGI("comparing %p vs %p %s.%s %s\n",
918 inlineSubs->method, calledMethod,
919 inlineSubs->method->clazz->descriptor,
920 inlineSubs->method->name,
921 inlineSubs->method->signature);
924 if (inlineSubs->method == calledMethod) {
925 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
926 (insns[0] & 0xff) == OP_INVOKE_STATIC ||
927 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
928 insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE;
929 insns[1] = (u2) inlineSubs->inlineIdx;
931 //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
932 // method->clazz->descriptor, method->name,
933 // calledMethod->clazz->descriptor, calledMethod->name);
944 * See if the method being called can be rewritten as an inline operation.
945 * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
947 * Returns "true" if we replace it.
949 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
950 MethodType methodType)
952 const InlineSub* inlineSubs = gDvm.inlineSubs;
953 ClassObject* clazz = method->clazz;
954 Method* calledMethod;
955 u2 methodIdx = insns[1];
957 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
958 if (calledMethod == NULL) {
959 LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
963 while (inlineSubs->method != NULL) {
964 if (inlineSubs->method == calledMethod) {
965 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
966 (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
967 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
968 insns[0] = (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE_RANGE;
969 insns[1] = (u2) inlineSubs->inlineIdx;
971 //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
972 // method->clazz->descriptor, method->name,
973 // calledMethod->clazz->descriptor, calledMethod->name);