Commit 39724b86 authored by barraclough@apple.com's avatar barraclough@apple.com
Browse files

https://bugs.webkit.org/show_bug.cgi?id=33731

Many false leaks in release builds due to PtrAndFlags

Reviewed by Darin Adler.

JavaScriptCore: 

StructureTransitionTable was effectively a smart pointer type,
one machine word in size and wholly contained as a member of
of Structure.  It either pointed to an actual table, or could
be used to describe a single transtion entry without use of a
table.

This, however, worked by using a PtrAndFlags, which is not
compatible with the leaks tool.  Since there is no clear way to
obtain another bit for 'free' here, and since there are bits
available up in Structure, merge this functionality back up into
Structure.  Having this in a separate class was quite clean
from an enacapsulation perspective, but this solution doesn't
seem to bad - all table access is now intermediated through the
Structure::structureTransitionTableFoo methods, keeping the
optimization fairly well contained.

This was the last use of PtrAndFlags, so removing the file too.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.h:
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::~Structure):
(JSC::Structure::addPropertyTransitionToExistingStructure):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::hasTransition):
* runtime/Structure.h:
(JSC::Structure::):
(JSC::Structure::structureTransitionTableContains):
(JSC::Structure::structureTransitionTableGet):
(JSC::Structure::structureTransitionTableHasTransition):
(JSC::Structure::structureTransitionTableRemove):
(JSC::Structure::structureTransitionTableAdd):
(JSC::Structure::structureTransitionTable):
(JSC::Structure::setStructureTransitionTable):
(JSC::Structure::singleTransition):
(JSC::Structure::setSingleTransition):
* runtime/StructureTransitionTable.h:
* wtf/PtrAndFlags.h: Removed.

WebCore: 

PtrAndFlags has now been removed; remove forwarding header.

* ForwardingHeaders/wtf/PtrAndFlags.h: Removed.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@54798 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 8ee0a9d7
2010-02-14 Gavin Barraclough <barraclough@apple.com>
Reviewed by Darin Adler.
https://bugs.webkit.org/show_bug.cgi?id=33731
Many false leaks in release builds due to PtrAndFlags
StructureTransitionTable was effectively a smart pointer type,
one machine word in size and wholly contained as a member of
of Structure. It either pointed to an actual table, or could
be used to describe a single transtion entry without use of a
table.
This, however, worked by using a PtrAndFlags, which is not
compatible with the leaks tool. Since there is no clear way to
obtain another bit for 'free' here, and since there are bits
available up in Structure, merge this functionality back up into
Structure. Having this in a separate class was quite clean
from an enacapsulation perspective, but this solution doesn't
seem to bad - all table access is now intermediated through the
Structure::structureTransitionTableFoo methods, keeping the
optimization fairly well contained.
This was the last use of PtrAndFlags, so removing the file too.
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.h:
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::~Structure):
(JSC::Structure::addPropertyTransitionToExistingStructure):
(JSC::Structure::addPropertyTransition):
(JSC::Structure::hasTransition):
* runtime/Structure.h:
(JSC::Structure::):
(JSC::Structure::structureTransitionTableContains):
(JSC::Structure::structureTransitionTableGet):
(JSC::Structure::structureTransitionTableHasTransition):
(JSC::Structure::structureTransitionTableRemove):
(JSC::Structure::structureTransitionTableAdd):
(JSC::Structure::structureTransitionTable):
(JSC::Structure::setStructureTransitionTable):
(JSC::Structure::singleTransition):
(JSC::Structure::setSingleTransition):
* runtime/StructureTransitionTable.h:
* wtf/PtrAndFlags.h: Removed.
2010-02-15 Gavin Barraclough <barraclough@apple.com>
 
