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"
30 * Virtual/direct calls to "method" are replaced with an execute-inline
31 * instruction with index "idx".
40 static void optimizeMethod(Method* method, bool essentialOnly);
41 static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
43 static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc);
44 static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc);
45 static bool rewriteInvokeObjectInit(Method* method, u2* insns);
46 static bool rewriteExecuteInline(Method* method, u2* insns,
47 MethodType methodType);
48 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
49 MethodType methodType);
50 static void rewriteReturnVoid(Method* method, u2* insns);
51 static bool needsReturnBarrier(Method* method);
55 * Create a table of inline substitutions. Sets gDvm.inlineSubs.
57 * TODO: this is currently just a linear array. We will want to put this
58 * into a hash table as the list size increases.
60 bool dvmCreateInlineSubsTable()
62 const InlineOperation* ops = dvmGetInlineOpsTable();
63 const int count = dvmGetInlineOpsTableLength();
67 assert(gDvm.inlineSubs == NULL);
70 * One slot per entry, plus an end-of-list marker.
72 table = (InlineSub*) calloc(count + 1, sizeof(InlineSub));
75 for (i = 0; i < count; i++) {
76 Method* method = dvmFindInlinableMethod(ops[i].classDescriptor,
77 ops[i].methodName, ops[i].methodSignature);
80 * Not expected. We only use this for key methods in core
81 * classes, so we should always be able to find them.
83 ALOGE("Unable to find method for inlining: %s.%s:%s",
84 ops[i].classDescriptor, ops[i].methodName,
85 ops[i].methodSignature);
89 table[tableIndex].method = method;
90 table[tableIndex].inlineIdx = i;
94 /* mark end of table */
95 table[tableIndex].method = NULL;
97 gDvm.inlineSubs = table;
102 * Release inline sub data structure.
104 void dvmFreeInlineSubsTable()
106 free(gDvm.inlineSubs);
107 gDvm.inlineSubs = NULL;
112 * Optimize the specified class.
114 * If "essentialOnly" is true, we only do essential optimizations. For
115 * example, accesses to volatile 64-bit fields must be replaced with
116 * "-wide-volatile" instructions or the program could behave incorrectly.
117 * (Skipping non-essential optimizations makes us a little bit faster, and
118 * more importantly avoids dirtying DEX pages.)
120 void dvmOptimizeClass(ClassObject* clazz, bool essentialOnly)
124 for (i = 0; i < clazz->directMethodCount; i++) {
125 optimizeMethod(&clazz->directMethods[i], essentialOnly);
127 for (i = 0; i < clazz->virtualMethodCount; i++) {
128 optimizeMethod(&clazz->virtualMethods[i], essentialOnly);
133 * Optimize instructions in a method.
135 * This does a single pass through the code, examining each instruction.
137 * This is not expected to fail if the class was successfully verified.
138 * The only significant failure modes on unverified code occur when an
139 * "essential" update fails, but we can't generally identify those: if we
140 * can't look up a field, we can't know if the field access was supposed
141 * to be handled as volatile.
143 * Instead, we give it our best effort, and hope for the best. For 100%
144 * reliability, only optimize a class after verification succeeds.
146 static void optimizeMethod(Method* method, bool essentialOnly)
148 bool needRetBar, forSmp;
152 if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
155 forSmp = gDvm.dexOptForSmp;
156 needRetBar = needsReturnBarrier(method);
158 insns = (u2*) method->insns;
159 assert(insns != NULL);
160 insnsSize = dvmGetMethodInsnsSize(method);
162 while (insnsSize > 0) {
163 Opcode opc, quickOpc, volatileOpc;
167 opc = dexOpcodeFromCodeUnit(*insns);
168 width = dexGetWidthFromInstruction(insns);
169 volatileOpc = OP_NOP;
172 * Each instruction may have:
173 * - "volatile" replacement
174 * - may be essential or essential-on-SMP
175 * - correctness replacement
176 * - may be essential or essential-on-SMP
177 * - performance replacement
178 * - always non-essential
180 * Replacements are considered in the order shown, and the first
181 * match is applied. For example, iget-wide will convert to
182 * iget-wide-volatile rather than iget-wide-quick if the target
187 * essential substitutions:
188 * {iget,iput,sget,sput}-wide --> {op}-wide-volatile
189 * invoke-direct[/range] --> invoke-object-init/range
191 * essential-on-SMP substitutions:
192 * {iget,iput,sget,sput}-* --> {op}-volatile
193 * return-void --> return-void-barrier
195 * non-essential substitutions:
196 * {iget,iput}-* --> {op}-quick
198 * TODO: might be time to merge this with the other two switches
202 case OP_IGET_BOOLEAN:
206 quickOpc = OP_IGET_QUICK;
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;
217 volatileOpc = OP_IGET_OBJECT_VOLATILE;
218 goto rewrite_inst_field;
220 case OP_IPUT_BOOLEAN:
224 quickOpc = OP_IPUT_QUICK;
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;
235 volatileOpc = OP_IPUT_OBJECT_VOLATILE;
239 quickOpc = OP_NOP; /* if essential-only, no "-quick" sub */
240 if (quickOpc != OP_NOP || volatileOpc != OP_NOP)
241 rewriteInstField(method, insns, quickOpc, volatileOpc);
245 case OP_SGET_BOOLEAN:
250 volatileOpc = OP_SGET_VOLATILE;
251 goto rewrite_static_field;
253 volatileOpc = OP_SGET_WIDE_VOLATILE;
254 goto rewrite_static_field;
257 volatileOpc = OP_SGET_OBJECT_VOLATILE;
258 goto rewrite_static_field;
260 case OP_SPUT_BOOLEAN:
265 volatileOpc = OP_SPUT_VOLATILE;
266 goto rewrite_static_field;
268 volatileOpc = OP_SPUT_WIDE_VOLATILE;
269 goto rewrite_static_field;
272 volatileOpc = OP_SPUT_OBJECT_VOLATILE;
274 rewrite_static_field:
275 if (volatileOpc != OP_NOP)
276 rewriteStaticField(method, insns, volatileOpc);
279 case OP_INVOKE_DIRECT:
280 case OP_INVOKE_DIRECT_RANGE:
281 if (!rewriteInvokeObjectInit(method, insns)) {
282 /* may want to try execute-inline, below */
288 rewriteReturnVoid(method, insns);
297 * non-essential substitutions:
298 * invoke-{virtual,direct,static}[/range] --> execute-inline
299 * invoke-{virtual,super}[/range] --> invoke-*-quick
301 if (!matched && !essentialOnly) {
303 case OP_INVOKE_VIRTUAL:
304 if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
305 rewriteVirtualInvoke(method, insns,
306 OP_INVOKE_VIRTUAL_QUICK);
309 case OP_INVOKE_VIRTUAL_RANGE:
310 if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
311 rewriteVirtualInvoke(method, insns,
312 OP_INVOKE_VIRTUAL_QUICK_RANGE);
315 case OP_INVOKE_SUPER:
316 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
318 case OP_INVOKE_SUPER_RANGE:
319 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
321 case OP_INVOKE_DIRECT:
322 rewriteExecuteInline(method, insns, METHOD_DIRECT);
324 case OP_INVOKE_DIRECT_RANGE:
325 rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
327 case OP_INVOKE_STATIC:
328 rewriteExecuteInline(method, insns, METHOD_STATIC);
330 case OP_INVOKE_STATIC_RANGE:
331 rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
334 /* nothing to do for this instruction */
340 assert(width <= insnsSize);
341 assert(width == dexGetWidthFromInstruction(insns));
347 assert(insnsSize == 0);
351 * Update a 16-bit code unit in "meth". The way in which the DEX data was
352 * loaded determines how we go about the write.
354 * This will be operating on post-byte-swap DEX data, so values will
357 void dvmUpdateCodeUnit(const Method* meth, u2* ptr, u2 newVal)
359 DvmDex* pDvmDex = meth->clazz->pDvmDex;
361 if (!pDvmDex->isMappedReadOnly) {
362 /* in-memory DEX (dexopt or byte[]), alter the output directly */
365 /* memory-mapped file, toggle the page read/write status */
366 dvmDexChangeDex2(pDvmDex, ptr, newVal);
371 * Update an instruction's opcode.
373 * If "opcode" is an 8-bit op, we just replace that portion. If it's a
374 * 16-bit op, we convert the opcode from "packed" form (e.g. 0x0108) to
375 * bytecode form (e.g. 0x08ff).
377 static inline void updateOpcode(const Method* meth, u2* ptr, Opcode opcode)
380 /* opcode low byte becomes high byte, low byte becomes 0xff */
381 assert((ptr[0] & 0xff) == 0xff);
382 dvmUpdateCodeUnit(meth, ptr, (u2) (opcode << 8) | 0x00ff);
384 /* 8-bit op, just replace the low byte */
385 assert((ptr[0] & 0xff) != 0xff);
386 dvmUpdateCodeUnit(meth, ptr, (ptr[0] & 0xff00) | (u2) opcode);
391 * If "referrer" and "resClass" don't come from the same DEX file, and
392 * the DEX we're working on is not destined for the bootstrap class path,
393 * tweak the class loader so package-access checks work correctly.
395 * Only do this if we're doing pre-verification or optimization.
397 static void tweakLoader(ClassObject* referrer, ClassObject* resClass)
399 if (!gDvm.optimizing)
401 assert(referrer->classLoader == NULL);
402 assert(resClass->classLoader == NULL);
404 if (!gDvm.optimizingBootstrapClass) {
405 /* class loader for an array class comes from element type */
406 if (dvmIsArrayClass(resClass))
407 resClass = resClass->elementClass;
408 if (referrer->pDvmDex != resClass->pDvmDex)
409 resClass->classLoader = (Object*) 0xdead3333;
414 * Undo the effects of tweakLoader.
416 static void untweakLoader(ClassObject* referrer, ClassObject* resClass)
418 if (!gDvm.optimizing || gDvm.optimizingBootstrapClass)
421 if (dvmIsArrayClass(resClass))
422 resClass = resClass->elementClass;
423 resClass->classLoader = NULL;
428 * Alternate version of dvmResolveClass for use with verification and
429 * optimization. Performs access checks on every resolve, and refuses
430 * to acknowledge the existence of classes defined in more than one DEX
433 * Exceptions caused by failures are cleared before returning.
435 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
437 ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
438 VerifyError* pFailure)
440 DvmDex* pDvmDex = referrer->pDvmDex;
441 ClassObject* resClass;
444 * Check the table first. If not there, do the lookup by name.
446 resClass = dvmDexGetResolvedClass(pDvmDex, classIdx);
447 if (resClass == NULL) {
448 const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, classIdx);
449 if (className[0] != '\0' && className[1] == '\0') {
451 resClass = dvmFindPrimitiveClass(className[0]);
453 resClass = dvmFindClassNoInit(className, referrer->classLoader);
455 if (resClass == NULL) {
456 /* not found, exception should be raised */
457 ALOGV("DexOpt: class %d (%s) not found",
459 dexStringByTypeIdx(pDvmDex->pDexFile, classIdx));
460 if (pFailure != NULL) {
461 /* dig through the wrappers to find the original failure */
462 Object* excep = dvmGetException(dvmThreadSelf());
464 Object* cause = dvmGetExceptionCause(excep);
469 if (strcmp(excep->clazz->descriptor,
470 "Ljava/lang/IncompatibleClassChangeError;") == 0)
472 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
474 *pFailure = VERIFY_ERROR_NO_CLASS;
477 dvmClearOptException(dvmThreadSelf());
482 * Add it to the resolved table so we're faster on the next lookup.
484 dvmDexSetResolvedClass(pDvmDex, classIdx, resClass);
487 /* multiple definitions? */
488 if (IS_CLASS_FLAG_SET(resClass, CLASS_MULTIPLE_DEFS)) {
489 ALOGI("DexOpt: not resolving ambiguous class '%s'",
490 resClass->descriptor);
491 if (pFailure != NULL)
492 *pFailure = VERIFY_ERROR_NO_CLASS;
496 /* access allowed? */
497 tweakLoader(referrer, resClass);
498 bool allowed = dvmCheckClassAccess(referrer, resClass);
499 untweakLoader(referrer, resClass);
501 ALOGW("DexOpt: resolve class illegal access: %s -> %s",
502 referrer->descriptor, resClass->descriptor);
503 if (pFailure != NULL)
504 *pFailure = VERIFY_ERROR_ACCESS_CLASS;
512 * Alternate version of dvmResolveInstField().
514 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
516 InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
517 VerifyError* pFailure)
519 DvmDex* pDvmDex = referrer->pDvmDex;
522 resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
523 if (resField == NULL) {
524 const DexFieldId* pFieldId;
525 ClassObject* resClass;
527 pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);
530 * Find the field's class.
532 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
533 if (resClass == NULL) {
534 //dvmClearOptException(dvmThreadSelf());
535 assert(!dvmCheckException(dvmThreadSelf()));
536 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
540 resField = (InstField*)dvmFindFieldHier(resClass,
541 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
542 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
543 if (resField == NULL) {
544 ALOGD("DexOpt: couldn't find field %s.%s",
545 resClass->descriptor,
546 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
547 if (pFailure != NULL)
548 *pFailure = VERIFY_ERROR_NO_FIELD;
551 if (dvmIsStaticField(resField)) {
552 ALOGD("DexOpt: wanted instance, got static for field %s.%s",
553 resClass->descriptor,
554 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
555 if (pFailure != NULL)
556 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
561 * Add it to the resolved table so we're faster on the next lookup.
563 dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
566 /* access allowed? */
567 tweakLoader(referrer, resField->clazz);
568 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
569 untweakLoader(referrer, resField->clazz);
571 ALOGI("DexOpt: access denied from %s to field %s.%s",
572 referrer->descriptor, resField->clazz->descriptor,
574 if (pFailure != NULL)
575 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
583 * Alternate version of dvmResolveStaticField().
585 * Does not force initialization of the resolved field's class.
587 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
589 StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
590 VerifyError* pFailure)
592 DvmDex* pDvmDex = referrer->pDvmDex;
593 StaticField* resField;
595 resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
596 if (resField == NULL) {
597 const DexFieldId* pFieldId;
598 ClassObject* resClass;
600 pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);
603 * Find the field's class.
605 resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
606 if (resClass == NULL) {
607 //dvmClearOptException(dvmThreadSelf());
608 assert(!dvmCheckException(dvmThreadSelf()));
609 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
613 const char* fieldName =
614 dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
616 resField = (StaticField*)dvmFindFieldHier(resClass, fieldName,
617 dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
618 if (resField == NULL) {
619 ALOGD("DexOpt: couldn't find static field %s.%s",
620 resClass->descriptor, fieldName);
621 if (pFailure != NULL)
622 *pFailure = VERIFY_ERROR_NO_FIELD;
625 if (!dvmIsStaticField(resField)) {
626 ALOGD("DexOpt: wanted static, got instance for field %s.%s",
627 resClass->descriptor, fieldName);
628 if (pFailure != NULL)
629 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
634 * Add it to the resolved table so we're faster on the next lookup.
636 * We can only do this if we're in "dexopt", because the presence
637 * of a valid value in the resolution table implies that the class
638 * containing the static field has been initialized.
641 dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
644 /* access allowed? */
645 tweakLoader(referrer, resField->clazz);
646 bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
647 untweakLoader(referrer, resField->clazz);
649 ALOGI("DexOpt: access denied from %s to field %s.%s",
650 referrer->descriptor, resField->clazz->descriptor,
652 if (pFailure != NULL)
653 *pFailure = VERIFY_ERROR_ACCESS_FIELD;
662 * Rewrite an iget/iput instruction if appropriate. These all have the form:
663 * op vA, vB, field@CCCC
665 * Where vA holds the value, vB holds the object reference, and CCCC is
666 * the field reference constant pool offset. For a non-volatile field,
667 * we want to replace the opcode with "quickOpc" and replace CCCC with
668 * the byte offset from the start of the object. For a volatile field,
669 * we just want to replace the opcode with "volatileOpc".
671 * If "volatileOpc" is OP_NOP we don't check to see if it's a volatile
672 * field. If "quickOpc" is OP_NOP, and this is a non-volatile field,
673 * we don't do anything.
675 * "method" is the referring method.
677 static void rewriteInstField(Method* method, u2* insns, Opcode quickOpc,
680 ClassObject* clazz = method->clazz;
681 u2 fieldIdx = insns[1];
682 InstField* instField;
684 instField = dvmOptResolveInstField(clazz, fieldIdx, NULL);
685 if (instField == NULL) {
686 ALOGI("DexOpt: unable to optimize instance field ref "
687 "0x%04x at 0x%02x in %s.%s",
688 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
693 if (volatileOpc != OP_NOP && dvmIsVolatileField(instField)) {
694 updateOpcode(method, insns, volatileOpc);
695 ALOGV("DexOpt: rewrote ifield access %s.%s --> volatile",
696 instField->clazz->descriptor, instField->name);
697 } else if (quickOpc != OP_NOP && instField->byteOffset < 65536) {
698 updateOpcode(method, insns, quickOpc);
699 dvmUpdateCodeUnit(method, insns+1, (u2) instField->byteOffset);
700 ALOGV("DexOpt: rewrote ifield access %s.%s --> %d",
701 instField->clazz->descriptor, instField->name,
702 instField->byteOffset);
704 ALOGV("DexOpt: no rewrite of ifield access %s.%s",
705 instField->clazz->descriptor, instField->name);
712 * Rewrite a static field access instruction if appropriate. If
713 * the target field is volatile, we replace the opcode with "volatileOpc".
715 * "method" is the referring method.
717 static void rewriteStaticField0(Method* method, u2* insns, Opcode volatileOpc,
720 ClassObject* clazz = method->clazz;
721 StaticField* staticField;
723 assert(volatileOpc != OP_NOP);
725 staticField = dvmOptResolveStaticField(clazz, fieldIdx, NULL);
726 if (staticField == NULL) {
727 ALOGI("DexOpt: unable to optimize static field ref "
728 "0x%04x at 0x%02x in %s.%s",
729 fieldIdx, (int) (insns - method->insns), clazz->descriptor,
734 if (dvmIsVolatileField(staticField)) {
735 updateOpcode(method, insns, volatileOpc);
736 ALOGV("DexOpt: rewrote sfield access %s.%s --> volatile",
737 staticField->clazz->descriptor, staticField->name);
741 static void rewriteStaticField(Method* method, u2* insns, Opcode volatileOpc)
743 u2 fieldIdx = insns[1];
744 rewriteStaticField0(method, insns, volatileOpc, fieldIdx);
748 * Alternate version of dvmResolveMethod().
750 * Doesn't throw exceptions, and checks access on every lookup.
752 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
754 Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
755 MethodType methodType, VerifyError* pFailure)
757 DvmDex* pDvmDex = referrer->pDvmDex;
760 assert(methodType == METHOD_DIRECT ||
761 methodType == METHOD_VIRTUAL ||
762 methodType == METHOD_STATIC);
764 LOGVV("--- resolving method %u (referrer=%s)", methodIdx,
765 referrer->descriptor);
767 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
768 if (resMethod == NULL) {
769 const DexMethodId* pMethodId;
770 ClassObject* resClass;
772 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
774 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
775 if (resClass == NULL) {
777 * Can't find the class that the method is a part of, or don't
778 * have permission to access the class.
780 ALOGV("DexOpt: can't find called method's class (?.%s)",
781 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
782 if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
785 if (dvmIsInterfaceClass(resClass)) {
786 /* method is part of an interface; this is wrong method for that */
787 ALOGW("DexOpt: method is in an interface");
788 if (pFailure != NULL)
789 *pFailure = VERIFY_ERROR_GENERIC;
794 * We need to chase up the class hierarchy to find methods defined
795 * in super-classes. (We only want to check the current class
796 * if we're looking for a constructor.)
799 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
801 if (methodType == METHOD_DIRECT) {
802 resMethod = dvmFindDirectMethod(resClass,
803 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
805 /* METHOD_STATIC or METHOD_VIRTUAL */
806 resMethod = dvmFindMethodHier(resClass,
807 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx), &proto);
810 if (resMethod == NULL) {
811 ALOGV("DexOpt: couldn't find method '%s'",
812 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx));
813 if (pFailure != NULL)
814 *pFailure = VERIFY_ERROR_NO_METHOD;
817 if (methodType == METHOD_STATIC) {
818 if (!dvmIsStaticMethod(resMethod)) {
819 ALOGD("DexOpt: wanted static, got instance for method %s.%s",
820 resClass->descriptor, resMethod->name);
821 if (pFailure != NULL)
822 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
825 } else if (methodType == METHOD_VIRTUAL) {
826 if (dvmIsStaticMethod(resMethod)) {
827 ALOGD("DexOpt: wanted instance, got static for method %s.%s",
828 resClass->descriptor, resMethod->name);
829 if (pFailure != NULL)
830 *pFailure = VERIFY_ERROR_CLASS_CHANGE;
835 /* see if this is a pure-abstract method */
836 if (dvmIsAbstractMethod(resMethod) && !dvmIsAbstractClass(resClass)) {
837 ALOGW("DexOpt: pure-abstract method '%s' in %s",
838 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx),
839 resClass->descriptor);
840 if (pFailure != NULL)
841 *pFailure = VERIFY_ERROR_GENERIC;
846 * Add it to the resolved table so we're faster on the next lookup.
848 * We can only do this for static methods if we're not in "dexopt",
849 * because the presence of a valid value in the resolution table
850 * implies that the class containing the static field has been
853 if (methodType != METHOD_STATIC || gDvm.optimizing)
854 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
857 LOGVV("--- found method %d (%s.%s)",
858 methodIdx, resMethod->clazz->descriptor, resMethod->name);
860 /* access allowed? */
861 tweakLoader(referrer, resMethod->clazz);
862 bool allowed = dvmCheckMethodAccess(referrer, resMethod);
863 untweakLoader(referrer, resMethod->clazz);
866 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
867 ALOGI("DexOpt: illegal method access (call %s.%s %s from %s)",
868 resMethod->clazz->descriptor, resMethod->name, desc,
869 referrer->descriptor);
872 if (pFailure != NULL)
873 *pFailure = VERIFY_ERROR_ACCESS_METHOD;
881 * Rewrite invoke-virtual, invoke-virtual/range, invoke-super, and
882 * invoke-super/range if appropriate. These all have the form:
883 * op vAA, meth@BBBB, reg stuff @CCCC
885 * We want to replace the method constant pool index BBBB with the
888 static void rewriteVirtualInvoke(Method* method, u2* insns, Opcode newOpc)
890 ClassObject* clazz = method->clazz;
892 u2 methodIdx = insns[1];
894 baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL, NULL);
895 if (baseMethod == NULL) {
896 ALOGD("DexOpt: unable to optimize virt call 0x%04x at 0x%02x in %s.%s",
898 (int) (insns - method->insns), clazz->descriptor,
903 assert((insns[0] & 0xff) == OP_INVOKE_VIRTUAL ||
904 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE ||
905 (insns[0] & 0xff) == OP_INVOKE_SUPER ||
906 (insns[0] & 0xff) == OP_INVOKE_SUPER_RANGE);
909 * Note: Method->methodIndex is a u2 and is range checked during the
912 updateOpcode(method, insns, newOpc);
913 dvmUpdateCodeUnit(method, insns+1, baseMethod->methodIndex);
915 //ALOGI("DexOpt: rewrote call to %s.%s --> %s.%s",
916 // method->clazz->descriptor, method->name,
917 // baseMethod->clazz->descriptor, baseMethod->name);
923 * Rewrite invoke-direct[/range] if the target is Object.<init>.
925 * This is useful as an optimization, because otherwise every object
926 * instantiation will cause us to call a method that does nothing.
927 * It also allows us to inexpensively mark objects as finalizable at the
930 * TODO: verifier should ensure Object.<init> contains only return-void,
931 * and issue a warning if not.
933 static bool rewriteInvokeObjectInit(Method* method, u2* insns)
935 ClassObject* clazz = method->clazz;
936 Method* calledMethod;
937 u2 methodIdx = insns[1];
939 calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT, NULL);
940 if (calledMethod == NULL) {
941 ALOGD("DexOpt: unable to opt direct call 0x%04x at 0x%02x in %s.%s",
942 methodIdx, (int) (insns - method->insns),
943 clazz->descriptor, method->name);
947 if (calledMethod->clazz == gDvm.classJavaLangObject &&
948 dvmCompareNameDescriptorAndMethod("<init>", "()V", calledMethod) == 0)
951 * Replace the instruction. If the debugger is attached, the
952 * interpreter will forward execution to the invoke-direct/range
953 * handler. If this was an invoke-direct/range instruction we can
954 * just replace the opcode, but if it was an invoke-direct we
955 * have to set the argument count (high 8 bits of first code unit)
958 u1 origOp = insns[0] & 0xff;
959 if (origOp == OP_INVOKE_DIRECT) {
960 dvmUpdateCodeUnit(method, insns,
961 OP_INVOKE_OBJECT_INIT_RANGE | 0x100);
963 assert(origOp == OP_INVOKE_DIRECT_RANGE);
964 assert((insns[0] >> 8) == 1);
965 updateOpcode(method, insns, OP_INVOKE_OBJECT_INIT_RANGE);
968 LOGVV("DexOpt: replaced Object.<init> in %s.%s",
969 method->clazz->descriptor, method->name);
976 * Resolve an interface method reference.
978 * No method access check here -- interface methods are always public.
980 * Returns NULL if the method was not found. Does not throw an exception.
982 Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
984 DvmDex* pDvmDex = referrer->pDvmDex;
987 LOGVV("--- resolving interface method %d (referrer=%s)",
988 methodIdx, referrer->descriptor);
990 resMethod = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
991 if (resMethod == NULL) {
992 const DexMethodId* pMethodId;
993 ClassObject* resClass;
995 pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
997 resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
998 if (resClass == NULL) {
999 /* can't find the class that the method is a part of */
1000 dvmClearOptException(dvmThreadSelf());
1003 if (!dvmIsInterfaceClass(resClass)) {
1005 ALOGI("Interface method not part of interface class");
1009 const char* methodName =
1010 dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
1012 dexProtoSetFromMethodId(&proto, pDvmDex->pDexFile, pMethodId);
1014 LOGVV("+++ looking for '%s' '%s' in resClass='%s'",
1015 methodName, methodSig, resClass->descriptor);
1016 resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
1017 if (resMethod == NULL) {
1021 /* we're expecting this to be abstract */
1022 if (!dvmIsAbstractMethod(resMethod)) {
1023 char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
1024 ALOGW("Found non-abstract interface method %s.%s %s",
1025 resMethod->clazz->descriptor, resMethod->name, desc);
1031 * Add it to the resolved table so we're faster on the next lookup.
1033 dvmDexSetResolvedMethod(pDvmDex, methodIdx, resMethod);
1036 LOGVV("--- found interface method %d (%s.%s)",
1037 methodIdx, resMethod->clazz->descriptor, resMethod->name);
1039 /* interface methods are always public; no need to check access */
1045 * Replace invoke-virtual, invoke-direct, or invoke-static with an
1046 * execute-inline operation if appropriate.
1048 * Returns "true" if we replace it.
1050 static bool rewriteExecuteInline(Method* method, u2* insns,
1051 MethodType methodType)
1053 const InlineSub* inlineSubs = gDvm.inlineSubs;
1054 ClassObject* clazz = method->clazz;
1055 Method* calledMethod;
1056 u2 methodIdx = insns[1];
1060 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1061 if (calledMethod == NULL) {
1062 ALOGV("+++ DexOpt inline: can't find %d", methodIdx);
1066 while (inlineSubs->method != NULL) {
1069 ALOGI("comparing %p vs %p %s.%s %s",
1070 inlineSubs->method, calledMethod,
1071 inlineSubs->method->clazz->descriptor,
1072 inlineSubs->method->name,
1073 inlineSubs->method->signature);
1076 if (inlineSubs->method == calledMethod) {
1077 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT ||
1078 (insns[0] & 0xff) == OP_INVOKE_STATIC ||
1079 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL);
1080 updateOpcode(method, insns, OP_EXECUTE_INLINE);
1081 dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
1083 //ALOGI("DexOpt: execute-inline %s.%s --> %s.%s",
1084 // method->clazz->descriptor, method->name,
1085 // calledMethod->clazz->descriptor, calledMethod->name);
1096 * Replace invoke-virtual/range, invoke-direct/range, or invoke-static/range
1097 * with an execute-inline operation if appropriate.
1099 * Returns "true" if we replace it.
1101 static bool rewriteExecuteInlineRange(Method* method, u2* insns,
1102 MethodType methodType)
1104 const InlineSub* inlineSubs = gDvm.inlineSubs;
1105 ClassObject* clazz = method->clazz;
1106 Method* calledMethod;
1107 u2 methodIdx = insns[1];
1109 calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
1110 if (calledMethod == NULL) {
1111 ALOGV("+++ DexOpt inline/range: can't find %d", methodIdx);
1115 while (inlineSubs->method != NULL) {
1116 if (inlineSubs->method == calledMethod) {
1117 assert((insns[0] & 0xff) == OP_INVOKE_DIRECT_RANGE ||
1118 (insns[0] & 0xff) == OP_INVOKE_STATIC_RANGE ||
1119 (insns[0] & 0xff) == OP_INVOKE_VIRTUAL_RANGE);
1120 updateOpcode(method, insns, OP_EXECUTE_INLINE_RANGE);
1121 dvmUpdateCodeUnit(method, insns+1, (u2) inlineSubs->inlineIdx);
1123 //ALOGI("DexOpt: execute-inline/range %s.%s --> %s.%s",
1124 // method->clazz->descriptor, method->name,
1125 // calledMethod->clazz->descriptor, calledMethod->name);
1136 * Returns "true" if the return-void instructions in this method should
1137 * be converted to return-void-barrier.
1139 * This is needed to satisfy a Java Memory Model requirement regarding
1140 * the construction of objects with final fields. (This does not apply
1141 * to <clinit> or static fields, since appropriate barriers are guaranteed
1142 * by the class initialization process.)
1144 static bool needsReturnBarrier(Method* method)
1146 if (!gDvm.dexOptForSmp)
1148 if (strcmp(method->name, "<init>") != 0)
1152 * Check to see if the class is finalizable. The loader sets a flag
1153 * if the class or one of its superclasses overrides finalize().
1155 const ClassObject* clazz = method->clazz;
1156 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE))
1160 * Check to see if the class has any final fields. If not, we don't
1161 * need to generate a barrier instruction.
1163 * In theory, we only need to do this if the method actually modifies
1164 * a final field. In practice, non-constructor methods are allowed
1165 * to modify final fields, and there are 3rd-party tools that rely on
1166 * this behavior. (The compiler does not allow it, but the VM does.)
1168 * If we alter the verifier to restrict final-field updates to
1169 * constructors, we can tighten this up as well.
1171 int idx = clazz->ifieldCount;
1172 while (--idx >= 0) {
1173 if (dvmIsFinalField(&clazz->ifields[idx]))
1181 * Convert a return-void to a return-void-barrier.
1183 static void rewriteReturnVoid(Method* method, u2* insns)
1185 assert((insns[0] & 0xff) == OP_RETURN_VOID);
1186 updateOpcode(method, insns, OP_RETURN_VOID_BARRIER);