Merge "Add read barriers for the weak roots in the JNI weak globals."
diff --git a/Android.mk b/Android.mk
index b329a5a..a30c090 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,8 @@
 include $(art_path)/dalvikvm/Android.mk
 include $(art_path)/tools/Android.mk
 include $(art_build_path)/Android.oat.mk
+include $(art_path)/sigchainlib/Android.mk
+
 
 
 
diff --git a/build/Android.libarttest.mk b/build/Android.libarttest.mk
index 9e5f3d6..c080928 100644
--- a/build/Android.libarttest.mk
+++ b/build/Android.libarttest.mk
@@ -16,6 +16,7 @@
 
 LIBARTTEST_COMMON_SRC_FILES := \
 	test/JniTest/jni_test.cc \
+	test/SignalTest/signaltest.cc \
 	test/ReferenceMap/stack_walk_refmap_jni.cc \
 	test/StackWalk/stack_walk_jni.cc \
 	test/UnsafeTest/unsafe_test.cc
diff --git a/runtime/Android.mk b/runtime/Android.mk
index c2507b1..a0648b0 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -402,11 +402,13 @@
     endif
   endif
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
+  LOCAL_C_INCLUDES += art/sigchainlib
+
   LOCAL_SHARED_LIBRARIES += liblog libnativehelper
   include external/libcxx/libcxx.mk
   LOCAL_SHARED_LIBRARIES += libbacktrace_libc++
   ifeq ($$(art_target_or_host),target)
-    LOCAL_SHARED_LIBRARIES += libcutils libdl libselinux libutils
+    LOCAL_SHARED_LIBRARIES += libcutils libdl libselinux libutils libsigchain
     LOCAL_STATIC_LIBRARIES := libziparchive libz
   else # host
     LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
@@ -459,3 +461,4 @@
 ifeq ($(ART_BUILD_TARGET_DEBUG),true)
   $(eval $(call build-libart,target,debug,$(ART_TARGET_CLANG)))
 endif
+
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 8d750c5..15c38c1 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -29,12 +29,22 @@
 #include "mirror/object-inl.h"
 #include "object_utils.h"
 #include "scoped_thread_state_change.h"
+#ifdef HAVE_ANDROID_OS
+#include "sigchain.h"
+#endif
 #include "verify_object-inl.h"
 
 namespace art {
 // Static fault manger object accessed by signal handler.
 FaultManager fault_manager;
 
+extern "C" {
+void art_sigsegv_fault() {
+  // Set a breakpoint here to be informed when a SIGSEGV is unhandled by ART.
+  VLOG(signals)<< "Caught unknown SIGSEGV in ART fault handler - chaining to next handler.";
+}
+}
+
 // Signal handler called on SIGSEGV.
 static void art_fault_handler(int sig, siginfo_t* info, void* context) {
   fault_manager.HandleFault(sig, info, context);
@@ -45,9 +55,13 @@
 }
 
 FaultManager::~FaultManager() {
+#ifdef HAVE_ANDROID_OS
+  UnclaimSignalChain(SIGSEGV);
+#endif
   sigaction(SIGSEGV, &oldaction_, nullptr);   // Restore old handler.
 }
 
+
 void FaultManager::Init() {
   struct sigaction action;
   action.sa_sigaction = art_fault_handler;
@@ -56,7 +70,13 @@
 #if !defined(__mips__)
   action.sa_restorer = nullptr;
 #endif
+
+  // Set our signal handler now.
   sigaction(SIGSEGV, &action, &oldaction_);
+#ifdef HAVE_ANDROID_OS
+  // Make sure our signal handler is called before any user handlers.
+  ClaimSignalChain(SIGSEGV, &oldaction_);
+#endif
 }
 
 void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
@@ -79,8 +99,13 @@
       return;
     }
   }
