Add implicit checks for x86_64 architecture.

This combines the x86 and x86_64 fault handlers into one.  It also
merges in the change to the entrypoints for X86_64.

Replaces generic instruction length calculator with one that only
works with the specific instructions we use.

Bug: 16256184

Change-Id: I1e8ab5ad43f46060de9597615b423c89a836035c
Signed-off-by: Chao-ying Fu <chao-ying.fu@intel.com>
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index bd2e0f3..2498298 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -880,9 +880,13 @@
 LIR* X86Mir2Lir::CheckSuspendUsingLoad() {
   // First load the pointer in fs:[suspend-trigger] into eax
   // Then use a test instruction to indirect via that address.
-  NewLIR2(kX86Mov32RT, rs_rAX.GetReg(),   cu_->target64 ?
-      Thread::ThreadSuspendTriggerOffset<8>().Int32Value() :
-      Thread::ThreadSuspendTriggerOffset<4>().Int32Value());
+  if (cu_->target64) {
+    NewLIR2(kX86Mov64RT, rs_rAX.GetReg(),
+        Thread::ThreadSuspendTriggerOffset<8>().Int32Value());
+  } else {
+    NewLIR2(kX86Mov32RT, rs_rAX.GetReg(),
+        Thread::ThreadSuspendTriggerOffset<4>().Int32Value());
+  }
   return NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rAX.GetReg(), 0);
 }
 
@@ -1287,14 +1291,14 @@
   // Compute the number of words to search in to rCX.
   Load32Disp(rs_rDX, count_offset, rs_rCX);
 
