Merge "Update frame size after the bitcode is translated into machine code." into ics-mr1-plus-art
diff --git a/src/compiler/codegen/x86/Assemble.cc b/src/compiler/codegen/x86/Assemble.cc
index bad7142..fc9878e 100644
--- a/src/compiler/codegen/x86/Assemble.cc
+++ b/src/compiler/codegen/x86/Assemble.cc
@@ -269,7 +269,7 @@
   EXT_0F_ENCODING_MAP(Divsd,     0xF2, 0x5E),
   EXT_0F_ENCODING_MAP(Divss,     0xF3, 0x5E),
 
-  { kX86PsllqRI, kRegImm, IS_BINARY_OP, { 0, 0, 0x0F, 0x73, 0, 7, 0, 1 }, "PsllqRI", "!0r, !1d" },
+  { kX86PsllqRI, kRegImm, IS_BINARY_OP, { 0, 0, 0x0F, 0x73, 0, 6, 0, 1 }, "PsllqRI", "!0r, !1d" },
 
   EXT_0F_ENCODING_MAP(Movdxr,    0x66, 0x6E),
   EXT_0F_ENCODING_MAP(Movdrx,    0x66, 0x7E),
diff --git a/src/disassembler_x86.cc b/src/disassembler_x86.cc
index 496da2a..ed0cd25 100644
--- a/src/disassembler_x86.cc
+++ b/src/disassembler_x86.cc
@@ -52,10 +52,18 @@
   }
 }
 
+enum RegFile { GPR, MMX, SSE };
+
 static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
-                    bool byte_operand, uint8_t size_override) {
+                    bool byte_operand, uint8_t size_override, RegFile reg_file) {
   size_t reg_num = reg;  // TODO: combine with REX.R on 64bit
-  DumpReg0(os, rex, reg_num, byte_operand, size_override);
+  if (reg_file == GPR) {
+    DumpReg0(os, rex, reg_num, byte_operand, size_override);
+  } else if (reg_file == SSE) {
+    os << "xmm" << reg_num;
+  } else {
+    os << "mm" << reg_num;
+  }
 }
 
 static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
@@ -138,6 +146,8 @@
   bool byte_operand = false;
   bool ax = false;  // implicit use of ax
   bool reg_in_opcode = false;  // low 3-bits of opcode encode register parameter
+  RegFile src_reg_file = GPR;
+  RegFile dst_reg_file = GPR;
   switch (*instr) {
 #define DISASSEMBLER_ENTRY(opname, \
                      rm8_r8, rm32_r32, \
@@ -222,6 +232,7 @@
           opcode << "movups";
         }
         has_modrm = true;
+        src_reg_file = dst_reg_file = SSE;
         load = *instr == 0x10;
         store = !load;
         break;
@@ -231,6 +242,102 @@
       case 0x3A:  // 3 byte extended opcode
         opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
         break;
