Bring our native stack usage down.

I'd have preferred to have a 512-byte limit, but there are some monsters
in the verifier; 2000-line functions and the like. I'm also not policing
tests (except for one silly one). They can use all the stack they like.

This fixes the IntMath test (the stack overflow test was failing because
we were using more than 4KiB to throw!).

Change-Id: I7e53e2fde2b39fde1910f8ee5b1712e8a66069c7
diff --git a/src/check_jni.cc b/src/check_jni.cc
index fa91100..a1a8a18 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -35,7 +35,7 @@
   Thread* self = Thread::Current();
   const Method* current_method = self->GetCurrentMethod();
 
-  std::stringstream os;
+  std::ostringstream os;
   os << "Aborting because JNI app bug detected (see above for details)";
 
   if (jni_function_name != NULL) {
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 53bcf7e..bd23b2d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -58,7 +58,7 @@
 void ThrowNoSuchMethodError(const char* kind,
     Class* c, const StringPiece& name, const StringPiece& signature) {
   DexCache* dex_cache = c->GetDexCache();
-  std::stringstream msg;
+  std::ostringstream msg;
   msg << "no " << kind << " method " << name << "." << signature
       << " in class " << c->GetDescriptor()->ToModifiedUtf8()
       << " or its superclasses";
@@ -2310,7 +2310,7 @@
 }
 
 struct LinkFieldsComparator {
-  bool operator()(const Field* field1, const Field* field2){
+  bool operator()(const Field* field1, const Field* field2) {
 
     // First come reference fields, then 64-bit, and finally 32-bit
     const Class* type1 = field1->GetTypeDuringLinking();
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index e73ccc9..0eff7ea 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -1689,7 +1689,7 @@
                                   const MIR* mir)
 {
     char buffer[256];
-    char operand0[256], operand1[256];
+    char operand0[32], operand1[32];
     const DecodedInstruction *insn = &mir->dalvikInsn;
     int opcode = insn->opcode;
     int dfAttributes = oatDataFlowAttributes[opcode];
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 015aee9..bee0376 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -697,7 +697,6 @@
     }
     oatArenaReset();
 
-    CompilationUnit cUnit;
     art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
     const art::DexFile& dex_file = class_linker->FindDexFile(
          method->GetDeclaringClass()->GetDexCache());
@@ -710,59 +709,59 @@
 
     oatInit(compiler);
 
-    memset(&cUnit, 0, sizeof(cUnit));
-    cUnit.compiler = &compiler;
-    cUnit.method = method;
-    cUnit.instructionSet = (OatInstructionSetType)insnSet;
-    cUnit.insns = code_item->insns_;
-    cUnit.insnsSize = code_item->insns_size_;
+    UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
+    memset(cUnit.get(), 0, sizeof(*cUnit));
+    cUnit->compiler = &compiler;
+    cUnit->method = method;
+    cUnit->instructionSet = (OatInstructionSetType)insnSet;
+    cUnit->insns = code_item->insns_;
+    cUnit->insnsSize = code_item->insns_size_;
     bool useMatch = compilerMethodMatch.length() != 0;
     bool match = useMatch && (compilerFlipMatch ^
         (PrettyMethod(method).find(compilerMethodMatch) != std::string::npos));
     if (!useMatch || match) {
-        cUnit.disableOpt = compilerOptimizerDisableFlags;
-        cUnit.enableDebug = compilerDebugFlags;
-        cUnit.printMe = compiler.IsVerbose() ||
-            (cUnit.enableDebug & (1 << kDebugVerbose));
+        cUnit->disableOpt = compilerOptimizerDisableFlags;
+        cUnit->enableDebug = compilerDebugFlags;
+        cUnit->printMe = compiler.IsVerbose() || (cUnit->enableDebug & (1 << kDebugVerbose));
     }
 
     /* Assume non-throwing leaf */
-    cUnit.attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
+    cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
 
     /* Initialize the block list */
-    oatInitGrowableList(&cUnit.blockList, 40);
+    oatInitGrowableList(&cUnit->blockList, 40);
 
     /* Initialize the switchTables list */
-    oatInitGrowableList(&cUnit.switchTables, 4);
+    oatInitGrowableList(&cUnit->switchTables, 4);
 
     /* Intialize the fillArrayData list */
-    oatInitGrowableList(&cUnit.fillArrayData, 4);
+    oatInitGrowableList(&cUnit->fillArrayData, 4);
 
     /* Intialize the throwLaunchpads list */
-    oatInitGrowableList(&cUnit.throwLaunchpads, 4);
+    oatInitGrowableList(&cUnit->throwLaunchpads, 4);
 
     /* Intialize the suspendLaunchpads list */
-    oatInitGrowableList(&cUnit.suspendLaunchpads, 4);
+    oatInitGrowableList(&cUnit->suspendLaunchpads, 4);
 
     /* Allocate the bit-vector to track the beginning of basic blocks */
-    ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.insnsSize,
+    ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit->insnsSize,
                                                      true /* expandable */);
-    cUnit.tryBlockAddr = tryBlockAddr;
+    cUnit->tryBlockAddr = tryBlockAddr;
 
     /* Create the default entry and exit blocks and enter them to the list */
     BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
     BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
 
-    cUnit.entryBlock = entryBlock;
-    cUnit.exitBlock = exitBlock;
+    cUnit->entryBlock = entryBlock;
+    cUnit->exitBlock = exitBlock;
 
-    oatInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
-    oatInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
+    oatInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
+    oatInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
 
     /* Current block to record parsed instructions */
     BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
     curBlock->startOffset = 0;
-    oatInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
+    oatInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
     entryBlock->fallThrough = curBlock;
     oatSetBit(curBlock->predecessors, entryBlock->id);
 
@@ -770,10 +769,10 @@
      * Store back the number of blocks since new blocks may be created of
      * accessing cUnit.
      */
-    cUnit.numBlocks = numBlocks;
+    cUnit->numBlocks = numBlocks;
 
     /* Identify code range in try blocks and set up the empty catch blocks */
-    processTryCatchBlocks(&cUnit);
+    processTryCatchBlocks(cUnit.get());
 
     /* Parse all instructions and put them into containing basic blocks */
     while (codePtr < codeEnd) {
@@ -792,7 +791,7 @@
         int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
 
         if (flags & kInstrCanBranch) {
-            processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
+            processCanBranch(cUnit.get(), curBlock, insn, curOffset, width, flags,
                              codePtr, codeEnd);
         } else if (flags & kInstrCanReturn) {
             curBlock->fallThrough = exitBlock;
@@ -807,7 +806,7 @@
                  * (incl. OP_NOP).
                  */
                 if (contentIsInsn(codePtr)) {
-                    findBlock(&cUnit, curOffset + width,
+                    findBlock(cUnit.get(), curOffset + width,
                               /* split */
                               false,
                               /* create */
@@ -815,13 +814,13 @@
                 }
             }
         } else if (flags & kInstrCanThrow) {
-            processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
+            processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
                             tryBlockAddr, codePtr, codeEnd);
         } else if (flags & kInstrCanSwitch) {
-            processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
+            processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
         }
         curOffset += width;
-        BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
+        BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
                                           /* split */
                                           false,
                                           /* create */
@@ -846,84 +845,74 @@
         }
     }
 
-    if (cUnit.printMe) {
-        oatDumpCompilationUnit(&cUnit);
+    if (cUnit->printMe) {
+        oatDumpCompilationUnit(cUnit.get());
     }
 
     /* Adjust this value accordingly once inlining is performed */
-    cUnit.numDalvikRegisters = cUnit.method->NumRegisters();
+    cUnit->numDalvikRegisters = cUnit->method->NumRegisters();
 
 
     /* Verify if all blocks are connected as claimed */
-    oatDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
-                                          kAllNodes,
-                                          false /* isIterative */);
-
-
+    oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes, false /* isIterative */);
 
     /* Perform SSA transformation for the whole method */
