Bug 1483310 - Update HarfBuzz to version 1.8.8. r=jfkthame
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 22 Aug 2018 13:57:00 +0000
changeset 432853 5874c9b590a03fa983421cc5d74b0b4a8a759351
parent 432852 deb8812556ef956417c81f6db7df15ff04dbbe9f
child 432854 7f64306b8f830ed29d4ee72414449ea67763c242
push id34489
push usercbrindusan@mozilla.com
push dateWed, 22 Aug 2018 21:55:30 +0000
treeherdermozilla-central@120c4145368d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame
bugs1483310
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1483310 - Update HarfBuzz to version 1.8.8. r=jfkthame Differential Revision: https://phabricator.services.mozilla.com/D3973
gfx/harfbuzz/NEWS
gfx/harfbuzz/README-mozilla
gfx/harfbuzz/configure.ac
gfx/harfbuzz/src/hb-atomic-private.hh
gfx/harfbuzz/src/hb-buffer.cc
gfx/harfbuzz/src/hb-common.cc
gfx/harfbuzz/src/hb-coretext.cc
gfx/harfbuzz/src/hb-face-private.hh
gfx/harfbuzz/src/hb-face.cc
gfx/harfbuzz/src/hb-font.cc
gfx/harfbuzz/src/hb-ft.cc
gfx/harfbuzz/src/hb-glib.cc
gfx/harfbuzz/src/hb-graphite2.cc
gfx/harfbuzz/src/hb-icu.cc
gfx/harfbuzz/src/hb-iter-private.hh
gfx/harfbuzz/src/hb-machinery-private.hh
gfx/harfbuzz/src/hb-object-private.hh
gfx/harfbuzz/src/hb-ot-font.cc
gfx/harfbuzz/src/hb-ot-layout-private.hh
gfx/harfbuzz/src/hb-ot-post-table.hh
gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
gfx/harfbuzz/src/hb-private.hh
gfx/harfbuzz/src/hb-shape-plan.cc
gfx/harfbuzz/src/hb-shape.cc
gfx/harfbuzz/src/hb-shaper-impl-private.hh
gfx/harfbuzz/src/hb-shaper-private.hh
gfx/harfbuzz/src/hb-shaper.cc
gfx/harfbuzz/src/hb-ucdn.cc
gfx/harfbuzz/src/hb-uniscribe.cc
gfx/harfbuzz/src/hb-version.h
gfx/harfbuzz/update.sh
--- a/gfx/harfbuzz/NEWS
+++ b/gfx/harfbuzz/NEWS
@@ -1,8 +1,26 @@
+Overview of changes leading to 1.8.8
+Tuesday, August 14, 2018
+====================================
+- Fix hb-icu crash on architectures where compare_exchange_weak() can
+  fail falsely.  This bug was introduced in 1.8.4.
+  https://bugs.chromium.org/p/chromium/issues/detail?id=873568
+- More internal refactoring of atomic operations and singletons.
+- API changes:
+  The following functions do NOT reference their return value before
+  returning:
+  * hb_unicode_funcs_get_default()
+  * hb_glib_get_unicode_funcs()
+  * hb_icu_get_unicode_funcs()
+  This is consistent with their naming ("get", instead of "reference")
+  as well as how they are used in the wild (ie. no one calls destroy()
+  on their return value.)
+
+
 Overview of changes leading to 1.8.7
 Wednesday, August 8, 2018
 ====================================
 - Fix assertion failure with GDEF-blacklisted fonts.
 
 
 Overview of changes leading to 1.8.6
 Tuesday, August 7, 2018
--- a/gfx/harfbuzz/README-mozilla
+++ b/gfx/harfbuzz/README-mozilla
@@ -1,12 +1,12 @@
 This directory contains the HarfBuzz source from the upstream repo:
 https://github.com/harfbuzz/harfbuzz
 
-Current version: 1.8.7 [commit b6fdcf4f8bd09e065c767939125861c9dc8ff18f]
+Current version: 1.8.8 [commit 63be5dcdde61275822d931b2924425478bc1dac1]
 
 UPDATING:
 
 Our in-tree copy of HarfBuzz does not depend on any generated files from the
 upstream build system. Therefore, it should be sufficient to simply overwrite
 the in-tree files one the updated ones from upstream to perform updates.
 
 To simplify this, the in-tree copy can be updated by running
--- a/gfx/harfbuzz/configure.ac
+++ b/gfx/harfbuzz/configure.ac
@@ -1,11 +1,11 @@
 AC_PREREQ([2.64])
 AC_INIT([HarfBuzz],
-        [1.8.7],
+        [1.8.8],
         [https://github.com/harfbuzz/harfbuzz/issues/new],
         [harfbuzz],
         [http://harfbuzz.org/])
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 
--- a/gfx/harfbuzz/src/hb-atomic-private.hh
+++ b/gfx/harfbuzz/src/hb-atomic-private.hh
@@ -30,56 +30,61 @@
  */
 
 #ifndef HB_ATOMIC_PRIVATE_HH
 #define HB_ATOMIC_PRIVATE_HH
 
 #include "hb-private.hh"
 
 
-/* atomic_int */
+/*
+ * Atomic integers and pointers.
+ */
+
 
 /* We need external help for these */
 
 #if defined(hb_atomic_int_impl_add) \
  && defined(hb_atomic_ptr_impl_get) \
  && defined(hb_atomic_ptr_impl_cmpexch)
 
-/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */
+/* Defined externally, i.e. in config.h. */
 
 
 #elif !defined(HB_NO_MT) && defined(__ATOMIC_CONSUME)
 
 /* C++11-style GCC primitives. */
 
-typedef int hb_atomic_int_impl_t;
 #define hb_atomic_int_impl_add(AI, V)		__atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL)
 #define hb_atomic_int_impl_set_relaxed(AI, V)	__atomic_store_n ((AI), (V), __ATOMIC_RELAXED)
 #define hb_atomic_int_impl_get_relaxed(AI)	__atomic_load_n ((AI), __ATOMIC_RELAXED)
 
+#define hb_atomic_ptr_impl_set_relaxed(P, V)	__atomic_store_n ((P), (V), __ATOMIC_RELAXED)
+#define hb_atomic_ptr_impl_get_relaxed(P)	__atomic_load_n ((P), __ATOMIC_RELAXED)
 #define hb_atomic_ptr_impl_get(P)		__atomic_load_n ((P), __ATOMIC_CONSUME)
 static inline bool
 _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 {
   const void *O = O_; // Need lvalue
   return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
 }
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	_hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
 
 #elif !defined(HB_NO_MT) && __cplusplus >= 201103L
 
 /* C++11 atomics. */
 
 #include <atomic>
 
-typedef int hb_atomic_int_impl_t;
 #define hb_atomic_int_impl_add(AI, V)		(reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
 #define hb_atomic_int_impl_set_relaxed(AI, V)	(reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
 #define hb_atomic_int_impl_get_relaxed(AI)	(reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
 
+#define hb_atomic_ptr_impl_set_relaxed(P, V)	(reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
+#define hb_atomic_ptr_impl_get_relaxed(P)	(reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed))
 #define hb_atomic_ptr_impl_get(P)		(reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_consume))
 static inline bool
 _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 {
   const void *O = O_; // Need lvalue
   return reinterpret_cast<std::atomic<const void*> *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
 }
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	_hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
@@ -96,47 +101,43 @@ static inline void _hb_memory_barrier (v
   long dummy = 0;
   InterlockedExchange (&dummy, 1);
 #else
   MemoryBarrier ();
 #endif
 }
 #define _hb_memory_barrier()			_hb_memory_barrier ()
 
-typedef LONG hb_atomic_int_impl_t;
-#define hb_atomic_int_impl_add(AI, V)		InterlockedExchangeAdd ((AI), (V))
+#define hb_atomic_int_impl_add(AI, V)		InterlockedExchangeAdd ((unsigned *) (AI), (V))
 
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 #define _hb_memory_barrier()			__sync_synchronize ()
 
-typedef int hb_atomic_int_impl_t;
 #define hb_atomic_int_impl_add(AI, V)		__sync_fetch_and_add ((AI), (V))
 
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	__sync_bool_compare_and_swap ((P), (O), (N))
 
 
 #elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
 
 #include <atomic.h>
 #include <mbarrier.h>
 
 #define _hb_memory_r_barrier()			__machine_r_barrier ()
 #define _hb_memory_w_barrier()			__machine_w_barrier ()
 #define _hb_memory_barrier()			__machine_rw_barrier ()
 
-typedef unsigned int hb_atomic_int_impl_t;
-
-static inline int _hb_fetch_and_add (hb_atomic_int_impl_t *AI, int V)
+static inline int _hb_fetch_and_add (int *AI, int V)
 {
   _hb_memory_w_barrier ();
-  int result = atomic_add_int_nv (AI, V);
+  int result = atomic_add_int_nv ((uint_t *) AI, V);
   _hb_memory_r_barrier ();
   return result;
 }
 static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, const void *N)
 {
   _hb_memory_w_barrier ();
   int result = atomic_cas_ptr ((void **) P, (void *) O, (void *) N) == (void *) O;
   _hb_memory_r_barrier ();
@@ -154,17 +155,16 @@ static inline bool _hb_compare_and_swap_
 #ifdef __MAC_OS_X_MIN_REQUIRED
 #include <AvailabilityMacros.h>
 #elif defined(__IPHONE_OS_MIN_REQUIRED)
 #include <Availability.h>
 #endif
 
 #define _hb_memory_barrier()			OSMemoryBarrier ()
 
-typedef int32_t hb_atomic_int_impl_t;
 #define hb_atomic_int_impl_add(AI, V)		(OSAtomicAdd32Barrier ((V), (AI)) - (V))
 
 #if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
 #else
 #if __ppc64__ || __x86_64__ || __aarch64__
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
 #else
@@ -174,19 +174,17 @@ typedef int32_t hb_atomic_int_impl_t;
 
 
 #elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
 
 #include <builtins.h>
 
 #define _hb_memory_barrier()			__lwsync ()
 
-typedef int hb_atomic_int_impl_t;
-
-static inline int _hb_fetch_and_add (hb_atomic_int_impl_t *AI, int V)
+static inline int _hb_fetch_and_add (int *AI, int V)
 {
   _hb_memory_barrier ();
   int result = __fetch_and_add (AI, V);
   _hb_memory_barrier ();
   return result;
 }
 static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
 {
@@ -203,63 +201,81 @@ static_assert ((sizeof (long) == sizeof 
 
 
 #elif !defined(HB_NO_MT)
 
 #define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
 
 #define _hb_memory_barrier()
 
-typedef volatile int hb_atomic_int_impl_t;
 #define hb_atomic_int_impl_add(AI, V)		((*(AI) += (V)) - (V))
 
-#define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
+#define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
 
 
 #else /* HB_NO_MT */
 
-typedef int hb_atomic_int_impl_t;
 #define hb_atomic_int_impl_add(AI, V)		((*(AI) += (V)) - (V))
 
 #define _hb_memory_barrier()
 
 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
 
 
 #endif
 
 
 #ifndef _hb_memory_r_barrier
 #define _hb_memory_r_barrier()			_hb_memory_barrier ()
 #endif
 #ifndef _hb_memory_w_barrier
 #define _hb_memory_w_barrier()			_hb_memory_barrier ()
 #endif
-#ifndef HB_ATOMIC_INT_INIT
-#define HB_ATOMIC_INT_INIT(V)          {V}
-#endif
 #ifndef hb_atomic_int_impl_set_relaxed
 #define hb_atomic_int_impl_set_relaxed(AI, V)	(*(AI) = (V))
 #endif
 #ifndef hb_atomic_int_impl_get_relaxed
 #define hb_atomic_int_impl_get_relaxed(AI)	(*(AI))
 #endif
+
+#ifndef hb_atomic_ptr_impl_set_relaxed
+#define hb_atomic_ptr_impl_set_relaxed(P, V)	(*(P) = (V))
+#endif
+#ifndef hb_atomic_ptr_impl_get_relaxed
+#define hb_atomic_ptr_impl_get_relaxed(P)	(*(P))
+#endif
 #ifndef hb_atomic_ptr_impl_get
 inline void *hb_atomic_ptr_impl_get (void **P)	{ void *v = *P; _hb_memory_r_barrier (); return v; }
 #endif
 
 
+#define HB_ATOMIC_INT_INIT(V)          {V}
 struct hb_atomic_int_t
 {
-  mutable hb_atomic_int_impl_t v;
-
-  inline void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
+  inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); }
   inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); }
   inline int inc (void) { return hb_atomic_int_impl_add (&v,  1); }
   inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); }
+
+  mutable int v;
 };
 
 