+      case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
+      case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
+        switch (*instr) {
+          case 0x50: opcode << "movmsk"; break;
+          case 0x51: opcode << "sqrt"; break;
+          case 0x52: opcode << "rsqrt"; break;
+          case 0x53: opcode << "rcp"; break;
+          case 0x54: opcode << "and"; break;
+          case 0x55: opcode << "andn"; break;
+          case 0x56: opcode << "or"; break;
+          case 0x57: opcode << "xor"; break;
+          case 0x58: opcode << "add"; break;
+          case 0x59: opcode << "mul"; break;
+          case 0x5C: opcode << "sub"; break;
+          case 0x5D: opcode << "min"; break;
+          case 0x5E: opcode << "div"; break;
+          case 0x5F: opcode << "max"; break;
+          default: LOG(FATAL) << "Unreachable";
+        }
+        if (prefix[2] == 0x66) {
+          opcode << "pd";
+          prefix[2] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else if (prefix[0] == 0xF2) {
+          opcode << "sd";
+          prefix[0] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else if (prefix[0] == 0xF3) {
+          opcode << "ss";
+          prefix[0] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else {
+          opcode << "ps";
+        }
+        load = true;
+        has_modrm = true;
+        src_reg_file = dst_reg_file = SSE;
+        break;
+      }
+      case 0x5A:
+        if (prefix[2] == 0x66) {
+          opcode << "cvtpd2ps";
+          prefix[2] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else if (prefix[0] == 0xF2) {
+          opcode << "cvtsd2ss";
+          prefix[0] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else if (prefix[0] == 0xF3) {
+          opcode << "cvtss2sd";
+          prefix[0] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else {
+          opcode << "cvtps2pd";
+        }
+        load = true;
+        has_modrm = true;
+        src_reg_file = dst_reg_file = SSE;
+        break;
+      case 0x5B:
+        if (prefix[2] == 0x66) {
+          opcode << "cvtps2dq";
+          prefix[2] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else if (prefix[0] == 0xF2) {
+          opcode << "bad opcode F2 0F 5B";
+        } else if (prefix[0] == 0xF3) {
+          opcode << "cvttps2dq";
+          prefix[0] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else {
+          opcode << "cvtdq2ps";
+        }
+        load = true;
+        has_modrm = true;
+        src_reg_file = dst_reg_file = SSE;
+        break;
+      case 0x6E:
+        if (prefix[2] == 0x66) {
+          dst_reg_file = SSE;
+          opcode << "movq";
+          prefix[2] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else {
+          dst_reg_file = MMX;
+          opcode << "movd";
+        }
+        load = true;
+        has_modrm = true;
+        break;
+      case 0x6F:
+        if (prefix[2] == 0x66) {
+          dst_reg_file = SSE;
+          opcode << "movdqa";
+        } else if (prefix[0] == 0xF3) {
+          dst_reg_file = SSE;
+          opcode << "movdqu";
+          prefix[0] = 0;  // clear prefix now its served its purpose as part of the opcode
+        } else {
+          dst_reg_file = MMX;
+          opcode << "movq";
+        }
+        load = true;
+        has_modrm = true;
+        break;
       case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
       case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
         opcode << "j" << condition_codes[*instr & 0xF];
@@ -312,7 +419,7 @@
   std::ostringstream args;
   if (reg_in_opcode) {
     DCHECK(!has_modrm);
-    DumpReg(args, rex, *instr & 0x7, false, prefix[2]);
+    DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR);
   }
   instr++;
   uint32_t address_bits = 0;
@@ -355,18 +462,18 @@
       }
       address << "]";
     } else {
-      if (mod != 3) {
+      if (mod == 3) {
+        DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file);
+      } else {
         address << "[";
-      }
-      DumpBaseReg(address, rex, rm);
-      if (mod == 1) {
-        address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
-        instr++;
-      } else if (mod == 2) {
-        address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
-        instr += 4;
-      }
-      if (mod != 3) {
+        DumpBaseReg(address, rex, rm);
+        if (mod == 1) {
+          address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
+          instr++;
+        } else if (mod == 2) {
+          address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
+          instr += 4;
+        }
         address << "]";
       }
     }
@@ -376,7 +483,7 @@
     }
     if (load) {
       if (!reg_is_opcode) {
-        DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2]);
+        DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);
         args << ", ";
       }
       DumpSegmentOverride(args, prefix[1]);
@@ -387,12 +494,12 @@
       args << address.str();
       if (!reg_is_opcode) {
         args << ", ";
-        DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2]);
+        DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
       }
     }
   }
   if (ax) {
-    DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2]);
+    DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR);
   }
   if (immediate_bytes > 0) {
     if (has_modrm || reg_in_opcode || ax) {
diff --git a/src/heap.cc b/src/heap.cc
index eb62807..b4bc7ce 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -641,16 +641,10 @@
   if (VLOG_IS_ON(gc) || gc_was_particularly_slow) {
     // TODO: somehow make the specific GC implementation (here MarkSweep) responsible for logging.
     size_t bytes_freed = initial_size - num_bytes_allocated_;
-    if (bytes_freed > KB) {  // ignore freed bytes in output if > 1KB
-      bytes_freed = RoundDown(bytes_freed, KB);
-    }
-    size_t bytes_allocated = RoundUp(num_bytes_allocated_, KB);
     // lose low nanoseconds in duration. TODO: make this part of PrettyDuration
     duration_ns = (duration_ns / 1000) * 1000;
-    size_t total = GetTotalMemory();
-    size_t percentFree = 100 - static_cast<size_t>(100.0f * static_cast<float>(num_bytes_allocated_) / total);
-    LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << percentFree << "% free, "
-              << PrettySize(bytes_allocated) << "/" << PrettySize(total) << ", "
+    LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << GetPercentFree() << "% free, "
+              << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory()) << ", "
               << "paused " << PrettyDuration(duration_ns);
   }
   Dbg::GcDidFinish();
@@ -663,6 +657,17 @@
   lock_->AssertHeld();
 }
 
