[HarfBuzz] harfbuzz: Branch 'master' - 16 commits

Behdad Esfahbod behdad at kemper.freedesktop.org
Mon Aug 13 00:37:15 UTC 2018


 src/hb-ft.cc                |  114 ++++++++++++--------------
 src/hb-glib.cc              |   50 +++++------
 src/hb-icu.cc               |   59 +++++--------
 src/hb-machinery-private.hh |  192 +++++++++++++++++++++++++++++---------------
 src/hb-ot-font.cc           |   57 +++++--------
 src/hb-ot-layout-private.hh |    2 
 src/hb-shape.cc             |   75 ++++++++---------
 src/hb-shaper.cc            |   78 ++++++++---------
 src/hb-ucdn.cc              |   51 +++++------
 src/hb-uniscribe.cc         |    3 
 10 files changed, 356 insertions(+), 325 deletions(-)

New commits:
commit 747d2564e6bdcc15cf6a197e543fb732924159c5
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 17:32:10 2018 -0700

    [lazy] Port more

diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index 2a7ef7ba..a179eea9 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -698,7 +698,6 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   inline Returned * get_unconst (void) const { return const_cast<Returned *> (Funcs::convert (get_stored ())); }
 
   /* To be possibly overloaded by subclasses. */
-  static inline const Returned* convert (const Stored *p) { return p; }
   static inline Returned* convert (Stored *p) { return p; }
 
   /* By default null/init/fini the object. */
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index e487582e..e423f255 100644
--- a/src/hb-shaper.cc
+++ b/src/hb-shaper.cc
@@ -26,7 +26,7 @@
 
 #include "hb-private.hh"
 #include "hb-shaper-private.hh"