-  if (!cu_->target64) {
-    // Possible signal here due to null pointer dereference.
-    // Note that the signal handler will expect the top word of
-    // the stack to be the ArtMethod*.  If the PUSH edi instruction
-    // below is ahead of the load above then this will not be true
-    // and the signal handler will not work.
-    MarkPossibleNullPointerException(0);
+  // Possible signal here due to null pointer dereference.
+  // Note that the signal handler will expect the top word of
+  // the stack to be the ArtMethod*.  If the PUSH edi instruction
+  // below is ahead of the load above then this will not be true
+  // and the signal handler will not work.
+  MarkPossibleNullPointerException(0);
 
+  if (!cu_->target64) {
     // EDI is callee-save register in 32-bit mode.
     NewLIR1(kX86Push32R, rs_rDI.GetReg());
   }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 0f1c8cd..403cb80 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1169,6 +1169,7 @@
     case kThumb2:
     case kArm64:
     case kX86:
+    case kX86_64:
       implicit_null_checks = true;
       implicit_so_checks = true;
       break;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 302e835..09ec004 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -248,6 +248,8 @@
 LIBART_TARGET_SRC_FILES_x86 := \
   $(LIBART_SRC_FILES_x86)
 
+# Note that the fault_handler_x86.cc is not a mistake.  This file is
+# shared between the x86 and x86_64 architectures.
 LIBART_SRC_FILES_x86_64 := \
   arch/x86_64/context_x86_64.cc \
   arch/x86_64/entrypoints_init_x86_64.cc \
@@ -257,7 +259,7 @@
   arch/x86_64/quick_entrypoints_x86_64.S \
   arch/x86_64/thread_x86_64.cc \
   monitor_pool.cc \
-  arch/x86_64/fault_handler_x86_64.cc
+  arch/x86/fault_handler_x86.cc
 
 LIBART_TARGET_SRC_FILES_x86_64 := \
   $(LIBART_SRC_FILES_x86_64) \
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 48582f4..be28544 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -46,7 +46,7 @@
   return instr_size;
 }
 
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
   struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index dc82cc2..3a7e689 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -37,7 +37,7 @@
 
 namespace art {
 
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
   struct ucontext *uc = reinterpret_cast<struct ucontext *>(context);
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 5a64a69..0e76aab 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -29,7 +29,7 @@
 
 namespace art {
 
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
 }
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 435f280..8b6c9b1 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -31,14 +31,21 @@
 #define CTX_ESP uc_mcontext->__ss.__esp
 #define CTX_EIP uc_mcontext->__ss.__eip
 #define CTX_EAX uc_mcontext->__ss.__eax
+#define CTX_METHOD uc_mcontext->__ss.__eax
+#elif defined(__x86_64__)
+#define CTX_ESP uc_mcontext.gregs[REG_RSP]
+#define CTX_EIP uc_mcontext.gregs[REG_RIP]
+#define CTX_EAX uc_mcontext.gregs[REG_RAX]
+#define CTX_METHOD uc_mcontext.gregs[REG_RDI]
 #else
 #define CTX_ESP uc_mcontext.gregs[REG_ESP]
 #define CTX_EIP uc_mcontext.gregs[REG_EIP]
 #define CTX_EAX uc_mcontext.gregs[REG_EAX]
+#define CTX_METHOD uc_mcontext.gregs[REG_EAX]
 #endif
 
 //
-// X86 specific fault handler functions.
+// X86 (and X86_64) specific fault handler functions.
 //
 
 namespace art {
@@ -47,129 +54,146 @@
 extern "C" void art_quick_throw_stack_overflow_from_signal();
 extern "C" void art_quick_test_suspend();
 
-// From the x86 disassembler...
-enum SegmentPrefix {
-  kCs = 0x2e,
-  kSs = 0x36,
-  kDs = 0x3e,
-  kEs = 0x26,
-  kFs = 0x64,
-  kGs = 0x65,
-};
-
 // Get the size of an instruction in bytes.
-static uint32_t GetInstructionSize(uint8_t* pc) {
-  uint8_t* instruction_start = pc;
-  bool have_prefixes = true;
-  bool two_byte = false;
-
-  // Skip all the prefixes.
-  do {
-    switch (*pc) {
-        // Group 1 - lock and repeat prefixes:
-      case 0xF0:
-      case 0xF2:
-      case 0xF3:
-        // Group 2 - segment override prefixes:
-      case kCs:
-      case kSs:
-      case kDs:
-      case kEs:
-      case kFs:
-      case kGs:
-        // Group 3 - operand size override:
-      case 0x66:
-        // Group 4 - address size override:
-      case 0x67:
-        break;
-      default:
-        have_prefixes = false;
-        break;
-    }
-    if (have_prefixes) {
-      pc++;
-    }
-  } while (have_prefixes);
-
-#if defined(__x86_64__)
-  // Skip REX is present.
-  if (*pc >= 0x40 && *pc <= 0x4F) {
-    ++pc;
-  }
+// Return 0 if the instruction is not handled.
+static uint32_t GetInstructionSize(const uint8_t* pc) {
+#if defined(__x86_64)
+  const bool x86_64 = true;
+#else
+  const bool x86_64 = false;
 #endif
 
-  // Check for known instructions.
-  uint32_t known_length = 0;
-  switch (*pc) {
-  case 0x83:                // cmp [r + v], b: 4 byte instruction
-    known_length = 4;
-    break;
-  }
+  const uint8_t* startpc = pc;
 
-  if (known_length > 0) {
-    VLOG(signals) << "known instruction with length " << known_length;
-    return known_length;
-  }
-
-  // Unknown instruction, work out length.
-
-  // Work out if we have a ModR/M byte.
   uint8_t opcode = *pc++;
-  if (opcode == 0xf) {
+  uint8_t modrm;
+  bool has_modrm = false;
+  bool two_byte = false;
+  uint32_t displacement_size = 0;
+  uint32_t immediate_size = 0;
+
+  // Prefixes.
+  while (true) {
+    bool prefix_present = false;
+    switch (opcode) {
+      // Group 1
+      case 0xf0:
+      case 0xf2:
+      case 0xf3:
+
+      // Group 2
+      case 0x2e:
+      case 0x36:
+      case 0x3e:
+      case 0x26:
+      case 0x64:
+      case 0x65:
+
+      // Group 3
+      case 0x66:
+
+      // Group 4
+      case 0x67:
+        opcode = *pc++;
+        prefix_present = true;
+        break;
+    }
+    if (!prefix_present) {
+      break;
+    }
+  }
+
+  if (x86_64 && opcode >= 0x40 && opcode <= 0x4f) {
+    opcode = *pc++;
+  }
+
+  if (opcode == 0x0f) {
+    // Two byte opcode
     two_byte = true;
     opcode = *pc++;
   }
 
-  bool has_modrm = false;         // Is ModR/M byte present?
-  uint8_t hi = opcode >> 4;       // Opcode high nybble.
-  uint8_t lo = opcode & 0b1111;   // Opcode low nybble.
+  bool unhandled_instruction = false;
 
-  // From the Intel opcode tables.
   if (two_byte) {
-    has_modrm = true;   // TODO: all of these?
-  } else if (hi < 4) {
-    has_modrm = lo < 4 || (lo >= 8 && lo <= 0xb);
-  } else if (hi == 6) {
-    has_modrm = lo == 3 || lo == 9 || lo == 0xb;
-  } else if (hi == 8) {
-    has_modrm = lo != 0xd;
-  } else if (hi == 0xc) {
-    has_modrm = lo == 1 || lo == 2 || lo == 6 || lo == 7;
-  } else if (hi == 0xd) {
-    has_modrm = lo < 4;
-  } else if (hi == 0xf) {
-    has_modrm = lo == 6 || lo == 7;
-  }
+    switch (opcode) {
+      case 0x10:            // vmovsd/ss
+      case 0x11:            // vmovsd/ss
+      case 0xb6:        // movzx
+      case 0xb7:
+      case 0xbe:        // movsx
+      case 0xbf:
+        modrm = *pc++;
+        has_modrm = true;
+        break;
+      default:
+        unhandled_instruction = true;
+        break;
+    }
+  } else {
+    switch (opcode) {
+      case 0x89:            // mov
+      case 0x8b:
+      case 0x38:        // cmp with memory.
+      case 0x39:
+      case 0x3a:
+      case 0x3b:
+      case 0x3c:
+      case 0x3d:
+      case 0x85:        // test.
+        modrm = *pc++;
+        has_modrm = true;
+        break;
 
-  if (has_modrm) {
-    uint8_t modrm = *pc++;
-    uint8_t mod = (modrm >> 6) & 0b11;
-    uint8_t reg = (modrm >> 3) & 0b111;
-    switch (mod) {
-      case 0:
+      case 0x80:        // group 1, byte immediate.
+      case 0x83:
+        modrm = *pc++;
+        has_modrm = true;
+        immediate_size = 1;
         break;
-      case 1:
-        if (reg == 4) {
-          // SIB + 1 byte displacement.
-          pc += 2;
-        } else {
-          pc += 1;
-        }
+
+      case 0x81:        // group 1, word immediate.
+        modrm = *pc++;
+        has_modrm = true;
+        immediate_size = 4;
         break;
-      case 2:
-        // SIB + 4 byte displacement.
-        pc += 5;
-        break;
-      case 3:
+
+      default:
+        unhandled_instruction = true;
         break;
     }
   }
 
-  VLOG(signals) << "calculated X86 instruction size is " << (pc - instruction_start);
-  return pc - instruction_start;
+  if (unhandled_instruction) {
+    VLOG(signals) << "Unhandled x86 instruction with opcode " << static_cast<int>(opcode);
+    return 0;
+  }
+
+  if (has_modrm) {
+    uint8_t mod = (modrm >> 6) & 0b11;
+
+    // Check for SIB.
+    if (mod != 0b11 && (modrm & 0b111) == 4) {
+      ++pc;     // SIB
+    }
+
+    switch (mod) {
+      case 0b00: break;
+      case 0b01: displacement_size = 1; break;
+      case 0b10: displacement_size = 4; break;
+      case 0b11:
+        break;
+    }
+  }
+
+  // Skip displacement and immediate.
+  pc += displacement_size + immediate_size;
+
+  VLOG(signals) << "x86 instruction length calculated as " << (pc - startpc);
+  return pc - startpc;
 }
 
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
+void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
   struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
@@ -180,21 +204,30 @@
   }
 
   // In the case of a stack overflow, the stack is not valid and we can't
-  // get the method from the top of the stack.  However it's in EAX.
+  // get the method from the top of the stack.  However it's in EAX(x86)/RDI(x86_64).
   uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr);
   uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
+#if defined(__x86_64__)
+      reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86_64));
+#else
       reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86));