+void Heap::DumpForSigQuit(std::ostream& os) {
+  os << "Heap: " << GetPercentFree() << "% free, "
+     << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory())
+     << "; " << num_objects_allocated_ << " objects";
+}
+
+size_t Heap::GetPercentFree() {
+  size_t total = GetTotalMemory();
+  return 100 - static_cast<size_t>(100.0f * static_cast<float>(num_bytes_allocated_) / total);
+}
+
 void Heap::SetIdealFootprint(size_t max_allowed_footprint) {
   size_t alloc_space_capacity = alloc_space_->Capacity();
   if (max_allowed_footprint > alloc_space_capacity) {
diff --git a/src/heap.h b/src/heap.h
index 7717871..3f0ffc0 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -17,6 +17,7 @@
 #ifndef ART_SRC_HEAP_H_
 #define ART_SRC_HEAP_H_
 
+#include <iosfwd>
 #include <string>
 #include <vector>
 
@@ -219,6 +220,8 @@
     return alloc_space_;
   }
 
+  void DumpForSigQuit(std::ostream& os);
+
  private:
   // Allocates uninitialized storage.
   Object* AllocateLocked(size_t num_bytes);
@@ -239,6 +242,8 @@
   // collection.
   void GrowForUtilization();
 
+  size_t GetPercentFree();
+
   void AddSpace(Space* space);
 
   void VerifyObjectLocked(const Object *obj);
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 3fe7640..6720e3e 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -163,31 +163,31 @@
   points->pCmpgFloat = CmpgFloat;
   points->pCmplDouble = CmplDouble;
   points->pCmplFloat = CmplFloat;
-  points->pDadd = NULL;
-  points->pDdiv = NULL;
-  points->pDmul = NULL;
-  points->pDsub = NULL;
-  points->pF2d = NULL;
-  points->pFmod = NULL;
-  points->pI2d = NULL;
-  points->pL2d = NULL;
-  points->pD2f = NULL;
-  points->pFadd = NULL;
-  points->pFdiv = NULL;
-  points->pFmodf = NULL;
-  points->pFmul = NULL;
-  points->pFsub = NULL;
-  points->pI2f = NULL;
-  points->pL2f = NULL;
-  points->pD2iz = NULL;
-  points->pF2iz = NULL;
+  //points->pDadd = NULL;
+  //points->pDdiv = NULL;
+  //points->pDmul = NULL;
+  //points->pDsub = NULL;
+  //points->pF2d = NULL;
+  //points->pFmod = NULL;
+  //points->pI2d = NULL;
+  //points->pL2d = NULL;
+  //points->pD2f = NULL;
+  //points->pFadd = NULL;
+  //points->pFdiv = NULL;
+  //points->pFmodf = NULL;
+  //points->pFmul = NULL;
+  //points->pFsub = NULL;
+  //points->pI2f = NULL;
+  //points->pL2f = NULL;
+  //points->pD2iz = NULL;
+  //points->pF2iz = NULL;
   points->pIdiv = art_idiv_from_code;
   points->pIdivmod = art_idivmod_from_code;
   points->pD2l = D2L;
   points->pF2l = F2L;
   points->pLdiv = art_ldiv_from_code;
   points->pLdivmod = art_ldivmod_from_code;
-  points->pLmul = NULL;
+  //points->pLmul = NULL;
   points->pShlLong = art_lshl_from_code;
   points->pShrLong = art_lshr_from_code;
   points->pUshrLong = art_lushr_from_code;
diff --git a/src/runtime.cc b/src/runtime.cc
index 77c887e..25789ab 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -37,6 +37,7 @@
 #include "oat_file.h"
 #include "ScopedLocalRef.h"
 #include "signal_catcher.h"
+#include "signal_set.h"
 #include "space.h"
 #include "thread.h"
 #include "thread_list.h"
@@ -658,6 +659,7 @@
                    options->image_);
 
   BlockSignals();
