Post by Jerry QuinnI finally traced this to __locale_cache:_M_init. When
filling out the cache, there is a call to numpunct::truename(), which
is required to create a temporary string. In general, this can't be
bypassed, because it calls a virtual function that does an unknown
computation to generate this string. Only if there is no subclassing
can we avoid the creation of the string here.
To get around this, we either have to trash the cache (I REALLY hope
this doesn't happen), or restrict zero alloc to posix locale and hope
for the best.
At this point, I'm stymied. Help?
OK, I've gotten further. The following patch works with zero
allocation. But it has some other testsuite regressions. I'm going to
try to squish those tomorrow (too late now).
As before, it's not cleaned up, but comments are still welcome :-)
Jerry
Index: config/linker-map.gnu
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/config/linker-map.gnu,v
retrieving revision 1.25.2.7
diff -u -r1.25.2.7 linker-map.gnu
--- config/linker-map.gnu 7 Mar 2003 22:04:18 -0000 1.25.2.7
+++ config/linker-map.gnu 1 May 2003 05:47:38 -0000
@@ -374,6 +374,9 @@
_ZNKSt7num_putI[wc]St19ostreambuf_iteratorI[wc]St11char_traitsI[wc]EEE12_M_group_int*;
+ _ZNSt9basic_iosI[cw]St11char_traitsI[cw]EE4initEPSt15basic_streambufI[cw]S1_EPSt14__locale_cacheI[cw]E;
+
+
# vtable
_ZTVSt19__locale_cache_base;
_ZTVSt14__locale_cacheI[cw]E;
Index: include/bits/basic_ios.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/bits/basic_ios.h,v
retrieving revision 1.14.2.4
diff -u -r1.14.2.4 basic_ios.h
--- include/bits/basic_ios.h 22 Apr 2003 15:40:34 -0000 1.14.2.4
+++ include/bits/basic_ios.h 1 May 2003 05:47:40 -0000
@@ -425,8 +425,11 @@
* memory.
*/
void
+ init(basic_streambuf<_CharT, _Traits>* __sb);
+
+ void
init(basic_streambuf<_CharT, _Traits>* __sb,
- __locale_cache<_CharT>* __cache=0);
+ __locale_cache<_CharT>* __cache);
bool
_M_check_facet(const locale::facet* __f) const
@@ -437,7 +440,7 @@
}
void
- _M_cache_locale(const locale& __loc,__locale_cache<_CharT>* __cache = 0);
+ _M_cache_locale(const locale& __loc,__locale_cache<_CharT>* __cache = 0, bool __init=false);
#if 1
// XXX GLIBCXX_ABI Deprecated, compatibility only.
Index: include/bits/basic_ios.tcc
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/bits/basic_ios.tcc,v
retrieving revision 1.17.4.3
diff -u -r1.17.4.3 basic_ios.tcc
--- include/bits/basic_ios.tcc 22 Apr 2003 15:40:34 -0000 1.17.4.3
+++ include/bits/basic_ios.tcc 1 May 2003 05:47:40 -0000
@@ -144,12 +144,17 @@
template<typename _CharT, typename _Traits>
void
+ basic_ios<_CharT, _Traits>::init(basic_streambuf<_CharT, _Traits>* __sb)
+ { init(__sb, 0); }
+
+ template<typename _CharT, typename _Traits>
+ void
basic_ios<_CharT, _Traits>::init(basic_streambuf<_CharT, _Traits>* __sb,
__locale_cache<_CharT>* __cache)
{
// NB: This may be called more than once on the same object.
ios_base::_M_init();
- _M_cache_locale(_M_ios_locale, __cache);
+ _M_cache_locale(_M_ios_locale, __cache, true);
_M_tie = 0;
// NB: The 27.4.4.1 Postconditions Table specifies requirements
@@ -175,7 +180,8 @@
template<typename _CharT, typename _Traits>
void
basic_ios<_CharT, _Traits>::_M_cache_locale(const locale& __loc,
- __locale_cache<_CharT>* __cache)
+ __locale_cache<_CharT>* __cache,
+ bool __init)
{
if (__builtin_expect(has_facet<__ctype_type>(__loc), true))
_M_fctype = &use_facet<__ctype_type>(__loc);
@@ -196,14 +202,14 @@
// be deleted.
if (__cache)
{
- pword(0) = auto_ptr<__cache_t>(new (__cache) __cache_t()).release();
+ pword(0) = auto_ptr<__cache_t>(new (__cache) __cache_t(true)).release();
iword(0) = 1; // so we don't try to clobber static cache
}
else
pword(0) = auto_ptr<__cache_t>(new __cache_t()).release();
register_callback(__cache_t::_S_callback, 0);
}
- static_cast<__cache_t&>(_M_cache())._M_init(__loc);
+ static_cast<__cache_t&>(_M_cache())._M_init(__loc, __init);
}
#if 1
Index: include/bits/ios_base.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/bits/ios_base.h,v
retrieving revision 1.21.2.5
diff -u -r1.21.2.5 ios_base.h
--- include/bits/ios_base.h 5 Mar 2003 19:09:45 -0000 1.21.2.5
+++ include/bits/ios_base.h 1 May 2003 05:47:40 -0000
@@ -376,6 +376,8 @@
iostate _M_streambuf_state;
//@}
+ friend class __locale_cache_base;
+
// 27.4.2.6 Members for callbacks
// 27.4.2.6 ios_base callbacks
struct _Callback_list
Index: include/bits/locale_facets.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/bits/locale_facets.h,v
retrieving revision 1.49.4.6
diff -u -r1.49.4.6 locale_facets.h
--- include/bits/locale_facets.h 5 Mar 2003 04:40:07 -0000 1.49.4.6
+++ include/bits/locale_facets.h 1 May 2003 05:47:40 -0000
@@ -579,6 +579,7 @@
_S_format_int(const ios_base& __io, char* __fptr, char __mod, char __modl);
};
+ template<typename _CharT> class __locale_cache;
template<typename _CharT>
class numpunct : public locale::facet
@@ -590,6 +591,8 @@
static locale::id id;
+ friend class __locale_cache<_CharT>;
+
private:
char_type _M_decimal_point;
char_type _M_thousands_sep;
@@ -845,6 +848,9 @@
do_get(iter_type, iter_type, ios_base&, ios_base::iostate&, bool&) const;
#endif
+ template <typename _CharT>
+ class __string;
+
template<typename _CharT, typename _OutIter>
class num_put : public locale::facet, public __num_base
{
@@ -902,7 +908,8 @@
char __mod, _ValueT __v) const;
void
- _M_group_float(const string& __grouping, char_type __sep,
+// _M_group_float(const string& __grouping, char_type __sep,
+ _M_group_float(const __string<char>& __grouping, char_type __sep,
const char_type* __p, char_type* __new, char_type* __cs,
int& __len) const;
@@ -912,7 +919,8 @@
_ValueT __v) const;
void
- _M_group_int(const string& __grouping, char_type __sep,
+// _M_group_int(const string& __grouping, char_type __sep,
+ _M_group_int(const __string<char>& __grouping, char_type __sep,
ios_base& __io, char_type* __new, char_type* __cs,
int& __len) const;
@@ -1964,11 +1972,77 @@
// calling the virtual functions in locale facets.
class __locale_cache_base
{
+ friend class ios_base;
+
+ // Used to provide space for a callback list entry for static caches.
+ char _M_static_cblist[sizeof(ios_base::_Callback_list)];
+
public:
virtual
~__locale_cache_base() {}
};
+ // Simple string wrapper. Assumes strings are null-terminated
+ // as necessary.
+ template <typename _CharT>
+ class __string
+ {
+ typedef char_traits<_CharT> traits_type;
+
+
+ _CharT _M_buf[8];
+ _CharT* _M_bufptr;
+ int _M_buflen;
+ int _M_len;
+ public:
+ __string() : _M_bufptr(_M_buf), _M_buflen(8), _M_len(0) { _M_buf[0] = 0; }
+ __string(const _CharT* __s)
+ : _M_bufptr(_M_buf), _M_buflen(8), _M_len(traits_type::length(__s))
+ { assign(__s, _M_len); }
+ __string(const _CharT* __s, int __len)
+ : _M_bufptr(_M_buf), _M_buflen(8), _M_len(__len)
+ { assign(__s, __len); }
+ __string(const __string& __s)
+ : _M_bufptr(_M_buf), _M_buflen(8), _M_len(__len)
+ { assign(__s._M_bufptr, __s._M_len); }
+ ~__string() { if (_M_bufptr != _M_buf) delete[] _M_bufptr; }
+
+ __string& operator=(const _CharT* __s)
+ {
+ assign(__s, traits_type::length(__s));
+ return *this;
+ }
+ __string& operator=(const __string& __s)
+ {
+ assign(__s._M_bufptr, __s._M_len);
+ return *this;
+ }
+ __string& operator=(const basic_string<_CharT>& __s)
+ {
+ assign(__s.c_str(), __s.length()+1);
+ return *this;
+ }
+
+ void assign(const _CharT* __s, int __len)
+ {
+ if (__len >= _M_buflen) {
+ if (_M_bufptr != _M_buf)
+ delete[] _M_bufptr;
+ _M_bufptr = new _CharT[__len+1];
+ _M_buflen = __len+1;
+ }
+ memcpy(_M_bufptr, __s, sizeof(_CharT)*(__len+1));
+ _M_len = __len;
+ }
+
+ int length() const { return _M_len; }
+ int size() const { return _M_len; }
+
+ const _CharT* c_str() const { return _M_bufptr; }
+ _CharT operator[](int __index) const { return _M_bufptr[__index]; }
+
+ };
+
template<typename _CharT>
class __locale_cache : public __locale_cache_base
{
@@ -1977,6 +2051,14 @@
typedef char_traits<_CharT> traits_type;
typedef basic_string<_CharT> string_type;
+ // Used to play ugly games for static standard streams
+ int _M_is_static;
+
+ _CharT _M_true_buf[8];
+ _CharT _M_false_buf[8];
+ _CharT _M_group_buf[8];
+
+ public:
public:
// Data Members:
@@ -2001,8 +2083,10 @@
// However the US's "false" and "true" are translated.
// From numpunct::truename() and numpunct::falsename(), respectively.
- string_type _M_truename;
- string_type _M_falsename;
+// string_type _M_truename;
+// string_type _M_falsename;
+ __string<_CharT> _M_truename;
+ __string<_CharT> _M_falsename;
// If we are checking groupings. This should be equivalent to
// numpunct::groupings().size() != 0
@@ -2010,18 +2094,26 @@
// If we are using numpunct's groupings, this is the current grouping
// string in effect (from numpunct::grouping()).
- string _M_grouping;
+ // string _M_grouping;
+ __string<char> _M_grouping;
- __locale_cache() : _M_use_grouping(false)
+ __locale_cache(bool __is_static=false) :
+// _M_is_static(__is_static), _M_truename(_M_true_buf), _M_falsename(_M_false_buf),
+// _M_use_grouping(false), _M_grouping(_M_group_buf)
+ _M_is_static(__is_static), _M_use_grouping(false)
{ };
+// ~__locale_cache()
+// {
+// }
+
__locale_cache&
operator=(const __locale_cache& __lc);
// Make sure the cache is built before the first use.
void
- _M_init(const locale&);
+ _M_init(const locale&, bool);
// ios_base::pword callbacks come here
static void
Index: include/bits/locale_facets.tcc
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/bits/locale_facets.tcc,v
retrieving revision 1.82.4.9
diff -u -r1.82.4.9 locale_facets.tcc
--- include/bits/locale_facets.tcc 22 Apr 2003 15:40:34 -0000 1.82.4.9
+++ include/bits/locale_facets.tcc 1 May 2003 05:47:41 -0000
@@ -730,7 +730,7 @@
template<typename _CharT, typename _OutIter>
void
num_put<_CharT, _OutIter>::
- _M_group_int(const string& __grouping, _CharT __sep, ios_base& __io,
+ _M_group_int(const __string<char>& __grouping, _CharT __sep, ios_base& __io,
_CharT* __new, _CharT* __cs, int& __len) const
{
// By itself __add_grouping cannot deal correctly with __ws when
@@ -816,7 +816,7 @@
template<typename _CharT, typename _OutIter>
void
num_put<_CharT, _OutIter>::
- _M_group_float(const string& __grouping, _CharT __sep, const _CharT* __p,
+ _M_group_float(const __string<char>& __grouping, _CharT __sep, const _CharT* __p,
_CharT* __new, _CharT* __cs, int& __len) const
{
#ifdef _GLIBCPP_RESOLVE_LIB_DEFECTS
@@ -977,15 +977,20 @@
{
typedef __locale_cache<_CharT> __cache_type;
__cache_type& __lc = static_cast<__cache_type&>(__io._M_cache());
- typedef basic_string<_CharT> __string_type;
- __string_type __name;
- if (__v)
- __name = __lc._M_truename;
- else
- __name = __lc._M_falsename;
+// typedef basic_string<_CharT> __string_type;
+// __string_type __name;
+// if (__v)
+// __name = __lc._M_truename;
+// else
+// __name = __lc._M_falsename;
+// const _CharT* __cs = __name.c_str();
+// int __len = __name.size();
+
+ __string<_CharT>& __name = __v ? __lc._M_truename : __lc._M_falsename;
const _CharT* __cs = __name.c_str();
int __len = __name.size();
+
_CharT* __cs3;
streamsize __w = __io.width();
if (__w > static_cast<streamsize>(__len))
@@ -2264,18 +2269,32 @@
template<typename _CharT>
void
- __locale_cache<_CharT>::_M_init(const locale& __loc)
+ __locale_cache<_CharT>::_M_init(const locale& __loc, bool __first_init)
{
if (__builtin_expect(has_facet<numpunct<_CharT> >(__loc), true))
{
const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
- _M_falsename = __np.falsename();
- _M_truename = __np.truename();
- _M_thousands_sep = __np.thousands_sep();
- _M_decimal_point = __np.decimal_point();
- _M_grouping = __np.grouping();
- _M_use_grouping = _M_grouping.size() != 0
- && _M_grouping.data()[0] != 0;
+ if (__builtin_expect(__first_init, false))
+ {
+ _M_truename = __np._M_truename;
+ _M_falsename = __np._M_falsename;
+ _M_thousands_sep = __np._M_thousands_sep;
+ _M_decimal_point = __np._M_decimal_point;
+ _M_grouping = __np._M_grouping;
+ _M_use_grouping = _M_grouping.size() != 0 && _M_grouping[0] != 0;
+ }
+ else
+ {
+ // The normal case
+ _M_falsename = __np.falsename();
+ _M_truename = __np.truename();
+ _M_thousands_sep = __np.thousands_sep();
+ _M_decimal_point = __np.decimal_point();
+ _M_grouping = __np.grouping();
+ _M_use_grouping = _M_grouping.size() != 0
+ && _M_grouping[0] != 0;
+ // && _M_grouping.data()[0] != 0;
+ }
}
if (__builtin_expect(has_facet<ctype<_CharT> >(__loc), true))
{
Index: include/std/std_istream.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/std/std_istream.h,v
retrieving revision 1.5.2.2
diff -u -r1.5.2.2 std_istream.h
--- include/std/std_istream.h 23 Apr 2003 16:44:15 -0000 1.5.2.2
+++ include/std/std_istream.h 1 May 2003 05:47:41 -0000
@@ -107,6 +107,12 @@
_M_gcount = streamsize(0);
}
+ basic_istream(__streambuf_type* __sb, __locale_cache<_CharT>* __lc)
+ {
+ this->init(__sb, __lc);
+ _M_gcount = streamsize(0);
+ }
+
/**
* @brief Base destructor.
*
Index: include/std/std_ostream.h
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/include/std/std_ostream.h,v
retrieving revision 1.5.2.1
diff -u -r1.5.2.1 std_ostream.h
--- include/std/std_ostream.h 9 Mar 2003 02:00:53 -0000 1.5.2.1
+++ include/std/std_ostream.h 1 May 2003 05:47:42 -0000
@@ -105,6 +105,9 @@
basic_ostream(__streambuf_type* __sb)
{ this->init(__sb); }
+ basic_ostream(__streambuf_type* __sb, __locale_cache<_CharT>* __lc)
+ { this->init(__sb, __lc); }
+
/**
* @brief Base destructor.
*
Index: src/ios.cc
===================================================================
RCS file: /cvsroot/gcc/gcc/libstdc++-v3/src/ios.cc,v
retrieving revision 1.33.2.6
diff -u -r1.33.2.6 ios.cc
--- src/ios.cc 22 Apr 2003 15:40:34 -0000 1.33.2.6
+++ src/ios.cc 1 May 2003 05:47:42 -0000
@@ -182,14 +182,10 @@
new (&buf_cin) stdio_filebuf<char>(stdin, ios_base::in, __in_size);
new (&buf_cerr) stdio_filebuf<char>(stderr, ios_base::out, __out_size);
- new (&cout) ostream(&buf_cout);
- new (&cin) istream(&buf_cin);
- new (&cerr) ostream(&buf_cerr);
- new (&clog) ostream(&buf_cerr);
- cout.init(&buf_cout, &locale_cache_cout);
- cin.init(&buf_cin, &locale_cache_cin);
- cerr.init(&buf_cerr, &locale_cache_cerr);
- clog.init(&buf_cerr, &locale_cache_clog);
+ new (&cout) ostream(&buf_cout, &locale_cache_cout);
+ new (&cin) istream(&buf_cin, &locale_cache_cin);
+ new (&cerr) ostream(&buf_cerr, &locale_cache_cerr);
+ new (&clog) ostream(&buf_cerr, &locale_cache_clog);
cin.tie(&cout);
cerr.flags(ios_base::unitbuf);
@@ -197,14 +193,10 @@
new (&buf_wcout) stdio_filebuf<wchar_t>(stdout, ios_base::out, __out_size);
new (&buf_wcin) stdio_filebuf<wchar_t>(stdin, ios_base::in, __in_size);
new (&buf_wcerr) stdio_filebuf<wchar_t>(stderr, ios_base::out, __out_size);
- new (&wcout) wostream(&buf_wcout);
- new (&wcin) wistream(&buf_wcin);
- new (&wcerr) wostream(&buf_wcerr);
- new (&wclog) wostream(&buf_wcerr);
- wcout.init(&buf_wcout, &locale_cache_wcout);
- wcin.init(&buf_wcin, &locale_cache_wcin);
- wcerr.init(&buf_wcerr, &locale_cache_wcerr);
- wclog.init(&buf_wcerr, &locale_cache_wclog);
+ new (&wcout) wostream(&buf_wcout, &locale_cache_wcout);
+ new (&wcin) wistream(&buf_wcin, &locale_cache_wcin);
+ new (&wcerr) wostream(&buf_wcerr, &locale_cache_wcerr);
+ new (&wclog) wostream(&buf_wcerr, &locale_cache_wclog);
wcin.tie(&wcout);
wcerr.flags(ios_base::unitbuf);
#endif
@@ -339,7 +331,18 @@
void
ios_base::register_callback(event_callback __fn, int __index)
- { _M_callbacks = new _Callback_list(__fn, __index, _M_callbacks); }
+ {
+ // Deal with static standard streams. For these, we didn't want
+ // Callback_list objects to be created on the heap. Instead we
+ // use the buffer in the cache.
+ if (__index == 0 && iword(0) == 1)
+ {
+ char* __cb_array = _M_cache()._M_static_cblist;
+ _M_callbacks = new (__cb_array) _Callback_list(__fn, __index, _M_callbacks);
+ }
+ else
+ _M_callbacks = new _Callback_list(__fn, __index, _M_callbacks);
+ }
void
ios_base::_M_call_callbacks(event __e) throw()
@@ -362,7 +365,9 @@
while (__p && __p->_M_remove_reference() == 0)
{
_Callback_list* __next = __p->_M_next;
- delete __p;
+ // Don't delete _Callback_list that is part of a static cache.
+ if (!(__p->_M_index == 0 && iword(0) == 1))
+ delete __p;
__p = __next;
}
_M_callbacks = 0;