-#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get((void **) P)
-#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N))
+template <typename T> struct hb_remove_ptr_t { typedef T value; };
+template <typename T> struct hb_remove_ptr_t<T *> { typedef T value; };
+
+#define HB_ATOMIC_PTR_INIT(V)          {V}
+template <typename P>
+struct hb_atomic_ptr_t
+{
+  typedef typename hb_remove_ptr_t<P>::value T;
+
+  inline void init (T* v_ = nullptr) { set_relaxed (v_); }
+  inline void set_relaxed (T* v_) const { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
+  inline T *get_relaxed (void) const { return hb_atomic_ptr_impl_get_relaxed (&v); }
+  inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
+  inline bool cmpexch (const T *old, T *new_) const{ return hb_atomic_ptr_impl_cmpexch (&v, old, new_); }
+
+  mutable T *v;
+};
 
 
 #endif /* HB_ATOMIC_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-buffer.cc
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -211,17 +211,17 @@ hb_buffer_t::get_scratch_buffer (unsigne
 
 void
 hb_buffer_t::reset (void)
 {
   if (unlikely (hb_object_is_inert (this)))
     return;
 
   hb_unicode_funcs_destroy (unicode);
-  unicode = hb_unicode_funcs_get_default ();
+  unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
   flags = HB_BUFFER_FLAG_DEFAULT;
   replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
 
   clear ();
 }
 
 void
 hb_buffer_t::clear (void)
@@ -903,17 +903,16 @@ hb_buffer_set_unicode_funcs (hb_buffer_t
 			     hb_unicode_funcs_t *unicode_funcs)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
   if (!unicode_funcs)
     unicode_funcs = hb_unicode_funcs_get_default ();
 
-
   hb_unicode_funcs_reference (unicode_funcs);
   hb_unicode_funcs_destroy (buffer->unicode);
   buffer->unicode = unicode_funcs;
 }
 
 /**
  * hb_buffer_get_unicode_funcs:
  * @buffer: an #hb_buffer_t.
--- a/gfx/harfbuzz/src/hb-common.cc
+++ b/gfx/harfbuzz/src/hb-common.cc
@@ -23,16 +23,17 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 
+#include "hb-machinery-private.hh"
 
 #include <locale.h>
 #ifdef HAVE_XLOCALE_H
 #include <xlocale.h>
 #endif
 
 
 /* hb_options_t */
@@ -239,41 +240,41 @@ struct hb_language_item_t {
   }
 
   void fini (void) { free ((void *) lang); }
 };
 
 
 /* Thread-safe lock-free language list */
 
