Custom codegen for small frameless methods.

Added a general mechanism that will allow pattern matching of
small methods and (generally) frameless code generation.  Prevously,
all frames were at least 16 bytes, not you can have zero-length
frames (and thus some old asserts had to go).

Change-Id: Ic786940a602e25b48cbc317ac601ac84cc307762
diff --git a/src/compiler/codegen/CompilerCodegen.h b/src/compiler/codegen/CompilerCodegen.h
index 1137db3..8f854da 100644
--- a/src/compiler/codegen/CompilerCodegen.h
+++ b/src/compiler/codegen/CompilerCodegen.h
@@ -29,6 +29,9 @@
 /* Lower middle-level IR to low-level IR for the whole method */
 void oatMethodMIR2LIR(CompilationUnit* cUnit);
 
+/* Lower middle-level IR to low-level IR for the simple methods */
+void oatSpecialMIR2LIR(CompilationUnit* cUnit, SpecialCaseHandler specialCase );
+
 /* Assemble LIR into machine code */
 void oatAssembleLIR(CompilationUnit* cUnit);
 AssemblerStatus oatAssembleInstructions(CompilationUnit* cUnit,
diff --git a/src/compiler/codegen/GenCommon.cc b/src/compiler/codegen/GenCommon.cc
index c5b28b3..f63ad4c 100644
--- a/src/compiler/codegen/GenCommon.cc
+++ b/src/compiler/codegen/GenCommon.cc
@@ -931,6 +931,17 @@
     setupResourceMasks(lir);
 }
 
+bool fastInstance(CompilationUnit* cUnit,  uint32_t fieldIdx,
+                  int& fieldOffset, bool& isVolatile, bool isPut)
+{
+    OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
+                             *cUnit->dex_file, *cUnit->dex_cache,
+                             cUnit->code_item, cUnit->method_idx,
+                             cUnit->access_flags);
+    return cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
+                     fieldOffset, isVolatile, isPut);
+}
+
 void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
              RegLocation rlDest, RegLocation rlObj,
                     bool isLongOrDouble, bool isObject)
@@ -939,13 +950,8 @@
     bool isVolatile;
     uint32_t fieldIdx = mir->dalvikInsn.vC;
 
-    OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
-                             *cUnit->dex_file, *cUnit->dex_cache,
-                             cUnit->code_item, cUnit->method_idx,
-                             cUnit->access_flags);
-
-    bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
-                    fieldOffset, isVolatile, false);
+    bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+                                 false);
 
     if (fastPath && !SLOW_FIELD_PATH) {
         RegLocation rlResult;
@@ -1006,13 +1012,8 @@
     bool isVolatile;
     uint32_t fieldIdx = mir->dalvikInsn.vC;
 
-    OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
-                             *cUnit->dex_file, *cUnit->dex_cache,
-                             cUnit->code_item, cUnit->method_idx,
-                             cUnit->access_flags);
-
-    bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
-                    fieldOffset, isVolatile, true);
+    bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+                                 true);
     if (fastPath && !SLOW_FIELD_PATH) {
         RegisterClass regClass = oatRegClassBySize(size);
         DCHECK_GE(fieldOffset, 0);
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 8f4df47..671eb73 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -887,6 +887,50 @@
     return false;
 }
 