Rubber Stamped by Geoff Garen.
......
......@@ -39,7 +39,6 @@
088FA5BB0EF76D4300578E6F /* RandomNumber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 088FA5B90EF76D4300578E6F /* RandomNumber.cpp */; };
088FA5BC0EF76D4300578E6F /* RandomNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 088FA5BA0EF76D4300578E6F /* RandomNumber.h */; settings = {ATTRIBUTES = (Private, ); }; };
08E279E90EF83B10007DB523 /* RandomNumberSeed.h in Headers */ = {isa = PBXBuildFile; fileRef = 08E279E80EF83B10007DB523 /* RandomNumberSeed.h */; };
0B1F921D0F1753500036468E /* PtrAndFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B1F921B0F17502D0036468E /* PtrAndFlags.h */; settings = {ATTRIBUTES = (Private, ); }; };
0B330C270F38C62300692DE3 /* TypeTraits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0B330C260F38C62300692DE3 /* TypeTraits.cpp */; };
0B4D7E630F319AC800AD7E58 /* TypeTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B4D7E620F319AC800AD7E58 /* TypeTraits.h */; settings = {ATTRIBUTES = (Private, ); }; };
0BDFFAE00FC6192900D69EF4 /* CrossThreadRefCounted.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BDFFAD40FC6171000D69EF4 /* CrossThreadRefCounted.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -1981,7 +1980,6 @@
BC18C4550E16F5CD00B34460 /* PropertySlot.h in Headers */,
BC18C4560E16F5CD00B34460 /* Protect.h in Headers */,
BC257DF40E1F53740016B6C9 /* PrototypeFunction.h in Headers */,
0B1F921D0F1753500036468E /* PtrAndFlags.h in Headers */,
147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */,
1429DA4A0ED245EC00B89619 /* Quantifier.h in Headers */,
088FA5BC0EF76D4300578E6F /* RandomNumber.h in Headers */,
......
......@@ -36,7 +36,6 @@
#include "JSGlobalObject.h"
#include "JumpTable.h"
#include "Nodes.h"
#include "PtrAndFlags.h"
#include "RegExp.h"
#include "UString.h"
#include <wtf/FastAllocBase.h>
......
......@@ -79,6 +79,106 @@ static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
static int comparePropertyMapEntryIndices(const void* a, const void* b);
inline void Structure::setTransitionTable(TransitionTable* table)
{
ASSERT(m_isUsingSingleSlot);
#ifndef NDEBUG
setSingleTransition(0);
#endif
m_isUsingSingleSlot = false;
m_transitions.m_table = table;
// This implicitly clears the flag that indicates we're using a single transition
ASSERT(!m_isUsingSingleSlot);
}
// The contains and get methods accept imprecise matches, so if an unspecialised transition exists
// for the given key they will consider that transition to be a match. If a specialised transition
// exists and it matches the provided specificValue, get will return the specific transition.
inline bool Structure::transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
{
if (m_isUsingSingleSlot) {
Structure* existingTransition = singleTransition();
return existingTransition && existingTransition->m_nameInPrevious.get() == key.first
&& existingTransition->m_attributesInPrevious == key.second
&& (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0);
}
TransitionTable::iterator find = transitionTable()->find(key);
if (find == transitionTable()->end())
return false;
return find->second.first || find->second.second->transitionedFor(specificValue);
}
inline Structure* Structure::transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
{
if (m_isUsingSingleSlot) {
Structure* existingTransition = singleTransition();
if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first
&& existingTransition->m_attributesInPrevious == key.second
&& (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0))
return existingTransition;
return 0;
}
Transition transition = transitionTable()->get(key);
if (transition.second && transition.second->transitionedFor(specificValue))
return transition.second;
return transition.first;
}
inline bool Structure::transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const
{
if (m_isUsingSingleSlot) {
Structure* transition = singleTransition();
return transition && transition->m_nameInPrevious == key.first
&& transition->m_attributesInPrevious == key.second;
}
return transitionTable()->contains(key);
}
inline void Structure::transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
{
if (m_isUsingSingleSlot) {
ASSERT(transitionTableContains(key, specificValue));
setSingleTransition(0);
return;
}
TransitionTable::iterator find = transitionTable()->find(key);
if (!specificValue)
find->second.first = 0;
else
find->second.second = 0;
if (!find->second.first && !find->second.second)
transitionTable()->remove(find);
}
inline void Structure::transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
{
if (m_isUsingSingleSlot) {
if (!singleTransition()) {
setSingleTransition(structure);
return;
}
Structure* existingTransition = singleTransition();
TransitionTable* transitionTable = new TransitionTable;
setTransitionTable(transitionTable);
if (existingTransition)
transitionTableAdd(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
}
if (!specificValue) {
TransitionTable::iterator find = transitionTable()->find(key);
if (find == transitionTable()->end())
transitionTable()->add(key, Transition(structure, 0));
else
find->second.first = structure;
} else {
// If we're adding a transition to a specific value, then there cannot be
// an existing transition
ASSERT(!transitionTable()->contains(key));
transitionTable()->add(key, Transition(0, structure));
}
}
void Structure::dumpStatistics()
{
#if DUMP_STRUCTURE_ID_STATISTICS
......@@ -136,7 +236,10 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anony
, m_attributesInPrevious(0)
, m_specificFunctionThrashCount(0)
, m_anonymousSlotCount(anonymousSlotCount)
, m_isUsingSingleSlot(true)
{
m_transitions.m_singleTransition = 0;
ASSERT(m_prototype);
ASSERT(m_prototype.isObject() || m_prototype.isNull());
......@@ -159,7 +262,7 @@ Structure::~Structure()
{
if (m_previous) {
ASSERT(m_nameInPrevious);
m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
m_previous->transitionTableRemove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
}
......@@ -177,6 +280,9 @@ Structure::~Structure()
fastFree(m_propertyTable);
}
if (!m_isUsingSingleSlot)
delete transitionTable();
#ifndef NDEBUG
#if ENABLE(JSC_MULTIPLE_THREADS)
MutexLocker protect(ignoreSetMutex);
......@@ -340,7 +446,7 @@ PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Struct
ASSERT(!structure->isDictionary());
ASSERT(structure->typeInfo().type() == ObjectType);
if (Structure* existingTransition = structure->table.get(make_pair(propertyName.ustring().rep(), attributes), specificValue)) {
if (Structure* existingTransition = structure->transitionTableGet(make_pair(propertyName.ustring().rep(), attributes), specificValue)) {
ASSERT(existingTransition->m_offset != noOffset);
offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount;
ASSERT(offset >= structure->m_anonymousSlotCount);
......@@ -405,7 +511,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
transition->m_offset = offset - structure->m_anonymousSlotCount;
ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
structure->table.add(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue);
structure->transitionTableAdd(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue);
return transition.release();
}
......@@ -852,7 +958,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
bool Structure::hasTransition(UString::Rep* rep, unsigned attributes)
{
return table.hasTransition(make_pair(rep, attributes));
return transitionTableHasTransition(make_pair(rep, attributes));
}
size_t Structure::remove(const Identifier& propertyName)
......
......@@ -179,6 +179,20 @@ namespace JSC {
// Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
return m_offset == noOffset ? 0 : m_offset + 1;
}
typedef std::pair<Structure*, Structure*> Transition;
typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
inline bool transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue);
inline void transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue);
inline void transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue);
inline bool transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const;
inline Structure* transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const;
TransitionTable* transitionTable() const { ASSERT(!m_isUsingSingleSlot); return m_transitions.m_table; }
inline void setTransitionTable(TransitionTable* table);
Structure* singleTransition() const { ASSERT(m_isUsingSingleSlot); return m_transitions.m_singleTransition; }
void setSingleTransition(Structure* structure) { ASSERT(m_isUsingSingleSlot); m_transitions.m_singleTransition = structure; }
bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
......@@ -199,7 +213,11 @@ namespace JSC {
RefPtr<UString::Rep> m_nameInPrevious;
JSCell* m_specificValueInPrevious;
StructureTransitionTable table;
// 'm_isUsingSingleSlot' indicates whether we are using the single transition optimisation.
union {
TransitionTable* m_table;
Structure* m_singleTransition;
} m_transitions;
WeakGCPtr<JSPropertyNameIterator> m_enumerationCache;
......@@ -224,7 +242,8 @@ namespace JSC {
#endif
unsigned m_specificFunctionThrashCount : 2;
unsigned m_anonymousSlotCount : 5;
// 5 free bits
unsigned m_isUsingSingleSlot : 1;
// 4 free bits
};
inline size_t Structure::get(const Identifier& propertyName)
......@@ -271,58 +290,7 @@ namespace JSC {
return m_propertyTable->entries()[entryIndex - 1].offset;
}
}
bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
{
if (usingSingleTransitionSlot()) {
Structure* existingTransition = singleTransition();
return existingTransition && existingTransition->m_nameInPrevious.get() == key.first
&& existingTransition->m_attributesInPrevious == key.second
&& (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0);
}
TransitionTable::iterator find = table()->find(key);
if (find == table()->end())
return false;
return find->second.first || find->second.second->transitionedFor(specificValue);
}
Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
{
if (usingSingleTransitionSlot()) {
Structure* existingTransition = singleTransition();
if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first
&& existingTransition->m_attributesInPrevious == key.second
&& (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0))
return existingTransition;
return 0;
}
Transition transition = table()->get(key);
if (transition.second && transition.second->transitionedFor(specificValue))
return transition.second;
return transition.first;
}
bool StructureTransitionTable::hasTransition(const StructureTransitionTableHash::Key& key) const
{
if (usingSingleTransitionSlot()) {
Structure* transition = singleTransition();
return transition && transition->m_nameInPrevious == key.first
&& transition->m_attributesInPrevious == key.second;
}
return table()->contains(key);
}
void StructureTransitionTable::reifySingleTransition()
{
ASSERT(usingSingleTransitionSlot());
Structure* existingTransition = singleTransition();
TransitionTable* transitionTable = new TransitionTable;
setTransitionTable(transitionTable);
if (existingTransition)
add(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
}
} // namespace JSC
#endif // Structure_h
......@@ -30,7 +30,6 @@
#include <wtf/HashFunctions.h>
#include <wtf/HashMap.h>
#include <wtf/HashTraits.h>
#include <wtf/PtrAndFlags.h>
#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
......@@ -67,99 +66,6 @@ namespace JSC {
static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
};
class StructureTransitionTable {
typedef std::pair<Structure*, Structure*> Transition;
typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
public:
StructureTransitionTable() {
m_transitions.m_singleTransition.set(0);
m_transitions.m_singleTransition.setFlag(usingSingleSlot);
}
~StructureTransitionTable() {
if (!usingSingleTransitionSlot())
delete table();
}
// The contains and get methods accept imprecise matches, so if an unspecialised transition exists
// for the given key they will consider that transition to be a match. If a specialised transition
// exists and it matches the provided specificValue, get will return the specific transition.
inline bool contains(const StructureTransitionTableHash::Key&, JSCell* specificValue);
inline Structure* get(const StructureTransitionTableHash::Key&, JSCell* specificValue) const;
inline bool hasTransition(const StructureTransitionTableHash::Key& key) const;
void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
{
if (usingSingleTransitionSlot()) {
ASSERT(contains(key, specificValue));
setSingleTransition(0);
return;
}
TransitionTable::iterator find = table()->find(key);
if (!specificValue)
find->second.first = 0;
else
find->second.second = 0;
if (!find->second.first && !find->second.second)
table()->remove(find);
}
void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
{
if (usingSingleTransitionSlot()) {
if (!singleTransition()) {
setSingleTransition(structure);
return;
}
reifySingleTransition();
}
if (!specificValue) {
TransitionTable::iterator find = table()->find(key);
if (find == table()->end())
table()->add(key, Transition(structure, 0));
else
find->second.first = structure;
} else {
// If we're adding a transition to a specific value, then there cannot be
// an existing transition
ASSERT(!table()->contains(key));
table()->add(key, Transition(0, structure));
}
}
private:
TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; }
Structure* singleTransition() const {
ASSERT(usingSingleTransitionSlot());
return m_transitions.m_singleTransition.get();
}
bool usingSingleTransitionSlot() const { return m_transitions.m_singleTransition.isFlagSet(usingSingleSlot); }
void setSingleTransition(Structure* structure)
{
ASSERT(usingSingleTransitionSlot());
m_transitions.m_singleTransition.set(structure);
}
void setTransitionTable(TransitionTable* table)
{
ASSERT(usingSingleTransitionSlot());
#ifndef NDEBUG
setSingleTransition(0);
#endif
m_transitions.m_table = table;
// This implicitly clears the flag that indicates we're using a single transition
ASSERT(!usingSingleTransitionSlot());
}
inline void reifySingleTransition();
enum UsingSingleSlot {
usingSingleSlot
};
// Last bit indicates whether we are using the single transition optimisation
union {
TransitionTable* m_table;
PtrAndFlagsBase<Structure, UsingSingleSlot> m_singleTransition;
} m_transitions;
};
} // namespace JSC
#endif // StructureTransitionTable_h
/*
* Copyright (C) 2009 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 PtrAndFlags_h
#define PtrAndFlags_h
#include <wtf/Assertions.h>
namespace WTF {
template<class T, typename FlagEnum> class PtrAndFlagsBase {
public:
bool isFlagSet(FlagEnum flagNumber) const { ASSERT(flagNumber < 2); return m_ptrAndFlags & (1 << flagNumber); }
void setFlag(FlagEnum flagNumber) { ASSERT(flagNumber < 2); m_ptrAndFlags |= (1 << flagNumber);}
void clearFlag(FlagEnum flagNumber) { ASSERT(flagNumber < 2); m_ptrAndFlags &= ~(1 << flagNumber);}
T* get() const { return reinterpret_cast<T*>(m_ptrAndFlags & ~3); }
void set(T* ptr)
{
ASSERT(!(reinterpret_cast<intptr_t>(ptr) & 3));
m_ptrAndFlags = reinterpret_cast<intptr_t>(ptr) | (m_ptrAndFlags & 3);
#ifndef NDEBUG
m_leaksPtr = ptr;
#endif
}
bool operator!() const { return !get(); }
T* operator->() const { return reinterpret_cast<T*>(m_ptrAndFlags & ~3); }
protected:
intptr_t m_ptrAndFlags;
#ifndef NDEBUG
void* m_leaksPtr; // Only used to allow tools like leaks on OSX to detect that the memory is referenced.
#endif
};
template<class T, typename FlagEnum> class PtrAndFlags : public PtrAndFlagsBase<T, FlagEnum> {
public:
PtrAndFlags()
{
PtrAndFlagsBase<T, FlagEnum>::m_ptrAndFlags = 0;
}
PtrAndFlags(T* ptr)
{
PtrAndFlagsBase<T, FlagEnum>::m_ptrAndFlags = 0;
PtrAndFlagsBase<T, FlagEnum>::set(ptr);
}
};
} // namespace WTF
using WTF::PtrAndFlagsBase;
using WTF::PtrAndFlags;
#endif // PtrAndFlags_h
2010-02-14 Gavin Barraclough <barraclough@apple.com>
Reviewed by Darin Adler.
https://bugs.webkit.org/show_bug.cgi?id=33731
Many false leaks in release builds due to PtrAndFlags
PtrAndFlags has now been removed; remove forwarding header.
* ForwardingHeaders/wtf/PtrAndFlags.h: Removed.
2010-02-15 Gavin Barraclough <barraclough@apple.com>
Reviewed by Geoff Garen.
......
#ifndef WebCore_FWD_PtrAndFlags_h
#define WebCore_FWD_PtrAndFlags_h
#include <JavaScriptCore/PtrAndFlags.h>
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment