Bug 719776 - Part 2: Make MOZ_CRASH and MOZ_ASSERT expand inline. r=waldo
authorBas Schouten <bschouten@mozilla.com>
Thu, 12 Apr 2012 02:03:07 +0200
changeset 91485 20218c1c79e0337a954adc6c68496e4f7d45c30d
parent 91484 d9964e231f469686a109f1da0a30a107c79e2ace
child 91486 a964ce19e78f0e29b7782127d7f515f2721889eb
push id22445
push usereakhgari@mozilla.com
push dateThu, 12 Apr 2012 16:19:55 +0000
treeherdermozilla-central@901dfde60183 [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: Make MOZ_CRASH and MOZ_ASSERT expand inline. 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
@@ -33,19 +33,22 @@
    /*
     * Prevent unused-variable warnings by defining the macro WTF uses to test
     * 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_UNUSED(variable, assertion) do { \
+    (void)variable; \
+    ASSERT(assertion); \
+} while (0)
 #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,78 @@
 #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. We need
+    * to specifically use the global namespace in the C++ case.
+    */
+#  ifdef __cplusplus
+#    define MOZ_CRASH() \
+       do { \
+         *((volatile int *) NULL) = 123; \
+         ::abort(); \
+       } while (0)
+#  else
+#    define MOZ_CRASH() \
+       do { \
+         *((volatile int *) NULL) = 123; \
+         abort(); \
+       } while (0)
+#  endif
+#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 +236,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 +275,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__)