Index: third_party/WebKit/Source/wtf/StdLibExtras.h |
diff --git a/third_party/WebKit/Source/wtf/StdLibExtras.h b/third_party/WebKit/Source/wtf/StdLibExtras.h |
index 26ba1d8d02958298aacfc73daea5743ccbbce201..9c2d45744f754091bead5ea4c82687101c395c93 100644 |
--- a/third_party/WebKit/Source/wtf/StdLibExtras.h |
+++ b/third_party/WebKit/Source/wtf/StdLibExtras.h |
@@ -26,26 +26,141 @@ |
#ifndef WTF_StdLibExtras_h |
#define WTF_StdLibExtras_h |
+#include <cstddef> |
#include "base/numerics/safe_conversions.h" |
#include "wtf/Assertions.h" |
#include "wtf/CPU.h" |
#include "wtf/LeakAnnotations.h" |
+#include "wtf/Noncopyable.h" |
#include "wtf/TypeTraits.h" |
-#include <cstddef> |
#if DCHECK_IS_ON() |
-#include "wtf/Noncopyable.h" |
#include "wtf/Threading.h" |
+#endif |
+ |
+// Use |DEFINE_STATIC_LOCAL()| to declare and define a static local variable |
+// (|static T;|) so that it is leaked and its destructors are not called at |
+// exit. T may also be a Blink garbage collected object, in which case it is |
+// wrapped up by an off-heap |Persistent<T>| reference to the object, keeping |
+// it alive across GCs. |
+// |
+// |DEFINE_STATIC_LOCAL()| takes an optional fourth argument of type |
+// |CheckScriptWrappable|. Rarely needed, but the argument serves to |
+// selectively disable verification |DCHECK()|s that the declared |
+// singleton doesn't contain any embedded |ScriptWrappable| instances. |
+// Having singletons retain such objects risks leaking v8 wrapper objects |
+// across contexts in a renderer process, which must not happen. |
+// However, if the singleton definition and use can be shown not to |
+// leak its |ScriptWrappable|s, the check can be disabled by supplying |
+// |CheckScriptWrappable::No| as a fourth argument. Its use isn't |
+// encouraged, so please consider alternatives to declaring a singleton. |
+// |
+#define DEFINE_STATIC_LOCAL(Type, Name, Arguments, ...) \ |
+ static WTF::StaticSingleton<Type, ##__VA_ARGS__> s_##Name( \ |
+ (WTF::StaticSingleton<Type, ##__VA_ARGS__>::enterScope(), \ |
+ new WTF::StaticSingleton<Type, ##__VA_ARGS__>::WrapperType Arguments)); \ |
+ Type& Name = s_##Name.get() |
+ |
+namespace blink { |
+template <typename T> |
+class Persistent; |
+class ScriptWrappable; |
+ |
+} // namespace blink |
+ |
+namespace WTF { |
+ |
+enum class CheckScriptWrappable { |
+ No, |
+ Yes, |
+}; |
-class WTF_EXPORT StaticLocalVerifier { |
- WTF_MAKE_NONCOPYABLE(StaticLocalVerifier); |
+template <typename Type, |
+ CheckScriptWrappable checkScriptWrappable = CheckScriptWrappable::Yes> |
+class StaticSingleton final { |
+ WTF_MAKE_NONCOPYABLE(StaticSingleton); |
public: |
- StaticLocalVerifier() |
- : m_safelyInitialized(WTF::isBeforeThreadCreated()), |
- m_thread(WTF::internal::currentThreadSyscall()) {} |
+ template <typename T, |
+ bool = WTF::IsGarbageCollectedType<T>::value && |
+ !WTF::IsPersistentReferenceType<T>::value> |
+ struct Wrapper { |
+ using type = T; |
+ |
+ static T& unwrap(T* singleton) { return *singleton; } |
+ }; |
+ |
+ template <typename T> |
+ struct Wrapper<T, true> { |
+ using type = blink::Persistent<T>; |
+ |
+ static T& unwrap(blink::Persistent<T>* singleton) { |
+ DCHECK(singleton); |
+ // If this assert triggers, you're supplying an empty ("()") 'Arguments' |
+ // argument to DEFINE_STATIC_LOCAL() - it must be the heap object you wish |
+ // to create as a static singleton and wrapped up with a Persistent |
+ // reference. |
+ DCHECK(*singleton); |
+ return **singleton; |
+ } |
+ }; |
+ |
+ using WrapperType = typename Wrapper<Type>::type; |
+ |
+ static_assert( |
+ !WTF::IsPersistentReferenceType<WrapperType>::value || |
+ !WTF::IsSubclass< |
+ typename WTF::RemoveTemplate<WrapperType, |
+ blink::Persistent>::type, |
+ blink::ScriptWrappable>::value, |
+ "It is unsafe to keep a static singleton to a ScriptWrappable-derived " |
+ "object"); |
+ |
+ // To cooperate with leak detection(LSan) for Blink garbage collected objects, |
+ // the objects owned by persistent local statics will in some cases have to be |
+ // finalized prior to leak checking. This only applies to static references to |
+ // Blink heap objects and what they transitively hold on to. Hence the |
+ // LEAK_SANITIZER_REGISTER_STATIC_LOCAL() use, it taking care of the grungy |
+ // details. |
+ |
+ explicit StaticSingleton(WrapperType* instance) |
+ : m_instance(LEAK_SANITIZER_REGISTER_STATIC_LOCAL(WrapperType, instance)) |
+#if DCHECK_IS_ON() |
+ , |
+ m_safelyInitialized(WTF::isBeforeThreadCreated()), |
+ m_thread(WTF::internal::currentThreadSyscall()) |
+#endif |
+ { |
+ leaveScope(); |
+ } |
+ |
+ Type& get() const { |
+#if DCHECK_IS_ON() |
+ DCHECK(isNotRacy()); |
+#endif |
+ return Wrapper<Type>::unwrap(m_instance); |
+ } |
+ |
+ operator Type&() { return get(); } |
+ |
+ static void enterScope() { |
+#if DCHECK_IS_ON() |
+ if (checkScriptWrappable == CheckScriptWrappable::Yes) |
+ NoScriptWrappableScope<WrapperType>::enter(); |
+#endif |
+ } |
+ |
+ static void leaveScope() { |
+#if DCHECK_IS_ON() |
+ if (checkScriptWrappable == CheckScriptWrappable::Yes) |
+ NoScriptWrappableScope<WrapperType>::leave(); |
+#endif |
+ } |
+ |
+ private: |
+#if DCHECK_IS_ON() |
- bool isNotRacy() { |
+ bool isNotRacy() const { |
// Make sure that this 1) is safely initialized, 2) keeps being called |
// on the same thread, or 3) is called within |
// AtomicallyInitializedStatic (i.e. with a lock held). |
@@ -54,71 +169,29 @@ class WTF_EXPORT StaticLocalVerifier { |
WTF::isAtomicallyInitializedStaticMutexLockHeld(); |
} |
- private: |
+ template <typename T, bool = WTF::IsPersistentReferenceType<T>::value> |
+ struct NoScriptWrappableScope { |
+ static void enter() {} |
+ static void leave() {} |
+ }; |
+ |
+ template <typename T> |
+ struct NoScriptWrappableScope<T, true> { |
+ static void enter() { T::enterNoScriptWrappableScope(); } |
+ static void leave() { T::leaveNoScriptWrappableScope(); } |
+ }; |
+#endif |
+ WrapperType* m_instance; |
+ |
+#if DCHECK_IS_ON() |
bool m_safelyInitialized; |
ThreadIdentifier m_thread; |
-}; |
#endif |
- |
-namespace blink { |
-template <typename T> |
-class Persistent; |
-}; |
- |
-template <typename T, |
- bool = WTF::IsGarbageCollectedType<T>::value && |
- !WTF::IsPersistentReferenceType<T>::value> |
-class StaticLocalWrapper { |
- public: |
- using WrapType = T; |
- |
- static T& unwrap(T* singleton) { return *singleton; } |
}; |
-template <typename T> |
-class StaticLocalWrapper<T, true> { |
- public: |
- using WrapType = blink::Persistent<T>; |
- |
- static T& unwrap(blink::Persistent<T>* singleton) { |
- DCHECK(singleton); |
- // If this assert triggers, you're supplying an empty ("()") 'Arguments' |
- // argument to DEFINE_STATIC_LOCAL() - it must be the heap object you wish |
- // to create as a static singleton and wrapped up with a Persistent |
- // reference. |
- DCHECK(*singleton); |
- return **singleton; |
- } |
-}; |
- |
-#if DCHECK_IS_ON() |
-#define DEFINE_STATIC_LOCAL_CHECK_THREADSAFE_ACCESS(Name) \ |
- static StaticLocalVerifier Name##StaticLocalVerifier; \ |
- DCHECK(Name##StaticLocalVerifier.isNotRacy()) |
-#else |
-#define DEFINE_STATIC_LOCAL_CHECK_THREADSAFE_ACCESS(Name) |
-#endif |
+} // namespace WTF |
-// Use DEFINE_STATIC_LOCAL() to declare and define a static local variable |
-// (static T;) so that it is leaked and its destructors are not called at exit. |
-// T may also be a Blink garbage collected object, in which case it is |
-// wrapped up by an off-heap Persistent<T> reference to the object, keeping |
-// it alive across GCs. |
-// |
-// To cooperate with leak detection(LSan) for Blink garbage collected objects, |
-// the objects owned by persistent local statics will in some cases have to be |
-// finalized prior to leak checking. This only applies to static references to |
-// Blink heap objects and what they transitively hold on to. Hence the |
-// LEAK_SANITIZER_REGISTER_STATIC_LOCAL() use, it taking care of the grungy |
-// details. |
-// |
-#define DEFINE_STATIC_LOCAL(Type, Name, Arguments) \ |
- DEFINE_STATIC_LOCAL_CHECK_THREADSAFE_ACCESS(Name); \ |
- using WrappedTypeFor##Name = StaticLocalWrapper<Type>::WrapType; \ |
- static WrappedTypeFor##Name* WrappedInstanceFor##Name = \ |
- LEAK_SANITIZER_REGISTER_STATIC_LOCAL( \ |
- WrappedTypeFor##Name, new WrappedTypeFor##Name Arguments); \ |
- Type& Name = StaticLocalWrapper<Type>::unwrap(WrappedInstanceFor##Name); |
+using WTF::CheckScriptWrappable; |
// Use this to declare and define a static local pointer to a ref-counted object |
// so that it is leaked so that the object's destructors are not called at |