+  InitPlatformSignalHandlers();
 
   java_vm_ = new JavaVMExt(this, options.get());
 
@@ -745,13 +747,13 @@
 #undef REGISTER
 }
 
-void Runtime::Dump(std::ostream& os) {
-  // TODO: dump other runtime statistics?
+void Runtime::DumpForSigQuit(std::ostream& os) {
   GetClassLinker()->DumpForSigQuit(os);
   GetInternTable()->DumpForSigQuit(os);
+  GetHeap()->DumpForSigQuit(os);
   os << "\n";
 
-  thread_list_->Dump(os);
+  thread_list_->DumpForSigQuit(os);
 }
 
 void Runtime::DumpLockHolders(std::ostream& os) {
@@ -822,22 +824,13 @@
 }
 
 void Runtime::BlockSignals() {
-  sigset_t sigset;
-  if (sigemptyset(&sigset) == -1) {
-    PLOG(FATAL) << "sigemptyset failed";
-  }
-  if (sigaddset(&sigset, SIGPIPE) == -1) {
-    PLOG(ERROR) << "sigaddset SIGPIPE failed";
-  }
+  SignalSet signals;
+  signals.Add(SIGPIPE);
   // SIGQUIT is used to dump the runtime's state (including stack traces).
-  if (sigaddset(&sigset, SIGQUIT) == -1) {
-    PLOG(ERROR) << "sigaddset SIGQUIT failed";
-  }
+  signals.Add(SIGQUIT);
   // SIGUSR1 is used to initiate a GC.
-  if (sigaddset(&sigset, SIGUSR1) == -1) {
-    PLOG(ERROR) << "sigaddset SIGUSR1 failed";
-  }
-  CHECK_EQ(sigprocmask(SIG_BLOCK, &sigset, NULL), 0);
+  signals.Add(SIGUSR1);
+  signals.Block();
 }
 
 void Runtime::AttachCurrentThread(const char* thread_name, bool as_daemon, Object* thread_group) {
diff --git a/src/runtime.h b/src/runtime.h
index 0dea763..dc61b15 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -130,7 +130,7 @@
   // Detaches the current native thread from the runtime.
   void DetachCurrentThread();
 
-  void Dump(std::ostream& os);
+  void DumpForSigQuit(std::ostream& os);
   void DumpLockHolders(std::ostream& os);
 
   ~Runtime();
@@ -247,6 +247,7 @@
 
  private:
   static void PlatformAbort(const char*, int);
+  static void InitPlatformSignalHandlers();
 
   Runtime();
 
diff --git a/src/runtime_android.cc b/src/runtime_android.cc
index 4a736e6..b64f8a1 100644
--- a/src/runtime_android.cc
+++ b/src/runtime_android.cc
@@ -22,4 +22,8 @@
   // On a device, debuggerd will give us a stack trace. Nothing to do here.
 }
 
+void Runtime::InitPlatformSignalHandlers() {
+  // On a device, debuggerd will give us a stack trace. Nothing to do here.
+}
+
 }  // namespace art
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index a604819..4214003 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -18,13 +18,14 @@
 
 #include <cxxabi.h>
 #include <execinfo.h>
