OSDN Git Service

Update dexopt control logic
authorAndy McFadden <fadden@android.com>
Fri, 25 Feb 2011 00:53:55 +0000 (16:53 -0800)
committerAndy McFadden <fadden@android.com>
Fri, 25 Feb 2011 22:39:12 +0000 (14:39 -0800)
This adds a new mode, -Xdexopt:full.  In most ways it behaves like
-Xdexopt:verified (the default), but when an un-optimized class is
loaded we will do a full set of optimizations instead of just the
"essential" set.

For classes that are verified and optimized by dexopt (which is to
say, most of them), this has no effect.  For the others, this trades
off speed for space, substituting quickened instructions but causing
copy-on-write of pages mapped from the DEX file.

This also demotes the substitution of execute-inline opcodes to
"non-essential" status.

Change-Id: I392fb2ff0bf0af83c000937079895d25ce7f0cb1

dexopt/OptMain.c
vm/Init.c
vm/analysis/DexPrepare.c
vm/analysis/DexPrepare.h
vm/analysis/Optimize.c
vm/oo/Class.c

index 765fd7f..7ecd1e0 100644 (file)
@@ -151,6 +151,7 @@ static int extractAndProcessZip(int zipFd, int cacheFd,
             case 'n':   dexOptMode = OPTIMIZE_MODE_NONE;        break;
             case 'v':   dexOptMode = OPTIMIZE_MODE_VERIFIED;    break;
             case 'a':   dexOptMode = OPTIMIZE_MODE_ALL;         break;
+            case 'f':   dexOptMode = OPTIMIZE_MODE_FULL;        break;
             default:                                            break;
             }
         }
index a1e058c..1d6b4c8 100644 (file)
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -106,7 +106,7 @@ static void usage(const char* progName)
     dvmFprintf(stderr, "\n");
     dvmFprintf(stderr, "These are unique to Dalvik:\n");
     dvmFprintf(stderr, "  -Xzygote\n");
-    dvmFprintf(stderr, "  -Xdexopt:{none,verified,all}\n");
+    dvmFprintf(stderr, "  -Xdexopt:{none,verified,all,full}\n");
     dvmFprintf(stderr, "  -Xnoquithandler\n");
     dvmFprintf(stderr,
                 "  -Xjnigreflimit:N  (must be multiple of 100, >= 200)\n");
@@ -887,6 +887,8 @@ static int processOptions(int argc, const char* const argv[],
                 gDvm.dexOptMode = OPTIMIZE_MODE_VERIFIED;
             else if (strcmp(argv[i] + 9, "all") == 0)
                 gDvm.dexOptMode = OPTIMIZE_MODE_ALL;
+            else if (strcmp(argv[i] + 9, "full") == 0)
+                gDvm.dexOptMode = OPTIMIZE_MODE_FULL;
             else {
                 dvmFprintf(stderr, "Unrecognized dexopt option '%s'\n",argv[i]);
                 return -1;
index 8f96bc5..99c8b1d 100644 (file)
@@ -173,19 +173,22 @@ retry:
     } else {
         bool expectVerify, expectOpt;
 
-        if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
+        if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
             expectVerify = false;
-        else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
+        } else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE) {
             expectVerify = !isBootstrap;
-        else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
+        } else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/ {
             expectVerify = true;
+        }
 
-        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
+        if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE) {
             expectOpt = false;
-        else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
+        } else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
+                   gDvm.dexOptMode == OPTIMIZE_MODE_FULL) {
             expectOpt = expectVerify;
-        else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
+        } else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/ {
             expectOpt = true;
+        }
 
         LOGV("checking deps, expecting vfy=%d opt=%d\n",
             expectVerify, expectOpt);
@@ -698,19 +701,22 @@ static bool rewriteDex(u1* addr, int len, u4* pHeaderFlags,
     *pHeaderFlags |= DEX_OPT_FLAG_BIG;
 #endif
 
-    if (gDvm.classVerifyMode == VERIFY_MODE_NONE)
+    if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
         doVerify = false;
-    else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE)
+    } else if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE) {
         doVerify = !gDvm.optimizingBootstrapClass;
-    else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/
+    } else /*if (gDvm.classVerifyMode == VERIFY_MODE_ALL)*/ {
         doVerify = true;
+    }
 
-    if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE)
+    if (gDvm.dexOptMode == OPTIMIZE_MODE_NONE) {
         doOpt = false;
-    else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED)
+    } else if (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
+               gDvm.dexOptMode == OPTIMIZE_MODE_FULL) {
         doOpt = doVerify;
-    else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/
+    } else /*if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)*/ {
         doOpt = true;
+    }
 
     /* TODO: decide if this is actually useful */
     if (doVerify)