-static hb_language_item_t *langs;
+static hb_atomic_ptr_t <hb_language_item_t> langs;
 
 #ifdef HB_USE_ATEXIT
 static void
 free_langs (void)
 {
 retry:
-  hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
-  if (!hb_atomic_ptr_cmpexch (&langs, first_lang, nullptr))
+  hb_language_item_t *first_lang = langs.get ();
+  if (unlikely (!langs.cmpexch (first_lang, nullptr)))
     goto retry;
 
   while (first_lang) {
     hb_language_item_t *next = first_lang->next;
     first_lang->fini ();
     free (first_lang);
     first_lang = next;
   }
 }
 #endif
 
 static hb_language_item_t *
 lang_find_or_insert (const char *key)
 {
 retry:
-  hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
+  hb_language_item_t *first_lang = langs.get ();
 
   for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
     if (*lang == key)
       return lang;
 
   /* Not found; allocate one. */
   hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
   if (unlikely (!lang))
@@ -281,17 +282,18 @@ retry:
   lang->next = first_lang;
   *lang = key;
   if (unlikely (!lang->lang))
   {
     free (lang);
     return nullptr;
   }
 
-  if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
+  if (unlikely (!langs.cmpexch (first_lang, lang)))
+  {
     lang->fini ();
     free (lang);
     goto retry;
   }
 
 #ifdef HB_USE_ATEXIT
   if (!first_lang)
     atexit (free_langs); /* First person registers atexit() callback. */
@@ -363,25 +365,26 @@ hb_language_to_string (hb_language_t lan
  *
  * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
 hb_language_t
 hb_language_get_default (void)
 {
-  static hb_language_t default_language = HB_LANGUAGE_INVALID;
+  static hb_atomic_ptr_t <hb_language_t> default_language;
 
-  hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
-  if (unlikely (language == HB_LANGUAGE_INVALID)) {
+  hb_language_t language = default_language.get ();
+  if (unlikely (language == HB_LANGUAGE_INVALID))
+  {
     language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
-    (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
+    (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
   }
 
-  return default_language;
+  return language;
 }
 
 
 /* hb_script_t */
 
 /**
  * hb_script_from_iso15924_tag:
  * @tag: an #hb_tag_t representing an ISO 15924 tag.
@@ -723,57 +726,56 @@ parse_uint32 (const char **pp, const cha
 #define HB_LOCALE_T _locale_t
 #define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
 #define HB_FREE_LOCALE(loc) _free_locale (loc)
 #define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
 #endif
 
 #ifdef USE_XLOCALE
 
-static HB_LOCALE_T C_locale;
+
+static void free_static_C_locale (void);
+
+static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<HB_LOCALE_T>::value,
+							  hb_C_locale_lazy_loader_t>
+{
+  static inline HB_LOCALE_T create (void)
+  {
+    HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
 
 #ifdef HB_USE_ATEXIT
-static void
-free_C_locale (void)
-{
-retry:
-  HB_LOCALE_T locale = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
+    atexit (free_static_C_locale);
+#endif
 
-  if (!hb_atomic_ptr_cmpexch (&C_locale, locale, nullptr))
-    goto retry;
+    return C_locale;
+  }
+  static inline void destroy (HB_LOCALE_T p)
+  {
+    HB_FREE_LOCALE (p);
+  }
+  static inline HB_LOCALE_T get_null (void)
+  {
+    return nullptr;
+  }
+} static_C_locale;
 
-  if (locale)
-    HB_FREE_LOCALE (locale);
+#ifdef HB_USE_ATEXIT
+static
+void free_static_C_locale (void)
+{
+  static_C_locale.free_instance ();
 }
 #endif
 
 static HB_LOCALE_T
 get_C_locale (void)
 {
-retry:
-  HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
-
-  if (unlikely (!C))
-  {
-    C = HB_CREATE_LOCALE ("C");
-
-    if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C))
-    {
-      HB_FREE_LOCALE (C_locale);
-      goto retry;
-    }
-
-#ifdef HB_USE_ATEXIT
-    atexit (free_C_locale); /* First person registers atexit() callback. */
-#endif
-  }
-
-  return C;
+  return static_C_locale.get_unconst ();
 }
-#endif
+#endif /* USE_XLOCALE */
 
 static bool
 parse_float (const char **pp, const char *end, float *pv)
 {
   char buf[32];
   unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
   strncpy (buf, *pp, len);
   buf[len] = '\0';
@@ -840,17 +842,17 @@ parse_tag (const char **pp, const char *
 
   if (*pp < end && (**pp == '\'' || **pp == '"'))
   {
     quote = **pp;
     (*pp)++;
   }
 
   const char *p = *pp;
-  while (*pp < end && ISALNUM(**pp))
+  while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
     (*pp)++;
 
   if (p == *pp || *pp - p > 4)
     return false;
 
   *tag = hb_tag_from_string (p, *pp - p);
 
   if (quote)
--- a/gfx/harfbuzz/src/hb-coretext.cc
+++ b/gfx/harfbuzz/src/hb-coretext.cc
@@ -343,17 +343,17 @@ hb_coretext_font_create (CTFontRef ct_fo
   hb_face_destroy (face);
 
   if (unlikely (hb_object_is_inert (font)))
     return font;
 
   hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
 
   /* Let there be dragons here... */
-  HB_SHAPER_DATA_GET (font) = (hb_coretext_font_data_t *) CFRetain (ct_font);
+  HB_SHAPER_DATA (HB_SHAPER, font).set_relaxed ((hb_coretext_font_data_t *) CFRetain (ct_font));
 
   return font;
 }
 
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
   if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
--- a/gfx/harfbuzz/src/hb-face-private.hh
+++ b/gfx/harfbuzz/src/hb-face-private.hh
@@ -56,17 +56,18 @@ struct hb_face_t
 
   struct hb_shaper_data_t shaper_data;	/* Various shaper data. */
 
   /* Cache */
   struct plan_node_t
   {
     hb_shape_plan_t *shape_plan;
     plan_node_t *next;
-  } *shape_plans;
+  };
+  hb_atomic_ptr_t<plan_node_t> shape_plans;
 
   inline hb_blob_t *reference_table (hb_tag_t tag) const
   {
     hb_blob_t *blob;
 
     if (unlikely (!reference_table_func))
       return hb_blob_get_empty ();
 
--- a/gfx/harfbuzz/src/hb-face.cc
+++ b/gfx/harfbuzz/src/hb-face.cc
@@ -73,22 +73,22 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
   nullptr, /* user_data */
   nullptr, /* destroy */
 
   0,    /* index */
   1000, /* upem */
   0,    /* num_glyphs */
 
   {
-#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID),
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
   },
 
-  nullptr, /* shape_plans */
+  HB_ATOMIC_PTR_INIT (nullptr), /* shape_plans */
 };
 
 
 /**
  * hb_face_create_for_tables:
  * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
  * @user_data:
  * @destroy:
@@ -244,17 +244,17 @@ hb_face_reference (hb_face_t *face)
  *
  * Since: 0.9.2
  **/
 void
 hb_face_destroy (hb_face_t *face)
 {
   if (!hb_object_destroy (face)) return;
 
-  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
+  for (hb_face_t::plan_node_t *node = face->shape_plans.get (); node; )
   {
     hb_face_t::plan_node_t *next = node->next;
     hb_shape_plan_destroy (node->shape_plan);
     free (node);
     node = next;
   }
 
 #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
--- a/gfx/harfbuzz/src/hb-font.cc
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -1242,17 +1242,17 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
   0, /* num_coords */
   nullptr, /* coords */
 
   const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t), /* klass */
   nullptr, /* user_data */
   nullptr, /* destroy */
 
   {
-#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID),
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
   }
 };
 
 
 /**
  * hb_font_create: (Xconstructor)
--- a/gfx/harfbuzz/src/hb-ft.cc
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -27,16 +27,17 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 
 #include "hb-ft.h"
 
 #include "hb-font-private.hh"
+#include "hb-machinery-private.hh"
 
 #include FT_ADVANCES_H
 #include FT_MULTIPLE_MASTERS_H
 #include FT_TRUETYPE_TABLES_H
 
 
 /* TODO:
  *
@@ -411,40 +412,23 @@ hb_ft_get_font_h_extents (hb_font_t *fon
   {
     metrics->ascender = -metrics->ascender;
     metrics->descender = -metrics->descender;
     metrics->line_gap = -metrics->line_gap;
   }
   return true;
 }
 
-static hb_font_funcs_t *static_ft_funcs = nullptr;
-
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ft_funcs (void)
-{
-retry:
-  hb_font_funcs_t *ft_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
-  if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, ft_funcs, nullptr))
-    goto retry;
+static void free_static_ft_funcs (void);
 
-  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 = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
-
-  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);
     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
     hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
@@ -453,30 +437,45 @@ retry:
     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
     hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
     hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
 
     hb_font_funcs_make_immutable (funcs);
 
-    if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, 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.free_instance ();
+}
 #endif
-  };
 
+static hb_font_funcs_t *
+_hb_ft_get_font_funcs (void)
+{
+  return static_ft_funcs.get_unconst ();
+}
+
+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);
 }
 
 
 static hb_blob_t *
 reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
 {
@@ -679,56 +678,55 @@ hb_ft_font_changed (hb_font_t *font)
 hb_font_t *
 hb_ft_font_create_referenced (FT_Face ft_face)
 {
   FT_Reference_Face (ft_face);
   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 }
 
 
-/* Thread-safe, lock-free, FT_Library */
+static void free_static_ft_library (void);
+
+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)
+  {
+    FT_Library l;
+    if (FT_Init_FreeType (&l))
+      return nullptr;
 
-static FT_Library ft_library;
+#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 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) hb_atomic_ptr_get (&ft_library);
-  if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr))
-    goto retry;
-
-  FT_Done_FreeType (library);
+  static_ft_library.free_instance ();
 }
 #endif
 
 static FT_Library
 get_ft_library (void)
 {
-retry:
-  FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
-
-  if (unlikely (!library))
-  {
-    /* Not found; allocate one. */
-    if (FT_Init_FreeType (&library))
-      return nullptr;
-
-    if (!hb_atomic_ptr_cmpexch (&ft_library, 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
 _release_blob (FT_Face ft_face)
 {
   hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
 }
 
--- a/gfx/harfbuzz/src/hb-glib.cc
+++ b/gfx/harfbuzz/src/hb-glib.cc
@@ -26,16 +26,17 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 
 #include "hb-glib.h"
 
 #include "hb-unicode-private.hh"
+#include "hb-machinery-private.hh"
 
 
 #if !GLIB_CHECK_VERSION(2,29,14)
 static const hb_script_t
 glib_script_to_script[] =
 {
   HB_SCRIPT_COMMON,
   HB_SCRIPT_INHERITED,
@@ -359,61 +360,57 @@ hb_glib_unicode_decompose_compatibility 
   for (i = 0, c = utf8_decomposed; i < utf8_decomposed_len; i++, c = g_utf8_next_char (c))
     *decomposed++ = g_utf8_get_char (c);
 
   g_free (utf8_decomposed);
 
   return utf8_decomposed_len;
 }
 
-static hb_unicode_funcs_t *static_glib_funcs = nullptr;
+
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_glib_funcs (void)
-{
-retry:
-  hb_unicode_funcs_t *glib_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs);
-  if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, glib_funcs, nullptr))
-    goto retry;
+static void free_static_glib_funcs (void);
 
-  hb_unicode_funcs_destroy (glib_funcs);
-}
-#endif
-
-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 = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs);
-
-  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);
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
     hb_unicode_funcs_make_immutable (funcs);
 
