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

Generated by: LCOV version 1.10