-#include "hb-atomic-private.hh"
+#include "hb-machinery-private.hh"
 
 
 static const hb_shaper_pair_t all_shapers[] = {
@@ -36,52 +36,28 @@ static const hb_shaper_pair_t all_shapers[] = {
 };
 
 
-/* Thread-safe, lock-free, shapers */
+static void free_static_shapers (void);
 
-static hb_atomic_ptr_t<const hb_shaper_pair_t> static_shapers;
-
-#ifdef HB_USE_ATEXIT
-static
-void free_static_shapers (void)
+static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t,
+							  hb_shapers_lazy_loader_t>
 {
-retry:
-  const hb_shaper_pair_t *shapers = static_shapers.get ();
-  if (unlikely (!static_shapers.cmpexch (shapers, nullptr)))
-    goto retry;
-
-  if (unlikely (shapers != all_shapers))
-    free ((void *) shapers);
-}
-#endif
-
-const hb_shaper_pair_t *
-_hb_shapers_get (void)
-{
-retry:
-  hb_shaper_pair_t *shapers = const_cast<hb_shaper_pair_t *> (static_shapers.get ());
-
-  if (unlikely (!shapers))
+  static inline hb_shaper_pair_t *create (void)
   {
     char *env = getenv ("HB_SHAPER_LIST");
-    if (!env || !*env) {
-      (void) static_shapers.cmpexch (nullptr, &all_shapers[0]);
-      return (const hb_shaper_pair_t *) all_shapers;
-    }
+    if (!env || !*env)
+      return nullptr;
 
-    /* Not found; allocate one. */
-    shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
+    hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
     if (unlikely (!shapers))
-    {
-      (void) static_shapers.cmpexch (nullptr, &all_shapers[0]);
-      return (const hb_shaper_pair_t *) all_shapers;
-    }
+      return nullptr;
 
     memcpy (shapers, all_shapers, sizeof (all_shapers));
 
      /* Reorder shaper list to prefer requested shapers. */
     unsigned int i = 0;
     char *end, *p = env;
-    for (;;) {
+    for (;;)
+    {
       end = strchr (p, ',');
       if (!end)
 	end = p + strlen (p);
@@ -103,16 +79,32 @@ retry:
 	p = end + 1;
     }
 
-    if (unlikely (!static_shapers.cmpexch (nullptr, shapers)))
-    {
-      free (shapers);
-      goto retry;
-    }
-
 #ifdef HB_USE_ATEXIT
-    atexit (free_static_shapers); /* First person registers atexit() callback. */
+    atexit (free_static_shapers);
 #endif
+
+    return shapers;
+  }
+  static inline void destroy (const hb_shaper_pair_t *p)
+  {
+    free ((void *) p);
   }
+  static inline const hb_shaper_pair_t *get_null (void)
+  {
+    return all_shapers;
+  }
+} static_shapers;
 
-  return shapers;
+#ifdef HB_USE_ATEXIT
+static
+void free_static_shapers (void)
+{
+  static_shapers.free_instance ();
+}
+#endif
+
+const hb_shaper_pair_t *
+_hb_shapers_get (void)
+{
+  return static_shapers.get_unconst ();
 }
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 22beb909..5810977d 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -190,7 +190,8 @@ hb_ScriptPlaceOpenType(
 }
 
 
-struct hb_uniscribe_shaper_funcs_t {
+struct hb_uniscribe_shaper_funcs_t
+{
   SIOT ScriptItemizeOpenType;
   SSOT ScriptShapeOpenType;
   SPOT ScriptPlaceOpenType;
commit 7bd508a0c4ce426f474bfcc729cb39207dd1f7b4
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 17:19:55 2018 -0700

    [lazy] Rename free()

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index e716ec91..01341b60 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -454,7 +454,7 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
 static
 void free_static_ft_funcs (void)
 {
-  static_ft_funcs.free ();
+  static_ft_funcs.free_instance ();
 }
 #endif
 
@@ -714,7 +714,7 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<FT_
 static
 void free_static_ft_library (void)
 {
-  static_ft_library.free ();
+  static_ft_library.free_instance ();
 }
 #endif
 
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index af7a0fd3..342891d9 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -394,7 +394,7 @@ static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
 static
 void free_static_glib_funcs (void)
 {
-  static_glib_funcs.free ();
+  static_glib_funcs.free_instance ();
 }
 #endif
 
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 551069fa..380a99c8 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -383,7 +383,7 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_
 static
 void free_static_icu_funcs (void)
 {
-  static_icu_funcs.free ();
+  static_icu_funcs.free_instance ();
 }
 #endif
 
diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index e60e3bec..2a7ef7ba 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -637,7 +637,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   {
     do_destroy (instance.get ());
   }
-  inline void free (void)
+  inline void free_instance (void)
   {
   retry:
     Stored *p = instance.get ();
@@ -720,7 +720,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   static inline void destroy (Stored *p)
   {
     p->fini ();
-    ::free (p);
+    free (p);
   }
 
   private:
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 0b14ff1e..9da8fc7d 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -264,7 +264,7 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
 static
 void free_static_ot_funcs (void)
 {
-  static_ot_funcs.free ();
+  static_ot_funcs.free_instance ();
 }
 #endif
 
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 22a2020b..86aa59ab 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -50,7 +50,7 @@
 static void free_static_shaper_list (void);
 
 static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
-							     hb_shaper_list_lazy_loader_t>
+							      hb_shaper_list_lazy_loader_t>
 {
   static inline const char ** create (void)
   {
@@ -72,7 +72,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
   }
   static inline void destroy (const char **l)
   {
-    ::free (l);
+    free (l);
   }
   static inline const char ** get_null (void)
   {
@@ -85,7 +85,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
 static
 void free_static_shaper_list (void)
 {
-  static_shaper_list.free ();
+  static_shaper_list.free_instance ();
 }
 #endif
 
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index 6b1bb804..7b26e512 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -267,7 +267,7 @@ static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
 static
 void free_static_ucdn_funcs (void)
 {
-  static_ucdn_funcs.free ();
+  static_ucdn_funcs.free_instance ();
 }
 #endif
 
commit a3b97db910662e26bafe6e6bc1c36b437f4ed931
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 17:14:32 2018 -0700

    [lazy] Port more to it

diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 01734f8f..22a2020b 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -32,6 +32,7 @@
 #include "hb-shape-plan-private.hh"
 #include "hb-buffer-private.hh"
 #include "hb-font-private.hh"
+#include "hb-machinery-private.hh"
 
 /**
  * SECTION:hb-shape
@@ -45,21 +46,50 @@
  * contains the output glyphs and their positions.
  **/
 
-static hb_atomic_ptr_t <const char **> static_shaper_list;
+
+static void free_static_shaper_list (void);
+
+static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
+							     hb_shaper_list_lazy_loader_t>
+{
+  static inline const char ** create (void)
+  {
+    const char **shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
+    if (unlikely (!shaper_list))
+      return nullptr;
+
+    const hb_shaper_pair_t *shapers = _hb_shapers_get ();
+    unsigned int i;
+    for (i = 0; i < HB_SHAPERS_COUNT; i++)
+      shaper_list[i] = shapers[i].name;
+    shaper_list[i] = nullptr;
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_shaper_list);
+#endif
+
+    return shaper_list;
+  }
+  static inline void destroy (const char **l)
+  {
+    ::free (l);
+  }
+  static inline const char ** get_null (void)
+  {
+    static const char *nil_shaper_list[] = {nullptr};
+    return nil_shaper_list;
+  }
+} static_shaper_list;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_shaper_list (void)
 {
-retry:
-  const char **shaper_list = static_shaper_list.get ();
-  if (unlikely (!static_shaper_list.cmpexch (shaper_list, nullptr)))
-    goto retry;
-
-  free (shaper_list);
+  static_shaper_list.free ();
 }
 #endif
 
+
 /**
  * hb_shape_list_shapers:
  *
@@ -73,36 +103,7 @@ retry:
 const char **
 hb_shape_list_shapers (void)
 {
-retry:
-  const char **shaper_list = static_shaper_list.get ();
-
-  if (unlikely (!shaper_list))
-  {
-    /* Not found; allocate one. */
-    shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
-    if (unlikely (!shaper_list)) {
-      static const char *nil_shaper_list[] = {nullptr};
-      return nil_shaper_list;
-    }
-
-    const hb_shaper_pair_t *shapers = _hb_shapers_get ();
-    unsigned int i;
-    for (i = 0; i < HB_SHAPERS_COUNT; i++)
-      shaper_list[i] = shapers[i].name;
-    shaper_list[i] = nullptr;
-
-    if (unlikely (!static_shaper_list.cmpexch (nullptr, shaper_list)))
-    {
-      free (shaper_list);
-      goto retry;
-    }
-
-#ifdef HB_USE_ATEXIT
-    atexit (free_static_shaper_list); /* First person registers atexit() callback. */
-#endif
-  }
-
-  return shaper_list;
+  return static_shaper_list.get_unconst ();
 }
 
 
commit 6901090945d7e16102f3a2b168465434032b9a09
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 16:57:06 2018 -0700

    [lazy] Make hb_lazy_loader_t<> more usable

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index eea2da13..e716ec91 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -685,9 +685,8 @@ hb_ft_font_create_referenced (FT_Face ft_face)
 
 static void free_static_ft_library (void);
 
-static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_ft_library_lazy_loader_t,
-							     void, 0,
-							     hb_remove_ptr_t<FT_Library>::value>
+static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<FT_Library>::value,
+							     hb_ft_library_lazy_loader_t>
 {
   static inline FT_Library create (void)
   {
@@ -705,7 +704,7 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_ft_library_lazy_
   {
     FT_Done_FreeType (l);
   }
-  static inline const FT_Library get_null (void)
+  static inline FT_Library get_null (void)
   {
     return nullptr;
   }
diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index d40f9d9c..e60e3bec 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -610,20 +610,27 @@ struct hb_data_wrapper_t
 template <>
 struct hb_data_wrapper_t<void, 0>
 {
-  template <typename Stored, typename Subclass>
+  template <typename Stored, typename Funcs>
   inline Stored * call_create (void) const
   {
-    return Subclass::create ();
+    return Funcs::create ();
   }
 };
 
-template <typename Subclass,
-	  typename Data,
-	  unsigned int WheresData,
-	  typename Returned,
+template <typename T1, typename T2> struct hb_non_void_t { typedef T1 value; };
+template <typename T2> struct hb_non_void_t<void, T2> { typedef T2 value; };
+
+template <typename Returned,
+	  typename Subclass = void,
+	  typename Data = void,
+	  unsigned int WheresData = 0,
 	  typename Stored = Returned>
 struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 {
+  typedef typename hb_non_void_t<Subclass,
+				 hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored>
+				>::value Funcs;
+
   inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
   inline void init (void) { instance.set_relaxed (nullptr); }
   inline void fini (void)
@@ -641,15 +648,15 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 
   inline Stored * do_create (void) const
   {
-    Stored *p = this->template call_create<Stored, Subclass> ();
+    Stored *p = this->template call_create<Stored, Funcs> ();
     if (unlikely (!p))
-      p = const_cast<Stored *> (Subclass::get_null ());
+      p = const_cast<Stored *> (Funcs::get_null ());
     return p;
   }
   static inline void do_destroy (Stored *p)
   {
-    if (p && p != Subclass::get_null ())
-      Subclass::destroy (p);
+    if (p && p != Funcs::get_null ())
+      Funcs::destroy (p);
   }
 
   inline const Returned * operator -> (void) const { return get (); }
@@ -687,8 +694,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
     do_destroy (p);
   }
 
-  inline const Returned * get (void) const { return Subclass::convert (get_stored ()); }
-  inline Returned * get_unconst (void) const { return const_cast<Returned *> (Subclass::convert (get_stored ())); }
+  inline const Returned * get (void) const { return Funcs::convert (get_stored ()); }
+  inline Returned * get_unconst (void) const { return const_cast<Returned *> (Funcs::convert (get_stored ())); }
 
   /* To be possibly overloaded by subclasses. */
   static inline const Returned* convert (const Stored *p) { return p; }
@@ -703,6 +710,13 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
       p->init (data);
     return p;
   }
+  static inline Stored *create (void)
+  {
+    Stored *p = (Stored *) calloc (1, sizeof (Stored));
+    if (likely (p))
+      p->init ();
+    return p;
+  }
   static inline void destroy (Stored *p)
   {
     p->fini ();
@@ -717,14 +731,15 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 /* Specializations. */
 
 template <unsigned int WheresFace, typename T>
-struct hb_face_lazy_loader_t : hb_lazy_loader_t<hb_face_lazy_loader_t<WheresFace, T>,
-						  hb_face_t, WheresFace,
-						  T> {};
+struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
+						hb_face_lazy_loader_t<WheresFace, T>,
+						hb_face_t, WheresFace> {};
 
 template <typename T, unsigned int WheresFace>
-struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, WheresFace>,
+struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
+						 hb_table_lazy_loader_t<T, WheresFace>,
 						 hb_face_t, WheresFace,
-						 T, hb_blob_t>
+						 hb_blob_t>
 {
   static inline hb_blob_t *create (hb_face_t *face)
   {
@@ -750,9 +765,7 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, Where
 };
 
 template <typename Subclass>
-struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<Subclass,
-						      void, 0,
-						      hb_font_funcs_t>
+struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<hb_font_funcs_t, Subclass>
 {
   static inline void destroy (hb_font_funcs_t *p)
   {
@@ -764,9 +777,7 @@ struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<Subclass,
   }
 };
 template <typename Subclass>
-struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<Subclass,
-							 void, 0,
-							 hb_unicode_funcs_t>
+struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Subclass>
 {
   static inline void destroy (hb_unicode_funcs_t *p)
   {
commit bb905e9afcc3eb28a22ba78c09e661a814d04c1f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 16:40:08 2018 -0700

    [lazy] Minor

diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index 193f5ed2..d40f9d9c 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -693,7 +693,21 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   /* To be possibly overloaded by subclasses. */
   static inline const Returned* convert (const Stored *p) { return p; }
   static inline Returned* convert (Stored *p) { return p; }
+
+  /* By default null/init/fini the object. */
   static inline const Stored* get_null (void) { return &Null(Stored); }
+  static inline Stored *create (Data *data)
+  {
+    Stored *p = (Stored *) calloc (1, sizeof (Stored));
+    if (likely (p))
+      p->init (data);
+    return p;
+  }
+  static inline void destroy (Stored *p)
+  {
+    p->fini ();
+    ::free (p);
+  }
 
   private:
   /* Must only have one pointer. */
@@ -703,23 +717,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 /* Specializations. */
 
 template <unsigned int WheresFace, typename T>
-struct hb_object_lazy_loader_t : hb_lazy_loader_t<hb_object_lazy_loader_t<WheresFace, T>,
+struct hb_face_lazy_loader_t : hb_lazy_loader_t<hb_face_lazy_loader_t<WheresFace, T>,
 						  hb_face_t, WheresFace,
-						  T>
-{
-  static inline T *create (hb_face_t *face)
-  {
-    T *p = (T *) calloc (1, sizeof (T));
-    if (likely (p))
-      p->init (face);
-    return p;
-  }
-  static inline void destroy (T *p)
-  {
-    p->fini ();
-    free (p);
-  }
-};
+						  T> {};
 
 template <typename T, unsigned int WheresFace>
 struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, WheresFace>,
@@ -751,8 +751,8 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, Where
 
 template <typename Subclass>
 struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<Subclass,
-						       void, 0,
-						       hb_font_funcs_t>
+						      void, 0,
+						      hb_font_funcs_t>
 {
   static inline void destroy (hb_font_funcs_t *p)
   {
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index cac18095..0b14ff1e 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -71,10 +71,10 @@ struct hb_ot_font_t
   OT::vmtx::accelerator_t v_metrics;
 
   hb_face_t *face; /* MUST be JUST before the lazy loaders. */
-  hb_object_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
-  hb_object_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
-  hb_object_lazy_loader_t<3, OT::post::accelerator_t> post;
-  hb_object_lazy_loader_t<4, OT::kern::accelerator_t> kern;
+  hb_face_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
+  hb_face_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
+  hb_face_lazy_loader_t<3, OT::post::accelerator_t> post;
+  hb_face_lazy_loader_t<4, OT::kern::accelerator_t> kern;
 };
 
 
commit 3945cd78a96bdd287e203a0261bac490df1314b0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 16:33:48 2018 -0700

    Minor

diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index 3c1181be..193f5ed2 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -719,10 +719,6 @@ struct hb_object_lazy_loader_t : hb_lazy_loader_t<hb_object_lazy_loader_t<Wheres
     p->fini ();
     free (p);
   }
-  static inline const T *get_null (void)
-  {
-    return &Null(T);
-  }
 };
 
 template <typename T, unsigned int WheresFace>
commit c21a1b95dffedb6ed66b384f4adf07e6d05d4b9f
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 16:30:39 2018 -0700

    [icu] Use get_relaxed for normalizer access
    
    We've had the proper barriers already.  No need for more with every access.

diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index a2cd7dd4..551069fa 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -178,7 +178,7 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 {
 #if U_ICU_VERSION_MAJOR_NUM >= 49
   {
-    UChar32 ret = unorm2_composePair (normalizer.get (), a, b);
+    UChar32 ret = unorm2_composePair (normalizer.get_relaxed (), a, b);
     if (ret < 0) return false;
     *ab = ret;
     return true;
@@ -226,7 +226,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
     UChar decomposed[4];
     int len;
     UErrorCode icu_err = U_ZERO_ERROR;
-    len = unorm2_getRawDecomposition (normalizer.get (), ab, decomposed,
+    len = unorm2_getRawDecomposition (normalizer.get_relaxed (), ab, decomposed,
 				      ARRAY_LENGTH (decomposed), &icu_err);
     if (U_FAILURE (icu_err) || len < 0) return false;
 
commit 125fefa2a6b23cf7eb4559904b23aff3731d5dba
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 16:29:41 2018 -0700

    [icu] Fix for breakage after recent change

diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 7b2c4d6e..a2cd7dd4 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -352,6 +352,16 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_
 {
   static inline hb_unicode_funcs_t *create (void)
   {
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+  retry:
+    if (!normalizer.get ())
+    {
+      UErrorCode icu_err = U_ZERO_ERROR;
+      if (unlikely (!normalizer.cmpexch (nullptr, unorm2_getNFCInstance (&icu_err))))
+        goto retry;
+    }
+#endif
+
     hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
 
 #define HB_UNICODE_FUNC_IMPLEMENT(name) \
commit 53442be1edc73993bdcaffc4b895c07f1ea03ba0
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 16:20:11 2018 -0700

    [lazy] Use for ft_library

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 5ac9a3e9..eea2da13 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -461,7 +461,7 @@ void free_static_ft_funcs (void)
 static hb_font_funcs_t *
 _hb_ft_get_font_funcs (void)
 {
-  return const_cast<hb_font_funcs_t *> (static_ft_funcs.get ());
+  return static_ft_funcs.get_unconst ();
 }
 
 static void
@@ -683,47 +683,46 @@ hb_ft_font_create_referenced (FT_Face ft_face)
 }
 
 
-/* Thread-safe, lock-free, FT_Library */
+static void free_static_ft_library (void);
 
-static hb_atomic_ptr_t<FT_Library> ft_library;
+static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_ft_library_lazy_loader_t,
+							     void, 0,
+							     hb_remove_ptr_t<FT_Library>::value>
+{
+  static inline FT_Library create (void)
+  {
+    FT_Library l;
+    if (FT_Init_FreeType (&l))
+      return nullptr;
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ft_library);
+#endif
+
+    return l;
+  }
+  static inline void destroy (FT_Library l)
+  {
+    FT_Done_FreeType (l);
+  }
+  static inline const FT_Library get_null (void)
+  {
+    return nullptr;
+  }
+} static_ft_library;
 
 #ifdef HB_USE_ATEXIT
 static
-void free_ft_library (void)
+void free_static_ft_library (void)
 {
-retry:
-  FT_Library library = ft_library.get ();
-  if (unlikely (!ft_library.cmpexch (library, nullptr)))
-    goto retry;
-
-  FT_Done_FreeType (library);
+  static_ft_library.free ();
 }
 #endif
 
 static FT_Library
 get_ft_library (void)
 {
-retry:
-  FT_Library library = ft_library.get ();
-
-  if (unlikely (!library))
-  {
-    /* Not found; allocate one. */
-    if (FT_Init_FreeType (&library))
-      return nullptr;
-
-    if (unlikely (!ft_library.cmpexch (nullptr, library)))
-    {
-      FT_Done_FreeType (library);
-      goto retry;
-    }
-
-#ifdef HB_USE_ATEXIT
-    atexit (free_ft_library); /* First person registers atexit() callback. */
-#endif
-  }
-
-  return library;
+  return static_ft_library.get_unconst ();
 }
 
 static void
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 6ce9a351..af7a0fd3 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -401,7 +401,7 @@ void free_static_glib_funcs (void)
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void)
 {
-  return hb_unicode_funcs_reference (const_cast<hb_unicode_funcs_t *> (static_glib_funcs.get ()));
+  return hb_unicode_funcs_reference (static_glib_funcs.get_unconst ());
 }
 
 
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 0442d92a..7b2c4d6e 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -380,5 +380,5 @@ void free_static_icu_funcs (void)
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void)
 {
-  return hb_unicode_funcs_reference (const_cast<hb_unicode_funcs_t *> (static_icu_funcs.get ()));
+  return hb_unicode_funcs_reference (static_icu_funcs.get_unconst ());
 }
diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index 6221fe59..3c1181be 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -667,7 +667,6 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
     if (unlikely (!p))
     {
       p = do_create ();
-      assert (p);
       if (unlikely (!this->instance.cmpexch (nullptr, p)))
       {
         do_destroy (p);
@@ -689,6 +688,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   }
 
   inline const Returned * get (void) const { return Subclass::convert (get_stored ()); }
+  inline Returned * get_unconst (void) const { return const_cast<Returned *> (Subclass::convert (get_stored ())); }
 
   /* To be possibly overloaded by subclasses. */
   static inline const Returned* convert (const Stored *p) { return p; }
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index f181b076..cac18095 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -271,7 +271,7 @@ void free_static_ot_funcs (void)
 static hb_font_funcs_t *
 _hb_ot_get_font_funcs (void)
 {
-  return const_cast<hb_font_funcs_t *> (static_ot_funcs.get ());
+  return static_ot_funcs.get_unconst ();
 }
 
 
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index 1945a1cf..6b1bb804 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -275,5 +275,5 @@ extern "C" HB_INTERNAL
 hb_unicode_funcs_t *
 hb_ucdn_get_unicode_funcs (void)
 {
-  return hb_unicode_funcs_reference (const_cast<hb_unicode_funcs_t *> (static_ucdn_funcs.get ()));
+  return hb_unicode_funcs_reference (static_ucdn_funcs.get_unconst ());
 }
commit 7a8d480378af4094645dfb1527a61a94b4786b54
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 16:00:13 2018 -0700

    [lazy] Add .free()

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index c58cd87c..5ac9a3e9 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -454,7 +454,7 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
 static
 void free_static_ft_funcs (void)
 {
-  static_ft_funcs.fini ();
+  static_ft_funcs.free ();
 }
 #endif
 
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index a5a82d47..6ce9a351 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -394,7 +394,7 @@ static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
 static
 void free_static_glib_funcs (void)
 {
-  static_glib_funcs.fini ();
+  static_glib_funcs.free ();
 }
 #endif
 
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 99e3d2cb..0442d92a 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -373,7 +373,7 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_
 static
 void free_static_icu_funcs (void)
 {
-  static_icu_funcs.fini ();
+  static_icu_funcs.free ();
 }
 #endif
 
diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index b26ca710..6221fe59 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -628,6 +628,10 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   inline void init (void) { instance.set_relaxed (nullptr); }
   inline void fini (void)
   {
+    do_destroy (instance.get ());
+  }
+  inline void free (void)
+  {
   retry:
     Stored *p = instance.get ();
     if (unlikely (p && !this->instance.cmpexch (p, nullptr)))
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 1fb18c48..f181b076 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -264,7 +264,7 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
 static
 void free_static_ot_funcs (void)
 {
-  static_ot_funcs.fini ();
+  static_ot_funcs.free ();
 }
 #endif
 
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index c58db05a..1945a1cf 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -267,7 +267,7 @@ static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
 static
 void free_static_ucdn_funcs (void)
 {
-  static_ucdn_funcs.fini ();
+  static_ucdn_funcs.free ();
 }
 #endif
 
commit c7ca30a5337cb660e650d51ddd17d389909357c2
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 13:46:53 2018 -0700

    [ot/ft] Port font_funcs statis to lazy-loader

diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 5ab2a887..c58cd87c 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -32,6 +32,7 @@
 #include "hb-ft.h"
 
 #include "hb-font-private.hh"
+#include "hb-machinery-private.hh"
 
 #include FT_ADVANCES_H
 #include FT_MULTIPLE_MASTERS_H
@@ -416,30 +417,13 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
   return true;
 }
 
-static hb_atomic_ptr_t<hb_font_funcs_t> static_ft_funcs;
+static void free_static_ft_funcs (void);
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ft_funcs (void)
-{
-retry:
-  hb_font_funcs_t *ft_funcs = static_ft_funcs.get ();
-  if (unlikely (!static_ft_funcs.cmpexch (ft_funcs, nullptr)))
-    goto retry;
-
-  hb_font_funcs_destroy (ft_funcs);
-}
-#endif
-
-static void
-_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
 {
-retry:
-  hb_font_funcs_t *funcs = static_ft_funcs.get ();
-
-  if (unlikely (!funcs))
+  static inline hb_font_funcs_t *create (void)
   {
-    funcs = hb_font_funcs_create ();
+    hb_font_funcs_t *funcs = hb_font_funcs_create ();
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
     //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
@@ -458,21 +442,35 @@ retry:
 
     hb_font_funcs_make_immutable (funcs);
 
-    if (unlikely (!static_ft_funcs. cmpexch (nullptr, funcs)))
-    {
-      hb_font_funcs_destroy (funcs);
-      goto retry;
-    }
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ft_funcs);
+#endif
+
+    return funcs;
+  }
+} static_ft_funcs;
 
 #ifdef HB_USE_ATEXIT
-    atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
+static
+void free_static_ft_funcs (void)
+{
+  static_ft_funcs.fini ();
+}
 #endif
-  };
 
+static hb_font_funcs_t *
+_hb_ft_get_font_funcs (void)
+{
+  return const_cast<hb_font_funcs_t *> (static_ft_funcs.get ());
+}
+
+static void
+_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+{
   bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
 
   hb_font_set_funcs (font,
-		     funcs,
+		     _hb_ft_get_font_funcs (),
 		     _hb_ft_font_create (ft_face, symbol, unref),
 		     _hb_ft_font_destroy);
 }
diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index 873596de..b26ca710 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -750,6 +750,20 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, Where
 };
 
 template <typename Subclass>
+struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<Subclass,
+						       void, 0,
+						       hb_font_funcs_t>
+{
+  static inline void destroy (hb_font_funcs_t *p)
+  {
+    hb_font_funcs_destroy (p);
+  }
+  static inline const hb_font_funcs_t *get_null (void)
+  {
+      return hb_font_funcs_get_empty ();
+  }
+};
+template <typename Subclass>
 struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<Subclass,
 							 void, 0,
 							 hb_unicode_funcs_t>
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 0284a45b..1fb18c48 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -29,6 +29,7 @@
 #include "hb-ot.h"
 
 #include "hb-font-private.hh"
+#include "hb-machinery-private.hh"
 
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-glyf-table.hh"
@@ -225,30 +226,14 @@ hb_ot_get_font_v_extents (hb_font_t *font,
   return ot_font->v_metrics.has_font_extents;
 }
 
-static hb_atomic_ptr_t <hb_font_funcs_t> static_ot_funcs;
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ot_funcs (void)
-{
-retry:
-  hb_font_funcs_t *ot_funcs = static_ot_funcs.get ();
-  if (unlikely (!static_ot_funcs.cmpexch (ot_funcs, nullptr)))
-    goto retry;
+static void free_static_ot_funcs (void);
 
-  hb_font_funcs_destroy (ot_funcs);
-}
-#endif
-
-static hb_font_funcs_t *
-_hb_ot_get_font_funcs (void)
+static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
 {
-retry:
-  hb_font_funcs_t *funcs = static_ot_funcs.get ();
-
-  if (unlikely (!funcs))
+  static inline hb_font_funcs_t *create (void)
   {
-    funcs = hb_font_funcs_create ();
+    hb_font_funcs_t *funcs = hb_font_funcs_create ();
 
     hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
     hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
@@ -267,18 +252,26 @@ retry:
 
     hb_font_funcs_make_immutable (funcs);
 
-    if (unlikely (!static_ot_funcs.cmpexch (nullptr, funcs)))
-    {
-      hb_font_funcs_destroy (funcs);
-      goto retry;
-    }
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ot_funcs);
+#endif
+
+    return funcs;
+  }
+} static_ot_funcs;
 
 #ifdef HB_USE_ATEXIT
-    atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
+static
+void free_static_ot_funcs (void)
+{
+  static_ot_funcs.fini ();
+}
 #endif
-  };
 
-  return funcs;
+static hb_font_funcs_t *
+_hb_ot_get_font_funcs (void)
+{
+  return const_cast<hb_font_funcs_t *> (static_ot_funcs.get ());
 }
 
 
commit cb3fc3685c03c8ed07bcf05188f5d6c582fd5aaa
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 13:39:01 2018 -0700

    [ucdn/glib/icu] Port unicode_funcs statics to lazy-loader

diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 4bb6f08f..a5a82d47 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -31,6 +31,7 @@
 #include "hb-glib.h"
 
 #include "hb-unicode-private.hh"
+#include "hb-machinery-private.hh"
 
 
 #if !GLIB_CHECK_VERSION(2,29,14)
@@ -364,30 +365,15 @@ hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   return utf8_decomposed_len;
 }
 
-static hb_atomic_ptr_t<hb_unicode_funcs_t> static_glib_funcs;
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_glib_funcs (void)
-{
-retry:
-  hb_unicode_funcs_t *glib_funcs = static_glib_funcs.get ();
-  if (unlikely (!static_glib_funcs.cmpexch (glib_funcs, nullptr)))
-    goto retry;
 
-  hb_unicode_funcs_destroy (glib_funcs);
-}
-#endif
+static void free_static_glib_funcs (void);
 
-hb_unicode_funcs_t *
-hb_glib_get_unicode_funcs (void)
+static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
 {
-retry:
-  hb_unicode_funcs_t *funcs = static_glib_funcs.get ();
-
-  if (unlikely (!funcs))
+  static inline hb_unicode_funcs_t *create (void)
   {
-    funcs = hb_unicode_funcs_create (nullptr);
+    hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
 
 #define HB_UNICODE_FUNC_IMPLEMENT(name) \
     hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr);
@@ -396,20 +382,30 @@ retry:
 
     hb_unicode_funcs_make_immutable (funcs);
 
-    if (unlikely (!static_glib_funcs.cmpexch (nullptr, funcs)))
-    {
-      hb_unicode_funcs_destroy (funcs);
-      goto retry;
-    }
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_glib_funcs);
+#endif
+
+    return funcs;
+  }
+} static_glib_funcs;
 
 #ifdef HB_USE_ATEXIT
-    atexit (free_static_glib_funcs); /* First person registers atexit() callback. */
+static
+void free_static_glib_funcs (void)
+{
+  static_glib_funcs.fini ();
+}
 #endif
-  };
 
-  return hb_unicode_funcs_reference (funcs);
+hb_unicode_funcs_t *
+hb_glib_get_unicode_funcs (void)
+{
+  return hb_unicode_funcs_reference (const_cast<hb_unicode_funcs_t *> (static_glib_funcs.get ()));
 }
 
+
+
 #if GLIB_CHECK_VERSION(2,31,10)
 
 static void
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index ce58de0c..99e3d2cb 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -32,6 +32,7 @@
 #include "hb-icu.h"
 
 #include "hb-unicode-private.hh"
+#include "hb-machinery-private.hh"
 
 #include <unicode/uchar.h>
 #include <unicode/unorm2.h>
@@ -345,39 +346,13 @@ hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 }
 
 
-static hb_atomic_ptr_t<hb_unicode_funcs_t> static_icu_funcs;
+static void free_static_icu_funcs (void);
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_icu_funcs (void)
-{
-retry:
-  hb_unicode_funcs_t *icu_funcs = static_icu_funcs.get ();
-  if (unlikely (!static_icu_funcs.cmpexch (icu_funcs, nullptr)))
-    goto retry;
-
-  hb_unicode_funcs_destroy (icu_funcs);
-}
-#endif
-
-hb_unicode_funcs_t *
-hb_icu_get_unicode_funcs (void)
+static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
 {
-retry:
-  hb_unicode_funcs_t *funcs = static_icu_funcs.get ();
-
-  if (unlikely (!funcs))
+  static inline hb_unicode_funcs_t *create (void)
   {
-#if U_ICU_VERSION_MAJOR_NUM >= 49
-    if (!normalizer.get ())
-    {
-      UErrorCode icu_err = U_ZERO_ERROR;
-      /* We ignore failure in getNFCInstace(). */
-      (void) normalizer.cmpexch (nullptr, unorm2_getNFCInstance (&icu_err));
-    }
-#endif
-
-    funcs = hb_unicode_funcs_create (nullptr);
+    hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
 
 #define HB_UNICODE_FUNC_IMPLEMENT(name) \
     hb_unicode_funcs_set_##name##_func (funcs, hb_icu_unicode_##name, nullptr, nullptr);
@@ -386,16 +361,24 @@ retry:
 
     hb_unicode_funcs_make_immutable (funcs);
 
-    if (unlikely (!static_icu_funcs.cmpexch (nullptr, funcs)))
-    {
-      hb_unicode_funcs_destroy (funcs);
-      goto retry;
-    }
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_icu_funcs);
+#endif
+
+    return funcs;
+  }
+} static_icu_funcs;
 
 #ifdef HB_USE_ATEXIT