-    if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, 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.free_instance ();
+}
 #endif
-  };
 
-  return hb_unicode_funcs_reference (funcs);
+hb_unicode_funcs_t *
+hb_glib_get_unicode_funcs (void)
+{
+  return static_glib_funcs.get_unconst ();
 }
 
+
+
 #if GLIB_CHECK_VERSION(2,31,10)
 
 static void
 _hb_g_bytes_unref (void *data)
 {
   g_bytes_unref ((GBytes *) data);
 }
 
--- a/gfx/harfbuzz/src/hb-graphite2.cc
+++ b/gfx/harfbuzz/src/hb-graphite2.cc
@@ -37,32 +37,34 @@
 HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face)
 HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font)
 
 
 /*
  * shaper face data
  */
 
-typedef struct hb_graphite2_tablelist_t {
+typedef struct hb_graphite2_tablelist_t
+{
   struct hb_graphite2_tablelist_t *next;
   hb_blob_t *blob;
   unsigned int tag;
 } hb_graphite2_tablelist_t;
 
-struct hb_graphite2_face_data_t {
+struct hb_graphite2_face_data_t
+{
   hb_face_t *face;
   gr_face   *grface;
-  hb_graphite2_tablelist_t *tlist;
+  hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist;
 };
 
 static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
 {
   hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
-  hb_graphite2_tablelist_t *tlist = face_data->tlist;
+  hb_graphite2_tablelist_t *tlist = face_data->tlist.get ();
 
   hb_blob_t *blob = nullptr;
 
   for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
     if (p->tag == tag) {
       blob = p->blob;
       break;
     }
@@ -75,20 +77,20 @@ static const void *hb_graphite2_get_tabl
     if (unlikely (!p)) {
       hb_blob_destroy (blob);
       return nullptr;
     }
     p->blob = blob;
     p->tag = tag;
 
 retry:
-    hb_graphite2_tablelist_t *tlist = (hb_graphite2_tablelist_t *) hb_atomic_ptr_get (&face_data->tlist);
+    hb_graphite2_tablelist_t *tlist = face_data->tlist.get ();
     p->next = tlist;
 
-    if (!hb_atomic_ptr_cmpexch (&face_data->tlist, tlist, p))
+    if (unlikely (!face_data->tlist.cmpexch (tlist, p)))
       goto retry;
   }
 
   unsigned int tlen;
   const char *d = hb_blob_get_data (blob, &tlen);
   *len = tlen;
   return d;
 }
@@ -119,17 +121,17 @@ hb_graphite2_face_data_t *
   }
 
   return data;
 }
 
 void
 _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
 {
-  hb_graphite2_tablelist_t *tlist = data->tlist;
+  hb_graphite2_tablelist_t *tlist = data->tlist.get ();
 
   while (tlist)
   {
     hb_graphite2_tablelist_t *old = tlist;
     hb_blob_destroy (tlist->blob);
     tlist = tlist->next;
     free (old);
   }
--- a/gfx/harfbuzz/src/hb-icu.cc
+++ b/gfx/harfbuzz/src/hb-icu.cc
@@ -27,16 +27,17 @@
  * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 
 #include "hb-icu.h"
 
 #include "hb-unicode-private.hh"
+#include "hb-machinery-private.hh"
 
 #include <unicode/uchar.h>
 #include <unicode/unorm2.h>
 #include <unicode/ustring.h>
 #include <unicode/utf16.h>
 #include <unicode/uversion.h>
 
 
@@ -159,29 +160,26 @@ hb_icu_unicode_script (hb_unicode_funcs_
   UScriptCode scriptCode = uscript_getScript(unicode, &status);
 
   if (unlikely (U_FAILURE (status)))
     return HB_SCRIPT_UNKNOWN;
 
   return hb_icu_script_to_script (scriptCode);
 }
 
-#if U_ICU_VERSION_MAJOR_NUM >= 49
-static const UNormalizer2 *normalizer;
-#endif
-
 static hb_bool_t
 hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 			hb_codepoint_t      a,
 			hb_codepoint_t      b,
 			hb_codepoint_t     *ab,
 			void               *user_data HB_UNUSED)
 {
 #if U_ICU_VERSION_MAJOR_NUM >= 49
   {
+    const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
     UChar32 ret = unorm2_composePair (normalizer, a, b);
     if (ret < 0) return false;
     *ab = ret;
     return true;
   }
 #endif
 
   /* We don't ifdef-out the fallback code such that compiler always
@@ -217,16 +215,17 @@ static hb_bool_t
 hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 			  hb_codepoint_t      ab,
 			  hb_codepoint_t     *a,
 			  hb_codepoint_t     *b,
 			  void               *user_data HB_UNUSED)
 {
 #if U_ICU_VERSION_MAJOR_NUM >= 49
   {
+    const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
     UChar decomposed[4];
     int len;
     UErrorCode icu_err = U_ZERO_ERROR;
     len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
 				      ARRAY_LENGTH (decomposed), &icu_err);
     if (U_FAILURE (icu_err) || len < 0) return false;
 
     len = u_countChar32 (decomposed, len);
@@ -340,60 +339,51 @@ hb_icu_unicode_decompose_compatibility (
   u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err);
   if (U_FAILURE (icu_err))
     return 0;
 
   return utf32_len;
 }
 
 
-static hb_unicode_funcs_t *static_icu_funcs = nullptr;
+static void free_static_icu_funcs (void);
+
+static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
+{
+  static inline hb_unicode_funcs_t *create (void)
+  {
+    void *user_data = nullptr;
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+    UErrorCode icu_err = U_ZERO_ERROR;
+    user_data = (void *) unorm2_getNFCInstance (&icu_err);
+    assert (user_data);
+#endif
+
+    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, user_data, nullptr);
+      HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+    hb_unicode_funcs_make_immutable (funcs);
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_icu_funcs);
+#endif
+
+    return funcs;
+  }
+} static_icu_funcs;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_icu_funcs (void)
 {
-retry:
-  hb_unicode_funcs_t *icu_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs);
-  if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, icu_funcs, nullptr))
-    goto retry;
-
-  hb_unicode_funcs_destroy (icu_funcs);
+  static_icu_funcs.free_instance ();
 }
 #endif
 
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void)
 {
-retry:
-  hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs);
-
-  if (unlikely (!funcs))
-  {
-#if U_ICU_VERSION_MAJOR_NUM >= 49
-    if (!hb_atomic_ptr_get (&normalizer)) {
-      UErrorCode icu_err = U_ZERO_ERROR;
-      /* We ignore failure in getNFCInstace(). */
-      (void) hb_atomic_ptr_cmpexch (&normalizer, nullptr, unorm2_getNFCInstance (&icu_err));
-    }
-#endif
-
-    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);
-      HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
-
-    hb_unicode_funcs_make_immutable (funcs);
-
-    if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, nullptr, funcs)) {
-      hb_unicode_funcs_destroy (funcs);
-      goto retry;
-    }
-
-#ifdef HB_USE_ATEXIT
-    atexit (free_static_icu_funcs); /* First person registers atexit() callback. */
-#endif
-  };
-
-  return hb_unicode_funcs_reference (funcs);
+  return static_icu_funcs.get_unconst ();
 }
--- a/gfx/harfbuzz/src/hb-iter-private.hh
+++ b/gfx/harfbuzz/src/hb-iter-private.hh
@@ -67,17 +67,17 @@ struct Iter<T *>
   /* Constructors. */
   inline Iter (T *array_, int length_) :
     array (array_), length (MAX (length_, 0)) {}
   template <unsigned int length_>
   explicit inline Iter (T (&array_)[length_]) :
     array (array_), length (length_) {}
 
   /* Emptiness. */
-  explicit inline operator bool (void) const { return bool (length); }
+  explicit_operator inline operator bool (void) const { return bool (length); }
 
   /* Current item. */
   inline T &operator * (void)
   {
     if (unlikely (!length)) return CrapOrNull(T);
     return *array;
   }
   inline T &operator -> (void)
--- a/gfx/harfbuzz/src/hb-machinery-private.hh
+++ b/gfx/harfbuzz/src/hb-machinery-private.hh
@@ -585,136 +585,208 @@ struct BEInt<Type, 4>
   private: uint8_t v[4];
 };
 
 
 /*
  * Lazy loaders.
  */
 
