97a8c4caff
Previously if one marker marked the weak property and another marker marked its key then the first marker might stop marking before it sees that the key was marked.
Here is a possible concurrent execution, assuming P is a WeakProperty and K is P.key:
(Marker A) (Marker B)
| |
[ mark property P ] |
| |
[ drain marking stack ] |
[ no more work to do ] |
| [ mark K ]
| [ draing marking stack ]
| [ no more work to do ]
| |
| |
... ...
| |
[Finalize] [Finalize]
|
[Clear P]
In this execution we end up clearing P even though P.key is marked.
To fix this issue without reintroducing central WeakProperty processing
we change the marking phase loop in such a way that markers consider the
marking done only if all of them agree that they have no more weak properties
with marked keys.
Essentially the marking loop now has a separate phase where all markers check
their pending weak properties. The decision to proceed to the next marking phase
(weak handles processing) is done in lock step using barrier - either all threads
advance to the next stage or one of the threads finds a weak property
with marked key and unmarked value and all threads resume marking.
BUG=
R=asiva@google.com
Review URL: https://codereview.chromium.org/2041413005 .
372 lines
12 KiB
C++
372 lines
12 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef PLATFORM_ASSERT_H_
|
|
#define PLATFORM_ASSERT_H_
|
|
|
|
// TODO(5411406): include sstream for now, once we have a Utils::toString()
|
|
// implemented for all the primitive types we can replace the usage of
|
|
// sstream by Utils::toString()
|
|
#if defined(TESTING)
|
|
#include <sstream>
|
|
#include <string>
|
|
#endif
|
|
|
|
#include "platform/globals.h"
|
|
|
|
#if !defined(DEBUG) && !defined(NDEBUG)
|
|
#error neither DEBUG nor NDEBUG defined
|
|
#elif defined(DEBUG) && defined(NDEBUG)
|
|
#error both DEBUG and NDEBUG defined
|
|
#endif
|
|
|
|
namespace dart {
|
|
|
|
class DynamicAssertionHelper {
|
|
public:
|
|
enum Kind {
|
|
ASSERT,
|
|
EXPECT
|
|
};
|
|
|
|
DynamicAssertionHelper(const char* file, int line, Kind kind)
|
|
: file_(file), line_(line), kind_(kind) { }
|
|
|
|
void Fail(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
|
|
|
|
#if defined(TESTING)
|
|
template<typename E, typename A>
|
|
void Equals(const E& expected, const A& actual);
|
|
|
|
template<typename E, typename A>
|
|
void NotEquals(const E& not_expected, const A& actual);
|
|
|
|
template<typename E, typename A, typename T>
|
|
void FloatEquals(const E& expected, const A& actual, const T& tol);
|
|
|
|
template<typename E, typename A>
|
|
void StringEquals(const E& expected, const A& actual);
|
|
|
|
template<typename E, typename A>
|
|
void IsSubstring(const E& needle, const A& haystack);
|
|
|
|
template<typename E, typename A>
|
|
void IsNotSubstring(const E& needle, const A& haystack);
|
|
|
|
template<typename E, typename A>
|
|
void LessThan(const E& left, const A& right);
|
|
|
|
template<typename E, typename A>
|
|
void LessEqual(const E& left, const A& right);
|
|
|
|
template<typename E, typename A>
|
|
void GreaterThan(const E& left, const A& right);
|
|
|
|
template<typename E, typename A>
|
|
void GreaterEqual(const E& left, const A& right);
|
|
#endif
|
|
|
|
template<typename T>
|
|
T NotNull(const T p);
|
|
|
|
private:
|
|
const char* const file_;
|
|
const int line_;
|
|
const Kind kind_;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicAssertionHelper);
|
|
};
|
|
|
|
|
|
class Assert: public DynamicAssertionHelper {
|
|
public:
|
|
Assert(const char* file, int line)
|
|
: DynamicAssertionHelper(file, line, ASSERT) { }
|
|
};
|
|
|
|
|
|
class Expect: public DynamicAssertionHelper {
|
|
public:
|
|
Expect(const char* file, int line)
|
|
: DynamicAssertionHelper(file, line, EXPECT) { }
|
|
};
|
|
|
|
|
|
#if defined(TESTING)
|
|
// Only allow the expensive (with respect to code size) assertions
|
|
// in testing code.
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::Equals(const E& expected, const A& actual) {
|
|
if (actual == expected) return;
|
|
std::ostringstream ess, ass;
|
|
ess << expected;
|
|
ass << actual;
|
|
std::string es = ess.str(), as = ass.str();
|
|
Fail("expected: <%s> but was: <%s>", es.c_str(), as.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::NotEquals(const E& not_expected,
|
|
const A& actual) {
|
|
if (actual != not_expected) return;
|
|
std::ostringstream ness;
|
|
ness << not_expected;
|
|
std::string nes = ness.str();
|
|
Fail("did not expect: <%s>", nes.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A, typename T>
|
|
void DynamicAssertionHelper::FloatEquals(const E& expected,
|
|
const A& actual,
|
|
const T& tol) {
|
|
if (((expected - tol) <= actual) && (actual <= (expected + tol))) {
|
|
return;
|
|
}
|
|
std::ostringstream ess, ass, tolss;
|
|
ess << expected;
|
|
ass << actual;
|
|
tolss << tol;
|
|
std::string es = ess.str(), as = ass.str(), tols = tolss.str();
|
|
Fail("expected: <%s> but was: <%s> (tolerance: <%s>)",
|
|
es.c_str(),
|
|
as.c_str(),
|
|
tols.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::StringEquals(const E& expected, const A& actual) {
|
|
std::ostringstream ess, ass;
|
|
ess << expected;
|
|
ass << actual;
|
|
std::string es = ess.str(), as = ass.str();
|
|
if (as == es) return;
|
|
Fail("expected:\n<\"%s\">\nbut was:\n<\"%s\">", es.c_str(), as.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::IsSubstring(const E& needle, const A& haystack) {
|
|
std::ostringstream ess, ass;
|
|
ess << needle;
|
|
ass << haystack;
|
|
std::string es = ess.str(), as = ass.str();
|
|
if (as.find(es) != std::string::npos) return;
|
|
Fail("expected <\"%s\"> to be a substring of <\"%s\">",
|
|
es.c_str(), as.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::IsNotSubstring(const E& needle,
|
|
const A& haystack) {
|
|
std::ostringstream ess, ass;
|
|
ess << needle;
|
|
ass << haystack;
|
|
std::string es = ess.str(), as = ass.str();
|
|
if (as.find(es) == std::string::npos) return;
|
|
Fail("expected <\"%s\"> to not be a substring of <\"%s\">",
|
|
es.c_str(), as.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::LessThan(const E& left, const A& right) {
|
|
if (left < right) return;
|
|
std::ostringstream ess, ass;
|
|
ess << left;
|
|
ass << right;
|
|
std::string es = ess.str(), as = ass.str();
|
|
Fail("expected: %s < %s", es.c_str(), as.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::LessEqual(const E& left, const A& right) {
|
|
if (left <= right) return;
|
|
std::ostringstream ess, ass;
|
|
ess << left;
|
|
ass << right;
|
|
std::string es = ess.str(), as = ass.str();
|
|
Fail("expected: %s <= %s", es.c_str(), as.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::GreaterThan(const E& left, const A& right) {
|
|
if (left > right) return;
|
|
std::ostringstream ess, ass;
|
|
ess << left;
|
|
ass << right;
|
|
std::string es = ess.str(), as = ass.str();
|
|
Fail("expected: %s > %s", es.c_str(), as.c_str());
|
|
}
|
|
|
|
|
|
template<typename E, typename A>
|
|
void DynamicAssertionHelper::GreaterEqual(const E& left, const A& right) {
|
|
if (left >= right) return;
|
|
std::ostringstream ess, ass;
|
|
ess << left;
|
|
ass << right;
|
|
std::string es = ess.str(), as = ass.str();
|
|
Fail("expected: %s >= %s", es.c_str(), as.c_str());
|
|
}
|
|
#endif
|
|
|
|
|
|
template<typename T>
|
|
T DynamicAssertionHelper::NotNull(const T p) {
|
|
if (p != NULL) return p;
|
|
Fail("expected: not NULL, found NULL");
|
|
return NULL;
|
|
}
|
|
|
|
} // namespace dart
|
|
|
|
|
|
#define FATAL(error) \
|
|
dart::Assert(__FILE__, __LINE__).Fail("%s", error)
|
|
|
|
#define FATAL1(format, p1) \
|
|
dart::Assert(__FILE__, __LINE__).Fail(format, (p1))
|
|
|
|
#define FATAL2(format, p1, p2) \
|
|
dart::Assert(__FILE__, __LINE__).Fail(format, (p1), (p2))
|
|
|
|
#define FATAL3(format, p1, p2, p3) \
|
|
dart::Assert(__FILE__, __LINE__).Fail(format, (p1), (p2), (p3))
|
|
|
|
#define UNIMPLEMENTED() \
|
|
FATAL("unimplemented code")
|
|
|
|
#define UNREACHABLE() \
|
|
FATAL("unreachable code")
|
|
|
|
|
|
#if defined(DEBUG)
|
|
// DEBUG binaries use assertions in the code.
|
|
// Note: We wrap the if statement in a do-while so that we get a compile
|
|
// error if there is no semicolon after ASSERT(condition). This
|
|
// ensures that we get the same behavior on DEBUG and RELEASE builds.
|
|
|
|
#define ASSERT(cond) \
|
|
do { \
|
|
if (!(cond)) dart::Assert(__FILE__, __LINE__).Fail("expected: %s", #cond); \
|
|
} while (false)
|
|
|
|
// DEBUG_ASSERT allows identifiers in condition to be undeclared in release
|
|
// mode.
|
|
#define DEBUG_ASSERT(cond) ASSERT(cond)
|
|
|
|
// Returns 'ptr'; useful for initializer lists:
|
|
// class Foo { Foo(int* ptr) : ptr_(ASSERT_NOTNULL(ptr)) ...
|
|
#define ASSERT_NOTNULL(ptr) \
|
|
dart::Assert(__FILE__, __LINE__).NotNull((ptr))
|
|
|
|
#else // if defined(DEBUG)
|
|
|
|
// In order to avoid variable unused warnings for code that only uses
|
|
// a variable in an ASSERT or EXPECT, we make sure to use the macro
|
|
// argument.
|
|
#define ASSERT(condition) do {} while (false && (condition))
|
|
|
|
#define DEBUG_ASSERT(cond)
|
|
|
|
#define ASSERT_NOTNULL(ptr) (ptr)
|
|
|
|
#endif // if defined(DEBUG)
|
|
|
|
|
|
#define RELEASE_ASSERT(cond) \
|
|
do { \
|
|
if (!(cond)) dart::Assert(__FILE__, __LINE__).Fail("expected: %s", #cond); \
|
|
} while (false)
|
|
|
|
|
|
// The COMPILE_ASSERT macro can be used to verify that a compile time
|
|
// expression is true. For example, you could use it to verify the
|
|
// size of a static array:
|
|
//
|
|
// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES);
|
|
//
|
|
// or to make sure a struct is smaller than a certain size:
|
|
//
|
|
// COMPILE_ASSERT(sizeof(foo) < 128);
|
|
//
|
|
|
|
template <bool>
|
|
struct CompileAssert {
|
|
};
|
|
// Macro to concatenate two tokens. The helper is need to proper expansion
|
|
// in case an argument is a macro itself.
|
|
#if !defined(COMPILE_ASSERT)
|
|
#define COMPILE_ASSERT_JOIN(a, b) COMPILE_ASSERT_JOIN_HELPER(a, b)
|
|
#define COMPILE_ASSERT_JOIN_HELPER(a, b) a##b
|
|
#define COMPILE_ASSERT(expr) \
|
|
DART_UNUSED typedef CompileAssert<(static_cast<bool>(expr))> \
|
|
COMPILE_ASSERT_JOIN(CompileAssertTypeDef, __LINE__)[static_cast<bool>(expr) \
|
|
? 1 : -1]
|
|
#endif // !defined(COMPILE_ASSERT)
|
|
|
|
#if defined(TESTING)
|
|
|
|
// EXPECT and FAIL are equivalent to ASSERT and FATAL except that they do not
|
|
// cause early termination of the unit test. This allows testing to proceed
|
|
// further to be able to report other failures before reporting the overall
|
|
// unit tests as failing.
|
|
|
|
#define EXPECT(condition) \
|
|
if (!(condition)) { \
|
|
dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition); \
|
|
}
|
|
|
|
#define EXPECT_EQ(expected, actual) \
|
|
dart::Expect(__FILE__, __LINE__).Equals((expected), (actual))
|
|
|
|
#define EXPECT_NE(not_expected, actual) \
|
|
dart::Expect(__FILE__, __LINE__).NotEquals((not_expected), (actual))
|
|
|
|
#define EXPECT_FLOAT_EQ(expected, actual, tol) \
|
|
dart::Expect(__FILE__, __LINE__).FloatEquals((expected), (actual), (tol))
|
|
|
|
#define EXPECT_STREQ(expected, actual) \
|
|
dart::Expect(__FILE__, __LINE__).StringEquals((expected), (actual))
|
|
|
|
#define EXPECT_SUBSTRING(needle, haystack) \
|
|
dart::Expect(__FILE__, __LINE__).IsSubstring((needle), (haystack))
|
|
|
|
#define EXPECT_NOTSUBSTRING(needle, haystack) \
|
|
dart::Expect(__FILE__, __LINE__).IsNotSubstring((needle), (haystack))
|
|
|
|
#define EXPECT_LT(left, right) \
|
|
dart::Expect(__FILE__, __LINE__).LessThan((left), (right))
|
|
|
|
#define EXPECT_LE(left, right) \
|
|
dart::Expect(__FILE__, __LINE__).LessEqual((left), (right))
|
|
|
|
#define EXPECT_GT(left, right) \
|
|
dart::Expect(__FILE__, __LINE__).GreaterThan((left), (right))
|
|
|
|
#define EXPECT_GE(left, right) \
|
|
dart::Expect(__FILE__, __LINE__).GreaterEqual((left), (right))
|
|
|
|
#define EXPECT_NOTNULL(ptr) \
|
|
dart::Expect(__FILE__, __LINE__).NotNull((ptr))
|
|
|
|
#define FAIL(error) \
|
|
dart::Expect(__FILE__, __LINE__).Fail("%s", error)
|
|
|
|
#define FAIL1(format, p1) \
|
|
dart::Expect(__FILE__, __LINE__).Fail(format, (p1))
|
|
|
|
#define FAIL2(format, p1, p2) \
|
|
dart::Expect(__FILE__, __LINE__).Fail(format, (p1), (p2))
|
|
|
|
#endif // defined(TESTING)
|
|
|
|
#endif // PLATFORM_ASSERT_H_
|