+#include <signal.h>
 
 #include "logging.h"
 #include "stringprintf.h"
 
 namespace art {
 
-std::string Demangle(const std::string& mangled_name) {
+static std::string Demangle(const std::string& mangled_name) {
   if (mangled_name.empty()) {
     return "??";
   }
@@ -41,9 +42,7 @@
   return mangled_name + "()";
 }
 
-void Runtime::PlatformAbort(const char* /*file*/, int /*line_number*/) {
-  // On the host, we don't have debuggerd to dump a stack for us.
-
+static void Backtrace() {
   // Get the raw stack frames.
   size_t MAX_STACK_FRAMES = 64;
   void* frames[MAX_STACK_FRAMES];
@@ -86,4 +85,144 @@
   free(symbols);
 }
 
+static const char* GetSignalCodeName(int signal_number, int signal_code) {
+  // Try the signal-specific codes...
+  switch (signal_number) {
+    case SIGILL:
+      switch (signal_code) {
+        case ILL_ILLOPC: return "ILL_ILLOPC";
+        case ILL_ILLOPN: return "ILL_ILLOPN";
+        case ILL_ILLADR: return "ILL_ILLADR";
+        case ILL_ILLTRP: return "ILL_ILLTRP";
+        case ILL_PRVOPC: return "ILL_PRVOPC";
+        case ILL_PRVREG: return "ILL_PRVREG";
+        case ILL_COPROC: return "ILL_COPROC";
+        case ILL_BADSTK: return "ILL_BADSTK";
+      }
+      break;
+    case SIGBUS:
+      switch (signal_code) {
+        case BUS_ADRALN: return "BUS_ADRALN";
+        case BUS_ADRERR: return "BUS_ADRERR";
+        case BUS_OBJERR: return "BUS_OBJERR";
+      }
+      break;
+    case SIGFPE:
+      switch (signal_code) {
+        case FPE_INTDIV: return "FPE_INTDIV";
+        case FPE_INTOVF: return "FPE_INTOVF";
+        case FPE_FLTDIV: return "FPE_FLTDIV";
+        case FPE_FLTOVF: return "FPE_FLTOVF";
+        case FPE_FLTUND: return "FPE_FLTUND";
+        case FPE_FLTRES: return "FPE_FLTRES";
+        case FPE_FLTINV: return "FPE_FLTINV";
+        case FPE_FLTSUB: return "FPE_FLTSUB";
+      }
+      break;
+    case SIGSEGV:
+      switch (signal_code) {
+        case SEGV_MAPERR: return "SEGV_MAPERR";
+        case SEGV_ACCERR: return "SEGV_ACCERR";
+      }
+      break;
+    case SIGTRAP:
+      switch (signal_code) {
+        case TRAP_BRKPT: return "TRAP_BRKPT";
+        case TRAP_TRACE: return "TRAP_TRACE";
+      }
+      break;
+  }
+  // Then the other codes...
+  switch (signal_code) {
+    case SI_USER:     return "SI_USER";
+#if defined(SI_KERNEL)
+    case SI_KERNEL:   return "SI_KERNEL";
+#endif
+    case SI_QUEUE:    return "SI_QUEUE";
+    case SI_TIMER:    return "SI_TIMER";
+    case SI_MESGQ:    return "SI_MESGQ";
+    case SI_ASYNCIO:  return "SI_ASYNCIO";
+#if defined(SI_SIGIO)
+    case SI_SIGIO:    return "SI_SIGIO";
+#endif
+#if defined(SI_TKILL)
+    case SI_TKILL:    return "SI_TKILL";
+#endif
+  }
+  // Then give up...
+  return "?";
+}
+
+static void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void*) {
+  const char* signal_name = "?";
+  bool has_address = false;
+  if (signal_number == SIGILL) {
+    signal_name = "SIGILL";
+    has_address = true;
+  } else if (signal_number == SIGTRAP) {
+    signal_name = "SIGTRAP";
+  } else if (signal_number == SIGABRT) {
+    signal_name = "SIGABRT";
+  } else if (signal_number == SIGBUS) {
+    signal_name = "SIGBUS";
+    has_address = true;
+  } else if (signal_number == SIGFPE) {
+    signal_name = "SIGFPE";
+    has_address = true;
+  } else if (signal_number == SIGSEGV) {
+    signal_name = "SIGSEGV";
+    has_address = true;
+#if defined(SIGSTKFLT)
+  } else if (signal_number == SIGSTKFLT) {
+    signal_name = "SIGSTKFLT";
+#endif
+  } else if (signal_number == SIGPIPE) {
+    signal_name = "SIGPIPE";
+  }
+
+  LOG(INTERNAL_FATAL) << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
+                      << StringPrintf("Fatal signal %d (%s), code %d (%s)",
+                                      signal_number, signal_name,
+                                      info->si_code,
+                                      GetSignalCodeName(signal_number, info->si_code))
+                      << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "");
+  Backtrace();
+
+  // TODO: make this part optional, like it is on the device?
+  // Wait for debugger to attach.
+  LOG(INTERNAL_FATAL) << "********************************************************\n"
+                      << "* Process " << getpid() << " has been suspended while crashing. Attach gdb:\n"
+                      << "*     gdb -p " << getpid() << "\n"
+                      << "********************************************************\n";
+  while (true) {
+  }
+}
+
+void Runtime::PlatformAbort(const char* /*file*/, int /*line_number*/) {
+  // On the host, we don't have debuggerd to dump a stack for us when we LOG(FATAL).
+  Backtrace();
+}
+
+void Runtime::InitPlatformSignalHandlers() {
+  // On the host, we don't have debuggerd to dump a stack for us when something unexpected happens.
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_sigaction = HandleUnexpectedSignal;
+  action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+  int rc = 0;
+  rc += sigaction(SIGILL, &action, NULL);
+  rc += sigaction(SIGTRAP, &action, NULL);
+  rc += sigaction(SIGABRT, &action, NULL);
+  rc += sigaction(SIGBUS, &action, NULL);
+  rc += sigaction(SIGFPE, &action, NULL);
+  rc += sigaction(SIGSEGV, &action, NULL);
+#if defined(SIGSTKFLT)
+  rc += sigaction(SIGSTKFLT, &action, NULL);
+#endif
+  rc += sigaction(SIGPIPE, &action, NULL);
+  CHECK_EQ(rc, 0);
+}
+
 }  // namespace art
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index be21372..5a9bf4e 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -31,6 +31,7 @@
 #include "os.h"
 #include "runtime.h"
 #include "scoped_heap_lock.h"