-    oatMethodSSATransformation(&cUnit);
+    oatMethodSSATransformation(cUnit.get());
 
     /* Perform null check elimination */
-    oatMethodNullCheckElimination(&cUnit);
+    oatMethodNullCheckElimination(cUnit.get());
 
-    oatInitializeRegAlloc(&cUnit);  // Needs to happen after SSA naming
+    oatInitializeRegAlloc(cUnit.get());  // Needs to happen after SSA naming
 
     /* Allocate Registers using simple local allocation scheme */
-    oatSimpleRegAlloc(&cUnit);
+    oatSimpleRegAlloc(cUnit.get());
 
     /* Convert MIR to LIR, etc. */
-    oatMethodMIR2LIR(&cUnit);
+    oatMethodMIR2LIR(cUnit.get());
 
     // Debugging only
-    if (cUnit.enableDebug & (1 << kDebugDumpCFG)) {
-        oatDumpCFG(&cUnit, "/sdcard/cfg/");
+    if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
+        oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
     }
 
     /* Method is not empty */
-    if (cUnit.firstLIRInsn) {
+    if (cUnit->firstLIRInsn) {
 
         // mark the targets of switch statement case labels
-        oatProcessSwitchTables(&cUnit);
+        oatProcessSwitchTables(cUnit.get());
 
         /* Convert LIR into machine code. */
-        oatAssembleLIR(&cUnit);
+        oatAssembleLIR(cUnit.get());
 
-        if (cUnit.printMe) {
-            oatCodegenDump(&cUnit);
+        if (cUnit->printMe) {
+            oatCodegenDump(cUnit.get());
         }
     }
 
     // Combine vmap tables - core regs, then fp regs - into vmapTable
     std::vector<uint16_t> vmapTable;
-    for (size_t i = 0 ; i < cUnit.coreVmapTable.size(); i++) {
-        vmapTable.push_back(cUnit.coreVmapTable[i]);
+    for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
+        vmapTable.push_back(cUnit->coreVmapTable[i]);
     }
     // Add a marker to take place of lr
-    cUnit.coreVmapTable.push_back(INVALID_VREG);
+    cUnit->coreVmapTable.push_back(INVALID_VREG);
     // Combine vmap tables - core regs, then fp regs
-    for (uint32_t i = 0; i < cUnit.fpVmapTable.size(); i++) {
-        cUnit.coreVmapTable.push_back(cUnit.fpVmapTable[i]);
+    for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
+        cUnit->coreVmapTable.push_back(cUnit->fpVmapTable[i]);
     }
-    DCHECK(cUnit.coreVmapTable.size() == (uint32_t)
-        (__builtin_popcount(cUnit.coreSpillMask) +
-         __builtin_popcount(cUnit.fpSpillMask)));
+    DCHECK(cUnit->coreVmapTable.size() == (uint32_t)
+        (__builtin_popcount(cUnit->coreSpillMask) + __builtin_popcount(cUnit->fpSpillMask)));
     vmapTable.push_back(-1);
-    for (size_t i = 0; i < cUnit.fpVmapTable.size(); i++) {
-        vmapTable.push_back(cUnit.fpVmapTable[i]);
+    for (size_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
+        vmapTable.push_back(cUnit->fpVmapTable[i]);
     }
     CompiledMethod* result = new CompiledMethod(art::kThumb2,
-                                                cUnit.codeBuffer,
-                                                cUnit.frameSize,
-                                                cUnit.frameSize - sizeof(intptr_t),
-                                                cUnit.coreSpillMask,
-                                                cUnit.fpSpillMask,
-                                                cUnit.mappingTable,
-                                                cUnit.coreVmapTable);
+        cUnit->codeBuffer, cUnit->frameSize, cUnit->frameSize - sizeof(intptr_t),
+        cUnit->coreSpillMask, cUnit->fpSpillMask, cUnit->mappingTable, cUnit->coreVmapTable);
 
     if (compiler.IsVerbose()) {
         LOG(INFO) << "Compiled " << PrettyMethod(method)
-                  << " (" << (cUnit.codeBuffer.size() * sizeof(cUnit.codeBuffer[0])) << " bytes)";
+                  << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0])) << " bytes)";
     }
 
     return result;
diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc
index c4d3b6d..2a20efa 100644
--- a/src/compiler/codegen/arm/ArchUtility.cc
+++ b/src/compiler/codegen/arm/ArchUtility.cc
@@ -18,6 +18,8 @@
 #include "ArmLIR.h"
 #include "../Ralloc.h"
 
+#include <string>
+
 static const char* coreRegNames[16] = {
     "r0",
     "r1",
@@ -104,11 +106,10 @@
  * Interpret a format string and build a string no longer than size
  * See format key in Assemble.c.
  */
-STATIC void buildInsnString(const char* fmt, ArmLIR* lir, char* buf,
-                            unsigned char* baseAddr, int size)
+STATIC std::string buildInsnString(const char* fmt, ArmLIR* lir, unsigned char* baseAddr)
 {
+    std::string buf;
     int i;
-    char* bufEnd = &buf[size-1];
     const char* fmtEnd = &fmt[strlen(fmt)];
     char tbuf[256];
     const char* name;
@@ -233,21 +234,14 @@
                    default:
                        strcpy(tbuf,"DecodeError1");
                        break;
-               }
-               if (buf+strlen(tbuf) <= bufEnd) {
-                   strcpy(buf, tbuf);
-                   buf += strlen(tbuf);
-               } else {
-                   break;
-               }
+                }
+                buf += tbuf;
             }
         } else {
-           *buf++ = *fmt++;
+           buf += *fmt++;
         }
