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);
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 * If "essentialOnly" is true, we only do essential optimizations. For
139 * example, accesses to volatile 64-bit fields must be replaced with
140 * "-wide-volatile" instructions or the program could behave incorrectly.
141 * (Skipping non-essential optimizations makes us a little bit faster, and
142 * more importantly avoids dirtying DEX pages.)
144 void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
148 for (i = 0; i < clazz->directMethodCount; i++) {
149 optimizeMethod(&clazz->directMethods[i], essentialOnly);
151 for (i = 0; i < clazz->virtualMethodCount; i++) {
152 optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
157 * Optimize instructions in a method.
159 * This does a single pass through the code, examining each instruction.
161 * This is not expected to fail if the class was successfully verified.
162 * The only significant failure modes occur when an "essential" update fails,
163 * but we can't generally identify those: if we can't look up a field,
164 * we can't know if the field access was supposed to be handled as volatile.
166 * Instead, we give it our best effort, and hope for the best. For 100%
167 * reliability, only optimize a class after verification succeeds.
169 static void optimizeMethod(Method* method, bool essentialOnly)
175 if (!gDvm.optimizing && !essentialOnly) {
176 /* unexpected; will force copy-on-write of a lot of pages */
177 LOGD("NOTE: doing full bytecode optimization outside dexopt\n");
180 if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
183 insns = (u2*) method->insns;
184 assert(insns != NULL);
185 insnsSize = dvmGetMethodInsnsSize(method);
187 while (insnsSize > 0) {
188 OpCode quickOpc, volatileOpc = OP_NOP;
190 bool notMatched = false;
192 inst = *insns & 0xff;
196 case OP_IGET_BOOLEAN:
200 quickOpc = OP_IGET_QUICK;
201 if (ANDROID_SMP != 0)
202 volatileOpc = OP_IGET_VOLATILE;
203 goto rewrite_inst_field;
205 quickOpc = OP_IGET_WIDE_QUICK;
206 volatileOpc = OP_IGET_WIDE_VOLATILE;
207 goto rewrite_inst_field;
209 quickOpc = OP_IGET_OBJECT_QUICK;
210 if (ANDROID_SMP != 0)
211 volatileOpc = OP_IGET_OBJECT_VOLATILE;
212 goto rewrite_inst_field;
214 case OP_IPUT_BOOLEAN:
218 quickOpc = OP_IPUT_QUICK;
219 if (ANDROID_SMP != 0)
220 volatileOpc = OP_IPUT_VOLATILE;
221 goto rewrite_inst_field;
223 quickOpc = OP_IPUT_WIDE_QUICK;
224 volatileOpc = OP_IPUT_WIDE_VOLATILE;
225 goto rewrite_inst_field;
227 quickOpc = OP_IPUT_OBJECT_QUICK;
228 if (ANDROID_SMP != 0)
229 volatileOpc = OP_IPUT_OBJECT_VOLATILE;
233 if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
234 rewriteInstField(method, insns, quickOpc, volatileOpc);
239 case OP_SGET_BOOLEAN:
243 volatileOpc = OP_SGET_VOLATILE;
244 goto rewrite_static_field;
246 volatileOpc = OP_SGET_OBJECT_VOLATILE;
247 goto rewrite_static_field;
249 case OP_SPUT_BOOLEAN:
253 volatileOpc = OP_SPUT_VOLATILE;
254 goto rewrite_static_field;
256 volatileOpc = OP_SPUT_OBJECT_VOLATILE;
257 goto rewrite_static_field;
260 volatileOpc = OP_SGET_WIDE_VOLATILE;
261 goto rewrite_static_field;
263 volatileOpc = OP_SPUT_WIDE_VOLATILE;
264 rewrite_static_field:
265 rewriteStaticField(method, insns, volatileOpc);
269 /* not one of the "essential" replacements; check for more */
273 if (notMatched && !essentialOnly) {
275 case OP_INVOKE_VIRTUAL:
276 if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
277 rewriteVirtualInvoke(method, insns,
278 OP_INVOKE_VIRTUAL_QUICK);
281 case OP_INVOKE_VIRTUAL_RANGE:
282 if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
283 rewriteVirtualInvoke(method, insns,
284 OP_INVOKE_VIRTUAL_QUICK_RANGE);
287 case OP_INVOKE_SUPER:
288 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
290 case OP_INVOKE_SUPER_RANGE:
291 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
294 case OP_INVOKE_DIRECT:
295 if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) {
296 rewriteEmptyDirectInvoke(method, insns);
299 case OP_INVOKE_DIRECT_RANGE:
300 rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
303 case OP_INVOKE_STATIC:
304 rewriteExecuteInline(method, insns, METHOD_STATIC);
306 case OP_INVOKE_STATIC_RANGE:
307 rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
311 /* nothing to do for this instruction */
316 width = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, insns);
323 assert(insnsSize == 0);
327 * Update a 16-bit code unit in "meth".
329 static inline void updateCode(const Method* meth, u2* ptr, u2 newVal)
331 if (gDvm.optimizing) {
332 /* dexopt time, alter the output directly */
335 /* runtime, toggle the page read/write status */
336 dvmDexChangeDex2(meth->clazz->pDvmDex, ptr, newVal);
341 * If "referrer" and "resClass" don't come from the same DEX file, and
342 * the DEX we're working on is not destined for the bootstrap class path,
343 * tweak the class loader so package-access checks work correctly.
345 * Only do this if we're doing pre-verification or optimization.
347 static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
349 if (!gDvm.optimizing)
351 assert(referrer->classLoader == NULL);
352 assert(resClass->classLoader == NULL);
354 if (!gDvm.optimizingBootstrapClass) {
355 /* class loader for an array class comes from element type */
356 if (dvmIsArrayClass(resClass))
357 resClass = resClass->elementClass;
358 if (referrer->pDvmDex != resClass->pDvmDex)
359 resClass->classLoader = (Object*) 0xdead3333;
364 * Undo the effects of tweakLoader.
366 static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
368 if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
371 if (dvmIsArrayClass(resClass))
372 resClass = resClass->elementClass;
373 resClass->classLoader = NULL;
378 * Alternate version of dvmResolveClass for use with verification and
379 * optimization. Performs access checks on every resolve, and refuses
380 * to acknowledge the existence of classes defined in more than one DEX
383 * Exceptions caused by failures are cleared before returning.
385 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
387 ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
388 VerifyError* pFailure)
390 DvmDex* pDvmDex = referrer->pDvmDex;
391 ClassObject* resClass;
394 * Check the table first. If not there, do the lookup by name.
396 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
397 if (resClass == NULL) {
398 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
399 if (className[0] != '\0' && className[1] == '\0') {
401 resClass = dvmFindPrimitiveClass(className[0]);
403 resClass = dvmFindClassNoInit(className, referrer->classLoader);
405 if (resClass == NULL) {
406 /* not found, exception should be raised */
407 LOGV("DexOpt: class %d (%s) not found\n",
409 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
410 if (pFailure != NULL) {
411 /* dig through the wrappers to find the original failure */
412 Object* excep = dvmGetException(dvmThreadSelf());
414 Object* cause = dvmGetExceptionCause(excep);
419 if (strcmp(excep->clazz->descriptor,
420 "Ljava/lang/IncompatibleClassChangeError;") == 0)
422 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
424 *pFailure = VERIFY_ERROR_NO_CLASS;
427 dvmClearOptException(dvmThreadSelf());
432 * Add it to the resolved table so we're faster on the next lookup.
434 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
437 /* multiple definitions? */
438 if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
439 LOGI("DexOpt: not resolving ambiguous class '%s'\n",
440 resClass->descriptor);
441 if (pFailure != NULL)
442 *pFailure = VERIFY_ERROR_NO_CLASS;
446 /* access allowed? */
447 tweakLoader(referrer, resClass);
448 bool allowed = dvmCheckClassAccess(referrer, resClass);
449 untweakLoader(referrer, resClass);
451 LOGW("DexOpt: resolve class illegal access: %s -> %s\n",
452 referrer->descriptor, resClass->descriptor);
453 if (pFailure != NULL)
454 *pFailure = VERIFY_ERROR_ACCESS_CLASS;
462 * Alternate version of dvmResolveInstField().
464 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
466 InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
467 VerifyError* pFailure)
469 DvmDex* pDvmDex = referrer->pDvmDex;
472 resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
473 if (resField == NULL) {
474 const DexFieldId* pFieldId;
475 ClassObject* resClass;
477 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
480 * Find the field's class.
482 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
483 if (resClass == NULL) {
484 //dvmClearOptException(dvmThreadSelf());
485 assert(!dvmCheckException(dvmThreadSelf()));
486 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
490 resField = (InstField*)dvmFindFieldHier(resClass,
491 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
492 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
493 if (resField == NULL) {
494 LOGD("DexOpt: couldn't find field %s.%s\n",
495 resClass->descriptor,
496 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
497 if (pFailure != NULL)
498 *pFailure = VERIFY_ERROR_NO_FIELD;
501 if (dvmIsStaticField(&resField->field)) {
502 LOGD("DexOpt: wanted instance, got static for field %s.%s\n",
503 resClass->descriptor,
504 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
505 if (pFailure != NULL)
506 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
511 * Add it to the resolved table so we're faster on the next lookup.
513 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
516 /* access allowed? */
517 tweakLoader(referrer, resField->field.clazz);
518 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
519 untweakLoader(referrer, resField->field.clazz);
521 LOGI("DexOpt: access denied from %s to field %s.%s\n",
522 referrer->descriptor, resField->field.clazz->descriptor,
523 resField->field.name);
524 if (pFailure != NULL)
525 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
533 * Alternate version of dvmResolveStaticField().
535 * Does not force initialization of the resolved field's class.
537 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
539 StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
540 VerifyError* pFailure)
542 DvmDex* pDvmDex = referrer->pDvmDex;
543 StaticField* resField;
545 resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
546 if (resField == NULL) {
547 const DexFieldId* pFieldId;
548 ClassObject* resClass;
550 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
553 * Find the field's class.
555 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
556 if (resClass == NULL) {
557 //dvmClearOptException(dvmThreadSelf());
558 assert(!dvmCheckException(dvmThreadSelf()));
559 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
563 resField = (StaticField*)dvmFindFieldHier(resClass,
564 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
565 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
566 if (resField == NULL) {
567 LOGD("DexOpt: couldn't find static field\n");
568 if (pFailure != NULL)
569 *pFailure = VERIFY_ERROR_NO_FIELD;
572 if (!dvmIsStaticField(&resField->field)) {
573 LOGD("DexOpt: wanted static, got instance for field %s.%s\n",
574 resClass->descriptor,
575 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
576 if (pFailure != NULL)
577 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
582 * Add it to the resolved table so we're faster on the next lookup.
584 * We can only do this if we're in "dexopt", because the presence
585 * of a valid value in the resolution table implies that the class
586 * containing the static field has been initialized.
589 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
592 /* access allowed? */
593 tweakLoader(referrer, resField->field.clazz);
594 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
595 untweakLoader(referrer, resField->field.clazz);
597 LOGI("DexOpt: access denied from %s to field %s.%s\n",
598 referrer->descriptor, resField->field.clazz->descriptor,
599 resField->field.name);
600 if (pFailure != NULL)
601 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
610 * Rewrite an iget/iput instruction. These all have the form:
611 * op vA, vB, field@CCCC
613 * Where vA holds the value, vB holds the object reference, and CCCC is
614 * the field reference constant pool offset. For a non-volatile field,
615 * we want to replace the opcode with "quickOpc" and replace CCCC with
616 * the byte offset from the start of the object. For a volatile field,
617 * we just want to replace the opcode with "volatileOpc".
619 * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
620 * field. If "quickOpc" is OP_NOP, and this is a non-volatile field,
621 * we don't do anything.
623 * "method" is the referring method.
625 static bool rewriteInstField(Method* method, u2* insns, OpCode quickOpc,
628 ClassObject* clazz = method->clazz;
629 u2 fieldIdx = insns[1];
630 InstField* instField;
632 instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
633 if (instField == NULL) {
634 LOGI("DexOpt: unable to optimize instance field ref "
635 "0x%04x at 0x%02x in %s.%s\n",
636 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
641 if (instField->byteOffset >= 65536) {
642 LOGI("DexOpt: field offset exceeds 64K (%d)\n", instField->byteOffset);
646 if (volatileOpc != OP_NOP && dvmIsVolatileField(&instField->field)) {
647 updateCode(method, insns, (insns[0] & 0xff00) | (u2) volatileOpc);
648 LOGV("DexOpt: rewrote ifield access %s.%s --> volatile\n",
649 instField->field.clazz->descriptor, instField->field.name);
650 } else if (quickOpc != OP_NOP) {
651 updateCode(method, insns, (insns[0] & 0xff00) | (u2) quickOpc);
652 updateCode(method, insns+1, (u2) instField->byteOffset);
653 LOGV("DexOpt: rewrote ifield access %s.%s --> %d\n",
654 instField->field.clazz->descriptor, instField->field.name,
655 instField->byteOffset);
657 LOGV("DexOpt: no rewrite of ifield access %s.%s\n",
658 instField->field.clazz->descriptor, instField->field.name);
665 * Rewrite an sget/sput instruction. These all have the form:
668 * Where vAA holds the value, and BBBB is the field reference constant
669 * pool offset. There is no "quick" form of static field accesses, so
670 * this is only useful for volatile fields.
672 * "method" is the referring method.
674 static bool rewriteStaticField(Method* method, u2* insns, OpCode volatileOpc)
676 ClassObject* clazz = method->clazz;
677 u2 fieldIdx = insns[1];
678 StaticField* staticField;
680 assert(volatileOpc != OP_NOP);
682 staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
683 if (staticField == NULL) {
684 LOGI("DexOpt: unable to optimize static field ref "
685 "0x%04x at 0x%02x in %s.%s\n",
686 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
691 if (dvmIsVolatileField(&staticField->field)) {
692 updateCode(method, insns, (insns[0] & 0xff00) | (u2) volatileOpc);
693 LOGV("DexOpt: rewrote sfield access %s.%s --> volatile\n",
694 staticField->field.clazz->descriptor, staticField->field.name);
701 * Alternate version of dvmResolveMethod().
703 * Doesn't throw exceptions, and checks access on every lookup.
705 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
707 Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
708 MethodType methodType, VerifyError* pFailure)
710 DvmDex* pDvmDex = referrer->pDvmDex;
713 assert(methodType == METHOD_DIRECT ||
714 methodType == METHOD_VIRTUAL ||
715 methodType == METHOD_STATIC);
717 LOGVV("--- resolving method %u (referrer=%s)\n", methodIdx,
718 referrer->descriptor);
720 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
721 if (resMethod == NULL) {
722 const DexMethodId* pMethodId;
723 ClassObject* resClass;
725 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
727 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
728 if (resClass == NULL) {
730 * Can't find the class that the method is a part of, or don't
731 * have permission to access the class.
733 LOGV("DexOpt: can't find called method's class (?.%s)\n",
734 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
735 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
738 if (dvmIsInterfaceClass(resClass)) {
739 /* method is part of an interface; this is wrong method for that */
740 LOGW("DexOpt: method is in an interface\n");
741 if (pFailure != NULL)
742 *pFailure = VERIFY_ERROR_GENERIC;
747 * We need to chase up the class hierarchy to find methods defined
748 * in super-classes. (We only want to check the current class
749 * if we're looking for a constructor.)
752 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
754 if (methodType == METHOD_DIRECT) {
755 resMethod = dvmFindDirectMethod(resClass,
756 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
758 /* METHOD_STATIC or METHOD_VIRTUAL */
759 resMethod = dvmFindMethodHier(resClass,
760 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
763 if (resMethod == NULL) {
764 LOGV("DexOpt: couldn't find method '%s'\n",
765 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
766 if (pFailure != NULL)
767 *pFailure = VERIFY_ERROR_NO_METHOD;
770 if (methodType == METHOD_STATIC) {
771 if (!dvmIsStaticMethod(resMethod)) {
772 LOGD("DexOpt: wanted static, got instance for method %s.%s\n",
773 resClass->descriptor, resMethod->name);
774 if (pFailure != NULL)
775 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
778 } else if (methodType == METHOD_VIRTUAL) {
779 if (dvmIsStaticMethod(resMethod)) {
780 LOGD("DexOpt: wanted instance, got static for method %s.%s\n",
781 resClass->descriptor, resMethod->name);
782 if (pFailure != NULL)
783 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
788 /* see if this is a pure-abstract method */
789 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
790 LOGW("DexOpt: pure-abstract method '%s' in %s\n",
791 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
792 resClass->descriptor);
793 if (pFailure != NULL)
794 *pFailure = VERIFY_ERROR_GENERIC;
799 * Add it to the resolved table so we're faster on the next lookup.
801 * We can only do this for static methods if we're not in "dexopt",
802 * because the presence of a valid value in the resolution table
803 * implies that the class containing the static field has been
806 if (methodType != METHOD_STATIC || gDvm.optimizing)
807 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
810 LOGVV("--- found method %d (%s.%s)\n",
811 methodIdx, resMethod->clazz->descriptor, resMethod->name);
813 /* access allowed? */
814 tweakLoader(referrer, resMethod->clazz);
815 bool allowed = dvmCheckMethodAccess(referrer, resMethod);
816 untweakLoader(referrer, resMethod->clazz);
819 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
820 LOGI("DexOpt: illegal method access (call %s.%s %s from %s)\n",
821 resMethod->clazz->descriptor, resMethod->name, desc,
822 referrer->descriptor);
825 if (pFailure != NULL)
826 *pFailure = VERIFY_ERROR_ACCESS_METHOD;
834 * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
835 * invoke-super/range. These all have the form:
836 * op vAA, meth@BBBB, reg stuff @CCCC
838 * We want to replace the method constant pool index BBBB with the
841 static bool rewriteVirtualInvoke(Method* method, u2* insns, OpCode newOpc)
843 ClassObject* clazz = method->clazz;
845 u2 methodIdx = insns[1];
847 baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
848 if (baseMethod == NULL) {
849 LOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s\n",
851 (int) (insns - method->insns), clazz->descriptor,
856 assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
857 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
858 (insns[0] & 0xff) == OP_INVOKE_SUPER ||
859 (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
862 * Note: Method->methodIndex is a u2 and is range checked during the
865 updateCode(method, insns, (insns[0] & 0xff00) | (u2) newOpc);
866 updateCode(method, insns+1, baseMethod->methodIndex);
868 //LOGI("DexOpt: rewrote call to %s.%s --> %s.%s\n",
869 // method->clazz->descriptor, method->name,
870 // baseMethod->clazz->descriptor, baseMethod->name);
876 * Rewrite invoke-direct, which has the form:
877 * op vAA, meth@BBBB, reg stuff @CCCC
879 * There isn't a lot we can do to make this faster, but in some situations
880 * we can make it go away entirely.
882 * This must only be used when the invoked method does nothing and has
883 * no return value (the latter being very important for verification).
885 static bool rewriteEmptyDirectInvoke(Method* method, u2* insns)
887 ClassObject* clazz = method->clazz;
888 Method* calledMethod;
889 u2 methodIdx = insns[1];
891 calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
892 if (calledMethod == NULL) {
893 LOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s\n",
895 (int) (insns - method->insns), clazz->descriptor,
900 /* TODO: verify that java.lang.Object() is actually empty! */
901 if (calledMethod->clazz == gDvm.classJavaLangObject &&
902 dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
905 * Replace with "empty" instruction. DO NOT disturb anything
906 * else about it, as we want it to function the same as
907 * OP_INVOKE_DIRECT when debugging is enabled.
909 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT);
910 updateCode(method, insns,
911 (insns[0] & 0xff00) | (u2) OP_INVOKE_DIRECT_EMPTY);
913 //LOGI("DexOpt: marked-empty call to %s.%s --> %s.%s\n",
914 // method->clazz->descriptor, method->name,
915 // calledMethod->clazz->descriptor, calledMethod->name);
922 * Resolve an interface method reference.
924 * No method access check here -- interface methods are always public.
926 * Returns NULL if the method was not found. Does not throw an exception.
928 Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
930 DvmDex* pDvmDex = referrer->pDvmDex;
934 LOGVV("--- resolving interface method %d (referrer=%s)\n",
935 methodIdx, referrer->descriptor);
937 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
938 if (resMethod == NULL) {
939 const DexMethodId* pMethodId;
940 ClassObject* resClass;
942 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
944 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
945 if (resClass == NULL) {
946 /* can't find the class that the method is a part of */
947 dvmClearOptException(dvmThreadSelf());
950 if (!dvmIsInterfaceClass(resClass)) {
952 LOGI("Interface method not part of interface class\n");
956 const char* methodName =
957 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
959 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
961 LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
962 methodName, methodSig, resClass->descriptor);
963 resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
964 if (resMethod == NULL) {
965 /* scan superinterfaces and superclass interfaces */
966 LOGVV("+++ did not resolve immediately\n");
967 for (i = 0; i < resClass->iftableCount; i++) {
968 resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
970 if (resMethod != NULL)
974 if (resMethod == NULL) {
975 LOGVV("+++ unable to resolve method %s\n", methodName);
979 LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
980 resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
983 /* we're expecting this to be abstract */
984 if (!dvmIsAbstractMethod(resMethod)) {
985 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
986 LOGW("Found non-abstract interface method %s.%s %s\n",
987 resMethod->clazz->descriptor, resMethod->name, desc);
993 * Add it to the resolved table so we're faster on the next lookup.
995 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
998 LOGVV("--- found interface method %d (%s.%s)\n",
999 methodIdx, resMethod->clazz->descriptor, resMethod->name);
1001 /* interface methods are always public; no need to check access */
1007 * See if the method being called can be rewritten as an inline operation.
1008 * Works for invoke-virtual, invoke-direct, and invoke-static.
1010 * Returns "true" if we replace it.
1012 static bool rewriteExecuteInline(Method* method, u2* insns,
1013 MethodType methodType)
1015 const InlineSub* inlineSubs = gDvm.inlineSubs;
1016 ClassObject* clazz = method->clazz;
1017 Method* calledMethod;
1018 u2 methodIdx = insns[1];
1022 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1023 if (calledMethod == NULL) {
1024 LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
1028 while (inlineSubs->method != NULL) {
1031 LOGI("comparing %p vs %p %s.%s %s\n",
1032 inlineSubs->method, calledMethod,
1033 inlineSubs->method->clazz->descriptor,
1034 inlineSubs->method->name,
1035 inlineSubs->method->signature);
1038 if (inlineSubs->method == calledMethod) {
1039 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
1040 (insns[0] & 0xff) == OP_INVOKE_STATIC ||
1041 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
1042 updateCode(method, insns,
1043 (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE);
1044 updateCode(method, insns+1, (u2) inlineSubs->inlineIdx);
1046 //LOGI("DexOpt: execute-inline %s.%s --> %s.%s\n",
1047 // method->clazz->descriptor, method->name,
1048 // calledMethod->clazz->descriptor, calledMethod->name);
1059 * See if the method being called can be rewritten as an inline operation.
1060 * Works for invoke-virtual/range, invoke-direct/range, and invoke-static/range.
1062 * Returns "true" if we replace it.
1064 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
1065 MethodType methodType)
1067 const InlineSub* inlineSubs = gDvm.inlineSubs;
1068 ClassObject* clazz = method->clazz;
1069 Method* calledMethod;
1070 u2 methodIdx = insns[1];
1072 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1073 if (calledMethod == NULL) {
1074 LOGV("+++ DexOpt inline/range: can't find %d\n", methodIdx);
1078 while (inlineSubs->method != NULL) {
1079 if (inlineSubs->method == calledMethod) {
1080 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
1081 (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
1082 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
1083 updateCode(method, insns,
1084 (insns[0] & 0xff00) | (u2) OP_EXECUTE_INLINE_RANGE);
1085 updateCode(method, insns+1, (u2) inlineSubs->inlineIdx);
1087 //LOGI("DexOpt: execute-inline/range %s.%s --> %s.%s\n",
1088 // method->clazz->descriptor, method->name,
1089 // calledMethod->clazz->descriptor, calledMethod->name);