-    atexit (free_static_icu_funcs); /* First person registers atexit() callback. */
+static
+void free_static_icu_funcs (void)
+{
+  static_icu_funcs.fini ();
+}
 #endif
-  };
 
-  return hb_unicode_funcs_reference (funcs);
+hb_unicode_funcs_t *
+hb_icu_get_unicode_funcs (void)
+{
+  return hb_unicode_funcs_reference (const_cast<hb_unicode_funcs_t *> (static_icu_funcs.get ()));
 }
diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index 1eeae4b2..873596de 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -632,17 +632,17 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
     Stored *p = instance.get ();
     if (unlikely (p && !this->instance.cmpexch (p, nullptr)))
       goto retry;
-    destroy (p);
+    do_destroy (p);
   }
 
-  inline Stored * create (void) const
+  inline Stored * do_create (void) const
   {
     Stored *p = this->template call_create<Stored, Subclass> ();
     if (unlikely (!p))
       p = const_cast<Stored *> (Subclass::get_null ());
     return p;
   }
-  static inline void destroy (Stored *p)
+  static inline void do_destroy (Stored *p)
   {
     if (p && p != Subclass::get_null ())
       Subclass::destroy (p);
@@ -662,11 +662,11 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
     Stored *p = this->instance.get ();
     if (unlikely (!p))
     {
-      p = create ();
+      p = do_create ();
       assert (p);
       if (unlikely (!this->instance.cmpexch (nullptr, p)))
       {
-        destroy (p);
+        do_destroy (p);
 	goto retry;
       }
     }
@@ -681,13 +681,14 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
     Stored *p = this->instance.get ();
     if (unlikely (!this->instance.cmpexch (p, instance_)))
       goto retry;
-    destroy (p);
+    do_destroy (p);
   }
 
   inline const Returned * get (void) const { return Subclass::convert (get_stored ()); }
 
   /* To be possibly overloaded by subclasses. */
   static inline const Returned* convert (const Stored *p) { return p; }