+/* Set basic block labels */
+bool labelBlocks(CompilationUnit* cUnit, BasicBlock* bb)
+{
+    LIR* labelList = (LIR*) cUnit->blockLabelList;
+    int blockId = bb->id;
+
+    cUnit->curBlock = bb;
+    labelList[blockId].operands[0] = bb->startOffset;
+
+    /* Insert the block label */
+    labelList[blockId].opcode = kPseudoNormalBlockLabel;
+    return false;
+}
+
+void oatSpecialMIR2LIR(CompilationUnit* cUnit, SpecialCaseHandler specialCase)
+{
+    /* Find the first DalvikByteCode block */
+    int numReachableBlocks = cUnit->numReachableBlocks;
+    const GrowableList *blockList = &cUnit->blockList;
+    BasicBlock*bb = NULL;
+    for (int idx = 0; idx < numReachableBlocks; idx++) {
+        int dfsIndex = cUnit->dfsOrder.elemList[idx];
+        bb = (BasicBlock*)oatGrowableListGetElement(blockList, dfsIndex);
+        if (bb->blockType == kDalvikByteCode) {
+            break;
+        }
+    }
+    if (bb == NULL) {
+        return;
+    }
+    DCHECK_EQ(bb->startOffset, 0);
+    DCHECK(bb->firstMIRInsn != 0);
+
+    /* Get the first instruction */
+    MIR* mir = bb->firstMIRInsn;
+
+    /* Free temp registers and reset redundant store tracking */
+    oatResetRegPool(cUnit);
+    oatResetDefTracking(cUnit);
+    oatClobberAllRegs(cUnit);
+
+    genSpecialCase(cUnit, bb, mir, specialCase);
+}
+
 void oatMethodMIR2LIR(CompilationUnit* cUnit)
 {
     /* Used to hold the labels of each block */
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 74412ab..8e72227 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -26,6 +26,196 @@
 
 namespace art {
 
+/* Return a RegLocation that describes an in-register argument */
+RegLocation argLoc(CompilationUnit* cUnit, RegLocation loc, int sReg)
+{
+    loc.location = kLocPhysReg;
+    int base = SRegToVReg(cUnit, sReg) - cUnit->numRegs;
+    loc.sRegLow = sReg;
+    loc.lowReg = rARG1 + base;
+    loc.home = true;
+    if (loc.wide) {
+        loc.highReg = loc.lowReg + 1;
+        oatLockTemp(cUnit, loc.lowReg);
+        oatLockTemp(cUnit, loc.highReg);
+    } else {
+        oatLockTemp(cUnit, loc.lowReg);
+    }
+    return loc;
+}
+
+/* Find the next MIR, which may be in a following basic block */
+MIR* getNextMir(CompilationUnit* cUnit, BasicBlock** pBb, MIR* mir)
+{
+    BasicBlock* bb = *pBb;
+    MIR* origMir = mir;
+    while (bb != NULL) {
+        if (mir != NULL) {
+            mir = mir->next;
+        }
+        if (mir != NULL) {
+            return mir;
+        } else {
+            bb = bb->fallThrough;
+            *pBb = bb;
+            if (bb) {
+               mir = bb->firstMIRInsn;
+               if (mir != NULL) {
+                   return mir;
+               }
+            }
+        }
+    }
+    return origMir;
+}
+
+/* Used for the "printMe" listing */
+void genPrintLabel(CompilationUnit *cUnit, MIR* mir)
+{
+    LIR* boundaryLIR;
+    /* Mark the beginning of a Dalvik instruction for line tracking */
+    char* instStr = cUnit->printMe ?
+       oatGetDalvikDisassembly(cUnit, mir->dalvikInsn, "") : NULL;
+    boundaryLIR = newLIR1(cUnit, kPseudoDalvikByteCodeBoundary,
+                          (intptr_t) instStr);
+    cUnit->boundaryMap.insert(std::make_pair(mir->offset,
+                             (LIR*)boundaryLIR));
+    /* Don't generate the SSA annotation unless verbose mode is on */
+    if (cUnit->printMe && mir->ssaRep) {
+        char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
+        newLIR1(cUnit, kPseudoSSARep, (int) ssaString);
+    }
+}
+
+MIR* specialIGet(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
+                 OpSize size, bool longOrDouble, bool isObject)
+{
+    int fieldOffset;
+    bool isVolatile;
+    uint32_t fieldIdx = mir->dalvikInsn.vC;
+    bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+                                 false);
+    if (!fastPath) {
+        return NULL;
+    }
+    mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+    genPrintLabel(cUnit, mir);
+    RegLocation rlObj = oatGetSrc(cUnit, mir, 0);
+    rlObj = argLoc(cUnit, rlObj, mir->ssaRep->uses[0]);
+    RegLocation rlDest;
+    if (longOrDouble) {
+        rlDest = oatGetReturnWide(cUnit, false);
+    } else {
+        rlDest = oatGetReturn(cUnit, false);
+    }
+    genIGet(cUnit, mir, size, rlDest, rlObj, longOrDouble, isObject);
+    return getNextMir(cUnit, bb, mir);
+}
+
+MIR* specialIPut(CompilationUnit* cUnit, BasicBlock** bb, MIR* mir,
+                 OpSize size, bool longOrDouble, bool isObject)
+{
+    int fieldOffset;
+    bool isVolatile;
+    uint32_t fieldIdx = mir->dalvikInsn.vC;
+    bool fastPath = fastInstance(cUnit, fieldIdx, fieldOffset, isVolatile,
+                                 false);
+    if (!fastPath) {
+        return NULL;
+    }
+    mir->optimizationFlags |= MIR_IGNORE_NULL_CHECK;
+    genPrintLabel(cUnit, mir);
+    RegLocation rlSrc;
+    RegLocation rlObj;
+    int sSreg = mir->ssaRep->uses[0];
+    int oSreg;
+    if (longOrDouble) {
+        rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
+        rlObj = oatGetSrc(cUnit, mir, 2);
+        oSreg = mir->ssaRep->uses[2];
+    } else {
+        rlSrc = oatGetSrc(cUnit, mir, 0);
+        rlObj = oatGetSrc(cUnit, mir, 1);
+        oSreg = mir->ssaRep->uses[1];
+    }
+    rlSrc = argLoc(cUnit, rlSrc, sSreg);
+    rlObj = argLoc(cUnit, rlObj, oSreg);
+    genIPut(cUnit, mir, size, rlSrc, rlObj, longOrDouble, isObject);
+    return getNextMir(cUnit, bb, mir);
+}
+
+/*
+ * Special-case code genration for simple non-throwing leaf methods.
+ */
+void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+                    SpecialCaseHandler specialCase)
+{
+   cUnit->currentDalvikOffset = mir->offset;
+   MIR* nextMir = NULL;
+   switch(specialCase) {
+       case kNullMethod:
+           DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
+           nextMir = mir;
+           break;
+       case kConstFunction:
+           genPrintLabel(cUnit, mir);
+           loadConstant(cUnit, rRET0, mir->dalvikInsn.vB);
+           nextMir = getNextMir(cUnit, &bb, mir);
+           break;
+       case kIGet:
+           nextMir = specialIGet(cUnit, &bb, mir, kWord, false, false);
+           break;;
+       case kIGetBoolean:
+       case kIGetByte:
+           nextMir = specialIGet(cUnit, &bb, mir, kUnsignedByte, false, false);
+           break;;
+       case kIGetObject:
+           nextMir = specialIGet(cUnit, &bb, mir, kWord, false, true);
+           break;;
+       case kIGetChar:
+           nextMir = specialIGet(cUnit, &bb, mir, kUnsignedHalf, false, false);
+           break;;
+       case kIGetShort:
+           nextMir = specialIGet(cUnit, &bb, mir, kSignedHalf, false, false);
+           break;;
+       case kIGetWide:
+           nextMir = specialIGet(cUnit, &bb, mir, kLong, true, false);
+           break;;
+       case kIPut:
+           nextMir = specialIPut(cUnit, &bb, mir, kWord, false, false);
+           break;;
+       case kIPutBoolean:
+       case kIPutByte:
+           nextMir = specialIPut(cUnit, &bb, mir, kUnsignedByte, false, false);
+           break;;
+       case kIPutObject:
+           nextMir = specialIPut(cUnit, &bb, mir, kWord, false, true);
+           break;;
+       case kIPutChar:
+           nextMir = specialIPut(cUnit, &bb, mir, kUnsignedHalf, false, false);
+           break;;
+       case kIPutShort:
+           nextMir = specialIPut(cUnit, &bb, mir, kSignedHalf, false, false);
+           break;;
+       case kIPutWide:
+           nextMir = specialIPut(cUnit, &bb, mir, kLong, true, false);
+           break;;
+       default:
+           return;
+   }
+   if (nextMir != NULL) {
+        cUnit->currentDalvikOffset = nextMir->offset;
+        genPrintLabel(cUnit, nextMir);
+        newLIR1(cUnit, kThumbBx, rLR);
+        cUnit->coreSpillMask = 0;
+        cUnit->numCoreSpills = 0;
+        cUnit->fpSpillMask = 0;
+        cUnit->numFPSpills = 0;
+        cUnit->frameSize = 0;
+        cUnit->coreVmapTable.clear();
+        cUnit->fpVmapTable.clear();
+    }
+}
 
 /*
  * Generate a Thumb2 IT instruction, which can nullify up to
diff --git a/src/compiler/codegen/mips/Mips32/Gen.cc b/src/compiler/codegen/mips/Mips32/Gen.cc
index 5b89e6a..4530517 100644
--- a/src/compiler/codegen/mips/Mips32/Gen.cc
+++ b/src/compiler/codegen/mips/Mips32/Gen.cc
@@ -24,6 +24,12 @@
 
 namespace art {
 
+void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+                    SpecialCaseHandler specialCase)
+{
+    // TODO
+}
+
 /*
  * The lack of pc-relative loads on Mips presents somewhat of a challenge
  * for our PIC switch table strategy.  To materialize the current location
diff --git a/src/compiler/codegen/x86/X86/Gen.cc b/src/compiler/codegen/x86/X86/Gen.cc
index 6f33b56..c6cd55c 100644
--- a/src/compiler/codegen/x86/X86/Gen.cc
+++ b/src/compiler/codegen/x86/X86/Gen.cc
@@ -24,6 +24,12 @@
 
 namespace art {
 
+void genSpecialCase(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
+                    SpecialCaseHandler specialCase)
+{
+    // TODO
+}
+
 /*
  * Perform register memory operation.
  */