-        if (buf == bufEnd)
-            break;
     }
-    *buf = 0;
+    return buf;
 }
 
 void oatDumpResourceMask(LIR* lir, u8 mask, const char* prefix)
@@ -365,19 +359,11 @@
             if (lir->flags.isNop && !dumpNop) {
                 break;
             } else {
-                // TODO: rewrite using string
-                char opOperands[256];
-                char opName[256];
-                buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
-                                baseAddr, 256);
-                buildInsnString(EncodingMap[lir->opcode].fmt, lir, opOperands,
-                                baseAddr, 256);
-                char tBuf[256];
-                snprintf(tBuf, 256, "%p (%04x): %-9s%s%s%s",
-                         baseAddr + offset, offset,
-                         opName, opOperands, lir->flags.isNop ? "(nop)" : "",
-                         lir->flags.squashed ? "(squashed)" : "");
-                LOG(INFO) << tBuf;
+                std::string op_name(buildInsnString(EncodingMap[lir->opcode].name, lir, baseAddr));
+                std::string op_operands(buildInsnString(EncodingMap[lir->opcode].fmt, lir, baseAddr));
+                LOG(INFO) << StringPrintf("%p (%04x): %-9s%s%s%s", baseAddr + offset, offset,
+                    op_name.c_str(), op_operands.c_str(), lir->flags.isNop ? "(nop)" : "",
+                    lir->flags.squashed ? "(squashed)" : "");
             }
             break;
     }
@@ -453,20 +439,14 @@
     }
     for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
         armLIR = (ArmLIR*) lirInsn;
-        char buf[100];
-        snprintf(buf, 100, "%x (%04x): .class (%s)",
-             armLIR->generic.offset, armLIR->generic.offset,
-             ((CallsiteInfo *) armLIR->operands[0])->classDescriptor);
-        LOG(INFO) << buf;
+        LOG(INFO) << StringPrintf("%x (%04x): .class (%s)",
+            armLIR->generic.offset, armLIR->generic.offset,
+            ((CallsiteInfo *) armLIR->operands[0])->classDescriptor);
     }
     for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
         armLIR = (ArmLIR*) lirInsn;
-        char buf[100];
-        snprintf(buf, 100, "%x (%04x): .word (%#x)",
-             armLIR->generic.offset, armLIR->generic.offset,
-             armLIR->operands[0]);
-        LOG(INFO) << buf;
-
+        LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)",
+            armLIR->generic.offset, armLIR->generic.offset, armLIR->operands[0]);
     }
 
     std::string signature = method->GetSignature()->ToModifiedUtf8();
@@ -474,22 +454,16 @@
     std::string descriptor = method->GetDeclaringClass()->GetDescriptor()->
         ToModifiedUtf8();
 
-    char buf[256];
-
     // Dump mapping table
     if (cUnit->mappingTable.size() > 0) {
-        sprintf(buf,"\n    MappingTable %s%s_%s_mappingTable[%d] = {",
-                descriptor.c_str(), name.c_str(), signature.c_str(),
-                cUnit->mappingTable.size());
-        for (unsigned int i = 0; i < strlen(buf); i++)
-            if (buf[i] == ';') buf[i] = '_';
-        LOG(INFO) << buf;
-        strcpy(buf,"       ");
+        std::string line(StringPrintf("\n    MappingTable %s%s_%s_mappingTable[%d] = {",
+            descriptor.c_str(), name.c_str(), signature.c_str(), cUnit->mappingTable.size()));
+        std::replace(line.begin(), line.end(), ';', '_');
+        LOG(INFO) << line;
         for (uint32_t i = 0; i < cUnit->mappingTable.size(); i+=2) {
-            sprintf(buf+strlen(buf)," {0x%08x, 0x%04x},",
+            line = StringPrintf("        {0x%08x, 0x%04x},",
                 cUnit->mappingTable[i], cUnit->mappingTable[i+1]);
-            LOG(INFO) << buf;
-            strcpy(buf,"       ");
+            LOG(INFO) << line;
         }
         LOG(INFO) <<"    };\n\n";
     }
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index d88960f..00be2be 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -2037,10 +2037,9 @@
 {
     /* Print compiled opcode in this VM instance */
     int i, start, streak;
-    char buf[1024];
+    std::string buf;
 
     streak = i = 0;
-    buf[0] = 0;
     while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
         i++;
     }
@@ -2052,9 +2051,9 @@
             streak++;
         } else {
             if (streak == 1) {
-                sprintf(buf+strlen(buf), "%x,", start);
+                StringAppendF(&buf, "%x,", start);
             } else {
-                sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
+                StringAppendF(&buf, "%x-%x,", start, start + streak - 1);
             }
             streak = 0;
             while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) {
@@ -2068,12 +2067,12 @@
     }
     if (streak) {
         if (streak == 1) {
-            sprintf(buf+strlen(buf), "%x", start);
+            StringAppendF(&buf, "%x", start);
         } else {
-            sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
+            StringAppendF(&buf, "%x-%x", start, start + streak - 1);
         }
     }
-    if (strlen(buf)) {
+    if (!buf.empty()) {
         LOG(INFO) << "dalvik.vm.oat.op = " << buf;
     }
 }
diff --git a/src/dalvik_system_VMDebug.cc b/src/dalvik_system_VMDebug.cc
index 1defb18..0540631 100644
--- a/src/dalvik_system_VMDebug.cc
+++ b/src/dalvik_system_VMDebug.cc
@@ -231,7 +231,7 @@
  * for seeing both interpreted and native stack traces.
  */
 void VMDebug_crash(JNIEnv*, jclass) {
-  std::stringstream os;
+  std::ostringstream os;
   os << "Crashing VM on request:\n";
   Thread::Current()->Dump(os);
   LOG(FATAL) << os.str();
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 57ff2e3..f3f2e28 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -194,8 +194,8 @@
     return NULL;
   }
 
-  char resolved[PATH_MAX];
-  char* absolute_path = realpath(filename.c_str(), resolved);
+  UniquePtr<char[]> resolved(new char[PATH_MAX]);
+  char* absolute_path = realpath(filename.c_str(), resolved.get());
   if (absolute_path == NULL) {
       LOG(ERROR) << "Failed to create absolute path for " << filename
                  << " when looking for classes.dex";
diff --git a/src/exception_test.cc b/src/exception_test.cc
index fff638f..29d91bb 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -96,9 +96,7 @@
 TEST_F(ExceptionTest, StackTraceElement) {
   runtime_->Start();
 
-  enum {STACK_SIZE = 1000};
-  uint32_t top_of_stack = 0;
-  uintptr_t fake_stack[STACK_SIZE];
+  std::vector<uintptr_t> fake_stack;
   ASSERT_EQ(kStackAlignment, 16);
   ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t));
 
@@ -108,23 +106,23 @@
   const uintptr_t pc_offset = 3 + 2;
 
   // Create/push fake 16byte stack frame for method g
-  fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_g_);
-  fake_stack[top_of_stack++] = 0;
-  fake_stack[top_of_stack++] = 0;
-  fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_f_->GetCode()) + pc_offset;  // return pc
+  fake_stack.push_back(reinterpret_cast<uintptr_t>(method_g_));
+  fake_stack.push_back(0);
+  fake_stack.push_back(0);
+  fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_->GetCode()) + pc_offset);  // return pc
 
   // Create/push fake 16byte stack frame for method f
-  fake_stack[top_of_stack++] = reinterpret_cast<uintptr_t>(method_f_);
-  fake_stack[top_of_stack++] = 0;
-  fake_stack[top_of_stack++] = 0;
-  fake_stack[top_of_stack++] = 0xEBAD6070;  // return pc
+  fake_stack.push_back(reinterpret_cast<uintptr_t>(method_f_));
+  fake_stack.push_back(0);
+  fake_stack.push_back(0);
+  fake_stack.push_back(0xEBAD6070);  // return pc
 
   // Pull Method* of NULL to terminate the trace