@@ -963,7 +969,9 @@ static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
     }
 
     if (doOpt) {
-        if (!verified && gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED) {
+        bool needVerify = (gDvm.dexOptMode == OPTIMIZE_MODE_VERIFIED ||
+                           gDvm.dexOptMode == OPTIMIZE_MODE_FULL);
+        if (!verified && needVerify) {
             LOGV("DexOpt: not optimizing '%s': not verified\n",
                 classDescriptor);
         } else {
index f20aca5..a424b9c 100644 (file)
 /*
  * Global DEX optimizer control.  Determines the circumstances in which we
  * try to rewrite instructions in the DEX file.
+ *
+ * Optimizing is performed ahead-of-time by dexopt and, in some cases, at
+ * load time by the VM.
  */
 typedef enum DexOptimizerMode {
     OPTIMIZE_MODE_UNKNOWN = 0,
-    OPTIMIZE_MODE_NONE,         /* never optimize */
+    OPTIMIZE_MODE_NONE,         /* never optimize (except "essential") */
     OPTIMIZE_MODE_VERIFIED,     /* only optimize verified classes (default) */
-    OPTIMIZE_MODE_ALL           /* optimize all classes */
+    OPTIMIZE_MODE_ALL,          /* optimize verified & unverified (risky) */
+    OPTIMIZE_MODE_FULL          /* fully opt verified classes at load time */
 } DexOptimizerMode;
 
 /* some additional bit flags for dexopt */
index c502303..e6b3f97 100644 (file)
@@ -147,11 +147,6 @@ static void optimizeMethod(Method* method, bool essentialOnly)
     u2* insns;
     u2 inst;
 
-    if (!gDvm.optimizing && !essentialOnly) {
-        /* unexpected; will force copy-on-write of a lot of pages */
-        LOGD("NOTE: doing full bytecode optimization outside dexopt\n");
-    }
-
     if (dvmIsNativeMethod(method) || dvmIsAbstractMethod(method))
         return;
 
@@ -172,7 +167,6 @@ static void optimizeMethod(Method* method, bool essentialOnly)
         /*
          * essential substitutions:
          *  {iget,iput,sget,sput}-wide --> *-wide-volatile
-         *  invoke-{virtual,direct,static}[/range] --> execute-inline
          *  invoke-direct --> invoke-object-init
          *
          * essential-on-SMP substitutions:
@@ -237,33 +231,13 @@ rewrite_static_field:
             rewriteStaticField(method, insns, volatileOpc);
             break;
 
-        case OP_INVOKE_VIRTUAL:
-            if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
-                /* may want to try -quick, below */
-                notMatched = true;
-            }
-            break;
-        case OP_INVOKE_VIRTUAL_RANGE:
-            if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
-                /* may want to try -quick, below */
-                notMatched = true;
-            }
-            break;
         case OP_INVOKE_DIRECT:
-            if (!rewriteExecuteInline(method, insns, METHOD_DIRECT)) {
-                rewriteInvokeObjectInit(method, insns);
+            /* TODO: also handle invoke-direct/range */
+            if (!rewriteInvokeObjectInit(method, insns)) {
+                /* may want to try execute-inline, below */
+                notMatched = true;
             }
             break;
-        case OP_INVOKE_DIRECT_RANGE:
-            rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
-            break;
-        case OP_INVOKE_STATIC:
-            rewriteExecuteInline(method, insns, METHOD_STATIC);
-            break;
-        case OP_INVOKE_STATIC_RANGE:
-            rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
-            break;
-
         default:
             notMatched = true;
             break;
@@ -312,16 +286,22 @@ rewrite_static_field2:
 
         /*
          * non-essential substitutions:
+         *  invoke-{virtual,direct,static}[/range] --> execute-inline
          *  invoke-{virtual,super}[/range] --> invoke-*-quick
          */
         if (notMatched && !essentialOnly) {
             switch (inst) {
             case OP_INVOKE_VIRTUAL:
-                rewriteVirtualInvoke(method, insns, OP_INVOKE_VIRTUAL_QUICK);
+                if (!rewriteExecuteInline(method, insns, METHOD_VIRTUAL)) {
+                    rewriteVirtualInvoke(method, insns,
+                        OP_INVOKE_VIRTUAL_QUICK);
+                }
                 break;
             case OP_INVOKE_VIRTUAL_RANGE:
-                rewriteVirtualInvoke(method, insns,
-                    OP_INVOKE_VIRTUAL_QUICK_RANGE);
+                if (!rewriteExecuteInlineRange(method, insns, METHOD_VIRTUAL)) {
+                    rewriteVirtualInvoke(method, insns,
+                        OP_INVOKE_VIRTUAL_QUICK_RANGE);
+                }
                 break;
             case OP_INVOKE_SUPER:
                 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK);
@@ -329,7 +309,18 @@ rewrite_static_field2:
             case OP_INVOKE_SUPER_RANGE:
                 rewriteVirtualInvoke(method, insns, OP_INVOKE_SUPER_QUICK_RANGE);
                 break;
-
+            case OP_INVOKE_DIRECT:
+                rewriteExecuteInline(method, insns, METHOD_DIRECT);
+                break;
+            case OP_INVOKE_DIRECT_RANGE:
+                rewriteExecuteInlineRange(method, insns, METHOD_DIRECT);
+                break;
+            case OP_INVOKE_STATIC:
+                rewriteExecuteInline(method, insns, METHOD_STATIC);
+                break;
+            case OP_INVOKE_STATIC_RANGE:
+                rewriteExecuteInlineRange(method, insns, METHOD_STATIC);
+                break;
             default:
                 /* nothing to do for this instruction */
                 ;
index 66c9fca..5ce0eeb 100644 (file)
@@ -4324,7 +4324,8 @@ noverify:
     if (!IS_CLASS_FLAG_SET(clazz, CLASS_ISOPTIMIZED) && !gDvm.optimizing) {
         LOGV("+++ late optimize on %s (pv=%d)\n",
             clazz->descriptor, IS_CLASS_FLAG_SET(clazz, CLASS_ISPREVERIFIED));
-        dvmOptimizeClass(clazz, true);
+        bool essentialOnly = (gDvm.dexOptMode != OPTIMIZE_MODE_FULL);
+        dvmOptimizeClass(clazz, essentialOnly);
         SET_CLASS_FLAG(clazz, CLASS_ISOPTIMIZED);
     }