diff --git a/hphp/runtime/base/memory/memory_manager.h b/hphp/runtime/base/memory/memory_manager.h index 3dd511812..a09af464a 100644 --- a/hphp/runtime/base/memory/memory_manager.h +++ b/hphp/runtime/base/memory/memory_manager.h @@ -398,6 +398,22 @@ void* smart_calloc(size_t count, size_t bytes); void* smart_realloc(void* ptr, size_t nbytes); void smart_free(void* ptr); +namespace smart { +namespace do_not_use_directly { +/* + * We are deriving from the std::collection classes to get + * smart::collection classes that use smart allocation. + * To avoid the various issues involved with deriving + * from value types, we want to make sure that there are + * no references to std::collection<...,SmartStlAlloc<>> + * other than the ones below. That way we know that + * a pointer to a smart::collection can never decay + * to a pointer to a std::collection. + * + * The namespace do_not_use_directly should remind us + * of that. + * + */ template class SmartStlAlloc { public: @@ -460,21 +476,50 @@ bool operator!= (const SmartStlAlloc&, return false; } -namespace smart { -template , - class Alloc = HPHP::SmartStlAlloc > > -class map : public std::map {}; - -template > -class deque : public std::deque {}; - -template > -class vector : public std::vector {}; - -template > -class queue : public std::queue {}; } +/* + * Derivation from value types is generally bad. + * Here, we derive from classes that do not exist anywhere + * else in the code base (see comments above). + * + * We also add no functionality to the derived class. Your + * code will not get past code review if you try to do so. + */ +template > +class map : public std::map< + Key, T, Compare, + do_not_use_directly::SmartStlAlloc > > {}; +template +class deque : public std::deque > {}; + +template +class vector : public std::vector > {}; + +template +class list : public std::list > {}; + +template +class queue : public std::queue > {}; + +template ,class _W = std::equal_to<_T> > +struct hash_map : std::tr1::unordered_map< + _T, _U, _V, _W, do_not_use_directly::SmartStlAlloc > > { + hash_map() : std::tr1::unordered_map< + _T, _U, _V, _W, do_not_use_directly::SmartStlAlloc > + >(0) {} +}; + +template ,class _W = std::equal_to<_T> > +struct hash_set : std::tr1::unordered_set< + _T, _V, _W, do_not_use_directly::SmartStlAlloc<_T> > { + hash_set() : std::tr1::unordered_set< + _T, _V, _W, do_not_use_directly::SmartStlAlloc<_T> >(0) {} +}; + +} /////////////////////////////////////////////////////////////////////////////// } diff --git a/hphp/runtime/base/variable_serializer.cpp b/hphp/runtime/base/variable_serializer.cpp index 24adf151c..8ff001f56 100644 --- a/hphp/runtime/base/variable_serializer.cpp +++ b/hphp/runtime/base/variable_serializer.cpp @@ -45,7 +45,7 @@ VariableSerializer::VariableSerializer(Type type, int option /* = 0 */, m_levelDebugger(0) { m_maxLevelDebugger = g_context->getDebuggerPrintLevel(); if (type == Serialize || type == APCSerialize || type == DebuggerSerialize) { - m_arrayIds = new PointerCounterMap(); + m_arrayIds = new SmartPtrCtrMap(); } else { m_arrayIds = nullptr; } @@ -477,7 +477,7 @@ void VariableSerializer::writeOverflow(void* ptr, bool isObject /* = false */) { case APCSerialize: { assert(m_arrayIds); - PointerCounterMap::const_iterator iter = m_arrayIds->find(ptr); + SmartPtrCtrMap::const_iterator iter = m_arrayIds->find(ptr); assert(iter != m_arrayIds->end()); int id = iter->second; if (isObject) { diff --git a/hphp/runtime/base/variable_serializer.h b/hphp/runtime/base/variable_serializer.h index 6fbfe5357..5aee04916 100644 --- a/hphp/runtime/base/variable_serializer.h +++ b/hphp/runtime/base/variable_serializer.h @@ -108,12 +108,13 @@ public: void getResourceInfo(String &rsrcName, int &rsrcId); Type getType() const { return m_type; } private: + typedef smart::hash_map > SmartPtrCtrMap; Type m_type; int m_option; // type specific extra options StringBuffer *m_buf; int m_indent; - PointerCounterMap m_counts; // counting seen arrays for recursive levels - PointerCounterMap *m_arrayIds; // reference ids for objs/arrays + SmartPtrCtrMap m_counts; // counting seen arrays for recursive levels + SmartPtrCtrMap *m_arrayIds; // reference ids for objs/arrays int m_valueCount; // Current ref index bool m_referenced; // mark current array element as reference int m_refCount; // current variable's reference count @@ -132,7 +133,7 @@ private: bool first_element; // whether this is first array element int indent_delta; // the extra indent to serialize this object }; - std::vector m_arrayInfos; + smart::vector m_arrayInfos; void writePropertyKey(CStrRef prop); }; diff --git a/hphp/runtime/base/variable_unserializer.h b/hphp/runtime/base/variable_unserializer.h index 6d4553edf..e3f436616 100644 --- a/hphp/runtime/base/variable_unserializer.h +++ b/hphp/runtime/base/variable_unserializer.h @@ -120,8 +120,8 @@ public: Type m_type; const char *m_buf; const char *m_end; - std::vector m_refs; - std::list m_vars; + smart::vector m_refs; + smart::list m_vars; bool m_unknownSerializable; void check() {