From 90d3233da87b372e02690978f89b2add3863fba6 Mon Sep 17 00:00:00 2001
From: David Kastrup <dak@gnu.org>
Date: Thu, 30 Apr 2015 20:48:09 +0200
Subject: [PATCH] Issue 4360: Reorganize smob initialization to make it more
 reliable

This change is a nuisance in that it requires an explicit call to
ADD_SMOB_INIT for each Scheme-related class.

However, this setup guarantees that at the point Scheme execution
commences, all predicates of the likes of "ly:grob?" will be present.
It also guarantees that if a particular type should seem required during
_other_ initializations that happen to depend on the type and get
executed earlier, it will be provided early.
---
 lily/book.cc                     |  1 +
 lily/box.cc                      |  2 ++
 lily/context-def.cc              |  2 ++
 lily/context-mod.cc              |  2 ++
 lily/context-property.cc         |  2 ++
 lily/context.cc                  |  2 ++
 lily/dispatcher.cc               |  2 ++
 lily/duration.cc                 |  2 ++
 lily/font-metric.cc              |  1 +
 lily/grob-array.cc               |  1 +
 lily/grob.cc                     |  1 +
 lily/include/smobs.hh            | 42 ++++++++++++++++----------------
 lily/include/smobs.tcc           | 22 ++++++-----------
 lily/input-smob.cc               |  2 ++
 lily/lily-lexer.cc               |  2 ++
 lily/lily-parser.cc              |  1 +
 lily/listener.cc                 |  2 ++
 lily/moment.cc                   |  2 ++
 lily/music-function.cc           |  2 ++
 lily/music-iterator.cc           |  1 +
 lily/music-output.cc             |  1 +
 lily/output-def.cc               |  2 ++
 lily/page-marker.cc              |  2 ++
 lily/paper-book.cc               |  1 +
 lily/paper-outputter.cc          |  1 +
 lily/pitch.cc                    |  2 ++
 lily/prob.cc                     |  1 +
 lily/scale.cc                    |  1 +
 lily/scheme-listener.cc          |  2 ++
 lily/scm-hash.cc                 |  2 ++
 lily/score.cc                    |  2 ++
 lily/simple-closure.cc           |  2 ++
 lily/simple-spacer.cc            |  2 ++
 lily/skyline-pair.cc             |  2 ++
 lily/skyline.cc                  |  2 ++
 lily/source-file.cc              |  2 ++
 lily/spring.cc                   |  2 ++
 lily/stencil.cc                  |  1 +
 lily/translator-dispatch-list.cc |  1 +
 lily/translator-group.cc         |  2 ++
 lily/translator.cc               |  2 ++
 lily/undead.cc                   |  2 ++
 42 files changed, 96 insertions(+), 35 deletions(-)

diff --git a/lily/book.cc b/lily/book.cc
index 8e63d889e0..e76963eaf3 100644
--- a/lily/book.cc
+++ b/lily/book.cc
@@ -33,6 +33,7 @@ using namespace std;
 #include "paper-score.hh"
 #include "page-marker.hh"
 
