Changeset 58432
- Timestamp:
- Dec 17, 2009, 4:35:23 PM (13 years ago)
- Author:
- Domagoj Šarić
- Message:
-
First changes: this is unfortunatelly one huge commit as it consists of many many changes that were done locally/offline/without source control so the individual steps are lost.
The most important changes are as follows:
- there was a lot of functionality in the function_template.hpp (in the main
boost::function<> template class) that was not related/specific to the
particular boost::function<> instantiation and could be extracted into the
non-template function_base base class (and was causing actual bloat as the
compiler/linker did not/could not merge it)...moved as much of such code as
possible into the base header/class
- along with that 'binary code duplication' caused by template code bloat
there was also a certain amount of source code duplication (like same
descisions being made both at the "front side" and the "back side", or type
information managing implemented both in the 'shared' manager and again in each
type specific manager...)
- there is now only a single invoker template (actually two, the void
returning version of the first one)
- there is now only one vtable type/struct (the one in the base header)
- the invoker pointer was moved into the base vtable and was placed at the
beginning of the vtable so that the vtable pointer would point to it directly
(to avoid the pointer offset calculation mentioned in the "[optional] layout"
thread)
- the invoker pointer/signature was changed to be a member function of the
function_buffer so that the thiscall calling convention would be used.
According to this information http://en.wikipedia.org/wiki/X86_calling_conventions#thiscall this makes no
difference for gcc but does for MSVC (and x86) because now the pointer to the
function_buffer is passed in the ECX register making the stack look exactly (or
more closely, depending on the target) as it needs to be to invoke the target
in the invoker function providing for a more direct call of the target (with no
or less stack adjustment/additional pushing/poping)
- the manager design was changed to allow easier splitting and extracting of
functionality (and in the end for both smaller and faster code): previous
manager design used a combination of one function pointer and
'message'/'op-code' passing and switching...this, among other things, caused
separate manager code to be generated for every different type of object
assigned to the boost::function<> object because the same function was
'managing' both the (obiously different) type information and the
move/clone/destroy functionality (which is actually shared for a vast majority
of assigned types of objects)...this was changed so that the op-codes were
replaced with an enlarged vtable with separate pointers/functions for move,
clone, destroy and type information functionality...type information
functionality was also changed so that the "back side" only creates an object
containing all the relevant information and passes it to the "front side" that
can then use how and _if_ it needs it (this way the type comparison code for
the target() member function is only generated if it is actually used)
- cv-qualifier information for objects stored as references is also no
longer saved in two run-time bools but is encoded in the type of the "back
side" (so function_buffer::type_t is now typed_functor, and no longer needs to
reside in the function_buffer and function_buffer::obj_ref_t is gone all
together)
- added more managers (total of 5, previously there were 3) that work with as
little type information as possible (the purpose and implementation should be
obvious from the source and acompanying comments)
- the vtable static initialization was moved outside the vtable_for_functor()
function to ensure that static initialization was actually always used (with
increased numer of function pointers/size of the vtable MSVC would start using
lazy initialization...like in a 'normal' "Meyers' singleton")
- the "has_trivial_copy_and_destroy" optimization and the encoding of that
information into the vtable pointer was removed because in practice it was
actually a pessimization (atleast/especially with the new design). If it
somehow turns out usefull at some later time it can now be more easily
implemented (e.g. with a larger vtable, the trivial functionality could simply
use null pointers...)...
- assignment functionality was moved from the (no longer present)
boost::function<> instantiation-specific vtable struct (BOOST_FUNCTION_VTABLE)
into the appropriate functor manager classes in the base header
- assignment functionality was also heavily optimized (although there is
still room for improvement)...until now the default 'safe' approach of
<copy-constructing a temporary and calling swap> was always used (which
resulted in hundreds if not a few thousands of asm instructions getting
executed, and was part of the template so it caused bloat)...now this is
done only for function objects that have nontrivial copy-constructors
and/or do not fit in the function_buffer (and is not part of the
template)...for the often case of simple binds and function pointers
assignment (and construction) now results in a call to the nothrow, and most
often trivial, destroy function and a couple of movs...
- empty-invocation handling was changed to no longer place an "if (empty)
throw" section in the operator() (of the template class, thus pretty much
adding to bloat) but to use (assign to itself an) "EmptyHandler" function
object when in the empty state (that then gets invoked and does 'its
thing')...(this also removed the need for the msvc 6.0 workaround for the
in/out of class definition of the operator() function - as it is now only a
thin wrapper it can, actually should, be safely inlined)...
- added BOOST_NO_TYPEID support that disables the type information
functionality
- explicit exception handling was replaced with guard objects
- const's were added, mutable's removed and pointers converted to references where ever possible
- the generic has_empty_target() function was fixed for MSVC to always use
the ( void const * ) overload because MSVC does not inline vararg functions so
it was always generating calls to a function that only returns false (so it was
unable to remove code that does not execute for the false case)...
- an additional template parameter was added to the main boost::function<>
template class called PolicyList (a list to cut down on the number of
parameters) that is expected to be a boost::mpl::map-like container of
policies. currently two policies exist:
- - how to handle invocation of empty function objects (three default
handlers are provided: throw_on_empty, assert_on_empty and nop_on_empty)
- - whether the function<> instantiation should 'report'/mark its operator()
as nothrow and accept only nothrow targets (for supported compilers). For detail on the throw/nothrow implementation check the relevant boost.devel discusion (links are in the readme file).
- (No files)
-