diff --git a/BUILD.gn b/BUILD.gn index 9a182277d6..f5c2382c3f 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -3979,6 +3979,7 @@ v8_source_set("cppgc_base") { "src/heap/cppgc/heap.cc", "src/heap/cppgc/heap.h", "src/heap/cppgc/liveness-broker.cc", + "src/heap/cppgc/logging.cc", "src/heap/cppgc/page-memory-inl.h", "src/heap/cppgc/page-memory.cc", "src/heap/cppgc/page-memory.h", diff --git a/include/cppgc/internal/logging.h b/include/cppgc/internal/logging.h new file mode 100644 index 0000000000..fc2d4e4505 --- /dev/null +++ b/include/cppgc/internal/logging.h @@ -0,0 +1,50 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef INCLUDE_CPPGC_INTERNAL_LOGGING_H_ +#define INCLUDE_CPPGC_INTERNAL_LOGGING_H_ + +#include "include/cppgc/source-location.h" +#include "include/v8config.h" + +namespace cppgc { +namespace internal { + +void V8_EXPORT DCheckImpl(const char*, + const SourceLocation& = SourceLocation::Current()); +[[noreturn]] void V8_EXPORT +FatalImpl(const char*, const SourceLocation& = SourceLocation::Current()); + +// Used to ignore -Wunused-variable. +template +struct EatParams {}; + +#if DEBUG +#define CPPGC_DCHECK_MSG(condition, message) \ + do { \ + if (V8_UNLIKELY(!(condition))) { \ + ::cppgc::internal::DCheckImpl(message); \ + } \ + } while (false) +#else +#define CPPGC_DCHECK_MSG(condition, message) \ + (static_cast(::cppgc::internal::EatParams(condition), message)>{})) +#endif + +#define CPPGC_DCHECK(condition) CPPGC_DCHECK_MSG(condition, #condition) + +#define CPPGC_CHECK_MSG(condition, message) \ + do { \ + if (V8_UNLIKELY(!(condition))) { \ + ::cppgc::internal::FatalImpl(message); \ + } \ + } while (false) + +#define CPPGC_CHECK(condition) CPPGC_CHECK_MSG(condition, #condition) + +} // namespace internal +} // namespace cppgc + +#endif // INCLUDE_CPPGC_INTERNAL_LOGGING_H_ diff --git a/include/cppgc/visitor.h b/include/cppgc/visitor.h index 9c23c59bf5..5555627c57 100644 --- a/include/cppgc/visitor.h +++ b/include/cppgc/visitor.h @@ -6,6 +6,7 @@ #define INCLUDE_CPPGC_VISITOR_H_ #include "include/cppgc/garbage-collected.h" +#include "include/cppgc/internal/logging.h" #include "include/cppgc/internal/pointer-policies.h" #include "include/cppgc/liveness-broker.h" #include "include/cppgc/member.h" @@ -29,8 +30,7 @@ class Visitor { template void Trace(const Member& member) { const T* value = member.GetRawAtomic(); - // TODO(chromium:1056170): DCHECK (or similar) for deleted values as they - // should come in at a different path. + CPPGC_DCHECK(value != kSentinelPointer); Trace(value); } diff --git a/src/heap/cppgc/logging.cc b/src/heap/cppgc/logging.cc new file mode 100644 index 0000000000..e98ca28dfb --- /dev/null +++ b/src/heap/cppgc/logging.cc @@ -0,0 +1,29 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "include/cppgc/internal/logging.h" +#include "include/cppgc/source-location.h" + +#include "src/base/logging.h" + +namespace cppgc { +namespace internal { + +void DCheckImpl(const char* message, const SourceLocation& loc) { + V8_Dcheck(loc.FileName(), static_cast(loc.Line()), message); +} + +void FatalImpl(const char* message, const SourceLocation& loc) { +#if DEBUG + V8_Fatal(loc.FileName(), static_cast(loc.Line()), "Check failed: %s.", + message); +#elif !defined(OFFICIAL_BUILD) + V8_Fatal("Check failed: %s.", message); +#else + V8_Fatal("ignored"); +#endif +} + +} // namespace internal +} // namespace cppgc diff --git a/test/unittests/BUILD.gn b/test/unittests/BUILD.gn index f0b2347749..905753cff9 100644 --- a/test/unittests/BUILD.gn +++ b/test/unittests/BUILD.gn @@ -50,6 +50,7 @@ v8_source_set("cppgc_unittests_sources") { "heap/cppgc/heap-object-header_unittest.cc", "heap/cppgc/heap-page_unittest.cc", "heap/cppgc/heap_unittest.cc", + "heap/cppgc/logging_unittest.cc", "heap/cppgc/member_unittests.cc", "heap/cppgc/page-memory_unittest.cc", "heap/cppgc/prefinalizer_unittests.cc", diff --git a/test/unittests/heap/cppgc/logging_unittest.cc b/test/unittests/heap/cppgc/logging_unittest.cc new file mode 100644 index 0000000000..1f66791441 --- /dev/null +++ b/test/unittests/heap/cppgc/logging_unittest.cc @@ -0,0 +1,79 @@ +// Copyright 2020 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "include/cppgc/internal/logging.h" +#include "include/cppgc/source-location.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cppgc { +namespace internal { + +namespace { +// GCC < 9 has a bug due to which calling non-constexpr functions are not +// allowed even on constexpr path: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67026. +#if !defined(__GNUC__) || defined(__clang__) +constexpr int CheckInConstexpr(int a) { + CPPGC_DCHECK(a > 0); + CPPGC_CHECK(a > 0); + return a; +} +#endif +} // namespace + +TEST(LoggingTest, Pass) { + CPPGC_DCHECK(true); + CPPGC_CHECK(true); +} + +TEST(LoggingTest, Fail) { +#if DEBUG + EXPECT_DEATH_IF_SUPPORTED(CPPGC_DCHECK(false), ""); +#endif + EXPECT_DEATH_IF_SUPPORTED(CPPGC_CHECK(false), ""); +} + +TEST(LoggingTest, DontReportUnused) { + int a = 1; + CPPGC_DCHECK(a); +} + +#if !defined(__GNUC__) || defined(__clang__) +TEST(LoggingTest, ConstexprContext) { + constexpr int a = CheckInConstexpr(1); + CPPGC_DCHECK(a); +} +#endif + +#if DEBUG && !defined(OFFICIAL_BUILD) +TEST(LoggingTest, Message) { + using ::testing::ContainsRegex; + EXPECT_DEATH_IF_SUPPORTED(CPPGC_DCHECK(5 == 7), + ContainsRegex("failed.*5 == 7")); + EXPECT_DEATH_IF_SUPPORTED(CPPGC_CHECK(5 == 7), + ContainsRegex("failed.*5 == 7")); +} + +#if CPPGC_SUPPORTS_SOURCE_LOCATION +TEST(LoggingTest, SourceLocation) { + using ::testing::AllOf; + using ::testing::HasSubstr; + constexpr auto loc = SourceLocation::Current(); + EXPECT_DEATH_IF_SUPPORTED(CPPGC_DCHECK(false), + AllOf(HasSubstr(loc.FileName()), + HasSubstr(std::to_string(loc.Line() + 3)))); + EXPECT_DEATH_IF_SUPPORTED(CPPGC_CHECK(false), + AllOf(HasSubstr(loc.FileName()), + HasSubstr(std::to_string(loc.Line() + 6)))); +} +#endif // CPPGC_SUPPORTS_SOURCE_LOCATION + +#endif // DEBUG + +} // namespace internal +} // namespace cppgc