-  VLOG(signals)<< "Caught unknown SIGSEGV in ART fault handler";
+  art_sigsegv_fault();
+
+#ifdef HAVE_ANDROID_OS
+  InvokeUserSignalHandler(sig, info, context);
+#else
   oldaction_.sa_sigaction(sig, info, context);
+#endif
 }
 
 void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 23a49cb..361070c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -562,9 +562,20 @@
     GetInstrumentation()->ForceInterpretOnly();
   }
 
-  if (options->explicit_checks_ != (ParsedOptions::kExplicitSuspendCheck |
-        ParsedOptions::kExplicitNullCheck |
-        ParsedOptions::kExplicitStackOverflowCheck) || kEnableJavaStackTraceHandler) {
+  bool implicit_checks_supported = false;
+  switch (kRuntimeISA) {
+    case kArm:
+    case kThumb2:
+      implicit_checks_supported = true;
+      break;
+    default:
+      break;
+  }
+
+  if (implicit_checks_supported &&
+      (options->explicit_checks_ != (ParsedOptions::kExplicitSuspendCheck |
+          ParsedOptions::kExplicitNullCheck |
+          ParsedOptions::kExplicitStackOverflowCheck) || kEnableJavaStackTraceHandler)) {
     fault_manager.Init();
 
     // These need to be in a specific order.  The null point check handler must be
diff --git a/runtime/thread.h b/runtime/thread.h
index 9a7cb48..08bbcae 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -121,7 +121,7 @@
   // of the stack (lowest memory).  The higher portion of the memory
   // is protected against reads and the lower is available for use while
   // throwing the StackOverflow exception.
-  static constexpr size_t kStackOverflowProtectedSize = 32 * KB;
+  static constexpr size_t kStackOverflowProtectedSize = 16 * KB;
   static constexpr size_t kStackOverflowImplicitCheckSize = kStackOverflowProtectedSize +
     kStackOverflowReservedBytes;
 
diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk
new file mode 100644
index 0000000..cb1778d
--- /dev/null
+++ b/sigchainlib/Android.mk
@@ -0,0 +1,29 @@
+#
+# Copyright (C) 2014 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include art/build/Android.common.mk
+
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+LOCAL_SRC_FILES := sigchain.cc
+LOCAL_MODULE:= libsigchain
+LOCAL_SHARED_LIBRARIES += liblog libdl
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_SHARED_LIBRARY)
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
new file mode 100644
index 0000000..26e7d31
--- /dev/null
+++ b/sigchainlib/sigchain.cc
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 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 <android/log.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace art {
+
+class SignalAction {
+ public:
+  SignalAction() : claimed_(false) {
+  }
+
+  // Claim the signal and keep the action specified.
+  void Claim(const struct sigaction& action) {
+    action_ = action;
+    claimed_ = true;
+  }
+
+  // Unclaim the signal and restore the old action.
+  void Unclaim(int signal) {
+    claimed_ = false;
+    sigaction(signal, &action_, NULL);        // Restore old action.
+  }
+
+  // Get the action associated with this signal.
+  const struct sigaction& GetAction() const {
+    return action_;
+  }
+
+  // Is the signal claimed?
+  bool IsClaimed() const {
+    return claimed_;
+  }
+
+  // Change the recorded action to that specified.
+  void SetAction(const struct sigaction& action) {
+    action_ = action;
+  }
+
+ private:
+  struct sigaction action_;     // Action to be performed.
+  bool claimed_;                // Whether signal is claimed or not.
+};
+
+// User's signal handlers
+static SignalAction user_sigactions[_NSIG];
+
+static void log(const char* format, ...) {
+  char buf[256];
+  va_list ap;
+  va_start(ap, format);
+  vsnprintf(buf, sizeof(buf), format, ap);
+  __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf);
+  va_end(ap);
+}
+
+static void CheckSignalValid(int signal) {
+  if (signal <= 0 || signal >= _NSIG) {
+    log("Invalid signal %d", signal);
+    abort();
+  }
+}
+
+// Claim a signal chain for a particular signal.
+void ClaimSignalChain(int signal, struct sigaction* oldaction) {
+  CheckSignalValid(signal);
+  user_sigactions[signal].Claim(*oldaction);
+}
+
+void UnclaimSignalChain(int signal) {
+  CheckSignalValid(signal);
+
+  user_sigactions[signal].Unclaim(signal);
+}
+
+// Invoke the user's signal handler.
+void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context) {
+  // Check the arguments.
+  CheckSignalValid(sig);
+
+  // The signal must have been claimed in order to get here.  Check it.
+  if (!user_sigactions[sig].IsClaimed()) {
+    abort();
+  }
+
+  const struct sigaction& action = user_sigactions[sig].GetAction();
+
+  // Only deliver the signal if the signal was not masked out.
+  if (sigismember(&action.sa_mask, sig)) {
+     return;
+  }
+  if ((action.sa_flags & SA_SIGINFO) == 0) {
+    if (action.sa_handler != NULL) {
+      action.sa_handler(sig);
+    }
+  } else {
+    if (action.sa_sigaction != NULL) {
+      action.sa_sigaction(sig, info, context);
+    }
+  }
+}
+
+extern "C" {
+// These functions are C linkage since they replace the functions in libc.
+
+int sigaction(int signal, const struct sigaction* new_action, struct sigaction* old_action) {
+  // If this signal has been claimed as a signal chain, record the user's
+  // action but don't pass it on to the kernel.
+  // Note that we check that the signal number is in range here.  An out of range signal
+  // number should behave exactly as the libc sigaction.
+  if (signal > 0 && signal < _NSIG && user_sigactions[signal].IsClaimed()) {
+    if (old_action != NULL) {
+      *old_action = user_sigactions[signal].GetAction();
+    }
+    if (new_action != NULL) {
+      user_sigactions[signal].SetAction(*new_action);
+    }
+    return 0;
+  }
+
+  // Will only get here if the signal chain has not been claimed.  We want
+  // to pass the sigaction on to the kernel via the real sigaction in libc.
+
+  void* linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
+  if (linked_sigaction_sym == nullptr) {
+    log("Unable to find next sigaction in signal chain");
+    abort();
+  }
+
+  typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
+  SigAction linked_sigaction = reinterpret_cast<SigAction>(linked_sigaction_sym);
+  return linked_sigaction(signal, new_action, old_action);
+}
+
+
+int sigprocmask(int how, const sigset_t* bionic_new_set, sigset_t* bionic_old_set) {
+  const sigset_t* new_set_ptr = bionic_new_set;
+  sigset_t tmpset;
+  if (bionic_new_set != NULL) {
+    tmpset = *bionic_new_set;
+
+    if (how == SIG_BLOCK) {
+      // Don't allow claimed signals in the mask.  If a signal chain has been claimed
+      // we can't allow the user to block that signal.
+      for (int i = 0 ; i < _NSIG; ++i) {
+        if (user_sigactions[i].IsClaimed() && sigismember(&tmpset, i)) {
+            sigdelset(&tmpset, i);
+        }
+      }
+    }
+    new_set_ptr = &tmpset;
+  }
+
+  void* linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
+  if (linked_sigprocmask_sym == nullptr) {
+    log("Unable to find next sigprocmask in signal chain");
+    abort();
+  }
+
+  typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
+  SigProcMask linked_sigprocmask= reinterpret_cast<SigProcMask>(linked_sigprocmask_sym);
+  return linked_sigprocmask(how, new_set_ptr, bionic_old_set);
+}
+}   // extern "C"
+}   // namespace art
+
diff --git a/sigchainlib/sigchain.h b/sigchainlib/sigchain.h
new file mode 100644
index 0000000..f6f2253
--- /dev/null
+++ b/sigchainlib/sigchain.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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_SIGCHAINLIB_SIGCHAIN_H_
+#define ART_SIGCHAINLIB_SIGCHAIN_H_
+
+#include <signal.h>
+namespace art {
+
+void ClaimSignalChain(int signal, struct sigaction* oldaction);
+void UnclaimSignalChain(int signal);
+void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context);
+
+}   // namespace art
+
+#endif  // ART_SIGCHAINLIB_SIGCHAIN_H_
diff --git a/test/Android.mk b/test/Android.mk
index 8caa033..c15259c 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -46,6 +46,7 @@
 	HelloWorld \
 	InterfaceTest \
 	JniTest \