+ADD_SMOB_INIT (Book);
 
 Book::Book ()
 {
diff --git a/lily/box.cc b/lily/box.cc
index 629b8010fa..050824a25a 100644
--- a/lily/box.cc
+++ b/lily/box.cc
@@ -19,6 +19,8 @@
 
 #include "box.hh"
 
+ADD_SMOB_INIT (Box);
+
 void
 Box::translate (Offset o)
 {
diff --git a/lily/context-def.cc b/lily/context-def.cc
index 10f31ae830..b2aaedf44a 100644
--- a/lily/context-def.cc
+++ b/lily/context-def.cc
@@ -29,6 +29,8 @@
 #include "translator.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Context_def);
+
 Context_def::Context_def ()
 {
   context_aliases_ = SCM_EOL;
diff --git a/lily/context-mod.cc b/lily/context-mod.cc
index fd2a25d2fe..b9c43fe76a 100644
--- a/lily/context-mod.cc
+++ b/lily/context-mod.cc
@@ -19,6 +19,8 @@
 
 #include "context-mod.hh"
 
+ADD_SMOB_INIT (Context_mod);
+
 Context_mod::Context_mod ()
 {
   mods_ = SCM_EOL;
diff --git a/lily/context-property.cc b/lily/context-property.cc
index 59bcf9afc6..7a605352fd 100644
--- a/lily/context-property.cc
+++ b/lily/context-property.cc
@@ -94,6 +94,8 @@ private:
     cooked_ (alist), cooked_from_ (alist), nested_ (0) { }
 };
 
+ADD_SMOB_INIT (Grob_properties);
+
 const char Grob_properties::type_p_name_[] = "ly:grob-properties?";
 
 SCM
diff --git a/lily/context.cc b/lily/context.cc
index 9dad38f269..1d8efed630 100644
--- a/lily/context.cc
+++ b/lily/context.cc
@@ -31,6 +31,8 @@
 #include "translator-group.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Context);
+
 bool
 Context::is_removable () const
 {
diff --git a/lily/dispatcher.cc b/lily/dispatcher.cc
index efb3ca506c..b76e76c35c 100644
--- a/lily/dispatcher.cc
+++ b/lily/dispatcher.cc
@@ -22,6 +22,8 @@
 #include "international.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Dispatcher);
+
 const char Dispatcher::type_p_name_[] = "ly:dispatcher?";
 
 Dispatcher::~Dispatcher ()
diff --git a/lily/duration.cc b/lily/duration.cc
index 4768f015b5..78ae045a88 100644
--- a/lily/duration.cc
+++ b/lily/duration.cc
@@ -20,6 +20,8 @@
 
 #include "duration.hh"
 
+ADD_SMOB_INIT (Duration);
+
 #include "misc.hh"
 #include "lily-proto.hh"
 
diff --git a/lily/font-metric.cc b/lily/font-metric.cc
index f18b2d7256..be071fe912 100644
--- a/lily/font-metric.cc
+++ b/lily/font-metric.cc
@@ -29,6 +29,7 @@ using namespace std;
 #include "stencil.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Font_metric);
 
 Real
 Font_metric::design_size () const
diff --git a/lily/grob-array.cc b/lily/grob-array.cc
index 2747e0d77f..f267ce5a44 100644
--- a/lily/grob-array.cc
+++ b/lily/grob-array.cc
@@ -21,6 +21,7 @@
 #include "item.hh"
 #include "spanner.hh"
 
+ADD_SMOB_INIT (Grob_array);
 
 Item *
 Grob_array::item (vsize i)
diff --git a/lily/grob.cc b/lily/grob.cc
index 435a6faff3..8cfb14d539 100644
--- a/lily/grob.cc
+++ b/lily/grob.cc
@@ -39,6 +39,7 @@
 #include "unpure-pure-container.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Grob);
 
 Grob *
 Grob::clone () const
diff --git a/lily/include/smobs.hh b/lily/include/smobs.hh
index 3ee2ef80ab..eeb385e1a2 100644
--- a/lily/include/smobs.hh
+++ b/lily/include/smobs.hh
@@ -127,37 +127,26 @@
 
 */
 
-// Initialization class.  Create a variable or static data member of
-// this type at global scope (or creation will happen too late for
-// Scheme initialization), initialising with a function to be called.
-// Reference somewhere (like in the constructor of the containing
-// class) to make sure the variable is actually instantiated.
-
-class Scm_init {
-public:
-  Scm_init () { }
-  Scm_init (void (*fun) (void))
-  {
-    add_scm_init_func (fun);
-  }
-};
-
 template <class Super>
 class Smob_base
 {
   static scm_t_bits smob_tag_;
-  static Scm_init scm_init_;
-  static void init (void);
+  static scm_t_bits init_id (void);
   static string smob_name_;
   static Super *unchecked_unsmob (SCM s)
   {
     return reinterpret_cast<Super *> (SCM_SMOB_DATA (s));
   }
 protected:
-  // reference scm_init_ in smob_tag which is sure to be called.  The
-  // constructor, in contrast, may not be called at all in classes
-  // like Smob1.
-  static scm_t_bits smob_tag () { (void) scm_init_; return smob_tag_; }
+  // This is an initialization with side effect.  It is called once,
+  // the first time smob_tag is actually getting called.  This
+  // allocates and initializes the type before it is first used for
+  // anything.
+  static scm_t_bits smob_tag ()
+  {
+    static scm_t_bits tag = init_id ();
+    return tag;
+  }
   Smob_base () { }
   static SCM register_ptr (Super *p);
   static Super *unregister_ptr (SCM obj);
@@ -217,6 +206,17 @@ private:
   static const int smob_proc_signature_ = -1;
 
 public:
+  static void init (void)
+  {
+    // This is stupid, but without forcing initialization at the
+    // Scheme startup hook stage, stuff like ly:undead? will not be
+    // defined when the first Scheme files are loaded.
+    //
+    // So we provide an explicit initialization routine that can be
+    // used with ADD_SCM_INIT_FUNC
+    (void) smob_tag ();
+  }
+#define ADD_SMOB_INIT(type) ADD_SCM_INIT_FUNC (Smob_init_ ## type, Smob_base<type>::init)
   static bool is_smob (SCM s)
   {
     return SCM_SMOB_PREDICATE (smob_tag (), s);
diff --git a/lily/include/smobs.tcc b/lily/include/smobs.tcc
index b4dacacaa3..097047e32b 100644
--- a/lily/include/smobs.tcc
+++ b/lily/include/smobs.tcc
@@ -106,17 +106,11 @@ Smob_base<Super>::unregister_ptr (SCM obj)
   return p;
 }
 
-template <class Super>
-scm_t_bits Smob_base<Super>::smob_tag_ = 0;
-
-template <class Super>
-Scm_init Smob_base<Super>::scm_init_ = init;
-
 template <class Super>
 string Smob_base<Super>::smob_name_;
 
 template <class Super>
-void Smob_base<Super>::init ()
+scm_t_bits Smob_base<Super>::init_id ()
 {
   smob_name_ = typeid (Super).name ();
   // Primitive demangling, suitable for GCC, should be harmless
@@ -124,8 +118,7 @@ void Smob_base<Super>::init ()
   // unsuitable for Texinfo documentation.  If that proves to be an
   // issue, we need some smarter strategy.
   smob_name_ = smob_name_.substr (smob_name_.find_first_not_of ("0123456789"));
-  assert(!smob_tag_);
-  smob_tag_ = scm_make_smob_type (smob_name_.c_str (), 0);
+  scm_t_bits smob_tag = scm_make_smob_type (smob_name_.c_str (), 0);
   // The following have trivial private default definitions not
   // referring to any aspect of the Super class apart from its name.
   // They should be overridden (or rather masked) at Super level: that
@@ -134,7 +127,7 @@ void Smob_base<Super>::init ()
   // doing it like the rest.
 
   if (&Super::free_smob != &Smob_base<Super>::free_smob)
-    scm_set_smob_free (smob_tag_, Super::free_smob);
+    scm_set_smob_free (smob_tag, Super::free_smob);
   // Old GCC versions get their type lattice for pointers-to-members
   // tangled up to a degree where we need to typecast _both_ covariant
   // types in order to be able to compare them.  The other comparisons
@@ -142,10 +135,10 @@ void Smob_base<Super>::init ()
   // pointers which work without those contortions.
   if (static_cast<SCM (Super::*)()>(&Super::mark_smob) !=
       static_cast<SCM (Super::*)()>(&Smob_base<Super>::mark_smob))
-    scm_set_smob_mark (smob_tag_, Super::mark_trampoline);
-  scm_set_smob_print (smob_tag_, Super::print_trampoline);
+    scm_set_smob_mark (smob_tag, Super::mark_trampoline);
+  scm_set_smob_print (smob_tag, Super::print_trampoline);
   if (&Super::equal_p != &Smob_base<Super>::equal_p)
-    scm_set_smob_equalp (smob_tag_, Super::equal_p);
+    scm_set_smob_equalp (smob_tag, Super::equal_p);
   if (Super::type_p_name_ != 0)
     {
       SCM subr = scm_c_define_gsubr (Super::type_p_name_, 1, 0, 0,
@@ -158,10 +151,11 @@ void Smob_base<Super>::init ()
     }
   ly_add_type_predicate ((void *) is_smob, smob_name_.c_str ());
   if (Super::smob_proc_signature_ >= 0)
-    scm_set_smob_apply (smob_tag_,
+    scm_set_smob_apply (smob_tag,
                         (scm_t_subr)Super::smob_proc,
                         Super::smob_proc_signature_ >> 8,
                         (Super::smob_proc_signature_ >> 4)&0xf,
                         Super::smob_proc_signature_ & 0xf);
+  return smob_tag;
 }
 #endif
diff --git a/lily/input-smob.cc b/lily/input-smob.cc
index 0a33bd6a59..f6a3b7a773 100644
--- a/lily/input-smob.cc
+++ b/lily/input-smob.cc
@@ -21,6 +21,8 @@
 #include "source-file.hh"
 #include "std-string.hh"
 
+ADD_SMOB_INIT (Input);
+
 
 /* Dummy input location for use if real one is missing.  */
 Input dummy_input_global;
diff --git a/lily/lily-lexer.cc b/lily/lily-lexer.cc
index 3bb7921b2b..7785ede296 100644
--- a/lily/lily-lexer.cc
+++ b/lily/lily-lexer.cc
@@ -36,6 +36,8 @@ using namespace std;
 #include "program-option.hh"
 #include "lily-parser.hh"
 
+ADD_SMOB_INIT (Lily_lexer);
+
 static Keyword_ent the_key_tab[]
 =
 {
diff --git a/lily/lily-parser.cc b/lily/lily-parser.cc
index 2d006f8d78..4bba3e445b 100644
--- a/lily/lily-parser.cc
+++ b/lily/lily-parser.cc
@@ -37,6 +37,7 @@
 #include "warn.hh"
 #include "program-option.hh"
 
+ADD_SMOB_INIT (Lily_parser);
 
 Lily_parser::Lily_parser (Sources *sources)
 {
diff --git a/lily/listener.cc b/lily/listener.cc
index 50f1969ecb..4194c83618 100644
--- a/lily/listener.cc
+++ b/lily/listener.cc
@@ -20,6 +20,8 @@
 #include "listener.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Listener);
+
 Listener::Listener ()
 {
   target_ = 0;
diff --git a/lily/moment.cc b/lily/moment.cc
index 9f3e8ed383..cd82c8a597 100644
--- a/lily/moment.cc
+++ b/lily/moment.cc
@@ -21,6 +21,8 @@
 
 #include "warn.hh"
 
+ADD_SMOB_INIT (Moment);
+
 Moment::Moment ()
 {
 }
diff --git a/lily/music-function.cc b/lily/music-function.cc
index 35341e3c6d..a20af4d0a2 100644
--- a/lily/music-function.cc
+++ b/lily/music-function.cc
@@ -19,6 +19,8 @@
 
 #include "music-function.hh"
 
+ADD_SMOB_INIT (Music_function);
+
 const char Music_function::type_p_name_[] = "ly:music-function?";
 
 /* Print a textual represenation of the smob to a given port.  */
diff --git a/lily/music-iterator.cc b/lily/music-iterator.cc
index 8eb238c295..ed778323b9 100644
--- a/lily/music-iterator.cc
+++ b/lily/music-iterator.cc
@@ -30,6 +30,7 @@ using namespace std;
 #include "music-wrapper-iterator.hh"
 #include "simple-music-iterator.hh"
 
+ADD_SMOB_INIT (Music_iterator);
 
 Music_iterator::Music_iterator ()
 {
diff --git a/lily/music-output.cc b/lily/music-output.cc
index 0907bf38f4..8e03177bf4 100644
--- a/lily/music-output.cc
+++ b/lily/music-output.cc
@@ -19,6 +19,7 @@
 
 #include "music-output.hh"
 
+ADD_SMOB_INIT (Music_output);
 
 Music_output::Music_output ()
 {
diff --git a/lily/output-def.cc b/lily/output-def.cc
index af407fb70a..525ccd975e 100644
--- a/lily/output-def.cc
+++ b/lily/output-def.cc
@@ -34,6 +34,8 @@
 
 #include "string-convert.hh"
 
+ADD_SMOB_INIT (Output_def);
+
 Output_def::Output_def ()
 {
   scope_ = SCM_EOL;
diff --git a/lily/page-marker.cc b/lily/page-marker.cc
index 1e393862e6..88eb975304 100644
--- a/lily/page-marker.cc
+++ b/lily/page-marker.cc
@@ -19,6 +19,8 @@
 
 #include "page-marker.hh"
 
+ADD_SMOB_INIT (Page_marker);
+
 Page_marker::Page_marker ()
 {
   symbol_ = SCM_EOL;
diff --git a/lily/paper-book.cc b/lily/paper-book.cc
index 7dce3a9507..00917966e5 100644
--- a/lily/paper-book.cc
+++ b/lily/paper-book.cc
@@ -31,6 +31,7 @@
 #include "program-option.hh"
 #include "page-marker.hh"
 
+ADD_SMOB_INIT (Paper_book);
 
 Paper_book::Paper_book ()
 {
diff --git a/lily/paper-outputter.cc b/lily/paper-outputter.cc
index 269e1e294c..e8f1d821aa 100644
--- a/lily/paper-outputter.cc
+++ b/lily/paper-outputter.cc
@@ -38,6 +38,7 @@ using namespace std;
 #include "string-convert.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Paper_outputter);
 
 Paper_outputter::Paper_outputter (SCM port, const string &format)
 {
diff --git a/lily/pitch.cc b/lily/pitch.cc
index 0fd7512947..4c5cb79e37 100644
--- a/lily/pitch.cc
+++ b/lily/pitch.cc
@@ -26,6 +26,8 @@
 
 #include <cmath>
 
+ADD_SMOB_INIT (Pitch);
+
 Pitch::Pitch (int o, int n, Rational a)
 {
   notename_ = n;
diff --git a/lily/prob.cc b/lily/prob.cc
index 37dad6246b..57f6b2f4d5 100644
--- a/lily/prob.cc
+++ b/lily/prob.cc
@@ -23,6 +23,7 @@
 #include "input.hh"
 #include "profile.hh"
 
+ADD_SMOB_INIT (Prob);
 
 const char Prob::type_p_name_[] = "ly:prob?";
 
diff --git a/lily/scale.cc b/lily/scale.cc
index a5afd41dae..57406f0af0 100644
--- a/lily/scale.cc
+++ b/lily/scale.cc
@@ -21,6 +21,7 @@
 
 #include "scale.hh"
 
+ADD_SMOB_INIT (Scale);
 
 /*
   todo: put string <-> pitch here too.
diff --git a/lily/scheme-listener.cc b/lily/scheme-listener.cc
index 9df6960bdf..8a9e175f5c 100644
--- a/lily/scheme-listener.cc
+++ b/lily/scheme-listener.cc
@@ -19,6 +19,8 @@
 
 #include "scheme-listener.hh"
 
+ADD_SMOB_INIT (Scheme_listener);
+
 IMPLEMENT_LISTENER (Scheme_listener, call)
 void
 Scheme_listener::call (SCM ev)
diff --git a/lily/scm-hash.cc b/lily/scm-hash.cc
index 5eb048f6d1..c5a8959548 100644
--- a/lily/scm-hash.cc
+++ b/lily/scm-hash.cc
@@ -23,6 +23,8 @@
 #include <algorithm>
 using namespace std;
 
+ADD_SMOB_INIT (Scheme_hash_table);
+
 
 /*
   Return: number of objects.
diff --git a/lily/score.cc b/lily/score.cc
index 5ce7e3ba95..9210766c77 100644
--- a/lily/score.cc
+++ b/lily/score.cc
@@ -19,6 +19,8 @@
 
 #include "score.hh"
 
+ADD_SMOB_INIT (Score);
+
 #include <cstdio>
 
 using namespace std;
diff --git a/lily/simple-closure.cc b/lily/simple-closure.cc
index b62649f06d..0ef57ded6e 100644
--- a/lily/simple-closure.cc
+++ b/lily/simple-closure.cc
@@ -22,6 +22,8 @@
 
 #include "grob.hh"
 
+ADD_SMOB_INIT (Simple_closure);
+
 SCM
 evaluate_args (SCM delayed_argument, SCM args, bool pure, int start, int end)
 {
diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc
index ada16593aa..ce587c5fdd 100644
--- a/lily/simple-spacer.cc
+++ b/lily/simple-spacer.cc
@@ -32,6 +32,8 @@
 #include "spring.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Simple_spacer);
+
 /*
   A simple spacing constraint solver. The approach:
 
diff --git a/lily/skyline-pair.cc b/lily/skyline-pair.cc
index 92ae97a342..005b9b77cf 100644
--- a/lily/skyline-pair.cc
+++ b/lily/skyline-pair.cc
@@ -22,6 +22,8 @@
 
 #include "international.hh"
 
+ADD_SMOB_INIT (Skyline_pair);
+
 Skyline_pair::Skyline_pair ()
   : skylines_ (Skyline (DOWN), Skyline (UP))
 {
diff --git a/lily/skyline.cc b/lily/skyline.cc
index 42a028fe0a..ef284e7131 100644
--- a/lily/skyline.cc
+++ b/lily/skyline.cc
@@ -65,6 +65,8 @@
    Alert to these considerations, we now accept buildings of zero-width.
 */
 
+ADD_SMOB_INIT (Skyline);
+
 static void
 print_buildings (list<Building> const &b)
 {
diff --git a/lily/source-file.cc b/lily/source-file.cc
index 1118b9d286..67690289b9 100644
--- a/lily/source-file.cc
+++ b/lily/source-file.cc
@@ -42,6 +42,8 @@ using namespace std;
 #include "misc.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Source_file);
+
 void
 Source_file::load_stdin ()
 {
diff --git a/lily/spring.cc b/lily/spring.cc
index d1640e72b9..3d3dfff5fb 100644
--- a/lily/spring.cc
+++ b/lily/spring.cc
@@ -36,6 +36,8 @@
 
 #include "spring.hh"
 
+ADD_SMOB_INIT (Spring);
+
 Spring::Spring ()
 {
   distance_ = 1.0;
diff --git a/lily/stencil.cc b/lily/stencil.cc
index 980618ceaa..b162280829 100644
--- a/lily/stencil.cc
+++ b/lily/stencil.cc
@@ -25,6 +25,7 @@
 #include "string-convert.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Stencil);
 
 Stencil::Stencil ()
 {
diff --git a/lily/translator-dispatch-list.cc b/lily/translator-dispatch-list.cc
index ed968c571a..02de105da9 100644
--- a/lily/translator-dispatch-list.cc
+++ b/lily/translator-dispatch-list.cc
@@ -20,6 +20,7 @@
 #include "translator-dispatch-list.hh"
 #include "engraver.hh"
 
+ADD_SMOB_INIT (Engraver_dispatch_list);
 
 void
 Engraver_dispatch_list::apply (Grob_info gi)
diff --git a/lily/translator-group.cc b/lily/translator-group.cc
index 2e6039a9af..f8818462c6 100644
--- a/lily/translator-group.cc
+++ b/lily/translator-group.cc
@@ -35,6 +35,8 @@
 #include "scm-hash.hh"
 #include "warn.hh"
 
+ADD_SMOB_INIT (Translator_group);
+
 void
 translator_each (SCM list, Translator_method method)
 {
diff --git a/lily/translator.cc b/lily/translator.cc
index d6874ef78c..a1053c5725 100644
--- a/lily/translator.cc
+++ b/lily/translator.cc
@@ -28,6 +28,8 @@
 
 #include "translator.icc"
 
+ADD_SMOB_INIT (Translator);
+
 Translator::~Translator ()
 {
 }
diff --git a/lily/undead.cc b/lily/undead.cc
index d6e3d550d1..9adc5e6fd0 100644
--- a/lily/undead.cc
+++ b/lily/undead.cc
@@ -32,6 +32,8 @@ public:
   Undead (SCM object = SCM_UNDEFINED) : object_ (object) { };
 };
 
+ADD_SMOB_INIT (Undead);
+
 SCM
 Undead::mark_smob ()
 {
-- 
2.39.5