+#endif
   if (overflow_addr == fault_addr) {
-    *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->CTX_EAX);
+    *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->CTX_METHOD);
   } else {
     // The method is at the top of the stack.
-    *out_method = reinterpret_cast<mirror::ArtMethod*>(reinterpret_cast<uintptr_t*>(*out_sp)[0]);
+    *out_method = (reinterpret_cast<StackReference<mirror::ArtMethod>* >(*out_sp)[0]).AsMirrorPtr();
   }
 
   uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
   VLOG(signals) << HexDump(pc, 32, true, "PC ");
 
   uint32_t instr_size = GetInstructionSize(pc);
+  if (instr_size == 0) {
+    // Unknown instruction, tell caller it's not ours.
+    *out_method = nullptr;
+    return;
+  }
   *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size);
 }
 
@@ -204,16 +237,21 @@
   uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
 
   uint32_t instr_size = GetInstructionSize(pc);
+  if (instr_size == 0) {
+    // Unknown instruction, can't really happen.
+    return false;
+  }
+
   // We need to arrange for the signal handler to return to the null pointer
   // exception generator.  The return address must be the address of the
   // next instruction (this instruction + instruction size).  The return address
   // is on the stack at the top address of the current frame.
 
   // Push the return address onto the stack.
-  uint32_t retaddr = reinterpret_cast<uint32_t>(pc + instr_size);
-  uint32_t* next_sp = reinterpret_cast<uint32_t*>(sp - 4);
+  uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + instr_size);
+  uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
   *next_sp = retaddr;