-template <unsigned int WheresFace,
-	  typename Subclass,
-	  typename Returned,
-	  typename Stored = Returned>
-struct hb_lazy_loader_t
+template <typename Data, unsigned int WheresData>
+struct hb_data_wrapper_t
+{
+  static_assert (WheresData > 0, "");
+
+  inline Data * get_data (void) const
+  {
+    return *(((Data **) (void *) 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>
 {
-  static_assert (WheresFace > 0, "");
+  template <typename Stored, typename Funcs>
+  inline Stored * call_create (void) const
+  {
+    return Funcs::create ();
+  }
+};
+
+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; };
 
-  /* 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); }
+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 = nullptr;
-  }
+  inline void init (void) { instance.set_relaxed (nullptr); }
   inline void fini (void)
   {
-    if (instance)
-      thiz ()->destroy (instance);
+    do_destroy (instance.get ());
+  }
+  inline void free_instance (void)
+  {
+  retry:
+    Stored *p = instance.get ();
+    if (unlikely (p && !this->instance.cmpexch (p, nullptr)))
+      goto retry;
+    do_destroy (p);
   }
 
-  inline const Returned * operator -> (void) const { return thiz ()->get (); }
-  inline const Returned & operator * (void) const { return *thiz ()->get (); }
+  inline Stored * do_create (void) const
+  {
+    Stored *p = this->template call_create<Stored, Funcs> ();
+    if (unlikely (!p))
+      p = const_cast<Stored *> (Funcs::get_null ());
+    return p;
+  }
+  static inline void do_destroy (Stored *p)
+  {
+    if (p && p != Funcs::get_null ())
+      Funcs::destroy (p);
+  }
+
+  inline const Returned * operator -> (void) const { return get (); }
+  inline const Returned & operator * (void) const { return *get (); }
+
+  inline Data * get_data (void) const
+  {
+    return *(((Data **) this) - WheresData);
+  }
 
   inline Stored * get_stored (void) const
   {
   retry:
-    Stored *p = (Stored *) hb_atomic_ptr_get (&this->instance);
+    Stored *p = this->instance.get ();
     if (unlikely (!p))
     {
-      hb_face_t *face = *(((hb_face_t **) this) - WheresFace);
-      if (likely (!p))
-	p = thiz ()->create (face);
-      if (unlikely (!p))
-	p = thiz ()->create (nullptr); /* Produce nil object. */
-      assert (p);
-      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<Stored **>(&this->instance), nullptr, p)))
+      p = do_create ();
+      if (unlikely (!this->instance.cmpexch (nullptr, p)))
       {
-        thiz ()->destroy (p);
+        do_destroy (p);
 	goto retry;
       }
     }
     return p;
   }
 
   inline void set_stored (Stored *instance_)
   {
     /* This *must* be called when there are no other threads accessing.
      * However, to make TSan, etc, happy, we using cmpexch. */
   retry:
-    Stored *p = (Stored *) hb_atomic_ptr_get (&this->instance);
-    if (p)
-    {
-      if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<Stored **>(&this->instance), p, instance_)))
-        goto retry;
-      thiz ()->destroy (p);
-    }
+    Stored *p = this->instance.get ();
+    if (unlikely (!this->instance.cmpexch (p, instance_)))
+      goto retry;
+    do_destroy (p);
   }
 
-  inline const Returned * get (void) const
+  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 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)
   {
-    return thiz ()->convert (get_stored ());
+    Stored *p = (Stored *) calloc (1, sizeof (Stored));
+    if (likely (p))
+      p->init (data);
+    return p;
   }
-
-  static inline const Returned* convert (const Stored *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 ();
+    free (p);
+  }
 
   private:
   /* Must only have one pointer. */
-  mutable Stored *instance;
+  hb_atomic_ptr_t<Stored *> instance;
 };
 
 /* Specializations. */
 
 template <unsigned int WheresFace, typename T>
-struct hb_object_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_object_lazy_loader_t<WheresFace, T>, T>
-{
-  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
-      p->init (face);
-    return p;
-  }
-  static inline void destroy (T *p)
-  {
-    if (p != &Null(T))
-    {
-      p->fini();
-      free (p);
-    }
-  }
-};
+struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
+						hb_face_lazy_loader_t<WheresFace, T>,
+						hb_face_t, WheresFace> {};
 
-template <unsigned int WheresFace, typename T>
-struct hb_table_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_table_lazy_loader_t<WheresFace, T>, T, hb_blob_t>
+template <typename T, unsigned int WheresFace>
+struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
+						 hb_table_lazy_loader_t<T, WheresFace>,
+						 hb_face_t, WheresFace,
+						 hb_blob_t>
 {
   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> ();
   }
 
   inline hb_blob_t* get_blob (void) const
   {
     return this->get_stored ();
   }
 };
 
+template <typename Subclass>
+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)
+  {
+    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<hb_unicode_funcs_t, Subclass>
+{
+  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 */
--- a/gfx/harfbuzz/src/hb-object-private.hh
+++ b/gfx/harfbuzz/src/hb-object-private.hh
@@ -138,22 +138,22 @@ struct hb_lockable_set_t
  */
 
 #define HB_REFERENCE_COUNT_INERT_VALUE 0
 #define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
 #define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT (HB_REFERENCE_COUNT_INERT_VALUE)}
 
 struct hb_reference_count_t
 {
-  hb_atomic_int_t ref_count;
+  mutable hb_atomic_int_t ref_count;
 
-  inline void init (int v) { ref_count.set_relaxed (v); }
+  inline void init (int v = 1) { ref_count.set_relaxed (v); }
   inline int get_relaxed (void) const { return ref_count.get_relaxed (); }
-  inline int inc (void) { return ref_count.inc (); }
-  inline int dec (void) { return ref_count.dec (); }
+  inline int inc (void) const { return ref_count.inc (); }
+  inline int dec (void) const { return ref_count.dec (); }
   inline void fini (void) { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); }
 
   inline bool is_inert (void) const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; }
   inline bool is_valid (void) const { return ref_count.get_relaxed () > 0; }
 };
 
 
 /* user_data */
@@ -189,19 +189,19 @@ struct hb_user_data_array_t
 
 /*
  * Object header
  */
 
 struct hb_object_header_t
 {
   hb_reference_count_t ref_count;
-  mutable hb_user_data_array_t *user_data;
+  hb_atomic_ptr_t<hb_user_data_array_t> user_data;
 
-#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, nullptr}
+#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_ATOMIC_PTR_INIT (nullptr)}
 
   private:
   ASSERT_POD ();
 };
 
 
 /*
  * Object
@@ -226,18 +226,18 @@ static inline Type *hb_object_create (vo
 
   hb_object_init (obj);
   hb_object_trace (obj, HB_FUNC);
   return obj;
 }
 template <typename Type>
 static inline void hb_object_init (Type *obj)
 {
-  obj->header.ref_count.init (1);
-  obj->header.user_data = nullptr;
+  obj->header.ref_count.init ();
+  obj->header.user_data.init ();
 }
 template <typename Type>
 static inline bool hb_object_is_inert (const Type *obj)
 {
   return unlikely (obj->header.ref_count.is_inert ());
 }
 template <typename Type>
 static inline bool hb_object_is_valid (const Type *obj)
@@ -266,56 +266,60 @@ static inline bool hb_object_destroy (Ty
 
   hb_object_fini (obj);
   return true;
 }
 template <typename Type>
 static inline void hb_object_fini (Type *obj)
 {
   obj->header.ref_count.fini (); /* Do this before user_data */
-  if (obj->header.user_data)
+  hb_user_data_array_t *user_data = obj->header.user_data.get ();
+  if (user_data)
   {
-    obj->header.user_data->fini ();
-    free (obj->header.user_data);
+    user_data->fini ();
+    free (user_data);
   }
 }
 template <typename Type>
 static inline bool hb_object_set_user_data (Type               *obj,
 					    hb_user_data_key_t *key,
 					    void *              data,
 					    hb_destroy_func_t   destroy,
 					    hb_bool_t           replace)
 {
   if (unlikely (!obj || hb_object_is_inert (obj)))
     return false;
   assert (hb_object_is_valid (obj));
 
 retry:
-  hb_user_data_array_t *user_data = (hb_user_data_array_t *) hb_atomic_ptr_get (&obj->header.user_data);
+  hb_user_data_array_t *user_data = obj->header.user_data.get ();
   if (unlikely (!user_data))
   {
     user_data = (hb_user_data_array_t *) calloc (sizeof (hb_user_data_array_t), 1);
     if (unlikely (!user_data))
       return false;
     user_data->init ();
-    if (unlikely (!hb_atomic_ptr_cmpexch (&obj->header.user_data, nullptr, user_data)))
+    if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data)))
     {
       user_data->fini ();
       free (user_data);
       goto retry;
     }
   }
 
   return user_data->set (key, data, destroy, replace);
 }
 
 template <typename Type>
 static inline void *hb_object_get_user_data (Type               *obj,
 					     hb_user_data_key_t *key)
 {
-  if (unlikely (!obj || hb_object_is_inert (obj) || !obj->header.user_data))
+  if (unlikely (!obj || hb_object_is_inert (obj)))
     return nullptr;
   assert (hb_object_is_valid (obj));
-  return obj->header.user_data->get (key);
+  hb_user_data_array_t *user_data = obj->header.user_data.get ();
+  if (!user_data)
+    return nullptr;
+  return user_data->get (key);
 }
 
 
 #endif /* HB_OBJECT_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-ot-font.cc
