Interpreter fix - limit suspend checks

Register maps are generated only for a subset of instructions (to
limit memory consumption).  The previous interpreter restructuring
was doing suspend checks at locations that had no register maps.
This CL limits suspend checks to instructions that have register
maps, and also expands that set to include foward as well as
backwards branches.

Change-Id: Ia2b2e1096efe524fdb2a5fd4be171a4216b6a3b4
diff --git a/vm/DalvikVersion.h b/vm/DalvikVersion.h
index a1000ab..673ca56 100644
--- a/vm/DalvikVersion.h
+++ b/vm/DalvikVersion.h
@@ -32,6 +32,6 @@
  * way classes load changes, e.g. field ordering or vtable layout.  Changing
  * this guarantees that the optimized form of the DEX file is regenerated.
  */
-#define DALVIK_VM_BUILD         26
+#define DALVIK_VM_BUILD         27
 
 #endif /*_DALVIK_VERSION*/
diff --git a/vm/analysis/DexVerify.c b/vm/analysis/DexVerify.c
index 16e5738..19513cb 100644
--- a/vm/analysis/DexVerify.c
+++ b/vm/analysis/DexVerify.c
@@ -1451,49 +1451,18 @@
             return false;
         }
 
-        /*
-         * Certain types of instructions can be GC points.  To support precise
-         * GC, all such instructions must export the PC in the interpreter,
-         * or the GC won't be able to identify the current PC for the thread.
-         */
-        const int kGcMask = kInstrCanBranch | kInstrCanSwitch |
-            kInstrCanThrow | kInstrCanReturn;
-
         OpcodeFlags opFlags = dexGetFlagsFromOpcode(decInsn.opcode);
-        if ((opFlags & kGcMask) != 0) {
+        if ((opFlags & VERIFY_GC_INST_MASK) != 0) {
             /*
-             * This instruction is probably a GC point.  Branch instructions
-             * only qualify if they go backward, so for those we need to
-             * check the offset.
+             * This instruction is a GC point.  If space is a concern,
+             * the set of GC points could be reduced by eliminating
+             * foward branches.
              *
              * TODO: we could also scan the targets of a "switch" statement,
              * and if none of them branch backward we could ignore that
              * instruction as well.
              */
-            s4 offset;
-            bool unused;
-            if ((opFlags & kInstrCanBranch) != 0) {
-                /*
-                 * Get the target.  This is slightly redundant, since the
-                 * component was tagged with kVfyBranch, but it's easier
-                 * to just grab it again than cart the state around.
-                 */
-                if (!dvmGetBranchOffset(meth, insnFlags, codeOffset, &offset,
-                        &unused))
-                {
-                    /* should never happen */
-                    LOGE("VFY: opcode %02x flagged as can branch, no target\n",
-                        decInsn.opcode);
-                    dvmAbort();
-                }
-                if (offset <= 0) {
-                    /* backward branch, set GC flag */
-                    dvmInsnSetGcPoint(insnFlags, codeOffset, true);
-                }
-            } else {
-                /* not a branch instruction, always set GC flag */
-                dvmInsnSetGcPoint(insnFlags, codeOffset, true);
-            }
+            dvmInsnSetGcPoint(insnFlags, codeOffset, true);
         }
 
         assert(width > 0);
diff --git a/vm/analysis/DexVerify.h b/vm/analysis/DexVerify.h
index ae1b557..90a724f 100644
--- a/vm/analysis/DexVerify.h
+++ b/vm/analysis/DexVerify.h
@@ -33,6 +33,14 @@
 } DexClassVerifyMode;
 
 /*
+ * Certain types of instructions can be GC points.  To support precise
+ * GC, all such instructions must export the PC in the interpreter,
+ * or the GC won't be able to identify the current PC for the thread.
+ */
+#define VERIFY_GC_INST_MASK (kInstrCanBranch | kInstrCanSwitch |\
+                             kInstrCanThrow | kInstrCanReturn)
+
+/*
  * Verify a single class.
  */
 bool dvmVerifyClass(ClassObject* clazz);
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index 6622874..7ad3096 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -1639,9 +1639,13 @@
 
     /* Suspend pending? */
     if (self->interpBreak.ctl.suspendCount) {
-        // Neeeded for precise GC
-        dvmExportPC(pc, fp);
-        dvmCheckSuspendPending(self);
+        // Are we are a safe point?
+        int flags;
+        flags = dexGetFlagsFromOpcode(dexOpcodeFromCodeUnit(*pc));
+        if (flags & VERIFY_GC_INST_MASK) {
+            dvmExportPC(pc, fp);
+            dvmCheckSuspendPending(self);
+        }
     }
 
     if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) {