From 0a18064197ecea262a36b65e6b8b77a5d97f067c Mon Sep 17 00:00:00 2001 From: Jordan DeLong Date: Fri, 31 May 2013 21:06:03 -0700 Subject: [PATCH] Add some unique_ptr-related support to smart:: containers - smart::make_unique, returns a unique pointer to smart allocated data. - Support forwarding in our allocator's construct, so smart::vector> works. - Move smart containers to their own header. --- hphp/runtime/base/memory/memory_manager.h | 134 +----------- hphp/runtime/base/memory/smart_containers.h | 198 ++++++++++++++++++ hphp/runtime/base/variable_serializer.h | 2 + hphp/runtime/base/variable_unserializer.h | 1 + hphp/runtime/ext/asio/asio_context.cpp | 2 +- hphp/runtime/ext/asio/asio_context.h | 1 + .../ext/asio/blockable_wait_handle.cpp | 1 + hphp/runtime/vm/jit/block.h | 2 +- hphp/runtime/vm/jit/cfg.h | 2 +- hphp/runtime/vm/jit/layout.h | 2 +- hphp/runtime/vm/jit/linearscan.cpp | 1 + hphp/runtime/vm/jit/print.cpp | 2 +- hphp/runtime/vm/jit/simplifier.cpp | 1 + hphp/runtime/vm/jit/simplifier.h | 1 + hphp/runtime/vm/jit/state_vector.h | 2 +- 15 files changed, 215 insertions(+), 137 deletions(-) create mode 100644 hphp/runtime/base/memory/smart_containers.h diff --git a/hphp/runtime/base/memory/memory_manager.h b/hphp/runtime/base/memory/memory_manager.h index ec182fda9..03d032d5b 100644 --- a/hphp/runtime/base/memory/memory_manager.h +++ b/hphp/runtime/base/memory/memory_manager.h @@ -18,6 +18,9 @@ #define incl_HPHP_MEMORY_MANAGER_H_ #include + +#include "folly/Memory.h" + #include "hphp/util/thread_local.h" #include "hphp/runtime/base/memory/memory_usage_stats.h" @@ -395,137 +398,6 @@ 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: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - template - struct rebind { - typedef SmartStlAlloc other; - }; - - pointer address (reference value) const { - return &value; - } - const_pointer address (const_reference value) const { - return &value; - } - - SmartStlAlloc() throw() {} - SmartStlAlloc(const SmartStlAlloc&) {} - template - SmartStlAlloc (const SmartStlAlloc&) {} - ~SmartStlAlloc() {} - - size_type max_size () const { - return std::numeric_limits::max() / sizeof(T); - } - - pointer allocate (size_type num, const void* = 0) { - pointer ret = (pointer)smart_malloc(num * sizeof(T)); - return ret; - } - - void construct (pointer p, const T& value) { - new ((void*)p) T(value); - } - - void construct (pointer p) { - new ((void*)p) T(); - } - - void destroy (pointer p) { - p->~T(); - } - - void deallocate (pointer p, size_type num) { - smart_free(p); - } -}; - -template -bool operator== (const SmartStlAlloc&, - const SmartStlAlloc&) { - return true; -} -template -bool operator!= (const SmartStlAlloc&, - const SmartStlAlloc&) { - return false; -} - -} -/* - * 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 > { - typedef std::vector > Base_; - public: - template - explicit vector(A &&... args) : Base_(std::forward(args)...) {} -}; - -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/memory/smart_containers.h b/hphp/runtime/base/memory/smart_containers.h new file mode 100644 index 000000000..faf461fe6 --- /dev/null +++ b/hphp/runtime/base/memory/smart_containers.h @@ -0,0 +1,198 @@ +/* + +----------------------------------------------------------------------+ + | HipHop for PHP | + +----------------------------------------------------------------------+ + | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ +#ifndef incl_HPHP_RUNTIME_BASE_MEMORY_SMART_CONTAINERS_H_ +#define incl_HPHP_RUNTIME_BASE_MEMORY_SMART_CONTAINERS_H_ + +#include "hphp/runtime/base/memory/memory_manager.h" + +namespace HPHP { namespace smart { + +////////////////////////////////////////////////////////////////////// + +/* + * Defines a family of types similar to std:: collections and + * pointers, except using the request-local allocator, which we + * consider smart. + * + * Replace std:: with smart:: if you know the data is request-local. + * + * You can also use smart::Allocator as a model of folly's + * SimpleAllocator where appropriate. + */ + +////////////////////////////////////////////////////////////////////// + +// STL-style allocator for the smart allocator. (Unfortunately we +// can't use allocator_traits yet.) + +template +struct Allocator { + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + template + struct rebind { + typedef Allocator other; + }; + + pointer address(reference value) const { + return &value; + } + const_pointer address(const_reference value) const { + return &value; + } + + Allocator() noexcept {} + Allocator(const Allocator&) noexcept {} + template Allocator(const Allocator&) noexcept {} + ~Allocator() noexcept {} + + size_type max_size() const { + return std::numeric_limits::max() / sizeof(T); + } + + pointer allocate(size_type num, const void* = 0) { + pointer ret = (pointer)smart_malloc(num * sizeof(T)); + return ret; + } + + template + void construct(pointer p, Args&&... args) { + new ((void*)p) T(std::forward(args)...); + } + + void destroy(pointer p) { + p->~T(); + } + + void deallocate(pointer p, size_type num) { + smart_free(p); + } + + template bool operator==(const Allocator&) const { + return true; + } + + template bool operator!=(const Allocator&) const { + return false; + } +}; + +/* + * Shorthand to create a std::unique_ptr to a smart-allocated object. + * + * Usage: + * + * auto ptr = smart::make_unique(arg1, arg2); + * + * If you need to make a typedef to one, since we don't have type + * aliases yet in our version of gcc you have to do: + * + * typedef smart::unique_ptr::type type; + */ + +template struct unique_ptr + : folly::AllocatorUniquePtr> +{}; + +template +typename unique_ptr::type make_unique(Args&&... args) { + return folly::allocate_unique( + Allocator(), + std::forward(args)... + ); +} + +static_assert( + sizeof(unique_ptr::type) == sizeof(std::unique_ptr), + "smart::unique_ptr pointer should not be larger than std::unique_ptr" +); + +/* + * 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 the base classes here + * 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. + * + * Derivation from value types is generally bad. We also add no + * functionality to the derived class. Your code will not get past + * code review if you try to do so. + * + * When we upgrade compilers we can change these to C++11 type + * aliases. + */ + +template > +class map : public std::map< + Key, T, Compare, + Allocator> +> {}; + +template +class deque : public std::deque> {}; + +template +class vector : public std::vector> { + typedef std::vector> Base; +public: + template + explicit vector(A &&... args) : Base(std::forward(args)...) {} +}; + +template +class list : public std::list> {}; + +template +class queue : public std::queue > {}; + +template , + class W = std::equal_to> +struct hash_map : std::tr1::unordered_map< + T, U, V, W, + Allocator> +> { + hash_map() + : std::tr1::unordered_map< + T, U, V, W, + Allocator> + >(0) + {} +}; + +template , + class W = std::equal_to> +struct hash_set : std::tr1::unordered_set > { + hash_set() + : std::tr1::unordered_set>(0) + {} +}; + +////////////////////////////////////////////////////////////////////// + +}} + +#endif diff --git a/hphp/runtime/base/variable_serializer.h b/hphp/runtime/base/variable_serializer.h index f1458ae1d..1da4e3fe8 100644 --- a/hphp/runtime/base/variable_serializer.h +++ b/hphp/runtime/base/variable_serializer.h @@ -19,6 +19,7 @@ #include "hphp/runtime/base/types.h" #include "hphp/runtime/base/util/string_buffer.h" +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/class.h" #include "hphp/runtime/vm/unit.h" @@ -107,6 +108,7 @@ public: void setResourceInfo(CStrRef rsrcName, int rsrcId); void getResourceInfo(String &rsrcName, int &rsrcId); Type getType() const { return m_type; } + private: typedef smart::hash_map > SmartPtrCtrMap; Type m_type; diff --git a/hphp/runtime/base/variable_unserializer.h b/hphp/runtime/base/variable_unserializer.h index 9451d6705..4c5c382e7 100644 --- a/hphp/runtime/base/variable_unserializer.h +++ b/hphp/runtime/base/variable_unserializer.h @@ -18,6 +18,7 @@ #define incl_HPHP_VARIABLE_UNSERIALIZER_H_ #include "hphp/runtime/base/types.h" +#include "hphp/runtime/base/memory/smart_containers.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// diff --git a/hphp/runtime/ext/asio/asio_context.cpp b/hphp/runtime/ext/asio/asio_context.cpp index d06316b9b..b7e7ed19e 100644 --- a/hphp/runtime/ext/asio/asio_context.cpp +++ b/hphp/runtime/ext/asio/asio_context.cpp @@ -14,9 +14,9 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ +#include "hphp/runtime/ext/asio/asio_context.h" #include "hphp/runtime/ext/ext_asio.h" -#include "hphp/runtime/ext/asio/asio_context.h" #include "hphp/runtime/ext/asio/asio_session.h" #include "hphp/system/lib/systemlib.h" diff --git a/hphp/runtime/ext/asio/asio_context.h b/hphp/runtime/ext/asio/asio_context.h index 7233df565..3a300a88d 100644 --- a/hphp/runtime/ext/asio/asio_context.h +++ b/hphp/runtime/ext/asio/asio_context.h @@ -21,6 +21,7 @@ #include #include #include "hphp/runtime/base/base_includes.h" +#include "hphp/runtime/base/memory/smart_containers.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// diff --git a/hphp/runtime/ext/asio/blockable_wait_handle.cpp b/hphp/runtime/ext/asio/blockable_wait_handle.cpp index 2966f4986..d0b67b973 100644 --- a/hphp/runtime/ext/asio/blockable_wait_handle.cpp +++ b/hphp/runtime/ext/asio/blockable_wait_handle.cpp @@ -15,6 +15,7 @@ +----------------------------------------------------------------------+ */ +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/ext/ext_asio.h" #include "hphp/runtime/ext/asio/asio_context.h" #include "hphp/system/lib/systemlib.h" diff --git a/hphp/runtime/vm/jit/block.h b/hphp/runtime/vm/jit/block.h index 53f21e1be..9b8b686b8 100644 --- a/hphp/runtime/vm/jit/block.h +++ b/hphp/runtime/vm/jit/block.h @@ -17,7 +17,7 @@ #ifndef incl_HPHP_VM_BLOCK_H_ #define incl_HPHP_VM_BLOCK_H_ -#include "hphp/runtime/base/memory/memory_manager.h" +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/jit/ir.h" #include "hphp/runtime/vm/jit/edge.h" #include "hphp/runtime/vm/jit/irinstruction.h" diff --git a/hphp/runtime/vm/jit/cfg.h b/hphp/runtime/vm/jit/cfg.h index 816b16805..427bede49 100644 --- a/hphp/runtime/vm/jit/cfg.h +++ b/hphp/runtime/vm/jit/cfg.h @@ -19,7 +19,7 @@ #include -#include "hphp/runtime/base/memory/memory_manager.h" +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/jit/block.h" #include "hphp/runtime/vm/jit/trace.h" diff --git a/hphp/runtime/vm/jit/layout.h b/hphp/runtime/vm/jit/layout.h index 14ce66c71..44f232653 100644 --- a/hphp/runtime/vm/jit/layout.h +++ b/hphp/runtime/vm/jit/layout.h @@ -16,7 +16,7 @@ #ifndef incl_HPHP_JIT_LAYOUT_H_ #define incl_HPHP_JIT_LAYOUT_H_ -#include "hphp/runtime/base/memory/memory_manager.h" +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/jit/ir.h" #include "hphp/runtime/vm/jit/block.h" diff --git a/hphp/runtime/vm/jit/linearscan.cpp b/hphp/runtime/vm/jit/linearscan.cpp index e48d7ac7e..1f177a57b 100644 --- a/hphp/runtime/vm/jit/linearscan.cpp +++ b/hphp/runtime/vm/jit/linearscan.cpp @@ -16,6 +16,7 @@ #include "hphp/runtime/vm/jit/linearscan.h" +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/jit/irfactory.h" #include "hphp/runtime/vm/jit/nativecalls.h" #include "hphp/runtime/vm/jit/print.h" diff --git a/hphp/runtime/vm/jit/print.cpp b/hphp/runtime/vm/jit/print.cpp index f5bcb79c3..3ea2b669a 100644 --- a/hphp/runtime/vm/jit/print.cpp +++ b/hphp/runtime/vm/jit/print.cpp @@ -13,9 +13,9 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ - #include "hphp/runtime/vm/jit/print.h" +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/jit/ir.h" #include "hphp/runtime/vm/jit/linearscan.h" #include "hphp/runtime/vm/jit/codegen.h" diff --git a/hphp/runtime/vm/jit/simplifier.cpp b/hphp/runtime/vm/jit/simplifier.cpp index c4f71f179..f666bc047 100644 --- a/hphp/runtime/vm/jit/simplifier.cpp +++ b/hphp/runtime/vm/jit/simplifier.cpp @@ -19,6 +19,7 @@ #include #include +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/base/type_conversions.h" #include "hphp/runtime/vm/jit/tracebuilder.h" #include "hphp/runtime/vm/runtime.h" diff --git a/hphp/runtime/vm/jit/simplifier.h b/hphp/runtime/vm/jit/simplifier.h index c7238d9d0..685423067 100644 --- a/hphp/runtime/vm/jit/simplifier.h +++ b/hphp/runtime/vm/jit/simplifier.h @@ -17,6 +17,7 @@ #ifndef incl_HPHP_HHVM_HHIR_SIMPLIFIER_H_ #define incl_HPHP_HHVM_HHIR_SIMPLIFIER_H_ +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/jit/cse.h" #include "hphp/runtime/vm/jit/ir.h" diff --git a/hphp/runtime/vm/jit/state_vector.h b/hphp/runtime/vm/jit/state_vector.h index 5de806bcc..cf3fe70d5 100644 --- a/hphp/runtime/vm/jit/state_vector.h +++ b/hphp/runtime/vm/jit/state_vector.h @@ -19,7 +19,7 @@ #include -#include "hphp/runtime/base/memory/memory_manager.h" +#include "hphp/runtime/base/memory/smart_containers.h" #include "hphp/runtime/vm/jit/irfactory.h" namespace HPHP { namespace JIT {