+++ b/gfx/harfbuzz/src/hb-ot-font.cc
@@ -24,16 +24,17 @@
  * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
  */
 
 #include "hb-private.hh"
 
 #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"
 #include "hb-ot-hmtx-table.hh"
 #include "hb-ot-kern-table.hh"
 #include "hb-ot-post-table.hh"
 
 #include "hb-ot-color-cbdt-table.hh"
@@ -65,20 +66,20 @@ struct hb_ot_font_t
     kern.fini ();
   }
 
   OT::cmap::accelerator_t cmap;
   OT::hmtx::accelerator_t h_metrics;
   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;
 };
 
 
 static hb_ot_font_t *
 _hb_ot_font_create (hb_face_t *face)
 {
   hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
 
@@ -220,40 +221,24 @@ hb_ot_get_font_v_extents (hb_font_t *fon
   const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
   metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
   metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
   metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
   // TODO Hook up variations.
   return ot_font->v_metrics.has_font_extents;
 }
 
-static hb_font_funcs_t *static_ot_funcs = nullptr;
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ot_funcs (void)
-{
-retry:
-  hb_font_funcs_t *ot_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
-  if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, 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 = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
-
-  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);
     hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
     hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
     hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr);
     hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr);
     //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
@@ -262,27 +247,36 @@ retry:
     //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, nullptr, nullptr);
     hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
     //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
     hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
     hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
 
     hb_font_funcs_make_immutable (funcs);
 
-    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, 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.free_instance ();
+}
 #endif
-  };
 
-  return funcs;
+static hb_font_funcs_t *
+_hb_ot_get_font_funcs (void)
+{
+  return static_ot_funcs.get_unconst ();
 }
 
 
 /**
  * hb_ot_font_set_funcs:
  *
  * Since: 0.9.28
  **/
--- a/gfx/harfbuzz/src/hb-ot-layout-private.hh
+++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh
@@ -200,31 +200,31 @@ struct hb_ot_layout_t
 #define HB_OT_LAYOUT_TABLE(Namespace, Type) \
 	HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type),
       HB_OT_LAYOUT_TABLES
 #undef HB_OT_LAYOUT_TABLE
     };
 
     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;
 };
 
 
 HB_INTERNAL hb_ot_layout_t *
 _hb_ot_layout_create (hb_face_t *face);
 
 HB_INTERNAL void
 _hb_ot_layout_destroy (hb_ot_layout_t *layout);
 
 
-#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
+#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot.get_relaxed ())
 
 
 /*
  * Buffer var routines.
  */
 
 /* buffer var allocations, used during the entire shaping process */
 #define unicode_props()		var2.u16[0]
--- a/gfx/harfbuzz/src/hb-ot-post-table.hh
+++ b/gfx/harfbuzz/src/hb-ot-post-table.hh
@@ -125,17 +125,17 @@ struct post
 
       const uint8_t *end = (uint8_t *) table + table_length;
       for (const uint8_t *data = pool; data < end && data + *data <= end; data += 1 + *data)
 	index_to_offset.push (data - pool);
     }
     inline void fini (void)
     {
       index_to_offset.fini ();
-      free (gids_sorted_by_name);
+      free (gids_sorted_by_name.get ());
     }
 
     inline bool get_glyph_name (hb_codepoint_t glyph,
 				char *buf, unsigned int buf_len) const
     {
       hb_bytes_t s = find_glyph_name (glyph);
       if (!s.len)
         return false;
@@ -157,29 +157,30 @@ struct post
 
       if (len < 0)
 	len = strlen (name);
 
       if (unlikely (!len))
 	return false;
 
     retry:
-      uint16_t *gids = (uint16_t *) hb_atomic_ptr_get (&gids_sorted_by_name);
+      uint16_t *gids = gids_sorted_by_name.get ();
 
       if (unlikely (!gids))
       {
 	gids = (uint16_t *) malloc (count * sizeof (gids[0]));
 	if (unlikely (!gids))
 	  return false; /* Anything better?! */
 
 	for (unsigned int i = 0; i < count; i++)
 	  gids[i] = i;
 	hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
 
-	if (!hb_atomic_ptr_cmpexch (&gids_sorted_by_name, nullptr, gids)) {
+	if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
+	{
 	  free (gids);
 	  goto retry;
 	}
       }
 
       hb_bytes_t st (name, len);
       const uint16_t *gid = (const uint16_t *) hb_bsearch_r (&st, gids, count, sizeof (gids[0]), cmp_key, (void *) this);
       if (gid)
@@ -250,17 +251,17 @@ struct post
     }
 
     private:
     hb_blob_t *blob;
     uint32_t version;
     const ArrayOf<HBUINT16> *glyphNameIndex;
     hb_vector_t<uint32_t, 1> index_to_offset;
     const uint8_t *pool;
-    mutable uint16_t *gids_sorted_by_name;
+    hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
   };
 
   public:
   FixedVersion<>version;		/* 0x00010000 for version 1.0
 					 * 0x00020000 for version 2.0
 					 * 0x00025000 for version 2.5 (deprecated)
 					 * 0x00030000 for version 3.0 */
   Fixed		italicAngle;		/* Italic angle in counter-clockwise degrees
--- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
+++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc
@@ -245,17 +245,17 @@ struct arabic_shape_plan_t
   ASSERT_POD ();
 
   /* The "+ 1" in the next array is to accommodate for the "NONE" command,
    * which is not an OpenType feature, but this simplifies the code by not
    * having to do a "if (... < NONE) ..." and just rely on the fact that
    * mask_array[NONE] == 0. */
   hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
 
-  mutable arabic_fallback_plan_t *fallback_plan;
+  hb_atomic_ptr_t<arabic_fallback_plan_t> fallback_plan;
 
   unsigned int do_fallback : 1;
   unsigned int has_stch : 1;
 };
 
 void *
 data_create_arabic (const hb_ot_shape_plan_t *plan)
 {
@@ -275,17 +275,17 @@ data_create_arabic (const hb_ot_shape_pl
   return arabic_plan;
 }
 
 void
 data_destroy_arabic (void *data)
 {
   arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
 
-  arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
+  arabic_fallback_plan_destroy (arabic_plan->fallback_plan.get ());
 
   free (data);
 }
 
 static void
 arabic_joining (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
@@ -398,22 +398,23 @@ arabic_fallback_shape (const hb_ot_shape
 		       hb_buffer_t *buffer)
 {
   const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
 
   if (!arabic_plan->do_fallback)
     return;
 
 retry:
-  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
+  arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan.get ();
   if (unlikely (!fallback_plan))
   {
     /* This sucks.  We need a font to build the fallback plan... */
     fallback_plan = arabic_fallback_plan_create (plan, font);
-    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, nullptr, fallback_plan))) {
+    if (unlikely (!arabic_plan->fallback_plan.cmpexch (nullptr, fallback_plan)))
+    {
       arabic_fallback_plan_destroy (fallback_plan);
       goto retry;
     }
   }
 
   arabic_fallback_plan_shape (fallback_plan, font, buffer);
 }
 
--- a/gfx/harfbuzz/src/hb-private.hh
+++ b/gfx/harfbuzz/src/hb-private.hh
@@ -120,17 +120,30 @@ struct _hb_alignof
     T t;
   };
   static constexpr size_t value = offsetof (s, t);
 };
 #ifndef alignof
 #define alignof(x) (_hb_alignof<x>::value)
 #endif
 
-#endif // __cplusplus < 201103L
+/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
+#ifndef explicit_operator
+#define explicit_operator
+#endif
+
+#else /* __cplusplus >= 201103L */
+
+/* https://github.com/harfbuzz/harfbuzz/issues/1127 */
+#ifndef explicit_operator
+#define explicit_operator explicit
+#endif
+
+#endif /* __cplusplus < 201103L */
+
 
 #if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
 #define likely(expr) (__builtin_expect (!!(expr), 1))
 #define unlikely(expr) (__builtin_expect (!!(expr), 0))
 #else
 #define likely(expr) (expr)
 #define unlikely(expr) (expr)
 #endif