+#include "signal_set.h"
 #include "thread.h"
 #include "thread_list.h"
 #include "utils.h"
@@ -114,7 +115,7 @@
     os << "Cmd line: " << cmdline << "\n";
   }
 
-  runtime->Dump(os);
+  runtime->DumpForSigQuit(os);
 
   if (false) {
     std::string maps;
@@ -135,21 +136,14 @@
   Runtime::Current()->GetHeap()->CollectGarbage(false);
 }
 
-int SignalCatcher::WaitForSignal(sigset_t& mask) {
+int SignalCatcher::WaitForSignal(SignalSet& signals) {
   ScopedThreadStateChange tsc(thread_, kVmWait);
 
   // Signals for sigwait() must be blocked but not ignored.  We
   // block signals like SIGQUIT for all threads, so the condition
   // is met.  When the signal hits, we wake up, without any signal
   // handlers being invoked.
-
-  // Sleep in sigwait() until a signal arrives. gdb causes EINTR failures.
-  int signal_number;
-  int rc = TEMP_FAILURE_RETRY(sigwait(&mask, &signal_number));
-  if (rc != 0) {
-    PLOG(FATAL) << "sigwait failed";
-  }
-
+  int signal_number = signals.Wait();
   if (!ShouldHalt()) {
     // Let the user know we got the signal, just in case the system's too screwed for us to
     // actually do what they want us to do...
@@ -177,13 +171,12 @@
   }
 
   // Set up mask with signals we want to handle.
-  sigset_t mask;
-  sigemptyset(&mask);
-  sigaddset(&mask, SIGQUIT);
-  sigaddset(&mask, SIGUSR1);
+  SignalSet signals;
+  signals.Add(SIGQUIT);
+  signals.Add(SIGUSR1);
 
   while (true) {
-    int signal_number = signal_catcher->WaitForSignal(mask);
+    int signal_number = signal_catcher->WaitForSignal(signals);
     if (signal_catcher->ShouldHalt()) {
       runtime->DetachCurrentThread();
       return NULL;
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index f237b12..131b07c 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -22,6 +22,7 @@
 namespace art {
 
 class Runtime;
+class SignalSet;
 class Thread;
 
 /*
@@ -43,7 +44,7 @@
   void Output(const std::string& s);
   void SetHaltFlag(bool new_value);
   bool ShouldHalt();
-  int WaitForSignal(sigset_t& mask);
+  int WaitForSignal(SignalSet& signals);
 
   std::string stack_trace_file_;
   mutable Mutex lock_;
diff --git a/src/signal_set.h b/src/signal_set.h
new file mode 100644
index 0000000..030a2d1
--- /dev/null
+++ b/src/signal_set.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_SIGNAL_SET_H_
+#define ART_SRC_SIGNAL_SET_H_
+
+#include <signal.h>
+
+#include "logging.h"
+
+namespace art {
+
+class SignalSet {
+ public:
+  SignalSet() {
+    if (sigemptyset(&set_) == -1) {
+      PLOG(FATAL) << "sigemptyset failed";
+    }
+  }
+
+  void Add(int signal) {
+    if (sigaddset(&set_, signal) == -1) {
+      PLOG(FATAL) << "sigaddset " << signal << " failed";
+    }
+  }
+
+  void Block() {
+    if (sigprocmask(SIG_BLOCK, &set_, NULL) == -1) {
+      PLOG(FATAL) << "sigprocmask failed";
+    }
+  }
+
+  int Wait() {
+    // Sleep in sigwait() until a signal arrives. gdb causes EINTR failures.
+    int signal_number;
+    int rc = TEMP_FAILURE_RETRY(sigwait(&set_, &signal_number));
+    if (rc != 0) {
+      PLOG(FATAL) << "sigwait failed";
+    }
+    return signal_number;
+  }
+
+ private:
+  sigset_t set_;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_SIGNAL_SET_H_
diff --git a/src/thread.cc b/src/thread.cc
index 930e0df..fbf2390 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -77,10 +77,20 @@
   card_table_ = Runtime::Current()->GetHeap()->GetCardTable()->GetBiasedBegin();
 }
 
+static void UnimplementedEntryPoint() {
+  UNIMPLEMENTED(FATAL);
+}
+
 void Thread::InitFunctionPointers() {
 #if defined(ART_USE_LLVM_COMPILER)
   memset(&entrypoints_, 0, sizeof(entrypoints_));
 #else
+  // Insert a placeholder so we can easily tell if we call an unimplemented entry point.
+  uintptr_t* begin = reinterpret_cast<uintptr_t*>(&entrypoints_);
+  uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(begin) + sizeof(entrypoints_));
+  for (uintptr_t* it = begin; it != end; ++it) {
+    *it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint);
+  }
   InitEntryPoints(&entrypoints_);
 #endif
 }
@@ -160,6 +170,11 @@
     stack_size = Runtime::Current()->GetDefaultStackSize();
   }
 
+  // Dalvik used the bionic pthread default stack size for native threads,
+  // so include that here to support apps that expect large native stacks.
+  stack_size += 1 * MB;
+
+
   // It's not possible to request a stack smaller than the system-defined PTHREAD_STACK_MIN.
   if (stack_size < PTHREAD_STACK_MIN) {
     stack_size = PTHREAD_STACK_MIN;
diff --git a/src/thread.h b/src/thread.h
index 4f43473..c5695cf 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -92,7 +92,7 @@
   static const size_t kStackOverflowReservedBytes = 8 * KB;
 #endif
 
-  static const size_t kDefaultStackSize = 128 * KB;
+  static const size_t kDefaultStackSize = 16 * KB;
 
   class StackVisitor {
    public:
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 43a8561..80ab2cf 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -54,7 +54,7 @@
   return thread_list_lock_.GetOwner();
 }
 
-void ThreadList::Dump(std::ostream& os) {
+void ThreadList::DumpForSigQuit(std::ostream& os) {
   ScopedThreadListLock thread_list_lock;
   DumpLocked(os);
 }
diff --git a/src/thread_list.h b/src/thread_list.h
index 0691808..f0b4f6b 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -31,7 +31,7 @@
   explicit ThreadList();
   ~ThreadList();
 
-  void Dump(std::ostream& os);
+  void DumpForSigQuit(std::ostream& os);
   void DumpLocked(std::ostream& os); // For thread suspend timeout dumps.
   pid_t GetLockOwner(); // For SignalCatcher.
 
diff --git a/src/utils.cc b/src/utils.cc
index 70d15bf..ea50073 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -345,16 +345,26 @@
   return result;
 }
 
-std::string PrettySize(size_t size_in_bytes) {
-  if ((size_in_bytes / GB) * GB == size_in_bytes) {
-    return StringPrintf("%zdGB", size_in_bytes / GB);
-  } else if ((size_in_bytes / MB) * MB == size_in_bytes) {
-    return StringPrintf("%zdMB", size_in_bytes / MB);
-  } else if ((size_in_bytes / KB) * KB == size_in_bytes) {
-    return StringPrintf("%zdKB", size_in_bytes / KB);
-  } else {
-    return StringPrintf("%zdB", size_in_bytes);
+std::string PrettySize(size_t byte_count) {
+  // The byte thresholds at which we display amounts.  A byte count is displayed
+  // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
+  static const size_t kUnitThresholds[] = {
+    0,              // B up to...
+    3*1024,         // KB up to...
+    2*1024*1024,    // MB up to...
+    1024*1024*1024  // GB from here.
+  };
+  static const size_t kBytesPerUnit[] = { 1, KB, MB, GB };
+  static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" };
+
+  int i = arraysize(kUnitThresholds);
+  while (--i > 0) {
+    if (byte_count >= kUnitThresholds[i]) {
+      break;
+    }
   }
+
+  return StringPrintf("%zd%s", byte_count / kBytesPerUnit[i], kUnitStrings[i]);
 }
 
 std::string PrettyDuration(uint64_t nano_duration) {
diff --git a/src/utils.h b/src/utils.h
index f11a769..f94c05e 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -191,7 +191,7 @@
 // Returns a human-readable form of the name of the given class with its class loader.
 std::string PrettyClassAndClassLoader(const Class* c);
 
-// Returns a human-readable size string. e.g. "1MB"
+// Returns a human-readable size string such as "1MB".
 std::string PrettySize(size_t size_in_bytes);
 
 // Returns a human-readable time string which prints every nanosecond while trying to limit the
diff --git a/src/utils_test.cc b/src/utils_test.cc
index e0b2139..311bd16 100644
--- a/src/utils_test.cc
+++ b/src/utils_test.cc
@@ -135,15 +135,17 @@
   if (sizeof(size_t) > sizeof(uint32_t)) {
     EXPECT_EQ("100GB", PrettySize(100 * GB));
   }
-  EXPECT_EQ("1MB", PrettySize(1 * MB));
+  EXPECT_EQ("1024KB", PrettySize(1 * MB));
   EXPECT_EQ("10MB", PrettySize(10 * MB));
   EXPECT_EQ("100MB", PrettySize(100 * MB));
-  EXPECT_EQ("1KB", PrettySize(1 * KB));
+  EXPECT_EQ("1024B", PrettySize(1 * KB));
   EXPECT_EQ("10KB", PrettySize(10 * KB));
   EXPECT_EQ("100KB", PrettySize(100 * KB));
+  EXPECT_EQ("0B", PrettySize(0));
   EXPECT_EQ("1B", PrettySize(1));
   EXPECT_EQ("10B", PrettySize(10));
   EXPECT_EQ("100B", PrettySize(100));
+  EXPECT_EQ("512B", PrettySize(512));
 }
 
 TEST_F(UtilsTest, PrettyDuration) {