+  static inline Returned* convert (Stored *p) { return p; }
   static inline const Stored* get_null (void) { return &Null(Stored); }
 
   private:
@@ -748,5 +749,20 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, Where
   }
 };
 
+template <typename Subclass>
+struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<Subclass,
+							 void, 0,
+							 hb_unicode_funcs_t>
+{
+  static inline void destroy (hb_unicode_funcs_t *p)
+  {
+    hb_unicode_funcs_destroy (p);
+  }
+  static inline const hb_unicode_funcs_t *get_null (void)
+  {
+      return hb_unicode_funcs_get_empty ();
+  }
+};
+
 
 #endif /* HB_MACHINERY_PRIVATE_HH */
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index b414b1d6..c58db05a 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -17,6 +17,7 @@
 #include "hb-private.hh"
 
 #include "hb-unicode-private.hh"
+#include "hb-machinery-private.hh"
 
 #include "ucdn.h"
 
@@ -238,31 +239,14 @@ hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED,
     return ucdn_compat_decompose(u, decomposed);
 }
 
-static hb_atomic_ptr_t<hb_unicode_funcs_t> static_ucdn_funcs;
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ucdn_funcs (void)
-{
-retry:
-  hb_unicode_funcs_t *ucdn_funcs = static_ucdn_funcs.get ();
-  if (unlikely (!static_ucdn_funcs.cmpexch (ucdn_funcs, nullptr)))
-    goto retry;
+static void free_static_ucdn_funcs (void);
 
-  hb_unicode_funcs_destroy (ucdn_funcs);
-}
-#endif
-
-extern "C" HB_INTERNAL
-hb_unicode_funcs_t *
-hb_ucdn_get_unicode_funcs (void)
+static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucdn_unicode_funcs_lazy_loader_t>
 {
-retry:
-  hb_unicode_funcs_t *funcs = static_ucdn_funcs.get ();
-
-  if (unlikely (!funcs))
+  static inline hb_unicode_funcs_t *create (void)
   {
-    funcs = hb_unicode_funcs_create (nullptr);
+    hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
 
 #define HB_UNICODE_FUNC_IMPLEMENT(name) \
     hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr);
@@ -271,16 +255,25 @@ retry:
 
     hb_unicode_funcs_make_immutable (funcs);
 
-    if (unlikely (!static_ucdn_funcs.cmpexch (nullptr, funcs)))
-    {
-      hb_unicode_funcs_destroy (funcs);
-      goto retry;
-    }
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_ucdn_funcs);
+#endif
+
+    return funcs;
+  }
+} static_ucdn_funcs;
 
 #ifdef HB_USE_ATEXIT