--- a/gfx/harfbuzz/src/hb-shape-plan.cc
+++ b/gfx/harfbuzz/src/hb-shape-plan.cc
@@ -44,21 +44,23 @@ hb_shape_plan_plan (hb_shape_plan_t    *
 		  num_user_features,
 		  num_coords,
 		  shaper_list);
 
   const hb_shaper_pair_t *shapers = _hb_shapers_get ();
 
 #define HB_SHAPER_PLAN(shaper) \
 	HB_STMT_START { \
-	  if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
-	    HB_SHAPER_DATA (shaper, shape_plan) = \
+	  if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) \
+	  { \
+	    /* XXX-MT-bug What happened to *ensure*ing this?!!!! */ \
+	    HB_SHAPER_DATA (shaper, shape_plan).set_relaxed ( \
 	      HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
 							       user_features, num_user_features, \
-							       coords, num_coords); \
+							       coords, num_coords)); \
 	    shape_plan->shaper_func = _hb_##shaper##_shape; \
 	    shape_plan->shaper_name = #shaper; \
 	    return; \
 	  } \
 	} HB_STMT_END
 
   if (likely (!shaper_list)) {
     for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
@@ -101,20 +103,20 @@ DEFINE_NULL_INSTANCE (hb_shape_plan_t) =
 
   nullptr, /* user_features */
   0,    /* num_user_featurs */
 
   nullptr, /* coords */
   0,    /* num_coords */
 
   {
-#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID),
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
-  }
+  },
 };
 
 
 /**
  * hb_shape_plan_create: (Xconstructor)
  * @face: 
  * @props: 
  * @user_features: (array length=num_user_features):
@@ -334,17 +336,17 @@ hb_shape_plan_execute (hb_shape_plan_t  
   if (unlikely (hb_object_is_inert (shape_plan)))
     return false;
 
   assert (shape_plan->face_unsafe == font->face);
   assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
 
 #define HB_SHAPER_EXECUTE(shaper) \
 	HB_STMT_START { \
-	  return HB_SHAPER_DATA (shaper, shape_plan) && \
+	  return HB_SHAPER_DATA (shaper, shape_plan).get () && \
 		 hb_##shaper##_shaper_font_data_ensure (font) && \
 		 _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
 	} HB_STMT_END
 
   if (0)
     ;
 #define HB_SHAPER_IMPLEMENT(shaper) \
   else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
@@ -512,17 +514,17 @@ hb_shape_plan_create_cached2 (hb_face_t 
 #undef HB_SHAPER_IMPLEMENT
 
     if (unlikely (!proposal.shaper_func))
       return hb_shape_plan_get_empty ();
   }
 
 
 retry:
-  hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
+  hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans.get ();
 
   /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */
   if (!hb_coords_present (coords, num_coords))
     for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
       if (hb_shape_plan_matches (node->shape_plan, &proposal))
       {
         DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
         return hb_shape_plan_reference (node->shape_plan);
@@ -547,17 +549,18 @@ retry:
 
   hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
   if (unlikely (!node))
     return shape_plan;
 
   node->shape_plan = shape_plan;
   node->next = cached_plan_nodes;
 
-  if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
+  if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node)))
+  {
     hb_shape_plan_destroy (shape_plan);
     free (node);
     goto retry;
   }
   DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
 
   return hb_shape_plan_reference (shape_plan);
 }
--- a/gfx/harfbuzz/src/hb-shape.cc
+++ b/gfx/harfbuzz/src/hb-shape.cc
@@ -27,86 +27,88 @@
  */
 
 #include "hb-private.hh"
 
 #include "hb-shaper-private.hh"
 #include "hb-shape-plan-private.hh"
 #include "hb-buffer-private.hh"
 #include "hb-font-private.hh"
+#include "hb-machinery-private.hh"
 
 /**
  * SECTION:hb-shape
  * @title: Shaping
  * @short_description: Conversion of text strings into positioned glyphs
  * @include: hb.h
  *
  * Shaping is the central operation of HarfBuzz. Shaping operates on buffers,
  * which are sequences of Unicode characters that use the same font and have
  * the same text direction, script and language. After shaping the buffer
  * contains the output glyphs and their positions.
  **/
 
-static const char **static_shaper_list;
+
+static void free_static_shaper_list (void);
+static const char *nil_shaper_list[] = {nullptr};
+
+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)
+  {
+    return nil_shaper_list;
+  }
+} static_shaper_list;
 
 #ifdef HB_USE_ATEXIT
 static
 void free_static_shaper_list (void)
 {
-retry:
-  const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
-  if (!hb_atomic_ptr_cmpexch (&static_shaper_list, shaper_list, nullptr))
-    goto retry;
-
-  free (shaper_list);
+  static_shaper_list.free_instance ();
 }
 #endif
 
+
 /**
  * hb_shape_list_shapers:
  *
  * Retrieves the list of shapers supported by HarfBuzz.
  *
  * Return value: (transfer none) (array zero-terminated=1): an array of
  *    constant strings
  *
  * Since: 0.9.2
  **/
 const char **
 hb_shape_list_shapers (void)
 {
-retry:
-  const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list);
-
-  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 (!hb_atomic_ptr_cmpexch (&static_shaper_list, 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 ();
 }
 
 
 /**
  * hb_shape_full:
  * @font: an #hb_font_t to use for shaping
  * @buffer: an #hb_buffer_t to shape
  * @features: (array length=num_features) (allow-none): an array of user
--- a/gfx/harfbuzz/src/hb-shaper-impl-private.hh
+++ b/gfx/harfbuzz/src/hb-shaper-impl-private.hh
@@ -31,13 +31,13 @@
 
 #include "hb-shaper-private.hh"
 #include "hb-shape-plan-private.hh"
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
 
 
 #ifdef HB_SHAPER
-#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object)
+#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object).get ()
 #endif
 
 
 #endif /* HB_SHAPER_IMPL_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-shaper-private.hh
+++ b/gfx/harfbuzz/src/hb-shaper-private.hh
@@ -51,82 +51,84 @@ HB_INTERNAL const hb_shaper_pair_t *
 
 /* Means: succeeded, but don't need to keep any data. */
 #define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
 /* Means: tried but failed to create. */
 #define HB_SHAPER_DATA_INVALID ((void *) -1)
 
 #define HB_SHAPER_DATA_TYPE_NAME(shaper, object)	hb_##shaper##_##object##_data_t
 #define HB_SHAPER_DATA_TYPE(shaper, object)		struct HB_SHAPER_DATA_TYPE_NAME(shaper, object)
-#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance)	(* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
+#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance)	(* reinterpret_cast<hb_atomic_ptr_t<HB_SHAPER_DATA_TYPE(shaper, object) *> *> (&(instance)->shaper_data.shaper))
 #define HB_SHAPER_DATA(shaper, object)			HB_SHAPER_DATA_INSTANCE(shaper, object, object)
 #define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create
 #define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_destroy
 #define HB_SHAPER_DATA_ENSURE_FUNC(shaper, object)	hb_##shaper##_shaper_##object##_data_ensure
 
 #define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
 	HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
 	extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
 	HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
 	extern "C" HB_INTERNAL void \
 	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data); \
 	extern "C" HB_INTERNAL bool \
 	HB_SHAPER_DATA_ENSURE_FUNC (shaper, object) (hb_##object##_t *object)
 
 #define HB_SHAPER_DATA_DESTROY(shaper, object) \
-    if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \
+    if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object).get ()) \
       if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \
         HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data);
 
 #define HB_SHAPER_DATA_ENSURE_DEFINE(shaper, object) \
 	HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(shaper, object, true)
 
 #define HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(shaper, object, condition) \
 bool \
 HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \
 {\
   retry: \
-  HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
+  HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object).get (); \
   if (likely (data) && !(condition)) { \
-    /* Note that evaluating condition above can be dangerous if another thread \
+    /* XXX-MT-bug \
+     * Note that evaluating condition above can be dangerous if another thread \
      * got here first and destructed data.  That's, as always, bad use pattern. \
      * If you modify the font (change font size), other threads must not be \
      * using it at the same time.  However, since this check is delayed to \
      * when one actually tries to shape something, this is a XXX race condition \
      * (and the only know we have that I know of) right now.  Ie. you modify the \
      * font size in one thread, then (supposedly safely) try to use it from two \
      * or more threads and BOOM!  I'm not sure how to fix this.  We want RCU. \
      * Maybe when it doesn't matter when we finally implement AAT shaping, as
      * this (condition) is currently only used by hb-coretext. */ \
     /* Drop and recreate. */ \
     /* If someone dropped it in the mean time, throw it away and don't touch it. \
      * Otherwise, destruct it. */ \
-    if (hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), data, nullptr)) { \
+    if (likely (HB_SHAPER_DATA (shaper, object).cmpexch (data, nullptr))) \
+    { \
       HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
     } \
     goto retry; \
   } \
   if (unlikely (!data)) { \
     data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
     if (unlikely (!data)) \
       data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
-    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), nullptr, data)) { \
+    if (unlikely (!HB_SHAPER_DATA (shaper, object).cmpexch (nullptr, data))) { \
       if (data && \
 	  data != HB_SHAPER_DATA_INVALID && \
 	  data != HB_SHAPER_DATA_SUCCEEDED) \
 	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
       goto retry; \
     } \
   } \
   return data != nullptr && (void *) data != HB_SHAPER_DATA_INVALID; \
 }
 
 
 /* For embedding in face / font / ... */
 struct hb_shaper_data_t {
-#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
+#define HB_SHAPER_IMPLEMENT(shaper) hb_atomic_ptr_t<void *> shaper;
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 };
 #define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
 
 
 #endif /* HB_SHAPER_PRIVATE_HH */