-  uc->CTX_ESP = reinterpret_cast<uint32_t>(next_sp);
+  uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
 
   uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception);
   VLOG(signals) << "Generating null pointer exception";
@@ -221,9 +259,14 @@
 }
 
 // A suspend check is done using the following instruction sequence:
+// (x86)
 // 0xf720f1df:         648B058C000000      mov     eax, fs:[0x8c]  ; suspend_trigger
 // .. some intervening instructions.
 // 0xf720f1e6:                   8500      test    eax, [eax]
+// (x86_64)
+// 0x7f579de45d9e: 65488B0425A8000000      movq    rax, gs:[0xa8]  ; suspend_trigger
+// .. some intervening instructions.
+// 0x7f579de45da7:               8500      test    eax, [eax]
 
 // The offset from fs is Thread::ThreadSuspendTriggerOffset().
 // To check for a suspend check, we examine the instructions that caused
@@ -231,11 +274,20 @@
 bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
   // These are the instructions to check for.  The first one is the mov eax, fs:[xxx]
   // where xxx is the offset of the suspend trigger.
+#if defined(__x86_64__)
+  uint32_t trigger = Thread::ThreadSuspendTriggerOffset<8>().Int32Value();
+#else
   uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value();
+#endif
 
   VLOG(signals) << "Checking for suspension point";
+#if defined(__x86_64__)
+  uint8_t checkinst1[] = {0x65, 0x48, 0x8b, 0x04, 0x25, static_cast<uint8_t>(trigger & 0xff),
+      static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
+#else
   uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff),
       static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
+#endif
   uint8_t checkinst2[] = {0x85, 0x00};
 
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
@@ -270,10 +322,10 @@
     // is on the stack at the top address of the current frame.
 
     // Push the return address onto the stack.
-    uint32_t retaddr = reinterpret_cast<uint32_t>(pc + 2);
-    uint32_t* next_sp = reinterpret_cast<uint32_t*>(sp - 4);
+    uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + 2);
+    uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
     *next_sp = retaddr;
-    uc->CTX_ESP = reinterpret_cast<uint32_t>(next_sp);
+    uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
 
     uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_test_suspend);
 
@@ -302,7 +354,11 @@
   VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
     ", fault_addr: " << fault_addr;
 
+#if defined(__x86_64__)
+  uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86_64);
+#else
   uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86);
+#endif
 
   Thread* self = Thread::Current();
   uintptr_t pregion = reinterpret_cast<uintptr_t>(self->GetStackEnd()) -
diff --git a/runtime/arch/x86_64/fault_handler_x86_64.cc b/runtime/arch/x86_64/fault_handler_x86_64.cc
deleted file mode 100644
index 88ae7f3..0000000
--- a/runtime/arch/x86_64/fault_handler_x86_64.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-
-#include "fault_handler.h"
-#include <sys/ucontext.h>
-#include "base/macros.h"
-#include "globals.h"
-#include "base/logging.h"
-#include "base/hex_dump.h"
-
-
-//
-// X86_64 specific fault handler functions.
-//
-
-namespace art {
-
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
-                                             mirror::ArtMethod** out_method,
-                                             uintptr_t* out_return_pc, uintptr_t* out_sp) {
-}
-
-bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
-  return false;
-}
-
-bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
-  return false;
-}
-
-bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
-  return false;
-}
-}       // namespace art
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 48bc240..f021ada 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -284,6 +284,18 @@
      */
 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
 
