提交 de93d90c 编写于 作者: E Eric Seidel

Remove heap/*.cpp files

Nothing in heap/ is called anymore, but it
still has its claws deep into many of the
base classes for the rest of Sky, so I've left
the (largely unmodified) headers for now.

We'll trim the headers further in later patches.

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/681963002
上级 7639e0fe
......@@ -396,21 +396,9 @@ struct V8ValueTraits<WTF::Vector<T, inlineCapacity, Allocator> > {
}
};
template<typename T, size_t inlineCapacity>
v8::Handle<v8::Value> v8Array(const HeapVector<T, inlineCapacity>& iterator, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size());
int index = 0;
typename HeapVector<T, inlineCapacity>::const_iterator end = iterator.end();
typedef V8ValueTraits<T> TraitsType;
for (typename HeapVector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
result->Set(v8::Integer::New(isolate, index++), TraitsType::toV8Value(*iter, creationContext, isolate));
return result;
}
template <typename T, size_t inlineCapacity>
struct V8ValueTraits<HeapVector<T, inlineCapacity> > {
static v8::Handle<v8::Value> toV8Value(const HeapVector<T, inlineCapacity>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
struct V8ValueTraits<Vector<T, inlineCapacity> > {
static v8::Handle<v8::Value> toV8Value(const Vector<T, inlineCapacity>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
return v8Array(value, creationContext, isolate);
}
......
......@@ -63,7 +63,7 @@ def cpp_type(idl_type):
return 'void'
# Callbacks use raw pointers, so raw_type=True
raw_cpp_type = idl_type.cpp_type_args(raw_type=True)
if raw_cpp_type.startswith(('Vector', 'HeapVector', 'Vector')):
if raw_cpp_type.startswith(('Vector', 'Vector')):
return 'const %s&' % raw_cpp_type
return raw_cpp_type
......
......@@ -35,34 +35,6 @@
namespace blink {
#if ENABLE(OILPAN)
bool CachedMatchedPropertiesHashTraits::traceInCollection(Visitor* visitor, Member<CachedMatchedProperties>& cachedProperties, WTF::ShouldWeakPointersBeMarkedStrongly strongify)
{
// Only honor the cache's weakness semantics if the collection is traced
// with WeakPointersActWeak. Otherwise just trace the cachedProperties
// strongly, ie. call trace on it.
if (cachedProperties && strongify == WTF::WeakPointersActWeak) {
// A given cache entry is only kept alive if none of the MatchedProperties
// in the CachedMatchedProperties value contain a dead "properties" field.
// If there is a dead field the entire cache entry is removed.
HeapVector<MatchedProperties>::iterator it = cachedProperties->matchedProperties.begin();
HeapVector<MatchedProperties>::iterator end = cachedProperties->matchedProperties.end();
for (; it != end; ++it) {
if (!visitor->isAlive(it->properties)) {
// For now report the cache entry as dead. This might not
// be the final result if in a subsequent call for this entry,
// the "properties" field has been marked via another path.
return true;
}
}
}
// At this point none of the entries in the matchedProperties vector
// had a dead "properties" field so trace CachedMatchedProperties strongly.
visitor->trace(cachedProperties);
return false;
}
#endif
void CachedMatchedProperties::set(const RenderStyle* style, const RenderStyle* parentStyle, const MatchResult& matchResult)
{
matchedProperties.appendVector(matchResult.matchedProperties);
......@@ -82,10 +54,8 @@ void CachedMatchedProperties::clear()
}
MatchedPropertiesCache::MatchedPropertiesCache()
#if !ENABLE(OILPAN)
: m_additionsSinceLastSweep(0)
, m_sweepTimer(this, &MatchedPropertiesCache::sweep)
#endif
{
}
......@@ -113,14 +83,12 @@ const CachedMatchedProperties* MatchedPropertiesCache::find(unsigned hash, const
void MatchedPropertiesCache::add(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
{
#if !ENABLE(OILPAN)
static const unsigned maxAdditionsBetweenSweeps = 100;
if (++m_additionsSinceLastSweep >= maxAdditionsBetweenSweeps
&& !m_sweepTimer.isActive()) {
static const unsigned sweepTimeInSeconds = 60;
m_sweepTimer.startOneShot(sweepTimeInSeconds, FROM_HERE);
}
#endif
ASSERT(hash);
Cache::AddResult addResult = m_cache.add(hash, nullptr);
......@@ -150,7 +118,6 @@ void MatchedPropertiesCache::clearViewportDependent()
m_cache.removeAll(toRemove);
}
#if !ENABLE(OILPAN)
void MatchedPropertiesCache::sweep(Timer<MatchedPropertiesCache>*)
{
// FIXME(sky): Do we still need this now that we removed PresentationAttributeStyle?
......@@ -170,7 +137,6 @@ void MatchedPropertiesCache::sweep(Timer<MatchedPropertiesCache>*)
m_cache.removeAll(toRemove);
m_additionsSinceLastSweep = 0;
}
#endif
bool MatchedPropertiesCache::isCacheable(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle)
{
......@@ -193,9 +159,6 @@ bool MatchedPropertiesCache::isCacheable(const Element* element, const RenderSty
void MatchedPropertiesCache::trace(Visitor* visitor)
{
#if ENABLE(OILPAN)
visitor->trace(m_cache);
#endif
}
}
......@@ -49,15 +49,6 @@ public:
void trace(Visitor* visitor) { visitor->trace(matchedProperties); }
};
// Specialize the HashTraits for CachedMatchedProperties to check for dead
// entries in the MatchedPropertiesCache.
#if ENABLE(OILPAN)
struct CachedMatchedPropertiesHashTraits : HashTraits<Member<CachedMatchedProperties> > {
static const WTF::WeakHandlingFlag weakHandlingFlag = WTF::WeakHandlingInCollections;
static bool traceInCollection(Visitor*, Member<CachedMatchedProperties>&, WTF::ShouldWeakPointersBeMarkedStrongly);
};
#endif
class MatchedPropertiesCache {
DISALLOW_ALLOCATION();
WTF_MAKE_NONCOPYABLE(MatchedPropertiesCache);
......@@ -75,9 +66,6 @@ public:
void trace(Visitor*);
private:
#if ENABLE(OILPAN)
typedef HeapHashMap<unsigned, Member<CachedMatchedProperties>, DefaultHash<unsigned>::Hash, HashTraits<unsigned>, CachedMatchedPropertiesHashTraits > Cache;
#else
// Every N additions to the matched declaration cache trigger a sweep where entries holding
// the last reference to a style declaration are garbage collected.
void sweep(Timer<MatchedPropertiesCache>*);
......@@ -86,7 +74,6 @@ private:
typedef HashMap<unsigned, OwnPtr<CachedMatchedProperties> > Cache;
Timer<MatchedPropertiesCache> m_sweepTimer;
#endif
Cache m_cache;
};
......
......@@ -464,11 +464,7 @@ void ImageLoader::addClient(ImageLoaderClient* client)
if (m_image && !m_highPriorityClientCount++)
memoryCache()->updateDecodedResource(m_image.get(), UpdateForPropertyChange, MemoryCacheLiveResourcePriorityHigh);
}
#if ENABLE(OILPAN)
m_clients.add(client, adoptPtr(new ImageLoaderClientRemover(*this, *client)));
#else
m_clients.add(client);
#endif
}
void ImageLoader::willRemoveClient(ImageLoaderClient& client)
......@@ -507,25 +503,11 @@ void ImageLoader::elementDidMoveToNewDocument()
void ImageLoader::sourceImageChanged()
{
#if ENABLE(OILPAN)
PersistentHeapHashMap<WeakMember<ImageLoaderClient>, OwnPtr<ImageLoaderClientRemover> >::iterator end = m_clients.end();
for (PersistentHeapHashMap<WeakMember<ImageLoaderClient>, OwnPtr<ImageLoaderClientRemover> >::iterator it = m_clients.begin(); it != end; ++it) {
it->key->notifyImageSourceChanged();
}
#else
HashSet<ImageLoaderClient*>::iterator end = m_clients.end();
for (HashSet<ImageLoaderClient*>::iterator it = m_clients.begin(); it != end; ++it) {
ImageLoaderClient* handle = *it;
handle->notifyImageSourceChanged();
}
#endif
}
#if ENABLE(OILPAN)
ImageLoader::ImageLoaderClientRemover::~ImageLoaderClientRemover()
{
m_loader.willRemoveClient(m_client);
}
#endif
}
......@@ -144,31 +144,8 @@ private:
RawPtr<Element> m_element;
ResourcePtr<ImageResource> m_image;
// FIXME: Oilpan: We might be able to remove this Persistent hack when
// ImageResourceClient is traceable.
GC_PLUGIN_IGNORE("http://crbug.com/383741")
RefPtr<Element> m_keepAlive;
#if ENABLE(OILPAN)
class ImageLoaderClientRemover {
public:
ImageLoaderClientRemover(ImageLoader& loader, ImageLoaderClient& client) : m_loader(loader), m_client(client) { }
~ImageLoaderClientRemover();
private:
ImageLoader& m_loader;
ImageLoaderClient& m_client;
};
friend class ImageLoaderClientRemover;
// Oilpan: This ImageLoader object must outlive its clients because they
// need to call ImageLoader::willRemoveClient before they
// die. Non-Persistent HeapHashMap doesn't work well because weak processing
// for HeapHashMap is not triggered when both of ImageLoader and
// ImageLoaderClient are unreachable.
GC_PLUGIN_IGNORE("http://crbug.com/383742")
PersistentHeapHashMap<WeakMember<ImageLoaderClient>, OwnPtr<ImageLoaderClientRemover> > m_clients;
#else
HashSet<ImageLoaderClient*> m_clients;
#endif
Timer<ImageLoader> m_derefElementTimer;
AtomicString m_failedLoadURL;
WeakPtr<Task> m_pendingTask; // owned by Microtask
......
......@@ -143,9 +143,6 @@ public:
{
return host ? host->requireSupplement(key) : 0;
}
// FIXME: Oilpan: Remove this callback once PersistentHeapSupplementable is removed again.
virtual void persistentHostHasBeenDestroyed() { }
};
// Helper class for implementing Supplementable, HeapSupplementable, and
......@@ -215,37 +212,6 @@ public:
}
};
// This class is used to make an off-heap class supplementable with supplements
// that are on-heap, aka. HeapSupplements.
template<typename T>
class GC_PLUGIN_IGNORE("http://crbug.com/395036") PersistentHeapSupplementable : public SupplementableBase<T, true> {
public:
PersistentHeapSupplementable() : m_root(this) { }
virtual ~PersistentHeapSupplementable()
{
typedef typename SupplementableTraits<T, true>::SupplementMap::iterator SupplementIterator;
for (SupplementIterator it = this->m_supplements.begin(); it != this->m_supplements.end(); ++it)
it->value->persistentHostHasBeenDestroyed();
}
virtual void trace(Visitor* visitor)
{
visitor->trace(this->m_supplements);
SupplementableBase<T, true>::trace(visitor);
}
private:
class TraceDelegate : PersistentBase<ThreadLocalPersistents<AnyThread>, TraceDelegate> {
public:
TraceDelegate(PersistentHeapSupplementable* owner) : m_owner(owner) { }
void trace(Visitor* visitor) { m_owner->trace(visitor); }
private:
PersistentHeapSupplementable* m_owner;
};
TraceDelegate m_root;
};
template<typename T>
class Supplement : public SupplementBase<T, false> { };
......
......@@ -7,13 +7,8 @@ visibility = ["//sky/engine/*"]
source_set("heap") {
sources = [
"AddressSanitizer.h",
"Handle.cpp",
"Handle.h",
"Heap.cpp",
"Heap.h",
"ThreadState.cpp",
"ThreadState.h",
"Visitor.cpp",
"Visitor.h",
]
......
// Copyright 2014 The Chromium 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 "config.h"
#include "platform/heap/Handle.h"
namespace blink {
}
......@@ -104,21 +104,6 @@ private:
static ThreadState* state() { return ThreadStateFor<Affinity>::state(); }
};
// RootsAccessor for Persistent that provides synchronized access to global
// list of persistent handles. Can be used for persistent handles that are
// passed between threads.
class GlobalPersistents {
public:
static PersistentNode* roots() { return ThreadState::globalRoots(); }
class Lock {
public:
Lock() : m_locker(ThreadState::globalRootsMutex()) { }
private:
MutexLocker m_locker;
};
};
// Base class for persistent handles. RootsAccessor specifies which list to
// link resulting handle into. Owner specifies the class containing trace
// method.
......@@ -158,7 +143,6 @@ protected:
{
// We don't support allocation of thread local Persistents while doing
// thread shutdown/cleanup.
ASSERT(!ThreadState::current()->isTerminating());
typename RootsAccessor::Lock lock;
ASSERT(otherref.m_roots == m_roots); // Handles must belong to the same list.
PersistentBase* other = const_cast<PersistentBase*>(&otherref);
......@@ -212,17 +196,6 @@ private:
friend class ThreadState;
};
#if ENABLE(ASSERT)
// For global persistent handles we cannot check that the
// pointer is in the heap because that would involve
// inspecting the heap of running threads.
#define ASSERT_IS_VALID_PERSISTENT_POINTER(pointer) \
bool isGlobalPersistent = WTF::IsSubclass<RootsAccessor, GlobalPersistents>::value; \
ASSERT(!pointer || isGlobalPersistent || ThreadStateFor<ThreadingTrait<T>::Affinity>::state()->contains(pointer))
#else
#define ASSERT_IS_VALID_PERSISTENT_POINTER(pointer)
#endif
template<typename T>
class CrossThreadPersistent;
......@@ -251,13 +224,11 @@ public:
Persistent(T* raw) : m_raw(raw)
{
ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw);
recordBacktrace();
}
explicit Persistent(T& raw) : m_raw(&raw)
{
ASSERT_IS_VALID_PERSISTENT_POINTER(m_raw);
recordBacktrace();
}
......@@ -373,18 +344,6 @@ private:
friend class CrossThreadPersistent<T>;
};
// Unlike Persistent, we can destruct a CrossThreadPersistent in a thread
// different from the construction thread.
template<typename T>
class CrossThreadPersistent : public Persistent<T, GlobalPersistents> {
WTF_DISALLOW_CONSTRUCTION_FROM_ZERO(CrossThreadPersistent);
WTF_DISALLOW_ZERO_ASSIGNMENT(CrossThreadPersistent);
public:
CrossThreadPersistent(T* raw) : Persistent<T, GlobalPersistents>(raw) { }
using Persistent<T, GlobalPersistents>::operator=;
};
// FIXME: derive affinity based on the collection.
template<typename Collection, ThreadAffinity Affinity = AnyThread>
class PersistentHeapCollectionBase
......
此差异已折叠。
......@@ -1527,12 +1527,8 @@ Address ThreadHeap<Header>::allocate(size_t size, const GCInfo* gcInfo)
template<typename T, typename HeapTraits>
Address Heap::allocate(size_t size)
{
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
ASSERT(state->isAllocationAllowed());
const GCInfo* gcInfo = GCInfoTrait<T>::get();
int heapIndex = HeapTraits::index(gcInfo->hasFinalizer());
BaseHeap* heap = state->heap(heapIndex);
return static_cast<typename HeapTraits::HeapType*>(heap)->allocate(size, gcInfo);
ASSERT_NOT_REACHED();
return 0;
}
template<typename T>
......@@ -1619,7 +1615,8 @@ public:
static bool isAllocationAllowed()
{
return ThreadState::current()->isAllocationAllowed();
ASSERT_NOT_REACHED();
return false;
}
static void markUsingGCInfo(Visitor* visitor, const void* buffer)
......
/*
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HeapLinkedStack_h
#define HeapLinkedStack_h
#include "platform/heap/Heap.h"
#include "platform/heap/Visitor.h"
namespace blink {
template <typename T>
class HeapLinkedStack : public GarbageCollected<HeapLinkedStack<T> > {
public:
HeapLinkedStack() : m_size(0) { }
bool isEmpty();
void push(const T&);
const T& peek();
void pop();
size_t size();
void trace(Visitor* visitor)
{
for (Node* current = m_head; current; current = current->m_next)
visitor->trace(current);
}
private:
class Node : public GarbageCollected<Node> {
public:
Node(const T&, Node* next);
void trace(Visitor* visitor) { visitor->trace(m_data); }
T m_data;
Member<Node> m_next;
};
Member<Node> m_head;
size_t m_size;
};
template <typename T>
HeapLinkedStack<T>::Node::Node(const T& data, Node* next)
: m_data(data)
, m_next(next)
{
}
template <typename T>
inline bool HeapLinkedStack<T>::isEmpty()
{
return !m_head;
}
template <typename T>
inline void HeapLinkedStack<T>::push(const T& data)
{
m_head = new Node(data, m_head);
++m_size;
}
template <typename T>
inline const T& HeapLinkedStack<T>::peek()
{
return m_head->m_data;
}
template <typename T>
inline void HeapLinkedStack<T>::pop()
{
ASSERT(m_head && m_size);
m_head = m_head->m_next;
--m_size;
}
template <typename T>
inline size_t HeapLinkedStack<T>::size()
{
return m_size;
}
}
#endif // HeapLinkedStack_h
此差异已折叠。
......@@ -316,7 +316,6 @@ public:
// can no longer use the garbage collected heap after this call.
static void detach();
static ThreadState* current() { return **s_threadSpecific; }
static ThreadState* mainThreadState()
{
return reinterpret_cast<ThreadState*>(s_mainThreadStateStorage);
......@@ -439,36 +438,6 @@ public:
void leaveSafePoint(SafePointAwareMutexLocker* = 0);
bool isAtSafePoint() const { return m_atSafePoint; }
class SafePointScope {
public:
enum ScopeNesting {
NoNesting,
AllowNesting
};
explicit SafePointScope(StackState stackState, ScopeNesting nesting = NoNesting)
: m_state(ThreadState::current())
{
if (m_state->isAtSafePoint()) {
RELEASE_ASSERT(nesting == AllowNesting);
// We can ignore stackState because there should be no heap object
// pointers manipulation after outermost safepoint was entered.
m_state = 0;
} else {
m_state->enterSafePoint(stackState, this);
}
}
~SafePointScope()
{
if (m_state)
m_state->leaveSafePoint();
}
private:
ThreadState* m_state;
};
// If attached thread enters long running loop that can call back
// into Blink and leaving and reentering safepoint at every
// transition between this loop and Blink is deemed too expensive
......@@ -613,7 +582,6 @@ private:
~ThreadState();
friend class SafePointBarrier;
friend class SafePointAwareMutexLocker;
void enterSafePoint(StackState, void*);
NO_SANITIZE_ADDRESS void copyStackUntilSafePointScope();
......@@ -705,69 +673,13 @@ public:
static ThreadState* state()
{
// This specialization must only be used from the main thread.
ASSERT(ThreadState::current()->isMainThread());
return ThreadState::mainThreadState();
}
};
template<> class ThreadStateFor<AnyThread> {
public:
static ThreadState* state() { return ThreadState::current(); }
};
// The SafePointAwareMutexLocker is used to enter a safepoint while waiting for
// a mutex lock. It also ensures that the lock is not held while waiting for a GC
// to complete in the leaveSafePoint method, by releasing the lock if the
// leaveSafePoint method cannot complete without blocking, see
// SafePointBarrier::checkAndPark.
class SafePointAwareMutexLocker {
WTF_MAKE_NONCOPYABLE(SafePointAwareMutexLocker);
public:
explicit SafePointAwareMutexLocker(MutexBase& mutex, ThreadState::StackState stackState = ThreadState::HeapPointersOnStack)
: m_mutex(mutex)
, m_locked(false)
{
ThreadState* state = ThreadState::current();
do {
bool leaveSafePoint = false;
// We cannot enter a safepoint if we are currently sweeping. In that
// case we just try to acquire the lock without being at a safepoint.
// If another thread tries to do a GC at that time it might time out
// due to this thread not being at a safepoint and waiting on the lock.
if (!state->isSweepInProgress() && !state->isAtSafePoint()) {
state->enterSafePoint(stackState, this);
leaveSafePoint = true;
}
m_mutex.lock();
m_locked = true;
if (leaveSafePoint) {
// When leaving the safepoint we might end up release the mutex
// if another thread is requesting a GC, see
// SafePointBarrier::checkAndPark. This is the case where we
// loop around to reacquire the lock.
state->leaveSafePoint(this);
}
} while (!m_locked);
}
~SafePointAwareMutexLocker()
{
ASSERT(m_locked);
m_mutex.unlock();
}
private:
friend class SafePointBarrier;
void reset()
{
ASSERT(m_locked);
m_mutex.unlock();
m_locked = false;
}
MutexBase& m_mutex;
bool m_locked;
static ThreadState* state() { return 0; }
};
// Common header for heap pages. Needs to be defined before class Visitor.
......
/*
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "platform/heap/Visitor.h"
namespace blink {
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册