--- a/gfx/harfbuzz/src/hb-shaper.cc
+++ b/gfx/harfbuzz/src/hb-shaper.cc
@@ -21,71 +21,48 @@
  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
 #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[] = {
 #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
 #include "hb-shaper-list.hh"
 #undef HB_SHAPER_IMPLEMENT
 };
 
 
-/* Thread-safe, lock-free, shapers */
-
-static const hb_shaper_pair_t *static_shapers;
-
-#ifdef HB_USE_ATEXIT
-static
-void free_static_shapers (void)
-{
-retry:
-  hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
-  if (!hb_atomic_ptr_cmpexch (&static_shapers, shapers, nullptr))
-    goto retry;
+static void free_static_shapers (void);
 
-  if (unlikely (shapers != all_shapers))
-    free ((void *) shapers);
-}
-#endif
-
-const hb_shaper_pair_t *
-_hb_shapers_get (void)
+static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t,
+							  hb_shapers_lazy_loader_t>
 {
-retry:
-  hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
-
-  if (unlikely (!shapers))
+  static inline hb_shaper_pair_t *create (void)
   {
     char *env = getenv ("HB_SHAPER_LIST");
-    if (!env || !*env) {
-      (void) hb_atomic_ptr_cmpexch (&static_shapers, 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));
-    if (unlikely (!shapers)) {
-      (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]);
-      return (const hb_shaper_pair_t *) all_shapers;
-    }
+    hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers));
+    if (unlikely (!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);
 
       for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
 	if (end - p == (int) strlen (shapers[j].name) &&
 	    0 == strncmp (shapers[j].name, p, end - p))
 	{
@@ -97,20 +74,37 @@ retry:
 	}
 
       if (!*end)
 	break;
       else
 	p = end + 1;
     }
 
-    if (!hb_atomic_ptr_cmpexch (&static_shapers, nullptr, shapers)) {
-      free (shapers);
-      goto retry;
-    }
+#ifdef HB_USE_ATEXIT
+    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;
 
 #ifdef HB_USE_ATEXIT
-    atexit (free_static_shapers); /* First person registers atexit() callback. */
+static
+void free_static_shapers (void)
+{
+  static_shapers.free_instance ();
+}
 #endif
-  }
 
-  return shapers;
+const hb_shaper_pair_t *
+_hb_shapers_get (void)
+{
+  return static_shapers.get_unconst ();
 }
--- a/gfx/harfbuzz/src/hb-ucdn.cc
+++ b/gfx/harfbuzz/src/hb-ucdn.cc
@@ -12,16 +12,17 @@
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include "hb-private.hh"
 
 #include "hb-unicode-private.hh"
+#include "hb-machinery-private.hh"
 
 #include "ucdn.h"
 
 static const hb_script_t ucdn_script_translate[] =
 {
     HB_SCRIPT_COMMON,
     HB_SCRIPT_LATIN,
     HB_SCRIPT_GREEK,
@@ -233,53 +234,46 @@ hb_ucdn_decompose(hb_unicode_funcs_t *uf
 static unsigned int
 hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED,
 				hb_codepoint_t u, hb_codepoint_t *decomposed,
 				void *user_data HB_UNUSED)
 {
     return ucdn_compat_decompose(u, decomposed);
 }
 
-static hb_unicode_funcs_t *static_ucdn_funcs = nullptr;
 
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ucdn_funcs (void)
-{
-retry:
-  hb_unicode_funcs_t *ucdn_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs);
-  if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, 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 = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs);
-
-  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);
       HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
     hb_unicode_funcs_make_immutable (funcs);
 
-    if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, 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.free_instance ();
+}
 #endif
-  };
 
-  return hb_unicode_funcs_reference (funcs);
+extern "C" HB_INTERNAL
+hb_unicode_funcs_t *
+hb_ucdn_get_unicode_funcs (void)
+{
+  return static_ucdn_funcs.get_unconst ();
 }
--- a/gfx/harfbuzz/src/hb-uniscribe.cc
+++ b/gfx/harfbuzz/src/hb-uniscribe.cc
@@ -185,17 +185,18 @@ hb_ScriptPlaceOpenType(
 		      psva,
 		      psa,
 		      piAdvance,
 		      pGoffset,
 		      pABC);
 }
 
 
-struct hb_uniscribe_shaper_funcs_t {
+struct hb_uniscribe_shaper_funcs_t
+{
   SIOT ScriptItemizeOpenType;
   SSOT ScriptShapeOpenType;
   SPOT ScriptPlaceOpenType;
 
   inline void init (void)
   {
     HMODULE hinstLib;
     this->ScriptItemizeOpenType = nullptr;
@@ -215,57 +216,59 @@ struct hb_uniscribe_shaper_funcs_t {
     {
       DEBUG_MSG (UNISCRIBE, nullptr, "OpenType versions of functions not found; falling back.");
       this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
       this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
       this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
     }
   }
 };
-static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;
+
+
+static void free_static_uniscribe_shaper_funcs (void);
+
+static struct hb_uniscribe_shaper_funcs_lazy_loader_t : hb_lazy_loader_t<hb_uniscribe_shaper_funcs_t,
+									 hb_uniscribe_shaper_funcs_lazy_loader_t>
+{
+  static inline hb_uniscribe_shaper_funcs_t *create (void)
+  {
+    hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
+    if (unlikely (!funcs))
+      return nullptr;
+
+    funcs->init ();
 
 #ifdef HB_USE_ATEXIT
-static inline void
-free_uniscribe_funcs (void)
+    atexit (free_static_uniscribe_shaper_funcs);
+#endif
+
+    return funcs;
+  }
+  static inline void destroy (hb_uniscribe_shaper_funcs_t *p)
+  {
+    free ((void *) p);
+  }
+  static inline hb_uniscribe_shaper_funcs_t *get_null (void)
+  {
+    return nullptr;
+  }
+} static_uniscribe_shaper_funcs;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_uniscribe_shaper_funcs (void)
 {
-retry:
-  hb_uniscribe_shaper_funcs_t *local_uniscribe_funcs =
-    (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
-  if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, local_uniscribe_funcs, nullptr))
-    goto retry;
-
-  free (uniscribe_funcs);
+  static_uniscribe_shaper_funcs.free_instance ();
 }
 #endif
 
 static hb_uniscribe_shaper_funcs_t *
 hb_uniscribe_shaper_get_funcs (void)
 {
-retry:
-  hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
-
-  if (unlikely (!funcs))
-  {
-    funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
-    if (unlikely (!funcs))
-      return nullptr;
-
-    funcs->init ();
-
-    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, nullptr, funcs)) {
-      free (funcs);
-      goto retry;
-    }
-
-#ifdef HB_USE_ATEXIT
-    atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
-#endif
-  }
-
-  return funcs;
+  return static_uniscribe_shaper_funcs.get_unconst ();
 }
 
 
 struct active_feature_t {
   OPENTYPE_FEATURE_RECORD rec;
   unsigned int order;
 
   static int cmp (const void *pa, const void *pb) {
--- a/gfx/harfbuzz/src/hb-version.h
+++ b/gfx/harfbuzz/src/hb-version.h
@@ -33,19 +33,19 @@
 
 #include "hb-common.h"
 
 HB_BEGIN_DECLS
 
 
 #define HB_VERSION_MAJOR 1
 #define HB_VERSION_MINOR 8
-#define HB_VERSION_MICRO 7
+#define HB_VERSION_MICRO 8
 
-#define HB_VERSION_STRING "1.8.7"
+#define HB_VERSION_STRING "1.8.8"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
 	 HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
 
 
 HB_EXTERN void
 hb_version (unsigned int *major,
--- a/gfx/harfbuzz/update.sh
+++ b/gfx/harfbuzz/update.sh
@@ -1,16 +1,16 @@
 #!/bin/sh
 
 # Script to update the mozilla in-tree copy of the HarfBuzz library.
 # Run this within the /gfx/harfbuzz directory of the source tree.
 
 MY_TEMP_DIR=`mktemp -d -t harfbuzz_update.XXXXXX` || exit 1
 
-VERSION=1.8.7
+VERSION=1.8.8
 
 git clone https://github.com/harfbuzz/harfbuzz ${MY_TEMP_DIR}/harfbuzz
 git -C ${MY_TEMP_DIR}/harfbuzz checkout ${VERSION}
 
 COMMIT=$(git -C ${MY_TEMP_DIR}/harfbuzz rev-parse HEAD)
 perl -p -i -e "s/(\d+\.)(\d+\.)(\d+)/${VERSION}/" README-mozilla;
 perl -p -i -e "s/\[commit [0-9a-f]{40}\]/[commit ${COMMIT}]/" README-mozilla;