LCOV - code coverage report
Current view: top level - src/base - logging.h (source / functions) Hit Total Coverage
Test: app.info Lines: 23 23 100.0 %
Date: 2017-10-20 Functions: 4 30 13.3 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_BASE_LOGGING_H_
       6             : #define V8_BASE_LOGGING_H_
       7             : 
       8             : #include <cstring>
       9             : #include <sstream>
      10             : #include <string>
      11             : 
      12             : #include "src/base/base-export.h"
      13             : #include "src/base/build_config.h"
      14             : #include "src/base/compiler-specific.h"
      15             : #include "src/base/template-utils.h"
      16             : 
      17             : [[noreturn]] PRINTF_FORMAT(3, 4) V8_BASE_EXPORT V8_NOINLINE
      18             :     void V8_Fatal(const char* file, int line, const char* format, ...);
      19             : 
      20             : V8_BASE_EXPORT V8_NOINLINE void V8_Dcheck(const char* file, int line,
      21             :                                           const char* message);
      22             : 
      23             : // The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during
      24             : // development, but they should not be relied on in the final product.
      25             : #ifdef DEBUG
      26             : #define FATAL(msg)                              \
      27             :   V8_Fatal(__FILE__, __LINE__, "%s", (msg))
      28             : #define UNIMPLEMENTED()                         \
      29             :   V8_Fatal(__FILE__, __LINE__, "unimplemented code")
      30             : #define UNREACHABLE()                           \
      31             :   V8_Fatal(__FILE__, __LINE__, "unreachable code")
      32             : #else
      33             : #define FATAL(msg)                              \
      34             :   V8_Fatal("", 0, "%s", (msg))
      35             : #define UNIMPLEMENTED()                         \
      36             :   V8_Fatal("", 0, "unimplemented code")
      37             : #define UNREACHABLE() V8_Fatal("", 0, "unreachable code")
      38             : #endif
      39             : 
      40             : 
      41             : namespace v8 {
      42             : namespace base {
      43             : 
      44             : // Overwrite the default function that prints a stack trace.
      45             : V8_BASE_EXPORT void SetPrintStackTrace(void (*print_stack_trace_)());
      46             : 
      47             : // Override the default function that handles DCHECKs.
      48             : V8_BASE_EXPORT void SetDcheckFunction(void (*dcheck_Function)(const char*, int,
      49             :                                                               const char*));
      50             : 
      51             : // CHECK dies with a fatal error if condition is not true.  It is *not*
      52             : // controlled by DEBUG, so the check will be executed regardless of
      53             : // compilation mode.
      54             : //
      55             : // We make sure CHECK et al. always evaluates their arguments, as
      56             : // doing CHECK(FunctionWithSideEffect()) is a common idiom.
      57             : #define CHECK_WITH_MSG(condition, message)                        \
      58             :   do {                                                            \
      59             :     if (V8_UNLIKELY(!(condition))) {                              \
      60             :       V8_Fatal(__FILE__, __LINE__, "Check failed: %s.", message); \
      61             :     }                                                             \
      62             :   } while (0)
      63             : #define CHECK(condition) CHECK_WITH_MSG(condition, #condition)
      64             : 
      65             : #ifdef DEBUG
      66             : 
      67             : #define DCHECK_WITH_MSG(condition, message)   \
      68             :   do {                                        \
      69             :     if (V8_UNLIKELY(!(condition))) {          \
      70             :       V8_Dcheck(__FILE__, __LINE__, message); \
      71             :     }                                         \
      72             :   } while (0)
      73             : #define DCHECK(condition) DCHECK_WITH_MSG(condition, #condition)
      74             : 
      75             : // Helper macro for binary operators.
      76             : // Don't use this macro directly in your code, use CHECK_EQ et al below.
      77             : #define CHECK_OP(name, op, lhs, rhs)                                      \
      78             :   do {                                                                    \
      79             :     if (std::string* _msg = ::v8::base::Check##name##Impl<                \
      80             :             typename ::v8::base::pass_value_or_ref<decltype(lhs)>::type,  \
      81             :             typename ::v8::base::pass_value_or_ref<decltype(rhs)>::type>( \
      82             :             (lhs), (rhs), #lhs " " #op " " #rhs)) {                       \
      83             :       V8_Fatal(__FILE__, __LINE__, "Check failed: %s.", _msg->c_str());   \
      84             :       delete _msg;                                                        \
      85             :     }                                                                     \
      86             :   } while (0)
      87             : 
      88             : #define DCHECK_OP(name, op, lhs, rhs)                                     \
      89             :   do {                                                                    \
      90             :     if (std::string* _msg = ::v8::base::Check##name##Impl<                \
      91             :             typename ::v8::base::pass_value_or_ref<decltype(lhs)>::type,  \
      92             :             typename ::v8::base::pass_value_or_ref<decltype(rhs)>::type>( \
      93             :             (lhs), (rhs), #lhs " " #op " " #rhs)) {                       \
      94             :       V8_Dcheck(__FILE__, __LINE__, _msg->c_str());                       \
      95             :       delete _msg;                                                        \
      96             :     }                                                                     \
      97             :   } while (0)
      98             : 
      99             : #else
     100             : 
     101             : // Make all CHECK functions discard their log strings to reduce code
     102             : // bloat for official release builds.
     103             : 
     104             : #define CHECK_OP(name, op, lhs, rhs)                                         \
     105             :   do {                                                                       \
     106             :     bool _cmp = ::v8::base::Cmp##name##Impl<                                 \
     107             :         typename ::v8::base::pass_value_or_ref<decltype(lhs)>::type,         \
     108             :         typename ::v8::base::pass_value_or_ref<decltype(rhs)>::type>((lhs),  \
     109             :                                                                      (rhs)); \
     110             :     CHECK_WITH_MSG(_cmp, #lhs " " #op " " #rhs);                             \
     111             :   } while (0)
     112             : 
     113             : #define DCHECK_WITH_MSG(condition, msg) void(0);
     114             : 
     115             : #endif
     116             : 
     117             : // Define PrintCheckOperand<T> for each T which defines operator<< for ostream.
     118             : template <typename T>
     119           4 : typename std::enable_if<has_output_operator<T>::value>::type PrintCheckOperand(
     120             :     std::ostream& os, T val) {
     121           2 :   os << std::forward<T>(val);
     122           4 : }
     123             : 
     124             : // Define PrintCheckOperand<T> for enums which have no operator<<.
     125             : template <typename T>
     126             : typename std::enable_if<std::is_enum<T>::value &&
     127             :                         !has_output_operator<T>::value>::type
     128             : PrintCheckOperand(std::ostream& os, T val) {
     129             :   using underlying_t = typename std::underlying_type<T>::type;
     130             :   // 8-bit types are not printed as number, so extend them to 16 bit.
     131             :   using int_t = typename std::conditional<
     132             :       std::is_same<underlying_t, uint8_t>::value, uint16_t,
     133             :       typename std::conditional<std::is_same<underlying_t, int8_t>::value,
     134             :                                 int16_t, underlying_t>::type>::type;
     135             :   PrintCheckOperand(os, static_cast<int_t>(static_cast<underlying_t>(val)));
     136             : }
     137             : 
     138             : // Define default PrintCheckOperand<T> for non-printable types.
     139             : template <typename T>
     140             : typename std::enable_if<!has_output_operator<T>::value &&
     141             :                         !std::is_enum<T>::value>::type
     142             : PrintCheckOperand(std::ostream& os, T val) {
     143             :   os << "<unprintable>";
     144             : }
     145             : 
     146             : // Define specializations for character types, defined in logging.cc.
     147             : #define DEFINE_PRINT_CHECK_OPERAND_CHAR(type)                              \
     148             :   template <>                                                              \
     149             :   V8_BASE_EXPORT void PrintCheckOperand<type>(std::ostream & os, type ch); \
     150             :   template <>                                                              \
     151             :   V8_BASE_EXPORT void PrintCheckOperand<type*>(std::ostream & os,          \
     152             :                                                type * cstr);               \
     153             :   template <>                                                              \
     154             :   V8_BASE_EXPORT void PrintCheckOperand<const type*>(std::ostream & os,    \
     155             :                                                      const type* cstr);
     156             : 
     157             : DEFINE_PRINT_CHECK_OPERAND_CHAR(char)
     158             : DEFINE_PRINT_CHECK_OPERAND_CHAR(signed char)
     159             : DEFINE_PRINT_CHECK_OPERAND_CHAR(unsigned char)
     160             : #undef DEFINE_PRINT_CHECK_OPERAND_CHAR
     161             : 
     162             : // Build the error message string.  This is separate from the "Impl"
     163             : // function template because it is not performance critical and so can
     164             : // be out of line, while the "Impl" code should be inline. Caller
     165             : // takes ownership of the returned string.
     166             : template <typename Lhs, typename Rhs>
     167           3 : std::string* MakeCheckOpString(Lhs lhs, Rhs rhs, char const* msg) {
     168           3 :   std::ostringstream ss;
     169           3 :   ss << msg << " (";
     170           2 :   PrintCheckOperand<Lhs>(ss, lhs);
     171           3 :   ss << " vs. ";
     172           2 :   PrintCheckOperand<Rhs>(ss, rhs);
     173           3 :   ss << ")";
     174           6 :   return new std::string(ss.str());
     175             : }
     176             : 
     177             : // Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
     178             : // in logging.cc.
     179             : #define EXPLICIT_CHECK_OP_INSTANTIATION(type)                                \
     180             :   extern template V8_BASE_EXPORT std::string* MakeCheckOpString<type, type>( \
     181             :       type, type, char const*);                                              \
     182             :   extern template V8_BASE_EXPORT void PrintCheckOperand<type>(std::ostream&, \
     183             :                                                               type);
     184             : 
     185             : EXPLICIT_CHECK_OP_INSTANTIATION(int)
     186             : EXPLICIT_CHECK_OP_INSTANTIATION(long)       // NOLINT(runtime/int)
     187             : EXPLICIT_CHECK_OP_INSTANTIATION(long long)  // NOLINT(runtime/int)
     188             : EXPLICIT_CHECK_OP_INSTANTIATION(unsigned int)
     189             : EXPLICIT_CHECK_OP_INSTANTIATION(unsigned long)       // NOLINT(runtime/int)
     190             : EXPLICIT_CHECK_OP_INSTANTIATION(unsigned long long)  // NOLINT(runtime/int)
     191             : EXPLICIT_CHECK_OP_INSTANTIATION(void const*)
     192             : #undef EXPLICIT_CHECK_OP_INSTANTIATION
     193             : 
     194             : // comparison_underlying_type provides the underlying integral type of an enum,
     195             : // or std::decay<T>::type if T is not an enum. Booleans are converted to
     196             : // "unsigned int", to allow "unsigned int == bool" comparisons.
     197             : template <typename T>
     198             : struct comparison_underlying_type {
     199             :   // std::underlying_type must only be used with enum types, thus use this
     200             :   // {Dummy} type if the given type is not an enum.
     201             :   enum Dummy {};
     202             :   using decay = typename std::decay<T>::type;
     203             :   static constexpr bool is_enum = std::is_enum<decay>::value;
     204             :   using underlying = typename std::underlying_type<
     205             :       typename std::conditional<is_enum, decay, Dummy>::type>::type;
     206             :   using type_or_bool =
     207             :       typename std::conditional<is_enum, underlying, decay>::type;
     208             :   using type =
     209             :       typename std::conditional<std::is_same<type_or_bool, bool>::value,
     210             :                                 unsigned int, type_or_bool>::type;
     211             : };
     212             : // Cast a value to its underlying type
     213             : #define MAKE_UNDERLYING(Type, value) \
     214             :   static_cast<typename comparison_underlying_type<Type>::type>(value)
     215             : 
     216             : // is_signed_vs_unsigned::value is true if both types are integral, Lhs is
     217             : // signed, and Rhs is unsigned. False in all other cases.
     218             : template <typename Lhs, typename Rhs>
     219             : struct is_signed_vs_unsigned {
     220             :   using lhs_underlying = typename comparison_underlying_type<Lhs>::type;
     221             :   using rhs_underlying = typename comparison_underlying_type<Rhs>::type;
     222             :   static constexpr bool value = std::is_integral<lhs_underlying>::value &&
     223             :                                 std::is_integral<rhs_underlying>::value &&
     224             :                                 std::is_signed<lhs_underlying>::value &&
     225             :                                 std::is_unsigned<rhs_underlying>::value;
     226             : };
     227             : // Same thing, other way around: Lhs is unsigned, Rhs signed.
     228             : template <typename Lhs, typename Rhs>
     229             : struct is_unsigned_vs_signed : public is_signed_vs_unsigned<Rhs, Lhs> {};
     230             : 
     231             : // Specialize the compare functions for signed vs. unsigned comparisons.
     232             : // std::enable_if ensures that this template is only instantiable if both Lhs
     233             : // and Rhs are integral types, and their signedness does not match.
     234             : #define MAKE_UNSIGNED(Type, value)         \
     235             :   static_cast<typename std::make_unsigned< \
     236             :       typename comparison_underlying_type<Type>::type>::type>(value)
     237             : #define DEFINE_SIGNED_MISMATCH_COMP(CHECK, NAME, IMPL)                  \
     238             :   template <typename Lhs, typename Rhs>                                 \
     239             :   V8_INLINE typename std::enable_if<CHECK<Lhs, Rhs>::value, bool>::type \
     240             :       Cmp##NAME##Impl(Lhs lhs, Rhs rhs) {                               \
     241             :     return IMPL;                                                        \
     242             :   }
     243     1325492 : DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, EQ,
     244             :                             lhs >= 0 && MAKE_UNSIGNED(Lhs, lhs) ==
     245             :                                             MAKE_UNDERLYING(Rhs, rhs))
     246      327518 : DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, LT,
     247             :                             lhs < 0 || MAKE_UNSIGNED(Lhs, lhs) <
     248             :                                            MAKE_UNDERLYING(Rhs, rhs))
     249      684182 : DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, LE,
     250             :                             lhs <= 0 || MAKE_UNSIGNED(Lhs, lhs) <=
     251             :                                             MAKE_UNDERLYING(Rhs, rhs))
     252     1046713 : DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, NE, !CmpEQImpl(lhs, rhs))
     253      648605 : DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, GT, !CmpLEImpl(lhs, rhs))
     254      270444 : DEFINE_SIGNED_MISMATCH_COMP(is_signed_vs_unsigned, GE, !CmpLTImpl(lhs, rhs))
     255             : DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, EQ, CmpEQImpl(rhs, lhs))
     256             : DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, NE, CmpNEImpl(rhs, lhs))
     257             : DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, LT, CmpGTImpl(rhs, lhs))
     258             : DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, LE, CmpGEImpl(rhs, lhs))
     259             : DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, GT, CmpLTImpl(rhs, lhs))
     260             : DEFINE_SIGNED_MISMATCH_COMP(is_unsigned_vs_signed, GE, CmpLEImpl(rhs, lhs))
     261             : #undef MAKE_UNSIGNED
     262             : #undef DEFINE_SIGNED_MISMATCH_COMP
     263             : 
     264             : // Helper functions for CHECK_OP macro.
     265             : // The (float, float) and (double, double) instantiations are explicitly
     266             : // externalized to ensure proper 32/64-bit comparisons on x86.
     267             : // The Cmp##NAME##Impl function is only instantiable if one of the two types is
     268             : // not integral or their signedness matches (i.e. whenever no specialization is
     269             : // required, see above). Otherwise it is disabled by the enable_if construct,
     270             : // and the compiler will pick a specialization from above.
     271             : #define DEFINE_CHECK_OP_IMPL(NAME, op)                                         \
     272             :   template <typename Lhs, typename Rhs>                                        \
     273             :   V8_INLINE                                                                    \
     274             :       typename std::enable_if<!is_signed_vs_unsigned<Lhs, Rhs>::value &&       \
     275             :                                   !is_unsigned_vs_signed<Lhs, Rhs>::value,     \
     276             :                               bool>::type Cmp##NAME##Impl(Lhs lhs, Rhs rhs) {  \
     277             :     return lhs op rhs;                                                         \
     278             :   }                                                                            \
     279             :   template <typename Lhs, typename Rhs>                                        \
     280             :   V8_INLINE std::string* Check##NAME##Impl(Lhs lhs, Rhs rhs,                   \
     281             :                                            char const* msg) {                  \
     282             :     using LhsPassT = typename pass_value_or_ref<Lhs>::type;                    \
     283             :     using RhsPassT = typename pass_value_or_ref<Rhs>::type;                    \
     284             :     bool cmp = Cmp##NAME##Impl<LhsPassT, RhsPassT>(lhs, rhs);                  \
     285             :     return V8_LIKELY(cmp)                                                      \
     286             :                ? nullptr                                                       \
     287             :                : MakeCheckOpString<LhsPassT, RhsPassT>(lhs, rhs, msg);         \
     288             :   }                                                                            \
     289             :   extern template V8_BASE_EXPORT std::string* Check##NAME##Impl<float, float>( \
     290             :       float lhs, float rhs, char const* msg);                                  \
     291             :   extern template V8_BASE_EXPORT std::string*                                  \
     292             :       Check##NAME##Impl<double, double>(double lhs, double rhs,                \
     293             :                                         char const* msg);
     294   380916492 : DEFINE_CHECK_OP_IMPL(EQ, ==)
     295      221827 : DEFINE_CHECK_OP_IMPL(NE, !=)
     296     3137041 : DEFINE_CHECK_OP_IMPL(LE, <=)
     297       57170 : DEFINE_CHECK_OP_IMPL(LT, < )
     298          10 : DEFINE_CHECK_OP_IMPL(GE, >=)
     299          18 : DEFINE_CHECK_OP_IMPL(GT, > )
     300             : #undef DEFINE_CHECK_OP_IMPL
     301             : 
     302             : #define CHECK_EQ(lhs, rhs) CHECK_OP(EQ, ==, lhs, rhs)
     303             : #define CHECK_NE(lhs, rhs) CHECK_OP(NE, !=, lhs, rhs)
     304             : #define CHECK_LE(lhs, rhs) CHECK_OP(LE, <=, lhs, rhs)
     305             : #define CHECK_LT(lhs, rhs) CHECK_OP(LT, <, lhs, rhs)
     306             : #define CHECK_GE(lhs, rhs) CHECK_OP(GE, >=, lhs, rhs)
     307             : #define CHECK_GT(lhs, rhs) CHECK_OP(GT, >, lhs, rhs)
     308             : #define CHECK_NULL(val) CHECK((val) == nullptr)
     309             : #define CHECK_NOT_NULL(val) CHECK((val) != nullptr)
     310             : #define CHECK_IMPLIES(lhs, rhs) \
     311             :   CHECK_WITH_MSG(!(lhs) || (rhs), #lhs " implies " #rhs)
     312             : 
     313             : }  // namespace base
     314             : }  // namespace v8
     315             : 
     316             : 
     317             : // The DCHECK macro is equivalent to CHECK except that it only
     318             : // generates code in debug builds.
     319             : #ifdef DEBUG
     320             : #define DCHECK_EQ(lhs, rhs) DCHECK_OP(EQ, ==, lhs, rhs)
     321             : #define DCHECK_NE(lhs, rhs) DCHECK_OP(NE, !=, lhs, rhs)
     322             : #define DCHECK_GT(lhs, rhs) DCHECK_OP(GT, >, lhs, rhs)
     323             : #define DCHECK_GE(lhs, rhs) DCHECK_OP(GE, >=, lhs, rhs)
     324             : #define DCHECK_LT(lhs, rhs) DCHECK_OP(LT, <, lhs, rhs)
     325             : #define DCHECK_LE(lhs, rhs) DCHECK_OP(LE, <=, lhs, rhs)
     326             : #define DCHECK_NULL(val) DCHECK((val) == nullptr)
     327             : #define DCHECK_NOT_NULL(val) DCHECK((val) != nullptr)
     328             : #define DCHECK_IMPLIES(lhs, rhs) \
     329             :   DCHECK_WITH_MSG(!(lhs) || (rhs), #lhs " implies " #rhs)
     330             : #else
     331             : #define DCHECK(condition)      ((void) 0)
     332             : #define DCHECK_EQ(v1, v2)      ((void) 0)
     333             : #define DCHECK_NE(v1, v2)      ((void) 0)
     334             : #define DCHECK_GT(v1, v2)      ((void) 0)
     335             : #define DCHECK_GE(v1, v2)      ((void) 0)
     336             : #define DCHECK_LT(v1, v2)      ((void) 0)
     337             : #define DCHECK_LE(v1, v2)      ((void) 0)
     338             : #define DCHECK_NULL(val)       ((void) 0)
     339             : #define DCHECK_NOT_NULL(val)   ((void) 0)
     340             : #define DCHECK_IMPLIES(v1, v2) ((void) 0)
     341             : #endif
     342             : 
     343             : #endif  // V8_BASE_LOGGING_H_

Generated by: LCOV version 1.10