From: Akim Demaille Date: Fri, 25 Jul 2008 20:48:42 +0000 (+0200) Subject: Add "%define assert" to variants. X-Git-Tag: v2.7.90~1142 X-Git-Url: https://git.saurik.com/bison.git/commitdiff_plain/2d32fc9fe2e648418f253405f0be19dc903bf8c9 Add "%define assert" to variants. This is used to help the user catch cases where some value gets ovewritten by a new one. This should not happen, as this will probably leak. Unfortunately this uncovered a bug in the C++ parser itself: the lookahead value was not destroyed between two calls to yylex. For instance if the previous lookahead was a std::string, and then an int, then the value of the std::string was correctly taken (i.e., the lookahead was now an empty string), but std::string structure itself was not reclaimed. This is now done in variant::build(other&) (which is used to take the value of the lookahead): other is not only stolen from its value, it is also destroyed. This incurs a new performance penalty of a few percent, and union becomes faster again. * data/lalr1-fusion.cc (variant::build(other&)): Destroy other. (b4_variant_if): New. (variant::built): New. Use it whereever the status of the variant changes. * etc/bench.pl.in: Check the penalty of %define assert. --- diff --git a/ChangeLog b/ChangeLog index 8054b254..b7cac251 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2008-11-07 Akim Demaille + + Add "%define assert" to variants. + This is used to help the user catch cases where some value gets + ovewritten by a new one. This should not happen, as this will + probably leak. + + Unfortunately this uncovered a bug in the C++ parser itself: the + lookahead value was not destroyed between two calls to yylex. For + instance if the previous lookahead was a std::string, and then an int, + then the value of the std::string was correctly taken (i.e., the + lookahead was now an empty string), but std::string structure itself + was not reclaimed. + + This is now done in variant::build(other&) (which is used to take the + value of the lookahead): other is not only stolen from its value, it + is also destroyed. This incurs a new performance penalty of a few + percent, and union becomes faster again. + + * data/lalr1-fusion.cc (variant::build(other&)): Destroy other. + (b4_variant_if): New. + (variant::built): New. + Use it whereever the status of the variant changes. + * etc/bench.pl.in: Check the penalty of %define assert. + 2008-11-07 Akim Demaille Use "%define variant" in bench.pl. diff --git a/data/lalr1-fusion.cc b/data/lalr1-fusion.cc index 63bc1d5a..1f1129ae 100644 --- a/data/lalr1-fusion.cc +++ b/data/lalr1-fusion.cc @@ -40,6 +40,12 @@ b4_variant_if([ ]) # b4_variant_if +# b4_assert_if([IF-ASSERTIONS-ARE-USED], [IF-NOT]) +# ---------------------------------------------------- +m4_define([b4_assert_if], +[b4_percent_define_ifdef([[assert]], [$1], [$2])]) + + # b4_rhs_value(RULE-LENGTH, NUM, [TYPE]) # -------------------------------------- # Expansion of $NUM, where the current rule has RULE-LENGTH @@ -161,6 +167,7 @@ dnl FIXME: This is wrong, we want computed header guards. ]b4_percent_code_get([[requires]])[ +]b4_assert_if([#include ])[ #include #include #include "stack.hh" @@ -177,12 +184,22 @@ dnl FIXME: This is wrong, we want computed header guards. /// via the current state. template struct variant - { + {]b4_assert_if([ + /// Whether something is contained. + bool built; + + /// Initially uninitialized. + variant () + : built(false) + {}])[ + /// Instantiate a \a T in here. template inline T& build() - { + {]b4_assert_if([ + assert(!built); + built = true;])[ return *new (buffer) T; } @@ -190,7 +207,8 @@ dnl FIXME: This is wrong, we want computed header guards. template inline T& as() - { + {]b4_assert_if([ + assert(built);])[ return reinterpret_cast(buffer); } @@ -198,7 +216,8 @@ dnl FIXME: This is wrong, we want computed header guards. template inline const T& as() const - { + {]b4_assert_if([ + assert(built);])[ return reinterpret_cast(buffer); } @@ -218,6 +237,7 @@ dnl FIXME: This is wrong, we want computed header guards. { build(); swap(other); + other.destroy(); } /// Destroy the stored \a T. @@ -225,7 +245,8 @@ dnl FIXME: This is wrong, we want computed header guards. inline void destroy() { - as().~T(); + as().~T();]b4_assert_if([ + built = false;])[ } /// A buffer large enough to store any of the semantic values. diff --git a/etc/bench.pl.in b/etc/bench.pl.in index f4f5a7e5..97facb51 100755 --- a/etc/bench.pl.in +++ b/etc/bench.pl.in @@ -816,6 +816,7 @@ sub bench_variant_parser () "f-var-deb" => ['%skeleton "lalr1-fusion.cc"', '%debug', '%define variant'], "f-var-dtr" => ['%skeleton "lalr1-fusion.cc"', '%define variant', "%code {\n#define VARIANT_DESTROY\n}"], "f-var-deb-dtr" => ['%skeleton "lalr1-fusion.cc"', '%debug', '%define variant', "%code {\n#define VARIANT_DESTROY\n}"], + "f-var-deb-dtr-ass" => ['%skeleton "lalr1-fusion.cc"', '%debug', '%define variant', "%code {\n#define VARIANT_DESTROY\n}", "%define assert"], ) ); }