Bug 719776 - Part 2: Inline MOZ_Assert and MOZ_Crash. r=waldo
authorBas Schouten <bschouten@mozilla.com>
Wed, 11 Apr 2012 16:55:31 +0200
changeset 95172 bc29c3a684199d44a0251b880d1a59e7c99091e7
parent 95171 0260266fa8b5fe5e78971e8a61fcd643dd338c44
child 95173 4b82f26f8593af632e852833fae06c8d4263d606
push id160
push userlsblakk@mozilla.com
push dateFri, 13 Jul 2012 18:18:57 +0000
treeherdermozilla-release@228ba1a111fc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs719776
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 719776 - Part 2: Inline MOZ_Assert and MOZ_Crash. r=waldo
js/public/Utility.h
js/src/assembler/wtf/Assertions.h
js/src/jscntxt.h
mfbt/Assertions.h
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -327,32 +327,16 @@ unsigned char _BitScanReverse64(unsigned
             (_log2) += 4, (j_) >>= 4;                                         \
         if ((j_) >> 2)                                                        \
             (_log2) += 2, (j_) >>= 2;                                         \
         if ((j_) >> 1)                                                        \
             (_log2) += 1;                                                     \
     JS_END_MACRO
 #endif
 
-/*
- * Internal function.
- * Compute the log of the least power of 2 greater than or equal to n. This is
- * a version of JS_CeilingLog2 that operates on unsigned integers with
- * CPU-dependant size.
- */
-#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1))
-
-/*
- * Internal function.
- * Compute the log of the greatest power of 2 less than or equal to n.
- * This is a version of JS_FloorLog2 that operates on unsigned integers with
- * CPU-dependant size and requires that n != 0.
- */
-#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n))
-
 #if JS_BYTES_PER_WORD == 4
 # ifdef JS_HAS_BUILTIN_BITSCAN32
 #  define js_FloorLog2wImpl(n)                                                \
     ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
 # else
 JS_PUBLIC_API(size_t) js_FloorLog2wImpl(size_t n);
 # endif
 #elif JS_BYTES_PER_WORD == 8
@@ -361,16 +345,37 @@ JS_PUBLIC_API(size_t) js_FloorLog2wImpl(
     ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
 # else
 JS_PUBLIC_API(size_t) js_FloorLog2wImpl(size_t n);
 # endif
 #else
 # error "NOT SUPPORTED"
 #endif
 
+/*
+ * Internal function.
+ * Compute the log of the least power of 2 greater than or equal to n. This is
+ * a version of JS_CeilingLog2 that operates on unsigned integers with
+ * CPU-dependant size.
+ */
+#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1))
+
+/*
+ * Internal function.
+ * Compute the log of the greatest power of 2 less than or equal to n.
+ * This is a version of JS_FloorLog2 that operates on unsigned integers with
+ * CPU-dependant size and requires that n != 0.
+ */
+static MOZ_ALWAYS_INLINE size_t
+JS_FLOOR_LOG2W(size_t n)
+{
+    JS_ASSERT(n != 0);
+    return js_FloorLog2wImpl(n);
+}
+
 JS_END_EXTERN_C
 
 #ifdef __cplusplus
 #include <new>
 
 /*
  * User guide to memory management within SpiderMonkey:
  *
--- a/js/src/assembler/wtf/Assertions.h
+++ b/js/src/assembler/wtf/Assertions.h
@@ -35,17 +35,17 @@
     * for assertions taking effect.
     */
 #  define ASSERT_DISABLED 1
 #endif
 
 #define ASSERT(assertion) MOZ_ASSERT(assertion)
 #define ASSERT_UNUSED(variable, assertion) (((void)variable), ASSERT(assertion))
 #define ASSERT_NOT_REACHED() MOZ_NOT_REACHED("")
-#define CRASH() MOZ_Crash()
+#define CRASH() MOZ_CRASH()
 #define COMPILE_ASSERT(exp, name) MOZ_STATIC_ASSERT(exp, #name)
 
 #endif
 
 #if 0
 /*
    no namespaces because this file has to be includable from C and Objective-C
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1531,40 +1531,43 @@ extern JSErrorFormatString js_ErrorForma
 
 #ifdef JS_THREADSAFE
 # define JS_ASSERT_REQUEST_DEPTH(cx)  JS_ASSERT((cx)->runtime->requestDepth >= 1)
 #else
 # define JS_ASSERT_REQUEST_DEPTH(cx)  ((void) 0)
 #endif
 
 /*
- * If the operation callback flag was set, call the operation callback.
- * This macro can run the full GC. Return true if it is OK to continue and
- * false otherwise.
- */
-#define JS_CHECK_OPERATION_LIMIT(cx)                                          \
-    (JS_ASSERT_REQUEST_DEPTH(cx),                                             \
-     (!cx->runtime->interrupt || js_InvokeOperationCallback(cx)))
-
-/*
  * Invoke the operation callback and return false if the current execution
  * is to be terminated.
  */
 extern JSBool
 js_InvokeOperationCallback(JSContext *cx);
 
 extern JSBool
 js_HandleExecutionInterrupt(JSContext *cx);
 
 extern jsbytecode*
 js_GetCurrentBytecodePC(JSContext* cx);
 
 extern JSScript *
 js_GetCurrentScript(JSContext* cx);
 
+/*
+ * If the operation callback flag was set, call the operation callback.
+ * This macro can run the full GC. Return true if it is OK to continue and
+ * false otherwise.
+ */
+static MOZ_ALWAYS_INLINE bool
+JS_CHECK_OPERATION_LIMIT(JSContext *cx)
+{
+    JS_ASSERT_REQUEST_DEPTH(cx);
+    return !cx->runtime->interrupt || js_InvokeOperationCallback(cx);
+}
+
 namespace js {
 
 #ifdef JS_METHODJIT
 namespace mjit {
     void ExpandInlineFrames(JSCompartment *compartment);
 }
 #endif
 
--- a/mfbt/Assertions.h
+++ b/mfbt/Assertions.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
@@ -41,16 +41,25 @@
 /* Implementations of runtime and static assertion macros for C and C++. */
 
 #ifndef mozilla_Assertions_h_
 #define mozilla_Assertions_h_
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Types.h"
 
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#  include <signal.h>
+#endif
+#ifdef ANDROID
+#  include <android/log.h>
+#endif
+
 /*
  * MOZ_STATIC_ASSERT may be used to assert a condition *at compile time*.  This
  * can be useful when you make certain assumptions about what must hold for
  * optimal, or even correct, behavior.  For example, you might assert that the
  * size of a struct is a multiple of the target architecture's word size:
  *
  *   struct S { ... };
  *   MOZ_STATIC_ASSERT(sizeof(S) % sizeof(size_t) == 0,
@@ -126,22 +135,69 @@
 #endif
 
 #define MOZ_STATIC_ASSERT_IF(cond, expr, reason)  MOZ_STATIC_ASSERT(!(cond) || (expr), reason)
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-extern MFBT_API(void)
-MOZ_Crash(void);
+#if defined(WIN32)
+   /*
+    * We used to call DebugBreak() on Windows, but amazingly, it causes
+    * the MSVS 2010 debugger not to be able to recover a call stack.
+    */
+#  define MOZ_CRASH() \
+     do { \
+       *((volatile int *) NULL) = 123; \
+       exit(3); \
+     } while (0)
+#elif defined(ANDROID)
+   /*
+    * On Android, raise(SIGABRT) is handled asynchronously. Seg fault now
+    * so we crash immediately and capture the current call stack.
+    */
+#  define MOZ_CRASH() \
+     do { \
+       *((volatile int *) NULL) = 123; \
+       abort(); \
+     } while (0)
+#elif defined(__APPLE__)
+   /*
+    * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are
+    * trapped.
+    */
+#  define MOZ_CRASH() \
+     do { \
+       *((volatile int *) NULL) = 123; \
+       raise(SIGABRT);  /* In case above statement gets nixed by the optimizer. */ \
+     } while (0)
+#else
+#  define MOZ_CRASH() \
+     do { \
+       raise(SIGABRT);  /* To continue from here in GDB: "signal 0". */ \
+     } while (0)
+#endif
+
 
 extern MFBT_API(void)
 MOZ_Assert(const char* s, const char* file, int ln);
 
+static MOZ_ALWAYS_INLINE void
+MOZ_OutputAssertMessage(const char* s, const char *file, int ln)
+{
+#ifdef ANDROID
+  __android_log_print(ANDROID_LOG_FATAL, "MOZ_Assert",
+                      "Assertion failure: %s, at %s:%d\n", s, file, ln);
+#else
+  fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
+  fflush(stderr);
+#endif
+}
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
 
 /*
  * MOZ_ASSERT(expr [, explanation-string]) asserts that |expr| must be truthy in
  * debug builds.  If it is, execution continues.  Otherwise, an error message
  * including the expression and the explanation-string (if provided) is printed,
@@ -171,20 +227,30 @@ MOZ_Assert(const char* s, const char* fi
  *              "we already set [[PrimitiveThis]] for this String object");
  *
  * MOZ_ASSERT has no effect in non-debug builds.  It is designed to catch bugs
  * *only* during debugging, not "in the field".
  */
 #ifdef DEBUG
    /* First the single-argument form. */
 #  define MOZ_ASSERT_HELPER1(expr) \
-     ((expr) ? ((void)0) : MOZ_Assert(#expr, __FILE__, __LINE__))
+     do { \
+       if (expr) { \
+         MOZ_OutputAssertMessage(#expr, __FILE__, __LINE__); \
+         MOZ_CRASH(); \
+       } \
+     } while (0)
    /* Now the two-argument form. */
 #  define MOZ_ASSERT_HELPER2(expr, explain) \
-     ((expr) ? ((void)0) : MOZ_Assert(#expr " (" explain ")", __FILE__, __LINE__))
+     do { \
+       if (expr) { \
+         MOZ_OutputAssertMessage(#expr " (" explain ")", __FILE__, __LINE__); \
+         MOZ_CRASH(); \
+       } \
+     } while (0)
    /* And now, helper macrology up the wazoo. */
    /*
     * Count the number of arguments passed to MOZ_ASSERT, very carefully
     * tiptoeing around an MSVC bug where it improperly expands __VA_ARGS__ as a
     * single token in argument lists.  See these URLs for details:
     *
     *   http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
     *   http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
@@ -200,32 +266,36 @@ MOZ_Assert(const char* s, const char* fi
 #  define MOZ_ASSERT_CHOOSE_HELPER1(count) MOZ_ASSERT_CHOOSE_HELPER2(count)
 #  define MOZ_ASSERT_CHOOSE_HELPER(count) MOZ_ASSERT_CHOOSE_HELPER1(count)
    /* The actual macro. */
 #  define MOZ_ASSERT_GLUE(x, y) x y
 #  define MOZ_ASSERT(...) \
      MOZ_ASSERT_GLUE(MOZ_ASSERT_CHOOSE_HELPER(MOZ_COUNT_ASSERT_ARGS(__VA_ARGS__)), \
                      (__VA_ARGS__))
 #else
-#  define MOZ_ASSERT(...) ((void)0)
+#  define MOZ_ASSERT(...) do { } while(0)
 #endif /* DEBUG */
 
 /*
  * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is
  * true.
  *
  *   MOZ_ASSERT_IF(isPrime(num), num == 2 || isOdd(num));
  *
  * As with MOZ_ASSERT, MOZ_ASSERT_IF has effect only in debug builds.  It is
  * designed to catch bugs during debugging, not "in the field".
  */
 #ifdef DEBUG
-#  define MOZ_ASSERT_IF(cond, expr)  ((cond) ? MOZ_ASSERT(expr) : ((void)0))
+#  define MOZ_ASSERT_IF(cond, expr) \
+     do { \
+       if ((cond)) \
+         MOZ_ASSERT(expr); \
+     } while (0)
 #else
-#  define MOZ_ASSERT_IF(cond, expr)  ((void)0)
+#  define MOZ_ASSERT_IF(cond, expr)  do { } while (0)
 #endif
 
 /* MOZ_NOT_REACHED_MARKER() expands (in compilers which support it) to an
  * expression which states that it is undefined behavior for the compiler to
  * reach this point. Most code should probably use the higher level
  * MOZ_NOT_REACHED (which expands to this when appropriate).
  */
 #if defined(__clang__)