-  fake_stack[top_of_stack++] = NULL;
+  fake_stack.push_back(NULL);
 
   // Set up thread to appear as if we called out of method_g_ at pc 3
   Thread* thread = Thread::Current();
-  thread->SetTopOfStack(fake_stack, reinterpret_cast<uintptr_t>(method_g_->GetCode()) + pc_offset);  // return pc
+  thread->SetTopOfStack(&fake_stack[0], reinterpret_cast<uintptr_t>(method_g_->GetCode()) + pc_offset);  // return pc
 
   JNIEnv* env = thread->GetJniEnv();
   jobject internal = thread->CreateInternalStackTrace(env);
diff --git a/src/heap_test.cc b/src/heap_test.cc
index 2a4cbbf..8e869be 100644
--- a/src/heap_test.cc
+++ b/src/heap_test.cc
@@ -8,6 +8,15 @@
 
 TEST_F(HeapTest, GarbageCollectClassLinkerInit) {
   // garbage is created during ClassLinker::Init
+
+  Class* c = class_linker_->FindSystemClass("[Ljava/lang/Object;");
+  for (size_t i = 0; i < 1024; ++i) {
+    ObjectArray<Object>* array = ObjectArray<Object>::Alloc(c, 2048);
+    for (size_t j = 0; j < 2048; ++j) {
+      array->Set(j, String::AllocFromModifiedUtf8("hello, world!"));
+    }
+  }
+
   Heap::CollectGarbage();
 }
 
diff --git a/src/logging.cc b/src/logging.cc
index 35a84ed..bf6ab91 100644
--- a/src/logging.cc
+++ b/src/logging.cc
@@ -29,10 +29,10 @@
 
 LogMessage::~LogMessage() {
   // Finish constructing the message.
-  if (errno_ != -1) {
-    buffer_ << ": " << strerror(errno_);
+  if (data_->error != -1) {
+    data_->buffer << ": " << strerror(data_->error);
   }
-  std::string msg(buffer_.str());
+  std::string msg(data_->buffer.str());
 
   // Do the actual logging with the lock held.
   {
@@ -52,13 +52,15 @@
   }
 
   // Abort if necessary.
-  if (severity_ == FATAL) {
-    art::Runtime::Abort(file_, line_number_);
+  if (data_->severity == FATAL) {
+    art::Runtime::Abort(data_->file, data_->line_number);
   }
+
+  delete data_;
 }
 
 std::ostream& LogMessage::stream() {
-  return buffer_;
+  return data_->buffer;
 }
 
 }  // namespace art
diff --git a/src/logging.h b/src/logging.h
index a0b290d..2f73599 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -134,6 +134,27 @@
   RHS rhs;
 };
 
+// This indirection greatly reduces the stack impact of having
+// lots of checks/logging in a function.
+struct LogMessageData {
+ public:
+  LogMessageData(int line, LogSeverity severity, int error)
+      : file(NULL),
+        line_number(line),
+        severity(severity),
+        error(error) {
+  }
+
+  std::ostringstream buffer;
+  const char* file;
+  int line_number;
+  LogSeverity severity;
+  int error;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
 class LogMessage {
  public:
   LogMessage(const char* file, int line, LogSeverity severity, int error);
@@ -143,11 +164,7 @@
  private:
   void LogLine(const char*);
 
-  std::stringstream buffer_;
-  const char* file_;
-  int line_number_;
-  LogSeverity severity_;
-  int errno_;
+  LogMessageData* data_;
 
   DISALLOW_COPY_AND_ASSIGN(LogMessage);
 };
diff --git a/src/logging_android.cc b/src/logging_android.cc
index 6d949da..2c34d8a 100644
--- a/src/logging_android.cc
+++ b/src/logging_android.cc
@@ -29,14 +29,14 @@
 };
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity, int error)
-    : file_(file), line_number_(line), severity_(severity), errno_(error) {
+    : data_(new LogMessageData(line, severity, error)) {
   const char* last_slash = strrchr(file, '/');
-  file_ = (last_slash == NULL) ? file : last_slash + 1;
+  data_->file = (last_slash == NULL) ? file : last_slash + 1;
 }
 
 void LogMessage::LogLine(const char* line) {
-  int priority = kLogSeverityToAndroidLogPriority[severity_];
-  LOG_PRI(priority, LOG_TAG, "%s:%d] %s", file_, line_number_, line);
+  int priority = kLogSeverityToAndroidLogPriority[data_->severity];
+  LOG_PRI(priority, LOG_TAG, "%s:%d] %s", data_->file, data_->line_number, line);
 }
 
 }  // namespace art