+// On entry to this function, RAX contains the ESP value for the overflow region.
+DEFINE_FUNCTION art_quick_throw_stack_overflow_from_signal
+    // Here, the RSP is above the protected region.  We need to create a
+    // callee save frame and then move RSP down to the overflow region.
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    mov %rsp, %rsi                    // get current stack pointer, pass SP as second arg
+    mov %rax, %rsp                    // move RSP to the overflow region.
+    mov %gs:THREAD_SELF_OFFSET, %rdi  // pass Thread::Current() as first arg
+    call PLT_SYMBOL(artThrowStackOverflowFromCode)    // artThrowStackOverflowFromCode(Thread*, SP)
+    int3                              // unreached
+END_FUNCTION art_quick_throw_stack_overflow_from_signal
+
     /*
      * Called by managed code, saves callee saves and then calls artThrowException
      * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 1b91628..8ddaf5c 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -76,6 +76,7 @@
   // Also, there is only an 8K stack available here to logging can cause memory
   // overwrite issues if you are unlucky.  If you want to enable logging and
   // are getting crashes, allocate more space for the alternate signal stack.
+
   VLOG(signals) << "Handling fault";
   if (IsInGeneratedCode(info, context, true)) {
     VLOG(signals) << "in generated code, looking for handler";
@@ -91,6 +92,7 @@
       return;
     }
   }
+
   art_sigsegv_fault();
 
   // Pass this on to the next handler in the chain, or the default if none.
@@ -150,7 +152,7 @@
 
   // Get the architecture specific method address and return address.  These
   // are in architecture specific files in arch/<arch>/fault_handler_<arch>.
-  GetMethodAndReturnPCAndSP(siginfo, context, &method_obj, &return_pc, &sp);
+  GetMethodAndReturnPcAndSp(siginfo, context, &method_obj, &return_pc, &sp);
 
   // If we don't have a potential method, we're outta here.
   VLOG(signals) << "potential method: " << method_obj;
@@ -236,7 +238,7 @@
     mirror::ArtMethod* method = nullptr;
     uintptr_t return_pc = 0;
     uintptr_t sp = 0;
-    manager_->GetMethodAndReturnPCAndSP(siginfo, context, &method, &return_pc, &sp);
+    manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp);
     Thread* self = Thread::Current();
     // Inside of generated code, sp[0] is the method, so sp is the frame.
     StackReference<mirror::ArtMethod>* frame =
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index 71c9977..1acd024 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -43,8 +43,14 @@
   void HandleFault(int sig, siginfo_t* info, void* context);
   void AddHandler(FaultHandler* handler, bool generated_code);
   void RemoveHandler(FaultHandler* handler);
-  void GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method,
-                                 uintptr_t* out_return_pc, uintptr_t* out_sp);
+
+  // Note that the following two functions are called in the context of a signal handler.
+  // The IsInGeneratedCode() function checks that the mutator lock is held before it
+  // calls GetMethodAndReturnPCAndSP().
+  // TODO: think about adding lock assertions and fake lock and unlock functions.
+  void GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method,
+                                 uintptr_t* out_return_pc, uintptr_t* out_sp)
+                                 NO_THREAD_SAFETY_ANALYSIS;
   bool IsInGeneratedCode(siginfo_t* siginfo, void *context, bool check_dex_pc)
                          NO_THREAD_SAFETY_ANALYSIS;
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index fe877d5..e0c0d63 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -621,6 +621,7 @@
     case kThumb2:
     case kX86:
     case kArm64:
+    case kX86_64:
       implicit_null_checks_ = true;
       implicit_so_checks_ = true;
       break;
diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc
index ee66ccc..9aacb30 100644
--- a/runtime/thread_linux.cc
+++ b/runtime/thread_linux.cc
@@ -32,11 +32,18 @@
   }
 }
 
+// The default SIGSTKSZ on linux is 8K.  If we do any logging in a signal
+// handler this is too small.  We allocate 16K instead.
+static constexpr int kHostAltSigStackSize = 16*1024;    // 16K signal stack.
+
 void Thread::SetUpAlternateSignalStack() {
   // Create and set an alternate signal stack.
+#ifdef HAVE_ANDROID_OS
+  LOG(FATAL) << "Invalid use of alternate signal stack on Android";
+#endif
   stack_t ss;
-  ss.ss_sp = new uint8_t[SIGSTKSZ];
-  ss.ss_size = SIGSTKSZ;
+  ss.ss_sp = new uint8_t[kHostAltSigStackSize];
+  ss.ss_size = kHostAltSigStackSize;
   ss.ss_flags = 0;
   CHECK(ss.ss_sp != NULL);
   SigAltStack(&ss, NULL);
@@ -56,7 +63,7 @@
   // Tell the kernel to stop using it.
   ss.ss_sp = NULL;
   ss.ss_flags = SS_DISABLE;
-  ss.ss_size = SIGSTKSZ;  // Avoid ENOMEM failure with Mac OS' buggy libc.
+  ss.ss_size = kHostAltSigStackSize;  // Avoid ENOMEM failure with Mac OS' buggy libc.
   SigAltStack(&ss, NULL);
 
   // Free it.