-    atexit (free_static_ucdn_funcs); /* First person registers atexit() callback. */
+static
+void free_static_ucdn_funcs (void)
+{
+  static_ucdn_funcs.fini ();
+}
 #endif
-  };
 
-  return hb_unicode_funcs_reference (funcs);
+extern "C" HB_INTERNAL
+hb_unicode_funcs_t *
+hb_ucdn_get_unicode_funcs (void)
+{
+  return hb_unicode_funcs_reference (const_cast<hb_unicode_funcs_t *> (static_ucdn_funcs.get ()));
 }
commit 1b6b481262465ae1865c66c4d499b4b2c8d297fb
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 13:16:40 2018 -0700

    [lazy] Allow calling fini() multiple times

diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index 9edd2be5..1eeae4b2 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -626,7 +626,14 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 {
   inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
   inline void init (void) { instance.set_relaxed (nullptr); }
-  inline void fini (void) { destroy (instance.get ()); }
+  inline void fini (void)
+  {
+  retry:
+    Stored *p = instance.get ();
+    if (unlikely (p && !this->instance.cmpexch (p, nullptr)))
+      goto retry;
+    destroy (p);
+  }
 
   inline Stored * create (void) const
   {
commit 918ad9f5d9b85384f24157523272a4ffc1927d16
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 13:12:29 2018 -0700

    [lazy] More

diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index da6e941c..9edd2be5 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -590,18 +590,51 @@ struct BEInt<Type, 4>
  * Lazy loaders.
  */
 
+template <typename Data, unsigned int WheresData>
+struct hb_data_wrapper_t
+{
+  static_assert (WheresData > 0, "");
+
+  inline Data * get_data (void) const
+  {
+    return *(((Data **) this) - WheresData);
+  }
+
+  template <typename Stored, typename Subclass>
+  inline Stored * call_create (void) const
+  {
+    Data *data = this->get_data ();
+    return likely (data) ? Subclass::create (data) : nullptr;
+  }
+};
+template <>
+struct hb_data_wrapper_t<void, 0>
+{
+  template <typename Stored, typename Subclass>
+  inline Stored * call_create (void) const
+  {
+    return Subclass::create ();
+  }
+};
+
 template <typename Subclass,
 	  typename Data,
 	  unsigned int WheresData,
 	  typename Returned,
 	  typename Stored = Returned>
-struct hb_lazy_loader_t
+struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
 {
-  static_assert (WheresData > 0, "");
-
   inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
   inline void init (void) { instance.set_relaxed (nullptr); }
   inline void fini (void) { destroy (instance.get ()); }
+
+  inline Stored * create (void) const
+  {
+    Stored *p = this->template call_create<Stored, Subclass> ();
+    if (unlikely (!p))
+      p = const_cast<Stored *> (Subclass::get_null ());
+    return p;
+  }
   static inline void destroy (Stored *p)
   {
     if (p && p != Subclass::get_null ())
@@ -622,11 +655,7 @@ struct hb_lazy_loader_t
     Stored *p = this->instance.get ();
     if (unlikely (!p))
     {
-      Data *data = get_data ();
-      if (likely (data))
-	p = Subclass::create (data);
-      if (unlikely (!p))
-	p = const_cast<Stored *> (Subclass::get_null ());
+      p = create ();
       assert (p);
       if (unlikely (!this->instance.cmpexch (nullptr, p)))
       {
commit 5abdf5eebadf9a4fbd50c1a893c9654de74d22ac
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 12:40:24 2018 -0700

    [lazy] More shuffle

diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index ea6dfa48..da6e941c 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -599,40 +599,38 @@ struct hb_lazy_loader_t
 {
   static_assert (WheresData > 0, "");
 
-  /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
-  inline const Subclass* thiz (void) const { return static_cast<const Subclass *> (this); }
-  inline Subclass* thiz (void) { return static_cast<Subclass *> (this); }
-
   inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
-  inline void init (void)
+  inline void init (void) { instance.set_relaxed (nullptr); }
+  inline void fini (void) { destroy (instance.get ()); }
+  static inline void destroy (Stored *p)
   {
-    instance.set_relaxed (nullptr);
+    if (p && p != Subclass::get_null ())
+      Subclass::destroy (p);
   }
-  inline void fini (void)
+
+  inline const Returned * operator -> (void) const { return get (); }
+  inline const Returned & operator * (void) const { return *get (); }
+
+  inline Data * get_data (void) const
   {
-    Stored *p = this->instance.get ();
-    if (p)
-      thiz ()->destroy (p);
+    return *(((Data **) this) - WheresData);
   }
 
-  inline const Returned * operator -> (void) const { return thiz ()->get (); }
-  inline const Returned & operator * (void) const { return *thiz ()->get (); }
-
   inline Stored * get_stored (void) const
   {
   retry:
     Stored *p = this->instance.get ();
     if (unlikely (!p))
     {
-      Data *data= *(((Data **) this) - WheresData);
-      if (likely (!p))
-	p = thiz ()->create (data);
+      Data *data = get_data ();
+      if (likely (data))
+	p = Subclass::create (data);
       if (unlikely (!p))
-	p = thiz ()->create (nullptr); /* Produce nil object. */
+	p = const_cast<Stored *> (Subclass::get_null ());
       assert (p);
       if (unlikely (!this->instance.cmpexch (nullptr, p)))
       {
-        thiz ()->destroy (p);
+        destroy (p);
 	goto retry;
       }
     }
@@ -645,23 +643,16 @@ struct hb_lazy_loader_t
      * However, to make TSan, etc, happy, we using cmpexch. */
   retry:
     Stored *p = this->instance.get ();
-    if (p)
-    {
-      if (unlikely (!this->instance.cmpexch (p, instance_)))
-        goto retry;
-      thiz ()->destroy (p);
-    }
+    if (unlikely (!this->instance.cmpexch (p, instance_)))
+      goto retry;
+    destroy (p);
   }
 
-  inline const Returned * get (void) const
-  {
-    return thiz ()->convert (get_stored ());
-  }
+  inline const Returned * get (void) const { return Subclass::convert (get_stored ()); }
 
-  static inline const Returned* convert (const Stored *p)
-  {
-    return p;
-  }
+  /* To be possibly overloaded by subclasses. */
+  static inline const Returned* convert (const Stored *p) { return p; }
+  static inline const Stored* get_null (void) { return &Null(Stored); }
 
   private:
   /* Must only have one pointer. */
@@ -677,22 +668,19 @@ struct hb_object_lazy_loader_t : hb_lazy_loader_t<hb_object_lazy_loader_t<Wheres
 {
   static inline T *create (hb_face_t *face)
   {
-    if (unlikely (!face))
-      return const_cast<T *> (&Null(T));
     T *p = (T *) calloc (1, sizeof (T));
-    if (unlikely (!p))
-      p = const_cast<T *> (&Null(T));
-    else
+    if (likely (p))
       p->init (face);
     return p;
   }
   static inline void destroy (T *p)
   {
-    if (p != &Null(T))
-    {
-      p->fini();
-      free (p);
-    }
+    p->fini ();
+    free (p);
+  }
+  static inline const T *get_null (void)
+  {
+    return &Null(T);
   }
 };
 
@@ -701,18 +689,18 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, Where
 						 hb_face_t, WheresFace,
 						 T, hb_blob_t>
 {
-  static_assert (WheresFace > 0, "");
-
   static inline hb_blob_t *create (hb_face_t *face)
   {
-    if (unlikely (!face))
-      return hb_blob_get_empty ();
     return hb_sanitize_context_t ().reference_table<T> (face);
   }
   static inline void destroy (hb_blob_t *p)
   {
     hb_blob_destroy (p);
   }
+  static inline const hb_blob_t *get_null (void)
+  {
+      return hb_blob_get_empty ();
+  }
   static inline const T* convert (const hb_blob_t *blob)
   {
     return blob->as<T> ();
commit 5d9863be6ecf873033cbab732207dd420f3866e7
Author: Behdad Esfahbod <behdad at behdad.org>
Date:   Sun Aug 12 12:27:47 2018 -0700

    Minor

diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh
index beb61fa9..ea6dfa48 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery-private.hh
@@ -696,11 +696,13 @@ struct hb_object_lazy_loader_t : hb_lazy_loader_t<hb_object_lazy_loader_t<Wheres
   }
 };
 
-template <unsigned int WheresFace, typename T>
-struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<WheresFace, T>,
+template <typename T, unsigned int WheresFace>
+struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, WheresFace>,
 						 hb_face_t, WheresFace,
 						 T, hb_blob_t>
 {
+  static_assert (WheresFace > 0, "");
+
   static inline hb_blob_t *create (hb_face_t *face)
   {
     if (unlikely (!face))
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index de1adda5..612bc7fc 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -205,7 +205,7 @@ struct hb_ot_layout_t
 
     hb_face_t *face; /* MUST be JUST before the lazy loaders. */
 #define HB_OT_LAYOUT_TABLE(Namespace, Type) \
-    hb_table_lazy_loader_t<HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type), struct Namespace::Type> Type;
+    hb_table_lazy_loader_t<struct Namespace::Type, HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type)> Type;
     HB_OT_LAYOUT_TABLES
 #undef HB_OT_LAYOUT_TABLE
   } table;


More information about the HarfBuzz mailing list