diff --git a/src/logging_linux.cc b/src/logging_linux.cc
index 42bc50b..2c1d699 100644
--- a/src/logging_linux.cc
+++ b/src/logging_linux.cc
@@ -28,15 +28,15 @@
 namespace art {
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity, int error)
-    : line_number_(line), severity_(severity), errno_(error) {
+    : data_(new LogMessageData(line, severity, error)) {
   const char* last_slash = strrchr(file, '/');
-  file_ = (last_slash == NULL) ? file : last_slash + 1;
+  data_->file = (last_slash == NULL) ? file : last_slash + 1;
 }
 
 void LogMessage::LogLine(const char* line) {
-  std::cerr << "VDIWEF"[severity_] << ' '
+  std::cerr << "VDIWEF"[data_->severity] << ' '
             << StringPrintf("%5d %5d", getpid(), ::art::GetTid()) << ' '
-            << file_ << ':' << line_number_ << "] " << line << std::endl;
+            << data_->file << ':' << data_->line_number << "] " << line << std::endl;
 }
 
 }  // namespace art
diff --git a/src/oatdump.cc b/src/oatdump.cc
index a5c8c7b..db17d30 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -322,7 +322,7 @@
     if (obj->IsClass()) {
       Class* klass = obj->AsClass();
       StringAppendF(&summary, "CLASS %s", klass->GetDescriptor()->ToModifiedUtf8().c_str());
-      std::stringstream ss;
+      std::ostringstream ss;
       ss << " (" << klass->GetStatus() << ")";
       summary += ss.str();
     } else if (obj->IsMethod()) {
diff --git a/src/object_bitmap.cc b/src/object_bitmap.cc
index 483feac..1a3d600 100644
--- a/src/object_bitmap.cc
+++ b/src/object_bitmap.cc
@@ -152,8 +152,9 @@
     // TODO: this should never happen
     return;
   }
-  void* pointer_buf[4 * kBitsPerWord];
-  void** pb = pointer_buf;
+  // TODO: rewrite the callbacks to accept a std::vector<void*> rather than a void**?
+  std::vector<void*> pointer_buf(4 * kBitsPerWord);
+  void** pb = &pointer_buf[0];
   size_t start = HB_OFFSET_TO_INDEX(base - live_bitmap.base_);
   size_t end = HB_OFFSET_TO_INDEX(max - live_bitmap.base_);
   word* live = live_bitmap.words_;
@@ -170,14 +171,14 @@
       }
       // Make sure that there are always enough slots available for an
       // entire word of one bits.
-      if (pb >= &pointer_buf[ARRAYSIZE_UNSAFE(pointer_buf) - kBitsPerWord]) {
-        (*callback)(pb - pointer_buf, pointer_buf, arg);
-        pb = pointer_buf;
+      if (pb >= &pointer_buf[pointer_buf.size() - kBitsPerWord]) {
+        (*callback)(pb - &pointer_buf[0], &pointer_buf[0], arg);
+        pb = &pointer_buf[0];
       }
     }
   }