+	SignalTest \
 	NativeAllocations \
 	ParallelGC \
 	ReferenceMap \
diff --git a/test/SignalTest/SignalTest.java b/test/SignalTest/SignalTest.java
new file mode 100644
index 0000000..7f15aea
--- /dev/null
+++ b/test/SignalTest/SignalTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+class SignalTest {
+    private static native void initSignalTest();
+    private static native void terminateSignalTest();
+    private static native int testSignal();
+
+    private static void stackOverflow() {
+       stackOverflow();
+    }
+
+    public static void main(String[] args) {
+        System.loadLibrary("arttest");
+
+        System.out.println("init signal test");
+        initSignalTest();
+        try {
+            Object o = null;
+            int hash = o.hashCode();
+
+            // Should never get here.
+            System.out.println("hash: " + hash);
+            throw new AssertionError();
+        } catch (NullPointerException e) {
+            System.out.println("Caught NullPointerException");
+        }
+        try {
+            stackOverflow();
+
+            // Should never get here.
+            throw new AssertionError();
+        } catch (StackOverflowError e) {
+            System.out.println("Caught StackOverflowError");
+        }
+
+        // Test that a signal in native code works.  This will return
+        // the value 1234 if the signal is caught.
+        int x = testSignal();
+        if (x != 1234) {
+            throw new AssertionError();
+        }
+
+        terminateSignalTest();
+        System.out.println("Signal test OK");
+    }
+}
diff --git a/test/SignalTest/signaltest.cc b/test/SignalTest/signaltest.cc
new file mode 100644
index 0000000..b84e395
--- /dev/null
+++ b/test/SignalTest/signaltest.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 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 <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "jni.h"
+
+#ifdef __arm__
+#include <sys/ucontext.h>
+#endif
+
+static void signalhandler(int sig, siginfo_t* info, void* context) {
+  printf("signal caught\n");
+#ifdef __arm__
+  // On ARM we do a more exhaustive test to make sure the signal
+  // context is OK.
+  // We can do this because we know that the instruction causing
+  // the signal is 2 bytes long (thumb mov instruction).  On
+  // other architectures this is more difficult.
+  // TODO: we could do this on other architectures too if necessary, it's just harder.
+  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+  sc->arm_pc += 2;          // Skip instruction causing segv.
+#endif
+}
+
+static struct sigaction oldaction;
+
+extern "C" JNIEXPORT void JNICALL Java_SignalTest_initSignalTest(JNIEnv*, jclass) {
+  struct sigaction action;
+  action.sa_sigaction = signalhandler;
+  sigemptyset(&action.sa_mask);
+  action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+#if !defined(__mips__)
+  action.sa_restorer = nullptr;
+#endif
+
+  sigaction(SIGSEGV, &action, &oldaction);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_SignalTest_terminateSignalTest(JNIEnv*, jclass) {
+  sigaction(SIGSEGV, &oldaction, nullptr);
+}
+
+// Prevent the compiler being a smart-alec and optimizing out the assignment
+// to nullptr.
+char *p = nullptr;
+
+extern "C" JNIEXPORT jint JNICALL Java_SignalTest_testSignal(JNIEnv*, jclass) {
+#ifdef __arm__
+  // On ARM we cause a real SEGV.
+  *p = 'a';
+#else
+  // On other architectures we simulate SEGV.
+  kill(getpid(), SIGSEGV);
+#endif
+  return 1234;
+}
+