mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-30 07:14:09 +08:00
debug_mode.html: Update.
2003-11-12 Benjamin Kosnik <bkoz@redhat.com> * docs/html/debug_mode.html: Update. * docs/html/17_intro/TODO: Update. From-SVN: r73525
This commit is contained in:
parent
f1045f1b27
commit
89341602bb
@ -1,3 +1,8 @@
|
||||
2003-11-12 Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
* docs/html/debug_mode.html: Update.
|
||||
* docs/html/17_intro/TODO: Update.
|
||||
|
||||
2003-11-12 Benjamin Kosnik <bkoz@redhat.com>
|
||||
|
||||
* include/bits/c++config: Move using directive...
|
||||
|
@ -36,12 +36,18 @@ std::locale
|
||||
functions and and LANG environment variable dependencies.
|
||||
|
||||
- use localedata to implement generic named (non-MT-safe) locales?
|
||||
Figure out a way to use ICU data, like libjava? Need a generic locale
|
||||
model that does something besides the "C" locale.
|
||||
Figure out a way to use ICU data, like libjava? Re-package and use
|
||||
the glibc localedata, even if we aren't on linux? Need a generic
|
||||
locale model that does something besides the "C" locale.
|
||||
|
||||
- make locale::classic() separate from named locale code. This will
|
||||
improve the static linkage situation, but will require new
|
||||
initialization code.
|
||||
initialization code. In particular, we need lazy-initialization of
|
||||
locale::classic(), and maybe the has_facet/use_facet functions for all
|
||||
the required facets. The end goal is a self-contained
|
||||
locale_init.cc, or one with transitive closure without the locale
|
||||
instantiations (locale-inst.cc) or the named locale bits
|
||||
(localename.cc).
|
||||
|
||||
- Jerry(?)/Paolo(?) work on __float_to_char.
|
||||
|
||||
@ -52,9 +58,9 @@ std::locale
|
||||
std::basic_filebuf, 27_io
|
||||
|
||||
- wfilebuf, get variable-encoding working and tested, including
|
||||
positioning and seeking.
|
||||
positioning and seeking. (I think this may be done now)
|
||||
|
||||
- wfilebuf testsuite
|
||||
- wfilebuf testsuite (getting there...)
|
||||
|
||||
- look ahead for unbuffered io, so know when multiple putc's can be
|
||||
coalesced.
|
||||
@ -90,9 +96,13 @@ testsuite
|
||||
|
||||
g++/binutils
|
||||
|
||||
- compression for wide versions of basic types
|
||||
- compression for wide versions of basic types, not just narrow
|
||||
|
||||
- get Apple's debug mode, or something with equivalent functionality, in.
|
||||
threads
|
||||
|
||||
- create MT abstraction layer for atomicity to pthreads.
|
||||
|
||||
- solution for threads + C++.
|
||||
|
||||
- audit for places where __builtin_expect can be used.
|
||||
|
||||
@ -157,8 +167,6 @@ sources, with macro-guards. Also, same with the TR.
|
||||
|
||||
- add feature-test macros for non-standard extensions
|
||||
|
||||
- create MT abstraction layer for atomicity to pthreads.
|
||||
|
||||
- add MT support for locale, string, istream, ostream
|
||||
|
||||
- need to think about doing a .texi or DocBook manual, instead of all
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta name="AUTHOR" content="dgregor@apple.com (Doug Gregor)" />
|
||||
<meta name="KEYWORDS" content="libstdc++, libstdc++-v3, GCC, g++, debug" />
|
||||
<meta name="AUTHOR" content="gregod@cs.rpi.edu (Doug Gregor)" />
|
||||
<meta name="KEYWORDS" content="C++, GCC, libstdc++, g++, debug" />
|
||||
<meta name="DESCRIPTION" content="Design of the libstdc++ debug mode." />
|
||||
<meta name="GENERATOR" content="vi and eight fingers" />
|
||||
<title>Design of the libstdc++ debug mode</title>
|
||||
@ -249,7 +249,7 @@
|
||||
following basic structure:</p>
|
||||
|
||||
<pre>
|
||||
template<typename _Tp, typename _Allocator = std::allocator<_Tp>
|
||||
template<typename _Tp, typename _Allocator = allocator<_Tp>
|
||||
class debug-list :
|
||||
public release-list<_Tp, _Allocator>,
|
||||
public __gnu_debug::_Safe_sequence<debug-list<_Tp, _Allocator> >
|
||||
@ -309,12 +309,14 @@ template<typename _Tp, typename _Allocator = std::allocator<_Tp>
|
||||
|
||||
<p>Achieving link- and run-time coexistence is not a trivial
|
||||
implementation task. To achieve this goal we required a small
|
||||
extension to the GNU C++ compiler (described in the section on
|
||||
<a href="#mixing">link- and run-time coexistence</a>) and complex
|
||||
organization of debug- and release-modes. The end result is that we
|
||||
have achieved per-use recompilation but have had to give up some
|
||||
checking of the <code>std::basic_string</code> class template
|
||||
(namely, safe iterators).
|
||||
extension to the GNU C++ compiler (described in the GCC Manual for
|
||||
C++ Extensions, see <a href =
|
||||
http://gcc.gnu.org/onlinedocs/gcc/Strong-Using.html>strong
|
||||
using</a>), and a complex organization of debug- and
|
||||
release-modes. The end result is that we have achieved per-use
|
||||
recompilation but have had to give up some checking of the
|
||||
<code>std::basic_string</code> class template (namely, safe
|
||||
iterators).
|
||||
|
||||
<h4><a name="compile_coexistence">Compile-time coexistence of release- and
|
||||
debug-mode components</a></h4>
|
||||
@ -322,95 +324,129 @@ template<typename _Tp, typename _Allocator = std::allocator<_Tp>
|
||||
components need to exist within a single translation unit so that
|
||||
the debug versions can wrap the release versions. However, only one
|
||||
of these components should be user-visible at any particular
|
||||
time with the standard name, e.g., <code>std::list</code>. In
|
||||
release mode, we define only the release-mode version of the
|
||||
component with its standard name and do not include the debugging
|
||||
component at all (except, perhaps, in <code>__gnu_debug</code>, if
|
||||
requested via the separate debugging headers). This method leaves the
|
||||
behavior of release mode completely unchanged from its behavior
|
||||
prior to the introduction of the libstdc++ debug mode.</p>
|
||||
time with the standard name, e.g., <code>std::list</code>. </p>
|
||||
|
||||
<p>In debug mode we include the release-mode container into its
|
||||
natural namespace but perform renaming to an implementation-defined
|
||||
name using preprocessor macros. Thus the
|
||||
release-mode <code>std::list</code> will be renamed
|
||||
to <code>std::_Release_list</code> during debug mode, and we will
|
||||
automatically include the debugging version with the
|
||||
name <code>std::list</code> for users to reference. This method
|
||||
allows the debug- and release-mode versions of the same component to
|
||||
coexist at compile-time without causing an unreasonable maintenance
|
||||
burden.</p>
|
||||
<p>In release mode, we define only the release-mode version of the
|
||||
component with its standard name and do not include the debugging
|
||||
component at all. The release mode version is defined within the
|
||||
namespace <code>__gnu_nom</code>, and then associated with namespace
|
||||
<code>std</code> via a "strong using" directive. Minus the
|
||||
namespace associations, this method leaves the behavior of release
|
||||
mode completely unchanged from its behavior prior to the
|
||||
introduction of the libstdc++ debug mode. Here's an example of what
|
||||
this ends up looking like, in C++.</p>
|
||||
|
||||
<pre>
|
||||
namespace __gnu_norm
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
template<typename _Tp, typename _Alloc = allocator<_Tp> >
|
||||
class list
|
||||
{
|
||||
// ...
|
||||
};
|
||||
} // namespace __gnu_norm
|
||||
|
||||
namespace std
|
||||
{
|
||||
using namespace __gnu_norm __attribute__ ((strong));
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>In debug mode we include the release-mode container and also the
|
||||
debug-mode container. The release mode version is defined exactly as
|
||||
before, and the debug-mode container is defined within the namespace
|
||||
<code>__gnu_debug</code>, which is associated with namespace
|
||||
<code>std</code> via a "strong using" directive. This method allows
|
||||
the debug- and release-mode versions of the same component to coexist
|
||||
at compile-time without causing an unreasonable maintenance burden,
|
||||
while minimizing confusion. Again, this boils down to C++ code as
|
||||
follows:</p>
|
||||
|
||||
<pre>
|
||||
namespace __gnu_norm
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
template<typename _Tp, typename _Alloc = allocator<_Tp> >
|
||||
class list
|
||||
{
|
||||
// ...
|
||||
};
|
||||
} // namespace __gnu_norm
|
||||
|
||||
namespace __gnu_debug
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
template<typename _Tp, typename _Alloc = allocator<_Tp> >
|
||||
class list
|
||||
: public __gnu_norm::list<_Tp, _Alloc>,
|
||||
public __gnu_debug::_Safe_sequence<list<_Tp, _Alloc> >
|
||||
{
|
||||
// ...
|
||||
};
|
||||
} // namespace __gnu_norm
|
||||
|
||||
namespace std
|
||||
{
|
||||
using namespace __gnu_debug __attribute__ ((strong));
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h4><a name="mixing">Link- and run-time coexistence of release- and
|
||||
debug-mode components</a></h4>
|
||||
<p>There is a problem with the simple compile-time coexistence
|
||||
mechanism: if a user compiles some modules with release mode and
|
||||
some modules with debug mode, the debuggable components will differ
|
||||
in different translation units, violating the C++ One Definition
|
||||
Rule (ODR). This violation will likely be detected at link time,
|
||||
because the sizes of debug-mode containers will differ from the
|
||||
sizes of release-mode containers, although in some cases (such as
|
||||
dynamic linking) the error may be detected much later (or not at
|
||||
all!).</p>
|
||||
|
||||
<p>Unfortunately, it is not possible to avoid violating the ODR with
|
||||
most debug mode designs (see the section on <a
|
||||
href="#coexistence_alt">alternatives for coexistence</a>), so the
|
||||
philosophy of the libstdc++ debug mode is to acknowledge that there
|
||||
is an unavoidable ODR violation in this case but to ensure that the
|
||||
ODR violation does not affect execution. To accomplish this, the
|
||||
libstdc++ debug mode uses the aforementioned preprocessor renaming
|
||||
scheme but includes an additional renaming scheme that happens at
|
||||
compile-time that essentially reverses the preprocessor
|
||||
renaming <em>from the linker's point of view</em>. Thus, in debug
|
||||
mode, the release-mode <code>list</code> container is
|
||||
named <code>std::_Release_list</code> but will be mangled with the
|
||||
name <code>std::list</code> (as it was in release mode). Similarly,
|
||||
the debug-mode <code>list</code> is named <code>std::list</code>
|
||||
(in debug mode) but will be mangled
|
||||
as <code>std::_Debug_list</code>. Thus the
|
||||
release-mode <code>list</code> always compiles down to code that
|
||||
uses the name <code>std::list</code>, and the
|
||||
debug-mode <code>list</code> always compiles down to code that uses
|
||||
the name <code>std::_Debug_list</code>, independent of the use of
|
||||
debug mode. This has several positive effects:</p>
|
||||
<p>Because each component has a distinct and separate release and
|
||||
debug implementation, there are are no issues with link-time
|
||||
coexistence: the separate namespaces result in different mangled
|
||||
names, and thus unique linkage.</p>
|
||||
|
||||
<ul>
|
||||
<li>No linking conflicts between debug/release objects: because the
|
||||
names of the debug- and release-mode containers are different in the
|
||||
compiled object files, there are no link-time conflicts between the
|
||||
two.</li>
|
||||
<p>However, components that are defined and used within the C++
|
||||
standard library itself face additional constraints. For instance,
|
||||
some of the member functions of <code> std::moneypunct</code> return
|
||||
<code>std::basic_string</code>. Normally, this is not a problem, but
|
||||
with a mixed mode standard library that could be using either
|
||||
debug-mode or release-mode <code> basic_string</code> objects, things
|
||||
get more complicated. As the return value of a function is not
|
||||
encoded into the mangled name, there is no way to specify a
|
||||
release-mode or a debug-mode string. In practice, this results in
|
||||
runtime errors. A simplified example of this problem is as follows.
|
||||
</p>
|
||||
|
||||
<li>Release-mode code is shared: the release-mode code can be shared
|
||||
within a program, even with it is compiled partly in release-mode
|
||||
and partly in debug-mode, because the release-mode code is unchanged
|
||||
in name and function. This can decrease the size of mixed
|
||||
debug/release binaries.</li>
|
||||
<p> Take this translation unit, compiled in debug-mode: <p>
|
||||
<pre>
|
||||
// -D_GLIBCXX_DEBUG
|
||||
#include <string>
|
||||
|
||||
<li>Able to catch <em>most</em> invalid debug/release combinations:
|
||||
because the names of debug- and release-mode containers are
|
||||
different in the compiled object files, if a debug/release
|
||||
interaction cannot occur (e.g., because a container a translation
|
||||
unit compiled in debug mode is passed to a routine in a translation
|
||||
unit compiled in release mode) the result will be an undefined
|
||||
symbol at link time. The undefined symbol occurs because the mangled
|
||||
name of the definition will contain the release-mode container type
|
||||
and the mangled name of the reference will contain the debug-mode
|
||||
container type. However, we cannot detect these collisions if the
|
||||
only use of the container is in the return type, because the return
|
||||
type is not part of the mangled name of a function.</li>
|
||||
</ul>
|
||||
std::string test02();
|
||||
|
||||
std::string test01()
|
||||
{
|
||||
return test02();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>The new <code>link_name</code> class attribute facilities
|
||||
renaming. It may be attached to any class type (or any class
|
||||
template) to override the name of the class used for name
|
||||
mangling. For instance, a class named <code>bar</code> would
|
||||
generally mangle as <code>3bar</code>; if the class has
|
||||
a <code>link_name</code> attribute that specifies the string
|
||||
"wibble", then it would mangle as <code>6wibble</code>.</p>
|
||||
<p> ... and linked to this translation unit, compiled in release mode:</p>
|
||||
|
||||
<p>Note that although we have hidden the ODR violation, it still
|
||||
exists. For this reason we cannot easily provide safe iterators for
|
||||
<pre>
|
||||
#include <string>
|
||||
|
||||
std::string
|
||||
test02()
|
||||
{
|
||||
return std::string("toast");
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p> For this reason we cannot easily provide safe iterators for
|
||||
the <code>std::basic_string</code> class template, as it is present
|
||||
throughout the C++ standard library. For instance, locale facets
|
||||
define typedefs that include <code>basic_string</code>: in a mixed
|
||||
@ -445,7 +481,7 @@ template<typename _Tp, typename _Allocator = std::allocator<_Tp>
|
||||
release-compiled translation units is enormous.</p>
|
||||
|
||||
<h4><a name="coexistence_alt">Alternatives for Coexistence</a></h4>
|
||||
<p>The coexistence scheme was chosen over many alternatives,
|
||||
<p>The coexistence scheme above was chosen over many alternatives,
|
||||
including language-only solutions and solutions that also required
|
||||
extensions to the C++ front end. The following is a partial list of
|
||||
solutions, with justifications for our rejection of each.</p>
|
||||
@ -491,19 +527,12 @@ template<typename _Tp, typename _Allocator = std::allocator<_Tp>
|
||||
declarations disallow specialization. This method fails
|
||||
the <b>correctness</b> criteria.</li>
|
||||
|
||||
<li><em>Extension: allow template aliasing/renaming</em>: This is
|
||||
the runner-up to the <code>link_name</code> solution, eliminated
|
||||
only because it requires more extensive compiler changes
|
||||
than <code>link_name</code>. In this model, we would define the
|
||||
debug containers in a different namespace
|
||||
(e.g., <code>__gnu_debug</code>) and then import them (e.g., with
|
||||
an extended <code>using</code> declaration that aliases templates,
|
||||
such as that of <a
|
||||
href="http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1449.pdf">template
|
||||
aliases</a> proposal). This solution is workable, and in fact
|
||||
would be desirable in the long run, but requires a sizeable change
|
||||
to the C++ compiler front-end that is not within the scope of
|
||||
this project.</li>
|
||||
<li><em> Use implementation-specific properties of anonymous
|
||||
namespaces. </em>
|
||||
See <a
|
||||
href="http://gcc.gnu.org/ml/libstdc++/2003-08/msg00004.html"> this post
|
||||
</a> </li>
|
||||
This method fails the <b>correctness</b> criteria.</li>
|
||||
|
||||
<li><em>Extension: allow reopening on namespaces</em>: This would
|
||||
allow the debug mode to effectively alias the
|
||||
@ -518,6 +547,21 @@ template<typename _Tp, typename _Allocator = std::allocator<_Tp>
|
||||
recompilation</b> requirement, because we would only be able to
|
||||
support option (1) or (2).</li>
|
||||
</li>
|
||||
|
||||
<li><em>Extension: use link name</em>: This option involves
|
||||
complicated re-naming between debug-mode and release-mode
|
||||
components at compile time, and then a g++ extension called <em>
|
||||
link name </em> to recover the original names at link time. There
|
||||
are two drawbacks to this approach. One, it's very verbose,
|
||||
relying on macro renaming at compile time and several levels of
|
||||
include ordering. Two, ODR issues remained with container member
|
||||
functions taking no arguments in mixed-mode settings resulting in
|
||||
equivalent link names, <code> vector::push_back() </code> being
|
||||
one example.
|
||||
See <a
|
||||
href="http://gcc.gnu.org/ml/libstdc++/2003-08/msg00177.html">link
|
||||
name</a> </li>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Other options may exist for implementing the debug mode, many of
|
||||
|
Loading…
Reference in New Issue
Block a user