-  if (pb > pointer_buf) {
-    (*callback)(pb - pointer_buf, pointer_buf, arg);
+  if (pb > &pointer_buf[0]) {
+    (*callback)(pb - &pointer_buf[0], &pointer_buf[0], arg);
   }
 }
 
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index ecd48cd..a129ba1 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -64,7 +64,7 @@
 void SignalCatcher::HandleSigQuit() {
   Runtime::Current()->GetThreadList()->SuspendAll();
 
-  std::stringstream os;
+  std::ostringstream os;
   os << "\n"
      << "\n"
      << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";
diff --git a/src/stl_util.h b/src/stl_util.h
index d826510..d503a54 100644
--- a/src/stl_util.h
+++ b/src/stl_util.h
@@ -58,7 +58,7 @@
 
 template <class T>
 std::string ToString(const T& v) {
-  std::stringstream os;
+  std::ostringstream os;
   os << "[";
   for (size_t i = 0; i < v.size(); ++i) {
     os << v[i];
diff --git a/src/thread.h b/src/thread.h
index e0c5d19..8fd0985 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -419,8 +419,12 @@
   // Set the stack end to that to be used during a stack overflow
   void SetStackEndForStackOverflow() {
     // During stack overflow we allow use of the full stack
-    CHECK(stack_end_ != stack_base_) << "Need to increase: kStackOverflowReservedBytes ("
-                                     << kStackOverflowReservedBytes << ")";
+    if (stack_end_ == stack_base_) {
+      DumpStack(std::cerr);
+      LOG(FATAL) << "Need to increase kStackOverflowReservedBytes (currently "
+                 << kStackOverflowReservedBytes << ")";
+    }
+
     stack_end_ = stack_base_;
   }
 
diff --git a/src/thread_x86.cc b/src/thread_x86.cc
index 5aa6d24..378889b 100644
--- a/src/thread_x86.cc
+++ b/src/thread_x86.cc
@@ -14,9 +14,10 @@
 void Thread::InitCpu() {
   // Read LDT
   CHECK_EQ((size_t)LDT_ENTRY_SIZE, sizeof(uint64_t));
-  uint64_t ldt[LDT_ENTRIES];
-  memset(ldt, 0, sizeof(ldt));
-  syscall(SYS_modify_ldt, 0, ldt, sizeof(ldt));
+  std::vector<uint64_t> ldt(LDT_ENTRIES);
+  size_t ldt_size(sizeof(uint64_t) * ldt.size());
+  memset(&ldt[0], 0, ldt_size);
+  syscall(SYS_modify_ldt, 0, &ldt[0], ldt_size);
   // Create empty slot to point at current Thread*
   user_desc ldt_entry;
   memset(&ldt_entry, 0, sizeof(ldt_entry));
diff --git a/src/utils.cc b/src/utils.cc
index 4f4cd8f..ceaf7cd 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -26,16 +26,16 @@
     return false;
   }
 
-  char buf[8 * KB];
+  std::vector<char> buf(8 * KB);
   while (true) {
-    int64_t n = file->Read(buf, sizeof(buf));
+    int64_t n = file->Read(&buf[0], buf.size());
     if (n == -1) {
       return false;
     }
     if (n == 0) {
       return true;
     }
-    result->append(buf, n);
+    result->append(&buf[0], n);
   }
 }
 
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index 41a25de..fb5d23c 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -16,6 +16,8 @@
 
 #include "zip_archive.h"
 
+#include <vector>
+
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -25,6 +27,8 @@
 
 namespace art {
 
+static const size_t kBufSize = 32 * KB;
+
 // Get 2 little-endian bytes.
 static uint32_t Le16ToHost(const byte* src) {
   return ((src[0] <<  0) |
@@ -117,16 +121,14 @@
 }
 
 static bool CopyFdToFile(File& file, int in, size_t count) {
-  const size_t kBufSize = 32768;
-  uint8_t buf[kBufSize];
-
+  std::vector<uint8_t> buf(kBufSize);
   while (count != 0) {
     size_t bytes_to_read = (count > kBufSize) ? kBufSize : count;
-    ssize_t actual = TEMP_FAILURE_RETRY(read(in, buf, bytes_to_read));
+    ssize_t actual = TEMP_FAILURE_RETRY(read(in, &buf[0], bytes_to_read));
     if (actual != static_cast<ssize_t>(bytes_to_read)) {
       return false;
     }
-    if (!file.WriteFully(buf, bytes_to_read)) {
+    if (!file.WriteFully(&buf[0], bytes_to_read)) {
       return false;
     }
     count -= bytes_to_read;
@@ -161,7 +163,6 @@
 };
 
 static bool InflateToFile(File& out, int in, size_t uncompressed_length, size_t compressed_length) {
-  const size_t kBufSize = 32768;
   UniquePtr<uint8_t[]> read_buf(new uint8_t[kBufSize]);
   UniquePtr<uint8_t[]> write_buf(new uint8_t[kBufSize]);
   if (read_buf.get() == NULL || write_buf.get() == NULL) {