Merge inbound to mozilla-central. a=merge
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Tue, 14 Aug 2018 12:30:50 +0300
changeset 431377 914b3b370ad059a04ad751642b74e013f8e3ad08
parent 431376 3e66cf1dad95c1594448d82bcac82711f8ba155e (current diff)
parent 431327 397dbf4d571f60282bed90ce11918adfae99b0d1 (diff)
child 431378 a12c995d61221cbeea9a53d48e5443f87d2d28ce
child 431451 a62c083163d60a523e2d3cae38c6b1a8adac0817
child 431461 0360d2d3a79a0fc685b65717ee7b4a9310013985
push id106435
push userebalazs@mozilla.com
push dateTue, 14 Aug 2018 09:36:55 +0000
treeherdermozilla-inbound@a12c995d6122 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
914b3b370ad0 / 63.0a1 / 20180814100100 / files
nightly linux64
914b3b370ad0 / 63.0a1 / 20180814100100 / files
nightly mac
914b3b370ad0 / 63.0a1 / 20180814100100 / files
nightly win32
914b3b370ad0 / 63.0a1 / 20180814100100 / files
nightly win64
914b3b370ad0 / 63.0a1 / 20180814100100 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
browser/extensions/formautofill/bootstrap.js
browser/extensions/formautofill/install.rdf.in
browser/extensions/formautofill/skin/shared/autocomplete-item.css
browser/extensions/formautofill/skin/shared/editDialog.css
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -707,17 +707,17 @@ nsIntRect
 Accessible::Bounds() const
 {
   return BoundsInAppUnits().ToNearestPixels(mDoc->PresContext()->AppUnitsPerDevPixel());
 }
 
 nsIntRect
 Accessible::BoundsInCSSPixels() const
 {
-  return BoundsInAppUnits().ToNearestPixels(mDoc->PresContext()->AppUnitsPerCSSPixel());
+  return BoundsInAppUnits().ToNearestPixels(AppUnitsPerCSSPixel());
 }
 
 void
 Accessible::SetSelected(bool aSelect)
 {
   if (!HasOwnContent())
     return;
 
--- a/build/debian-packages/valgrind-wheezy.diff
+++ b/build/debian-packages/valgrind-wheezy.diff
@@ -1,4821 +1,75 @@
-diff -Nru valgrind-3.13.0/debian/changelog valgrind-3.13.0/debian/changelog
---- valgrind-3.13.0/debian/changelog	2017-07-24 08:41:05.000000000 +0900
-+++ valgrind-3.13.0/debian/changelog	2018-01-11 17:08:25.000000000 +0900
-@@ -1,3 +1,13 @@
-+valgrind (1:3.13.0-1.deb7moz1) wheezy; urgency=medium
-+
-+  * Mozilla backport for wheezy.
-+  * debian/patches/valgrind-epochs.patch: Apply patch from Julian Seward that
-+    allows us to write a suppression for a leak in a library that gets
-+    unloaded before shutdown.
-+    Ref: https://bugs.kde.org/show_bug.cgi?id=79362
-+
-+ -- Mike Hommey <glandium@debian.org>  Thu, 11 Jan 2018 17:08:25 +0900
-+
- valgrind (1:3.13.0-1) unstable; urgency=medium
+diff -Nru valgrind-3.13.0/debian/patches/05_fix-callgrind_control.patch valgrind-3.14.0.git20180806/debian/patches/05_fix-callgrind_control.patch
+--- valgrind-3.13.0/debian/patches/05_fix-callgrind_control.patch	2017-07-24 08:41:05.000000000 +0900
++++ valgrind-3.14.0.git20180806/debian/patches/05_fix-callgrind_control.patch	2018-08-10 16:00:19.142494503 +0900
+@@ -7,9 +7,9 @@
  
-   * New upstream release
-diff -Nru valgrind-3.13.0/debian/patches/series valgrind-3.13.0/debian/patches/series
+ --- a/callgrind/callgrind_control.in
+ +++ b/callgrind/callgrind_control.in
+-@@ -29,7 +29,7 @@
++@@ -33,7 +33,7 @@
+    @pids = ();
+-   open LIST, "vgdb $vgdbPrefixOption -l|";
++   open LIST, $vgdb_exe . " $vgdbPrefixOption -l|";
+    while(<LIST>) {
+ -      if (/^use --pid=(\d+) for \S*?valgrind\s+(.*?)\s*$/) {
+ +      if (/^use --pid=(\d+) for \S*?valgrind\.bin\s+(.*?)\s*$/) {
+diff -Nru valgrind-3.13.0/debian/patches/07_fix-spelling-in-binary.patch valgrind-3.14.0.git20180806/debian/patches/07_fix-spelling-in-binary.patch
+--- valgrind-3.13.0/debian/patches/07_fix-spelling-in-binary.patch	2017-07-24 08:41:05.000000000 +0900
++++ valgrind-3.14.0.git20180806/debian/patches/07_fix-spelling-in-binary.patch	2018-08-10 16:01:46.110793537 +0900
+@@ -16,7 +16,7 @@
+            && VKI_S_ISREG(stat_buf.mode)
+ --- a/coregrind/m_gdbserver/server.c
+ +++ b/coregrind/m_gdbserver/server.c
+-@@ -254,7 +254,7 @@
++@@ -256,7 +256,7 @@
+  "    Valgrind internal host status/memory\n"
+  "  v.translate <addr> [<traceflags>]  : debug translation of <addr> with <traceflags>\n"
+  "    (default traceflags 0b00100000 : show after instrumentation)\n"
+@@ -27,7 +27,7 @@
+     case  1: /* v.set */
+ --- a/VEX/priv/ir_defs.c
+ +++ b/VEX/priv/ir_defs.c
+-@@ -4643,7 +4643,7 @@
++@@ -4698,7 +4698,7 @@
+     if (bb->stmts_used < 0 || bb->stmts_size < 8
+         || bb->stmts_used > bb->stmts_size)
+        /* this BB is so strange we can't even print it */
+@@ -60,7 +60,7 @@
+                  " N-plicated elts\n");
+ --- a/coregrind/m_scheduler/scheduler.c
+ +++ b/coregrind/m_scheduler/scheduler.c
+-@@ -2147,7 +2147,7 @@
++@@ -2208,7 +2208,7 @@
+        "to recompile such code, using the header files from this version of\n"
+        "Valgrind, and not any previous version.\n"
+        "\n"
+@@ -71,7 +71,7 @@
+        "   http://www.valgrind.org/support/bug_reports.html\n"
+ --- a/coregrind/m_xtree.c
+ +++ b/coregrind/m_xtree.c
+-@@ -946,7 +946,7 @@
++@@ -961,7 +961,7 @@
+        FP("n%u: %llu %s\n", n_groups, top_total, header->top_node_desc);
+  
+        /* Output depth 0 groups. */
+diff -Nru valgrind-3.13.0/debian/patches/09_fix-armhf-detect.patch valgrind-3.14.0.git20180806/debian/patches/09_fix-armhf-detect.patch
+--- valgrind-3.13.0/debian/patches/09_fix-armhf-detect.patch	2017-07-24 08:41:05.000000000 +0900
++++ valgrind-3.14.0.git20180806/debian/patches/09_fix-armhf-detect.patch	2018-08-10 16:02:01.462846319 +0900
+@@ -6,7 +6,7 @@
+ 
+ --- a/configure.ac
+ +++ b/configure.ac
+-@@ -234,7 +234,7 @@
++@@ -252,7 +252,7 @@
+          ARCH_MAX="s390x"
+          ;;
+  
+diff -Nru valgrind-3.13.0/debian/patches/series valgrind-3.14.0.git20180806/debian/patches/series
 --- valgrind-3.13.0/debian/patches/series	2017-07-24 08:41:05.000000000 +0900
-+++ valgrind-3.13.0/debian/patches/series	2018-01-11 17:08:25.000000000 +0900
-@@ -4,3 +4,4 @@
++++ valgrind-3.14.0.git20180806/debian/patches/series	2018-08-10 15:59:43.434371705 +0900
+@@ -2,5 +2,4 @@
+ 04_workaround-SIGSEGV-on-PPC.patch
+ 05_fix-callgrind_control.patch
  07_fix-spelling-in-binary.patch
- 08_fix-spelling-in-manpage.patch
+-08_fix-spelling-in-manpage.patch
  09_fix-armhf-detect.patch
-+valgrind-epochs.patch
-diff -Nru valgrind-3.13.0/debian/patches/valgrind-epochs.patch valgrind-3.13.0/debian/patches/valgrind-epochs.patch
---- valgrind-3.13.0/debian/patches/valgrind-epochs.patch	1970-01-01 09:00:00.000000000 +0900
-+++ valgrind-3.13.0/debian/patches/valgrind-epochs.patch	2018-01-11 17:08:25.000000000 +0900
-@@ -0,0 +1,4792 @@
-+Index: valgrind-3.13.0/Makefile.am
-+===================================================================
-+--- valgrind-3.13.0.orig/Makefile.am
-++++ valgrind-3.13.0/Makefile.am
-+@@ -16,6 +16,10 @@ EXP_TOOLS = 	exp-sgcheck \
-+ 		exp-bbv \
-+ 		exp-dhat
-+ 
-++#TOOLS = none memcheck
-++#EXP_TOOLS =
-++
-++
-+ # Put docs last because building the HTML is slow and we want to get
-+ # everything else working before we try it.
-+ SUBDIRS = \
-+Index: valgrind-3.13.0/cachegrind/cg_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/cachegrind/cg_main.c
-++++ valgrind-3.13.0/cachegrind/cg_main.c
-+@@ -210,12 +210,14 @@ static HChar* get_perm_string(const HCha
-+ static void get_debug_info(Addr instr_addr, const HChar **dir,
-+                            const HChar **file, const HChar **fn, UInt* line)
-+ {
-++   DiEpoch ep = VG_(current_DiEpoch)();
-+    Bool found_file_line = VG_(get_filename_linenum)(
-++                             ep,
-+                              instr_addr, 
-+                              file, dir,
-+                              line
-+                           );
-+-   Bool found_fn        = VG_(get_fnname)(instr_addr, fn);
-++   Bool found_fn        = VG_(get_fnname)(ep, instr_addr, fn);
-+ 
-+    if (!found_file_line) {
-+       *file = "???";
-+Index: valgrind-3.13.0/callgrind/bb.c
-+===================================================================
-+--- valgrind-3.13.0.orig/callgrind/bb.c
-++++ valgrind-3.13.0/callgrind/bb.c
-+@@ -199,7 +199,8 @@ obj_node* obj_of_address(Addr addr)
-+   DebugInfo* di;
-+   PtrdiffT offset;
-+ 
-+-  di = VG_(find_DebugInfo)(addr);
-++  DiEpoch ep = VG_(current_DiEpoch)();
-++  di = VG_(find_DebugInfo)(ep, addr);
-+   obj = CLG_(get_obj_node)( di );
-+ 
-+   /* Update symbol offset in object if remapped */
-+Index: valgrind-3.13.0/callgrind/dump.c
-+===================================================================
-+--- valgrind-3.13.0.orig/callgrind/dump.c
-++++ valgrind-3.13.0/callgrind/dump.c
-+@@ -373,7 +373,8 @@ Bool get_debug_pos(BBCC* bbcc, Addr addr
-+ 	found_file_line = debug_cache_info[cachepos];
-+     }
-+     else {
-+-	found_file_line = VG_(get_filename_linenum)(addr,
-++        DiEpoch ep = VG_(current_DiEpoch)();
-++	found_file_line = VG_(get_filename_linenum)(ep, addr,
-+ 						    &file,
-+ 						    &dir,
-+ 						    &(p->line));
-+Index: valgrind-3.13.0/callgrind/fn.c
-+===================================================================
-+--- valgrind-3.13.0.orig/callgrind/fn.c
-++++ valgrind-3.13.0/callgrind/fn.c
-+@@ -434,17 +434,18 @@ Bool CLG_(get_debug_info)(Addr instr_add
-+   
-+   CLG_DEBUG(6, "  + get_debug_info(%#lx)\n", instr_addr);
-+ 
-++  DiEpoch ep = VG_(current_DiEpoch)();
-+   if (pDebugInfo) {
-+-      *pDebugInfo = VG_(find_DebugInfo)(instr_addr);
-++      *pDebugInfo = VG_(find_DebugInfo)(ep, instr_addr);
-+ 
-+       // for generated code in anonymous space, pSegInfo is 0
-+    }
-+ 
-+-   found_file_line = VG_(get_filename_linenum)(instr_addr,
-++   found_file_line = VG_(get_filename_linenum)(ep, instr_addr,
-+ 					       file,
-+ 					       dir,
-+ 					       &line);
-+-   found_fn = VG_(get_fnname)(instr_addr, fn_name);
-++   found_fn = VG_(get_fnname)(ep, instr_addr, fn_name);
-+ 
-+    if (!found_file_line && !found_fn) {
-+      CLG_(stat).no_debug_BBs++;
-+@@ -503,6 +504,7 @@ fn_node* CLG_(get_fn_node)(BB* bb)
-+     CLG_(get_debug_info)(bb_addr(bb),
-+                          &dirname, &filename, &fnname, &line_num, &di);
-+ 
-++    DiEpoch ep = VG_(current_DiEpoch)();
-+     if (0 == VG_(strcmp)(fnname, "???")) {
-+ 	int p;
-+         static HChar buf[32];  // for sure large enough
-+@@ -521,7 +523,7 @@ fn_node* CLG_(get_fn_node)(BB* bb)
-+         fnname = buf;
-+     }
-+     else {
-+-      if (VG_(get_fnname_if_entry)(bb_addr(bb), &fnname))
-++      if (VG_(get_fnname_if_entry)(ep, bb_addr(bb), &fnname))
-+ 	bb->is_entry = 1;
-+     }
-+ 
-+Index: valgrind-3.13.0/coregrind/m_addrinfo.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_addrinfo.c
-++++ valgrind-3.13.0/coregrind/m_addrinfo.c
-+@@ -86,7 +86,7 @@ static ThreadId find_tid_with_stack_cont
-+    return VG_INVALID_THREADID;
-+ }
-+ 
-+-void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
-++void VG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai )
-+ {
-+    VgSectKind sect;
-+ 
-+@@ -99,7 +99,7 @@ void VG_(describe_addr) ( Addr a, /*OUT*
-+                     VG_(free), sizeof(HChar) );
-+ 
-+    (void) VG_(get_data_description)( ai->Addr.Variable.descr1,
-+-                                     ai->Addr.Variable.descr2, a );
-++                                     ai->Addr.Variable.descr2, ep, a );
-+    /* If there's nothing in descr1/2, free them.  Why is it safe to
-+       VG_(indexXA) at zero here?  Because VG_(get_data_description)
-+       guarantees to zero terminate descr1/2 regardless of the outcome
-+@@ -127,7 +127,7 @@ void VG_(describe_addr) ( Addr a, /*OUT*
-+       there. -- */
-+    const HChar *name;
-+    if (VG_(get_datasym_and_offset)(
-+-             a, &name,
-++             ep, a, &name,
-+              &ai->Addr.DataSym.offset )) {
-+       ai->Addr.DataSym.name = VG_(strdup)("mc.da.dsname", name);
-+       ai->tag = Addr_DataSym;
-+@@ -148,6 +148,7 @@ void VG_(describe_addr) ( Addr a, /*OUT*
-+             ai->tag            = Addr_Stack;
-+             VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
-+             ai->Addr.Stack.tinfo.tid = tid;
-++            ai->Addr.Stack.epoch = ep;
-+             ai->Addr.Stack.IP = 0;
-+             ai->Addr.Stack.frameNo = -1;
-+             ai->Addr.Stack.stackPos = StackPos_stacked;
-+@@ -196,9 +197,9 @@ void VG_(describe_addr) ( Addr a, /*OUT*
-+          ai->Addr.Block.block_desc = aai.name;
-+          ai->Addr.Block.block_szB = aai.block_szB;
-+          ai->Addr.Block.rwoffset = aai.rwoffset;
-+-         ai->Addr.Block.allocated_at = VG_(null_ExeContext)();
-++         ai->Addr.Block.allocated_at = VG_(null_ExeContextAndEpoch)();
-+          VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo);
-+-         ai->Addr.Block.freed_at = VG_(null_ExeContext)();
-++         ai->Addr.Block.freed_at = VG_(null_ExeContextAndEpoch)();
-+          return;
-+       }
-+    }
-+@@ -248,6 +249,7 @@ void VG_(describe_addr) ( Addr a, /*OUT*
-+          ai->tag  = Addr_Stack;
-+          VG_(initThreadInfo)(&ai->Addr.Stack.tinfo);
-+          ai->Addr.Stack.tinfo.tid = tid;
-++         ai->Addr.Stack.epoch = ep;
-+          ai->Addr.Stack.IP = 0;
-+          ai->Addr.Stack.frameNo = -1;
-+          vg_assert (stackPos != StackPos_stacked);
-+@@ -447,20 +449,24 @@ static void pp_addrinfo_WRK ( Addr a, co
-+             Bool haslinenum;
-+             PtrdiffT offset;
-+ 
-+-            if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.IP,
-++            if (VG_(get_inst_offset_in_function)( ai->Addr.Stack.epoch,
-++                                                  ai->Addr.Stack.IP,
-+                                                   &offset))
-+-               haslinenum = VG_(get_linenum) (ai->Addr.Stack.IP - offset,
-++               haslinenum = VG_(get_linenum) (ai->Addr.Stack.epoch,
-++                                              ai->Addr.Stack.IP - offset,
-+                                               &linenum);
-+             else
-+                haslinenum = False;
-+ 
-+-            hasfile = VG_(get_filename)(ai->Addr.Stack.IP, &file);
-++            hasfile = VG_(get_filename)(ai->Addr.Stack.epoch,
-++                                        ai->Addr.Stack.IP, &file);
-+ 
-+             HChar strlinenum[16] = "";   // large enough
-+             if (hasfile && haslinenum)
-+                VG_(sprintf)(strlinenum, "%u", linenum);
-+ 
-+-            hasfn = VG_(get_fnname)(ai->Addr.Stack.IP, &fn);
-++            hasfn = VG_(get_fnname)(ai->Addr.Stack.epoch,
-++                                    ai->Addr.Stack.IP, &fn);
-+ 
-+             if (hasfn || hasfile)
-+                VG_(emit)( "%sin frame #%d, created by %ps (%ps:%s)%s\n",
-+@@ -533,32 +539,35 @@ static void pp_addrinfo_WRK ( Addr a, co
-+                xpost
-+             );
-+          if (ai->Addr.Block.block_kind==Block_Mallocd) {
-+-            VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
-+-            vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
-++            VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.allocated_at);
-++            vg_assert(
-++               VG_(is_null_ExeContextAndEpoch)(ai->Addr.Block.freed_at));
-+          }
-+          else if (ai->Addr.Block.block_kind==Block_Freed) {
-+-            VG_(pp_ExeContext)(ai->Addr.Block.freed_at);
-+-            if (ai->Addr.Block.allocated_at != VG_(null_ExeContext)()) {
-++            VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.freed_at);
-++            if (!VG_(is_null_ExeContextAndEpoch)(ai->Addr.Block.allocated_at)) {
-+                VG_(emit)(
-+                   "%sBlock was alloc'd at%s\n",
-+                   xpre,
-+                   xpost
-+                );
-+-               VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
-++               VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.allocated_at);
-+             }
-+          }
-+          else if (ai->Addr.Block.block_kind==Block_MempoolChunk
-+                   || ai->Addr.Block.block_kind==Block_UserG) {
-+             // client-defined
-+-            VG_(pp_ExeContext)(ai->Addr.Block.allocated_at);
-+-            vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
-++            VG_(pp_ExeContextAndEpoch)(ai->Addr.Block.allocated_at);
-++            vg_assert(VG_(is_null_ExeContextAndEpoch)(ai->Addr.Block.freed_at));
-+             /* Nb: cannot have a freed_at, as a freed client-defined block
-+                has a Block_Freed block_kind. */
-+          } else {
-+             // Client or Valgrind arena. At least currently, we never
-+             // have stacktraces for these.
-+-            vg_assert (ai->Addr.Block.allocated_at == VG_(null_ExeContext)());
-+-            vg_assert (ai->Addr.Block.freed_at == VG_(null_ExeContext)());
-++            vg_assert(VG_(is_null_ExeContextAndEpoch)
-++                         (ai->Addr.Block.allocated_at));
-++            vg_assert(VG_(is_null_ExeContextAndEpoch)
-++                         (ai->Addr.Block.freed_at));
-+          }
-+          if (ai->Addr.Block.alloc_tinfo.tnr || ai->Addr.Block.alloc_tinfo.tid)
-+             VG_(emit)(
-+@@ -603,7 +612,7 @@ static void pp_addrinfo_WRK ( Addr a, co
-+          if (ai->Addr.SectKind.kind == Vg_SectText) {
-+             /* To better describe the address in a text segment,
-+                pp a dummy stacktrace made of this single address. */
-+-            VG_(pp_StackTrace)( &a, 1 );
-++            VG_(pp_StackTrace)( VG_(current_DiEpoch)(), &a, 1 );
-+          }
-+          break;
-+ 
-+Index: valgrind-3.13.0/coregrind/m_debuginfo/debuginfo.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_debuginfo/debuginfo.c
-++++ valgrind-3.13.0/coregrind/m_debuginfo/debuginfo.c
-+@@ -70,6 +70,10 @@
-+    should-we-load-debuginfo-now? finite state machine. */
-+ #define DEBUG_FSM 0
-+ 
-++/* Set this to 1 to enable somewhat minimal debug printing for the
-++   debuginfo-epoch machinery. */
-++#define DEBUG_EPOCHS 0
-++
-+ 
-+ /*------------------------------------------------------------*/
-+ /*--- The _svma / _avma / _image / _bias naming scheme     ---*/
-+@@ -109,6 +113,116 @@ static void caches__invalidate (void);
-+ 
-+ 
-+ /*------------------------------------------------------------*/
-++/*--- Epochs                                               ---*/
-++/*------------------------------------------------------------*/
-++
-++/* The DebugInfo epoch is incremented every time we either load debuginfo in
-++   response to an object mapping, or an existing DebugInfo becomes
-++   non-current (or will be discarded) due to an object unmap.  By storing,
-++   in each DebugInfo, the first and last epoch for which it is valid, we can
-++   unambiguously identify the set of DebugInfos which should be used to
-++   provide metadata for a code or data address, provided we know the epoch
-++   to which that address pertains.
-++
-++   Note, this isn't the same as the "handle_counter" below.  That only
-++   advances when new DebugInfos are created.  "current_epoch" advances both
-++   at DebugInfo created and destruction-or-making-non-current.
-++*/
-++
-++// The value zero is reserved for indicating an invalid epoch number.
-++static UInt current_epoch = 1;
-++
-++inline DiEpoch VG_(current_DiEpoch) ( void ) {
-++   DiEpoch dep; dep.n = current_epoch; return dep;
-++}
-++
-++static void advance_current_DiEpoch ( const HChar* msg ) {
-++   current_epoch++;
-++   if (DEBUG_EPOCHS)
-++      VG_(printf)("Advancing current epoch to %u due to %s\n",
-++                  current_epoch, msg);
-++}
-++
-++static inline Bool eq_DiEpoch ( DiEpoch dep1, DiEpoch dep2 ) {
-++   return dep1.n == dep2.n && /*neither is invalid*/dep1.n != 0;
-++}
-++
-++// Is this DebugInfo currently "allocated" (pre-use state, only FSM active) ?
-++static inline Bool is_DebugInfo_allocated ( const DebugInfo* di )
-++{
-++   if (is_DiEpoch_INVALID(di->first_epoch)
-++       && is_DiEpoch_INVALID(di->last_epoch)) {
-++      return True;
-++   } else {
-++      return False;
-++   }
-++}
-++
-++// Is this DebugInfo currently "active" (valid for the current epoch) ?
-++static inline Bool is_DebugInfo_active ( const DebugInfo* di )
-++{
-++   if (!is_DiEpoch_INVALID(di->first_epoch)
-++       && is_DiEpoch_INVALID(di->last_epoch)) {
-++      // Yes it is active.  Sanity check ..
-++      tl_assert(di->first_epoch.n <= current_epoch);
-++      return True;
-++   } else {
-++      return False;
-++   }
-++}
-++
-++// Is this DebugInfo currently "archived" ?
-++static inline Bool is_DebugInfo_archived ( const DebugInfo* di )
-++{
-++   if (!is_DiEpoch_INVALID(di->first_epoch)
-++       && !is_DiEpoch_INVALID(di->last_epoch)) {
-++      // Yes it is archived.  Sanity checks ..
-++      tl_assert(di->first_epoch.n <= di->last_epoch.n);
-++      tl_assert(di->last_epoch.n <= current_epoch);
-++      return True;
-++   } else {
-++      return False;
-++   }
-++}
-++
-++// Is this DebugInfo valid for the specified epoch?
-++static inline Bool is_DI_valid_for_epoch ( const DebugInfo* di, DiEpoch ep )
-++{
-++   // Stay sane
-++   vg_assert(ep.n > 0 && ep.n <= current_epoch);
-++
-++   Bool first_valid = !is_DiEpoch_INVALID(di->first_epoch);
-++   Bool last_valid  = !is_DiEpoch_INVALID(di->last_epoch);
-++
-++   if (first_valid) {
-++      if (last_valid) {
-++         // Both valid.  di is in Archived state.
-++         return di->first_epoch.n <= ep.n && ep.n <= di->last_epoch.n;
-++      } else {
-++         // First is valid, last is invalid.  di is in Active state.
-++         return di->first_epoch.n <= ep.n;
-++      }
-++   } else {
-++      if (last_valid) {
-++         // First is invalid, last is valid.  This is an impossible state.
-++         vg_assert(0);
-++         /*NOTREACHED*/
-++         return False;
-++      } else {
-++         // Neither is valid.  di is in Allocated state.
-++         return False;
-++      }
-++   }
-++
-++}
-++
-++static inline UInt ROL32 ( UInt x, UInt n )
-++{
-++   return (x << n) | (x >> (32-n));
-++}
-++
-++
-++/*------------------------------------------------------------*/
-+ /*--- Root structure                                       ---*/
-+ /*------------------------------------------------------------*/
-+ 
-+@@ -162,6 +276,23 @@ static void move_DebugInfo_one_step_forw
-+ }
-+ 
-+ 
-++// Debugging helper for epochs
-++static void show_epochs ( const HChar* msg )
-++{
-++   if (DEBUG_EPOCHS) {
-++      DebugInfo* di;
-++      VG_(printf)("\nDebugInfo epoch display, requested by \"%s\"\n", msg);
-++      VG_(printf)("  Current epoch (note: 0 means \"invalid epoch\") = %u\n",
-++                  current_epoch);
-++      for (di = debugInfo_list; di; di = di->next) {
-++         VG_(printf)("  [di=%p]  first %u  last %u  %s\n", 
-++                     di, di->first_epoch.n, di->last_epoch.n, di->fsm.filename);
-++      }
-++      VG_(printf)("\n");
-++   }
-++}
-++
-++
-+ /*------------------------------------------------------------*/
-+ /*--- Notification (acquire/discard) helpers               ---*/
-+ /*------------------------------------------------------------*/
-+@@ -182,6 +313,8 @@ DebugInfo* alloc_DebugInfo( const HChar*
-+ 
-+    di = ML_(dinfo_zalloc)("di.debuginfo.aDI.1", sizeof(DebugInfo));
-+    di->handle       = handle_counter++;
-++   di->first_epoch  = DiEpoch_INVALID();
-++   di->last_epoch   = DiEpoch_INVALID();
-+    di->fsm.filename = ML_(dinfo_strdup)("di.debuginfo.aDI.2", filename);
-+    di->fsm.maps     = VG_(newXA)(
-+                          ML_(dinfo_zalloc), "di.debuginfo.aDI.3",
-+@@ -302,34 +435,52 @@ static void free_DebugInfo ( DebugInfo*
-+ }
-+ 
-+ 
-+-/* 'si' is a member of debugInfo_list.  Find it, remove it from the
-+-   list, notify m_redir that this has happened, and free all storage
-+-   reachable from it.
-++/* 'di' is a member of debugInfo_list.  Find it, and either (remove it from
-++   the list and free all storage reachable from it) or archive it, notify
-++   m_redir that this has happened, and free all storage reachable from it.
-++
-++   Note that 'di' can't be archived.  Is a DebugInfo is archived then we
-++   want to hold on to it forever.  This is asserted for.
-++
-++   Note also, we don't advance the current epoch here.  That's the
-++   responsibility of some (non-immediate) caller.
-+ */
-+-static void discard_DebugInfo ( DebugInfo* di )
-++static void discard_or_archive_DebugInfo ( DebugInfo* di )
-+ {
-+-   const HChar* reason = "munmap";
-++   const HChar* reason  = "munmap";
-++   const Bool   archive = VG_(clo_keep_debuginfo);
-+ 
-+    DebugInfo** prev_next_ptr = &debugInfo_list;
-+    DebugInfo*  curr          =  debugInfo_list;
-+ 
-+    while (curr) {
-+       if (curr == di) {
-+-         /* Found it;  remove from list and free it. */
-++         /* It must be active! */
-++         vg_assert( is_DebugInfo_active(di));
-++         /* Found it; (remove from list and free it), or archive it. */
-+          if (curr->have_dinfo
-+              && (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir)))
-+             VG_(message)(Vg_DebugMsg, 
-+-                         "Discarding syms at %#lx-%#lx in %s due to %s()\n",
-++                         "%s syms at %#lx-%#lx in %s due to %s()\n",
-++                         archive ? "Archiving" : "Discarding",
-+                          di->text_avma, 
-+                          di->text_avma + di->text_size,
-+                          curr->fsm.filename ? curr->fsm.filename
-+                                             : "???",
-+                          reason);
-+          vg_assert(*prev_next_ptr == curr);
-+-         *prev_next_ptr = curr->next;
-+-         if (curr->have_dinfo)
-++         if (!archive) {
-++            *prev_next_ptr = curr->next;
-++         }
-++         if (curr->have_dinfo) {
-+             VG_(redir_notify_delete_DebugInfo)( curr );
-+-         free_DebugInfo(curr);
-++         }
-++         if (archive) {
-++            /* Adjust the epoch markers appropriately. */
-++            di->last_epoch = VG_(current_DiEpoch)();
-++         } else {
-++            free_DebugInfo(curr);
-++         }
-+          return;
-+       }
-+       prev_next_ptr = &curr->next;
-+@@ -358,10 +509,11 @@ static Bool discard_syms_in_range ( Addr
-+       while (True) {
-+          if (curr == NULL)
-+             break;
-+-         if (curr->text_present
-+-             && curr->text_size > 0
-+-             && (start+length - 1 < curr->text_avma 
-+-                 || curr->text_avma + curr->text_size - 1 < start)) {
-++         if (is_DebugInfo_archived(curr)
-++             || (curr->text_present
-++                 && curr->text_size > 0
-++                 && (start+length - 1 < curr->text_avma 
-++                     || curr->text_avma + curr->text_size - 1 < start))) {
-+             /* no overlap */
-+ 	 } else {
-+ 	    found = True;
-+@@ -372,7 +524,7 @@ static Bool discard_syms_in_range ( Addr
-+ 
-+       if (!found) break;
-+       anyFound = True;
-+-      discard_DebugInfo( curr );
-++      discard_or_archive_DebugInfo( curr );
-+    }
-+ 
-+    return anyFound;
-+@@ -418,9 +570,9 @@ static Bool do_DebugInfos_overlap ( cons
-+ }
-+ 
-+ 
-+-/* Discard all elements of debugInfo_list whose .mark bit is set.
-++/* Discard or archive all elements of debugInfo_list whose .mark bit is set.
-+ */
-+-static void discard_marked_DebugInfos ( void )
-++static void discard_or_archive_marked_DebugInfos ( void )
-+ {
-+    DebugInfo* curr;
-+ 
-+@@ -436,7 +588,7 @@ static void discard_marked_DebugInfos (
-+       }
-+ 
-+       if (!curr) break;
-+-      discard_DebugInfo( curr );
-++      discard_or_archive_DebugInfo( curr );
-+ 
-+    }
-+ }
-+@@ -446,19 +598,22 @@ static void discard_marked_DebugInfos (
-+    Clearly diRef must have its mapping information set to something sane. */
-+ static void discard_DebugInfos_which_overlap_with ( DebugInfo* diRef )
-+ {
-++   vg_assert(is_DebugInfo_allocated(diRef));
-+    DebugInfo* di;
-+    /* Mark all the DebugInfos in debugInfo_list that need to be
-+       deleted.  First, clear all the mark bits; then set them if they
-+       overlap with siRef.  Since siRef itself is in this list we at
-+       least expect its own mark bit to be set. */
-+    for (di = debugInfo_list; di; di = di->next) {
-++      if (is_DebugInfo_archived(di))
-++         continue;
-+       di->mark = do_DebugInfos_overlap( di, diRef );
-+       if (di == diRef) {
-+          vg_assert(di->mark);
-+          di->mark = False;
-+       }
-+    }
-+-   discard_marked_DebugInfos();
-++   discard_or_archive_marked_DebugInfos();
-+ }
-+ 
-+ 
-+@@ -470,6 +625,8 @@ static DebugInfo* find_or_create_DebugIn
-+    DebugInfo* di;
-+    vg_assert(filename);
-+    for (di = debugInfo_list; di; di = di->next) {
-++      if (is_DebugInfo_archived(di))
-++         continue;
-+       vg_assert(di->fsm.filename);
-+       if (0==VG_(strcmp)(di->fsm.filename, filename))
-+          break;
-+@@ -480,6 +637,7 @@ static DebugInfo* find_or_create_DebugIn
-+       di->next = debugInfo_list;
-+       debugInfo_list = di;
-+    }
-++   vg_assert(!is_DebugInfo_archived(di));
-+    return di;
-+ }
-+ 
-+@@ -723,6 +881,8 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST
-+    ULong di_handle;
-+    Bool  ok;
-+ 
-++   advance_current_DiEpoch("di_notify_ACHIEVE_ACCEPT_STATE");
-++
-+    vg_assert(di->fsm.filename);
-+    TRACE_SYMTAB("\n");
-+    TRACE_SYMTAB("------ start ELF OBJECT "
-+@@ -734,7 +894,8 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST
-+    /* We're going to read symbols and debug info for the avma
-+       ranges specified in the _DebugInfoFsm mapping array. First
-+       get rid of any other DebugInfos which overlap any of those
-+-      ranges (to avoid total confusion). */
-++      ranges (to avoid total confusion).  But only those valid in
-++     the current epoch.  We don't want to discard archived DebugInfos. */
-+    discard_DebugInfos_which_overlap_with( di );
-+ 
-+    /* The DebugInfoMappings that now exist in the FSM may involve
-+@@ -765,6 +926,15 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST
-+          priv_storage.h. */
-+       check_CFSI_related_invariants(di);
-+       ML_(finish_CFSI_arrays)(di);
-++
-++      // Mark di's first epoch point as a valid epoch.  Because its
-++      // last_epoch value is still invalid, this changes di's state from
-++      // "allocated" to "active".
-++      vg_assert(is_DebugInfo_allocated(di));
-++      di->first_epoch = VG_(current_DiEpoch)();
-++      vg_assert(is_DebugInfo_active(di));
-++      show_epochs("di_notify_ACHIEVE_ACCEPT_STATE success");
-++
-+       /* notify m_redir about it */
-+       TRACE_SYMTAB("\n------ Notifying m_redir ------\n");
-+       VG_(redir_notify_new_DebugInfo)( di );
-+@@ -1077,8 +1247,11 @@ void VG_(di_notify_munmap)( Addr a, Size
-+    Bool anyFound;
-+    if (0) VG_(printf)("DISCARD %#lx %#lx\n", a, a+len);
-+    anyFound = discard_syms_in_range(a, len);
-+-   if (anyFound)
-++   if (anyFound) {
-+       caches__invalidate();
-++      advance_current_DiEpoch("VG_(di_notify_munmap)");
-++      show_epochs("VG_(di_notify_munmap)");
-++   }
-+ }
-+ 
-+ 
-+@@ -1094,8 +1267,10 @@ void VG_(di_notify_mprotect)( Addr a, Si
-+ #  endif
-+    if (0 && !exe_ok) {
-+       Bool anyFound = discard_syms_in_range(a, len);
-+-      if (anyFound)
-++      if (anyFound) {
-+          caches__invalidate();
-++         advance_current_DiEpoch("VG_(di_notify_mprotect)");
-++      }
-+    }
-+ }
-+ 
-+@@ -1395,6 +1570,7 @@ void VG_(di_notify_pdb_debuginfo)( Int f
-+    caches__invalidate();
-+    /* dump old info for this range, if any */
-+    discard_syms_in_range( avma_obj, total_size );
-++   advance_current_DiEpoch("VG_(di_notify_pdb_debuginfo)");
-+ 
-+    { DebugInfo* di = find_or_create_DebugInfo_for(exename);
-+ 
-+@@ -1471,6 +1647,7 @@ DebugInfoMapping* ML_(find_rx_mapping) (
-+ /*------------------------------------------------------------*/
-+ /*--- Types and functions for inlined IP cursor            ---*/
-+ /*------------------------------------------------------------*/
-++
-+ struct _InlIPCursor {
-+    Addr eip;             // Cursor used to describe calls at eip.
-+    DebugInfo* di;        // DebugInfo describing inlined calls at eip
-+@@ -1534,8 +1711,8 @@ Bool VG_(next_IIPC)(InlIPCursor *iipc)
-+ }
-+ 
-+ /* Forward */
-+-static void search_all_loctabs ( Addr ptr, /*OUT*/DebugInfo** pdi,
-+-                                           /*OUT*/Word* locno );
-++static void search_all_loctabs ( DiEpoch ep, Addr ptr,
-++                                 /*OUT*/DebugInfo** pdi, /*OUT*/Word* locno );
-+ 
-+ /* Returns the position after which eip would be inserted in inltab.
-+    (-1 if eip should be inserted before position 0).
-+@@ -1565,7 +1742,7 @@ static Word inltab_insert_pos (DebugInfo
-+    return lo - 1;
-+ }
-+ 
-+-InlIPCursor* VG_(new_IIPC)(Addr eip)
-++InlIPCursor* VG_(new_IIPC)(DiEpoch ep, Addr eip)
-+ {
-+    DebugInfo*  di;
-+    Word        locno;
-+@@ -1576,8 +1753,8 @@ InlIPCursor* VG_(new_IIPC)(Addr eip)
-+    if (!VG_(clo_read_inline_info))
-+       return NULL; // No way we can find inlined calls.
-+ 
-+-   /* Search the DebugInfo for eip */
-+-   search_all_loctabs ( eip, &di, &locno );
-++   /* Search the DebugInfo for (ep, eip) */
-++   search_all_loctabs ( ep, eip, &di, &locno );
-+    if (di == NULL || di->inltab_used == 0)
-+       return NULL; // No di (with inltab) containing eip.
-+ 
-+@@ -1641,8 +1818,8 @@ void VG_(delete_IIPC)(InlIPCursor *iipc)
-+    If findText==True,  only text symbols are searched for.
-+    If findText==False, only data symbols are searched for.
-+ */
-+-static void search_all_symtabs ( Addr ptr, /*OUT*/DebugInfo** pdi,
-+-                                           /*OUT*/Word* symno,
-++static void search_all_symtabs ( DiEpoch ep, Addr ptr,
-++                                 /*OUT*/DebugInfo** pdi, /*OUT*/Word* symno,
-+                                  Bool findText )
-+ {
-+    Word       sno;
-+@@ -1651,6 +1828,9 @@ static void search_all_symtabs ( Addr pt
-+ 
-+    for (di = debugInfo_list; di != NULL; di = di->next) {
-+ 
-++      if (!is_DI_valid_for_epoch(di, ep))
-++         continue;
-++
-+       if (findText) {
-+          /* Consider any symbol in the r-x mapped area to be text.
-+             See Comment_Regarding_Text_Range_Checks in storage.c for
-+@@ -1698,15 +1878,17 @@ static void search_all_symtabs ( Addr pt
-+ }
-+ 
-+ 
-+-/* Search all loctabs that we know about to locate ptr.  If found, set
-+-   *pdi to the relevant DebugInfo, and *locno to the loctab entry
-++/* Search all loctabs that we know about to locate ptr at epoch ep.  If
-++   *found, set pdi to the relevant DebugInfo, and *locno to the loctab entry
-+    *number within that.  If not found, *pdi is set to NULL. */
-+-static void search_all_loctabs ( Addr ptr, /*OUT*/DebugInfo** pdi,
-+-                                           /*OUT*/Word* locno )
-++static void search_all_loctabs ( DiEpoch ep, Addr ptr,
-++                                 /*OUT*/DebugInfo** pdi, /*OUT*/Word* locno )
-+ {
-+    Word       lno;
-+    DebugInfo* di;
-+    for (di = debugInfo_list; di != NULL; di = di->next) {
-++      if (!is_DI_valid_for_epoch(di, ep))
-++         continue;
-+       if (di->text_present
-+           && di->text_size > 0
-+           && di->text_avma <= ptr 
-+@@ -1729,19 +1911,22 @@ static void search_all_loctabs ( Addr pt
-+ 
-+ typedef
-+    struct {
-+-      Addr sym_avma;
-++      // (sym_epoch, sym_avma) are the hash table key.
-++      DiEpoch sym_epoch;
-++      Addr    sym_avma;
-++      // Fields below here are not part of the key.
-+       const HChar* sym_name;
-+       PtrdiffT offset : (sizeof(PtrdiffT)*8)-1; 
-+       Bool isText : 1;
-+    }
-+    Sym_Name_CacheEnt;
-+-/* Sym_Name_CacheEnt associates a queried address to the sym name found.
-+-   By nature, if a sym name was found, it means the searched address
-+-   stored in the cache is an avma (see e.g. search_all_symtabs).
-+-   Note however that the caller is responsibe to work with 'avma'
-+-   addresses e.g. when calling VG_(get_fnname) : m_debuginfo.c has
-+-   no way to differentiate an 'svma a' from an 'avma a'. It is however
-+-   unlikely that svma would percolate outside of this module. */
-++/* Sym_Name_CacheEnt associates a queried (epoch, address) pair to the sym
-++   name found.  By nature, if a sym name was found, it means the searched
-++   address stored in the cache is an avma (see e.g. search_all_symtabs).
-++   Note however that the caller is responsibe to work with 'avma' addresses
-++   e.g. when calling VG_(get_fnname) : m_debuginfo.c has no way to
-++   differentiate an 'svma a' from an 'avma a'. It is however unlikely that
-++   svma would percolate outside of this module. */
-+ 
-+ static Sym_Name_CacheEnt sym_name_cache[N_SYM_NAME_CACHE];
-+ 
-+@@ -1757,13 +1942,15 @@ static void sym_name_cache__invalidate (
-+    sym_name_cache[0].sym_name = no_sym_name;
-+ }
-+ 
-+-/* The whole point of this whole big deal: map a code address to a
-+-   plausible symbol name.  Returns False if no idea; otherwise True.
-++/* The whole point of this whole big deal: map an (epoch, code address) pair
-++   to a plausible symbol name.  Returns False if no idea; otherwise True.
-++
-+    Caller supplies buf.  If do_cxx_demangling is False, don't do
-+    C++ demangling, regardless of VG_(clo_demangle) -- probably because the
-+    call has come from VG_(get_fnname_raw)().  findText
-+    indicates whether we're looking for a text symbol or a data symbol
-+    -- caller must choose one kind or the other.
-++
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership
-+    in pub_tool_debuginfo.h 
-+    get_sym_name and the fact it calls the demangler is the main reason
-+@@ -1772,22 +1959,32 @@ static void sym_name_cache__invalidate (
-+    (1) the DebugInfo it belongs to is not discarded
-+    (2) the demangler is not invoked again
-+    Also, the returned string is owned by "somebody else". Callers must
-+-   not free it or modify it.*/
-++   not free it or modify it. */
-+ static
-+ Bool get_sym_name ( Bool do_cxx_demangling, Bool do_z_demangling,
-+                     Bool do_below_main_renaming,
-+-                    Addr a, const HChar** buf,
-++                    DiEpoch ep, Addr a, const HChar** buf,
-+                     Bool match_anywhere_in_sym, Bool show_offset,
-+                     Bool findText, /*OUT*/PtrdiffT* offsetP )
-+ {
-+-   UWord         hash = a % N_SYM_NAME_CACHE;
-+-   Sym_Name_CacheEnt* se =  &sym_name_cache[hash];
-++   // Compute the hash from 'ep' and 'a'.  The latter contains lots of
-++   // significant bits, but 'ep' is expected to be a small number, typically
-++   // less than 500.  So rotate it around a bit in the hope of spreading the
-++   // bits out somewhat.
-++   vg_assert(!is_DiEpoch_INVALID(ep));
-++   UWord hash = a ^ (UWord)(ep.n ^ ROL32(ep.n, 5) 
-++                                 ^ ROL32(ep.n, 13) ^ ROL32(ep.n, 19));
-++   hash %= N_SYM_NAME_CACHE;
-++
-++   Sym_Name_CacheEnt* se = &sym_name_cache[hash];
-+ 
-+-   if (UNLIKELY(se->sym_avma != a || se->isText != findText)) {
-++   if (UNLIKELY(se->sym_epoch.n != ep.n || se->sym_avma != a
-++                || se->isText != findText)) {
-+       DebugInfo* di;
-+       Word       sno;
-+ 
-+-      search_all_symtabs ( a, &di, &sno, findText );
-++      search_all_symtabs ( ep, a, &di, &sno, findText );
-++      se->sym_epoch = ep;
-+       se->sym_avma = a;
-+       se->isText = findText;
-+       if (di == NULL || a == 0)
-+@@ -1846,12 +2043,12 @@ Bool get_sym_name ( Bool do_cxx_demangli
-+ /* ppc64be-linux only: find the TOC pointer (R2 value) that should be in
-+    force at the entry point address of the function containing
-+    guest_code_addr.  Returns 0 if not known. */
-+-Addr VG_(get_tocptr) ( Addr guest_code_addr )
-++Addr VG_(get_tocptr) ( DiEpoch ep, Addr guest_code_addr )
-+ {
-+ #if defined(VGA_ppc64be) || defined(VGA_ppc64le)
-+    DebugInfo* si;
-+    Word       sno;
-+-   search_all_symtabs ( guest_code_addr, 
-++   search_all_symtabs ( ep, guest_code_addr, 
-+                         &si, &sno,
-+                         True/*consider text symbols only*/ );
-+    if (si == NULL) 
-+@@ -1867,11 +2064,11 @@ Addr VG_(get_tocptr) ( Addr guest_code_a
-+    match anywhere in function, but don't show offsets.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership
-+    in pub_tool_debuginfo.h */
-+-Bool VG_(get_fnname) ( Addr a, const HChar** buf )
-++Bool VG_(get_fnname) ( DiEpoch ep, Addr a, const HChar** buf )
-+ {
-+    return get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True,
-+                          /*below-main-renaming*/True,
-+-                         a, buf,
-++                         ep, a, buf,
-+                          /*match_anywhere_in_fun*/True, 
-+                          /*show offset?*/False,
-+                          /*text sym*/True,
-+@@ -1882,11 +2079,11 @@ Bool VG_(get_fnname) ( Addr a, const HCh
-+    match anywhere in function, and show offset if nonzero.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership
-+    in pub_tool_debuginfo.h */
-+-Bool VG_(get_fnname_w_offset) ( Addr a, const HChar** buf )
-++Bool VG_(get_fnname_w_offset) ( DiEpoch ep, Addr a, const HChar** buf )
-+ {
-+    return get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True,
-+                          /*below-main-renaming*/True,
-+-                         a, buf,
-++                         ep, a, buf,
-+                          /*match_anywhere_in_fun*/True, 
-+                          /*show offset?*/True,
-+                          /*text sym*/True,
-+@@ -1898,14 +2095,14 @@ Bool VG_(get_fnname_w_offset) ( Addr a,
-+    and don't show offsets.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership
-+    in pub_tool_debuginfo.h */
-+-Bool VG_(get_fnname_if_entry) ( Addr a, const HChar** buf )
-++Bool VG_(get_fnname_if_entry) ( DiEpoch ep, Addr a, const HChar** buf )
-+ {
-+    const HChar *tmp;
-+    Bool res;
-+ 
-+    res =  get_sym_name ( /*C++-demangle*/True, /*Z-demangle*/True,
-+                          /*below-main-renaming*/True,
-+-                         a, &tmp,
-++                         ep, a, &tmp,
-+                          /*match_anywhere_in_fun*/False, 
-+                          /*show offset?*/False,
-+                          /*text sym*/True,
-+@@ -1920,11 +2117,11 @@ Bool VG_(get_fnname_if_entry) ( Addr a,
-+    offsets.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership
-+    in pub_tool_debuginfo.h  */
-+-Bool VG_(get_fnname_raw) ( Addr a, const HChar** buf )
-++Bool VG_(get_fnname_raw) ( DiEpoch ep, Addr a, const HChar** buf )
-+ {
-+    return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False,
-+                          /*below-main-renaming*/False,
-+-                         a, buf,
-++                         ep, a, buf,
-+                          /*match_anywhere_in_fun*/True, 
-+                          /*show offset?*/False,
-+                          /*text sym*/True,
-+@@ -1936,14 +2133,22 @@ Bool VG_(get_fnname_raw) ( Addr a, const
-+    don't show offsets.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership
-+    in pub_tool_debuginfo.h */
-+-Bool VG_(get_fnname_no_cxx_demangle) ( Addr a, const HChar** buf,
-++Bool VG_(get_fnname_no_cxx_demangle) ( DiEpoch ep, Addr a, const HChar** buf,
-+                                        const InlIPCursor* iipc )
-+ {
-++   // FIXME JRS 28 June 2017: should we use 'iipc->di->first_epoch'
-++   // instead of 'ep' in the call to get_sym_name?  At least let's
-++   // assert that the DebugInfo that 'iipc' mentions is valid for the
-++   // specified epoch.
-++   if (iipc) {
-++      vg_assert(is_DI_valid_for_epoch(iipc->di, ep));
-++   }
-++
-+    if (is_bottom(iipc)) {
-+       // At the bottom (towards main), we describe the fn at eip.
-+       return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/True,
-+                             /*below-main-renaming*/True,
-+-                            a, buf,
-++                            ep, a, buf,
-+                             /*match_anywhere_in_fun*/True, 
-+                             /*show offset?*/False,
-+                             /*text sym*/True,
-+@@ -1962,13 +2167,13 @@ Bool VG_(get_fnname_no_cxx_demangle) ( A
-+ /* mips-linux only: find the offset of current address. This is needed for 
-+    stack unwinding for MIPS.
-+ */
-+-Bool VG_(get_inst_offset_in_function)( Addr a,
-++Bool VG_(get_inst_offset_in_function)( DiEpoch ep, Addr a,
-+                                        /*OUT*/PtrdiffT* offset )
-+ {
-+    const HChar *fnname;
-+    return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False,
-+                          /*below-main-renaming*/False,
-+-                         a, &fnname,
-++                         ep, a, &fnname,
-+                          /*match_anywhere_in_sym*/True, 
-+                          /*show offset?*/False,
-+                          /*text sym*/True,
-+@@ -2000,13 +2205,13 @@ Vg_FnNameKind VG_(get_fnname_kind) ( con
-+    }
-+ }
-+ 
-+-Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( Addr ip )
-++Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( DiEpoch ep, Addr ip )
-+ {
-+    const HChar *buf;
-+ 
-+    // We don't demangle, because it's faster not to, and the special names
-+    // we're looking for won't be mangled.
-+-   if (VG_(get_fnname_raw) ( ip, &buf )) {
-++   if (VG_(get_fnname_raw) ( ep, ip, &buf )) {
-+ 
-+       return VG_(get_fnname_kind)(buf);
-+    } else {
-+@@ -2019,13 +2224,13 @@ Vg_FnNameKind VG_(get_fnname_kind_from_I
-+    Also data_addr's offset from the symbol start is put into *offset.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership
-+    in pub_tool_debuginfo.h  */
-+-Bool VG_(get_datasym_and_offset)( Addr data_addr,
-++Bool VG_(get_datasym_and_offset)( DiEpoch ep, Addr data_addr,
-+                                   /*OUT*/const HChar** dname,
-+                                   /*OUT*/PtrdiffT* offset )
-+ {
-+    return get_sym_name ( /*C++-demangle*/False, /*Z-demangle*/False,
-+                        /*below-main-renaming*/False,
-+-                       data_addr, dname,
-++                       ep, data_addr, dname,
-+                        /*match_anywhere_in_sym*/True, 
-+                        /*show offset?*/False,
-+                        /*text sym*/False,
-+@@ -2038,7 +2243,7 @@ Bool VG_(get_datasym_and_offset)( Addr d
-+    (1) the DebugInfo it belongs to is not discarded
-+    (2) the segment containing the address is not merged with another segment
-+ */
-+-Bool VG_(get_objname) ( Addr a, const HChar** objname )
-++Bool VG_(get_objname) ( DiEpoch ep, Addr a, const HChar** objname )
-+ {
-+    DebugInfo* di;
-+    const NSegment *seg;
-+@@ -2047,6 +2252,8 @@ Bool VG_(get_objname) ( Addr a, const HC
-+    /* Look in the debugInfo_list to find the name.  In most cases we
-+       expect this to produce a result. */
-+    for (di = debugInfo_list; di != NULL; di = di->next) {
-++      if (!is_DI_valid_for_epoch(di, ep))
-++         continue;
-+       if (di->text_present
-+           && di->text_size > 0
-+           && di->text_avma <= a 
-+@@ -2059,8 +2266,13 @@ Bool VG_(get_objname) ( Addr a, const HC
-+       the debugInfo_list, ask the address space manager whether it
-+       knows the name of the file associated with this mapping.  This
-+       allows us to print the names of exe/dll files in the stack trace
-+-      when running programs under wine. */
-+-   if ( (seg = VG_(am_find_nsegment)(a)) != NULL 
-++      when running programs under wine.
-++
-++      Restrict this to the case where 'ep' is the current epoch, though, so
-++      that we don't return information about this epoch when the caller was
-++      enquiring about a different one. */
-++   if ( eq_DiEpoch(ep, VG_(current_DiEpoch)())
-++        && (seg = VG_(am_find_nsegment)(a)) != NULL 
-+         && (filename = VG_(am_get_filename)(seg)) != NULL ) {
-+       *objname = filename;
-+       return True;
-+@@ -2070,12 +2282,14 @@ Bool VG_(get_objname) ( Addr a, const HC
-+ 
-+ /* Map a code address to its DebugInfo.  Returns NULL if not found.  Doesn't
-+    require debug info. */
-+-DebugInfo* VG_(find_DebugInfo) ( Addr a )
-++DebugInfo* VG_(find_DebugInfo) ( DiEpoch ep, Addr a )
-+ {
-+    static UWord n_search = 0;
-+    DebugInfo* di;
-+    n_search++;
-+    for (di = debugInfo_list; di != NULL; di = di->next) {
-++      if (!is_DI_valid_for_epoch(di, ep))
-++         continue;
-+       if (di->text_present
-+           && di->text_size > 0
-+           && di->text_avma <= a 
-+@@ -2091,13 +2305,13 @@ DebugInfo* VG_(find_DebugInfo) ( Addr a
-+ /* Map a code address to a filename.  Returns True if successful. The
-+    returned string is persistent as long as the DebugInfo to which it
-+    belongs is not discarded. */
-+-Bool VG_(get_filename)( Addr a, const HChar** filename )
-++Bool VG_(get_filename)( DiEpoch ep, Addr a, const HChar** filename )
-+ {
-+    DebugInfo* si;
-+    Word       locno;
-+    UInt       fndn_ix;
-+ 
-+-   search_all_loctabs ( a, &si, &locno );
-++   search_all_loctabs ( ep, a, &si, &locno );
-+    if (si == NULL) 
-+       return False;
-+    fndn_ix = ML_(fndn_ix) (si, locno);
-+@@ -2106,11 +2320,11 @@ Bool VG_(get_filename)( Addr a, const HC
-+ }
-+ 
-+ /* Map a code address to a line number.  Returns True if successful. */
-+-Bool VG_(get_linenum)( Addr a, UInt* lineno )
-++Bool VG_(get_linenum)( DiEpoch ep, Addr a, UInt* lineno )
-+ {
-+    DebugInfo* si;
-+    Word       locno;
-+-   search_all_loctabs ( a, &si, &locno );
-++   search_all_loctabs ( ep, a, &si, &locno );
-+    if (si == NULL) 
-+       return False;
-+    *lineno = si->loctab[locno].lineno;
-+@@ -2121,7 +2335,7 @@ Bool VG_(get_linenum)( Addr a, UInt* lin
-+ /* Map a code address to a filename/line number/dir name info.
-+    See prototype for detailed description of behaviour.
-+ */
-+-Bool VG_(get_filename_linenum) ( Addr a, 
-++Bool VG_(get_filename_linenum) ( DiEpoch ep, Addr a, 
-+                                  /*OUT*/const HChar** filename,
-+                                  /*OUT*/const HChar** dirname,
-+                                  /*OUT*/UInt* lineno )
-+@@ -2130,7 +2344,7 @@ Bool VG_(get_filename_linenum) ( Addr a,
-+    Word       locno;
-+    UInt       fndn_ix;
-+ 
-+-   search_all_loctabs ( a, &si, &locno );
-++   search_all_loctabs ( ep, a, &si, &locno );
-+    if (si == NULL) {
-+       if (dirname) {
-+          *dirname = "";
-+@@ -2159,7 +2373,8 @@ Bool VG_(get_filename_linenum) ( Addr a,
-+    Therefore specify "*" to search all the objects.  On TOC-afflicted
-+    platforms, a symbol is deemed to be found only if it has a nonzero
-+    TOC pointer.  */
-+-Bool VG_(lookup_symbol_SLOW)(const HChar* sopatt, const HChar* name,
-++Bool VG_(lookup_symbol_SLOW)(DiEpoch ep,
-++                             const HChar* sopatt, const HChar* name,
-+                              SymAVMAs* avmas)
-+ {
-+    Bool     require_pToc = False;
-+@@ -2172,6 +2387,8 @@ Bool VG_(lookup_symbol_SLOW)(const HChar
-+    for (si = debugInfo_list; si; si = si->next) {
-+       if (debug)
-+          VG_(printf)("lookup_symbol_SLOW: considering %s\n", si->soname);
-++      if (!is_DI_valid_for_epoch(si, ep))
-++         continue;
-+       if (!VG_(string_match)(sopatt, si->soname)) {
-+          if (debug)
-+             VG_(printf)(" ... skip\n");
-+@@ -2254,7 +2471,7 @@ putStrEsc( SizeT n, HChar** buf, SizeT *
-+    return n;
-+ }
-+ 
-+-const HChar* VG_(describe_IP)(Addr eip, const InlIPCursor *iipc)
-++const HChar* VG_(describe_IP)(DiEpoch ep, Addr eip, const InlIPCursor *iipc)
-+ {
-+    static HChar *buf = NULL;
-+    static SizeT bufsiz = 0;
-+@@ -2267,7 +2484,10 @@ const HChar* VG_(describe_IP)(Addr eip,
-+    HChar ibuf[50];   // large enough
-+    SizeT n = 0;
-+ 
-+-   vg_assert (!iipc || iipc->eip == eip);
-++   // An InlIPCursor is associated with one specific DebugInfo.  So if
-++   // it exists, make sure that it is valid for the specified DiEpoch.
-++   vg_assert (!iipc
-++              || (is_DI_valid_for_epoch(iipc->di, ep) && iipc->eip == eip));
-+ 
-+    const HChar *buf_fn;
-+    const HChar *buf_obj;
-+@@ -2282,8 +2502,8 @@ const HChar* VG_(describe_IP)(Addr eip,
-+    if (is_bottom(iipc)) {
-+       // At the bottom (towards main), we describe the fn at eip.
-+       know_fnname = VG_(clo_sym_offsets)
-+-                    ? VG_(get_fnname_w_offset) (eip, &buf_fn)
-+-                    : VG_(get_fnname) (eip, &buf_fn);
-++                    ? VG_(get_fnname_w_offset) (ep, eip, &buf_fn)
-++                    : VG_(get_fnname) (ep, eip, &buf_fn);
-+    } else {
-+       const DiInlLoc *next_inl = iipc && iipc->next_inltab >= 0
-+          ? & iipc->di->inltab[iipc->next_inltab]
-+@@ -2301,12 +2521,12 @@ const HChar* VG_(describe_IP)(Addr eip,
-+       // ??? Currently never showing an offset.
-+    }
-+ 
-+-   know_objname = VG_(get_objname)(eip, &buf_obj);
-++   know_objname = VG_(get_objname)(ep, eip, &buf_obj);
-+ 
-+    if (is_top(iipc)) {
-+       // The source for the highest level is in the loctab entry.
-+       know_srcloc  = VG_(get_filename_linenum)(
-+-                        eip, 
-++                        ep, eip, 
-+                         &buf_srcloc, 
-+                         &buf_dirname,
-+                         &lineno 
-+@@ -2459,6 +2679,20 @@ const HChar* VG_(describe_IP)(Addr eip,
-+ /*---                                                        ---*/
-+ /*--------------------------------------------------------------*/
-+ 
-++/* Note that the CFI machinery pertains to unwinding the stack "right now".
-++   There is no support for unwinding stack images obtained from some time in
-++   the past.  That means that:
-++
-++   (1) We only deal with CFI from DebugInfos that are valid for the current
-++       debuginfo epoch.  Unlike in the rest of the file, there is no
-++       epoch-awareness.
-++
-++   (2) We assume that the CFI cache will be invalidated every time the the
-++       epoch changes.  This is done by ensuring (in the file above) that
-++       every call to advance_current_DiEpoch has a call to
-++       caches__invalidate alongside it.
-++*/
-++
-+ /* Gather up all the constant pieces of info needed to evaluate
-+    a CfiExpr into one convenient struct. */
-+ typedef
-+@@ -2579,6 +2813,9 @@ UWord evalCfiExpr ( const XArray* exprs,
-+    *cfsi_mP to the cfsi_m pointer in that DebugInfo's cfsi_m_pool.
-+ 
-+    If not found, set *diP to (DebugInfo*)1 and *cfsi_mP to zero.
-++
-++   Per comments at the top of this section, we only look for CFI in
-++   DebugInfos that are valid for the current epoch.
-+ */
-+ __attribute__((noinline))
-+ static void find_DiCfSI ( /*OUT*/DebugInfo** diP, 
-+@@ -2594,10 +2831,15 @@ static void find_DiCfSI ( /*OUT*/DebugIn
-+ 
-+    if (0) VG_(printf)("search for %#lx\n", ip);
-+ 
-++   DiEpoch curr_epoch = VG_(current_DiEpoch)();
-++
-+    for (di = debugInfo_list; di != NULL; di = di->next) {
-+       Word j;
-+       n_steps++;
-+ 
-++      if (!is_DI_valid_for_epoch(di, curr_epoch))
-++         continue;
-++
-+       /* Use the per-DebugInfo summary address ranges to skip
-+          inapplicable DebugInfos quickly. */
-+       if (di->cfsi_used == 0)
-+@@ -2605,6 +2847,11 @@ static void find_DiCfSI ( /*OUT*/DebugIn
-+       if (ip < di->cfsi_minavma || ip > di->cfsi_maxavma)
-+          continue;
-+ 
-++      // This di must be active (because we have explicitly chosen not to
-++      // allow unwinding stacks that pertain to some past epoch).  It can't
-++      // be archived or not-yet-active.
-++      vg_assert(is_DebugInfo_active(di));
-++
-+       /* It might be in this DebugInfo.  Search it. */
-+       j = ML_(search_one_cfitab)( di, ip );
-+       vg_assert(j >= -1 && j < (Word)di->cfsi_used);
-+@@ -3032,6 +3279,7 @@ Bool VG_(use_CF_info) ( /*MOD*/D3UnwindR
-+ Bool VG_(use_FPO_info) ( /*MOD*/Addr* ipP,
-+                          /*MOD*/Addr* spP,
-+                          /*MOD*/Addr* fpP,
-++                         DiEpoch ep,
-+                          Addr min_accessible,
-+                          Addr max_accessible )
-+ {
-+@@ -3049,6 +3297,9 @@ Bool VG_(use_FPO_info) ( /*MOD*/Addr* ip
-+    for (di = debugInfo_list; di != NULL; di = di->next) {
-+       n_steps++;
-+ 
-++      if (!is_DI_valid_for_epoch(di, ep))
-++         continue;
-++
-+       /* Use the per-DebugInfo summary address ranges to skip
-+          inapplicable DebugInfos quickly. */
-+       if (di->fpo == NULL)
-+@@ -3552,6 +3803,7 @@ static void format_message ( /*MOD*/XArr
-+ static 
-+ Bool consider_vars_in_frame ( /*MOD*/XArray* /* of HChar */ dname1,
-+                               /*MOD*/XArray* /* of HChar */ dname2,
-++                              DiEpoch ep,
-+                               Addr data_addr,
-+                               Addr ip, Addr sp, Addr fp,
-+                               /* shown to user: */
-+@@ -3570,6 +3822,8 @@ Bool consider_vars_in_frame ( /*MOD*/XAr
-+    /* first, find the DebugInfo that pertains to 'ip'. */
-+    for (di = debugInfo_list; di; di = di->next) {
-+       n_steps++;
-++      if (!is_DI_valid_for_epoch(di, ep))
-++         continue;
-+       /* text segment missing? unlikely, but handle it .. */
-+       if (!di->text_present || di->text_size == 0)
-+          continue;
-+@@ -3687,7 +3941,7 @@ Bool consider_vars_in_frame ( /*MOD*/XAr
-+ Bool VG_(get_data_description)( 
-+         /*MOD*/ XArray* /* of HChar */ dname1,
-+         /*MOD*/ XArray* /* of HChar */ dname2,
-+-        Addr data_addr
-++        DiEpoch ep, Addr data_addr
-+      )
-+ {
-+ #  define N_FRAMES 8
-+@@ -3807,7 +4061,7 @@ Bool VG_(get_data_description)(
-+    vg_assert(n_frames >= 0 && n_frames <= N_FRAMES);
-+    for (j = 0; j < n_frames; j++) {
-+       if (consider_vars_in_frame( dname1, dname2,
-+-                                  data_addr,
-++                                  ep, data_addr,
-+                                   ips[j], 
-+                                   sps[j], fps[j], tid, j )) {
-+          zterm_XA( dname1 );
-+@@ -3834,7 +4088,7 @@ Bool VG_(get_data_description)(
-+          equivalent kludge. */
-+       if (j > 0 /* this is a non-innermost frame */
-+           && consider_vars_in_frame( dname1, dname2,
-+-                                     data_addr,
-++                                     ep, data_addr,
-+                                      ips[j] + 1, 
-+                                      sps[j], fps[j], tid, j )) {
-+          zterm_XA( dname1 );
-+Index: valgrind-3.13.0/coregrind/m_debuginfo/priv_storage.h
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_debuginfo/priv_storage.h
-++++ valgrind-3.13.0/coregrind/m_debuginfo/priv_storage.h
-+@@ -588,6 +588,36 @@ struct _DebugInfo {
-+       structure is allocated. */
-+    ULong handle;
-+ 
-++   /* The range of epochs for which this DebugInfo is valid.  These also
-++      divide the DebugInfo's lifetime into three parts:
-++
-++      (1) Allocated: but with only .fsm holding useful info -- in
-++          particular, not yet holding any debug info.
-++          .first_epoch == DebugInfoEpoch_INVALID
-++          .last_epoch  == DebugInfoEpoch_INVALID
-++
-++      (2) Active: containing debug info, and current.
-++          .first_epoch != DebugInfoEpoch_INVALID
-++          .last_epoch  == DebugInfoEpoch_INVALID
-++
-++      (3) Archived: containing debug info, but no longer current.
-++          .first_epoch != DebugInfoEpoch_INVALID
-++          .last_epoch  != DebugInfoEpoch_INVALID
-++
-++      State (2) corresponds to an object which is currently mapped.  When
-++      the object is unmapped, what happens depends on the setting of
-++      --keep-debuginfo:
-++      
-++      * when =no, the DebugInfo is removed from debugInfo_list and
-++        deleted.
-++
-++      * when =yes, the DebugInfo is retained in debugInfo_list, but its
-++        .last_epoch field is filled in, and current_epoch is advanced.  This
-++        effectively moves the DebugInfo into state (3).
-++   */
-++   DiEpoch first_epoch;
-++   DiEpoch last_epoch;
-++
-+    /* Used for debugging only - indicate what stuff to dump whilst
-+       reading stuff into the seginfo.  Are computed as early in the
-+       lifetime of the DebugInfo as possible -- at the point when it is
-+Index: valgrind-3.13.0/coregrind/m_errormgr.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_errormgr.c
-++++ valgrind-3.13.0/coregrind/m_errormgr.c
-+@@ -136,16 +136,16 @@ struct _Error {
-+    Int count;
-+ 
-+    // The tool-specific part
-+-   ThreadId tid;           // Initialised by core
-+-   ExeContext* where;      // Initialised by core
-+-   ErrorKind ekind;        // Used by ALL.  Must be in the range (0..)
-+-   Addr addr;              // Used frequently
-+-   const HChar* string;    // Used frequently
-+-   void* extra;            // For any tool-specific extras
-++   ThreadId tid;              // Initialised by core
-++   ExeContextAndEpoch where;  // Initialised by core
-++   ErrorKind ekind;           // Used by ALL.  Must be in the range (0..)
-++   Addr addr;                 // Used frequently
-++   const HChar* string;       // Used frequently
-++   void* extra;               // For any tool-specific extras
-+ };
-+ 
-+ 
-+-ExeContext* VG_(get_error_where) ( const Error* err )
-++ExeContextAndEpoch VG_(get_error_where) ( const Error* err )
-+ {
-+    return err->where;
-+ }
-+@@ -293,7 +293,10 @@ static Bool eq_Error ( VgRes res, const
-+ {
-+    if (e1->ekind != e2->ekind) 
-+       return False;
-+-   if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
-++   // This comparison ignores the debuginfo epoch.  Result is that we
-++   // could conclude this error is the same as one from some other epoch.
-++   // I don't think that's a big deal in practice.
-++   if (!VG_(eq_ExeContext)(res, e1->where.ec, e2->where.ec))
-+       return False;
-+ 
-+    switch (e1->ekind) {
-+@@ -321,15 +324,15 @@ static Bool eq_Error ( VgRes res, const
-+ */
-+ #define ERRTXT_LEN   4096
-+ 
-+-static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque)
-++static void printSuppForIp_XML(UInt n, DiEpoch ep, Addr ip, void* uu_opaque)
-+ {
-+    const HChar *buf;
-+-   InlIPCursor* iipc = VG_(new_IIPC)(ip);
-++   InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
-+    do {
-+-      if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
-++      if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
-+          VG_(printf_xml)("    <sframe> <fun>%pS</fun> </sframe>\n", buf);
-+       } else
-+-      if ( VG_(get_objname)(ip, &buf) ) {
-++      if ( VG_(get_objname)(ep, ip, &buf) ) {
-+          VG_(printf_xml)("    <sframe> <obj>%pS</obj> </sframe>\n", buf);
-+       } else {
-+          VG_(printf_xml)("    <sframe> <obj>*</obj> </sframe>\n");
-+@@ -338,16 +341,16 @@ static void printSuppForIp_XML(UInt n, A
-+    VG_(delete_IIPC)(iipc);
-+ }
-+ 
-+-static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV)
-++static void printSuppForIp_nonXML(UInt n, DiEpoch ep, Addr ip, void* textV)
-+ {
-+    const HChar *buf;
-+    XArray* /* of HChar */ text = (XArray*)textV;
-+-   InlIPCursor* iipc = VG_(new_IIPC)(ip);
-++   InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
-+    do {
-+-      if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
-++      if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
-+          VG_(xaprintf)(text, "   fun:%s\n", buf);
-+       } else
-+-      if ( VG_(get_objname)(ip, &buf) ) {
-++      if ( VG_(get_objname)(ep, ip, &buf) ) {
-+          VG_(xaprintf)(text, "   obj:%s\n", buf);
-+       } else {
-+          VG_(xaprintf)(text, "   obj:*\n");
-+@@ -361,15 +364,15 @@ static void printSuppForIp_nonXML(UInt n
-+ static void gen_suppression(const Error* err)
-+ {
-+    const HChar* name;
-+-   ExeContext* ec;
-++   ExeContextAndEpoch ece;
-+    XArray* /* HChar */ text;
-+ 
-+    const HChar* dummy_name = "insert_a_suppression_name_here";
-+ 
-+    vg_assert(err);
-+ 
-+-   ec = VG_(get_error_where)(err);
-+-   vg_assert(ec);
-++   ece = VG_(get_error_where)(err);
-++   vg_assert(ece.ec);
-+ 
-+    name = VG_TDICT_CALL(tool_get_error_name, err);
-+    if (NULL == name) {
-+@@ -408,12 +411,12 @@ static void gen_suppression(const Error*
-+       VG_(xaprintf)(text, "   %s\n", xtra);
-+ 
-+    // Print stack trace elements
-+-   UInt n_ips = VG_(get_ExeContext_n_ips)(ec);
-++   UInt n_ips = VG_(get_ExeContext_n_ips)(ece.ec);
-+    vg_assert(n_ips > 0);
-+    vg_assert(n_ips <= VG_DEEPEST_BACKTRACE);
-+    VG_(apply_StackTrace)(printSuppForIp_nonXML,
-+-                         text,
-+-                         VG_(get_ExeContext_StackTrace)(ec),
-++                         text, ece.epoch,
-++                         VG_(get_ExeContext_StackTrace)(ece.ec),
-+                          n_ips);
-+ 
-+    VG_(xaprintf)(text, "}\n");
-+@@ -441,9 +444,9 @@ static void gen_suppression(const Error*
-+ 
-+       // Print stack trace elements
-+       VG_(apply_StackTrace)(printSuppForIp_XML,
-+-                            NULL,
-+-                            VG_(get_ExeContext_StackTrace)(ec),
-+-                            VG_(get_ExeContext_n_ips)(ec));
-++                            NULL, ece.epoch,
-++                            VG_(get_ExeContext_StackTrace)(ece.ec),
-++                            VG_(get_ExeContext_n_ips)(ece.ec));
-+ 
-+       // And now the cdata bit
-+       // XXX FIXME!  properly handle the case where the raw text
-+@@ -637,7 +640,7 @@ static void pp_Error ( const Error* err,
-+ /* Construct an error */
-+ static
-+ void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
-+-                       const HChar* s, void* extra, ExeContext* where )
-++                       const HChar* s, void* extra, ExeContextAndEpoch where )
-+ {
-+    /* DO NOT MAKE unique_counter NON-STATIC */
-+    static UInt unique_counter = 0;
-+@@ -650,10 +653,7 @@ void construct_error ( Error* err, Threa
-+    err->supp     = NULL;
-+    err->count    = 1;
-+    err->tid      = tid;
-+-   if (NULL == where)
-+-     err->where = VG_(record_ExeContext)( tid, 0 );
-+-   else
-+-      err->where = where;
-++   err->where    = where;
-+ 
-+    /* Tool-relevant parts */
-+    err->ekind  = ekind;
-+@@ -744,7 +744,10 @@ void VG_(maybe_record_error) ( ThreadId
-+    }
-+ 
-+    /* Build ourselves the error */
-+-   construct_error ( &err, tid, ekind, a, s, extra, NULL );
-++   { ExeContextAndEpoch ece
-++        = VG_(tag_EC_with_current_epoch)( VG_(record_ExeContext)( tid, 0 ) );
-++      construct_error ( &err, tid, ekind, a, s, extra, ece );
-++   }
-+ 
-+    /* First, see if we've got an error record matching this one. */
-+    em_errlist_searches++;
-+@@ -853,7 +856,8 @@ void VG_(maybe_record_error) ( ThreadId
-+    Bool 'count_error' dictates whether to count the error in n_errs_found.
-+ */
-+ Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
-+-                         void* extra, ExeContext* where, Bool print_error,
-++                         void* extra, ExeContextAndEpoch where,
-++                         Bool print_error,
-+                          Bool allow_db_attach, Bool count_error )
-+ {
-+    Error err;
-+@@ -1016,7 +1020,7 @@ void VG_(show_all_errors) (  Int verbosi
-+       vg_assert(! xml);
-+ 
-+       if ((i+1 == VG_(clo_dump_error))) {
-+-         StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
-++         StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where.ec);
-+          VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
-+                           ips[0], /*debugging*/True, 0xFE/*verbosity*/,
-+                           /*bbs_done*/0,
-+@@ -1500,6 +1504,7 @@ static Bool supploc_IsQuery ( const void
-+    allocations and the nr of debuginfo search. */
-+ typedef
-+    struct {
-++      DiEpoch epoch;  // used to interpret .ips
-+       StackTrace ips; // stack trace we are lazily completing.
-+       UWord n_ips; // nr of elements in ips.
-+ 
-+@@ -1595,9 +1600,11 @@ static void clearIPtoFunOrObjCompleter (
-+                    su->sname,
-+                    filename,
-+                    su->sname_lineno);
-+-      } else
-++      } else {
-+          VG_(dmsg)("errormgr matching end no suppression matched:\n");
-+-      VG_(pp_StackTrace) (ip2fo->ips, ip2fo->n_ips);
-++      }
-++      // JRS 27 July 2017: is it OK to use the current epoch here?
-++      VG_(pp_StackTrace) (ip2fo->epoch, ip2fo->ips, ip2fo->n_ips);
-+       pp_ip2fo(ip2fo);
-+    }
-+    if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
-+@@ -1660,7 +1667,8 @@ static HChar* foComplete(IPtoFunOrObjCom
-+          // up comparing "malloc" in the suppression against
-+          // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
-+          // two of them need to be made to match.
-+-         if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->ips[ixInput],
-++         if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch,
-++                                              ip2fo->ips[ixInput],
-+                                               &caller,
-+                                               NULL))
-+             caller = "???";
-+@@ -1681,7 +1689,7 @@ static HChar* foComplete(IPtoFunOrObjCom
-+             last_expand_pos_ips is the last offset in fun/obj where
-+             ips[pos_ips] has been expanded. */
-+ 
-+-         if (!VG_(get_objname)(ip2fo->ips[pos_ips], &caller))
-++         if (!VG_(get_objname)(ip2fo->epoch, ip2fo->ips[pos_ips], &caller))
-+             caller = "???";
-+ 
-+          // Have all inlined calls pointing at this object name
-+@@ -1751,7 +1759,7 @@ static void expandInput (IPtoFunOrObjCom
-+          const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
-+          InlIPCursor *iipc;
-+ 
-+-         iipc = VG_(new_IIPC)(IP);
-++         iipc = VG_(new_IIPC)(ip2fo->epoch, IP);
-+          // The only thing we really need is the nr of inlined fn calls
-+          // corresponding to the IP we will expand.
-+          // However, computing this is mostly the same as finding
-+@@ -1760,7 +1768,7 @@ static void expandInput (IPtoFunOrObjCom
-+             const HChar *caller;
-+             grow_offsets(ip2fo, ip2fo->n_expanded+1);
-+             ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
-+-            if (!VG_(get_fnname_no_cxx_demangle)(IP, 
-++            if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch, IP, 
-+                                                  &caller,
-+                                                  iipc))
-+                caller = "???";
-+@@ -1788,18 +1796,18 @@ static void expandInput (IPtoFunOrObjCom
-+    }
-+ }
-+ 
-+-static Bool haveInputInpC (void* inputCompleter, UWord ixInput )
-++static Bool haveInputInpC (void* inputCompleterV, UWord ixInput )
-+ {
-+-   IPtoFunOrObjCompleter* ip2fo = inputCompleter;
-++   IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
-+    expandInput(ip2fo, ixInput);
-+    return ixInput < ip2fo->n_expanded;
-+ }
-+ 
-+ static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
-+-                             void* inputCompleter, UWord ixInput )
-++                             void* inputCompleterV, UWord ixInput )
-+ {
-+-   const SuppLoc* supploc = supplocV; /* PATTERN */
-+-   IPtoFunOrObjCompleter* ip2fo = inputCompleter;
-++   const SuppLoc* supploc = (const SuppLoc*)supplocV; /* PATTERN */
-++   IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
-+    HChar* funobj_name; // Fun or Obj name.
-+    Bool ret;
-+ 
-+@@ -1926,8 +1934,9 @@ static Supp* is_suppressible_error ( con
-+    em_supplist_searches++;
-+ 
-+    /* Prepare the lazy input completer. */
-+-   ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
-+-   ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
-++   ip2fo.epoch = err->where.epoch;
-++   ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where.ec);
-++   ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where.ec);
-+    ip2fo.n_ips_expanded = 0;
-+    ip2fo.n_expanded = 0;
-+    ip2fo.sz_offsets = 0;
-+Index: valgrind-3.13.0/coregrind/m_execontext.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_execontext.c
-++++ valgrind-3.13.0/coregrind/m_execontext.c
-+@@ -116,7 +116,7 @@ static ULong ec_cmpAlls;
-+ 
-+ 
-+ /*------------------------------------------------------------*/
-+-/*--- Exported functions.                                  ---*/
-++/*--- ExeContext functions.                                ---*/
-+ /*------------------------------------------------------------*/
-+ 
-+ static ExeContext* record_ExeContext_wrk2 ( const Addr* ips, UInt n_ips );
-+@@ -169,7 +169,9 @@ void VG_(print_ExeContext_stats) ( Bool
-+          for (ec = ec_htab[i]; ec; ec = ec->chain) {
-+             VG_(message)(Vg_DebugMsg, "   exectx: stacktrace ecu %u n_ips %u\n",
-+                          ec->ecu, ec->n_ips);
-+-            VG_(pp_StackTrace)( ec->ips, ec->n_ips );
-++            // FIXME JRS 27 July 2017: is a fake epoch here OK?
-++            DiEpoch ep = VG_(current_DiEpoch)();
-++            VG_(pp_StackTrace)( ep, ec->ips, ec->n_ips );
-+          }
-+       }
-+       VG_(message)(Vg_DebugMsg, 
-+@@ -202,13 +204,6 @@ void VG_(print_ExeContext_stats) ( Bool
-+ }
-+ 
-+ 
-+-/* Print an ExeContext. */
-+-void VG_(pp_ExeContext) ( ExeContext* ec )
-+-{
-+-   VG_(pp_StackTrace)( ec->ips, ec->n_ips );
-+-}
-+-
-+-
-+ /* Compare two ExeContexts.  Number of callers considered depends on res. */
-+ Bool VG_(eq_ExeContext) ( VgRes res, const ExeContext* e1,
-+                           const ExeContext* e2 )
-+@@ -544,12 +539,48 @@ ExeContext* VG_(make_ExeContext_from_Sta
-+    return record_ExeContext_wrk2(ips, n_ips);
-+ }
-+ 
-+-ExeContext* VG_(null_ExeContext) (void)
-++
-++/*------------------------------------------------------------*/
-++/*--- ExeContextAndEpoch functions.                        ---*/
-++/*------------------------------------------------------------*/
-++
-++ExeContextAndEpoch VG_(tag_EC_with_current_epoch)( ExeContext* ec )
-++{
-++   ExeContextAndEpoch ece;
-++   ece.ec    = ec;
-++   ece.epoch = VG_(current_DiEpoch)();
-++   return ece;
-++}
-++
-++ExeContextAndEpoch VG_(invalid_ExeContextAndEpoch) ( void )
-++{
-++   ExeContextAndEpoch ece;
-++   ece.ec      = NULL/*invalid ExeContext*/;
-++   ece.epoch.n = 0/*invalid epoch*/;
-++   return ece;
-++}
-++
-++
-++void VG_(pp_ExeContextAndEpoch) ( ExeContextAndEpoch ece )
-++{
-++   VG_(pp_StackTrace)( ece.epoch, ece.ec->ips, ece.ec->n_ips );
-++}
-++
-++ExeContextAndEpoch VG_(null_ExeContextAndEpoch) ( void )
-+ {
-+    init_ExeContext_storage();
-+-   return null_ExeContext;
-++   ExeContextAndEpoch ece
-++      = mk_ExeContextAndEpoch(null_ExeContext, VG_(current_DiEpoch)());
-++   return ece;
-+ }
-+ 
-++Bool VG_(is_null_ExeContextAndEpoch)( ExeContextAndEpoch ece )
-++{
-++   init_ExeContext_storage();
-++   return ece.ec == null_ExeContext;
-++}
-++
-++
-+ /*--------------------------------------------------------------------*/
-+ /*--- end                                           m_execontext.c ---*/
-+ /*--------------------------------------------------------------------*/
-+Index: valgrind-3.13.0/coregrind/m_gdbserver/m_gdbserver.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/m_gdbserver.c
-++++ valgrind-3.13.0/coregrind/m_gdbserver/m_gdbserver.c
-+@@ -142,14 +142,17 @@ static HChar* sym (Addr addr, Bool is_co
-+    PtrdiffT offset;
-+    if (w == 2) w = 0;
-+ 
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+    if (is_code) {
-+       const HChar *name;
-+-      name = VG_(describe_IP) (addr, NULL);
-++      name = VG_(describe_IP) (ep, addr, NULL);
-+       if (buf[w]) VG_(free)(buf[w]);
-+       buf[w] = VG_(strdup)("gdbserver sym", name);
-+    } else {
-+       const HChar *name;
-+-      VG_(get_datasym_and_offset) (addr, &name, &offset);
-++      VG_(get_datasym_and_offset) (ep, addr, &name, &offset);
-+       if (buf[w]) VG_(free)(buf[w]);
-+       buf[w] = VG_(strdup)("gdbserver sym", name);
-+    }
-+Index: valgrind-3.13.0/coregrind/m_gdbserver/server.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/server.c
-++++ valgrind-3.13.0/coregrind/m_gdbserver/server.c
-+@@ -195,6 +195,9 @@ int handle_gdb_valgrind_command (char *m
-+    int   kwdid;
-+    int int_value;
-+ 
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+    vg_assert (initial_valgrind_sink_saved);
-+ 
-+    strcpy (s, mon);
-+@@ -334,7 +337,7 @@ int handle_gdb_valgrind_command (char *m
-+          }
-+          if (hostvisibility) {
-+             const DebugInfo *tooldi 
-+-               = VG_(find_DebugInfo) ((Addr)handle_gdb_valgrind_command);
-++               = VG_(find_DebugInfo) (ep, (Addr)handle_gdb_valgrind_command);
-+             /* Normally, we should always find the tooldi. In case we
-+                do not, suggest a 'likely somewhat working' address: */
-+             const Addr tool_text_start
-+@@ -442,14 +445,14 @@ int handle_gdb_valgrind_command (char *m
-+                                                &dummy_sz, &ssaveptr)) {
-+             // If tool provides location information, use that.
-+             if (VG_(needs).info_location) {
-+-               VG_TDICT_CALL(tool_info_location, address);
-++               VG_TDICT_CALL(tool_info_location, ep, address);
-+             } 
-+             // If tool does not provide location info, use the common one.
-+             // Also use the common to compare with tool when debug log is set.
-+             if (!VG_(needs).info_location || VG_(debugLog_getLevel)() > 0 ) {
-+                AddrInfo ai;
-+                ai.tag = Addr_Undescribed;
-+-               VG_(describe_addr) (address, &ai);
-++               VG_(describe_addr) (ep, address, &ai);
-+                VG_(pp_addrinfo) (address, &ai);
-+                VG_(clear_addrinfo) (&ai);
-+             }
-+Index: valgrind-3.13.0/coregrind/m_gdbserver/target.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/target.c
-++++ valgrind-3.13.0/coregrind/m_gdbserver/target.c
-+@@ -209,7 +209,10 @@ void gdbserver_process_exit_encountered
-+ static
-+ const HChar* sym (Addr addr)
-+ {
-+-   return VG_(describe_IP) (addr, NULL);
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-++   return VG_(describe_IP) (ep, addr, NULL);
-+ }
-+ 
-+ ThreadId vgdb_interrupted_tid = 0;
-+Index: valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-arm.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/valgrind-low-arm.c
-++++ valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-arm.c
-+@@ -149,8 +149,12 @@ Addr thumb_pc (Addr pc)
-+       // the debug info with the bit0 set
-+       // (why can't debug info do that for us ???)
-+       // (why if this is a 4 bytes thumb instruction ???)
-+-      if (VG_(get_fnname_raw) (pc | 1, &fnname)) {
-+-         if (VG_(lookup_symbol_SLOW)( "*", fnname, &avmas )) {
-++
-++      // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++      const DiEpoch ep = VG_(current_DiEpoch)();
-++
-++      if (VG_(get_fnname_raw) (ep, pc | 1, &fnname)) {
-++         if (VG_(lookup_symbol_SLOW)( ep, "*", fnname, &avmas )) {
-+             dlog (1, "fnname %s lookupsym %p => %p %s.\n",
-+                   fnname, C2v(avmas.main), C2v(pc),
-+                   (avmas.main & 1 ? "thumb" : "arm"));
-+Index: valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips32.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/valgrind-low-mips32.c
-++++ valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips32.c
-+@@ -228,7 +228,11 @@ static Addr mips_adjust_breakpoint_addre
-+    /* Make sure we don't scan back before the beginning of the current
-+       function, since we may fetch constant data or insns that look like
-+       a jump. */
-+-   if (VG_(get_inst_offset_in_function) (bpaddr, &offset)) {
-++
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-++   if (VG_(get_inst_offset_in_function) (ep, bpaddr, &offset)) {
-+       func_addr = bpaddr - offset;
-+       if (func_addr > boundary && func_addr <= bpaddr)
-+          boundary = func_addr;
-+Index: valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips64.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_gdbserver/valgrind-low-mips64.c
-++++ valgrind-3.13.0/coregrind/m_gdbserver/valgrind-low-mips64.c
-+@@ -229,7 +229,11 @@ static Addr mips_adjust_breakpoint_addre
-+    /* Make sure we don't scan back before the beginning of the current
-+       function, since we may fetch constant data or insns that look like
-+       a jump. */
-+-   if (VG_(get_inst_offset_in_function) (bpaddr, &offset)) {
-++
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-++   if (VG_(get_inst_offset_in_function) (ep, bpaddr, &offset)) {
-+       func_addr = bpaddr - offset;
-+       if (func_addr > boundary && func_addr <= bpaddr)
-+          boundary = func_addr;
-+Index: valgrind-3.13.0/coregrind/m_libcassert.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_libcassert.c
-++++ valgrind-3.13.0/coregrind/m_libcassert.c
-+@@ -369,7 +369,7 @@ static void show_sched_status_wrk ( Bool
-+          );
-+       VG_(printf)("\nhost stacktrace:\n"); 
-+       VG_(clo_xml) = False;
-+-      VG_(pp_StackTrace) (ips, n_ips);
-++      VG_(pp_StackTrace) (VG_(current_DiEpoch)(), ips, n_ips);
-+       VG_(clo_xml) = save_clo_xml;
-+    }
-+ 
-+Index: valgrind-3.13.0/coregrind/m_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_main.c
-++++ valgrind-3.13.0/coregrind/m_main.c
-+@@ -128,6 +128,10 @@ static void usage_NORETURN ( Bool debug_
-+ "    --error-exitcode=<number> exit code to return if errors found [0=disable]\n"
-+ "    --error-markers=<begin>,<end> add lines with begin/end markers before/after\n"
-+ "                              each error output in plain text mode [none]\n"
-++"    --keep-debuginfo=no|yes   Keep symbols etc for unloaded code [no]\n"
-++"                              This allows stack traces for memory leaks to\n"
-++"                              include file/line info for code that has been\n"
-++"                              dlclose'd (or similar)\n"
-+ "    --show-below-main=no|yes  continue stack traces below main() [no]\n"
-+ "    --default-suppressions=yes|no\n"
-+ "                              load default suppressions [yes]\n"
-+@@ -626,6 +630,7 @@ void main_process_cmd_line_options( void
-+       else if VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres)) {}
-+       else if VG_BOOL_CLO(arg, "--run-cxx-freeres",  VG_(clo_run_cxx_freeres)) {}
-+       else if VG_BOOL_CLO(arg, "--show-below-main",  VG_(clo_show_below_main)) {}
-++      else if VG_BOOL_CLO(arg, "--keep-debuginfo",   VG_(clo_keep_debuginfo)) {}
-+       else if VG_BOOL_CLO(arg, "--time-stamp",       VG_(clo_time_stamp)) {}
-+       else if VG_BOOL_CLO(arg, "--track-fds",        VG_(clo_track_fds)) {}
-+       else if VG_BOOL_CLO(arg, "--trace-children",   VG_(clo_trace_children)) {}
-+Index: valgrind-3.13.0/coregrind/m_options.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_options.c
-++++ valgrind-3.13.0/coregrind/m_options.c
-+@@ -129,6 +129,7 @@ Bool   VG_(clo_run_libc_freeres) = True;
-+ Bool   VG_(clo_run_cxx_freeres) = True;
-+ Bool   VG_(clo_track_fds)      = False;
-+ Bool   VG_(clo_show_below_main)= False;
-++Bool   VG_(clo_keep_debuginfo) = False;
-+ Bool   VG_(clo_show_emwarns)   = False;
-+ Word   VG_(clo_max_stackframe) = 2000000;
-+ UInt   VG_(clo_max_threads)    = MAX_THREADS_DEFAULT;
-+Index: valgrind-3.13.0/coregrind/m_redir.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_redir.c
-++++ valgrind-3.13.0/coregrind/m_redir.c
-+@@ -1859,15 +1859,16 @@ static void show_active ( const HChar* l
-+ {
-+    Bool ok;
-+    const HChar *buf;
-+- 
-+-   ok = VG_(get_fnname_w_offset)(act->from_addr, &buf);
-++
-++   DiEpoch ep = VG_(current_DiEpoch)(); 
-++   ok = VG_(get_fnname_w_offset)(ep, act->from_addr, &buf);
-+    if (!ok) buf = "???";
-+    // Stash away name1
-+    HChar name1[VG_(strlen)(buf) + 1];
-+    VG_(strcpy)(name1, buf);
-+ 
-+    const HChar *name2;
-+-   ok = VG_(get_fnname_w_offset)(act->to_addr, &name2);
-++   ok = VG_(get_fnname_w_offset)(ep, act->to_addr, &name2);
-+    if (!ok) name2 = "???";
-+ 
-+    VG_(message)(Vg_DebugMsg, "%s0x%08lx (%-20s) %s-> (%04d.%d) 0x%08lx %s\n", 
-+Index: valgrind-3.13.0/coregrind/m_sbprofile.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_sbprofile.c
-++++ valgrind-3.13.0/coregrind/m_sbprofile.c
-+@@ -74,6 +74,9 @@ void show_SB_profile ( const SBProfEntry
-+ 
-+    VG_(printf)("Total score = %'llu\n\n", score_total);
-+ 
-++   // FIXME JRS 28 July 2017: this is probably not right in general
-++   DiEpoch ep = VG_(current_DiEpoch)();
-++
-+    /* Print an initial per-block summary. */
-+    VG_(printf)("rank  ---cumulative---      -----self-----\n");
-+    score_cumul = 0;
-+@@ -84,7 +87,7 @@ void show_SB_profile ( const SBProfEntry
-+          continue;
-+ 
-+       const HChar *name;
-+-      VG_(get_fnname_w_offset)(tops[r].addr, &name);
-++      VG_(get_fnname_w_offset)(ep, tops[r].addr, &name);
-+ 
-+       score_here = tops[r].score;
-+       score_cumul += score_here;
-+@@ -123,7 +126,7 @@ void show_SB_profile ( const SBProfEntry
-+             continue;
-+ 
-+          const HChar *name;
-+-         VG_(get_fnname_w_offset)(tops[r].addr, &name);
-++         VG_(get_fnname_w_offset)(ep, tops[r].addr, &name);
-+ 
-+          score_here = tops[r].score;
-+          score_cumul += score_here;
-+@@ -159,7 +162,7 @@ void show_SB_profile ( const SBProfEntry
-+             continue;
-+ 
-+          const HChar *name;
-+-         VG_(get_fnname_w_offset)(tops[r].addr, &name);
-++         VG_(get_fnname_w_offset)(ep, tops[r].addr, &name);
-+ 
-+          score_here = tops[r].score;
-+ 
-+Index: valgrind-3.13.0/coregrind/m_scheduler/scheduler.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_scheduler/scheduler.c
-++++ valgrind-3.13.0/coregrind/m_scheduler/scheduler.c
-+@@ -2037,8 +2037,12 @@ void do_client_request ( ThreadId tid )
-+ 
-+          VG_(memset)(buf64, 0, 64);
-+          UInt linenum = 0;
-++
-++         // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++         const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+          Bool ok = VG_(get_filename_linenum)(
-+-                      ip, &buf, NULL, &linenum
-++                      ep, ip, &buf, NULL, &linenum
-+                    );
-+          if (ok) {
-+             /* For backward compatibility truncate the filename to
-+Index: valgrind-3.13.0/coregrind/m_signals.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_signals.c
-++++ valgrind-3.13.0/coregrind/m_signals.c
-+@@ -1878,7 +1878,7 @@ static void default_action(const vki_sig
-+                       : VG_(record_depth_1_ExeContext)( tid,
-+                                                         first_ip_delta );
-+          vg_assert(ec);
-+-         VG_(pp_ExeContext)( ec );
-++         VG_(pp_ExeContextAndEpoch)( VG_(tag_EC_with_current_epoch)(ec) );
-+       }
-+       if (sigNo == VKI_SIGSEGV 
-+           && is_signal_from_kernel(tid, sigNo, info->si_code)
-+Index: valgrind-3.13.0/coregrind/m_stacktrace.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_stacktrace.c
-++++ valgrind-3.13.0/coregrind/m_stacktrace.c
-+@@ -446,6 +446,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId
-+       /* And, similarly, try for MSVC FPO unwind info. */
-+       if (FPO_info_present
-+           && VG_(use_FPO_info)( &uregs.xip, &uregs.xsp, &uregs.xbp,
-++                                VG_(current_DiEpoch)(),
-+                                 fp_min, fp_max ) ) {
-+          if (debug) unwind_case = "MS";
-+          if (do_stats) stats.MS++;
-+@@ -1539,12 +1540,12 @@ UInt VG_(get_StackTrace) ( ThreadId tid,
-+                                        stack_highest_byte);
-+ }
-+ 
-+-static void printIpDesc(UInt n, Addr ip, void* uu_opaque)
-++static void printIpDesc(UInt n, DiEpoch ep, Addr ip, void* uu_opaque)
-+ {
-+-   InlIPCursor *iipc = VG_(new_IIPC)(ip);
-++   InlIPCursor *iipc = VG_(new_IIPC)(ep, ip);
-+ 
-+    do {
-+-      const HChar *buf = VG_(describe_IP)(ip, iipc);
-++      const HChar *buf = VG_(describe_IP)(ep, ip, iipc);
-+       if (VG_(clo_xml)) {
-+          VG_(printf_xml)("    %s\n", buf);
-+       } else {
-+@@ -1558,14 +1559,14 @@ static void printIpDesc(UInt n, Addr ip,
-+ }
-+ 
-+ /* Print a StackTrace. */
-+-void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips )
-++void VG_(pp_StackTrace) ( DiEpoch ep, StackTrace ips, UInt n_ips )
-+ {
-+    vg_assert( n_ips > 0 );
-+ 
-+    if (VG_(clo_xml))
-+       VG_(printf_xml)("  <stack>\n");
-+ 
-+-   VG_(apply_StackTrace)( printIpDesc, NULL, ips, n_ips );
-++   VG_(apply_StackTrace)( printIpDesc, NULL, ep, ips, n_ips );
-+ 
-+    if (VG_(clo_xml))
-+       VG_(printf_xml)("  </stack>\n");
-+@@ -1580,13 +1581,13 @@ void VG_(get_and_pp_StackTrace) ( Thread
-+                             NULL/*array to dump SP values in*/,
-+                             NULL/*array to dump FP values in*/,
-+                             0/*first_ip_delta*/);
-+-   VG_(pp_StackTrace)(ips, n_ips);
-++   VG_(pp_StackTrace)(VG_(current_DiEpoch)(), ips, n_ips);
-+ }
-+ 
-+ void VG_(apply_StackTrace)(
-+-        void(*action)(UInt n, Addr ip, void* opaque),
-++        void(*action)(UInt n, DiEpoch ep, Addr ip, void* opaque),
-+         void* opaque,
-+-        StackTrace ips, UInt n_ips
-++        DiEpoch ep, StackTrace ips, UInt n_ips
-+      )
-+ {
-+    Int i;
-+@@ -1597,7 +1598,7 @@ void VG_(apply_StackTrace)(
-+       // or the last appearance of a below main function.
-+       // Then decrease n_ips so as to not call action for the below main
-+       for (i = n_ips - 1; i >= 0; i--) {
-+-         Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(ips[i]);
-++         Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(ep, ips[i]);
-+          if (Vg_FnNameMain == kind || Vg_FnNameBelowMain == kind)
-+             n_ips = i + 1;
-+          if (Vg_FnNameMain == kind)
-+@@ -1607,7 +1608,7 @@ void VG_(apply_StackTrace)(
-+ 
-+    for (i = 0; i < n_ips; i++)
-+       // Act on the ip
-+-      action(i, ips[i], opaque);
-++      action(i, ep, ips[i], opaque);
-+ }
-+ 
-+ 
-+Index: valgrind-3.13.0/coregrind/m_syswrap/syswrap-generic.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_syswrap/syswrap-generic.c
-++++ valgrind-3.13.0/coregrind/m_syswrap/syswrap-generic.c
-+@@ -540,7 +540,8 @@ typedef struct OpenFd
-+ {
-+    Int fd;                        /* The file descriptor */
-+    HChar *pathname;               /* NULL if not a regular file or unknown */
-+-   ExeContext *where;             /* NULL if inherited from parent */
-++   ExeContextAndEpoch where;      /* VG_(null_ExeContextAndEpoch)
-++                                     if inherited from parent */
-+    struct OpenFd *next, *prev;
-+ } OpenFd;
-+ 
-+@@ -614,7 +615,10 @@ void ML_(record_fd_open_with_given_name)
-+ 
-+    i->fd = fd;
-+    i->pathname = VG_(strdup)("syswrap.rfdowgn.2", pathname);
-+-   i->where = (tid == -1) ? NULL : VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
-++   i->where = (tid == -1)
-++                 ? VG_(null_ExeContextAndEpoch)()
-++                 : VG_(tag_EC_with_current_epoch)(
-++                      VG_(record_ExeContext)(tid, 0/*first_ip_delta*/));
-+ }
-+ 
-+ // Record opening of an fd, and find its name.
-+@@ -846,8 +850,8 @@ void VG_(show_open_fds) (const HChar* wh
-+          }
-+       }
-+ 
-+-      if(i->where) {
-+-         VG_(pp_ExeContext)(i->where);
-++      if (!VG_(is_null_ExeContextAndEpoch)(i->where)) {
-++         VG_(pp_ExeContextAndEpoch)(i->where);
-+          VG_(message)(Vg_UserMsg, "\n");
-+       } else {
-+          VG_(message)(Vg_UserMsg, "   <inherited from parent>\n");
-+Index: valgrind-3.13.0/coregrind/m_tooliface.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_tooliface.c
-++++ valgrind-3.13.0/coregrind/m_tooliface.c
-+@@ -323,7 +323,7 @@ void VG_(needs_print_stats) (
-+ }
-+ 
-+ void VG_(needs_info_location) (
-+-   void (*info_location)(Addr)
-++   void (*info_location)(DiEpoch, Addr)
-+ )
-+ {
-+    VG_(needs).info_location = True;
-+Index: valgrind-3.13.0/coregrind/m_translate.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_translate.c
-++++ valgrind-3.13.0/coregrind/m_translate.c
-+@@ -1527,24 +1527,25 @@ Bool VG_(translate) ( ThreadId tid,
-+       Bool ok;
-+       const HChar *buf;
-+       const HChar *name2;
-++      const DiEpoch ep = VG_(current_DiEpoch)();
-+ 
-+       /* Try also to get the soname (not the filename) of the "from"
-+          object.  This makes it much easier to debug redirection
-+          problems. */
-+       const HChar* nraddr_soname = "???";
-+-      DebugInfo*   nraddr_di     = VG_(find_DebugInfo)(nraddr);
-++      DebugInfo*   nraddr_di     = VG_(find_DebugInfo)(ep, nraddr);
-+       if (nraddr_di) {
-+          const HChar* t = VG_(DebugInfo_get_soname)(nraddr_di);
-+          if (t)
-+             nraddr_soname = t;
-+       }
-+ 
-+-      ok = VG_(get_fnname_w_offset)(nraddr, &buf);
-++      ok = VG_(get_fnname_w_offset)(ep, nraddr, &buf);
-+       if (!ok) buf = "???";
-+       // Stash away name1
-+       HChar name1[VG_(strlen)(buf) + 1];
-+       VG_(strcpy)(name1, buf);
-+-      ok = VG_(get_fnname_w_offset)(addr, &name2);
-++      ok = VG_(get_fnname_w_offset)(ep, addr, &name2);
-+       if (!ok) name2 = "???";
-+ 
-+       VG_(message)(Vg_DebugMsg, 
-+@@ -1561,7 +1562,8 @@ Bool VG_(translate) ( ThreadId tid,
-+    if (VG_(clo_trace_flags) || debugging_translation) {
-+       const HChar* objname = "UNKNOWN_OBJECT";
-+       OffT         objoff  = 0;
-+-      DebugInfo*   di      = VG_(find_DebugInfo)( addr );
-++      const DiEpoch ep     = VG_(current_DiEpoch)();
-++      DebugInfo*   di      = VG_(find_DebugInfo)( ep, addr );
-+       if (di) {
-+          objname = VG_(DebugInfo_get_filename)(di);
-+          objoff  = addr - VG_(DebugInfo_get_text_bias)(di);
-+@@ -1569,7 +1571,7 @@ Bool VG_(translate) ( ThreadId tid,
-+       vg_assert(objname);
-+  
-+       const HChar *fnname;
-+-      Bool ok = VG_(get_fnname_w_offset)(addr, &fnname);
-++      Bool ok = VG_(get_fnname_w_offset)(ep, addr, &fnname);
-+       if (!ok) fnname = "UNKNOWN_FUNCTION";
-+       VG_(printf)(
-+          "==== SB %u (evchecks %llu) [tid %u] 0x%lx %s %s%c0x%lx\n",
-+Index: valgrind-3.13.0/coregrind/m_xtree.c
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/m_xtree.c
-++++ valgrind-3.13.0/coregrind/m_xtree.c
-+@@ -438,6 +438,9 @@ void VG_(XT_callgrind_print)
-+    const HChar* filename_dir;
-+    const HChar* filename_name;
-+ 
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+    if (fp == NULL)
-+       return;
-+ 
-+@@ -501,7 +504,7 @@ void VG_(XT_callgrind_print)
-+       // the strings  called_filename/called_fnname.
-+ #define CALLED_FLF(n)                                                   \
-+       if ((n) < 0                                                       \
-+-          || !VG_(get_filename_linenum)(ips[(n)],                       \
-++          || !VG_(get_filename_linenum)(ep, ips[(n)],                   \
-+                                         &filename_name,                 \
-+                                         &filename_dir,                  \
-+                                         &called_linenum)) {             \
-+@@ -509,7 +512,7 @@ void VG_(XT_callgrind_print)
-+          called_linenum = 0;                                            \
-+       }                                                                 \
-+       if ((n) < 0                                                       \
-+-          || !VG_(get_fnname)(ips[(n)], &called_fnname)) {              \
-++          || !VG_(get_fnname)(ep, ips[(n)], &called_fnname)) {          \
-+          called_fnname = "UnknownFn???";                                \
-+       }                                                                 \
-+       {                                                                 \
-+@@ -554,7 +557,9 @@ void VG_(XT_callgrind_print)
-+ 
-+          if (0) {
-+             VG_(printf)("entry img %s\n", img);
-+-            VG_(pp_ExeContext)(xe->ec);
-++            // JRS 27 July 2017: it may be a hack to use the current epoch
-++            // here.  I don't know.
-++            VG_(pp_ExeContextAndEpoch)(VG_(tag_EC_with_current_epoch)(xe->ec));
-+             VG_(printf)("\n");
-+          }
-+          xt->add_data_fn(xt->tmp_data, VG_(indexXA)(xt->data, xecu));
-+@@ -762,11 +767,14 @@ static void ms_output_group (VgFile* fp,
-+    ms_make_groups(depth+1, group->ms_ec, group->n_ec, sig_sz,
-+                   &n_groups, &groups);
-+ 
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+    FP("%*s" "n%u: %ld %s\n", 
-+       depth + 1, "",
-+       n_groups, 
-+       group->total,
-+-      VG_(describe_IP)(group->ms_ec->ips[depth] - 1, NULL));
-++      VG_(describe_IP)(ep, group->ms_ec->ips[depth] - 1, NULL));
-+    /* XTREE??? Massif original code removes 1 to get the IP description. I am
-+       wondering if this is not something that predates revision r8818,
-+       which introduced a -1 in the stack unwind (see m_stacktrace.c)
-+@@ -963,6 +971,10 @@ Int VG_(XT_offset_main_or_below_main)(Ad
-+       from there.
-+       If no main is found, we will then do a search for main or
-+       below main function till the top. */
-++
-++   // FIXME JRS 28 July 2017: HACK!  Is this correct?
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+    static Int deepest_main = 0;
-+    Vg_FnNameKind kind = Vg_FnNameNormal;
-+    Int mbm = n_ips - 1; // Position of deepest main or below main.
-+@@ -972,7 +984,7 @@ Int VG_(XT_offset_main_or_below_main)(Ad
-+    for (i = n_ips - 1 - deepest_main;
-+         i < n_ips;
-+         i++) {
-+-      mbmkind = VG_(get_fnname_kind_from_IP)(ips[i]);
-++      mbmkind = VG_(get_fnname_kind_from_IP)(ep, ips[i]);
-+       if (mbmkind != Vg_FnNameNormal) {
-+          mbm = i;
-+          break;
-+@@ -983,7 +995,7 @@ Int VG_(XT_offset_main_or_below_main)(Ad
-+    for (i = mbm - 1;
-+         i >= 0 && mbmkind != Vg_FnNameMain;
-+         i--) {
-+-      kind = VG_(get_fnname_kind_from_IP)(ips[i]);
-++      kind = VG_(get_fnname_kind_from_IP)(ep, ips[i]);
-+       if (kind != Vg_FnNameNormal) {
-+          mbm = i;
-+          mbmkind = kind;
-+Index: valgrind-3.13.0/coregrind/pub_core_debuginfo.h
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/pub_core_debuginfo.h
-++++ valgrind-3.13.0/coregrind/pub_core_debuginfo.h
-+@@ -86,20 +86,21 @@ extern void VG_(di_discard_ALL_debuginfo
-+  * It should only be used in cases where the names of interest will have
-+  * particular (ie. non-mangled) forms, or the mangled form is acceptable. */
-+ extern
-+-Bool VG_(get_fnname_raw) ( Addr a, const HChar** buf );
-++Bool VG_(get_fnname_raw) ( DiEpoch ep, Addr a, const HChar** buf );
-+ 
-+ /* Like VG_(get_fnname), but without C++ demangling.  (But it does
-+  Z-demangling and below-main renaming.)
-+  iipc argument: same usage as in VG_(describe_IP) in pub_tool_debuginfo.h. */
-+ extern
-+-Bool VG_(get_fnname_no_cxx_demangle) ( Addr a, const HChar** buf,
-++Bool VG_(get_fnname_no_cxx_demangle) ( DiEpoch ep, Addr a, const HChar** buf,
-+                                        const InlIPCursor* iipc );
-+ 
-+ /* mips-linux only: find the offset of current address. This is needed for 
-+    stack unwinding for MIPS.
-+ */
-+ extern
-+-Bool VG_(get_inst_offset_in_function)( Addr a, /*OUT*/PtrdiffT* offset );
-++Bool VG_(get_inst_offset_in_function)( DiEpoch ep, Addr a,
-++                                       /*OUT*/PtrdiffT* offset );
-+ 
-+ 
-+ /* Use DWARF2/3 CFA information to do one step of stack unwinding.
-+@@ -158,6 +159,7 @@ extern Bool VG_(FPO_info_present)(void);
-+ extern Bool VG_(use_FPO_info) ( /*MOD*/Addr* ipP,
-+                                 /*MOD*/Addr* spP,
-+                                 /*MOD*/Addr* fpP,
-++                                DiEpoch ep,
-+                                 Addr min_accessible,
-+                                 Addr max_accessible );
-+ 
-+@@ -217,7 +219,7 @@ void VG_(DebugInfo_syms_getidx)  ( const
-+ /* ppc64-linux only: find the TOC pointer (R2 value) that should be in
-+    force at the entry point address of the function containing
-+    guest_code_addr.  Returns 0 if not known. */
-+-extern Addr VG_(get_tocptr) ( Addr guest_code_addr );
-++extern Addr VG_(get_tocptr) ( DiEpoch ep, Addr guest_code_addr );
-+ 
-+ /* Map a function name to its SymAVMAs.  Is done by
-+    sequential search of all symbol tables, so is very slow.  To
-+@@ -227,7 +229,8 @@ extern Addr VG_(get_tocptr) ( Addr guest
-+    platforms, a symbol is deemed to be found only if it has a nonzero
-+    TOC pointer.  */
-+ extern
-+-Bool VG_(lookup_symbol_SLOW)(const HChar* sopatt, const HChar* name,
-++Bool VG_(lookup_symbol_SLOW)(DiEpoch ep, 
-++                             const HChar* sopatt, const HChar* name,
-+                              SymAVMAs* avmas);
-+ 
-+ #endif   // __PUB_CORE_DEBUGINFO_H
-+Index: valgrind-3.13.0/coregrind/pub_core_tooliface.h
-+===================================================================
-+--- valgrind-3.13.0.orig/coregrind/pub_core_tooliface.h
-++++ valgrind-3.13.0/coregrind/pub_core_tooliface.h
-+@@ -156,7 +156,7 @@ typedef struct {
-+    void (*tool_print_stats)(void);
-+ 
-+    // VG_(needs).info_location
-+-   void (*tool_info_location)(Addr a);
-++   void (*tool_info_location)(DiEpoch ep, Addr a);
-+ 
-+    // VG_(needs).malloc_replacement
-+    void* (*tool_malloc)              (ThreadId, SizeT);
-+Index: valgrind-3.13.0/docs/xml/manual-core.xml
-+===================================================================
-+--- valgrind-3.13.0.orig/docs/xml/manual-core.xml
-++++ valgrind-3.13.0/docs/xml/manual-core.xml
-+@@ -1219,6 +1219,19 @@ that can report errors, e.g. Memcheck, b
-+     </listitem>
-+   </varlistentry>
-+ 
-++  <varlistentry id="opt.keep-debuginfo" xreflabel="--keep-debuginfo">
-++    <term>
-++      <option><![CDATA[--keep-debuginfo=<yes|no> [default: no] ]]></option>
-++    </term>
-++    <listitem>
-++      <para>When enabled, keep symbols and all other debuginfo for unloaded
-++      code. This allows stack traces for memory leaks to include file/line
-++      info for code that has been dlclose'd (or similar).  Be careful with
-++      this, since it can lead to unbounded memory use for programs which
-++      repeatedly load and unload shard objects.</para>
-++    </listitem>
-++  </varlistentry>
-++  
-+   <varlistentry id="opt.show-below-main" xreflabel="--show-below-main">
-+     <term>
-+       <option><![CDATA[--show-below-main=<yes|no> [default: no] ]]></option>
-+Index: valgrind-3.13.0/drd/drd_error.c
-+===================================================================
-+--- valgrind-3.13.0.orig/drd/drd_error.c
-++++ valgrind-3.13.0/drd/drd_error.c
-+@@ -139,12 +139,14 @@ static void first_observed(const Addr ob
-+                           "    <what>%pS</what>\n"
-+                           "    <address>0x%lx</address>\n",
-+                           DRD_(clientobj_type_name)(cl->any.type), obj);
-+-         VG_(pp_ExeContext)(cl->any.first_observed_at);
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)(cl->any.first_observed_at));
-+          print_err_detail("  </first_observed_at>\n");
-+       } else {
-+          print_err_detail("%s 0x%lx was first observed at:\n",
-+                           DRD_(clientobj_type_name)(cl->any.type), obj);
-+-         VG_(pp_ExeContext)(cl->any.first_observed_at);
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)(cl->any.first_observed_at));
-+       }
-+    }
-+ }
-+@@ -161,6 +163,7 @@ void drd_report_data_race(const Error* c
-+    const HChar* const indent = xml ? "  " : "";
-+    AddrInfo ai;
-+ 
-++   DiEpoch ep = VG_(current_DiEpoch)();
-+    XArray* /* of HChar */ descr1
-+       = VG_(newXA)( VG_(malloc), "drd.error.drdr2.1",
-+                     VG_(free), sizeof(HChar) );
-+@@ -172,7 +175,7 @@ void drd_report_data_race(const Error* c
-+    tl_assert(dri->addr);
-+    tl_assert(dri->size > 0);
-+ 
-+-   (void) VG_(get_data_description)(descr1, descr2, dri->addr);
-++   (void) VG_(get_data_description)(descr1, descr2, ep, dri->addr);
-+    /* If there's nothing in descr1/2, free them.  Why is it safe to
-+       VG_(indexXA) at zero here?  Because VG_(get_data_description)
-+       guarantees to zero terminate descr1/2 regardless of the outcome
-+@@ -202,7 +205,7 @@ void drd_report_data_race(const Error* c
-+                     what_prefix, dri->access_type == eStore ? "store" : "load",
-+                     dri->tid, dri->addr, dri->size, what_suffix);
-+ 
-+-   VG_(pp_ExeContext)(VG_(get_error_where)(err));
-++   VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(err));
-+    if (descr1 != NULL) {
-+       print_err_detail("%s%s\n", indent, (HChar*)VG_(indexXA)(descr1, 0));
-+       if (descr2 != NULL)
-+@@ -216,7 +219,7 @@ void drd_report_data_race(const Error* c
-+          print_err_detail("  <allocation_context>\n");
-+       else
-+          print_err_detail(" Allocation context:\n");
-+-      VG_(pp_ExeContext)(ai.lastchange);
-++      VG_(pp_ExeContextAndEpoch)(mk_ExeContextAndEpoch(ai.lastchange, ep));
-+       if (xml)
-+          print_err_detail("  </allocation_context>\n");
-+    } else {
-+@@ -322,7 +325,7 @@ static void drd_tool_error_pp(const Erro
-+          print_err_detail("%sThe object at address 0x%lx is not a mutex.%s\n",
-+                           what_prefix, p->mutex, what_suffix);
-+       }
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(p->mutex);
-+       break;
-+    }
-+@@ -330,7 +333,7 @@ static void drd_tool_error_pp(const Erro
-+       CondErrInfo* cdei =(CondErrInfo*)(VG_(get_error_extra)(e));
-+       print_err_detail("%s%s: cond 0x%lx%s\n", what_prefix,
-+                        VG_(get_error_string)(e), cdei->cond, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(cdei->cond);
-+       break;
-+    }
-+@@ -339,7 +342,7 @@ static void drd_tool_error_pp(const Erro
-+       print_err_detail("%s%s: cond 0x%lx, mutex 0x%lx locked by thread %u%s\n",
-+                        what_prefix, VG_(get_error_string)(e), cdi->cond,
-+                        cdi->mutex, cdi->owner, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(cdi->mutex);
-+       break;
-+    }
-+@@ -349,7 +352,7 @@ static void drd_tool_error_pp(const Erro
-+                        " has been signaled but the associated mutex 0x%lx is"
-+                        " not locked by the signalling thread.%s\n",
-+                        what_prefix, cei->cond, cei->mutex, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(cei->cond);
-+       first_observed(cei->mutex);
-+       break;
-+@@ -359,7 +362,7 @@ static void drd_tool_error_pp(const Erro
-+       print_err_detail("%s%s: condition variable 0x%lx, mutexes 0x%lx and"
-+                        " 0x%lx%s\n", what_prefix, VG_(get_error_string)(e),
-+                        cwei->cond, cwei->mutex1, cwei->mutex2, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(cwei->cond);
-+       first_observed(cwei->mutex1);
-+       first_observed(cwei->mutex2);
-+@@ -370,7 +373,7 @@ static void drd_tool_error_pp(const Erro
-+       tl_assert(sei);
-+       print_err_detail("%s%s: semaphore 0x%lx%s\n", what_prefix,
-+                        VG_(get_error_string)(e), sei->semaphore, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(sei->semaphore);
-+       break;
-+    }
-+@@ -379,13 +382,14 @@ static void drd_tool_error_pp(const Erro
-+       tl_assert(bei);
-+       print_err_detail("%s%s: barrier 0x%lx%s\n", what_prefix,
-+                        VG_(get_error_string)(e), bei->barrier, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       if (bei->other_context) {
-+          if (xml)
-+             print_err_detail("  <confl_wait_call>\n");
-+          print_err_detail("%sConflicting wait call by thread %u:%s\n",
-+                           what_prefix, bei->other_tid, what_suffix);
-+-         VG_(pp_ExeContext)(bei->other_context);
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)(bei->other_context));
-+          if (xml)
-+             print_err_detail("  </confl_wait_call>\n");
-+       }
-+@@ -397,7 +401,7 @@ static void drd_tool_error_pp(const Erro
-+       tl_assert(p);
-+       print_err_detail("%s%s: rwlock 0x%lx.%s\n", what_prefix,
-+                        VG_(get_error_string)(e), p->rwlock, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(p->rwlock);
-+       break;
-+    }
-+@@ -409,14 +413,15 @@ static void drd_tool_error_pp(const Erro
-+          print_err_detail("  <acquired_at>\n");
-+       else
-+          print_err_detail("Acquired at:\n");
-+-      VG_(pp_ExeContext)(p->acquired_at);
-++      VG_(pp_ExeContextAndEpoch)(
-++         VG_(tag_EC_with_current_epoch)(p->acquired_at));
-+       if (xml)
-+          print_err_detail("  </acquired_at>\n");
-+       print_err_detail("%sLock on %s 0x%lx was held during %u ms"
-+                        " (threshold: %u ms).%s\n", what_prefix,
-+                        VG_(get_error_string)(e), p->synchronization_object,
-+                        p->hold_time_ms, p->threshold_ms, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       first_observed(p->synchronization_object);
-+       break;
-+    }
-+@@ -424,7 +429,7 @@ static void drd_tool_error_pp(const Erro
-+       GenericErrInfo* gei = (GenericErrInfo*)(VG_(get_error_extra)(e));
-+       print_err_detail("%s%s%s\n", what_prefix, VG_(get_error_string)(e),
-+                        what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       if (gei->addr)
-+ 	 first_observed(gei->addr);
-+       break;
-+@@ -433,7 +438,7 @@ static void drd_tool_error_pp(const Erro
-+       InvalidThreadIdInfo* iti =(InvalidThreadIdInfo*)(VG_(get_error_extra)(e));
-+       print_err_detail("%s%s 0x%llx%s\n", what_prefix, VG_(get_error_string)(e),
-+                        iti->ptid, what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       break;
-+    }
-+    case UnimpHgClReq: {
-+@@ -441,7 +446,7 @@ static void drd_tool_error_pp(const Erro
-+       print_err_detail("%sThe annotation macro %s has not yet been implemented"
-+                        " in %ps%s\n", what_prefix, uicr->descr,
-+                        "<valgrind/helgrind.h>", what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       break;
-+    }
-+    case UnimpDrdClReq: {
-+@@ -449,13 +454,13 @@ static void drd_tool_error_pp(const Erro
-+       print_err_detail("%sThe annotation macro %s has not yet been implemented"
-+                        " in %ps%s\n", what_prefix, uicr->descr,
-+                        "<valgrind/drd.h>", what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       break;
-+    }
-+    default:
-+       print_err_detail("%s%s%s\n", what_prefix, VG_(get_error_string)(e),
-+                        what_suffix);
-+-      VG_(pp_ExeContext)(VG_(get_error_where)(e));
-++      VG_(pp_ExeContextAndEpoch)(VG_(get_error_where)(e));
-+       break;
-+    }
-+ }
-+Index: valgrind-3.13.0/drd/drd_thread.c
-+===================================================================
-+--- valgrind-3.13.0.orig/drd/drd_thread.c
-++++ valgrind-3.13.0/drd/drd_thread.c
-+@@ -1338,7 +1338,8 @@ static void show_call_stack(const DrdThr
-+ 
-+    if (vg_tid != VG_INVALID_THREADID) {
-+       if (callstack)
-+-         VG_(pp_ExeContext)(callstack);
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)(callstack));
-+       else
-+          VG_(get_and_pp_StackTrace)(vg_tid, VG_(clo_backtrace_size));
-+    } else {
-+Index: valgrind-3.13.0/exp-bbv/bbv_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/exp-bbv/bbv_main.c
-++++ valgrind-3.13.0/exp-bbv/bbv_main.c
-+@@ -346,6 +346,7 @@ static IRSB* bbv_instrument ( VgCallback
-+    IRDirty  *di;
-+    IRExpr   **argv, *arg1;
-+    Int      regparms,opcode_type;
-++   DiEpoch  ep = VG_(current_DiEpoch)();
-+ 
-+       /* We don't handle a host/guest word size mismatch */
-+    if (gWordTy != hWordTy) {
-+@@ -392,8 +393,8 @@ static IRSB* bbv_instrument ( VgCallback
-+       block_num++;
-+          /* get function name and entry point information */
-+       const HChar *fn_name;
-+-      VG_(get_fnname)(origAddr, &fn_name);
-+-      bbInfo->is_entry=VG_(get_fnname_if_entry)(origAddr, &fn_name);
-++      VG_(get_fnname)(ep, origAddr, &fn_name);
-++      bbInfo->is_entry=VG_(get_fnname_if_entry)(ep, origAddr, &fn_name);
-+       bbInfo->fn_name =VG_(strdup)("bbv_strings", fn_name);
-+          /* insert structure into table */
-+       VG_(OSetGen_Insert)( instr_info_table, bbInfo );
-+Index: valgrind-3.13.0/exp-dhat/dh_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/exp-dhat/dh_main.c
-++++ valgrind-3.13.0/exp-dhat/dh_main.c
-+@@ -1146,7 +1146,7 @@ static void show_APInfo ( APInfo* api )
-+              bufR, bufW,
-+              api->n_reads, api->n_writes);
-+ 
-+-   VG_(pp_ExeContext)(api->ap);
-++   VG_(pp_ExeContextAndEpoch)(VG_(tag_EC_with_current_epoch)(api->ap));
-+ 
-+    if (api->histo && api->xsize_tag == Exactly) {
-+       VG_(umsg)("\nAggregated access counts by offset:\n");
-+Index: valgrind-3.13.0/exp-sgcheck/pc_common.c
-+===================================================================
-+--- valgrind-3.13.0.orig/exp-sgcheck/pc_common.c
-++++ valgrind-3.13.0/exp-sgcheck/pc_common.c
-+@@ -322,7 +322,7 @@ void pc_pp_Error ( const Error* err )
-+          emit( "  <what>Invalid %s of size %ld</what>\n",
-+                xe->XE.SorG.sszB < 0 ? "write" : "read",
-+                Word__abs(xe->XE.SorG.sszB) );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+          emit( "  <auxwhat>Address %#lx expected vs actual:</auxwhat>\n",
-+                xe->XE.SorG.addr );
-+@@ -336,7 +336,7 @@ void pc_pp_Error ( const Error* err )
-+          emit( "Invalid %s of size %ld\n", 
-+                xe->XE.SorG.sszB < 0 ? "write" : "read",
-+                Word__abs(xe->XE.SorG.sszB) );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+          emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr );
-+          emit( " Expected: %s\n", &xe->XE.SorG.expect[0] );
-+@@ -362,7 +362,7 @@ void pc_pp_Error ( const Error* err )
-+             emit( "  <what>Invalid %s of size %ld</what>\n",
-+                   readwrite(xe->XE.Heap.sszB),
-+                   Word__abs(xe->XE.Heap.sszB) );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             emit( "  <auxwhat>Address %#lx is not derived from "
-+                   "any known block</auxwhat>\n", a );
-+@@ -372,7 +372,7 @@ void pc_pp_Error ( const Error* err )
-+             emit( "Invalid %s of size %ld\n",
-+                   readwrite(xe->XE.Heap.sszB),
-+                   Word__abs(xe->XE.Heap.sszB) );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             emit( " Address %#lx is not derived from "
-+                   "any known block\n", a );
-+@@ -397,7 +397,7 @@ void pc_pp_Error ( const Error* err )
-+                   how_invalid,
-+                   readwrite(xe->XE.Heap.sszB),
-+                   Word__abs(xe->XE.Heap.sszB) );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             emit( "  <auxwhat>Address %#lx is %lu bytes %s "
-+                      "the accessing pointer's</auxwhat>\n",
-+@@ -406,7 +406,8 @@ void pc_pp_Error ( const Error* err )
-+                      "a block of size %lu %s</auxwhat>\n",
-+                   legit, Seg__size(vseg),
-+                   Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
-+-            VG_(pp_ExeContext)(Seg__where(vseg));
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(Seg__where(vseg)));
-+ 
-+          } else {
-+ 
-+@@ -414,14 +415,15 @@ void pc_pp_Error ( const Error* err )
-+                   how_invalid,
-+                   readwrite(xe->XE.Heap.sszB),
-+                   Word__abs(xe->XE.Heap.sszB) );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             emit( " Address %#lx is %lu bytes %s the accessing pointer's\n",
-+                   a, miss_size, place );
-+             emit( " %slegitimate range, a block of size %lu %s\n",
-+                   legit, Seg__size(vseg),
-+                   Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
-+-            VG_(pp_ExeContext)(Seg__where(vseg));
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(Seg__where(vseg)));
-+ 
-+          }
-+       }
-+@@ -477,7 +479,7 @@ void pc_pp_Error ( const Error* err )
-+ 
-+          emit( "  <what>Invalid arguments to %s</what>\n",
-+                xe->XE.Arith.opname );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+          if (seg1 != seg2) {
-+             if (NONPTR == seg1) {
-+@@ -488,7 +490,8 @@ void pc_pp_Error ( const Error* err )
-+                emit( "  <auxwhat>First arg derived from address %#lx of "
-+                      "%lu-byte block alloc'd</auxwhat>\n",
-+                      Seg__addr(seg1), Seg__size(seg1) );
-+-               VG_(pp_ExeContext)(Seg__where(seg1));
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(Seg__where(seg1)));
-+             }
-+             which = "Second arg";
-+          } else {
-+@@ -500,14 +503,15 @@ void pc_pp_Error ( const Error* err )
-+             emit( "  <auxwhat>%s derived from address %#lx of "
-+                   "%lu-byte block alloc'd</auxwhat>\n",
-+                   which, Seg__addr(seg2), Seg__size(seg2) );
-+-            VG_(pp_ExeContext)(Seg__where(seg2));
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(Seg__where(seg2)));
-+          }
-+ 
-+       } else {
-+ 
-+          emit( "Invalid arguments to %s\n",
-+                xe->XE.Arith.opname );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+          if (seg1 != seg2) {
-+             if (NONPTR == seg1) {
-+@@ -518,7 +522,8 @@ void pc_pp_Error ( const Error* err )
-+                emit( " First arg derived from address %#lx of "
-+                      "%lu-byte block alloc'd\n",
-+                      Seg__addr(seg1), Seg__size(seg1) );
-+-               VG_(pp_ExeContext)(Seg__where(seg1));
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(Seg__where(seg1)));
-+             }
-+             which = "Second arg";
-+          } else {
-+@@ -530,7 +535,8 @@ void pc_pp_Error ( const Error* err )
-+             emit( " %s derived from address %#lx of "
-+                   "%lu-byte block alloc'd\n",
-+                   which, Seg__addr(seg2), Seg__size(seg2) );
-+-            VG_(pp_ExeContext)(Seg__where(seg2));
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(Seg__where(seg2)));
-+          }
-+ 
-+       }
-+@@ -562,23 +568,25 @@ void pc_pp_Error ( const Error* err )
-+ 
-+             emit( "  <what>%s%s contains unaddressable byte(s)</what>\n",
-+                   what, s );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             emit( "  <auxwhat>Address %#lx is %lu bytes inside a "
-+                   "%lu-byte block free'd</auxwhat>\n",
-+                   lo, lo-Seg__addr(seglo), Seg__size(seglo) );
-+-            VG_(pp_ExeContext)(Seg__where(seglo));
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(Seg__where(seglo)));
-+ 
-+          } else {
-+ 
-+             emit( " %s%s contains unaddressable byte(s)\n",
-+                   what, s );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             emit( " Address %#lx is %lu bytes inside a "
-+                   "%lu-byte block free'd\n",
-+                   lo, lo-Seg__addr(seglo), Seg__size(seglo) );
-+-            VG_(pp_ExeContext)(Seg__where(seglo));
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(Seg__where(seglo)));
-+ 
-+          }
-+ 
-+@@ -589,7 +597,7 @@ void pc_pp_Error ( const Error* err )
-+ 
-+             emit( "  <what>%s%s is non-contiguous</what>\n",
-+                   what, s );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             if (UNKNOWN == seglo) {
-+                emit( "  <auxwhat>First byte is "
-+@@ -598,7 +606,8 @@ void pc_pp_Error ( const Error* err )
-+                emit( "  <auxwhat>First byte (%#lx) is %lu bytes inside a "
-+                      "%lu-byte block alloc'd</auxwhat>\n",
-+                      lo, lo-Seg__addr(seglo), Seg__size(seglo) );
-+-               VG_(pp_ExeContext)(Seg__where(seglo));
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(Seg__where(seglo)));
-+             }
-+    
-+             if (UNKNOWN == seghi) {
-+@@ -608,14 +617,15 @@ void pc_pp_Error ( const Error* err )
-+                emit( "  <auxwhat>Last byte (%#lx) is %lu bytes inside a "
-+                      "%lu-byte block alloc'd</auxwhat>\n",
-+                      hi, hi-Seg__addr(seghi), Seg__size(seghi) );
-+-               VG_(pp_ExeContext)(Seg__where(seghi));
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(Seg__where(seghi)));
-+             }
-+ 
-+          } else {
-+ 
-+             emit( "%s%s is non-contiguous\n",
-+                   what, s );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+    
-+             if (UNKNOWN == seglo) {
-+                emit( " First byte is not inside a known block\n" );
-+@@ -623,7 +633,8 @@ void pc_pp_Error ( const Error* err )
-+                emit( " First byte (%#lx) is %lu bytes inside a "
-+                      "%lu-byte block alloc'd\n",
-+                      lo, lo-Seg__addr(seglo), Seg__size(seglo) );
-+-               VG_(pp_ExeContext)(Seg__where(seglo));
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(Seg__where(seglo)));
-+             }
-+    
-+             if (UNKNOWN == seghi) {
-+@@ -632,7 +643,8 @@ void pc_pp_Error ( const Error* err )
-+                emit( " Last byte (%#lx) is %lu bytes inside a "
-+                      "%lu-byte block alloc'd\n",
-+                      hi, hi-Seg__addr(seghi), Seg__size(seghi) );
-+-               VG_(pp_ExeContext)(Seg__where(seghi));
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(Seg__where(seghi)));
-+             }
-+ 
-+          }
-+@@ -650,6 +662,8 @@ void pc_pp_Error ( const Error* err )
-+ UInt pc_update_Error_extra ( const Error* err )
-+ {
-+    XError *xe = (XError*)VG_(get_error_extra)(err);
-++   DiEpoch ep = VG_(get_error_where)(err).epoch;
-++
-+    tl_assert(xe);
-+    switch (xe->tag) {
-+       case XE_SorG:
-+@@ -675,7 +689,7 @@ UInt pc_update_Error_extra ( const Error
-+          have_descr
-+             = VG_(get_data_description)( xe->XE.Heap.descr1,
-+                                          xe->XE.Heap.descr2,
-+-                                         xe->XE.Heap.addr );
-++                                         ep, xe->XE.Heap.addr );
-+ 
-+          /* If there's nothing in descr1/2, free it.  Why is it safe to
-+             to VG_(indexXA) at zero here?  Because
-+@@ -699,7 +713,7 @@ UInt pc_update_Error_extra ( const Error
-+          if (!have_descr) {
-+             const HChar *name;
-+             if (VG_(get_datasym_and_offset)(
-+-                   xe->XE.Heap.addr, &name,
-++                   ep, xe->XE.Heap.addr, &name,
-+                    &xe->XE.Heap.datasymoff )
-+                ) {
-+               xe->XE.Heap.datasym =
-+Index: valgrind-3.13.0/exp-sgcheck/sg_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/exp-sgcheck/sg_main.c
-++++ valgrind-3.13.0/exp-sgcheck/sg_main.c
-+@@ -1936,7 +1936,8 @@ void shadowStack_new_frame ( ThreadId ti
-+      const HChar *fnname;
-+      Bool ok;
-+      Addr ip = ip_post_call_insn;
-+-     ok = VG_(get_fnname_w_offset)( ip, &fnname );
-++     DiEpoch ep = VG_(current_DiEpoch)();
-++     ok = VG_(get_fnname_w_offset)( ep, ip, &fnname );
-+      while (d > 0) {
-+         VG_(printf)(" ");
-+         d--;
-+Index: valgrind-3.13.0/helgrind/hg_addrdescr.c
-+===================================================================
-+--- valgrind-3.13.0.orig/helgrind/hg_addrdescr.c
-++++ valgrind-3.13.0/helgrind/hg_addrdescr.c
-+@@ -45,7 +45,7 @@
-+ #include "hg_lock_n_thread.h"
-+ #include "hg_addrdescr.h"            /* self */
-+ 
-+-void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
-++void HG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai )
-+ {
-+    tl_assert(ai->tag == Addr_Undescribed);
-+ 
-+@@ -75,13 +75,14 @@ void HG_(describe_addr) ( Addr a, /*OUT*
-+       ai->Addr.Block.block_desc = "block";
-+       ai->Addr.Block.block_szB  = hszB;
-+       ai->Addr.Block.rwoffset   = (Word)(a) - (Word)(haddr);
-+-      ai->Addr.Block.allocated_at = hctxt;
-++      ai->Addr.Block.allocated_at.ec = hctxt;
-++      ai->Addr.Block.allocated_at.epoch = ep;
-+       VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo);
-+       ai->Addr.Block.alloc_tinfo.tnr = tnr;
-+-      ai->Addr.Block.freed_at = VG_(null_ExeContext)();;
-++      ai->Addr.Block.freed_at = VG_(null_ExeContextAndEpoch)();
-+    } else {
-+       /* No block found. Search a non-heap block description. */
-+-      VG_(describe_addr) (a, ai);
-++      VG_(describe_addr) (ep, a, ai);
-+ 
-+       /* In case ai contains a tid, set tnr to the corresponding helgrind
-+          thread number. */
-+@@ -100,14 +101,14 @@ void HG_(describe_addr) ( Addr a, /*OUT*
-+    }
-+ }
-+ 
-+-Bool HG_(get_and_pp_addrdescr) (Addr addr)
-++Bool HG_(get_and_pp_addrdescr) (DiEpoch ep, Addr addr)
-+ {
-+ 
-+    Bool ret;
-+    AddrInfo glai;
-+ 
-+    glai.tag = Addr_Undescribed;
-+-   HG_(describe_addr) (addr, &glai);
-++   HG_(describe_addr) (ep, addr, &glai);
-+    VG_(pp_addrinfo) (addr, &glai);
-+    ret = glai.tag != Addr_Unknown;
-+ 
-+Index: valgrind-3.13.0/helgrind/hg_addrdescr.h
-+===================================================================
-+--- valgrind-3.13.0.orig/helgrind/hg_addrdescr.h
-++++ valgrind-3.13.0/helgrind/hg_addrdescr.h
-+@@ -37,12 +37,12 @@
-+    lock description, putting the result in ai.
-+    This might allocate some memory in ai, to be cleared with
-+    VG_(clear_addrinfo). */
-+-extern void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai );
-++extern void HG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai );
-+ 
-+ /* Get a readable description of addr, then print it using HG_(pp_addrdescr)
-+    using xml False and VG_(printf) to emit the characters.
-+    Returns True if a description was found/printed, False otherwise. */
-+-extern Bool HG_(get_and_pp_addrdescr) (Addr a);
-++extern Bool HG_(get_and_pp_addrdescr) (DiEpoch ep, Addr a);
-+ 
-+ /* For error creation/address description:
-+    map 'data_addr' to a malloc'd chunk, if any.
-+Index: valgrind-3.13.0/helgrind/hg_errors.c
-+===================================================================
-+--- valgrind-3.13.0.orig/helgrind/hg_errors.c
-++++ valgrind-3.13.0/helgrind/hg_errors.c
-+@@ -421,7 +421,8 @@ UInt HG_(update_extra) ( const Error* er
-+          VG_(printf)("HG_(update_extra): "
-+                      "%d conflicting-event queries\n", xxx);
-+ 
-+-      HG_(describe_addr) (xe->XE.Race.data_addr, &xe->XE.Race.data_addrinfo);
-++      HG_(describe_addr) (VG_(get_error_where)(err).epoch,
-++                          xe->XE.Race.data_addr, &xe->XE.Race.data_addrinfo);
-+ 
-+       /* And poke around in the conflicting-event map, to see if we
-+          can rustle up a plausible-looking conflicting memory access
-+@@ -748,7 +749,8 @@ static Bool announce_one_thread ( Thread
-+          VG_(printf_xml)("  <isrootthread></isrootthread>\n");
-+       } else {
-+          tl_assert(thr->created_at != NULL);
-+-         VG_(pp_ExeContext)( thr->created_at );
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)( thr->created_at ) );
-+       }
-+       VG_(printf_xml)("</announcethread>\n\n");
-+ 
-+@@ -767,7 +769,8 @@ static Bool announce_one_thread ( Thread
-+          tl_assert(thr->created_at != NULL);
-+          VG_(message)(Vg_UserMsg, "Thread #%d was created\n",
-+                                   thr->errmsg_index);
-+-         VG_(pp_ExeContext)( thr->created_at );
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)( thr->created_at ) );
-+       }
-+       VG_(message)(Vg_UserMsg, "\n");
-+ 
-+@@ -789,19 +792,21 @@ static void announce_LockP ( Lock* lk )
-+       if (lk->appeared_at) {
-+          emit( "  <auxwhat>Lock at %p was first observed</auxwhat>\n",
-+                (void*)lk );
-+-         VG_(pp_ExeContext)( lk->appeared_at );
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)( lk->appeared_at ) );
-+       }
-+ 
-+    } else {
-+       if (lk->appeared_at) {
-+          VG_(umsg)( " Lock at %p was first observed\n",
-+                     (void*)lk->guestaddr );
-+-         VG_(pp_ExeContext)( lk->appeared_at );
-++         VG_(pp_ExeContextAndEpoch)(
-++            VG_(tag_EC_with_current_epoch)( lk->appeared_at ) );
-+       } else {
-+          VG_(umsg)( " Lock at %p : no stacktrace for first observation\n",
-+                     (void*)lk->guestaddr );
-+       }
-+-      HG_(get_and_pp_addrdescr) (lk->guestaddr);
-++      HG_(get_and_pp_addrdescr) (VG_(current_DiEpoch)(), lk->guestaddr);
-+       VG_(umsg)("\n");
-+    }
-+ }
-+@@ -941,11 +946,12 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "    <hthreadid>%d</hthreadid>\n",
-+                (Int)xe->XE.Misc.thr->errmsg_index );
-+          emit( "  </xwhat>\n" );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          if (xe->XE.Misc.auxstr) {
-+             emit("  <auxwhat>%s</auxwhat>\n", xe->XE.Misc.auxstr);
-+             if (xe->XE.Misc.auxctx)
-+-               VG_(pp_ExeContext)( xe->XE.Misc.auxctx );
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)( xe->XE.Misc.auxctx ));
-+          }
-+ 
-+       } else {
-+@@ -953,11 +959,12 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "Thread #%d: %s\n",
-+                (Int)xe->XE.Misc.thr->errmsg_index,
-+                xe->XE.Misc.errstr );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          if (xe->XE.Misc.auxstr) {
-+             emit(" %s\n", xe->XE.Misc.auxstr);
-+             if (xe->XE.Misc.auxctx)
-+-               VG_(pp_ExeContext)( xe->XE.Misc.auxctx );
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)( xe->XE.Misc.auxctx ));
-+          }
-+ 
-+       }
-+@@ -978,17 +985,21 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "    <hthreadid>%d</hthreadid>\n",
-+                (Int)xe->XE.LockOrder.thr->errmsg_index );
-+          emit( "  </xwhat>\n" );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          if (xe->XE.LockOrder.shouldbe_earlier_ec
-+              && xe->XE.LockOrder.shouldbe_later_ec) {
-+             emit( "  <auxwhat>Required order was established by "
-+                   "acquisition of lock at %p</auxwhat>\n",
-+                   (void*)xe->XE.LockOrder.shouldbe_earlier_lk->guestaddr );
-+-            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_earlier_ec );
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(
-++                  xe->XE.LockOrder.shouldbe_earlier_ec ));
-+             emit( "  <auxwhat>followed by a later acquisition "
-+                   "of lock at %p</auxwhat>\n",
-+                   (void*)xe->XE.LockOrder.shouldbe_later_lk->guestaddr );
-+-            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_later_ec );
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(
-++                  xe->XE.LockOrder.shouldbe_later_ec ));
-+          }
-+          announce_LockP ( xe->XE.LockOrder.shouldbe_earlier_lk );
-+          announce_LockP ( xe->XE.LockOrder.shouldbe_later_lk );
-+@@ -1004,25 +1015,31 @@ void HG_(pp_Error) ( const Error* err )
-+                "acquisition of lock at %p\n",
-+                (void*)xe->XE.LockOrder.shouldbe_later_lk->guestaddr);
-+          if (xe->XE.LockOrder.actual_earlier_ec) {
-+-             VG_(pp_ExeContext)(xe->XE.LockOrder.actual_earlier_ec);
-++             VG_(pp_ExeContextAndEpoch)(
-++                VG_(tag_EC_with_current_epoch)(
-++                   xe->XE.LockOrder.actual_earlier_ec));
-+          } else {
-+             emit("   (stack unavailable)\n");
-+          }
-+          emit( "\n" );
-+          emit(" followed by a later acquisition of lock at %p\n",
-+               (void*)xe->XE.LockOrder.shouldbe_earlier_lk->guestaddr);
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          if (xe->XE.LockOrder.shouldbe_earlier_ec
-+              && xe->XE.LockOrder.shouldbe_later_ec) {
-+             emit("\n");
-+             emit( "Required order was established by "
-+                   "acquisition of lock at %p\n",
-+                   (void*)xe->XE.LockOrder.shouldbe_earlier_lk->guestaddr );
-+-            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_earlier_ec );
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(
-++                   xe->XE.LockOrder.shouldbe_earlier_ec ));
-+             emit( "\n" );
-+             emit( " followed by a later acquisition of lock at %p\n",
-+                   (void*)xe->XE.LockOrder.shouldbe_later_lk->guestaddr );
-+-            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_later_ec );
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)(
-++                  xe->XE.LockOrder.shouldbe_later_ec ));
-+          }
-+          emit("\n");
-+          announce_LockP ( xe->XE.LockOrder.shouldbe_earlier_lk );
-+@@ -1048,7 +1065,7 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "  </xwhat>\n" );
-+          emit( "  <what>with error code %ld (%s)</what>\n",
-+                xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+ 
-+       } else {
-+ 
-+@@ -1057,7 +1074,7 @@ void HG_(pp_Error) ( const Error* err )
-+                       xe->XE.PthAPIerror.fnname );
-+          emit( "   with error code %ld (%s)\n",
-+                xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+ 
-+       }
-+ 
-+@@ -1077,14 +1094,14 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "    <hthreadid>%d</hthreadid>\n",
-+                (Int)xe->XE.UnlockBogus.thr->errmsg_index );
-+          emit( "  </xwhat>\n" );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+ 
-+       } else {
-+ 
-+          emit( "Thread #%d unlocked an invalid lock at %p\n",
-+                (Int)xe->XE.UnlockBogus.thr->errmsg_index,
-+                (void*)xe->XE.UnlockBogus.lock_ga );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+ 
-+       }
-+ 
-+@@ -1109,7 +1126,7 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "    <hthreadid>%d</hthreadid>\n",
-+                (Int)xe->XE.UnlockForeign.owner->errmsg_index );
-+          emit( "  </xwhat>\n" );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          announce_LockP ( xe->XE.UnlockForeign.lock );
-+ 
-+       } else {
-+@@ -1119,7 +1136,7 @@ void HG_(pp_Error) ( const Error* err )
-+                (Int)xe->XE.UnlockForeign.thr->errmsg_index,
-+                (void*)xe->XE.UnlockForeign.lock->guestaddr,
-+                (Int)xe->XE.UnlockForeign.owner->errmsg_index );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          announce_LockP ( xe->XE.UnlockForeign.lock );
-+ 
-+       }
-+@@ -1141,7 +1158,7 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "    <hthreadid>%d</hthreadid>\n",
-+                (Int)xe->XE.UnlockUnlocked.thr->errmsg_index );
-+          emit( "  </xwhat>\n" );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          announce_LockP ( xe->XE.UnlockUnlocked.lock);
-+ 
-+       } else {
-+@@ -1149,7 +1166,7 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "Thread #%d unlocked a not-locked lock at %p\n",
-+                (Int)xe->XE.UnlockUnlocked.thr->errmsg_index,
-+                (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          announce_LockP ( xe->XE.UnlockUnlocked.lock);
-+ 
-+       }
-+@@ -1179,7 +1196,7 @@ void HG_(pp_Error) ( const Error* err )
-+          emit( "    <hthreadid>%d</hthreadid>\n",
-+                (Int)xe->XE.Race.thr->errmsg_index );
-+          emit( "  </xwhat>\n" );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+ 
-+          if (xe->XE.Race.h2_ct) {
-+             tl_assert(xe->XE.Race.h2_ct_accEC); // assured by update_extra
-+@@ -1192,7 +1209,8 @@ void HG_(pp_Error) ( const Error* err )
-+             emit( "    <hthreadid>%d</hthreadid>\n", 
-+                   xe->XE.Race.h2_ct->errmsg_index);
-+             emit("  </xauxwhat>\n");
-+-            VG_(pp_ExeContext)( xe->XE.Race.h2_ct_accEC );
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)( xe->XE.Race.h2_ct_accEC ));
-+          }
-+ 
-+          if (xe->XE.Race.h1_ct) {
-+@@ -1204,13 +1222,17 @@ void HG_(pp_Error) ( const Error* err )
-+                   xe->XE.Race.h1_ct->errmsg_index );
-+             emit("  </xauxwhat>\n");
-+             if (xe->XE.Race.h1_ct_mbsegstartEC) {
-+-               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegstartEC );
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(
-++                     xe->XE.Race.h1_ct_mbsegstartEC ));
-+             } else {
-+                emit( "  <auxwhat>(the start of the thread)</auxwhat>\n" );
-+             }
-+             emit( "  <auxwhat>but before</auxwhat>\n" );
-+             if (xe->XE.Race.h1_ct_mbsegendEC) {
-+-               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegendEC );
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(
-++                     xe->XE.Race.h1_ct_mbsegendEC ));
-+             } else {
-+                emit( "  <auxwhat>(the end of the thread)</auxwhat>\n" );
-+             }
-+@@ -1228,7 +1250,7 @@ void HG_(pp_Error) ( const Error* err )
-+ 
-+          tl_assert(xe->XE.Race.locksHeldW);
-+          show_LockP_summary_textmode( xe->XE.Race.locksHeldW, "" );
-+-         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++         VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+ 
-+          if (xe->XE.Race.h2_ct) {
-+             tl_assert(xe->XE.Race.h2_ct_accEC); // assured by update_extra
-+@@ -1240,7 +1262,8 @@ void HG_(pp_Error) ( const Error* err )
-+                   xe->XE.Race.h2_ct_accSzB,
-+                   xe->XE.Race.h2_ct->errmsg_index );
-+             show_LockP_summary_textmode( xe->XE.Race.h2_ct_locksHeldW, "" );
-+-            VG_(pp_ExeContext)( xe->XE.Race.h2_ct_accEC );
-++            VG_(pp_ExeContextAndEpoch)(
-++               VG_(tag_EC_with_current_epoch)( xe->XE.Race.h2_ct_accEC ));
-+          }
-+ 
-+          if (xe->XE.Race.h1_ct) {
-+@@ -1248,13 +1271,17 @@ void HG_(pp_Error) ( const Error* err )
-+                   "after\n",
-+                   xe->XE.Race.h1_ct->errmsg_index );
-+             if (xe->XE.Race.h1_ct_mbsegstartEC) {
-+-               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegstartEC );
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(
-++                     xe->XE.Race.h1_ct_mbsegstartEC ));
-+             } else {
-+                emit( "   (the start of the thread)\n" );
-+             }
-+             emit( " but before\n" );
-+             if (xe->XE.Race.h1_ct_mbsegendEC) {
-+-               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegendEC );
-++               VG_(pp_ExeContextAndEpoch)(
-++                  VG_(tag_EC_with_current_epoch)(
-++                     xe->XE.Race.h1_ct_mbsegendEC ));
-+             } else {
-+                emit( "   (the end of the thread)\n" );
-+             }
-+@@ -1307,7 +1334,7 @@ void HG_(print_access) (StackTrace ips,
-+       show_LockP_summary_textmode( locksHeldW_P, "" );
-+       HG_(free) (locksHeldW_P);
-+    }
-+-   VG_(pp_StackTrace) (ips, n_ips);
-++   VG_(pp_StackTrace)( VG_(current_DiEpoch)(), ips, n_ips );
-+    VG_(printf) ("\n");
-+ }
-+ 
-+Index: valgrind-3.13.0/helgrind/hg_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/helgrind/hg_main.c
-++++ valgrind-3.13.0/helgrind/hg_main.c
-+@@ -483,13 +483,14 @@ static void pp_Lock ( Int d, Lock* lk,
-+                       Bool show_lock_addrdescr,
-+                       Bool show_internal_data)
-+ {
-++   DiEpoch ep = VG_(current_DiEpoch)();
-+    space(d+0); 
-+    if (show_internal_data)
-+       VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr);
-+    else
-+       VG_(printf)("Lock ga %#lx {\n", lk->guestaddr);
-+    if (!show_lock_addrdescr 
-+-       || !HG_(get_and_pp_addrdescr) ((Addr) lk->guestaddr))
-++       || !HG_(get_and_pp_addrdescr) (ep, (Addr) lk->guestaddr))
-+       VG_(printf)("\n");
-+       
-+    if (sHOW_ADMIN) {
-+@@ -4598,7 +4599,7 @@ static Bool is_in_dynamic_linker_shared_
-+    DebugInfo* dinfo;
-+    const HChar* soname;
-+ 
-+-   dinfo = VG_(find_DebugInfo)( ga );
-++   dinfo = VG_(find_DebugInfo)( VG_(current_DiEpoch)(), ga );
-+    if (!dinfo) return False;
-+ 
-+    soname = VG_(DebugInfo_get_soname)(dinfo);
-+@@ -5817,9 +5818,9 @@ static void hg_post_clo_init ( void )
-+       VG_(XTMemory_Full_init)(VG_(XT_filter_1top_and_maybe_below_main));
-+ }
-+ 
-+-static void hg_info_location (Addr a)
-++static void hg_info_location (DiEpoch ep, Addr a)
-+ {
-+-   (void) HG_(get_and_pp_addrdescr) (a);
-++   (void) HG_(get_and_pp_addrdescr) (ep, a);
-+ }
-+ 
-+ static void hg_pre_clo_init ( void )
-+Index: valgrind-3.13.0/helgrind/libhb_core.c
-+===================================================================
-+--- valgrind-3.13.0.orig/helgrind/libhb_core.c
-++++ valgrind-3.13.0/helgrind/libhb_core.c
-+@@ -4095,7 +4095,7 @@ static void note_local_Kw_n_stack_for (
-+       VG_(printf)("LOCAL Kw: thr %p,  Kw %llu,  ec %p\n",
-+                   thr, pair.ull, pair.ec );
-+    if (0)
-+-      VG_(pp_ExeContext)(pair.ec);
-++      VG_(pp_ExeContextAndEpoch)(VG_(tag_EC_with_current_epoch)(pair.ec));
-+ }
-+ 
-+ static Int cmp__ULong_n_EC__by_ULong ( const ULong_n_EC* pair1,
-+Index: valgrind-3.13.0/include/pub_tool_addrinfo.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_addrinfo.h
-++++ valgrind-3.13.0/include/pub_tool_addrinfo.h
-+@@ -135,6 +135,7 @@ struct _AddrInfo {
-+       // (spoffset will be negative, as stacks are assumed growing down).
-+       struct {
-+          ThreadInfo tinfo;
-++         DiEpoch  epoch;
-+          Addr     IP;
-+          Int      frameNo;
-+          StackPos stackPos;
-+@@ -151,9 +152,9 @@ struct _AddrInfo {
-+          const HChar* block_desc;   // "block","mempool","user-defined",arena
-+          SizeT       block_szB;
-+          PtrdiffT    rwoffset;
-+-         ExeContext* allocated_at;  // might be null_ExeContext.
-+-         ThreadInfo  alloc_tinfo;   // which thread did alloc this block.
-+-         ExeContext* freed_at;      // might be null_ExeContext.
-++         ExeContextAndEpoch allocated_at; // might contain null_ExeContext.
-++         ThreadInfo         alloc_tinfo;  // which thread alloc'd this block.
-++         ExeContextAndEpoch freed_at;     // might contain null_ExeContext.
-+       } Block;
-+ 
-+       // In a global .data symbol.  This holds
-+@@ -204,7 +205,7 @@ struct _AddrInfo {
-+    On entry, ai->tag must be equal to Addr_Undescribed.
-+    This might allocate some memory, that can be cleared with
-+    VG_(clear_addrinfo). */
-+-extern void VG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai );
-++extern void VG_(describe_addr) ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai );
-+ 
-+ extern void VG_(clear_addrinfo) ( AddrInfo* ai);
-+ 
-+Index: valgrind-3.13.0/include/pub_tool_basics.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_basics.h
-++++ valgrind-3.13.0/include/pub_tool_basics.h
-+@@ -129,6 +129,24 @@ typedef  struct { UWord uw1; UWord uw2;
-+ /* ThreadIds are simply indices into the VG_(threads)[] array. */
-+ typedef UInt ThreadId;
-+ 
-++
-++/* You need a debuginfo epoch in order to convert an address into any source
-++   level entity, since that conversion depends on what objects were mapped
-++   in at the time.  An epoch is simply a monotonically increasing counter,
-++   which we wrap up in a struct so as to enable the C type system to
-++   distinguish it from other kinds of numbers.  m_debuginfo holds and
-++   maintains the current epoch number. */
-++typedef  struct { UInt n; }  DiEpoch;
-++
-++static inline DiEpoch DiEpoch_INVALID ( void ) {
-++   DiEpoch dep; dep.n = 0; return dep;
-++}
-++
-++static inline Bool is_DiEpoch_INVALID ( DiEpoch dep ) {
-++   return dep.n == 0;
-++}
-++
-++
-+ /* Many data structures need to allocate and release memory.
-+    The allocation/release functions must be provided by the caller.
-+    The Alloc_Fn_t function must allocate a chunk of memory of size szB.
-+Index: valgrind-3.13.0/include/pub_tool_debuginfo.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_debuginfo.h
-++++ valgrind-3.13.0/include/pub_tool_debuginfo.h
-+@@ -31,11 +31,20 @@
-+ #ifndef __PUB_TOOL_DEBUGINFO_H
-+ #define __PUB_TOOL_DEBUGINFO_H
-+ 
-+-#include "pub_tool_basics.h"   // VG_ macro
-++#include "pub_tool_basics.h"   // VG_ macro, DiEpoch
-+ #include "pub_tool_xarray.h"   // XArray
-+ 
-++
-+ /*====================================================================*/
-+-/*=== Obtaining debug information                                  ===*/
-++/*=== Debuginfo epochs.                                            ===*/
-++/*====================================================================*/
-++
-++// This returns the current epoch.
-++DiEpoch VG_(current_DiEpoch)(void);
-++
-++
-++/*====================================================================*/
-++/*=== Obtaining information pertaining to source artefacts.        ===*/
-+ /*====================================================================*/
-+ 
-+ /* IMPORTANT COMMENT about memory persistence and ownership.
-+@@ -76,11 +85,11 @@
-+    demangles C++ function names.  VG_(get_fnname_w_offset) is the
-+    same, except it appends "+N" to symbol names to indicate offsets.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership. */
-+-extern Bool VG_(get_filename) ( Addr a, const HChar** filename );
-+-extern Bool VG_(get_fnname)   ( Addr a, const HChar** fnname );
-+-extern Bool VG_(get_linenum)  ( Addr a, UInt* linenum );
-++extern Bool VG_(get_filename) ( DiEpoch ep, Addr a, const HChar** filename );
-++extern Bool VG_(get_fnname)   ( DiEpoch ep, Addr a, const HChar** fnname );
-++extern Bool VG_(get_linenum)  ( DiEpoch ep, Addr a, UInt* linenum );
-+ extern Bool VG_(get_fnname_w_offset)
-+-                              ( Addr a, const HChar** fnname );
-++                              ( DiEpoch ep, Addr a, const HChar** fnname );
-+ 
-+ /* This one is the most general.  It gives filename, line number and
-+    optionally directory name.  filename and linenum may not be NULL.
-+@@ -95,7 +104,7 @@ extern Bool VG_(get_fnname_w_offset)
-+    Returned value indicates whether any filename/line info could be
-+    found. */
-+ extern Bool VG_(get_filename_linenum)
-+-                              ( Addr a, 
-++                              ( DiEpoch ep, Addr a, 
-+                                 /*OUT*/const HChar** filename,
-+                                 /*OUT*/const HChar** dirname,
-+                                 /*OUT*/UInt* linenum );
-+@@ -108,7 +117,8 @@ extern Bool VG_(get_filename_linenum)
-+    of its symbols, this function will not be able to recognise function
-+    entry points within it.
-+    NOTE: See IMPORTANT COMMENT above about persistence and ownership. */
-+-extern Bool VG_(get_fnname_if_entry) ( Addr a, const HChar** fnname );
-++extern Bool VG_(get_fnname_if_entry) ( DiEpoch ep, Addr a,
-++                                       const HChar** fnname );
-+ 
-+ typedef
-+    enum {
-+@@ -121,13 +131,13 @@ typedef
-+ extern Vg_FnNameKind VG_(get_fnname_kind) ( const HChar* name );
-+ 
-+ /* Like VG_(get_fnname_kind), but takes a code address. */
-+-extern Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( Addr ip );
-++extern Vg_FnNameKind VG_(get_fnname_kind_from_IP) ( DiEpoch ep, Addr ip );
-+ 
-+ /* Looks up data_addr in the collection of data symbols, and if found
-+    puts its name (or as much as will fit) into dname[0 .. n_dname-1],
-+    which is guaranteed to be zero terminated.  Also data_addr's offset
-+    from the symbol start is put into *offset. */
-+-extern Bool VG_(get_datasym_and_offset)( Addr data_addr,
-++extern Bool VG_(get_datasym_and_offset)( DiEpoch ep, Addr data_addr,
-+                                          /*OUT*/const HChar** dname,
-+                                          /*OUT*/PtrdiffT* offset );
-+ 
-+@@ -147,14 +157,14 @@ extern Bool VG_(get_datasym_and_offset)(
-+ Bool VG_(get_data_description)( 
-+         /*MOD*/ XArray* /* of HChar */ dname1v,
-+         /*MOD*/ XArray* /* of HChar */ dname2v,
-+-        Addr data_addr
-++        DiEpoch ep, Addr data_addr
-+      );
-+ 
-+ /* Succeeds if the address is within a shared object or the main executable.
-+    It first searches if Addr a belongs to the text segment of debug info.
-+    If not found, it asks the address space manager whether it
-+    knows the name of the file associated with this mapping. */
-+-extern Bool VG_(get_objname)  ( Addr a, const HChar** objname );
-++extern Bool VG_(get_objname) ( DiEpoch ep, Addr a, const HChar** objname );
-+ 
-+ 
-+ /* Cursor allowing to describe inlined function calls at an IP,
-+@@ -169,7 +179,7 @@ typedef  struct _InlIPCursor InlIPCursor
-+    eip can possibly corresponds to inlined function call(s).
-+    To describe eip and the inlined function calls, the following must
-+    be done:
-+-       InlIPCursor *iipc = VG_(new_IIPC)(eip);
-++       InlIPCursor *iipc = VG_(new_IIPC)(ep, eip);
-+        do {
-+           buf = VG_(describe_IP)(eip, iipc);
-+           ... use buf ...
-+@@ -182,12 +192,16 @@ typedef  struct _InlIPCursor InlIPCursor
-+    Note, that the returned string is allocated in a static buffer local to
-+    VG_(describe_IP). That buffer will be overwritten with every invocation.
-+    Therefore, callers need to possibly stash away the string.
-++
-++   Since this maps a code location to a source artefact (function names),
-++   new_IIPC requires a DiEpoch argument (ep) too.
-+ */
-+-extern const HChar* VG_(describe_IP)(Addr eip, const InlIPCursor* iipc);
-++extern const HChar* VG_(describe_IP)(DiEpoch ep, Addr eip,
-++                                     const InlIPCursor* iipc);
-+ 
-+ /* Builds a IIPC (Inlined IP Cursor) to describe eip and all the inlined calls
-+    at eip. Such a cursor must be deleted after use using VG_(delete_IIPC). */
-+-extern InlIPCursor* VG_(new_IIPC)(Addr eip);
-++extern InlIPCursor* VG_(new_IIPC)(DiEpoch ep, Addr eip);
-+ /* Move the cursor to the next call to describe.
-+    Returns True if there are still calls to describe.
-+    False if nothing to describe anymore. */
-+@@ -239,7 +253,7 @@ VG_(di_get_global_blocks_from_dihandle)
-+ 
-+ 
-+ /*====================================================================*/
-+-/*=== Obtaining debug information                                  ===*/
-++/*=== Obtaining information pertaining to shared objects.          ===*/
-+ /*====================================================================*/
-+ 
-+ /* A way to make limited debuginfo queries on a per-mapped-object
-+@@ -248,7 +262,7 @@ typedef  struct _DebugInfo  DebugInfo;
-+ 
-+ /* Returns NULL if the DebugInfo isn't found.  It doesn't matter if
-+    debug info is present or not. */
-+-DebugInfo* VG_(find_DebugInfo) ( Addr a );
-++DebugInfo* VG_(find_DebugInfo) ( DiEpoch ep, Addr a );
-+ 
-+ /* Fish bits out of DebugInfos. */
-+ Addr          VG_(DebugInfo_get_text_avma)   ( const DebugInfo *di );
-+Index: valgrind-3.13.0/include/pub_tool_errormgr.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_errormgr.h
-++++ valgrind-3.13.0/include/pub_tool_errormgr.h
-+@@ -56,11 +56,11 @@ typedef
-+ 
-+ /* Useful in VG_(tdict).tool_error_matches_suppression(),
-+  * VG_(tdict).tool_pp_Error(), etc */
-+-ExeContext*  VG_(get_error_where)   ( const Error* err );
-+-ErrorKind    VG_(get_error_kind)    ( const Error* err );
-+-Addr         VG_(get_error_address) ( const Error* err );
-+-const HChar* VG_(get_error_string)  ( const Error* err );
-+-void*        VG_(get_error_extra)   ( const Error* err );
-++ExeContextAndEpoch  VG_(get_error_where)   ( const Error* err );
-++ErrorKind           VG_(get_error_kind)    ( const Error* err );
-++Addr                VG_(get_error_address) ( const Error* err );
-++const HChar*        VG_(get_error_string)  ( const Error* err );
-++void*               VG_(get_error_extra)   ( const Error* err );
-+ 
-+ /* Call this when an error occurs.  It will be recorded if it hasn't been
-+    seen before.  If it has, the existing error record will have its count
-+@@ -90,7 +90,7 @@ extern void VG_(maybe_record_error) ( Th
-+    whether to add the error in the error total count (another mild hack). */
-+ extern Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind,
-+                                 Addr a, const HChar* s, void* extra,
-+-                                ExeContext* where, Bool print_error,
-++                                ExeContextAndEpoch where, Bool print_error,
-+                                 Bool allow_GDB_attach, Bool count_error );
-+ 
-+ /* Gets from fd (an opened suppression file) a non-blank, non-comment
-+Index: valgrind-3.13.0/include/pub_tool_execontext.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_execontext.h
-++++ valgrind-3.13.0/include/pub_tool_execontext.h
-+@@ -30,7 +30,13 @@
-+ #ifndef __PUB_TOOL_EXECONTEXT_H
-+ #define __PUB_TOOL_EXECONTEXT_H
-+ 
-+-#include "pub_tool_basics.h"   // ThreadID
-++#include "pub_tool_basics.h"     // ThreadID
-++#include "pub_tool_debuginfo.h"  // DiEpoch
-++
-++
-++/*====================================================================*/
-++/*=== ExeContext                                                   ===*/
-++/*====================================================================*/
-+ 
-+ // It's an abstract type.
-+ typedef
-+@@ -84,9 +90,6 @@ extern void VG_(apply_ExeContext)( void(
-+ extern Bool VG_(eq_ExeContext) ( VgRes res, const ExeContext* e1,
-+                                  const ExeContext* e2 );
-+ 
-+-// Print an ExeContext.
-+-extern void VG_(pp_ExeContext) ( ExeContext* ec );
-+-
-+ // Get the 32-bit unique reference number for this ExeContext
-+ // (the "ExeContext Unique").  Guaranteed to be nonzero and to be a
-+ // multiple of four (iow, the lowest two bits are guaranteed to
-+@@ -113,10 +116,52 @@ static inline Bool VG_(is_plausible_ECU)
-+ // Make an ExeContext containing exactly the specified stack frames.
-+ ExeContext* VG_(make_ExeContext_from_StackTrace)( const Addr* ips, UInt n_ips );
-+ 
-+-// Returns the "null" exe context. The null execontext is an artificial
-+-// exe context, with a stack trace made of one Addr (the NULL address).
-+-extern 
-+-ExeContext* VG_(null_ExeContext) (void);
-++
-++/*====================================================================*/
-++/*=== ExeContextAndEpoch                                           ===*/
-++/*====================================================================*/
-++
-++/* A plain ExeContext is not generally symbolisable, since we also need to
-++   know which DebugInfo epoch it pertains to.  ExeContextAndEpoch pairs them
-++   up.  Note this is just two words, so passing it around by value is
-++   fine. */
-++typedef
-++   struct {
-++      ExeContext* ec;
-++      DiEpoch     epoch;
-++   }
-++   ExeContextAndEpoch;
-++
-++// A trivial constructor.
-++static inline ExeContextAndEpoch mk_ExeContextAndEpoch ( ExeContext* ec,
-++                                                         DiEpoch ep ) {
-++   ExeContextAndEpoch ece;
-++   ece.ec    = ec;
-++   ece.epoch = ep;
-++   return ece;
-++}
-++
-++// Generates a completely invalid ExeContextAndEpoch, with NULL for .ec and
-++// zero for .epoch.  Both values are invalid.
-++ExeContextAndEpoch VG_(invalid_ExeContextAndEpoch) ( void );
-++
-++// Takes an ExeContext and tags it with the current epoch, which is
-++// generally what we want to do.
-++ExeContextAndEpoch VG_(tag_EC_with_current_epoch)( ExeContext* ec );
-++
-++// Print an ExeContextAndEpoch.  We can't print a plain ExeContext
-++// because we can't symbolising it without knowing which debuginfo
-++// epoch it pertains to.
-++void VG_(pp_ExeContextAndEpoch) ( ExeContextAndEpoch ece );
-++
-++// Returns the "null" exe context tagged with the current debuginfo
-++// epoch. The null execontext is an artificial exe context, with a stack
-++// trace made of one Addr (the NULL address), and the current epoch.
-++ExeContextAndEpoch VG_(null_ExeContextAndEpoch) ( void );
-++
-++// Is this a value obtained from VG_(null_ExeContextAndEpoch) ?
-++Bool VG_(is_null_ExeContextAndEpoch)( ExeContextAndEpoch ece );
-++
-+ 
-+ #endif   // __PUB_TOOL_EXECONTEXT_H
-+ 
-+Index: valgrind-3.13.0/include/pub_tool_options.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_options.h
-++++ valgrind-3.13.0/include/pub_tool_options.h
-+@@ -249,6 +249,12 @@ extern Int   VG_(clo_backtrace_size);
-+ /* Continue stack traces below main()?  Default: NO */
-+ extern Bool VG_(clo_show_below_main);
-+ 
-++/* Keep symbols (and all other debuginfo) for code that is unloaded (dlclose
-++   or similar) so that stack traces can still give line/file info for
-++   previously captured stack traces.  e.g. ... showing where a block was
-++   allocated e.g. leaks of or accesses just outside a block. */
-++extern Bool VG_(clo_keep_debuginfo);
-++
-+ 
-+ /* Used to expand file names.  "option_name" is the option name, eg.
-+    "--log-file".  'format' is what follows, eg. "cachegrind.out.%p".  In
-+Index: valgrind-3.13.0/include/pub_tool_stacktrace.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_stacktrace.h
-++++ valgrind-3.13.0/include/pub_tool_stacktrace.h
-+@@ -31,7 +31,7 @@
-+ #ifndef __PUB_TOOL_STACKTRACE_H
-+ #define __PUB_TOOL_STACKTRACE_H
-+ 
-+-#include "pub_tool_basics.h"   // Addr
-++#include "pub_tool_basics.h"   // Addr, DiEpoch
-+ 
-+ // The basic stack trace type:  just an array of code addresses.
-+ typedef Addr* StackTrace;
-+@@ -64,19 +64,19 @@ extern UInt VG_(get_StackTrace) ( Thread
-+                                   /*OUT*/StackTrace fps,
-+                                   Word first_ip_delta );
-+ 
-+-// Apply a function to every element in the StackTrace.  The parameter
-+-// 'n' gives the index of the passed ip.  'opaque' is an arbitrary
-+-// pointer provided to each invocation of 'action' (a poor man's
-+-// closure).  Doesn't go below main() unless --show-below-main=yes is
-+-// set.
-++// Apply a function to every element in the StackTrace.  The parameter 'n'
-++// gives the index of the passed ip.  'opaque' is an arbitrary pointer
-++// provided to each invocation of 'action' (a poor man's closure).  'ep' is
-++// the debuginfo epoch assumed to apply to all code addresses in the stack
-++// trace.  Doesn't go below main() unless --show-below-main=yes is set.
-+ extern void VG_(apply_StackTrace)(
-+-               void(*action)(UInt n, Addr ip, void* opaque),
-++               void(*action)(UInt n, DiEpoch ep, Addr ip, void* opaque),
-+                void* opaque,
-+-               StackTrace ips, UInt n_ips
-++               DiEpoch ep, StackTrace ips, UInt n_ips
-+             );
-+ 
-+ // Print a StackTrace.
-+-extern void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips );
-++extern void VG_(pp_StackTrace) ( DiEpoch ep, StackTrace ips, UInt n_ips );
-+ 
-+ // Gets and immediately prints a StackTrace.  Just a bit simpler than
-+ // calling VG_(get_StackTrace)() then VG_(pp_StackTrace)().
-+Index: valgrind-3.13.0/include/pub_tool_tooliface.h
-+===================================================================
-+--- valgrind-3.13.0.orig/include/pub_tool_tooliface.h
-++++ valgrind-3.13.0/include/pub_tool_tooliface.h
-+@@ -463,7 +463,7 @@ extern void VG_(needs_print_stats) (
-+    of an address ? */
-+ extern void VG_(needs_info_location) (
-+    // Get and pp information about Addr
-+-   void (*info_location)(Addr)
-++   void (*info_location)(DiEpoch, Addr)
-+ );
-+ 
-+ /* Do we need to see variable type and location information? */
-+Index: valgrind-3.13.0/lackey/lk_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/lackey/lk_main.c
-++++ valgrind-3.13.0/lackey/lk_main.c
-+@@ -664,6 +664,7 @@ IRSB* lk_instrument ( VgCallbackClosure*
-+    Addr       iaddr = 0, dst;
-+    UInt       ilen = 0;
-+    Bool       condition_inverted = False;
-++   DiEpoch    ep = VG_(current_DiEpoch)();
-+ 
-+    if (gWordTy != hWordTy) {
-+       /* We don't currently support this case. */
-+@@ -750,7 +751,7 @@ IRSB* lk_instrument ( VgCallbackClosure*
-+                tl_assert(clo_fnname);
-+                tl_assert(clo_fnname[0]);
-+                const HChar *fnname;
-+-               if (VG_(get_fnname_if_entry)(st->Ist.IMark.addr, 
-++               if (VG_(get_fnname_if_entry)(ep, st->Ist.IMark.addr, 
-+                                             &fnname)
-+                    && 0 == VG_(strcmp)(fnname, clo_fnname)) {
-+                   di = unsafeIRDirty_0_N( 
-+Index: valgrind-3.13.0/massif/ms_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/massif/ms_main.c
-++++ valgrind-3.13.0/massif/ms_main.c
-+@@ -520,8 +520,9 @@ void filter_IPs (Addr* ips, Int n_ips,
-+    //  alloc function 'inside' a stacktrace e.g.
-+    //    0x1 0x2 0x3 alloc func1 main
-+    //  becomes   0x1 0x2 0x3 func1 main
-++   DiEpoch ep = VG_(current_DiEpoch)();
-+    for (i = *top; i < n_ips; i++) {
-+-      top_has_fnname = VG_(get_fnname)(ips[*top], &fnname);
-++      top_has_fnname = VG_(get_fnname)(ep, ips[*top], &fnname);
-+       if (top_has_fnname &&  VG_(strIsMemberXA)(alloc_fns, fnname)) {
-+          VERB(4, "filtering alloc fn %s\n", fnname);
-+          (*top)++;
-+@@ -576,7 +577,8 @@ static ExeContext* make_ec(ThreadId tid,
-+    if (exclude_first_entry && n_ips > 0) {
-+       const HChar *fnname;
-+       VERB(4, "removing top fn %s from stacktrace\n", 
-+-           VG_(get_fnname)(ips[0], &fnname) ? fnname : "???");
-++              VG_(get_fnname)(VG_(current_DiEpoch)(), ips[0], &fnname)
-++                 ? fnname : "???");
-+       return VG_(make_ExeContext_from_StackTrace)(ips+1, n_ips-1);
-+    } else
-+       return VG_(make_ExeContext_from_StackTrace)(ips, n_ips);
-+Index: valgrind-3.13.0/memcheck/mc_errors.c
-+===================================================================
-+--- valgrind-3.13.0.orig/memcheck/mc_errors.c
-++++ valgrind-3.13.0/memcheck/mc_errors.c
-+@@ -94,15 +94,15 @@ struct _MC_Error {
-+       struct {
-+          SizeT szB;   // size of value in bytes
-+          // Origin info
-+-         UInt        otag;      // origin tag
-+-         ExeContext* origin_ec; // filled in later
-++         UInt               otag;       // origin tag
-++         ExeContextAndEpoch origin_ece; // filled in later
-+       } Value;
-+ 
-+       // Use of an undefined value in a conditional branch or move.
-+       struct {
-+          // Origin info
-+-         UInt        otag;      // origin tag
-+-         ExeContext* origin_ec; // filled in later
-++         UInt               otag;       // origin tag
-++         ExeContextAndEpoch origin_ece; // filled in later
-+       } Cond;
-+ 
-+       // Addressability error in core (signal-handling) operation.
-+@@ -127,8 +127,8 @@ struct _MC_Error {
-+       // System call register input contains undefined bytes.
-+       struct {
-+          // Origin info
-+-         UInt        otag;      // origin tag
-+-         ExeContext* origin_ec; // filled in later
-++         UInt               otag;       // origin tag
-++         ExeContextAndEpoch origin_ece; // filled in later
-+       } RegParam;
-+ 
-+       // System call memory input contains undefined/unaddressable bytes
-+@@ -136,8 +136,8 @@ struct _MC_Error {
-+          Bool     isAddrErr;  // Addressability or definedness error?
-+          AddrInfo ai;
-+          // Origin info
-+-         UInt        otag;      // origin tag
-+-         ExeContext* origin_ec; // filled in later
-++         UInt               otag;       // origin tag
-++         ExeContextAndEpoch origin_ece; // filled in later
-+       } MemParam;
-+ 
-+       // Problem found from a client request like CHECK_MEM_IS_ADDRESSABLE.
-+@@ -145,8 +145,8 @@ struct _MC_Error {
-+          Bool     isAddrErr;  // Addressability or definedness error?
-+          AddrInfo ai;
-+          // Origin info
-+-         UInt        otag;      // origin tag
-+-         ExeContext* origin_ec; // filled in later
-++         UInt               otag;       // origin tag
-++         ExeContextAndEpoch origin_ece; // filled in later
-+       } User;
-+ 
-+       // Program tried to free() something that's not a heap block (this
-+@@ -279,10 +279,10 @@ static const HChar* pp_Reachedness_for_l
-+    }
-+ }
-+ 
-+-static void mc_pp_origin ( ExeContext* ec, UInt okind )
-++static void mc_pp_origin ( ExeContextAndEpoch ece, UInt okind )
-+ {
-+    const HChar* src = NULL;
-+-   tl_assert(ec);
-++   tl_assert(ece.ec);
-+ 
-+    switch (okind) {
-+       case MC_OKIND_STACK:   src = " by a stack allocation"; break;
-+@@ -295,10 +295,10 @@ static void mc_pp_origin ( ExeContext* e
-+    if (VG_(clo_xml)) {
-+       emit( "  <auxwhat>Uninitialised value was created%s</auxwhat>\n",
-+             src);
-+-      VG_(pp_ExeContext)( ec );
-++      VG_(pp_ExeContextAndEpoch)( ece );
-+    } else {
-+       emit( " Uninitialised value was created%s\n", src);
-+-      VG_(pp_ExeContext)( ec );
-++      VG_(pp_ExeContextAndEpoch)( ece );
-+    }
-+ }
-+ 
-+@@ -379,7 +379,7 @@ static void pp_LossRecord(UInt n_this_re
-+          emit( "    <leakedblocks>%u</leakedblocks>\n", lr->num_blocks);
-+          emit( "  </xwhat>\n" );
-+       }
-+-      VG_(pp_ExeContext)(lr->key.allocated_at);
-++      VG_(pp_ExeContextAndEpoch)(lr->key.allocated_at);
-+    } else { /* ! if (xml) */
-+       if (lr->indirect_szB > 0) {
-+          emit(
-+@@ -401,7 +401,7 @@ static void pp_LossRecord(UInt n_this_re
-+             n_this_record, n_total_records
-+          );
-+       }
-+-      VG_(pp_ExeContext)(lr->key.allocated_at);
-++      VG_(pp_ExeContextAndEpoch)(lr->key.allocated_at);
-+    } /* if (xml) */
-+ }
-+ 
-+@@ -427,11 +427,11 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "  <kind>CoreMemError</kind>\n" );
-+             emit( "  <what>%pS contains unaddressable byte(s)</what>\n",
-+                   VG_(get_error_string)(err));
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          } else {
-+             emit( "%s contains unaddressable byte(s)\n",
-+                   VG_(get_error_string)(err));
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          }
-+          break;
-+       
-+@@ -441,19 +441,19 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "  <kind>UninitValue</kind>\n" );
-+             emit( "  <what>Use of uninitialised value of size %lu</what>\n",
-+                   extra->Err.Value.szB );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-+-            if (extra->Err.Value.origin_ec)
-+-               mc_pp_origin( extra->Err.Value.origin_ec,
-+-                            extra->Err.Value.otag & 3 );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-++            if (extra->Err.Value.origin_ece.ec)
-++               mc_pp_origin( extra->Err.Value.origin_ece,
-++                             extra->Err.Value.otag & 3 );
-+          } else {
-+             /* Could also show extra->Err.Cond.otag if debugging origin
-+                tracking */
-+             emit( "Use of uninitialised value of size %lu\n",
-+                   extra->Err.Value.szB );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-+-            if (extra->Err.Value.origin_ec)
-+-               mc_pp_origin( extra->Err.Value.origin_ec,
-+-                            extra->Err.Value.otag & 3 );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-++            if (extra->Err.Value.origin_ece.ec)
-++               mc_pp_origin( extra->Err.Value.origin_ece,
-++                             extra->Err.Value.otag & 3 );
-+          }
-+          break;
-+ 
-+@@ -463,18 +463,18 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "  <kind>UninitCondition</kind>\n" );
-+             emit( "  <what>Conditional jump or move depends"
-+                   " on uninitialised value(s)</what>\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-+-            if (extra->Err.Cond.origin_ec)
-+-               mc_pp_origin( extra->Err.Cond.origin_ec,
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-++            if (extra->Err.Cond.origin_ece.ec)
-++               mc_pp_origin( extra->Err.Cond.origin_ece,
-+                              extra->Err.Cond.otag & 3 );
-+          } else {
-+             /* Could also show extra->Err.Cond.otag if debugging origin
-+                tracking */
-+             emit( "Conditional jump or move depends"
-+                   " on uninitialised value(s)\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-+-            if (extra->Err.Cond.origin_ec)
-+-               mc_pp_origin( extra->Err.Cond.origin_ec,
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-++            if (extra->Err.Cond.origin_ece.ec)
-++               mc_pp_origin( extra->Err.Cond.origin_ece,
-+                              extra->Err.Cond.otag & 3 );
-+          }
-+          break;
-+@@ -486,16 +486,16 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "  <what>Syscall param %pS contains "
-+                   "uninitialised byte(s)</what>\n",
-+                   VG_(get_error_string)(err) );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-+-            if (extra->Err.RegParam.origin_ec)
-+-               mc_pp_origin( extra->Err.RegParam.origin_ec,
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-++            if (extra->Err.RegParam.origin_ece.ec)
-++               mc_pp_origin( extra->Err.RegParam.origin_ece,
-+                              extra->Err.RegParam.otag & 3 );
-+          } else {
-+             emit( "Syscall param %s contains uninitialised byte(s)\n",
-+                   VG_(get_error_string)(err) );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-+-            if (extra->Err.RegParam.origin_ec)
-+-               mc_pp_origin( extra->Err.RegParam.origin_ec,
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-++            if (extra->Err.RegParam.origin_ece.ec)
-++               mc_pp_origin( extra->Err.RegParam.origin_ece,
-+                              extra->Err.RegParam.otag & 3 );
-+          }
-+          break;
-+@@ -509,24 +509,24 @@ void MC_(pp_Error) ( const Error* err )
-+                   VG_(get_error_string)(err),
-+                   extra->Err.MemParam.isAddrErr 
-+                      ? "unaddressable" : "uninitialised" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
-+                                 &extra->Err.MemParam.ai, False);
-+-            if (extra->Err.MemParam.origin_ec 
-++            if (extra->Err.MemParam.origin_ece.ec 
-+                 && !extra->Err.MemParam.isAddrErr)
-+-               mc_pp_origin( extra->Err.MemParam.origin_ec,
-++               mc_pp_origin( extra->Err.MemParam.origin_ece,
-+                              extra->Err.MemParam.otag & 3 );
-+          } else {
-+             emit( "Syscall param %s points to %s byte(s)\n",
-+                   VG_(get_error_string)(err),
-+                   extra->Err.MemParam.isAddrErr 
-+                      ? "unaddressable" : "uninitialised" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
-+                                 &extra->Err.MemParam.ai, False);
-+-            if (extra->Err.MemParam.origin_ec 
-++            if (extra->Err.MemParam.origin_ece.ec 
-+                 && !extra->Err.MemParam.isAddrErr)
-+-               mc_pp_origin( extra->Err.MemParam.origin_ec,
-++               mc_pp_origin( extra->Err.MemParam.origin_ece,
-+                              extra->Err.MemParam.otag & 3 );
-+          }
-+          break;
-+@@ -540,21 +540,21 @@ void MC_(pp_Error) ( const Error* err )
-+                   "during client check request</what>\n", 
-+                    extra->Err.User.isAddrErr
-+                       ? "Unaddressable" : "Uninitialised" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), &extra->Err.User.ai,
-+                                 False);
-+-            if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr)
-+-               mc_pp_origin( extra->Err.User.origin_ec,
-++            if (extra->Err.User.origin_ece.ec && !extra->Err.User.isAddrErr)
-++               mc_pp_origin( extra->Err.User.origin_ece,
-+                              extra->Err.User.otag & 3 );
-+          } else {
-+             emit( "%s byte(s) found during client check request\n", 
-+                    extra->Err.User.isAddrErr
-+                       ? "Unaddressable" : "Uninitialised" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)(VG_(get_error_address)(err), &extra->Err.User.ai,
-+                                 False);
-+-            if (extra->Err.User.origin_ec && !extra->Err.User.isAddrErr)
-+-               mc_pp_origin( extra->Err.User.origin_ec,
-++            if (extra->Err.User.origin_ece.ec && !extra->Err.User.isAddrErr)
-++               mc_pp_origin( extra->Err.User.origin_ece,
-+                              extra->Err.User.otag & 3 );
-+          }
-+          break;
-+@@ -564,12 +564,12 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "  <kind>InvalidFree</kind>\n" );
-+             emit( "  <what>Invalid free() / delete / delete[]"
-+                   " / realloc()</what>\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
-+                                  &extra->Err.Free.ai, False );
-+          } else {
-+             emit( "Invalid free() / delete / delete[] / realloc()\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
-+                                  &extra->Err.Free.ai, False );
-+          }
-+@@ -579,12 +579,12 @@ void MC_(pp_Error) ( const Error* err )
-+          if (xml) {
-+             emit( "  <kind>MismatchedFree</kind>\n" );
-+             emit( "  <what>Mismatched free() / delete / delete []</what>\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
-+                                 &extra->Err.FreeMismatch.ai, False);
-+          } else {
-+             emit( "Mismatched free() / delete / delete []\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)(VG_(get_error_address)(err),
-+                                 &extra->Err.FreeMismatch.ai, False);
-+          }
-+@@ -597,7 +597,7 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "  <what>Invalid %s of size %lu</what>\n",
-+                   extra->Err.Addr.isWrite ? "write" : "read",
-+                   extra->Err.Addr.szB );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
-+                                  &extra->Err.Addr.ai,
-+                                  extra->Err.Addr.maybe_gcc );
-+@@ -605,7 +605,7 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "Invalid %s of size %lu\n",
-+                   extra->Err.Addr.isWrite ? "write" : "read",
-+                   extra->Err.Addr.szB );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+ 
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
-+                                  &extra->Err.Addr.ai,
-+@@ -618,12 +618,12 @@ void MC_(pp_Error) ( const Error* err )
-+             emit( "  <kind>InvalidJump</kind>\n" );
-+             emit( "  <what>Jump to the invalid address stated "
-+                   "on the next line</what>\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), &extra->Err.Jump.ai,
-+                                  False );
-+          } else {
-+             emit( "Jump to the invalid address stated on the next line\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err), &extra->Err.Jump.ai,
-+                                  False );
-+          }
-+@@ -644,7 +644,7 @@ void MC_(pp_Error) ( const Error* err )
-+                      extra->Err.Overlap.dst, extra->Err.Overlap.src,
-+                      extra->Err.Overlap.szB );
-+             }
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          } else {
-+             if (extra->Err.Overlap.szB == 0) {
-+                emit( "Source and destination overlap in %s(%#lx, %#lx)\n",
-+@@ -656,7 +656,7 @@ void MC_(pp_Error) ( const Error* err )
-+                      extra->Err.Overlap.dst, extra->Err.Overlap.src,
-+                      extra->Err.Overlap.szB );
-+             }
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          }
-+          break;
-+ 
-+@@ -666,12 +666,12 @@ void MC_(pp_Error) ( const Error* err )
-+          if (xml) {
-+             emit( "  <kind>InvalidMemPool</kind>\n" );
-+             emit( "  <what>Illegal memory pool address</what>\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
-+                                  &extra->Err.IllegalMempool.ai, False );
-+          } else {
-+             emit( "Illegal memory pool address\n" );
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+             VG_(pp_addrinfo_mc)( VG_(get_error_address)(err),
-+                                  &extra->Err.IllegalMempool.ai, False );
-+          }
-+@@ -695,14 +695,14 @@ void MC_(pp_Error) ( const Error* err )
-+                   extra->Err.FishyValue.function_name,
-+                   (SSizeT)extra->Err.FishyValue.value);
-+             emit( "</what>");
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          } else {
-+             emit( "Argument '%s' of function %s has a fishy "
-+                   "(possibly negative) value: %ld\n",
-+                   extra->Err.FishyValue.argument_name,
-+                   extra->Err.FishyValue.function_name,
-+                   (SSizeT)extra->Err.FishyValue.value);
-+-            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
-++            VG_(pp_ExeContextAndEpoch)( VG_(get_error_where)(err) );
-+          }
-+          break;
-+ 
-+@@ -773,9 +773,10 @@ void MC_(record_value_error) ( ThreadId
-+    tl_assert( MC_(clo_mc_level) >= 2 );
-+    if (otag > 0)
-+       tl_assert( MC_(clo_mc_level) == 3 );
-+-   extra.Err.Value.szB       = szB;
-+-   extra.Err.Value.otag      = otag;
-+-   extra.Err.Value.origin_ec = NULL;  /* Filled in later */
-++   extra.Err.Value.szB        = szB;
-++   extra.Err.Value.otag       = otag;
-++   extra.Err.Value.origin_ece = VG_(invalid_ExeContextAndEpoch)();
-++                                /* Filled in later */
-+    VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra );
-+ }
-+ 
-+@@ -785,8 +786,9 @@ void MC_(record_cond_error) ( ThreadId t
-+    tl_assert( MC_(clo_mc_level) >= 2 );
-+    if (otag > 0)
-+       tl_assert( MC_(clo_mc_level) == 3 );
-+-   extra.Err.Cond.otag      = otag;
-+-   extra.Err.Cond.origin_ec = NULL;  /* Filled in later */
-++   extra.Err.Cond.otag       = otag;
-++   extra.Err.Cond.origin_ece = VG_(invalid_ExeContextAndEpoch)();
-++                               /* Filled in later */
-+    VG_(maybe_record_error)( tid, Err_Cond, /*addr*/0, /*s*/NULL, &extra );
-+ }
-+ 
-+@@ -804,8 +806,9 @@ void MC_(record_regparam_error) ( Thread
-+    tl_assert(VG_INVALID_THREADID != tid);
-+    if (otag > 0)
-+       tl_assert( MC_(clo_mc_level) == 3 );
-+-   extra.Err.RegParam.otag      = otag;
-+-   extra.Err.RegParam.origin_ec = NULL;  /* Filled in later */
-++   extra.Err.RegParam.otag       = otag;
-++   extra.Err.RegParam.origin_ece = VG_(invalid_ExeContextAndEpoch)();
-++                                 /* Filled in later */
-+    VG_(maybe_record_error)( tid, Err_RegParam, /*addr*/0, msg, &extra );
-+ }
-+ 
-+@@ -820,10 +823,11 @@ void MC_(record_memparam_error) ( Thread
-+       tl_assert( MC_(clo_mc_level) == 3 );
-+       tl_assert( !isAddrErr );
-+    }
-+-   extra.Err.MemParam.isAddrErr = isAddrErr;
-+-   extra.Err.MemParam.ai.tag    = Addr_Undescribed;
-+-   extra.Err.MemParam.otag      = otag;
-+-   extra.Err.MemParam.origin_ec = NULL;  /* Filled in later */
-++   extra.Err.MemParam.isAddrErr  = isAddrErr;
-++   extra.Err.MemParam.ai.tag     = Addr_Undescribed;
-++   extra.Err.MemParam.otag       = otag;
-++   extra.Err.MemParam.origin_ece = VG_(invalid_ExeContextAndEpoch)();
-++                                 /* Filled in later */
-+    VG_(maybe_record_error)( tid, Err_MemParam, a, msg, &extra );
-+ }
-+ 
-+@@ -925,10 +929,11 @@ void MC_(record_user_error) ( ThreadId t
-+       tl_assert( MC_(clo_mc_level) >= 2 );
-+    }
-+    tl_assert(VG_INVALID_THREADID != tid);
-+-   extra.Err.User.isAddrErr = isAddrErr;
-+-   extra.Err.User.ai.tag    = Addr_Undescribed;
-+-   extra.Err.User.otag      = otag;
-+-   extra.Err.User.origin_ec = NULL;  /* Filled in later */
-++   extra.Err.User.isAddrErr  = isAddrErr;
-++   extra.Err.User.ai.tag     = Addr_Undescribed;
-++   extra.Err.User.otag       = otag;
-++   extra.Err.User.origin_ece = VG_(invalid_ExeContextAndEpoch)();
-++                             /* Filled in later */
-+    VG_(maybe_record_error)( tid, Err_User, a, /*s*/NULL, &extra );
-+ }
-+ 
-+@@ -1053,7 +1058,7 @@ static Bool mempool_block_maybe_describe
-+ 
-+ /* Describe an address as best you can, for error messages,
-+    putting the result in ai. */
-+-static void describe_addr ( Addr a, /*OUT*/AddrInfo* ai )
-++static void describe_addr ( DiEpoch ep, Addr a, /*OUT*/AddrInfo* ai )
-+ {
-+    MC_Chunk*  mc;
-+ 
-+@@ -1121,28 +1126,30 @@ static void describe_addr ( Addr a, /*OU
-+    }
-+ 
-+    /* No block found. Search a non-heap block description. */
-+-   VG_(describe_addr) (a, ai);
-++   VG_(describe_addr) (ep, a, ai);
-+ }
-+ 
-+-void MC_(pp_describe_addr) ( Addr a )
-++void MC_(pp_describe_addr) ( DiEpoch ep, Addr a )
-+ {
-+    AddrInfo ai;
-+ 
-+    ai.tag = Addr_Undescribed;
-+-   describe_addr (a, &ai);
-++   describe_addr (ep, a, &ai);
-+    VG_(pp_addrinfo_mc) (a, &ai, /* maybe_gcc */ False);
-+    VG_(clear_addrinfo) (&ai);
-+ }
-+ 
-+-/* Fill in *origin_ec as specified by otag, or NULL it out if otag
-++/* Fill in *origin_ece as specified by otag, or NULL it out if otag
-+    does not refer to a known origin. */
-+-static void update_origin ( /*OUT*/ExeContext** origin_ec,
-++static void update_origin ( /*OUT*/ExeContextAndEpoch* origin_ece,
-+                             UInt otag )
-+ {
-+    UInt ecu = otag & ~3;
-+-   *origin_ec = NULL;
-+    if (VG_(is_plausible_ECU)(ecu)) {
-+-      *origin_ec = VG_(get_ExeContext_from_ECU)( ecu );
-++      *origin_ece
-++         = VG_(tag_EC_with_current_epoch)(VG_(get_ExeContext_from_ECU)( ecu ));
-++   } else {
-++      *origin_ece = VG_(invalid_ExeContextAndEpoch)();
-+    }
-+ }
-+ 
-+@@ -1150,6 +1157,7 @@ static void update_origin ( /*OUT*/ExeCo
-+ UInt MC_(update_Error_extra)( const Error* err )
-+ {
-+    MC_Error* extra = VG_(get_error_extra)(err);
-++   DiEpoch   ep    = VG_(get_error_where)(err).epoch;
-+ 
-+    switch (VG_(get_error_kind)(err)) {
-+    // These ones don't have addresses associated with them, and so don't
-+@@ -1169,45 +1177,45 @@ UInt MC_(update_Error_extra)( const Erro
-+    // origin tag.  Note that it is a kludge to assume that 
-+    // a length-1 trace indicates a stack origin.  FIXME.
-+    case Err_Value:
-+-      update_origin( &extra->Err.Value.origin_ec,
-++      update_origin( &extra->Err.Value.origin_ece,
-+                      extra->Err.Value.otag );
-+       return sizeof(MC_Error);
-+    case Err_Cond:
-+-      update_origin( &extra->Err.Cond.origin_ec,
-++      update_origin( &extra->Err.Cond.origin_ece,
-+                      extra->Err.Cond.otag );
-+       return sizeof(MC_Error);
-+    case Err_RegParam:
-+-      update_origin( &extra->Err.RegParam.origin_ec,
-++      update_origin( &extra->Err.RegParam.origin_ece,
-+                      extra->Err.RegParam.otag );
-+       return sizeof(MC_Error);
-+ 
-+    // These ones always involve a memory address.
-+    case Err_Addr:
-+-      describe_addr ( VG_(get_error_address)(err),
-++      describe_addr ( ep, VG_(get_error_address)(err),
-+                       &extra->Err.Addr.ai );
-+       return sizeof(MC_Error);
-+    case Err_MemParam:
-+-      describe_addr ( VG_(get_error_address)(err),
-++      describe_addr ( ep, VG_(get_error_address)(err),
-+                       &extra->Err.MemParam.ai );
-+-      update_origin( &extra->Err.MemParam.origin_ec,
-++      update_origin( &extra->Err.MemParam.origin_ece,
-+                      extra->Err.MemParam.otag );
-+       return sizeof(MC_Error);
-+    case Err_Jump:
-+-      describe_addr ( VG_(get_error_address)(err),
-++      describe_addr ( ep, VG_(get_error_address)(err),
-+                       &extra->Err.Jump.ai );
-+       return sizeof(MC_Error);
-+    case Err_User:
-+-      describe_addr ( VG_(get_error_address)(err),
-++      describe_addr ( ep, VG_(get_error_address)(err),
-+                       &extra->Err.User.ai );
-+-      update_origin( &extra->Err.User.origin_ec,
-++      update_origin( &extra->Err.User.origin_ece,
-+                      extra->Err.User.otag );
-+       return sizeof(MC_Error);
-+    case Err_Free:
-+-      describe_addr ( VG_(get_error_address)(err),
-++      describe_addr ( ep, VG_(get_error_address)(err),
-+                       &extra->Err.Free.ai );
-+       return sizeof(MC_Error);
-+    case Err_IllegalMempool:
-+-      describe_addr ( VG_(get_error_address)(err),
-++      describe_addr ( ep, VG_(get_error_address)(err),
-+                       &extra->Err.IllegalMempool.ai );
-+       return sizeof(MC_Error);
-+ 
-+@@ -1252,7 +1260,7 @@ static Bool client_block_maybe_describe(
-+          ai->Addr.Block.rwoffset   = (Word)(a) - (Word)(cgbs[i].start);
-+          ai->Addr.Block.allocated_at = cgbs[i].where;
-+          VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo);
-+-         ai->Addr.Block.freed_at = VG_(null_ExeContext)();;
-++         ai->Addr.Block.freed_at = VG_(null_ExeContextAndEpoch)();
-+          return True;
-+       }
-+    }
-+Index: valgrind-3.13.0/memcheck/mc_include.h
-+===================================================================
-+--- valgrind-3.13.0.orig/memcheck/mc_include.h
-++++ valgrind-3.13.0/memcheck/mc_include.h
-+@@ -67,17 +67,17 @@ typedef
-+       Addr         data;            // Address of the actual block.
-+       SizeT        szB : (sizeof(SizeT)*8)-2; // Size requested; 30 or 62 bits.
-+       MC_AllocKind allockind : 2;   // Which operation did the allocation.
-+-      ExeContext*  where[0];
-++      ExeContextAndEpoch where[0];
-+       /* Variable-length array. The size depends on MC_(clo_keep_stacktraces).
-+          This array optionally stores the alloc and/or free stack trace. */
-+    }
-+    MC_Chunk;
-+ 
-+-/* Returns the execontext where the MC_Chunk was allocated/freed.
-++/* Returns the execontext and epoch where the MC_Chunk was allocated/freed.
-+    Returns VG_(null_ExeContext)() if the execontext has not been recorded (due
-+    to MC_(clo_keep_stacktraces) and/or because block not yet freed). */
-+-ExeContext* MC_(allocated_at) (MC_Chunk*);
-+-ExeContext* MC_(freed_at) (MC_Chunk*);
-++ExeContextAndEpoch MC_(allocated_at) (MC_Chunk*);
-++ExeContextAndEpoch MC_(freed_at) (MC_Chunk*);
-+ 
-+ /* Records and sets execontext according to MC_(clo_keep_stacktraces) */
-+ void  MC_(set_allocated_at) (ThreadId, MC_Chunk*);
-+@@ -432,8 +432,8 @@ typedef
-+ /* When a LossRecord is put into an OSet, these elements represent the key. */
-+ typedef
-+    struct _LossRecordKey {
-+-      Reachedness  state;        // LC_Extra.state value shared by all blocks.
-+-      ExeContext*  allocated_at; // Where they were allocated.
-++      Reachedness         state;  // LC_Extra.state value shared by all blocks.
-++      ExeContextAndEpoch  allocated_at; // Where they were allocated.
-+    } 
-+    LossRecordKey;
-+ 
-+@@ -569,8 +569,8 @@ Bool MC_(record_fishy_value_error)  ( Th
-+ /* Leak kinds tokens to call VG_(parse_enum_set). */
-+ extern const HChar* MC_(parse_leak_kinds_tokens);
-+ 
-+-/* prints a description of address a */
-+-void MC_(pp_describe_addr) (Addr a);
-++/* prints a description of address a in the specified debuginfo epoch */
-++void MC_(pp_describe_addr) ( DiEpoch ep, Addr a );
-+ 
-+ /* Is this address in a user-specified "ignored range" ? */
-+ Bool MC_(in_ignored_range) ( Addr a );
-+@@ -588,10 +588,10 @@ Bool MC_(in_ignored_range_below_sp) ( Ad
-+    start == size == 0.  */
-+ typedef
-+    struct {
-+-      Addr        start;
-+-      SizeT       size;
-+-      ExeContext* where;
-+-      HChar*      desc;
-++      Addr               start;
-++      SizeT              size;
-++      ExeContextAndEpoch where;
-++      HChar*             desc;
-+    } 
-+    CGenBlock;
-+ 
-+Index: valgrind-3.13.0/memcheck/mc_leakcheck.c
-+===================================================================
-+--- valgrind-3.13.0.orig/memcheck/mc_leakcheck.c
-++++ valgrind-3.13.0/memcheck/mc_leakcheck.c
-+@@ -1060,6 +1060,8 @@ lc_scan_memory(Addr start, SizeT len, Bo
-+    const Addr end = VG_ROUNDDN(start+len, sizeof(Addr));
-+    fault_catcher_t prev_catcher;
-+ 
-++   const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+    if (VG_DEBUG_LEAKCHECK)
-+       VG_(printf)("scan %#lx-%#lx (%lu)\n", start, end, len);
-+ 
-+@@ -1139,14 +1141,14 @@ lc_scan_memory(Addr start, SizeT len, Bo
-+             if (addr >= searched && addr < searched + szB) {
-+                if (addr == searched) {
-+                   VG_(umsg)("*%#lx points at %#lx\n", ptr, searched);
-+-                  MC_(pp_describe_addr) (ptr);
-++                  MC_(pp_describe_addr) (ep, ptr); // FIXME JRS: ep correct?
-+                } else {
-+                   Int ch_no;
-+                   MC_Chunk *ch;
-+                   LC_Extra *ex;
-+                   VG_(umsg)("*%#lx interior points at %lu bytes inside %#lx\n",
-+                             ptr, (long unsigned) addr - searched, searched);
-+-                  MC_(pp_describe_addr) (ptr);
-++                  MC_(pp_describe_addr) (ep, ptr); // FIXME JRS: ep correct?
-+                   if (lc_is_a_chunk_ptr(addr, &ch_no, &ch, &ex) ) {
-+                      Int h;
-+                      for (h = LchStdString; h < N_LEAK_CHECK_HEURISTICS; h++) {
-+@@ -1203,13 +1205,17 @@ static Word cmp_LossRecordKey_LossRecord
-+    // Compare on states first because that's fast.
-+    if (a->state < b->state) return -1;
-+    if (a->state > b->state) return  1;
-+-   // Ok, the states are equal.  Now compare the locations, which is slower.
-++   // Also on epochs, for the same reason.
-++   if (a->allocated_at.epoch.n < b->allocated_at.epoch.n) return -1;
-++   if (a->allocated_at.epoch.n > b->allocated_at.epoch.n) return 1;
-++   // Ok, the states and epochs are equal.  Now compare the locations, which
-++   // is slower.
-+    if (VG_(eq_ExeContext)(
-+-            MC_(clo_leak_resolution), a->allocated_at, b->allocated_at))
-++            MC_(clo_leak_resolution), a->allocated_at.ec, b->allocated_at.ec))
-+       return 0;
-+    // Different locations.  Ordering is arbitrary, just use the ec pointer.
-+-   if (a->allocated_at < b->allocated_at) return -1;
-+-   if (a->allocated_at > b->allocated_at) return  1;
-++   if (a->allocated_at.ec < b->allocated_at.ec) return -1;
-++   if (a->allocated_at.ec > b->allocated_at.ec) return  1;
-+    VG_(tool_panic)("bad LossRecord comparison");
-+ }
-+ 
-+@@ -1231,10 +1237,15 @@ static Int cmp_LossRecords(const void* v
-+    // possible.  So:  compare num_blocks.
-+    if (lr_a->num_blocks < lr_b->num_blocks) return -1;
-+    if (lr_a->num_blocks > lr_b->num_blocks) return  1;
-++   // Then epochs.
-++   if (lr_a->key.allocated_at.epoch.n < lr_b->key.allocated_at.epoch.n)
-++      return -1;
-++   if (lr_a->key.allocated_at.epoch.n > lr_b->key.allocated_at.epoch.n)
-++      return 1;
-+    // Finally, compare ExeContext addresses... older ones are likely to have
-+    // lower addresses.
-+-   if (lr_a->key.allocated_at < lr_b->key.allocated_at) return -1;
-+-   if (lr_a->key.allocated_at > lr_b->key.allocated_at) return  1;
-++   if (lr_a->key.allocated_at.ec < lr_b->key.allocated_at.ec) return -1;
-++   if (lr_a->key.allocated_at.ec > lr_b->key.allocated_at.ec) return  1;
-+    return 0;
-+ }
-+ 
-+@@ -1381,7 +1392,7 @@ static void XT_insert_lr (LossRecord* lr
-+       xtl.xt_lr[i].vid[XT_Decrease].num_blocks 
-+          = lr->old_num_blocks - lr->num_blocks;
-+ 
-+-   VG_(XT_add_to_ec)(leak_xt, lr->key.allocated_at, &xtl);
-++   VG_(XT_add_to_ec)(leak_xt, lr->key.allocated_at.ec, &xtl);
-+ }
-+ 
-+ static void MC_(XT_Leak_sub) (void* from, const void* xtleak)
-+@@ -2133,9 +2144,9 @@ void MC_(detect_memory_leaks) ( ThreadId
-+             VG_(umsg)("Block 0x%lx..0x%lx overlaps with block 0x%lx..0x%lx\n",
-+                       start1, end1, start2, end2);
-+             VG_(umsg)("Blocks allocation contexts:\n"),
-+-            VG_(pp_ExeContext)( MC_(allocated_at)(ch1));
-++            VG_(pp_ExeContextAndEpoch)( MC_(allocated_at)(ch1));
-+             VG_(umsg)("\n"),
-+-            VG_(pp_ExeContext)(  MC_(allocated_at)(ch2));
-++            VG_(pp_ExeContextAndEpoch)(  MC_(allocated_at)(ch2));
-+             VG_(umsg)("This is usually caused by using ");
-+             VG_(umsg)("VALGRIND_MALLOCLIKE_BLOCK in an inappropriate way.\n");
-+             tl_assert (0);
-+Index: valgrind-3.13.0/memcheck/mc_main.c
-+===================================================================
-+--- valgrind-3.13.0.orig/memcheck/mc_main.c
-++++ valgrind-3.13.0/memcheck/mc_main.c
-+@@ -6719,9 +6719,11 @@ static Bool handle_gdb_monitor_command (
-+       const HChar* src;
-+       UInt otag;
-+       UInt ecu;
-+-      ExeContext* origin_ec;
-++      ExeContextAndEpoch origin_ece;
-+       MC_ReadResult res;
-+ 
-++      const DiEpoch ep = VG_(current_DiEpoch)();
-++
-+       Int kwdid = VG_(keyword_id) 
-+          ("addressable defined",
-+           VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
-+@@ -6738,7 +6740,8 @@ static Bool handle_gdb_monitor_command (
-+             VG_(printf)
-+                ("Address %p len %lu not addressable:\nbad address %p\n",
-+                 (void *)address, szB, (void *) bad_addr);
-+-         MC_(pp_describe_addr) (address);
-++         // FIXME JRS epoch ok?
-++         MC_(pp_describe_addr) (ep, address);
-+          break;
-+       case  1: /* defined */
-+          res = is_mem_defined ( address, szB, &bad_addr, &otag );
-+@@ -6765,14 +6768,16 @@ static Bool handle_gdb_monitor_command (
-+                 (void *)address, szB, (void *) bad_addr, src);
-+             ecu = otag & ~3;
-+             if (VG_(is_plausible_ECU)(ecu)) {
-+-               origin_ec = VG_(get_ExeContext_from_ECU)( ecu );
-+-               VG_(pp_ExeContext)( origin_ec );
-++               origin_ece = VG_(tag_EC_with_current_epoch)(
-++                               VG_(get_ExeContext_from_ECU)( ecu ));
-++               VG_(pp_ExeContextAndEpoch)( origin_ece );
-+             }
-+          }
-+          else
-+             VG_(printf) ("Address %p len %lu defined\n",
-+                          (void *)address, szB);
-+-         MC_(pp_describe_addr) (address);
-++         // FIXME JRS epoch ok?
-++         MC_(pp_describe_addr) (ep, address);
-+          break;
-+       default: tl_assert(0);
-+       }
-+@@ -7049,7 +7054,9 @@ static Bool mc_handle_client_request ( T
-+             cgbs[i].start = arg[1];
-+             cgbs[i].size  = arg[2];
-+             cgbs[i].desc  = VG_(strdup)("mc.mhcr.1", (HChar *)arg[3]);
-+-            cgbs[i].where = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
-++            cgbs[i].where = VG_(tag_EC_with_current_epoch)(
-++                               VG_(record_ExeContext) ( tid,
-++                                                        0/*first_ip_delta*/ ));
-+             *ret = i;
-+          } else
-+             *ret = -1;
-+@@ -7917,7 +7924,7 @@ static void mc_post_clo_init ( void )
-+    }
-+ 
-+    MC_(chunk_poolalloc) = VG_(newPA)
-+-      (sizeof(MC_Chunk) + MC_(n_where_pointers)() * sizeof(ExeContext*),
-++      (sizeof(MC_Chunk) + MC_(n_where_pointers)() * sizeof(ExeContextAndEpoch),
-+        1000,
-+        VG_(malloc),
-+        "mc.cMC.1 (MC_Chunk pools)",
-+Index: valgrind-3.13.0/memcheck/mc_malloc_wrappers.c
-+===================================================================
-+--- valgrind-3.13.0.orig/memcheck/mc_malloc_wrappers.c
-++++ valgrind-3.13.0/memcheck/mc_malloc_wrappers.c
-+@@ -199,8 +199,8 @@ MC_Chunk* create_MC_Chunk ( ThreadId tid
-+    mc->szB       = szB;
-+    mc->allockind = kind;
-+    switch ( MC_(n_where_pointers)() ) {
-+-      case 2: mc->where[1] = 0; // fallback to 1
-+-      case 1: mc->where[0] = 0; // fallback to 0
-++      case 2: mc->where[1] = VG_(invalid_ExeContextAndEpoch)(); // fall thru
-++      case 1: mc->where[0] = VG_(invalid_ExeContextAndEpoch)(); // fall thru
-+       case 0: break;
-+       default: tl_assert(0);
-+    }
-+@@ -268,30 +268,34 @@ static Bool live_block (MC_Chunk* mc)
-+    return in_block_list ( MC_(malloc_list), mc );
-+ }
-+ 
-+-ExeContext* MC_(allocated_at) (MC_Chunk* mc)
-++ExeContextAndEpoch MC_(allocated_at) (MC_Chunk* mc)
-+ {
-+    switch (MC_(clo_keep_stacktraces)) {
-+-      case KS_none:            return VG_(null_ExeContext) ();
-++      case KS_none:            return VG_(null_ExeContextAndEpoch) ();
-+       case KS_alloc:           return mc->where[0];
-+-      case KS_free:            return VG_(null_ExeContext) ();
-+-      case KS_alloc_then_free: return (live_block(mc) ?
-+-                                       mc->where[0] : VG_(null_ExeContext) ());
-++      case KS_free:            return VG_(null_ExeContextAndEpoch) ();
-++      case KS_alloc_then_free: return live_block(mc) 
-++                                         ? mc->where[0]
-++                                         : VG_(null_ExeContextAndEpoch) ();
-+       case KS_alloc_and_free:  return mc->where[0];
-+       default: tl_assert (0);
-+    }
-+ }
-+ 
-+-ExeContext* MC_(freed_at) (MC_Chunk* mc)
-++ExeContextAndEpoch MC_(freed_at) (MC_Chunk* mc)
-+ {
-+    switch (MC_(clo_keep_stacktraces)) {
-+-      case KS_none:            return VG_(null_ExeContext) ();
-+-      case KS_alloc:           return VG_(null_ExeContext) ();
-+-      case KS_free:            return (mc->where[0] ?
-+-                                       mc->where[0] : VG_(null_ExeContext) ());
-+-      case KS_alloc_then_free: return (live_block(mc) ?
-+-                                       VG_(null_ExeContext) () : mc->where[0]);
-+-      case KS_alloc_and_free:  return (mc->where[1] ?
-+-                                       mc->where[1] : VG_(null_ExeContext) ());
-++      case KS_none:            return VG_(null_ExeContextAndEpoch) ();
-++      case KS_alloc:           return VG_(null_ExeContextAndEpoch) ();
-++      case KS_free:            return mc->where[0].ec
-++                                         ? mc->where[0]
-++                                         : VG_(null_ExeContextAndEpoch) ();
-++      case KS_alloc_then_free: return live_block(mc)
-++                                         ? VG_(null_ExeContextAndEpoch) ()
-++                                         : mc->where[0];
-++      case KS_alloc_and_free:  return mc->where[1].ec
-++                                         ? mc->where[1]
-++                                         : VG_(null_ExeContextAndEpoch) ();
-+       default: tl_assert (0);
-+    }
-+ }
-+@@ -306,15 +310,16 @@ void  MC_(set_allocated_at) (ThreadId ti
-+       case KS_alloc_and_free:  break;
-+       default: tl_assert (0);
-+    }
-+-   mc->where[0] = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
-++   mc->where[0] = VG_(tag_EC_with_current_epoch)(
-++                     VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ ));
-+    if (UNLIKELY(VG_(clo_xtree_memory) == Vg_XTMemory_Full))
-+-       VG_(XTMemory_Full_alloc)(mc->szB, mc->where[0]);
-++       VG_(XTMemory_Full_alloc)(mc->szB, mc->where[0].ec);
-+ }
-+ 
-+ void  MC_(set_freed_at) (ThreadId tid, MC_Chunk* mc)
-+ {
-+    Int pos;
-+-   ExeContext* ec_free;
-++   ExeContextAndEpoch ec_free;
-+ 
-+    switch (MC_(clo_keep_stacktraces)) {
-+       case KS_none:            return;
-+@@ -333,9 +338,10 @@ void  MC_(set_freed_at) (ThreadId tid, M
-+       Note: we are guaranteed to find the ec_alloc in mc->where[0], as
-+       mc_post_clo_init verifies the consistency of --xtree-memory and
-+       --keep-stacktraces. */
-+-   ec_free = VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ );
-++   ec_free = VG_(tag_EC_with_current_epoch)(
-++                VG_(record_ExeContext) ( tid, 0/*first_ip_delta*/ ));
-+    if (UNLIKELY(VG_(clo_xtree_memory) == Vg_XTMemory_Full))
-+-       VG_(XTMemory_Full_free)(mc->szB, mc->where[0], ec_free);
-++       VG_(XTMemory_Full_free)(mc->szB, mc->where[0].ec, ec_free.ec);
-+    if (LIKELY(pos >= 0))
-+       mc->where[pos] = ec_free;
-+ }
-+@@ -391,7 +397,7 @@ void* MC_(new_block) ( ThreadId tid,
-+    if (is_zeroed)
-+       MC_(make_mem_defined)( p, szB );
-+    else {
-+-      UInt ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(mc));
-++      UInt ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(mc).ec);
-+       tl_assert(VG_(is_plausible_ECU)(ecu));
-+       MC_(make_mem_undefined_w_otag)( p, szB, ecu | MC_OKIND_HEAP );
-+    }
-+@@ -605,7 +611,7 @@ void* MC_(realloc) ( ThreadId tid, void*
-+          // If the block has grown, we mark the grown area as undefined.
-+          // We have to do that after VG_(HT_add_node) to ensure the ecu
-+          // execontext is for a fully allocated block.
-+-         ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(new_mc));
-++         ecu = VG_(get_ECU_from_ExeContext)(MC_(allocated_at)(new_mc).ec);
-+          tl_assert(VG_(is_plausible_ECU)(ecu));
-+          MC_(make_mem_undefined_w_otag)( a_new+old_szB,
-+                                          new_szB-old_szB,
-+@@ -673,7 +679,7 @@ void MC_(handle_resizeInPlace)(ThreadId
-+       return;
-+ 
-+    if (UNLIKELY(VG_(clo_xtree_memory) == Vg_XTMemory_Full))
-+-       VG_(XTMemory_Full_resize_in_place)(oldSizeB,  newSizeB, mc->where[0]);
-++       VG_(XTMemory_Full_resize_in_place)(oldSizeB, newSizeB, mc->where[0].ec);
-+ 
-+    mc->szB = newSizeB;
-+    if (newSizeB < oldSizeB) {
-+@@ -887,7 +893,7 @@ check_mempool_sane(MC_Mempool* mp)
-+                          chunks[i]->data, 
-+                          chunks[i]->data + chunks[i]->szB);
-+ 
-+-            VG_(pp_ExeContext)(MC_(allocated_at)(chunks[i]));
-++            VG_(pp_ExeContextAndEpoch)(MC_(allocated_at)(chunks[i]));
-+          }
-+    }
-+    VG_(free)(chunks);
-+@@ -1147,7 +1153,7 @@ static void xtmemory_report_next_block(X
-+    if (mc) {
-+       xta->nbytes = mc->szB;
-+       xta->nblocks = 1;
-+-      *ec_alloc = MC_(allocated_at)(mc);
-++      *ec_alloc = MC_(allocated_at)(mc).ec;
-+    } else
-+       xta->nblocks = 0;
-+ }
-+Index: valgrind-3.13.0/memcheck/tests/linux/Makefile.am
-+===================================================================
-+--- valgrind-3.13.0.orig/memcheck/tests/linux/Makefile.am
-++++ valgrind-3.13.0/memcheck/tests/linux/Makefile.am
-+@@ -6,6 +6,10 @@ dist_noinst_SCRIPTS = filter_stderr
-+ EXTRA_DIST = \
-+ 	brk.stderr.exp brk.vgtest \
-+ 	capget.vgtest capget.stderr.exp capget.stderr.exp2 \
-++	dlclose_leak-no-keep.stderr.exp dlclose_leak-no-keep.stdout.exp \
-++	    dlclose_leak-no-keep.vgtest \
-++	dlclose_leak.stderr.exp dlclose_leak.stdout.exp \
-++	    dlclose_leak.vgtest \
-+ 	ioctl-tiocsig.vgtest ioctl-tiocsig.stderr.exp \
-+ 	lsframe1.vgtest lsframe1.stdout.exp lsframe1.stderr.exp \
-+ 	lsframe2.vgtest lsframe2.stdout.exp lsframe2.stderr.exp \
-+@@ -25,6 +29,7 @@ EXTRA_DIST = \
-+ check_PROGRAMS = \
-+ 	brk \
-+ 	capget \
-++	dlclose_leak dlclose_leak_so.so \
-+ 	ioctl-tiocsig \
-+ 	getregset \
-+ 	lsframe1 \
-+@@ -48,3 +53,15 @@ AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
-+ stack_switch_LDADD    = -lpthread
-+ timerfd_syscall_LDADD = -lrt
-+ 
-++# Build shared object for dlclose_leak
-++dlclose_leak_so_so_SOURCES = dlclose_leak_so.c
-++dlclose_leak_so_so_CFLAGS  = $(AM_CFLAGS) -fpic -g -O0
-++dlclose_leak_so_so_LDFLAGS  = -fpic $(AM_FLAG_M3264_PRI) -shared -Wl,-soname \
-++                              -Wl,dlclose_leak_so.so
-++
-++dlclose_leak_SOURCES          = dlclose_leak.c
-++dlclose_leak_DEPENDENCIES     = dlclose_leak_so.so
-++dlclose_leak_LDADD            = dlclose_leak_so.so
-++dlclose_leak_LDFLAGS          = $(AM_FLAG_M3264_PRI) \
-++                                -ldl \
-++                                -Wl,-rpath,$(top_builddir)/memcheck/tests/linux
-+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.stderr.exp
-+===================================================================
-+--- /dev/null
-++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.stderr.exp
-+@@ -0,0 +1,30 @@
-++
-++Conditional jump or move depends on uninitialised value(s)
-++   ...
-++
-++Invalid read of size 1
-++   ...
-++ Address 0x........ is 1 bytes before a block of size 1 alloc'd
-++   at 0x........: malloc (vg_replace_malloc.c:...)
-++   ...
-++
-++done!
-++
-++HEAP SUMMARY:
-++    in use at exit: 1 bytes in 1 blocks
-++  total heap usage: 4 allocs, 3 frees, 123 bytes allocated
-++
-++1 bytes in 1 blocks are definitely lost in loss record ... of ...
-++   at 0x........: malloc (vg_replace_malloc.c:...)
-++   ...
-++
-++LEAK SUMMARY:
-++   definitely lost: 1 bytes in 1 blocks
-++   indirectly lost: 0 bytes in 0 blocks
-++     possibly lost: 0 bytes in 0 blocks
-++   still reachable: 0 bytes in 0 blocks
-++        suppressed: 0 bytes in 0 blocks
-++
-++For counts of detected and suppressed errors, rerun with: -v
-++Use --track-origins=yes to see where uninitialised values come from
-++ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
-+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.vgtest
-+===================================================================
-+--- /dev/null
-++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak-no-keep.vgtest
-+@@ -0,0 +1,3 @@
-++prog: dlclose_leak
-++stderr_filter: ../filter_stderr
-++vgopts: --leak-check=yes --keep-debuginfo=no
-+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.c
-+===================================================================
-+--- /dev/null
-++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.c
-+@@ -0,0 +1,32 @@
-++/*  Test reporting of memory leaks in objects that have been dlopen'ed.
-++ *   File:   dlclose_leak.c */
-++
-++#include <stdio.h>
-++#include <stdlib.h>
-++#include <dlfcn.h>
-++#include <assert.h>
-++
-++int (*jmp_on_uninit)(void);
-++char* (*alloc_1_byte)(void);
-++
-++int main(int argc, char** argv) {
-++    char* memToLeak;
-++    char x;
-++    void* handle = dlopen("./dlclose_leak_so.so", RTLD_NOW);
-++    if(!handle) {
-++        printf("FAILURE to dlopen dlclose_leak_so.so\n");
-++        return EXIT_FAILURE;
-++    }
-++    jmp_on_uninit = dlsym(handle,"jmp_on_uninit");
-++    //fprintf(stderr, "jmp_on_uninit: %p\n", jmp_on_uninit);
-++    assert(jmp_on_uninit);
-++    alloc_1_byte = dlsym(handle,"alloc_1_byte");
-++    //fprintf(stderr, "alloc_1_byte: %p\n", alloc_1_byte);
-++    assert(alloc_1_byte);
-++    (void)jmp_on_uninit();
-++    memToLeak = alloc_1_byte();
-++    dlclose(handle);
-++    x = memToLeak[-1];
-++    fprintf(stderr, "done!\n");
-++    return (EXIT_SUCCESS);
-++}
-+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.stderr.exp
-+===================================================================
-+--- /dev/null
-++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.stderr.exp
-+@@ -0,0 +1,33 @@
-++
-++Conditional jump or move depends on uninitialised value(s)
-++   at 0x........: jmp_on_uninit (dlclose_leak_so.c:10)
-++   by 0x........: main (dlclose_leak.c:26)
-++
-++Invalid read of size 1
-++   at 0x........: main (dlclose_leak.c:29)
-++ Address 0x........ is 1 bytes before a block of size 1 alloc'd
-++   at 0x........: malloc (vg_replace_malloc.c:...)
-++   by 0x........: alloc_1_byte (dlclose_leak_so.c:20)
-++   by 0x........: main (dlclose_leak.c:27)
-++
-++done!
-++
-++HEAP SUMMARY:
-++    in use at exit: 1 bytes in 1 blocks
-++  total heap usage: 4 allocs, 3 frees, 123 bytes allocated
-++
-++1 bytes in 1 blocks are definitely lost in loss record ... of ...
-++   at 0x........: malloc (vg_replace_malloc.c:...)
-++   by 0x........: alloc_1_byte (dlclose_leak_so.c:20)
-++   by 0x........: main (dlclose_leak.c:27)
-++
-++LEAK SUMMARY:
-++   definitely lost: 1 bytes in 1 blocks
-++   indirectly lost: 0 bytes in 0 blocks
-++     possibly lost: 0 bytes in 0 blocks
-++   still reachable: 0 bytes in 0 blocks
-++        suppressed: 0 bytes in 0 blocks
-++
-++For counts of detected and suppressed errors, rerun with: -v
-++Use --track-origins=yes to see where uninitialised values come from
-++ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
-+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.vgtest
-+===================================================================
-+--- /dev/null
-++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak.vgtest
-+@@ -0,0 +1,3 @@
-++prog: dlclose_leak
-++stderr_filter: ../filter_stderr
-++vgopts: --leak-check=yes --keep-debuginfo=yes
-+Index: valgrind-3.13.0/memcheck/tests/linux/dlclose_leak_so.c
-+===================================================================
-+--- /dev/null
-++++ valgrind-3.13.0/memcheck/tests/linux/dlclose_leak_so.c
-+@@ -0,0 +1,21 @@
-++/* dlclose_leak_so.c */
-++
-++#include <stdlib.h>
-++
-++/** Makes a jump based on an uninitialized variable in order to make sure
-++ * errors reported while the dlopen'ed object is loaded work. */
-++int jmp_on_uninit(void) {
-++    int uninit[27];
-++    __asm__ __volatile("":::"cc","memory");
-++    if(uninit[13]) {
-++        return 1;
-++    } else {
-++        return 0;
-++    }
-++}
-++
-++/** Leak 1 byte of memory. This is to test the stack check reported after the
-++ *  object has been dlclose'd. */
-++char* alloc_1_byte(void) {
-++    return (char*)malloc(1);
-++}
-+Index: valgrind-3.13.0/none/tests/cmdline1.stdout.exp
-+===================================================================
-+--- valgrind-3.13.0.orig/none/tests/cmdline1.stdout.exp
-++++ valgrind-3.13.0/none/tests/cmdline1.stdout.exp
-+@@ -42,6 +42,10 @@ usage: valgrind [options] prog-and-args
-+     --error-exitcode=<number> exit code to return if errors found [0=disable]
-+     --error-markers=<begin>,<end> add lines with begin/end markers before/after
-+                               each error output in plain text mode [none]
-++    --keep-debuginfo=no|yes   Keep symbols etc for unloaded code [no]
-++                              This allows stack traces for memory leaks to
-++                              include file/line info for code that has been
-++                              dlclose'd (or similar)
-+     --show-below-main=no|yes  continue stack traces below main() [no]
-+     --default-suppressions=yes|no
-+                               load default suppressions [yes]
-+Index: valgrind-3.13.0/none/tests/cmdline2.stdout.exp
-+===================================================================
-+--- valgrind-3.13.0.orig/none/tests/cmdline2.stdout.exp
-++++ valgrind-3.13.0/none/tests/cmdline2.stdout.exp
-+@@ -42,6 +42,10 @@ usage: valgrind [options] prog-and-args
-+     --error-exitcode=<number> exit code to return if errors found [0=disable]
-+     --error-markers=<begin>,<end> add lines with begin/end markers before/after
-+                               each error output in plain text mode [none]
-++    --keep-debuginfo=no|yes   Keep symbols etc for unloaded code [no]
-++                              This allows stack traces for memory leaks to
-++                              include file/line info for code that has been
-++                              dlclose'd (or similar)
-+     --show-below-main=no|yes  continue stack traces below main() [no]
-+     --default-suppressions=yes|no
-+                               load default suppressions [yes]
--- a/build/unix/elfhack/elfhack.cpp
+++ b/build/unix/elfhack/elfhack.cpp
@@ -1104,17 +1104,17 @@ int do_relocation_section(Elf *elf, unsi
         // But sometimes it appears *before* the eh_frame_hdr section.
         eh_frame = eh_frame_hdr->getPrevious();
         first = eh_frame;
         second = eh_frame_hdr;
     }
     if (eh_frame_hdr && (!eh_frame || strcmp(eh_frame->getName(), ".eh_frame"))) {
         throw std::runtime_error("Expected to find an .eh_frame section adjacent to .eh_frame_hdr");
     }
-    if (eh_frame && first->getAddr() > relhack->getAddr() && second->getAddr() < relhackcode->getAddr()) {
+    if (eh_frame && first->getAddr() > relhack->getAddr() && second->getAddr() < first_executable->getAddr()) {
         // The distance between both sections needs to be preserved because eh_frame_hdr
         // contains relative offsets to eh_frame. Well, they could be relocated too, but
         // it's not worth the effort for the few number of bytes this would save.
         unsigned int distance = second->getAddr() - first->getAddr();
         unsigned int origAddr = eh_frame->getAddr();
         ElfSection* previous = first->getPrevious();
         first->getShdr().sh_addr =
             (previous->getAddr() + previous->getSize() + first->getAddrAlign() - 1)
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -736,15 +736,15 @@ skip-if = os != "mac" || debug || !night
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_stepping-02.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_stepping-03.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_stepping-04.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_recovery-01.js]
-skip-if = os != "mac" || debug || !nightly_build
+skip-if = true # See bug 1481009
 [browser_dbg_rr_replay-01.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_replay-02.js]
 skip-if = os != "mac" || debug || !nightly_build
 [browser_dbg_rr_replay-03.js]
 skip-if = os != "mac" || debug || !nightly_build
--- a/devtools/client/netmonitor/test/browser_net_headers_sorted.js
+++ b/devtools/client/netmonitor/test/browser_net_headers_sorted.js
@@ -80,17 +80,17 @@ async function verifyRawHeaders(monitor)
   const actualRequestHeaders = [];
 
   const expectedResponseHeaders = ["cache-control", "pragma", "expires",
                                    "set-cookie", "set-cookie", "content-type", "foo-bar",
                                    "foo-bar", "foo-bar", "connection", "server",
                                    "date", "content-length"];
 
   const expectedRequestHeaders = ["Host", "User-Agent", "Accept", "Accept-Language",
-                                  "Accept-Encoding", "Cookie", "Connection",
+                                  "Accept-Encoding", "Connection", "Cookie",
                                   "Upgrade-Insecure-Requests", "Pragma",
                                   "Cache-Control"];
 
   // Click the 'Raw headers' button to show original headers source.
   const rawHeadersBtn = document.querySelector(".raw-headers-button");
   rawHeadersBtn.click();
 
   // Wait till raw headers are available.
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -1365,17 +1365,17 @@ ChromeTooltipListener::sTooltipCallback(
         self->mPossibleTooltipNode, getter_Copies(tooltipText),
         getter_Copies(directionText), &textFound);
 
       if (textFound) {
         LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
         double scaleFactor = 1.0;
         if (shell->GetPresContext()) {
           nsDeviceContext* dc = shell->GetPresContext()->DeviceContext();
-          scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel()) /
+          scaleFactor = double(AppUnitsPerCSSPixel()) /
                         dc->AppUnitsPerDevPixelAtUnitFullZoom();
         }
         // ShowTooltip expects widget-relative position.
         self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor,
                           self->mMouseScreenY - screenDot.y / scaleFactor,
                           tooltipText, directionText);
       }
     }
--- a/dom/base/DOMRect.cpp
+++ b/dom/base/DOMRect.cpp
@@ -82,14 +82,14 @@ RoundFloat(double aValue)
 
 void
 DOMRect::SetLayoutRect(const nsRect& aLayoutRect)
 {
   double scale = 65536.0;
   // Round to the nearest 1/scale units. We choose scale so it can be represented
   // exactly by machine floating point.
   double scaleInv = 1/scale;
-  double t2pScaled = scale/nsPresContext::AppUnitsPerCSSPixel();
+  double t2pScaled = scale/AppUnitsPerCSSPixel();
   double x = RoundFloat(aLayoutRect.x*t2pScaled)*scaleInv;
   double y = RoundFloat(aLayoutRect.y*t2pScaled)*scaleInv;
   SetRect(x, y, RoundFloat(aLayoutRect.XMost()*t2pScaled)*scaleInv - x,
           RoundFloat(aLayoutRect.YMost()*t2pScaled)*scaleInv - y);
 }
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -6,16 +6,17 @@
 
 // Needs to be first.
 #include "base/basictypes.h"
 
 #include "Navigator.h"
 #include "nsIXULAppInfo.h"
 #include "nsPluginArray.h"
 #include "nsMimeTypeArray.h"
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/BodyExtractor.h"
 #include "mozilla/dom/FetchBinding.h"
 #include "mozilla/dom/File.h"
 #include "nsGeolocation.h"
 #include "nsIClassOfService.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsIContentPolicy.h"
@@ -58,16 +59,17 @@
 #include "mozilla/dom/Event.h" // for Event
 #include "nsGlobalWindow.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
 #include "nsRFPService.h"
 #include "nsStringStream.h"
 #include "nsComponentManagerUtils.h"
+#include "nsICookieService.h"
 #include "nsIStringStream.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsStreamUtils.h"
 #include "WidgetUtils.h"
 #include "nsIPresentationService.h"
 #include "nsIScriptError.h"
 
@@ -508,25 +510,21 @@ Navigator::Storage()
 
   if(!mStorageManager) {
     mStorageManager = new StorageManager(mWindow->AsGlobal());
   }
 
   return mStorageManager;
 }
 
-// Values for the network.cookie.cookieBehavior pref are documented in
-// nsCookieService.cpp.
-#define COOKIE_BEHAVIOR_REJECT 2
-
 bool
 Navigator::CookieEnabled()
 {
   bool cookieEnabled = (StaticPrefs::network_cookie_cookieBehavior() !=
-                        COOKIE_BEHAVIOR_REJECT);
+                        nsICookieService::BEHAVIOR_REJECT);
 
   // Check whether an exception overrides the global cookie behavior
   // Note that the code for getting the URI here matches that in
   // nsHTMLDocument::SetCookie.
   if (!mWindow || !mWindow->GetDocShell()) {
     return cookieEnabled;
   }
 
@@ -539,30 +537,18 @@ Navigator::CookieEnabled()
   doc->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI));
 
   if (!codebaseURI) {
     // Not a codebase, so technically can't set cookies, but let's
     // just return the default value.
     return cookieEnabled;
   }
 
-  nsCOMPtr<nsICookiePermission> permMgr =
-    do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
-  NS_ENSURE_TRUE(permMgr, cookieEnabled);
-
-  // Pass null for the channel, just like the cookie service does.
-  nsCookieAccess access;
-  nsresult rv = permMgr->CanAccess(doc->NodePrincipal(), &access);
-  NS_ENSURE_SUCCESS(rv, cookieEnabled);
-
-  if (access != nsICookiePermission::ACCESS_DEFAULT) {
-    cookieEnabled = access != nsICookiePermission::ACCESS_DENY;
-  }
-
-  return cookieEnabled;
+  return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(mWindow,
+                                                                 codebaseURI);
 }
 
 bool
 Navigator::OnLine()
 {
   return !NS_IsOffline();
 }
 
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -2020,17 +2020,17 @@ Selection::DoAutoScroll(nsIFrame* aFrame
     }
     if (!didScroll && !done) {
       // If aPoint is at the screen edge then try to scroll anyway, once.
       RefPtr<nsDeviceContext> dx = shell->GetViewManager()->GetDeviceContext();
       nsRect screen;
       dx->GetRect(screen);
       nsPoint screenPoint = globalPoint +
                             rootmostFrame->GetScreenRectInAppUnits().TopLeft();
-      nscoord onePx = nsPresContext::AppUnitsPerCSSPixel();
+      nscoord onePx = AppUnitsPerCSSPixel();
       nscoord scrollAmount = 10 * onePx;
       if (std::abs(screen.x - screenPoint.x) <= onePx) {
         aPoint.x -= scrollAmount;
       } else if (std::abs(screen.XMost() - screenPoint.x) <= onePx) {
         aPoint.x += scrollAmount;
       } else if (std::abs(screen.y - screenPoint.y) <= onePx) {
         aPoint.y -= scrollAmount;
       } else if (std::abs(screen.YMost() - screenPoint.y) <= onePx) {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -212,18 +212,18 @@
 #include "nsWidgetsCID.h"
 #include "nsIWindowProvider.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsXULPopupManager.h"
 #include "xpcprivate.h" // nsXPConnect
 #include "HTMLSplitOnSpacesTokenizer.h"
 #include "nsContentTypeParser.h"
 #include "nsICookiePermission.h"
+#include "nsICookieService.h"
 #include "mozIThirdPartyUtil.h"
-#include "nsICookieService.h"
 #include "mozilla/EnumSet.h"
 #include "mozilla/BloomFilter.h"
 #include "TabChild.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 #include "nsIWebNavigationInfo.h"
 #include "nsPluginHost.h"
 #include "mozilla/HangAnnotations.h"
@@ -8746,57 +8746,50 @@ nsContentUtils::StorageAccess
 nsContentUtils::StorageAllowedForPrincipal(nsIPrincipal* aPrincipal)
 {
   return InternalStorageAllowedForPrincipal(aPrincipal, nullptr, nullptr,
                                             nullptr);
 }
 
 // static, private
 void
-nsContentUtils::GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
-                                              uint32_t* aLifetimePolicy,
-                                              uint32_t* aBehavior)
+nsContentUtils::GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal,
+                                                    uint32_t* aLifetimePolicy)
 {
   *aLifetimePolicy = sCookiesLifetimePolicy;
-  *aBehavior = StaticPrefs::network_cookie_cookieBehavior();
 
   // Any permissions set for the given principal will override our default
   // settings from preferences.
   nsCOMPtr<nsIPermissionManager> permissionManager =
     services::GetPermissionManager();
   if (!permissionManager) {
     return;
   }
 
   uint32_t perm;
   permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm);
   switch (perm) {
     case nsICookiePermission::ACCESS_ALLOW:
-      *aBehavior = nsICookieService::BEHAVIOR_ACCEPT;
       *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
       break;
     case nsICookiePermission::ACCESS_DENY:
-      *aBehavior = nsICookieService::BEHAVIOR_REJECT;
       *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
       break;
     case nsICookiePermission::ACCESS_SESSION:
-      *aBehavior = nsICookieService::BEHAVIOR_ACCEPT;
       *aLifetimePolicy = nsICookieService::ACCEPT_SESSION;
       break;
     case nsICookiePermission::ACCESS_ALLOW_FIRST_PARTY_ONLY:
-      *aBehavior = nsICookieService::BEHAVIOR_REJECT_FOREIGN;
       // NOTE: The decision was made here to override the lifetime policy to be
       // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does
       // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a
       // specific domain. As BEHAVIOR_REJECT_FOREIGN isn't visible in our UI,
       // this is probably not an issue.
       *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
       break;
     case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY:
-      *aBehavior = nsICookieService::BEHAVIOR_LIMIT_FOREIGN;
       // NOTE: The decision was made here to override the lifetime policy to be
       // ACCEPT_NORMALLY for consistency with ACCESS_ALLOW, but this does
       // prevent us from expressing BEHAVIOR_REJECT_FOREIGN/ACCEPT_SESSION for a
       // specific domain. As BEHAVIOR_LIMIT_FOREIGN isn't visible in our UI,
       // this is probably not an issue.
       *aLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
       break;
   }
@@ -8856,96 +8849,82 @@ nsContentUtils::IsTrackingResourceWindow
   }
 
   return httpChannel->GetIsTrackingResource();
 }
 
 static bool
 StorageDisabledByAntiTrackingInternal(nsPIDOMWindowInner* aWindow,
                                       nsIChannel* aChannel,
+                                      nsIPrincipal* aPrincipal,
                                       nsIURI* aURI)
 {
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
-    return false;
-  }
-
-  // Let's check if this is a 3rd party context.
-  if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) {
-    return false;
-  }
+  MOZ_ASSERT(aWindow || aChannel || aPrincipal);
 
   if (aWindow) {
-    nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
-    nsGlobalWindowOuter* outerWindow =
-      nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow());
-    if (NS_WARN_IF(!outerWindow)) {
-      return false;
-    }
-
-    // We are a first party resource.
-    if (outerWindow->IsTopLevelWindow()) {
-      return false;
-    }
-
     nsIURI* documentURI = aURI ? aURI : aWindow->GetDocumentURI();
-    if (documentURI &&
-        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow,
-                                                                documentURI)) {
+    return !documentURI ||
+           !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aWindow,
+                                                                    documentURI);
+  }
+
+  if (aChannel) {
+    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+    if (!httpChannel) {
       return false;
     }
 
-    return true;
-  }
-
-  // aChannel and aWindow are mutually exclusive.
-  MOZ_ASSERT(aChannel);
-
-  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
-  if (!httpChannel) {
-    return false;
-  }
-
-  // If this is not a tracking resource, nothing is disabled.
-  if (!httpChannel->GetIsTrackingResource()) {
-    return false;
-  }
-
-  nsCOMPtr<nsIURI> uri;
-  nsresult rv = httpChannel->GetURI(getter_AddRefs(uri));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  return AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
-                                                                 uri);
+    nsCOMPtr<nsIURI> uri;
+    nsresult rv = httpChannel->GetURI(getter_AddRefs(uri));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return false;
+    }
+
+    return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
+                                                                    uri);
+  }
+
+  MOZ_ASSERT(aPrincipal);
+  return !AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(aPrincipal);
 }
 
 // static public
 bool
 nsContentUtils::StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
                                               nsIChannel* aChannel,
+                                              nsIPrincipal* aPrincipal,
                                               nsIURI* aURI)
 {
   bool disabled =
-    StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aURI);
+    StorageDisabledByAntiTrackingInternal(aWindow, aChannel, aPrincipal, aURI);
   if (disabled &&
       StaticPrefs::privacy_restrict3rdpartystorage_ui_enabled()) {
     nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
     if (!thirdPartyUtil) {
       return false;
     }
 
-    nsCOMPtr<mozIDOMWindowProxy> win;
-    nsresult rv = thirdPartyUtil->GetTopWindowForChannel(aChannel,
-                                                         getter_AddRefs(win));
-    NS_ENSURE_SUCCESS(rv, false);
-    auto* pwin = nsPIDOMWindowOuter::From(win);
-
-    pwin->NotifyContentBlockingState(
-      nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, aChannel);
+    nsCOMPtr<nsPIDOMWindowOuter> pwin;
+    if (aWindow) {
+      auto* outer = nsGlobalWindowOuter::Cast(aWindow->GetOuterWindow());
+      if (outer) {
+        pwin = outer->GetTopOuter();
+      }
+    } else if (aChannel) {
+      nsCOMPtr<mozIDOMWindowProxy> win;
+      nsresult rv = thirdPartyUtil->GetTopWindowForChannel(aChannel,
+                                                           getter_AddRefs(win));
+      NS_ENSURE_SUCCESS(rv, false);
+      pwin = nsPIDOMWindowOuter::From(win);
+    }
+
+    if (pwin) {
+      pwin->NotifyContentBlockingState(
+        nsIWebProgressListener::STATE_BLOCKED_TRACKING_COOKIES, aChannel);
+    }
   }
   return disabled;
 }
 
 // static, private
 nsContentUtils::StorageAccess
 nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
                                                    nsPIDOMWindowInner* aWindow,
@@ -8957,45 +8936,39 @@ nsContentUtils::InternalStorageAllowedFo
   StorageAccess access = StorageAccess::eAllow;
 
   // We don't allow storage on the null principal, in general. Even if the
   // calling context is chrome.
   if (aPrincipal->GetIsNullPrincipal()) {
     return StorageAccess::eDeny;
   }
 
-  if (StorageDisabledByAntiTracking(aWindow, aChannel, aURI)) {
-    return StorageAccess::eDeny;
-  }
-
   if (aWindow) {
     // If the document is sandboxed, then it is not permitted to use storage
     nsIDocument* document = aWindow->GetExtantDoc();
     if (document && document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
       return StorageAccess::eDeny;
     }
 
     // Check if we are in private browsing, and record that fact
     if (IsInPrivateBrowsing(document)) {
       access = StorageAccess::ePrivateBrowsing;
     }
   }
 
   uint32_t lifetimePolicy;
-  uint32_t behavior;
 
   // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
   // and ACCEPT_NORMALLY as lifetimePolicy (See Bug 1406675 for rationale).
   auto policy = BasePrincipal::Cast(aPrincipal)->AddonPolicy();
 
   if (policy) {
-    behavior = nsICookieService::BEHAVIOR_ACCEPT;
     lifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
   } else {
-    GetCookieBehaviorForPrincipal(aPrincipal, &lifetimePolicy, &behavior);
+    GetCookieLifetimePolicyForPrincipal(aPrincipal, &lifetimePolicy);
   }
 
   // Check if we should only allow storage for the session, and record that fact
   if (lifetimePolicy == nsICookieService::ACCEPT_SESSION) {
     // Storage could be StorageAccess::ePrivateBrowsing or StorageAccess::eAllow
     // so perform a std::min comparison to make sure we preserve ePrivateBrowsing
     // if it has been set.
     access = std::min(StorageAccess::eSessionScoped, access);
@@ -9031,29 +9004,17 @@ nsContentUtils::InternalStorageAllowedFo
   if (uri) {
     bool isAbout = false;
     MOZ_ALWAYS_SUCCEEDS(uri->SchemeIs("about", &isAbout));
     if (isAbout) {
       return access;
     }
   }
 
-  // We don't want to prompt for every attempt to access permissions.
-  if (behavior == nsICookieService::BEHAVIOR_REJECT) {
-    return StorageAccess::eDeny;
-  }
-
-  if ((behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
-       behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) &&
-      IsThirdPartyWindowOrChannel(aWindow, aChannel, aURI)) {
-    // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
-    // simply rejecting the request to use the storage. In the future, if we
-    // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
-    // for non-cookie storage types, this may change.
-
+  if (StorageDisabledByAntiTracking(aWindow, aChannel, aPrincipal, aURI)) {
     return StorageAccess::eDeny;
   }
 
   return access;
 }
 
 namespace {
 
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2946,21 +2946,23 @@ public:
   /*
    * Checks if storage for the given principal is permitted by the user's
    * preferences. The caller is assumed to not be a third-party iframe.
    * (if that is possible, the caller should use StorageAllowedForWindow)
    */
   static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal);
 
   /*
-   * Returns true if this window/channel should disable storages because of the
-   * anti-tracking feature.
+   * Returns true if this window/channel/aPrincipal should disable storages
+   * because of the anti-tracking feature.
+   * Note that either aWindow or aChannel may be null when calling this function.
    */
   static bool StorageDisabledByAntiTracking(nsPIDOMWindowInner* aWindow,
                                             nsIChannel* aChannel,
+                                            nsIPrincipal* aPrincipal,
                                             nsIURI* aURI);
 
   /*
    * Returns true if this window/channel is a 3rd party context.
    */
   static bool IsThirdPartyWindowOrChannel(nsPIDOMWindowInner* aWindow,
                                           nsIChannel* aChannel,
                                           nsIURI* aURI);
@@ -3337,24 +3339,23 @@ private:
                                                                       mozilla::dom::AutocompleteInfo& aInfo,
                                                                       bool aGrantAllValidValue = false);
 
   static bool CallOnAllRemoteChildren(mozilla::dom::MessageBroadcaster* aManager,
                                       CallOnRemoteChildFunction aCallback,
                                       void* aArg);
 
   /**
-   * Gets the current cookie lifetime policy and cookie behavior for a given
-   * principal by checking with preferences and the permission manager.
+   * Gets the current cookie lifetime policy for a given principal by checking
+   * with preferences and the permission manager.
    *
    * Used in the implementation of InternalStorageAllowedForPrincipal.
    */
-  static void GetCookieBehaviorForPrincipal(nsIPrincipal* aPrincipal,
-                                            uint32_t* aLifetimePolicy,
-                                            uint32_t* aBehavior);
+  static void GetCookieLifetimePolicyForPrincipal(nsIPrincipal* aPrincipal,
+                                                  uint32_t* aLifetimePolicy);
 
   /*
    * Checks if storage for a given principal is permitted by the user's
    * preferences. If aWindow is non-null, its principal must be passed as
    * aPrincipal, and the third-party iframe and sandboxing status of the window
    * are also checked.  If aURI is non-null, then it is used as the comparison
    * against aWindow to determine if this is a third-party load.  We also
    * allow a channel instead of the window reference when determining 3rd party
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -273,16 +273,17 @@
 
 #include "nsIURIClassifier.h"
 #include "nsIURIMutator.h"
 #include "mozilla/DocumentStyleRootIterator.h"
 #include "mozilla/RestyleManager.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "nsHTMLTags.h"
 #include "NodeUbiReporting.h"
+#include "nsICookieService.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 typedef nsTArray<Link*> LinkArray;
 
 static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
 static LazyLogModule gCspPRLog("CSP");
@@ -12638,17 +12639,18 @@ nsIDocument::SetDocTreeHadPlayRevoked()
   if (topLevelDoc) {
     topLevelDoc->mDocTreeHadPlayRevoked = true;
   }
 }
 
 void
 nsIDocument::MaybeAllowStorageForOpener()
 {
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
+  if (StaticPrefs::network_cookie_cookieBehavior() !=
+        nsICookieService::BEHAVIOR_REJECT_TRACKER) {
     return;
   }
 
   // This will probably change for project fission, but currently this document
   // and the opener are on the same process. In the future, we should make this
   // part async.
 
   nsPIDOMWindowInner* inner = GetInnerWindow();
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -3453,17 +3453,17 @@ nsGlobalWindowOuter::GetDevicePixelRatio
   }
 
   float overrideDPPX = presContext->GetOverrideDPPX();
 
   if (overrideDPPX > 0) {
     return overrideDPPX;
   }
 
-  return double(nsPresContext::AppUnitsPerCSSPixel()) /
+  return double(AppUnitsPerCSSPixel()) /
          double(presContext->AppUnitsPerDevPixel());
 }
 
 float
 nsPIDOMWindowOuter::GetDevicePixelRatio(CallerType aCallerType)
 {
   return nsGlobalWindowOuter::Cast(this)->GetDevicePixelRatioOuter(aCallerType);
 }
@@ -6999,17 +6999,17 @@ nsGlobalWindowOuter::OpenInternal(const 
 
     }
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // success!
 
-  if (!aCalledNoScript && !windowExists && uri) {
+  if (!aCalledNoScript && !windowExists && uri && !forceNoOpener) {
     MaybeAllowStorageForOpenedWindow(uri);
   }
 
   NS_ENSURE_TRUE(domReturn, NS_OK);
   nsCOMPtr<nsPIDOMWindowOuter> outerReturn =
     nsPIDOMWindowOuter::From(domReturn);
   outerReturn.swap(*aReturn);
 
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -12,20 +12,20 @@
 #include "mozilla/dom/StructuredCloneHolder.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRef.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/PBackgroundChild.h"
-#include "mozilla/StaticPrefs.h"
 #include "nsContentUtils.h"
 
 #include "nsIBFCacheEntry.h"
+#include "nsICookieService.h"
 #include "nsIDocument.h"
 #include "nsISupportsPrimitives.h"
 
 #ifdef XP_WIN
 #undef PostMessage
 #endif
 
 namespace mozilla {
@@ -68,22 +68,24 @@ GetPrincipalFromThreadSafeWorkerRef(Thre
 
   return wp->GetPrincipal();
 }
 
 class InitializeRunnable final : public WorkerMainThreadRunnable
 {
 public:
   InitializeRunnable(ThreadSafeWorkerRef* aWorkerRef, nsACString& aOrigin,
-                     PrincipalInfo& aPrincipalInfo, ErrorResult& aRv)
+                     PrincipalInfo& aPrincipalInfo, bool* aThirdPartyWindow,
+                     ErrorResult& aRv)
     : WorkerMainThreadRunnable(aWorkerRef->Private(),
                                NS_LITERAL_CSTRING("BroadcastChannel :: Initialize"))
     , mWorkerRef(aWorkerRef)
     , mOrigin(aOrigin)
     , mPrincipalInfo(aPrincipalInfo)
+    , mThirdPartyWindow(aThirdPartyWindow)
     , mRv(aRv)
   {
     MOZ_ASSERT(mWorkerRef);
   }
 
   bool MainThreadRun() override
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -111,23 +113,27 @@ public:
     }
 
     // Window doesn't exist for some kind of workers (eg: SharedWorkers)
     nsPIDOMWindowInner* window = wp->GetWindow();
     if (!window) {
       return true;
     }
 
+    *mThirdPartyWindow =
+      nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr, nullptr);
+
     return true;
   }
 
 private:
   RefPtr<ThreadSafeWorkerRef> mWorkerRef;
   nsACString& mOrigin;
   PrincipalInfo& mPrincipalInfo;
+  bool* mThirdPartyWindow;
   ErrorResult& mRv;
 };
 
 class CloseRunnable final : public nsIRunnable,
                             public nsICancelableRunnable
 {
 public:
   NS_DECL_ISUPPORTS
@@ -296,53 +302,56 @@ BroadcastChannel::Constructor(const Glob
       return nullptr;
     }
 
     aRv = PrincipalToPrincipalInfo(principal, &principalInfo);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
 
-    if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() &&
+    if (nsContentUtils::IsThirdPartyWindowOrChannel(window, nullptr,
+                                                    nullptr) &&
         nsContentUtils::StorageAllowedForWindow(window) !=
           nsContentUtils::StorageAccess::eAllow) {
       aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
       return nullptr;
     }
   } else {
     JSContext* cx = aGlobal.Context();
 
     WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
     MOZ_ASSERT(workerPrivate);
 
-    if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() &&
-        !workerPrivate->IsStorageAllowed()) {
-      aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
-      return nullptr;
-    }
-
     RefPtr<StrongWorkerRef> workerRef =
       StrongWorkerRef::Create(workerPrivate, "BroadcastChannel",
                               [bc] () { bc->Shutdown(); });
     // We are already shutting down the worker. Let's return a non-active
     // object.
     if (NS_WARN_IF(!workerRef)) {
       aRv.Throw(NS_ERROR_FAILURE);
       return nullptr;
     }
 
     RefPtr<ThreadSafeWorkerRef> tsr = new ThreadSafeWorkerRef(workerRef);
 
+    bool thirdPartyWindow = false;
+
     RefPtr<InitializeRunnable> runnable =
-      new InitializeRunnable(tsr, origin, principalInfo, aRv);
+      new InitializeRunnable(tsr, origin, principalInfo, &thirdPartyWindow,
+                             aRv);
     runnable->Dispatch(Canceling, aRv);
     if (aRv.Failed()) {
       return nullptr;
     }
 
+    if (thirdPartyWindow && !workerPrivate->IsStorageAllowed()) {
+      aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+      return nullptr;
+    }
+
     bc->mWorkerRef = std::move(workerRef);
   }
 
   // Register this component to PBackground.
   PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!actorChild)) {
     // Firefox is probably shutting down. Let's return a 'generic' error.
     aRv.Throw(NS_ERROR_FAILURE);
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2845,29 +2845,29 @@ public:
     , mExplicitLanguage(aExplicitLanguage)
     , mPresContext(aPresContext)
   {
   }
 
   virtual float GetEmLength() const override
   {
     return NSAppUnitsToFloatPixels(mFont.size,
-                                   nsPresContext::AppUnitsPerCSSPixel());
+                                   AppUnitsPerCSSPixel());
   }
 
   virtual float GetExLength() const override
   {
     nsDeviceContext* dc = mPresContext->DeviceContext();
     nsFontMetrics::Params params;
     params.language = mFontLanguage;
     params.explicitLanguage = mExplicitLanguage;
     params.textPerf = mPresContext->GetTextPerfMetrics();
     RefPtr<nsFontMetrics> fontMetrics = dc->GetMetricsFor(mFont, params);
     return NSAppUnitsToFloatPixels(fontMetrics->XHeight(),
-                                   nsPresContext::AppUnitsPerCSSPixel());
+                                   AppUnitsPerCSSPixel());
   }
 
   virtual gfx::Size GetSize() const override
   { return Size(mSize); }
 
 private:
   gfx::IntSize mSize;
   const nsFont& mFont;
@@ -3736,17 +3736,17 @@ CanvasRenderingContext2D::SetFontInterna
   nsFont resizedFont(fontStyle->mFont);
   // Create a font group working in units of CSS pixels instead of the usual
   // device pixels, to avoid being affected by page zoom. nsFontMetrics will
   // convert nsFont size in app units to device pixels for the font group, so
   // here we first apply to the size the equivalent of a conversion from device
   // pixels to CSS pixels, to adjust for the difference in expectations from
   // other nsFontMetrics clients.
   resizedFont.size =
-    (fontStyle->mSize * c->AppUnitsPerDevPixel()) / nsPresContext::AppUnitsPerCSSPixel();
+    (fontStyle->mSize * c->AppUnitsPerDevPixel()) / AppUnitsPerCSSPixel();
 
   nsFontMetrics::Params params;
   params.language = fontStyle->mLanguage;
   params.explicitLanguage = fontStyle->mExplicitLanguage;
   params.userFontSet = c->GetUserFontSet();
   params.textPerf = c->GetTextPerfMetrics();
   RefPtr<nsFontMetrics> metrics =
     c->DeviceContext()->GetMetricsFor(resizedFont, params);
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -1176,17 +1176,17 @@ protected:
 
     nsIPresShell *ps = GetPresShell();
     nsPresContext *pc;
 
     if (!ps) goto FINISH;
     pc = ps->GetPresContext();
     if (!pc) goto FINISH;
     devPixel = pc->AppUnitsPerDevPixel();
-    cssPixel = nsPresContext::AppUnitsPerCSSPixel();
+    cssPixel = AppUnitsPerCSSPixel();
 
   FINISH:
     if (aPerDevPixel)
       *aPerDevPixel = devPixel;
     if (aPerCSSPixel)
       *aPerCSSPixel = cssPixel;
   }
 
--- a/dom/events/WheelEvent.cpp
+++ b/dom/events/WheelEvent.cpp
@@ -70,37 +70,37 @@ WheelEvent::InitWheelEvent(const nsAStri
 
 double
 WheelEvent::DeltaX()
 {
   if (!mAppUnitsPerDevPixel) {
     return mEvent->AsWheelEvent()->mDeltaX;
   }
   return mEvent->AsWheelEvent()->mDeltaX *
-    mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel();
+    mAppUnitsPerDevPixel / AppUnitsPerCSSPixel();
 }
 
 double
 WheelEvent::DeltaY()
 {
   if (!mAppUnitsPerDevPixel) {
     return mEvent->AsWheelEvent()->mDeltaY;
   }
   return mEvent->AsWheelEvent()->mDeltaY *
-    mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel();
+    mAppUnitsPerDevPixel / AppUnitsPerCSSPixel();
 }
 
 double
 WheelEvent::DeltaZ()
 {
   if (!mAppUnitsPerDevPixel) {
     return mEvent->AsWheelEvent()->mDeltaZ;
   }
   return mEvent->AsWheelEvent()->mDeltaZ *
-    mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel();
+    mAppUnitsPerDevPixel / AppUnitsPerCSSPixel();
 }
 
 uint32_t
 WheelEvent::DeltaMode()
 {
   return mEvent->AsWheelEvent()->mDeltaMode;
 }
 
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1102,17 +1102,17 @@ nsHTMLDocument::GetCookie(nsAString& aCo
   // If the document's sandboxed origin flag is set, access to read cookies
   // is prohibited.
   if (mSandboxFlags & SANDBOXED_ORIGIN) {
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr,
-                                                    nullptr)) {
+                                                    NodePrincipal(), nullptr)) {
     return;
   }
 
   // If the document is a cookie-averse Document... return the empty string.
   if (IsCookieAverse()) {
     return;
   }
 
@@ -1157,17 +1157,17 @@ nsHTMLDocument::SetCookie(const nsAStrin
   // If the document's sandboxed origin flag is set, access to write cookies
   // is prohibited.
   if (mSandboxFlags & SANDBOXED_ORIGIN) {
     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   if (nsContentUtils::StorageDisabledByAntiTracking(GetInnerWindow(), nullptr,
-                                                    nullptr)) {
+                                                    NodePrincipal(), nullptr)) {
     return;
   }
 
   // If the document is a cookie-averse Document... do nothing.
   if (IsCookieAverse()) {
     return;
   }
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -142,17 +142,16 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIMemoryInfoDumper.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMozBrowserFrame.h"
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIParentChannel.h"
 #include "nsIPresShell.h"
-#include "nsIPromptService.h"
 #include "nsIRemoteWindowContext.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISiteSecurityService.h"
 #include "nsISound.h"
 #include "nsISpellChecker.h"
 #include "nsIStringBundle.h"
 #include "nsISupportsPrimitives.h"
@@ -5231,28 +5230,16 @@ ContentParent::RecvGraphicsError(const n
     std::stringstream message;
     message << "CP+" << aError.get();
     lf->UpdateStringsVector(message.str());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-ContentParent::RecvRecordReplayFatalError(const nsCString& aError)
-{
-  nsCOMPtr<nsIPromptService> promptService(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
-  MOZ_RELEASE_ASSERT(promptService);
-
-  nsAutoCString str(aError);
-  promptService->Alert(nullptr, u"Fatal Record/Replay Error", NS_ConvertUTF8toUTF16(str).get());
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 ContentParent::RecvBeginDriverCrashGuard(const uint32_t& aGuardType, bool* aOutCrashed)
 {
   // Only one driver crash guard should be active at a time, per-process.
   MOZ_ASSERT(!mDriverCrashGuard);
 
   UniquePtr<gfx::DriverCrashGuard> guard;
   switch (gfx::CrashGuardType(aGuardType)) {
   case gfx::CrashGuardType::D3D11Layers:
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1150,18 +1150,16 @@ public:
                                                           const TabId& aTabId,
                                                           layers::LayersId* aId) override;
 
   virtual mozilla::ipc::IPCResult RecvDeallocateLayerTreeId(const ContentParentId& aCpId,
                                                             const layers::LayersId& aId) override;
 
   virtual mozilla::ipc::IPCResult RecvGraphicsError(const nsCString& aError) override;
 
-  virtual mozilla::ipc::IPCResult RecvRecordReplayFatalError(const nsCString& aError) override;
-
   virtual mozilla::ipc::IPCResult
   RecvBeginDriverCrashGuard(const uint32_t& aGuardType,
                             bool* aOutCrashed) override;
 
   virtual mozilla::ipc::IPCResult RecvEndDriverCrashGuard(const uint32_t& aGuardType) override;
 
   virtual mozilla::ipc::IPCResult RecvAddIdleObserver(const uint64_t& observerId,
                                                       const uint32_t& aIdleTimeInS) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -933,19 +933,16 @@ parent:
     async RecordingDeviceEvents(nsString recordingStatus,
                                 nsString pageURL,
                                 bool isAudio,
                                 bool isVideo);
 
     // Graphics errors
     async GraphicsError(nsCString aError);
 
-    // Record/replay errors.
-    async RecordReplayFatalError(nsCString aError);
-
     // Driver crash guards. aGuardType must be a member of CrashGuardType.
     sync BeginDriverCrashGuard(uint32_t aGuardType) returns (bool crashDetected);
     sync EndDriverCrashGuard(uint32_t aGuardType);
 
     async AddIdleObserver(uint64_t observerId, uint32_t idleTimeInS);
     async RemoveIdleObserver(uint64_t observerId, uint32_t idleTimeInS);
 
     /**
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1178,17 +1178,17 @@ TabParent::SendRealMouseEvent(WidgetMous
 
 LayoutDeviceToCSSScale
 TabParent::GetLayoutDeviceToCSSScale()
 {
   nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
   nsIDocument* doc = (content ? content->OwnerDoc() : nullptr);
   nsPresContext* ctx = (doc ? doc->GetPresContext() : nullptr);
   return LayoutDeviceToCSSScale(ctx
-    ? (float)ctx->AppUnitsPerDevPixel() / nsPresContext::AppUnitsPerCSSPixel()
+    ? (float)ctx->AppUnitsPerDevPixel() / AppUnitsPerCSSPixel()
     : 0.0f);
 }
 
 bool
 TabParent::QueryDropLinksForVerification()
 {
   // Before sending the dragEvent, we query the links being dragged and
   // store them on the parent, to make sure the child can not modify links.
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1025,17 +1025,17 @@ NPBool nsPluginInstanceOwner::ConvertPoi
     if (destY) {
       *destY = sourceY;
     }
     return true;
   }
 
   nsPresContext* presContext = pluginFrame->PresContext();
   CSSToLayoutDeviceScale scaleFactor(
-    double(nsPresContext::AppUnitsPerCSSPixel()) /
+    double(AppUnitsPerCSSPixel()) /
     presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
 
   PuppetWidget *puppetWidget = static_cast<PuppetWidget*>(widget);
   PuppetWidget *rootWidget = static_cast<PuppetWidget*>(widget->GetTopLevelWidget());
   if (!rootWidget) {
     return false;
   }
   CSSIntPoint chromeSize = CSSIntPoint::Truncate(
@@ -1134,17 +1134,17 @@ NPBool nsPluginInstanceOwner::ConvertPoi
     }
     if (destY) {
       *destY = sourceY;
     }
     return true;
   }
 
   nsPresContext* presContext = pluginFrame->PresContext();
-  double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
+  double scaleFactor = double(AppUnitsPerCSSPixel())/
     presContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
 
   nsCOMPtr<nsIScreen> screen = widget->GetWidgetScreen();
   if (!screen) {
     return false;
   }
 
   int32_t screenX, screenY, screenWidth, screenHeight;
@@ -1944,17 +1944,17 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* 
       anEvent->mMessage == eMouseOver ||
       anEvent->mMessage == eMouseOut)
   {
     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(anEvent, aObjectFrame) -
                  aObjectFrame->GetContentRectRelativeToSelf().TopLeft();
     nsPresContext* presContext = aObjectFrame->PresContext();
     // Plugin event coordinates need to be translated from device pixels
     // into "display pixels" in HiDPI modes.
-    double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
+    double scaleFactor = double(AppUnitsPerCSSPixel())/
       aObjectFrame->PresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
     size_t intScaleFactor = ceil(scaleFactor);
     nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x) / intScaleFactor,
                     presContext->AppUnitsToDevPixels(pt.y) / intScaleFactor);
     cocoaEvent.data.mouse.pluginX = double(ptPx.x);
     cocoaEvent.data.mouse.pluginY = double(ptPx.y);
   }
 
@@ -3295,17 +3295,17 @@ nsPluginInstanceOwner::GetContentsScaleF
   double scaleFactor = 1.0;
   // On Mac, device pixels need to be translated to (and from) "display pixels"
   // for plugins. On other platforms, plugin coordinates are always in device
   // pixels.
 #if defined(XP_MACOSX) || defined(XP_WIN)
   nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
   nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
   if (presShell) {
-    scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
+    scaleFactor = double(AppUnitsPerCSSPixel())/
       presShell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
   }
 #endif
   *result = scaleFactor;
   return NS_OK;
 }
 
 void
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RuntimeService.h"
 
 #include "nsAutoPtr.h"
 #include "nsIChannel.h"
 #include "nsIContentSecurityPolicy.h"
+#include "nsICookieService.h"
 #include "nsIDocument.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIObserverService.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
@@ -2263,17 +2264,18 @@ RuntimeService::ResumeWorkersForWindow(n
   }
 }
 
 void
 RuntimeService::PropagateFirstPartyStorageAccessGranted(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aWindow);
-  MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
+  MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() ==
+               nsICookieService::BEHAVIOR_REJECT_TRACKER);
 
   nsTArray<WorkerPrivate*> workers;
   GetWorkersForWindow(aWindow, workers);
 
   for (uint32_t index = 0; index < workers.Length(); index++) {
     workers[index]->PropagateFirstPartyStorageAccessGranted();
   }
 }
@@ -2876,17 +2878,18 @@ ResumeWorkersForWindow(nsPIDOMWindowInne
     runtime->ResumeWorkersForWindow(aWindow);
   }
 }
 
 void
 PropagateFirstPartyStorageAccessGrantedToWorkers(nsPIDOMWindowInner* aWindow)
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT(StaticPrefs::privacy_restrict3rdpartystorage_enabled());
+  MOZ_ASSERT(StaticPrefs::network_cookie_cookieBehavior() ==
+               nsICookieService::BEHAVIOR_REJECT_TRACKER);
 
   RuntimeService* runtime = RuntimeService::GetService();
   if (runtime) {
     runtime->PropagateFirstPartyStorageAccessGranted(aWindow);
   }
 }
 
 WorkerPrivate*
--- a/gfx/layers/AnimationHelper.cpp
+++ b/gfx/layers/AnimationHelper.cpp
@@ -67,17 +67,17 @@ CompositorAnimationStorage::GetOMTAValue
       // Undo the rebasing applied by
       // nsDisplayTransform::GetResultingTransformMatrixInternal
       transform.ChangeBasis(-transformOrigin);
 
       // Convert to CSS pixels (this undoes the operations performed by
       // nsStyleTransformMatrix::ProcessTranslatePart which is called from
       // nsDisplayTransform::GetResultingTransformMatrix)
       double devPerCss =
-        double(scale) / double(nsDeviceContext::AppUnitsPerCSSPixel());
+        double(scale) / double(AppUnitsPerCSSPixel());
       transform._41 *= devPerCss;
       transform._42 *= devPerCss;
       transform._43 *= devPerCss;
       omtaValue = transform;
       break;
     }
     case AnimatedValue::NONE:
       break;
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -254,18 +254,18 @@ SetDisplayPortMargins(nsIPresShell* aPre
   nsLayoutUtils::SetDisplayPortMargins(aContent, aPresShell, margins, 0);
   if (!hadDisplayPort) {
     nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
         aContent->GetPrimaryFrame(), nsLayoutUtils::RepaintMode::Repaint);
   }
 
   CSSSize baseSize = aMetrics.CalculateCompositedSizeInCssPixels();
   nsRect base(0, 0,
-              baseSize.width * nsPresContext::AppUnitsPerCSSPixel(),
-              baseSize.height * nsPresContext::AppUnitsPerCSSPixel());
+              baseSize.width * AppUnitsPerCSSPixel(),
+              baseSize.height * AppUnitsPerCSSPixel());
   nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base);
 }
 
 static void
 SetPaintRequestTime(nsIContent* aContent, const TimeStamp& aPaintRequestTime)
 {
   aContent->SetProperty(nsGkAtoms::paintRequestTime,
                         new TimeStamp(aPaintRequestTime),
--- a/gfx/src/AppUnits.h
+++ b/gfx/src/AppUnits.h
@@ -5,12 +5,12 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_AppUnits_h
 #define mozilla_AppUnits_h
 
 #include <stdint.h>
 
 namespace mozilla {
-inline int32_t AppUnitsPerCSSPixel() { return 60; }
-inline int32_t AppUnitsPerCSSInch() { return 96 * AppUnitsPerCSSPixel(); }
+constexpr inline int32_t AppUnitsPerCSSPixel() { return 60; }
+constexpr inline int32_t AppUnitsPerCSSInch() { return 96 * AppUnitsPerCSSPixel(); }
 } // namespace mozilla
 #endif /* _NS_APPUNITS_H_ */
--- a/gfx/src/nsDeviceContext.h
+++ b/gfx/src/nsDeviceContext.h
@@ -77,22 +77,16 @@ public:
      * Create a reference rendering context and initialize it.  Only call this
      * method on device contexts that were initialized for printing.
      *
      * @return the new rendering context.
      */
     already_AddRefed<gfxContext> CreateReferenceRenderingContext();
 
     /**
-     * Gets the number of app units in one CSS pixel; this number is global,
-     * not unique to each device context.
-     */
-    static int32_t AppUnitsPerCSSPixel() { return mozilla::AppUnitsPerCSSPixel(); }
-
-    /**
      * Gets the number of app units in one device pixel; this number
      * is usually a factor of AppUnitsPerCSSPixel(), although that is
      * not guaranteed.
      */
     int32_t AppUnitsPerDevPixel() const { return mAppUnitsPerDevPixel; }
 
     /**
      * Convert device pixels which is used for gfx/thebes to nearest
@@ -110,22 +104,16 @@ public:
     /**
      * Gets the number of app units in one physical inch; this is the
      * device's DPI times AppUnitsPerDevPixel().
      */
     int32_t AppUnitsPerPhysicalInch() const
     { return mAppUnitsPerPhysicalInch; }
 
     /**
-     * Gets the number of app units in one CSS inch; this is
-     * 96 times AppUnitsPerCSSPixel.
-     */
-    static int32_t AppUnitsPerCSSInch() { return mozilla::AppUnitsPerCSSInch(); }
-
-    /**
      * Get the ratio of app units to dev pixels that would be used at unit
      * (100%) full zoom.
      */
     int32_t AppUnitsPerDevPixelAtUnitFullZoom() const
     { return mAppUnitsPerDevPixelAtUnitFullZoom; }
 
     /**
      * Get the nsFontMetrics that describe the properties of
--- a/gfx/src/nsFontMetrics.cpp
+++ b/gfx/src/nsFontMetrics.cpp
@@ -133,17 +133,17 @@ nsFontMetrics::nsFontMetrics(const nsFon
                        aFont.synthesis & NS_FONT_SYNTHESIS_WEIGHT,
                        aFont.synthesis & NS_FONT_SYNTHESIS_STYLE,
                        aFont.languageOverride);
 
     aFont.AddFontFeaturesToStyle(&style, mOrientation == gfxFont::eVertical);
     aFont.AddFontVariationsToStyle(&style);
 
     gfxFloat devToCssSize = gfxFloat(mP2A) /
-        gfxFloat(nsDeviceContext::AppUnitsPerCSSPixel());
+        gfxFloat(AppUnitsPerCSSPixel());
     mFontGroup = gfxPlatform::GetPlatform()->
         CreateFontGroup(aFont.fontlist, &style, aParams.textPerf,
                         aParams.userFontSet, devToCssSize);
 }
 
 nsFontMetrics::~nsFontMetrics()
 {
     // Should not be dropped by stylo
--- a/gfx/src/nsRect.cpp
+++ b/gfx/src/nsRect.cpp
@@ -40,24 +40,24 @@ bool nsRect::Overflows() const {
 
 FILE* operator<<(FILE* out, const nsRect& rect)
 {
   nsAutoString tmp;
 
   // Output the coordinates in fractional pixels so they're easier to read
   tmp.Append('{');
   tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.X(),
-                       nsDeviceContext::AppUnitsPerCSSPixel()));
+                       AppUnitsPerCSSPixel()));
   tmp.AppendLiteral(", ");
   tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.Y(),
-                       nsDeviceContext::AppUnitsPerCSSPixel()));
+                       AppUnitsPerCSSPixel()));
   tmp.AppendLiteral(", ");
   tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.Width(),
-                       nsDeviceContext::AppUnitsPerCSSPixel()));
+                       AppUnitsPerCSSPixel()));
   tmp.AppendLiteral(", ");
   tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.Height(),
-                       nsDeviceContext::AppUnitsPerCSSPixel()));
+                       AppUnitsPerCSSPixel()));
   tmp.Append('}');
   fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
   return out;
 }
 
 #endif // DEBUG
--- a/gfx/thebes/gfxFontMissingGlyphs.cpp
+++ b/gfx/thebes/gfxFontMissingGlyphs.cpp
@@ -254,17 +254,17 @@ gfxFontMissingGlyphs::DrawMissingGlyph(u
 
 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
     Point center = rect.Center();
     Float halfGap = HEX_CHAR_GAP / 2.f;
     Float top = -(MINIFONT_HEIGHT + halfGap);
     // We always want integer scaling, otherwise the "bitmap" glyphs will look
     // even uglier than usual when zoomed
     int32_t devPixelsPerCSSPx =
-        std::max<int32_t>(1, nsDeviceContext::AppUnitsPerCSSPixel() /
+        std::max<int32_t>(1, AppUnitsPerCSSPixel() /
                              aAppUnitsPerDevPixel);
 
     Matrix tempMat;
     if (aMat) {
         // If there is an orientation transform, since draw target transforms may
         // not be supported, scale and translate it so that it can be directly used
         // for rendering the mini font without changing the draw target transform.
         tempMat = Matrix(*aMat).PostScale(devPixelsPerCSSPx, devPixelsPerCSSPx)
@@ -332,11 +332,11 @@ gfxFontMissingGlyphs::GetDesiredMinWidth
  * like this so you can see what goes where.
  */
     Float width = BOX_HORIZONTAL_INSET + BOX_BORDER_WIDTH + HEX_CHAR_GAP +
         MINIFONT_WIDTH + HEX_CHAR_GAP + MINIFONT_WIDTH +
          ((aChar < 0x10000) ? 0 : HEX_CHAR_GAP + MINIFONT_WIDTH) +
         HEX_CHAR_GAP + BOX_BORDER_WIDTH + BOX_HORIZONTAL_INSET;
     // Note that this will give us floating-point division, so the width will
     // -not- be snapped to integer multiples of its basic pixel value
-    width *= Float(nsDeviceContext::AppUnitsPerCSSPixel()) / aAppUnitsPerDevPixel;
+    width *= Float(AppUnitsPerCSSPixel()) / aAppUnitsPerDevPixel;
     return width;
 }
--- a/image/ClippedImage.cpp
+++ b/image/ClippedImage.cpp
@@ -148,17 +148,17 @@ ClippedImage::ClippedImage(Image* aImage
   : ImageWrapper(aImage)
   , mClip(aClip)
 {
   MOZ_ASSERT(aImage != nullptr, "ClippedImage requires an existing Image");
   MOZ_ASSERT_IF(aSVGViewportSize,
                 aImage->GetType() == imgIContainer::TYPE_VECTOR);
   if (aSVGViewportSize) {
     mSVGViewportSize = Some(aSVGViewportSize->ToNearestPixels(
-                                        nsPresContext::AppUnitsPerCSSPixel()));
+                                        AppUnitsPerCSSPixel()));
   }
 }
 
 ClippedImage::~ClippedImage()
 { }
 
 bool
 ClippedImage::ShouldClip()
--- a/image/ImageCacheKey.cpp
+++ b/image/ImageCacheKey.cpp
@@ -3,23 +3,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ImageCacheKey.h"
 
 #include "mozilla/HashFunctions.h"
 #include "mozilla/Move.h"
 #include "nsContentUtils.h"
+#include "nsICookieService.h"
 #include "nsLayoutUtils.h"
 #include "nsString.h"
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
-#include "mozilla/StaticPrefs.h"
 #include "nsIDocument.h"
 #include "nsPrintfCString.h"
 
 namespace mozilla {
 
 using namespace dom;
 
 namespace image {
@@ -136,39 +136,33 @@ ImageCacheKey::GetSpecialCaseDocumentTok
 
   // For controlled documents, we cast the pointer into a void* to avoid
   // dereferencing it (since we only use it for comparisons).
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   if (swm && aDocument->GetController().isSome()) {
     return aDocument;
   }
 
-  // We want to have a unique image cache if the anti-tracking feature is
-  // enabled for 3rd party resources.
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled() ||
-      !nsContentUtils::IsThirdPartyWindowOrChannel(aDocument->GetInnerWindow(),
-                                                   nullptr, aURI)) {
-    return nullptr;
-  }
-
-  // If the window is 3rd party resource, let's see if the first party storage
-  // access is granted for this image.
-  if (nsContentUtils::IsTrackingResourceWindow(aDocument->GetInnerWindow())) {
-    return nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(),
-                                                         nullptr, aURI)
-             ? aDocument : nullptr;
+  // If we must disable the storage, we want to create a unique cache key for
+  // this image.
+  if (nsContentUtils::StorageDisabledByAntiTracking(aDocument->GetInnerWindow(),
+                                                    nullptr,
+                                                    aDocument->NodePrincipal(),
+                                                    aURI)) {
+    return aDocument;
   }
 
   // Another scenario is if this image is a 3rd party resource loaded by a
   // first party context. In this case, we should check if the nsIChannel has
   // been marked as tracking resource, but we don't have the channel yet at
   // this point.  The best approach here is to be conservative: if we are sure
   // that the permission is granted, let's return a nullptr. Otherwise, let's
   // make a unique image cache.
-  if (!AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(),
+  if (!aDocument->IsCookieAverse() &&
+      !AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(aDocument->GetInnerWindow(),
                                                                     aURI)) {
     return aDocument;
   }
 
   return nullptr;
 }
 
 } // namespace image
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -10173,15 +10173,19 @@ GeneralParser<ParseHandler, CharT>::expr
                                                  PossibleError* possibleError /* = nullptr */)
 {
     MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lp));
     return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
 }
 
 template class PerHandlerParser<FullParseHandler>;
 template class PerHandlerParser<SyntaxParseHandler>;
+template class GeneralParser<FullParseHandler, Utf8Unit>;
+template class GeneralParser<SyntaxParseHandler, Utf8Unit>;
 template class GeneralParser<FullParseHandler, char16_t>;
 template class GeneralParser<SyntaxParseHandler, char16_t>;
+template class Parser<FullParseHandler, Utf8Unit>;
+template class Parser<SyntaxParseHandler, Utf8Unit>;
 template class Parser<FullParseHandler, char16_t>;
 template class Parser<SyntaxParseHandler, char16_t>;
 
 } /* namespace frontend */
 } /* namespace js */
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -1415,16 +1415,27 @@ if test -n "$MOZ_OPTIMIZE"; then
         [printf("Hello World\n");],
         _results=yes,
         _results=no)
     AC_MSG_RESULT([$_results])
     if test "$_results" = "no"; then
         AC_MSG_ERROR([These compiler flags are invalid: $MOZ_OPTIMIZE_FLAGS])
     fi
     CFLAGS=$_SAVE_CFLAGS
+    if test -n "$MOZ_LTO" -a -n "$CLANG_CC"; then
+        # When using llvm-based LTO, non numeric optimization levels are
+        # not supported by the linker, so force the linker to use -O2 (
+        # which doesn't influence the level compilation units are actually
+        # compiled at).
+        case " $MOZ_OPTIMIZE_FLAGS " in
+        *\ -Os\ *|*\ -Oz\ *)
+            MOZ_OPTIMIZE_LDFLAGS="$MOZ_OPTIMIZE_LDFLAGS -O2"
+            ;;
+        esac
+    fi
 fi
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST_LIST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST_LIST(MOZ_OPTIMIZE_FLAGS)
 AC_SUBST_LIST(MOZ_OPTIMIZE_LDFLAGS)
 AC_SUBST_LIST(MOZ_PGO_OPTIMIZE_FLAGS)
 
--- a/layout/base/AccessibleCaretEventHub.cpp
+++ b/layout/base/AccessibleCaretEventHub.cpp
@@ -614,17 +614,17 @@ AccessibleCaretEventHub::HandleKeyboardE
   return nsEventStatus_eIgnore;
 }
 
 bool
 AccessibleCaretEventHub::MoveDistanceIsLarge(const nsPoint& aPoint) const
 {
   nsPoint delta = aPoint - mPressPoint;
   return NS_hypot(delta.x, delta.y) >
-         nsPresContext::AppUnitsPerCSSPixel() * kMoveStartToleranceInPixel;
+         AppUnitsPerCSSPixel() * kMoveStartToleranceInPixel;
 }
 
 void
 AccessibleCaretEventHub::LaunchLongTapInjector()
 {
   if (!mLongTapInjectorTimer) {
     return;
   }
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4674,17 +4674,17 @@ PresShell::RenderDocument(const nsRect& 
   MOZ_ASSERT(aThebesContext->CurrentOp() == CompositionOp::OP_OVER);
 
   aThebesContext->Clip();
 
   nsDeviceContext* devCtx = mPresContext->DeviceContext();
 
   gfxPoint offset(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
                   -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y));
-  gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel();
+  gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/AppUnitsPerCSSPixel();
 
   // Since canvas APIs use floats to set up their matrices, we may have some
   // slight rounding errors here.  We use NudgeToIntegers() here to adjust
   // matrix components that are integers up to the accuracy of floats to be
   // those integers.
   gfxMatrix newTM = aThebesContext->CurrentMatrixDouble().PreTranslate(offset).
                                                           PreScale(scale, scale).
                                                           NudgeToIntegers();
@@ -5068,17 +5068,17 @@ PresShell::PaintRangePaintInfo(const nsT
   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
   MOZ_ASSERT(ctx); // already checked the draw target above
 
   if (aRegion) {
     RefPtr<PathBuilder> builder = dt->CreatePathBuilder(FillRule::FILL_WINDING);
 
     // Convert aRegion from CSS pixels to dev pixels
     nsIntRegion region =
-        aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel())
+        aRegion->ToAppUnits(AppUnitsPerCSSPixel())
           .ToOutsidePixels(pc->AppUnitsPerDevPixel());
     for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
       const IntRect& rect = iter.Get();
 
       builder->MoveTo(rect.TopLeft());
       builder->LineTo(rect.TopRight());
       builder->LineTo(rect.BottomRight());
       builder->LineTo(rect.BottomLeft());
@@ -5163,17 +5163,17 @@ PresShell::RenderNode(nsINode* aNode,
     return nullptr;
   }
 
   Maybe<CSSIntRegion> region = aRegion;
   if (region) {
     // combine the area with the supplied region
     CSSIntRect rrectPixels = region->GetBounds();
 
-    nsRect rrect = ToAppUnits(rrectPixels, nsPresContext::AppUnitsPerCSSPixel());
+    nsRect rrect = ToAppUnits(rrectPixels, AppUnitsPerCSSPixel());
     area.IntersectRect(area, rrect);
 
     nsPresContext* pc = GetPresContext();
     if (!pc)
       return nullptr;
 
     // move the region so that it is offset from the topleft corner of the surface
     region->MoveBy(-nsPresContext::AppUnitsToIntCSSPixels(area.x),
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -3923,17 +3923,17 @@ nsDocumentViewer::Print(nsIPrintSettings
   // Release()'d in Destroy().  Therefore, we need to grab the instance with
   // a local variable, so that it won't be deleted during its own method.
   RefPtr<nsPrintJob> printJob = mPrintJob;
   if (!printJob) {
     NS_ENSURE_STATE(mDeviceContext);
     printJob = new nsPrintJob();
 
     rv = printJob->Initialize(this, mContainer, mDocument,
-                              float(mDeviceContext->AppUnitsPerCSSInch()) /
+                              float(AppUnitsPerCSSInch()) /
                               float(mDeviceContext->AppUnitsPerDevPixel()) /
                               mPageZoom);
     if (NS_FAILED(rv)) {
       printJob->Destroy();
       return rv;
     }
     mPrintJob = printJob;
   }
@@ -4007,17 +4007,17 @@ nsDocumentViewer::PrintPreview(nsIPrintS
   // Our call to nsPrintJob::PrintPreview() may cause mPrintJob to be
   // Release()'d in Destroy().  Therefore, we need to grab the instance with
   // a local variable, so that it won't be deleted during its own method.
   RefPtr<nsPrintJob> printJob = mPrintJob;
   if (!printJob) {
     printJob = new nsPrintJob();
 
     rv = printJob->Initialize(this, mContainer, doc,
-                              float(mDeviceContext->AppUnitsPerCSSInch()) /
+                              float(AppUnitsPerCSSInch()) /
                               float(mDeviceContext->AppUnitsPerDevPixel()) /
                               mPageZoom);
     if (NS_FAILED(rv)) {
       printJob->Destroy();
       return rv;
     }
     mPrintJob = printJob;
   }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6882,17 +6882,17 @@ nsLayoutUtils::DrawSingleImage(gfxContex
                                const SamplingFilter   aSamplingFilter,
                                const nsRect&          aDest,
                                const nsRect&          aDirty,
                                const Maybe<SVGImageContext>& aSVGContext,
                                uint32_t               aImageFlags,
                                const nsPoint*         aAnchorPoint,
                                const nsRect*          aSourceArea)
 {
-  nscoord appUnitsPerCSSPixel = nsDeviceContext::AppUnitsPerCSSPixel();
+  nscoord appUnitsPerCSSPixel = AppUnitsPerCSSPixel();
   CSSIntSize pixelImageSize(ComputeSizeForDrawingWithFallback(aImage, aDest.Size()));
   if (pixelImageSize.width < 1 || pixelImageSize.height < 1) {
     NS_ASSERTION(pixelImageSize.width >= 0 && pixelImageSize.height >= 0,
                  "Image width or height is negative");
     return ImgDrawResult::SUCCESS;  // no point in drawing a zero size image
   }
 
   nsSize imageSize(CSSPixel::ToAppUnits(pixelImageSize));
@@ -9845,17 +9845,17 @@ ComputeSVGReferenceRect(nsIFrame* aFrame
   switch (aGeometryBox) {
     case StyleGeometryBox::StrokeBox: {
       // XXX Bug 1299876
       // The size of srtoke-box is not correct if this graphic element has
       // specific stroke-linejoin or stroke-linecap.
       gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
                 nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke);
       r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
-                                         nsPresContext::AppUnitsPerCSSPixel());
+                                         AppUnitsPerCSSPixel());
       break;
     }
     case StyleGeometryBox::ViewBox: {
       nsIContent* content = aFrame->GetContent();
       nsSVGElement* element = static_cast<nsSVGElement*>(content);
       SVGViewportElement* svgElement = element->GetCtx();
       MOZ_ASSERT(svgElement);
 
@@ -9887,25 +9887,25 @@ ComputeSVGReferenceRect(nsIFrame* aFrame
     case StyleGeometryBox::BorderBox:
     case StyleGeometryBox::ContentBox:
     case StyleGeometryBox::PaddingBox:
     case StyleGeometryBox::MarginBox:
     case StyleGeometryBox::FillBox: {
       gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
                                          nsSVGUtils::eBBoxIncludeFill);
       r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
-                                         nsPresContext::AppUnitsPerCSSPixel());
+                                         AppUnitsPerCSSPixel());
       break;
     }
     default:{
       MOZ_ASSERT_UNREACHABLE("unknown StyleGeometryBox type");
       gfxRect bbox = nsSVGUtils::GetBBox(aFrame,
                                          nsSVGUtils::eBBoxIncludeFill);
       r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
-                                         nsPresContext::AppUnitsPerCSSPixel());
+                                         AppUnitsPerCSSPixel());
       break;
     }
   }
 
   return r;
 }
 
 static nsRect
@@ -10079,17 +10079,17 @@ nsLayoutUtils::ApplyMinFontSize(nsStyleF
 
 /* static */ void
 nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont, LookAndFeel::FontID aFontID,
                                  const nsPresContext* aPresContext,
                                  const nsFont* aDefaultVariableFont)
 {
   gfxFontStyle fontStyle;
   float devPerCSS =
-    (float)nsPresContext::AppUnitsPerCSSPixel() /
+    (float)AppUnitsPerCSSPixel() /
     aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
   nsAutoString systemFontName;
   if (LookAndFeel::GetFont(aFontID, systemFontName, fontStyle, devPerCSS)) {
     systemFontName.Trim("\"'");
     aSystemFont->fontlist = FontFamilyList(systemFontName, eUnquotedName);
     aSystemFont->fontlist.SetDefaultFontType(eFamily_none);
     aSystemFont->style = fontStyle.style;
     aSystemFont->systemFont = fontStyle.systemFont;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -653,39 +653,37 @@ public:
    *
    * If |aChanged| is non-null, then aChanged is filled in with whether
    * the screen size value has changed since either:
    *  a. the last time the function was called with non-null aChanged, or
    *  b. the first time the function was called.
    */
   gfxSize ScreenSizeInchesForFontInflation(bool* aChanged = nullptr);
 
-  static int32_t AppUnitsPerCSSPixel() { return mozilla::AppUnitsPerCSSPixel(); }
   int32_t AppUnitsPerDevPixel() const;
-  static int32_t AppUnitsPerCSSInch() { return mozilla::AppUnitsPerCSSInch(); }
 
   static nscoord CSSPixelsToAppUnits(int32_t aPixels)
   { return NSToCoordRoundWithClamp(float(aPixels) *
-             float(AppUnitsPerCSSPixel())); }
+             float(mozilla::AppUnitsPerCSSPixel())); }
 
   static nscoord CSSPixelsToAppUnits(float aPixels)
   { return NSToCoordRoundWithClamp(aPixels *
-             float(AppUnitsPerCSSPixel())); }
+             float(mozilla::AppUnitsPerCSSPixel())); }
 
   static int32_t AppUnitsToIntCSSPixels(nscoord aAppUnits)
   { return NSAppUnitsToIntPixels(aAppUnits,
-             float(AppUnitsPerCSSPixel())); }
+             float(mozilla::AppUnitsPerCSSPixel())); }
 
   static float AppUnitsToFloatCSSPixels(nscoord aAppUnits)
   { return NSAppUnitsToFloatPixels(aAppUnits,
-             float(AppUnitsPerCSSPixel())); }
+             float(mozilla::AppUnitsPerCSSPixel())); }
 
   static double AppUnitsToDoubleCSSPixels(nscoord aAppUnits)
   { return NSAppUnitsToDoublePixels(aAppUnits,
-             double(AppUnitsPerCSSPixel())); }
+             double(mozilla::AppUnitsPerCSSPixel())); }
 
   nscoord DevPixelsToAppUnits(int32_t aPixels) const
   { return NSIntPixelsToAppUnits(aPixels, AppUnitsPerDevPixel()); }
 
   int32_t AppUnitsToDevPixels(nscoord aAppUnits) const
   { return NSAppUnitsToIntPixels(aAppUnits,
              float(AppUnitsPerDevPixel())); }
 
@@ -705,17 +703,17 @@ public:
   { return AppUnitsToIntCSSPixels(DevPixelsToAppUnits(aPixels)); }
 
   float DevPixelsToFloatCSSPixels(int32_t aPixels)
   { return AppUnitsToFloatCSSPixels(DevPixelsToAppUnits(aPixels)); }
 
   mozilla::CSSToLayoutDeviceScale CSSToDevPixelScale() const
   {
     return mozilla::CSSToLayoutDeviceScale(
-        float(AppUnitsPerCSSPixel()) / float(AppUnitsPerDevPixel()));
+        float(mozilla::AppUnitsPerCSSPixel()) / float(AppUnitsPerDevPixel()));
   }
 
   // If there is a remainder, it is rounded to nearest app units.
   nscoord GfxUnitsToAppUnits(gfxFloat aGfxUnits) const;
 
   gfxFloat AppUnitsToGfxUnits(nscoord aAppUnits) const;
 
   gfxRect AppUnitsToGfxUnits(const nsRect& aAppRect) const
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -6827,17 +6827,17 @@ nsIFrame::GetTransformMatrix(const nsIFr
    * shift us to our parent.
    */
   if (IsTransformed()) {
     /* Compute the delta to the parent, which we need because we are converting
      * coordinates to our parent.
      */
     NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
                  "Cannot transform the viewport frame!");
-    int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel()
+    int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? AppUnitsPerCSSPixel()
                                                    : PresContext()->AppUnitsPerDevPixel());
 
     Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this,
                          nsPoint(0,0), scaleFactor,
                          nsDisplayTransform::INCLUDE_PERSPECTIVE|nsDisplayTransform::OFFSET_BY_ORIGIN,
                          nullptr);
     *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
     nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
@@ -6917,17 +6917,17 @@ nsIFrame::GetTransformMatrix(const nsIFr
   }
 
   NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
 
   /* Translate from this frame to our ancestor, if it exists.  That's the
    * entire transform, so we're done.
    */
   nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
-  int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel()
+  int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? AppUnitsPerCSSPixel()
                                                  : PresContext()->AppUnitsPerDevPixel());
   return Matrix4x4::Translation(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
                                 NSAppUnitsToFloatPixels(delta.y, scaleFactor),
                                 0.0f);
 }
 
 static void InvalidateRenderingObservers(nsIFrame* aDisplayRoot, nsIFrame* aFrame, bool aFrameChanged = true)
 {
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2857,19 +2857,19 @@ ScrollFrameHelper::ScrollToImpl(nsPoint 
   }
 
   bool needFrameVisibilityUpdate = mLastUpdateFramesPos == nsPoint(-1,-1);
 
   nsPoint dist(std::abs(pt.x - mLastUpdateFramesPos.x),
                std::abs(pt.y - mLastUpdateFramesPos.y));
   nsSize visualViewportSize = GetVisualViewportSize();
   nscoord horzAllowance = std::max(visualViewportSize.width / std::max(sHorzScrollFraction, 1),
-                                   nsPresContext::AppUnitsPerCSSPixel());
+                                   AppUnitsPerCSSPixel());
   nscoord vertAllowance = std::max(visualViewportSize.height / std::max(sVertScrollFraction, 1),
-                                   nsPresContext::AppUnitsPerCSSPixel());
+                                   AppUnitsPerCSSPixel());
   if (dist.x >= horzAllowance || dist.y >= vertAllowance) {
     needFrameVisibilityUpdate = true;
   }
 
   // notify the listeners.
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->ScrollPositionWillChange(pt.x, pt.y);
   }
--- a/layout/painting/ActiveLayerTracker.cpp
+++ b/layout/painting/ActiveLayerTracker.cpp
@@ -258,17 +258,17 @@ IncrementScaleRestyleCountIfNeeded(nsIFr
   }
 
   // Compute the new scale due to the CSS transform property.
   bool dummyBool;
   nsStyleTransformMatrix::TransformReferenceBox refBox(aFrame);
   Matrix4x4 transform =
     nsStyleTransformMatrix::ReadTransforms(transformList->mHead,
                                            refBox,
-                                           nsPresContext::AppUnitsPerCSSPixel(),
+                                           AppUnitsPerCSSPixel(),
                                            &dummyBool);
   Matrix transform2D;
   if (!transform.Is2D(&transform2D)) {
     // We don't attempt to handle 3D transforms; just assume the scale changed.
     aActivity->mPreviousTransformScale = Nothing();
     IncrementMutationCount(&aActivity->mRestyleCounts[LayerActivity::ACTIVITY_SCALE]);
     return;
   }
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3648,17 +3648,17 @@ nsCSSBorderImageRenderer::DrawBorderImag
         fillStyleV = StyleBorderImageRepeat::Stretch;
       }
 
       nsRect destArea(borderX[i], borderY[j], borderWidth[i], borderHeight[j]);
       nsRect subArea(sliceX[i], sliceY[j], sliceWidth[i], sliceHeight[j]);
       if (subArea.IsEmpty())
         continue;
 
-      nsIntRect intSubArea = subArea.ToOutsidePixels(nsPresContext::AppUnitsPerCSSPixel());
+      nsIntRect intSubArea = subArea.ToOutsidePixels(AppUnitsPerCSSPixel());
       result &=
         mImageRenderer.DrawBorderImageComponent(aPresContext,
                                                  aRenderingContext, aDirtyRect,
                                                  destArea, CSSIntRect(intSubArea.x,
                                                                       intSubArea.y,
                                                                       intSubArea.width,
                                                                       intSubArea.height),
                                                  fillStyleH, fillStyleV,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -7924,34 +7924,34 @@ nsDisplayTransform::GetResultingTransfor
                                      &parentsChildrenOnlyTransform);
   /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
   if (aProperties.mTransformList) {
     result = nsStyleTransformMatrix::ReadTransforms(aProperties.mTransformList->mHead,
                                                     refBox, aAppUnitsPerPixel,
                                                     &dummyBool);
   } else if (hasSVGTransforms) {
     // Correct the translation components for zoom:
-    float pixelsPerCSSPx = frame->PresContext()->AppUnitsPerCSSPixel() /
+    float pixelsPerCSSPx = AppUnitsPerCSSPixel() /
                              aAppUnitsPerPixel;
     svgTransform._31 *= pixelsPerCSSPx;
     svgTransform._32 *= pixelsPerCSSPx;
     result = Matrix4x4::From2D(svgTransform);
   }
 
   // Apply any translation due to 'transform-origin' and/or 'transform-box':
   result.ChangeBasis(aProperties.mToTransformOrigin);
 
   // See the comment for nsSVGContainerFrame::HasChildrenOnlyTransform for
   // an explanation of what children-only transforms are.
   bool parentHasChildrenOnlyTransform =
     hasSVGTransforms && !parentsChildrenOnlyTransform.IsIdentity();
 
   if (parentHasChildrenOnlyTransform) {
     float pixelsPerCSSPx =
-      frame->PresContext()->AppUnitsPerCSSPixel() / aAppUnitsPerPixel;
+      AppUnitsPerCSSPixel() / aAppUnitsPerPixel;
     parentsChildrenOnlyTransform._31 *= pixelsPerCSSPx;
     parentsChildrenOnlyTransform._32 *= pixelsPerCSSPx;
 
     Point3D frameOffset(
       NSAppUnitsToFloatPixels(-frame->GetPosition().x, aAppUnitsPerPixel),
       NSAppUnitsToFloatPixels(-frame->GetPosition().y, aAppUnitsPerPixel),
       0);
     Matrix4x4 parentsChildrenOnlyTransform3D =
@@ -8104,17 +8104,17 @@ nsDisplayTransform::ShouldPrerenderTrans
     *aDirtyRect = overflow;
     return FullPrerender;
   } else if (gfxPrefs::PartiallyPrerenderAnimatedContent()) {
     *aDirtyRect = nsLayoutUtils::ComputePartialPrerenderArea(*aDirtyRect, overflow, maxSize);
     return PartialPrerender;
   }
 
   if (frameArea > maxLimitArea) {
-    uint64_t appUnitsPerPixel = nsPresContext::AppUnitsPerCSSPixel();
+    uint64_t appUnitsPerPixel = AppUnitsPerCSSPixel();
     EffectCompositor::SetPerformanceWarning(
       aFrame, eCSSProperty_transform,
       AnimationPerformanceWarning(
         AnimationPerformanceWarning::Type::ContentTooLargeArea,
         {
           int(frameArea / (appUnitsPerPixel * appUnitsPerPixel)),
           int(maxLimitArea / (appUnitsPerPixel * appUnitsPerPixel)),
         }));
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -378,23 +378,23 @@ nsImageRenderer::ComputeConstrainedSize(
   float scaleY = double(aConstrainingSize.height) / aIntrinsicRatio.height;
   nsSize size;
   if ((aFitType == CONTAIN) == (scaleX < scaleY)) {
     size.width = aConstrainingSize.width;
     size.height = NSCoordSaturatingNonnegativeMultiply(
                     aIntrinsicRatio.height, scaleX);
     // If we're reducing the size by less than one css pixel, then just use the
     // constraining size.
-    if (aFitType == CONTAIN && aConstrainingSize.height - size.height < nsPresContext::AppUnitsPerCSSPixel()) {
+    if (aFitType == CONTAIN && aConstrainingSize.height - size.height < AppUnitsPerCSSPixel()) {
       size.height = aConstrainingSize.height;
     }
   } else {
     size.width = NSCoordSaturatingNonnegativeMultiply(
                    aIntrinsicRatio.width, scaleY);
-    if (aFitType == CONTAIN && aConstrainingSize.width - size.width < nsPresContext::AppUnitsPerCSSPixel()) {
+    if (aFitType == CONTAIN && aConstrainingSize.width - size.width < AppUnitsPerCSSPixel()) {
       size.width = aConstrainingSize.width;
     }
     size.height = aConstrainingSize.height;
   }
   return size;
 }
 
 /**
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -1694,17 +1694,17 @@ nsPrintJob::ReconstructAndReflow(bool do
       "mPresContext and mPresShell shouldn't be nullptr when the print object "
       "has been marked as \"print the document\"");
 
     UpdateZoomRatio(po, doSetPixelScale);
 
     po->mPresContext->SetPageScale(po->mZoomRatio);
 
     // Calculate scale factor from printer to screen
-    float printDPI = float(printData->mPrintDC->AppUnitsPerCSSInch()) /
+    float printDPI = float(AppUnitsPerCSSInch()) /
                        float(printData->mPrintDC->AppUnitsPerDevPixel());
     po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
 
     po->mPresShell->ReconstructFrames();
 
     // If the printing was canceled or restarted with different data,
     // let's stop doing this printing.
     if (NS_WARN_IF(mPrt != printData)) {
@@ -2383,17 +2383,17 @@ nsPrintJob::ReflowPrintObject(const Uniq
 
   aPO->mPresShell->BeginObservingDocument();
 
   aPO->mPresContext->SetPageSize(adjSize);
   aPO->mPresContext->SetVisibleArea(nsRect(0, 0, adjSize.width, adjSize.height));
   aPO->mPresContext->SetIsRootPaginatedDocument(documentIsTopLevel);
   aPO->mPresContext->SetPageScale(aPO->mZoomRatio);
   // Calculate scale factor from printer to screen
-  float printDPI = float(printData->mPrintDC->AppUnitsPerCSSInch()) /
+  float printDPI = float(AppUnitsPerCSSInch()) /
                      float(printData->mPrintDC->AppUnitsPerDevPixel());
   aPO->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
 
   if (mIsCreatingPrintPreview && documentIsTopLevel) {
     mDocViewerPrint->SetPrintPreviewPresentation(aPO->mViewManager,
                                                  aPO->mPresContext,
                                                  aPO->mPresShell);
   }
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -290,17 +290,17 @@ GetResolution(nsIDocument* aDocument, co
   float dppx = 1.;
 
   if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) {
     if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
       dppx = dx->GetFullZoom();
     } else {
       // Get the actual device pixel ratio, which also takes zoom into account.
       dppx =
-        float(nsPresContext::AppUnitsPerCSSPixel()) / dx->AppUnitsPerDevPixel();
+        float(AppUnitsPerCSSPixel()) / dx->AppUnitsPerDevPixel();
     }
   }
 
   aResult.SetFloatValue(dppx, eCSSUnit_Pixel);
 }
 
 static void
 GetScan(nsIDocument* aDocument, const nsMediaFeature*,
--- a/layout/style/nsROCSSPrimitiveValue.cpp
+++ b/layout/style/nsROCSSPrimitiveValue.cpp
@@ -259,45 +259,41 @@ nsROCSSPrimitiveValue::GetFloatValue(uin
     case CSS_PX:
       if (mType == CSS_PX) {
         return nsPresContext::AppUnitsToFloatCSSPixels(mValue.mAppUnits);
       }
 
       break;
     case CSS_CM:
       if (mType == CSS_PX) {
-        return mValue.mAppUnits * CM_PER_INCH_FLOAT /
-          nsPresContext::AppUnitsPerCSSInch();
+        return mValue.mAppUnits * CM_PER_INCH_FLOAT / AppUnitsPerCSSInch();
       }
 
       break;
     case CSS_MM:
       if (mType == CSS_PX) {
-        return mValue.mAppUnits * MM_PER_INCH_FLOAT /
-          nsPresContext::AppUnitsPerCSSInch();
+        return mValue.mAppUnits * MM_PER_INCH_FLOAT / AppUnitsPerCSSInch();
       }
 
       break;
     case CSS_IN:
       if (mType == CSS_PX) {
-        return mValue.mAppUnits / nsPresContext::AppUnitsPerCSSInch();
+        return mValue.mAppUnits / AppUnitsPerCSSInch();
       }
 
       break;
     case CSS_PT:
       if (mType == CSS_PX) {
-        return mValue.mAppUnits * POINTS_PER_INCH_FLOAT /
-          nsPresContext::AppUnitsPerCSSInch();
+        return mValue.mAppUnits * POINTS_PER_INCH_FLOAT / AppUnitsPerCSSInch();
       }
 
       break;
     case CSS_PC:
       if (mType == CSS_PX) {
-        return mValue.mAppUnits * 6.0f /
-          nsPresContext::AppUnitsPerCSSInch();
+        return mValue.mAppUnits * 6.0f / AppUnitsPerCSSInch();
       }
 
       break;
     case CSS_PERCENTAGE:
       if (mType == CSS_PERCENTAGE) {
         return mValue.mFloat * 100;
       }
 
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -168,23 +168,23 @@ ProcessTranslatePart(const nsCSSValue& a
   } else {
     // Note: The unit of nsCSSValue passed from Servo side would be number,
     //       pixel, percent, or eCSSUnit_Calc, so it is impossible to go into
     //       this branch.
     MOZ_CRASH("unexpected unit in ProcessTranslatePart");
   }
 
   float translation =
-    NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel());
+    NSAppUnitsToFloatPixels(offset, AppUnitsPerCSSPixel());
   // We want to avoid calling aDimensionGetter if there's no percentage to be
   // resolved (for performance reasons - see TransformReferenceBox).
   if (percent != 0.0f && aRefBox && !aRefBox->IsEmpty()) {
     translation +=
       percent * NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(),
-                                        nsPresContext::AppUnitsPerCSSPixel());
+                                        AppUnitsPerCSSPixel());
   }
   return translation;
 }
 
 /**
  * Helper functions to process all the transformation function types.
  *
  * These take a matrix parameter to accumulate the current matrix.
@@ -503,17 +503,17 @@ ProcessMatrixOperator(Matrix4x4& aMatrix
         list = nullptr;
     }
 
     Matrix4x4 matrix;
     if (!list) {
       return matrix;
     }
 
-    float appUnitPerCSSPixel = nsPresContext::AppUnitsPerCSSPixel();
+    float appUnitPerCSSPixel = AppUnitsPerCSSPixel();
     matrix = nsStyleTransformMatrix::ReadTransforms(list,
                                                     aRefBox,
                                                     appUnitPerCSSPixel,
                                                     aContains3dTransform);
     return matrix;
   };
 
   Matrix4x4 matrix1 = readTransform(aData->Item(1));
@@ -946,17 +946,17 @@ ReadTransforms(const nsCSSValueList* aLi
     NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
                  "Incoming function is too short!");
 
     /* Read in a single transform matrix. */
     MatrixForTransformFunction(result, currElem.GetArrayValue(), aRefBox,
                                aContains3dTransform);
   }
 
-  float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
+  float scale = float(AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
   result.PreScale(1/scale, 1/scale, 1/scale);
   result.PostScale(scale, scale, scale);
 
   return result;
 }
 
 Point
 Convert2DPosition(nsStyleCoord const (&aValue)[2],
--- a/layout/svg/SVGGeometryFrame.cpp
+++ b/layout/svg/SVGGeometryFrame.cpp
@@ -97,17 +97,17 @@ nsDisplaySVGGeometry::HitTest(nsDisplayL
 {
   SVGGeometryFrame *frame = static_cast<SVGGeometryFrame*>(mFrame);
   nsPoint pointRelativeToReferenceFrame = aRect.Center();
   // ToReferenceFrame() includes frame->GetPosition(), our user space position.
   nsPoint userSpacePtInAppUnits = pointRelativeToReferenceFrame -
                                    (ToReferenceFrame() - frame->GetPosition());
   gfxPoint userSpacePt =
     gfxPoint(userSpacePtInAppUnits.x, userSpacePtInAppUnits.y) /
-      frame->PresContext()->AppUnitsPerCSSPixel();
+      AppUnitsPerCSSPixel();
   if (frame->GetFrameForPoint(userSpacePt)) {
     aOutFrames->AppendElement(frame);
   }
 }
 
 void
 nsDisplaySVGGeometry::Paint(nsDisplayListBuilder* aBuilder,
                             gfxContext* aCtx)
@@ -317,17 +317,17 @@ SVGGeometryFrame::GetFrameForPoint(const
     fillRule = nsSVGUtils::ToFillRule(StyleSVG()->mClipRule);
   } else {
     hitTestFlags = GetHitTestFlags();
     if (!hitTestFlags) {
       return nullptr;
     }
     if (hitTestFlags & SVG_HIT_TEST_CHECK_MRECT) {
       gfxRect rect =
-        nsLayoutUtils::RectToGfxRect(mRect, PresContext()->AppUnitsPerCSSPixel());
+        nsLayoutUtils::RectToGfxRect(mRect, AppUnitsPerCSSPixel());
       if (!rect.Contains(aPoint)) {
         return nullptr;
       }
     }
     fillRule = nsSVGUtils::ToFillRule(StyleSVG()->mFillRule);
   }
 
   bool isHit = false;
@@ -398,17 +398,17 @@ SVGGeometryFrame::ReflowSVG()
    flags |= nsSVGUtils::eBBoxIncludeFillGeometry;
   }
   if ((hitTestFlags & SVG_HIT_TEST_STROKE)) {
    flags |= nsSVGUtils::eBBoxIncludeStrokeGeometry;
   }
 
   gfxRect extent = GetBBoxContribution(Matrix(), flags).ToThebesRect();
   mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent,
-            PresContext()->AppUnitsPerCSSPixel());
+            AppUnitsPerCSSPixel());
 
   if (mState & NS_FRAME_FIRST_REFLOW) {
     // Make sure we have our filter property (if any) before calling
     // FinishAndStoreOverflow (subsequent filter changes are handled off
     // nsChangeHint_UpdateEffects):
     SVGObserverUtils::UpdateEffects(this);
   }
 
@@ -473,17 +473,17 @@ SVGGeometryFrame::GetBBoxContribution(co
 
   if (aToBBoxUserspace.IsSingular()) {
     // XXX ReportToConsole
     return bbox;
   }
 
   if ((aFlags & nsSVGUtils::eForGetClientRects) &&
       aToBBoxUserspace.PreservesAxisAlignedRectangles()) {
-    Rect rect = NSRectToRect(mRect, PresContext()->AppUnitsPerCSSPixel());
+    Rect rect = NSRectToRect(mRect, AppUnitsPerCSSPixel());
     bbox = aToBBoxUserspace.TransformBounds(rect);
     return bbox;
   }
 
   SVGGeometryElement* element =
     static_cast<SVGGeometryElement*>(GetContent());
 
   bool getFill = (aFlags & nsSVGUtils::eBBoxIncludeFillGeometry) ||
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -345,17 +345,17 @@ GetBaselinePosition(nsTextFrame* aFrame,
       return writingMode.IsVerticalRL()
              ? metrics.mAscent + metrics.mDescent -
                aFrame->GetLogicalBaseline(writingMode)
              : aFrame->GetLogicalBaseline(writingMode);
 
     case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
       return aFrame->GetLogicalBaseline(writingMode) -
         SVGContentUtils::GetFontXHeight(aFrame) / 2.0 *
-        aFrame->PresContext()->AppUnitsPerCSSPixel() * aFontSizeScaleFactor;
+        AppUnitsPerCSSPixel() * aFontSizeScaleFactor;
 
     case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
     case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
       return writingMode.IsVerticalLR()
              ? 0 : metrics.mAscent + metrics.mDescent;
 
     case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
     case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
@@ -883,17 +883,17 @@ TextRenderedRun::GetTransformFromRunUser
     return m;
   }
 
   nscoord start, end;
   GetClipEdges(start, end);
 
   // Translate by the horizontal distance into the text frame this
   // rendered run is.
-  gfxFloat appPerCssPx = nsPresContext::AppUnitsPerCSSPixel();
+  gfxFloat appPerCssPx = AppUnitsPerCSSPixel();
   gfxPoint t = IsVertical() ? gfxPoint(0, start / appPerCssPx)
                             : gfxPoint(start / appPerCssPx, 0);
   return m.PreTranslate(t);
 }
 
 SVGBBox
 TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext,
                                      uint32_t aFlags) const
@@ -3106,17 +3106,17 @@ nsDisplaySVGText::HitTest(nsDisplayListB
   SVGTextFrame *frame = static_cast<SVGTextFrame*>(mFrame);
   nsPoint pointRelativeToReferenceFrame = aRect.Center();
   // ToReferenceFrame() includes frame->GetPosition(), our user space position.
   nsPoint userSpacePtInAppUnits = pointRelativeToReferenceFrame -
                                     (ToReferenceFrame() - frame->GetPosition());
 
   gfxPoint userSpacePt =
     gfxPoint(userSpacePtInAppUnits.x, userSpacePtInAppUnits.y) /
-      frame->PresContext()->AppUnitsPerCSSPixel();
+      AppUnitsPerCSSPixel();
 
   nsIFrame* target = frame->GetFrameForPoint(userSpacePt);
   if (target) {
     aOutFrames->AppendElement(target);
   }
 }
 
 void
@@ -3807,17 +3807,17 @@ SVGTextFrame::ReflowSVG()
       r.UnionEdges(run.GetUserSpaceRect(presContext, runFlags));
     }
   }
 
   if (r.IsEmpty()) {
     mRect.SetEmpty();
   } else {
     mRect =
-      nsLayoutUtils::RoundGfxRectToAppRect(r.ToThebesRect(), nsPresContext::AppUnitsPerCSSPixel());
+      nsLayoutUtils::RoundGfxRectToAppRect(r.ToThebesRect(), AppUnitsPerCSSPixel());
 
     // Due to rounding issues when we have a transform applied, we sometimes
     // don't include an additional row of pixels.  For now, just inflate our
     // covered region.
     mRect.Inflate(presContext->AppUnitsPerDevPixel());
   }
 
   if (mState & NS_FRAME_FIRST_REFLOW) {
@@ -3868,17 +3868,17 @@ TextRenderedRunFlagsForBBoxContribution(
 SVGBBox
 SVGTextFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
                                   uint32_t aFlags)
 {
   NS_ASSERTION(PrincipalChildList().FirstChild(), "must have a child frame");
   SVGBBox bbox;
 
   if (aFlags & nsSVGUtils::eForGetClientRects) {
-    Rect rect = NSRectToRect(mRect, PresContext()->AppUnitsPerCSSPixel());
+    Rect rect = NSRectToRect(mRect, AppUnitsPerCSSPixel());
     if (!rect.IsEmpty()) {
       bbox = aToBBoxUserspace.TransformBounds(rect);
     }
     return bbox;
   }
 
   nsIFrame* kid = PrincipalChildList().FirstChild();
   if (kid && NS_SUBTREE_DIRTY(kid)) {
@@ -5678,17 +5678,17 @@ SVGTextFrame::TransformFramePointToTextC
   UpdateGlyphPositioning();
 
   nsPresContext* presContext = PresContext();
 
   // Add in the mRect offset to aPoint, as that will have been taken into
   // account when transforming the point from the ancestor frame down
   // to this one.
   float cssPxPerDevPx = nsPresContext::AppUnitsToFloatCSSPixels(presContext->AppUnitsPerDevPixel());
-  float factor = nsPresContext::AppUnitsPerCSSPixel();
+  float factor = AppUnitsPerCSSPixel();
   Point framePosition(NSAppUnitsToFloatPixels(mRect.x, factor),
                       NSAppUnitsToFloatPixels(mRect.y, factor));
   Point pointInUserSpace = aPoint * cssPxPerDevPx + framePosition;
 
   // Find the closest rendered run for the text frames beneath aChildFrame.
   TextRenderedRunIterator it(this, TextRenderedRunIterator::eAllFrames,
                              aChildFrame);
   TextRenderedRun hit;
@@ -5785,17 +5785,17 @@ SVGTextFrame::TransformFrameRectFromText
 
       // Union it into the result.
       result.UnionRect(result, rectInUserSpace);
     }
   }
 
   // Subtract the mRect offset from the result, as our user space for
   // this frame is relative to the top-left of mRect.
-  float factor = nsPresContext::AppUnitsPerCSSPixel();
+  float factor = AppUnitsPerCSSPixel();
   gfxPoint framePosition(NSAppUnitsToFloatPixels(mRect.x, factor),
                          NSAppUnitsToFloatPixels(mRect.y, factor));
 
   return result - framePosition;
 }
 
 void
 SVGTextFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
--- a/layout/svg/nsCSSClipPathInstance.cpp
+++ b/layout/svg/nsCSSClipPathInstance.cpp
@@ -58,17 +58,17 @@ nsCSSClipPathInstance::HitTestBasicShape
     return false;
   }
 
   nsCSSClipPathInstance instance(aFrame, clipPathStyle);
 
   RefPtr<DrawTarget> drawTarget =
     gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
   RefPtr<Path> path = instance.CreateClipPath(drawTarget);
-  float pixelRatio = float(nsPresContext::AppUnitsPerCSSPixel()) /
+  float pixelRatio = float(AppUnitsPerCSSPixel()) /
                      aFrame->PresContext()->AppUnitsPerDevPixel();
   return path->ContainsPoint(ToPoint(aPoint) * pixelRatio, Matrix());
 }
 
 /* static */ Rect
 nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(nsIFrame* aFrame,
                                                         const StyleShapeSource& aClipPathStyle)
 {
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -571,17 +571,17 @@ nsIntRect
 nsFilterInstance::FrameSpaceToFilterSpace(const nsRect* aRect) const
 {
   nsIntRect rect = OutputFilterSpaceBounds();
   if (aRect) {
     if (aRect->IsEmpty()) {
       return nsIntRect();
     }
     gfxRect rectInCSSPx =
-      nsLayoutUtils::RectToGfxRect(*aRect, nsPresContext::AppUnitsPerCSSPixel());
+      nsLayoutUtils::RectToGfxRect(*aRect, AppUnitsPerCSSPixel());
     gfxRect rectInFilterSpace =
       mFrameSpaceInCSSPxToFilterSpaceTransform.TransformBounds(rectInCSSPx);
     rectInFilterSpace.RoundOut();
     nsIntRect intRect;
     if (gfxUtils::GfxRectToIntRect(rectInFilterSpace, &intRect)) {
       rect = intRect;
     }
   }
@@ -592,17 +592,17 @@ nsRect
 nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const
 {
   if (aRect.IsEmpty()) {
     return nsRect();
   }
   gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
   r = mFilterSpaceToFrameSpaceInCSSPxTransform.TransformBounds(r);
   // nsLayoutUtils::RoundGfxRectToAppRect rounds out.
-  return nsLayoutUtils::RoundGfxRectToAppRect(r, nsPresContext::AppUnitsPerCSSPixel());
+  return nsLayoutUtils::RoundGfxRectToAppRect(r, AppUnitsPerCSSPixel());
 }
 
 nsIntRegion
 nsFilterInstance::FrameSpaceToFilterSpace(const nsRegion* aRegion) const
 {
   if (!aRegion) {
     return OutputFilterSpaceBounds();
   }
--- a/layout/svg/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/nsSVGForeignObjectFrame.cpp
@@ -233,17 +233,17 @@ nsSVGForeignObjectFrame::PaintSVG(gfxCon
     NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular");
 
     gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
                                      aDirtyRect->width, aDirtyRect->height);
     transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
 
     kidDirtyRect.IntersectRect(kidDirtyRect,
       nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect,
-                       PresContext()->AppUnitsPerCSSPixel()));
+                       AppUnitsPerCSSPixel()));
 
     // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect,
     // not with kidDirtyRect. I.e.
     // int32_t appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
     // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)
     if (kidDirtyRect.IsEmpty())
       return;
   }
@@ -308,17 +308,17 @@ nsSVGForeignObjectFrame::GetFrameForPoin
   if (!gfxRect(x, y, width, height).Contains(aPoint) ||
       !nsSVGUtils::HitTestClip(this, aPoint)) {
     return nullptr;
   }
 
   // Convert the point to app units relative to the top-left corner of the
   // viewport that's established by the foreignObject element:
 
-  gfxPoint pt = (aPoint + gfxPoint(x, y)) * nsPresContext::AppUnitsPerCSSPixel();
+  gfxPoint pt = (aPoint + gfxPoint(x, y)) * AppUnitsPerCSSPixel();
   nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
 
   return nsLayoutUtils::GetFrameForPoint(kid, point);
 }
 
 void
 nsSVGForeignObjectFrame::ReflowSVG()
 {
@@ -340,17 +340,17 @@ nsSVGForeignObjectFrame::ReflowSVG()
     GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
 
   // If mRect's width or height are negative, reflow blows up! We must clamp!
   if (w < 0.0f) w = 0.0f;
   if (h < 0.0f) h = 0.0f;
 
   mRect = nsLayoutUtils::RoundGfxRectToAppRect(
                            gfxRect(x, y, w, h),
-                           PresContext()->AppUnitsPerCSSPixel());
+                           AppUnitsPerCSSPixel());
 
   // Fully mark our kid dirty so that it gets resized if necessary
   // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case):
   nsIFrame* kid = PrincipalChildList().FirstChild();
   kid->AddStateBits(NS_FRAME_IS_DIRTY);
 
   // Make sure to not allow interrupts if we're not being reflown as a root:
   nsPresContext::InterruptPreventer noInterrupts(PresContext());
@@ -558,17 +558,17 @@ nsRect
 nsSVGForeignObjectFrame::GetInvalidRegion()
 {
   MOZ_ASSERT(!NS_SVGDisplayListPaintingEnabled(),
              "Only called by nsDisplayOuterSVG code");
 
   nsIFrame* kid = PrincipalChildList().FirstChild();
   if (kid->HasInvalidFrameInSubtree()) {
     gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height);
-    r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
+    r.Scale(1.0 / AppUnitsPerCSSPixel());
     nsRect rect = nsSVGUtils::ToCanvasBounds(r, GetCanvasTM(), PresContext());
     rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect);
     return rect;
   }
   return nsRect();
 }
 
 void
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -435,17 +435,17 @@ nsSVGImageFrame::ReflowSVG()
   float x, y, width, height;
   SVGImageElement *element = static_cast<SVGImageElement*>(GetContent());
   element->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
 
   Rect extent(x, y, width, height);
 
   if (!extent.IsEmpty()) {
     mRect = nsLayoutUtils::RoundGfxRectToAppRect(extent,
-              PresContext()->AppUnitsPerCSSPixel());
+              AppUnitsPerCSSPixel());
   } else {
     mRect.SetEmpty();
   }
 
   if (mState & NS_FRAME_FIRST_REFLOW) {
     // Make sure we have our filter property (if any) before calling
     // FinishAndStoreOverflow (subsequent filter changes are handled off
     // nsChangeHint_UpdateEffects):
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -233,17 +233,17 @@ nsSVGIntegrationUtils::GetSVGBBoxForNonS
   nsRect r = (aUnionContinuations)
     ? GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(),
                                        GetOffsetToBoundingBox(firstFrame),
                                        false)
     : GetPreEffectsVisualOverflow(firstFrame, aNonSVGFrame,
                                   GetOffsetToBoundingBox(firstFrame));
 
   return nsLayoutUtils::RectToGfxRect(r,
-           aNonSVGFrame->PresContext()->AppUnitsPerCSSPixel());
+           AppUnitsPerCSSPixel());
 }
 
 // XXX Since we're called during reflow, this method is broken for frames with
 // continuations. When we're called for a frame with continuations, we're
 // called for each continuation in turn as it's reflowed. However, it isn't
 // until the last continuation is reflowed that this method's
 // GetOffsetToBoundingBox() and GetPreEffectsVisualOverflowUnion() calls will
 // obtain valid border boxes for all the continuations. As a result, we'll
@@ -295,17 +295,17 @@ nsRect
   // XXX Why are we rounding out to pixel boundaries? We don't do that in
   // GetSVGBBoxForNonSVGFrame, and it doesn't appear to be necessary.
   gfxRect overrideBBox =
     nsLayoutUtils::RectToGfxRect(
       GetPreEffectsVisualOverflowUnion(firstFrame, aFrame,
                                        aPreEffectsOverflowRect,
                                        firstFrameToBoundingBox,
                                        true),
-      aFrame->PresContext()->AppUnitsPerCSSPixel());
+      AppUnitsPerCSSPixel());
   overrideBBox.RoundOut();
 
   nsRect overflowRect =
     nsFilterInstance::GetPostFilterBounds(firstFrame, &overrideBBox);
 
   // Return overflowRect relative to aFrame, rather than "user space":
   return overflowRect - (aFrame->GetOffsetTo(firstFrame) + firstFrameToBoundingBox);
 }
@@ -389,17 +389,17 @@ nsSVGIntegrationUtils::HitTestFrameForEf
     // XXXmstange Isn't this wrong for svg:use and innerSVG frames?
     toUserSpace = aFrame->GetPosition();
   } else {
     toUserSpace =
       aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame);
   }
   nsPoint pt = aPt + toUserSpace;
   gfxPoint userSpacePt =
-    gfxPoint(pt.x, pt.y) / aFrame->PresContext()->AppUnitsPerCSSPixel();
+    gfxPoint(pt.x, pt.y) / AppUnitsPerCSSPixel();
   return nsSVGUtils::HitTestClip(firstFrame, userSpacePt);
 }
 
 class RegularFramePaintCallback : public nsSVGFilterPaintCallback
 {
 public:
   RegularFramePaintCallback(nsDisplayListBuilder* aBuilder,
                             LayerManager* aManager,
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -580,17 +580,17 @@ nsDisplayOuterSVG::HitTest(nsDisplayList
     ToReferenceFrame() + outerSVGFrame->GetContentRectRelativeToSelf().TopLeft();
 
   nsPoint pointRelativeToContentBox =
     nsPoint(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2) -
       refFrameToContentBox;
 
   gfxPoint svgViewportRelativePoint =
     gfxPoint(pointRelativeToContentBox.x, pointRelativeToContentBox.y) /
-      outerSVGFrame->PresContext()->AppUnitsPerCSSPixel();
+      AppUnitsPerCSSPixel();
 
   nsSVGOuterSVGAnonChildFrame *anonKid =
     static_cast<nsSVGOuterSVGAnonChildFrame*>(
       outerSVGFrame->PrincipalChildList().FirstChild());
 
   nsIFrame* frame =
     nsSVGUtils::HitTestChildren(anonKid, svgViewportRelativePoint);
   if (frame) {
--- a/layout/svg/nsSVGUseFrame.cpp
+++ b/layout/svg/nsSVGUseFrame.cpp
@@ -106,17 +106,17 @@ nsSVGUseFrame::ReflowSVG()
   // We only handle x/y offset here, since any width/height that is in force is
   // handled by the nsSVGOuterSVGFrame for the anonymous <svg> that will be
   // created for that purpose.
   float x, y;
   static_cast<SVGUseElement*>(GetContent())->
     GetAnimatedLengthValues(&x, &y, nullptr);
   mRect.MoveTo(nsLayoutUtils::RoundGfxRectToAppRect(
                  gfxRect(x, y, 0.0, 0.0),
-                 PresContext()->AppUnitsPerCSSPixel()).TopLeft());
+                 AppUnitsPerCSSPixel()).TopLeft());
 
   // If we have a filter, we need to invalidate ourselves because filter
   // output can change even if none of our descendants need repainting.
   if (StyleEffects()->HasFilters()) {
     InvalidateFrame();
   }
 
   nsSVGGFrame::ReflowSVG();
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -828,17 +828,17 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
       }
       gfxMatrix deviceToUserSpace = userToDeviceSpace;
       deviceToUserSpace.Invert();
       gfxRect dirtyBounds = deviceToUserSpace.TransformBounds(
                               gfxRect(aDirtyRect->x, aDirtyRect->y,
                                       aDirtyRect->width, aDirtyRect->height));
       tmpDirtyRegion =
         nsLayoutUtils::RoundGfxRectToAppRect(
-          dirtyBounds, aFrame->PresContext()->AppUnitsPerCSSPixel()) -
+          dirtyBounds, AppUnitsPerCSSPixel()) -
         aFrame->GetPosition();
       dirtyRegion = &tmpDirtyRegion;
     }
 
     gfxContextMatrixAutoSaveRestore autoSR(target);
 
     // 'target' is currently scaled such that its user space units are CSS
     // pixels (SVG user space units). But PaintFilteredFrame expects it to be
@@ -957,17 +957,17 @@ nsSVGUtils::HitTestChildren(nsSVGDisplay
 }
 
 nsRect
 nsSVGUtils::TransformFrameRectToOuterSVG(const nsRect& aRect,
                                          const gfxMatrix& aMatrix,
                                          nsPresContext* aPresContext)
 {
   gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
-  r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
+  r.Scale(1.0 / AppUnitsPerCSSPixel());
   return nsLayoutUtils::RoundGfxRectToAppRect(
     aMatrix.TransformBounds(r), aPresContext->AppUnitsPerDevPixel());
 }
 
 IntSize
 nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize,
                                  bool *aResultOverflows)
 {
@@ -1213,17 +1213,17 @@ nsSVGUtils::FrameSpaceInCSSPxToUserSpace
     // frame's border-box rects over all continuations.
     return gfxPoint();
   }
 
   // Leaf frames apply their own offset inside their user space.
   if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) ||
       nsSVGUtils::IsInSVGTextSubtree(aFrame)) {
     return nsLayoutUtils::RectToGfxRect(aFrame->GetRect(),
-                                         nsPresContext::AppUnitsPerCSSPixel()).TopLeft();
+                                         AppUnitsPerCSSPixel()).TopLeft();
   }
 
   // For foreignObject frames, nsSVGUtils::GetBBox applies their local
   // transform, so we need to do the same here.
   if (aFrame->IsSVGForeignObjectFrame()) {
     gfxMatrix transform = static_cast<nsSVGElement*>(aFrame->GetContent())->
         PrependLocalTransformsTo(gfxMatrix(), eChildToUserSpace);
     NS_ASSERTION(!transform.HasNonTranslation(), "we're relying on this being an offset-only transform");
--- a/layout/svg/nsSVGViewportFrame.cpp
+++ b/layout/svg/nsSVGViewportFrame.cpp
@@ -61,17 +61,17 @@ nsSVGViewportFrame::ReflowSVG()
 {
   // mRect must be set before FinishAndStoreOverflow is called in order
   // for our overflow areas to be clipped correctly.
   float x, y, width, height;
   static_cast<SVGViewportElement*>(GetContent())->
     GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
   mRect = nsLayoutUtils::RoundGfxRectToAppRect(
                            gfxRect(x, y, width, height),
-                           PresContext()->AppUnitsPerCSSPixel());
+                           AppUnitsPerCSSPixel());
 
   // If we have a filter, we need to invalidate ourselves because filter
   // output can change even if none of our descendants need repainting.
   if (StyleEffects()->HasFilters()) {
     InvalidateFrame();
   }
 
   nsSVGDisplayContainerFrame::ReflowSVG();
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -446,13 +446,13 @@ nsTableRowFrame::GetContinuousBCBorderWi
   aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
                                                  mBStartContBorderWidth);
   aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
                                                  mIEndContBorderWidth);
 }
 
 inline nscoord nsTableRowFrame::GetOuterBStartContBCBorderWidth()
 {
-  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
+  int32_t aPixelsToTwips = mozilla::AppUnitsPerCSSPixel();
   return BC_BORDER_START_HALF_COORD(aPixelsToTwips, mBStartContBorderWidth);
 }
 
 #endif
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -1377,17 +1377,17 @@ nsMenuPopupFrame::SetPopupPosition(nsIFr
     // If we can't reach a root pres context, don't bother continuing:
     if (!rootPresContext) {
       return NS_OK;
     }
 
     // If anchored to a rectangle, use that rectangle. Otherwise, determine the
     // rectangle from the anchor.
     if (mAnchorType == MenuPopupAnchorType_Rect) {
-      anchorRect = ToAppUnits(mScreenRect, nsPresContext::AppUnitsPerCSSPixel());
+      anchorRect = ToAppUnits(mScreenRect, AppUnitsPerCSSPixel());
     }
     else {
       // if the frame is not specified, use the anchor node passed to OpenPopup. If
       // that wasn't specified either, use the root frame. Note that mAnchorContent
       // might be a different document so its presshell must be used.
       if (!aAnchorFrame) {
         if (mAnchorContent) {
           aAnchorFrame = mAnchorContent->GetPrimaryFrame();
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -368,17 +368,17 @@ public:
                     bool aAttributesOverride);
 
   bool GetAutoPosition();
   void SetAutoPosition(bool aShouldAutoPosition);
 
   nsIScrollableFrame* GetScrollFrame(nsIFrame* aStart);
 
   void SetOverrideConstraintRect(mozilla::LayoutDeviceIntRect aRect) {
-    mOverrideConstraintRect = ToAppUnits(aRect, PresContext()->AppUnitsPerCSSPixel());
+    mOverrideConstraintRect = ToAppUnits(aRect, mozilla::AppUnitsPerCSSPixel());
   }
 
   // For a popup that should appear anchored at the given rect, determine
   // the screen area that it is constrained by. This will be the available
   // area of the screen the popup should be displayed on. Content popups,
   // however, will also be constrained by the content area, given by
   // aRootScreenRect. All coordinates are in app units.
   // For non-toplevel popups (which will always be panels), we will also
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -239,17 +239,17 @@ nsResizerFrame::HandleEvent(nsPresContex
         // direction, don't allow the new size to be less that the resizer's
         // size. This ensures that content isn't resized too small as to make
         // the resizer invisible.
         nsRect appUnitsRect = ToAppUnits(rect.ToUnknownRect(), aPresContext->AppUnitsPerDevPixel());
         if (appUnitsRect.width < mRect.width && mouseMove.x)
           appUnitsRect.width = mRect.width;
         if (appUnitsRect.height < mRect.height && mouseMove.y)
           appUnitsRect.height = mRect.height;
-        nsIntRect cssRect = appUnitsRect.ToInsidePixels(nsPresContext::AppUnitsPerCSSPixel());
+        nsIntRect cssRect = appUnitsRect.ToInsidePixels(AppUnitsPerCSSPixel());
 
         LayoutDeviceIntRect oldRect;
         AutoWeakFrame weakFrame(menuPopupFrame);
         if (menuPopupFrame) {
           nsCOMPtr<nsIWidget> widget = menuPopupFrame->GetWidget();
           if (widget)
             oldRect = widget->GetScreenBounds();
 
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -573,17 +573,17 @@ nsTreeBodyFrame::GetSelectionRegion()
   nsCOMPtr<nsITreeSelection> selection;
   mView->GetSelection(getter_AddRefs(selection));
   if (!selection) {
     return Nothing();
   }
 
 
   RefPtr<nsPresContext> presContext = PresContext();
-  nsIntRect rect = mRect.ToOutsidePixels(presContext->AppUnitsPerCSSPixel());
+  nsIntRect rect = mRect.ToOutsidePixels(AppUnitsPerCSSPixel());
 
   nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame();
   nsPoint origin = GetOffsetTo(rootFrame);
 
   CSSIntRegion region;
 
   // iterate through the visible rows and add the selected ones to the
   // drag region
--- a/mfbt/Utf8.h
+++ b/mfbt/Utf8.h
@@ -258,17 +258,17 @@ inline bool
 IsTrailingUnit(Utf8Unit aUnit)
 {
   return (aUnit.toUint8() & 0b1100'0000) == 0b1000'0000;
 }
 
 /**
  * Given |aLeadUnit| that is a non-ASCII code unit, a pointer to an |Iter aIter|
  * that (initially) itself points one unit past |aLeadUnit|, and
- * |const EndIter aEnd| that denotes the end of the UTF-8 data when compared
+ * |const EndIter& aEnd| that denotes the end of the UTF-8 data when compared
  * against |*aIter| using |aEnd - *aIter|:
  *
  * If |aLeadUnit| and subsequent code units computed using |*aIter| (up to
  * |aEnd|) encode a valid code point -- not exceeding Unicode's range, not a
  * surrogate, in shortest form -- then return Some(that code point) and advance
  * |*aIter| past those code units.
  *
  * Otherwise decrement |*aIter| (so that it points at |aLeadUnit|) and return
@@ -294,17 +294,17 @@ template<typename Iter,
          typename EndIter,
          class OnBadLeadUnit,
          class OnNotEnoughUnits,
          class OnBadTrailingUnit,
          class OnBadCodePoint,
          class OnNotShortestForm>
 MOZ_ALWAYS_INLINE Maybe<char32_t>
 DecodeOneUtf8CodePointInline(const Utf8Unit aLeadUnit,
-                             Iter* aIter, const EndIter aEnd,
+                             Iter* aIter, const EndIter& aEnd,
                              OnBadLeadUnit aOnBadLeadUnit,
                              OnNotEnoughUnits aOnNotEnoughUnits,
                              OnBadTrailingUnit aOnBadTrailingUnit,
                              OnBadCodePoint aOnBadCodePoint,
                              OnNotShortestForm aOnNotShortestForm)
 {
   MOZ_ASSERT(Utf8Unit((*aIter)[-1]) == aLeadUnit);
 
@@ -386,17 +386,17 @@ template<typename Iter,
          typename EndIter,
          class OnBadLeadUnit,
          class OnNotEnoughUnits,
          class OnBadTrailingUnit,
          class OnBadCodePoint,
          class OnNotShortestForm>
 inline Maybe<char32_t>
 DecodeOneUtf8CodePoint(const Utf8Unit aLeadUnit,
-                       Iter* aIter, const EndIter aEnd,
+                       Iter* aIter, const EndIter& aEnd,
                        OnBadLeadUnit aOnBadLeadUnit,
                        OnNotEnoughUnits aOnNotEnoughUnits,
                        OnBadTrailingUnit aOnBadTrailingUnit,
                        OnBadCodePoint aOnBadCodePoint,
                        OnNotShortestForm aOnNotShortestForm)
 {
   return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd,
                                       aOnBadLeadUnit, aOnNotEnoughUnits,
@@ -409,17 +409,17 @@ DecodeOneUtf8CodePoint(const Utf8Unit aL
  * trailing if-invalid notifier functors.
  *
  * This function is MOZ_ALWAYS_INLINE: if you don't need that, use the version
  * of this function without the "Inline" suffix on the name.
  */
 template<typename Iter, typename EndIter>
 MOZ_ALWAYS_INLINE Maybe<char32_t>
 DecodeOneUtf8CodePointInline(const Utf8Unit aLeadUnit,
-                             Iter* aIter, const EndIter aEnd)
+                             Iter* aIter, const EndIter& aEnd)
 {
   // aOnBadLeadUnit is called when |aLeadUnit| itself is an invalid lead unit in
   // a multi-unit code point.  It is passed no arguments: the caller already has
   // |aLeadUnit| on hand, so no need to provide it again.
   auto onBadLeadUnit = []() {};
 
   // aOnNotEnoughUnits is called when |aLeadUnit| properly indicates a code
   // point length, but there aren't enough units from |*aIter| to |aEnd| to
@@ -461,16 +461,16 @@ DecodeOneUtf8CodePointInline(const Utf8U
 
 /**
  * Identical to the above function, but not forced to be instantiated inline --
  * the compiler/linker are allowed to common up separate invocations.
  */
 template<typename Iter, typename EndIter>
 inline Maybe<char32_t>
 DecodeOneUtf8CodePoint(const Utf8Unit aLeadUnit,
-                       Iter* aIter, const EndIter aEnd)
+                       Iter* aIter, const EndIter& aEnd)
 {
   return DecodeOneUtf8CodePointInline(aLeadUnit, aIter, aEnd);
 }
 
 } // namespace mozilla
 
 #endif /* mozilla_Utf8_h */
--- a/mobile/android/config/mozconfigs/android-aarch64/nightly
+++ b/mobile/android/config/mozconfigs/android-aarch64/nightly
@@ -1,13 +1,19 @@
 . "$topsrcdir/mobile/android/config/mozconfigs/common"
 
 # Android
 ac_add_options --with-android-min-sdk=21
 ac_add_options --target=aarch64-linux-android
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
+export AR="$topsrcdir/clang/bin/llvm-ar"
+export NM="$topsrcdir/clang/bin/llvm-nm"
+export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
+
+ac_add_options --enable-lto
+
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 export MOZ_ANDROID_POCKET=1
 
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-api-16/nightly
+++ b/mobile/android/config/mozconfigs/android-api-16/nightly
@@ -11,9 +11,15 @@ ac_add_options --target=arm-linux-androi
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 export MOZ_ANDROID_MMA=1
 export MOZ_ANDROID_POCKET=1
 
+export AR="$topsrcdir/clang/bin/llvm-ar"
+export NM="$topsrcdir/clang/bin/llvm-nm"
+export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
+
+ac_add_options --enable-lto
+
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/mobile/android/config/mozconfigs/android-x86/nightly
+++ b/mobile/android/config/mozconfigs/android-x86/nightly
@@ -9,9 +9,15 @@ ac_add_options --target=i686-linux-andro
 ac_add_options --with-android-min-sdk=16
 
 ac_add_options --with-branding=mobile/android/branding/nightly
 
 export MOZILLA_OFFICIAL=1
 export MOZ_TELEMETRY_REPORTING=1
 export MOZ_ANDROID_POCKET=1
 
+export AR="$topsrcdir/clang/bin/llvm-ar"
+export NM="$topsrcdir/clang/bin/llvm-nm"
+export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
+
+ac_add_options --enable-lto
+
 . "$topsrcdir/mobile/android/config/mozconfigs/common.override"
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1086,22 +1086,23 @@ VARCACHE_PREF(
 // - true: They are allow to present http auth. dialog
 // - false: They are not allow to present http auth. dialog.
 VARCACHE_PREF(
   "network.auth.non-web-content-triggered-resources-http-auth-allow",
    network_auth_non_web_content_triggered_resources_http_auth_allow,
   bool, false
 )
 
-// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign
+// 0-Accept, 1-dontAcceptForeign, 2-dontAcceptAny, 3-limitForeign,
+// 4-rejectTracker
 // Keep the old default of accepting all cookies
 VARCACHE_PREF(
   "network.cookie.cookieBehavior",
   network_cookie_cookieBehavior,
-  int32_t, 0
+  RelaxedAtomicInt32, 0
 )
 
 // Enables the predictive service.
 VARCACHE_PREF(
   "network.predictor.enabled",
    network_predictor_enabled,
   bool, true
 )
@@ -1227,22 +1228,16 @@ VARCACHE_PREF(
 
 PREF("preferences.allow.omt-write", bool, true)
 
 //---------------------------------------------------------------------------
 // Privacy prefs
 //---------------------------------------------------------------------------
 
 VARCACHE_PREF(
-  "privacy.restrict3rdpartystorage.enabled",
-   privacy_restrict3rdpartystorage_enabled,
-  RelaxedAtomicBool, false
-)
-
-VARCACHE_PREF(
   "privacy.restrict3rdpartystorage.ui.enabled",
    privacy_restrict3rdpartystorage_ui_enabled,
   RelaxedAtomicBool, false
 )
 
 // Anti-tracking permission expiration
 VARCACHE_PREF(
   "privacy.restrict3rdpartystorage.expiration",
--- a/netwerk/base/nsChannelClassifier.cpp
+++ b/netwerk/base/nsChannelClassifier.cpp
@@ -7,16 +7,17 @@
 #include "nsChannelClassifier.h"
 
 #include "mozIThirdPartyUtil.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsIAddonPolicyService.h"
 #include "nsICacheEntry.h"
 #include "nsICachingChannel.h"
+#include "nsICookieService.h"
 #include "nsIChannel.h"
 #include "nsIClassOfService.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIIOService.h"
 #include "nsIParentChannel.h"
@@ -946,17 +947,18 @@ TrackingURICallback::OnClassifyComplete(
                                         const nsACString& aFullHash)
 {
   MOZ_ASSERT(aErrorCode == NS_OK);
 
   const bool shouldEnableTrackingProtection =
     mChannelClassifier->ShouldEnableTrackingProtection();
   const bool shouldEnableTrackingAnnotation =
     mChannelClassifier->ShouldEnableTrackingAnnotation() ||
-    StaticPrefs::privacy_restrict3rdpartystorage_enabled();
+    StaticPrefs::network_cookie_cookieBehavior() ==
+      nsICookieService::BEHAVIOR_REJECT_TRACKER;
   MOZ_ASSERT(shouldEnableTrackingProtection || shouldEnableTrackingAnnotation);
 
   LOG(("TrackingURICallback[%p]:OnClassifyComplete "
        "shouldEnableTrackingProtection=%d, shouldEnableTrackingAnnnotation=%d",
        mChannelClassifier.get(), shouldEnableTrackingProtection,
        shouldEnableTrackingAnnotation));
 
   // Figure out whether we are receiving the results of a blacklist or
@@ -1194,17 +1196,18 @@ TrackingURICallback::OnTrackerFound(nsre
     mChannelClassifier->SetBlockedContent(channel, aErrorCode,
                                           mList, mProvider, mFullHash);
     LOG(("TrackingURICallback[%p]::OnTrackerFound, cancelling channel[%p]",
          mChannelClassifier.get(), channel.get()));
     channel->Cancel(aErrorCode);
   } else {
     MOZ_ASSERT(aErrorCode == NS_ERROR_TRACKING_ANNOTATION_URI);
     MOZ_ASSERT(mChannelClassifier->ShouldEnableTrackingAnnotation() ||
-               StaticPrefs::privacy_restrict3rdpartystorage_enabled());
+               StaticPrefs::network_cookie_cookieBehavior() ==
+                 nsICookieService::BEHAVIOR_REJECT_TRACKER);
 
     LOG(("TrackingURICallback[%p]::OnTrackerFound, annotating channel[%p]",
          mChannelClassifier.get(), channel.get()));
 
     // Even with TP disabled, we still want to show the user that there
     // are unblocked trackers on the site, so notify the UI that we loaded
     // tracking content. UI code can treat this notification differently
     // depending on whether TP is enabled or disabled.
@@ -1416,17 +1419,18 @@ nsChannelClassifier::CheckIsTrackerWithL
 
   nsCOMPtr<nsIURIClassifier> uriClassifier =
     do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   const bool shouldEnableTrackingProtection = ShouldEnableTrackingProtection();
-  const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() || StaticPrefs::privacy_restrict3rdpartystorage_enabled();
+  const bool shouldEnableTrackingAnnotation = ShouldEnableTrackingAnnotation() ||
+    StaticPrefs::network_cookie_cookieBehavior() == nsICookieService::BEHAVIOR_REJECT_TRACKER;
   if (!shouldEnableTrackingProtection && !shouldEnableTrackingAnnotation) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIURI> uri;
   rv = mChannel->GetURI(getter_AddRefs(uri));
   if (NS_FAILED(rv) || !uri) {
     return rv;
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -2405,17 +2405,17 @@ nsCookieService::RunInTransaction(nsICoo
  * pref observer impl
  ******************************************************************************/
 
 void
 nsCookieService::PrefChanged(nsIPrefBranch *aPrefBranch)
 {
   int32_t val;
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
-    mCookieBehavior = (uint8_t) LIMIT(val, 0, 3, 0);
+    mCookieBehavior = (uint8_t) LIMIT(val, 0, nsICookieService::BEHAVIOR_LAST, 0);
 
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val)))
     mMaxNumberOfCookies = (uint16_t) LIMIT(val, 1, 0xFFFF, kMaxNumberOfCookies);
 
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxCookiesPerHost, &val)))
     mMaxCookiesPerHost = (uint16_t) LIMIT(val, 1, 0xFFFF, kMaxCookiesPerHost);
 
   if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookiePurgeAge, &val))) {
@@ -4194,24 +4194,16 @@ nsCookieService::CheckPrefs(nsICookiePer
   nsCOMPtr<nsIPrincipal> principal =
       BasePrincipal::CreateCodebasePrincipal(aHostURI, aOriginAttrs);
 
   if (!principal) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "non-codebase principals cannot get/set cookies");
     return STATUS_REJECTED_WITH_ERROR;
   }
 
-  // No cookies allowed if this request comes from a tracker, in a 3rd party
-  // context, when anti-tracking protection is enabled and when we don't have
-  // access to the first-party cookie jar.
-  if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
-      StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
-      return STATUS_REJECTED;
-  }
-
   // check the permission list first; if we find an entry, it overrides
   // default prefs. see bug 184059.
   if (aPermissionService) {
     nsCookieAccess access;
     // Not passing an nsIChannel here is probably OK; our implementation
     // doesn't do anything with it anyway.
     rv = aPermissionService->CanAccess(principal, &access);
 
@@ -4245,16 +4237,25 @@ nsCookieService::CheckPrefs(nsICookiePer
                             "for this site");
           return STATUS_REJECTED;
         }
         return STATUS_ACCEPTED;
       }
     }
   }
 
+  // No cookies allowed if this request comes from a tracker, in a 3rd party
+  // context, when anti-tracking protection is enabled and when we don't have
+  // access to the first-party cookie jar.
+  if (aIsForeign && aIsTrackingResource && !aFirstPartyStorageAccessGranted &&
+      aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER) {
+      COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled in trackers");
+      return STATUS_REJECTED;
+  }
+
   // check default prefs
   if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
     COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
     return STATUS_REJECTED;
   }
 
   // check if cookie is foreign
   if (aIsForeign) {
@@ -4266,17 +4267,19 @@ nsCookieService::CheckPrefs(nsICookiePer
     if (aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
       if (aNumOfCookies == 0) {
         COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
         return STATUS_REJECTED;
       }
     }
 
     MOZ_ASSERT(aCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT ||
-               aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN);
+               aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
+               // But with permission granted.
+               aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
 
     if (aThirdPartySession)
       return STATUS_ACCEPT_SESSION;
 
     if (aThirdPartyNonsecureSession) {
       bool isHTTPS = false;
       aHostURI->SchemeIs("https", &isHTTPS);
       if (!isHTTPS)
--- a/netwerk/cookie/nsICookiePermission.idl
+++ b/netwerk/cookie/nsICookiePermission.idl
@@ -47,17 +47,17 @@ interface nsICookiePermission : nsISuppo
    *        the new cookie access for the URI.
    */
   void setAccess(in nsIURI         aURI,
                  in nsCookieAccess aAccess);
 
   /**
    * canAccess
    *
-   * this method is called to test whether or not the given URI/channel may
+   * this method is called to test whether or not the given principal may
    * access the cookie database, either to set or get cookies.
    *
    * @param aPrincipal
    *        the principal trying to access cookies.
    *
    * @return one of the following nsCookieAccess values:
    *         ACCESS_DEFAULT, ACCESS_ALLOW, ACCESS_DENY, or
    *         ACCESS_ALLOW_FIRST_PARTY_ONLY
--- a/netwerk/cookie/nsICookieService.idl
+++ b/netwerk/cookie/nsICookieService.idl
@@ -84,16 +84,19 @@ interface nsICookieService : nsISupports
   /*
    * Possible values for the "network.cookie.cookieBehavior" preference.
    */
   const uint32_t BEHAVIOR_ACCEPT         = 0; // allow all cookies
   const uint32_t BEHAVIOR_REJECT_FOREIGN = 1; // reject all third-party cookies
   const uint32_t BEHAVIOR_REJECT         = 2; // reject all cookies
   const uint32_t BEHAVIOR_LIMIT_FOREIGN  = 3; // reject third-party cookies unless the
                                               // eTLD already has at least one cookie
+  const uint32_t BEHAVIOR_REJECT_TRACKER = 4; // reject trackers
+  // When adding a new cookie behavior, please increase this value!
+  const uint32_t BEHAVIOR_LAST           = 4;
 
   /*
    * Possible values for the "network.cookie.lifetimePolicy" preference.
    */
   const uint32_t ACCEPT_NORMALLY   = 0; // accept normally
   // Value = 1 is considered the same as 0 (See Bug 606655).
   const uint32_t ACCEPT_SESSION    = 2; // downgrade to session
   // Value = 3 is considered the same as 0
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -17,16 +17,17 @@
 #include "nsHttpChannel.h"
 #include "nsHttpHandler.h"
 #include "nsIApplicationCacheService.h"
 #include "nsIApplicationCacheContainer.h"
 #include "nsICacheStorageService.h"
 #include "nsICacheStorage.h"
 #include "nsICacheEntry.h"
 #include "nsICaptivePortalService.h"
+#include "nsICookieService.h"
 #include "nsICryptoHash.h"
 #include "nsINetworkInterceptController.h"
 #include "nsINSSErrorsService.h"
 #include "nsISecurityReporter.h"
 #include "nsIStringBundle.h"
 #include "nsIStreamListenerTee.h"
 #include "nsISeekableStream.h"
 #include "nsILoadGroupChild.h"
@@ -50,16 +51,17 @@
 #include "mozilla/TimeStamp.h"
 #include "nsError.h"
 #include "nsPrintfCString.h"
 #include "nsAlgorithm.h"
 #include "nsQueryObject.h"
 #include "nsThreadUtils.h"
 #include "GeckoProfiler.h"
 #include "nsIConsoleService.h"
+#include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsISSLSocketControl.h"
 #include "sslt.h"
 #include "nsContentUtils.h"
 #include "nsContentSecurityManager.h"
@@ -98,17 +100,16 @@
 #include "nsIDocument.h"
 #include "nsICompressConvStats.h"
 #include "nsCORSListenerProxy.h"
 #include "nsISocketProvider.h"
 #include "mozilla/extensions/StreamFilterParent.h"
 #include "mozilla/net/Predictor.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/NullPrincipal.h"
-#include "mozilla/StaticPrefs.h"
 #include "CacheControlParser.h"
 #include "nsMixedContentBlocker.h"
 #include "CacheStorageService.h"
 #include "HttpChannelParent.h"
 #include "InterceptedHttpChannel.h"
 #include "nsIBufferedStreams.h"
 #include "nsIFileStreams.h"
 #include "nsIMIMEInputStream.h"
@@ -433,20 +434,80 @@ nsHttpChannel::LogBlockedCORSRequest(con
     return NS_ERROR_UNEXPECTED;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel <private>
 //-----------------------------------------------------------------------------
 
 nsresult
+nsHttpChannel::PrepareToConnect()
+{
+    LOG(("nsHttpChannel::PrepareToConnect [this=%p]\n", this));
+
+    AddCookiesToRequest();
+
+    // notify "http-on-modify-request" observers
+    CallOnModifyRequestObservers();
+
+    SetLoadGroupUserAgentOverride();
+
+    // Check if request was cancelled during on-modify-request or on-useragent.
+    if (mCanceled) {
+        return mStatus;
+    }
+
+    if (mSuspendCount) {
+        // We abandon the connection here if there was one.
+        LOG(("Waiting until resume OnBeforeConnect [this=%p]\n", this));
+        MOZ_ASSERT(!mCallOnResume);
+        mCallOnResume = &nsHttpChannel::HandleOnBeforeConnect;
+        return NS_OK;
+    }
+
+    return OnBeforeConnect();
+}
+
+void
+nsHttpChannel::HandleOnBeforeConnect()
+{
+    MOZ_ASSERT(!mCallOnResume, "How did that happen?");
+    nsresult rv;
+
+    if (mSuspendCount) {
+        LOG(("Waiting until resume OnBeforeConnect [this=%p]\n", this));
+        mCallOnResume = &nsHttpChannel::HandleOnBeforeConnect;
+        return;
+    }
+
+    LOG(("nsHttpChannel::HandleOnBeforeConnect [this=%p]\n", this));
+    rv = OnBeforeConnect();
+    if (NS_FAILED(rv)) {
+        CloseCacheEntry(false);
+        Unused << AsyncAbort(rv);
+    }
+}
+
+nsresult
 nsHttpChannel::OnBeforeConnect()
 {
     nsresult rv;
 
+    // Check if request was cancelled during suspend AFTER on-modify-request or
+    // on-useragent.
+    if (mCanceled) {
+        return mStatus;
+    }
+
+    // Check to see if we should redirect this channel elsewhere by
+    // nsIHttpChannel.redirectTo API request
+    if (mAPIRedirectToURI) {
+        return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
+    }
+
     // Note that we are only setting the "Upgrade-Insecure-Requests" request
     // header for *all* navigational requests instead of all requests as
     // defined in the spec, see:
     // https://www.w3.org/TR/upgrade-insecure-requests/#preference
     nsContentPolicyType type = mLoadInfo ?
                                mLoadInfo->GetExternalContentPolicyType() :
                                nsIContentPolicy::TYPE_OTHER;
 
@@ -3824,38 +3885,36 @@ nsHttpChannel::OpenCacheEntryInternal(bo
 
     if (mPostID) {
         extension.Append(nsPrintfCString("%d", mPostID));
     }
     if (mTRR) {
         extension.Append("TRR");
     }
 
-    if (StaticPrefs::privacy_restrict3rdpartystorage_enabled() &&
-        mIsTrackingResource) {
-        nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
-            services::GetThirdPartyUtil();
-        if (thirdPartyUtil) {
-            bool thirdParty = false;
-            Unused << thirdPartyUtil->IsThirdPartyChannel(this,
-                                                          nullptr,
-                                                          &thirdParty);
-            if (thirdParty) {
-                nsCOMPtr<nsIURI> topWindowURI;
-                rv = GetTopWindowURI(getter_AddRefs(topWindowURI));
-                NS_ENSURE_SUCCESS(rv, rv);
-
-                nsAutoString topWindowOrigin;
-                rv = nsContentUtils::GetUTFOrigin(topWindowURI, topWindowOrigin);
-                NS_ENSURE_SUCCESS(rv, rv);
-
-                extension.Append("-trackerFor:");
-                extension.Append(NS_ConvertUTF16toUTF8(topWindowOrigin));
-            }
-        }
+    if (!AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(this, mURI)) {
+        nsCOMPtr<nsIURI> topWindowURI;
+        rv = GetTopWindowURI(getter_AddRefs(topWindowURI));
+        bool isDocument = false;
+        if (NS_FAILED(rv) &&
+            NS_SUCCEEDED(GetIsMainDocumentChannel(&isDocument)) &&
+            isDocument) {
+          // For top-level documents, use the document channel's origin to compute
+          // the unique storage space identifier instead of the top Window URI.
+          rv = NS_GetFinalChannelURI(this, getter_AddRefs(topWindowURI));
+          NS_ENSURE_SUCCESS(rv, rv);
+        }
+
+        nsAutoString topWindowOrigin;
+        rv = nsContentUtils::GetUTFOrigin(topWindowURI ? topWindowURI : mURI,
+                                          topWindowOrigin);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        extension.Append("-unique:");
+        extension.Append(NS_ConvertUTF16toUTF8(topWindowOrigin));
     }
 
     mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY;
     mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority);
 
     if (sRCWNEnabled && maybeRCWN && !mApplicationCacheForWrite) {
         bool hasAltData = false;
         uint32_t sizeInKb = 0;
@@ -6115,18 +6174,16 @@ nsHttpChannel::AsyncOpen(nsIStreamListen
     }
 
     // Remember the cookie header that was set, if any
     nsAutoCString cookieHeader;
     if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Cookie, cookieHeader))) {
         mUserSetCookieHeader = cookieHeader;
     }
 
-    AddCookiesToRequest();
-
     // Set user agent override, do so before OnOpeningRequest notification
     // since we want to allow consumers of that notification change or remove
     // the User-Agent request header.
     HttpBaseChannel::SetDocshellUserAgentOverride();
 
     // After we notify any observers (on-opening-request, loadGroup, etc) we
     // must return NS_OK and return any errors asynchronously via
     // OnStart/OnStopRequest.  Observers may add a reference to the channel
@@ -6329,73 +6386,16 @@ nsHttpChannel::BeginConnect()
     // check to see if authorization headers should be included
     // mCustomAuthHeader is set in AsyncOpen if we find Authorization header
     rv = mAuthProvider->AddAuthorizationHeaders(mCustomAuthHeader);
     if (NS_FAILED(rv)) {
         LOG(("nsHttpChannel %p AddAuthorizationHeaders failed (%08x)",
              this, static_cast<uint32_t>(rv)));
     }
 
-    // notify "http-on-modify-request" observers
-    CallOnModifyRequestObservers();
-
-    SetLoadGroupUserAgentOverride();
-
-    // Check if request was cancelled during on-modify-request or on-useragent.
-    if (mCanceled) {
-        return mStatus;
-    }
-
-    if (mSuspendCount) {
-        LOG(("Waiting until resume BeginConnect [this=%p]\n", this));
-        MOZ_ASSERT(!mCallOnResume);
-        mCallOnResume = &nsHttpChannel::HandleBeginConnectContinue;
-        return NS_OK;
-    }
-
-    return BeginConnectContinue();
-}
-
-void
-nsHttpChannel::HandleBeginConnectContinue()
-{
-    MOZ_ASSERT(!mCallOnResume, "How did that happen?");
-    nsresult rv;
-
-    if (mSuspendCount) {
-        LOG(("Waiting until resume BeginConnect [this=%p]\n", this));
-        mCallOnResume = &nsHttpChannel::HandleBeginConnectContinue;
-        return;
-    }
-
-    LOG(("nsHttpChannel::HandleBeginConnectContinue [this=%p]\n", this));
-    rv = BeginConnectContinue();
-    if (NS_FAILED(rv)) {
-        CloseCacheEntry(false);
-        Unused << AsyncAbort(rv);
-    }
-}
-
-nsresult
-nsHttpChannel::BeginConnectContinue()
-{
-    nsresult rv;
-
-    // Check if request was cancelled during suspend AFTER on-modify-request or
-    // on-useragent.
-    if (mCanceled) {
-        return mStatus;
-    }
-
-    // Check to see if we should redirect this channel elsewhere by
-    // nsIHttpChannel.redirectTo API request
-    if (mAPIRedirectToURI) {
-        return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
-    }
-
     // If mTimingEnabled flag is not set after OnModifyRequest() then
     // clear the already recorded AsyncOpen value for consistency.
     if (!mTimingEnabled)
         mAsyncOpenTime = TimeStamp();
 
     // if this somehow fails we can go on without it
     Unused << gHttpHandler->AddConnectionHeader(&mRequestHead, mCaps);
 
@@ -6657,17 +6657,17 @@ nsHttpChannel::ContinueBeginConnectWithR
         LOG(("Waiting until resume to do async connect [this=%p]\n", this));
         mCallOnResume = &nsHttpChannel::ContinueBeginConnect;
         rv = NS_OK;
     } else if (mCanceled) {
         // We may have been cancelled already, by nsChannelClassifier in that
         // case, we should not send the request to the server
         rv = mStatus;
     } else {
-        rv = OnBeforeConnect();
+        rv = PrepareToConnect();
     }
 
     LOG(("nsHttpChannel::ContinueBeginConnectWithResult result [this=%p rv=%" PRIx32
          " mCanceled=%u]\n",
          this, static_cast<uint32_t>(rv), static_cast<bool>(mCanceled)));
     return rv;
 }
 
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -290,20 +290,20 @@ private:
     nsresult BeginConnectActual();
 
     // We might synchronously or asynchronously call BeginConnectActual,
     // which includes DNS prefetch and speculative connection, according to
     // whether an async tracker lookup is required. If the tracker lookup
     // is required, this funciton will just return NS_OK and BeginConnectActual()
     // will be called when callback. See Bug 1325054 for more information.
     nsresult BeginConnect();
-    void     HandleBeginConnectContinue();
-    MOZ_MUST_USE nsresult BeginConnectContinue();
     MOZ_MUST_USE nsresult ContinueBeginConnectWithResult();
     void     ContinueBeginConnect();
+    MOZ_MUST_USE nsresult PrepareToConnect();
+    void HandleOnBeforeConnect();
     MOZ_MUST_USE nsresult OnBeforeConnect();
     void     OnBeforeConnectContinue();
     MOZ_MUST_USE nsresult Connect();
     void     SpeculativeConnect();
     MOZ_MUST_USE nsresult SetupTransaction();
     MOZ_MUST_USE nsresult CallOnStartRequest();
     MOZ_MUST_USE nsresult ProcessResponse();
     void                  AsyncContinueProcessResponse();
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -474,17 +474,17 @@ interface nsIHttpChannel : nsIChannel
      */
     [must_use] attribute uint64_t topLevelContentWindowId;
 
     /**
      * Returns true if the channel has loaded a resource that is on the tracking
      * protection list.  This is only available if the
      * privacy.trackingprotection.annotate_channels pref is set and its value
      * should only be relied on after the channel has established a connection.
-     * Note that, if privacy.restrict3rdpartystorage.enabled pref is set, also
+     * Note that, if the privacy.trackingprotection.annotate_channels pref is set, also
      * top-level channels could be marked as tracking resource.
      */
     [infallible] readonly attribute boolean isTrackingResource;
 
     /**
      * This method is used in order to override the tracking status of an HTTP
      * channel.  This should only be called by Gecko under certain circumstances
      * when Gecko can guarantee that the channel classifier service will not be
--- a/old-configure.in
+++ b/old-configure.in
@@ -3464,16 +3464,27 @@ if test -n "$MOZ_OPTIMIZE"; then
         [printf("Hello World\n");],
         _results=yes,
         _results=no)
     AC_MSG_RESULT([$_results])
     if test "$_results" = "no"; then
         AC_MSG_ERROR([These compiler flags for C are invalid: $MOZ_OPTIMIZE_FLAGS])
     fi
     CFLAGS=$_SAVE_CFLAGS
+    if test -n "$MOZ_LTO" -a -n "$CLANG_CC"; then
+        # When using llvm-based LTO, non numeric optimization levels are
+        # not supported by the linker, so force the linker to use -O2 (
+        # which doesn't influence the level compilation units are actually
+        # compiled at).
+        case " $MOZ_OPTIMIZE_FLAGS " in
+        *\ -Os\ *|*\ -Oz\ *)
+            MOZ_OPTIMIZE_LDFLAGS="$MOZ_OPTIMIZE_LDFLAGS -O2"
+            ;;
+        esac
+    fi
 fi
 fi # COMPILE_ENVIRONMENT
 
 AC_SUBST_LIST(MOZ_FRAMEPTR_FLAGS)
 AC_SUBST_LIST(MOZ_OPTIMIZE_FLAGS)
 AC_SUBST_LIST(MOZ_OPTIMIZE_LDFLAGS)
 AC_SUBST_LIST(MOZ_PGO_OPTIMIZE_FLAGS)
 
--- a/taskcluster/ci/packages/kind.yml
+++ b/taskcluster/ci/packages/kind.yml
@@ -133,22 +133,35 @@ jobs:
       dsc:
         url: http://snapshot.debian.org/archive/debian/20160317T100542Z/pool/main/g/git/git_2.8.0%7Erc3-1.dsc
         sha256: 6e81a318fb4eb5cca0333b7b6ff0c70dd0097e9fe711b159d5eac4b9f47c6c27
 
   deb7-valgrind:
     description: "Valgrind for Debian Wheezy"
     treeherder:
       symbol: Deb7(valgrind)
+    worker:
+      env:
+        VERSION: 3.14.0.git20180806
+        COMMIT: 2eb2df759f51b15702934dee108f4c20c3db5fef
     run:
       using: debian-package
       dsc:
         url: http://snapshot.debian.org/archive/debian/20170725T040438Z/pool/main/v/valgrind/valgrind_3.13.0-1.dsc
         sha256: ab84e017d1660efd30e9e0593a4c8b976aeda013cefb8c416dd284cc7222c11c
+      packages:
+        - deb7-git
       patch: valgrind-wheezy.diff
+      pre-build-command: >-
+        git clone -n git://sourceware.org/git/valgrind.git ../valgrind-git &&
+        git -C ../valgrind-git archive --format=tar --prefix=valgrind-$VERSION/ $COMMIT | bzip2 > ../valgrind_$VERSION.orig.tar.bz2 &&
+        tar -C .. -jxf ../valgrind_$VERSION.orig.tar.bz2 &&
+        cp -r debian ../valgrind-$VERSION &&
+        cd ../valgrind-$VERSION &&
+        debchange -v 1:$VERSION-1.deb7moz1 --distribution wheezy "Mozilla backport of git master as of 2018-08-06." < /dev/null
 
   deb7-dh-python:
     description: "dh-python for Debian wheezy"
     treeherder:
       symbol: Deb7(dh-python)
     run:
       using: debian-package
       dsc:
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -8,20 +8,23 @@
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/AbstractThread.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindowInner.h"
+#include "nsICookiePermission.h"
+#include "nsICookieService.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
+#include "nsScriptSecurityManager.h"
 #include "prtime.h"
 
 #define ANTITRACKING_PERM_KEY "3rdPartyStorage"
 
 using namespace mozilla;
 using mozilla::dom::ContentChild;
 
 namespace {
@@ -66,25 +69,63 @@ CreatePermissionKey(const nsCString& aTr
     return;
   }
 
   aPermissionKey = nsPrintfCString(ANTITRACKING_PERM_KEY "^%s^%s",
                                    aTrackingOrigin.get(),
                                    aGrantedOrigin.get());
 }
 
+// This internal method returns ACCESS_DENY if the access is denied,
+// ACCESS_DEFAULT if unknown, some other access code if granted.
+nsCookieAccess
+CheckCookiePermissionForPrincipal(nsIPrincipal* aPrincipal)
+{
+  nsCookieAccess access = nsICookiePermission::ACCESS_DEFAULT;
+  if (!aPrincipal->GetIsCodebasePrincipal()) {
+    return access;
+  }
+
+  nsCOMPtr<nsICookiePermission> cps =
+    do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
+  if (NS_WARN_IF(!cps)) {
+    return access;
+  }
+
+  nsresult rv = cps->CanAccess(aPrincipal, &access);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return access;
+  }
+
+  // If we have a custom cookie permission, let's use it.
+  return access;
+}
+
+int32_t
+CookiesBehavior(nsIPrincipal* aPrincipal)
+{
+  // WebExtensions principals always get BEHAVIOR_ACCEPT as cookieBehavior
+  // (See Bug 1406675 for rationale).
+  if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
+    return nsICookieService::BEHAVIOR_ACCEPT;
+  }
+
+  return StaticPrefs::network_cookie_cookieBehavior();
+}
+
 } // anonymous
 
 /* static */ RefPtr<AntiTrackingCommon::StorageAccessGrantPromise>
 AntiTrackingCommon::AddFirstPartyStorageAccessGrantedFor(const nsAString& aOrigin,
                                                          nsPIDOMWindowInner* aParentWindow)
 {
   MOZ_ASSERT(aParentWindow);
 
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
+  if (StaticPrefs::network_cookie_cookieBehavior() !=
+        nsICookieService::BEHAVIOR_REJECT_TRACKER) {
     return StorageAccessGrantPromise::CreateAndResolve(true, __func__);
   }
 
   nsCOMPtr<nsIPrincipal> topLevelStoragePrincipal;
   nsAutoCString trackingOrigin;
 
   nsGlobalWindowInner* parentWindow = nsGlobalWindowInner::Cast(aParentWindow);
   nsGlobalWindowOuter* outerParentWindow =
@@ -170,35 +211,70 @@ AntiTrackingCommon::SaveFirstPartyStorag
   nsresult rv = pm->AddFromPrincipal(aParentPrincipal, type.get(),
                                      nsIPermissionManager::ALLOW_ACTION,
                                      nsIPermissionManager::EXPIRE_TIME, when);
   Unused << NS_WARN_IF(NS_FAILED(rv));
   aResolver(NS_SUCCEEDED(rv));
 }
 
 bool
-AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* a3rdPartyTrackingWindow,
+AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aWindow,
                                                         nsIURI* aURI)
 {
-  MOZ_ASSERT(a3rdPartyTrackingWindow);
+  MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aURI);
 
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
+  nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
+  nsIPrincipal* toplevelPrincipal = innerWindow->GetTopLevelPrincipal();
+  if (!toplevelPrincipal) {
+    // We are already the top-level principal. Let's use the window's principal.
+    toplevelPrincipal = innerWindow->GetPrincipal();
+  }
+
+  if (!toplevelPrincipal) {
+    // This should not be possible, right?
+    return false;
+  }
+
+  nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal);
+  if (access != nsICookiePermission::ACCESS_DEFAULT) {
+    return access != nsICookiePermission::ACCESS_DENY;
+  }
+
+  int32_t behavior = CookiesBehavior(toplevelPrincipal);
+  if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
     return true;
   }
 
-  if (!nsContentUtils::IsThirdPartyWindowOrChannel(a3rdPartyTrackingWindow,
-                                                   nullptr, aURI) ||
-      !nsContentUtils::IsTrackingResourceWindow(a3rdPartyTrackingWindow)) {
+  if (behavior == nsICookieService::BEHAVIOR_REJECT) {
+    return false;
+  }
+
+  // Let's check if this is a 3rd party context.
+  if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, nullptr, aURI)) {
+    return true;
+  }
+
+  if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
+      behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
+    // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
+    // simply rejecting the request to use the storage. In the future, if we
+    // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
+    // for non-cookie storage types, this may change.
+    return false;
+  }
+
+  MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
+  if (!nsContentUtils::IsTrackingResourceWindow(aWindow)) {
     return true;
   }
 
   nsCOMPtr<nsIPrincipal> parentPrincipal;
   nsAutoCString trackingOrigin;
-  if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(a3rdPartyTrackingWindow),
+  if (!GetParentPrincipalAndTrackingOrigin(nsGlobalWindowInner::Cast(aWindow),
                                            getter_AddRefs(parentPrincipal),
                                            trackingOrigin)) {
     return false;
   }
 
   nsAutoString origin;
   nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -223,40 +299,124 @@ AntiTrackingCommon::IsFirstPartyStorageA
 }
 
 bool
 AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel,
                                                         nsIURI* aURI)
 {
   MOZ_ASSERT(aURI);
   MOZ_ASSERT(aChannel);
-  MOZ_ASSERT(aChannel->GetIsTrackingResource());
 
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
   if (!loadInfo) {
     return true;
   }
 
+  // We need to find the correct principal to check the cookie permission. For
+  // third-party contexts, we want to check if the top-level window has a custom
+  // cookie permission.
+  nsIPrincipal* toplevelPrincipal = loadInfo->TopLevelPrincipal();
+
+  // If this is already the top-level window, we should use the loading
+  // principal.
+  if (!toplevelPrincipal) {
+    toplevelPrincipal = loadInfo->LoadingPrincipal();
+  }
+
+  nsCOMPtr<nsIPrincipal> channelPrincipal;
+  nsIScriptSecurityManager* ssm = nsScriptSecurityManager::GetScriptSecurityManager();
+  nsresult rv = ssm->GetChannelResultPrincipal(aChannel,
+                                               getter_AddRefs(channelPrincipal));
+
+  // If we don't have a loading principal and this is a document channel, we are
+  // a top-level window!
+  if (!toplevelPrincipal) {
+    bool isDocument = false;
+    nsresult rv2 = aChannel->GetIsMainDocumentChannel(&isDocument);
+    if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2) && isDocument) {
+      toplevelPrincipal = channelPrincipal;
+    }
+  }
+
+  // Let's use the triggering principal then.
+  if (!toplevelPrincipal) {
+    toplevelPrincipal = loadInfo->TriggeringPrincipal();
+  }
+
+  if (NS_WARN_IF(!toplevelPrincipal)) {
+    return false;
+  }
+
+  nsCookieAccess access = CheckCookiePermissionForPrincipal(toplevelPrincipal);
+  if (access != nsICookiePermission::ACCESS_DEFAULT) {
+    return access != nsICookiePermission::ACCESS_DENY;
+  }
+
+  if (NS_WARN_IF(NS_FAILED(rv) || !channelPrincipal)) {
+    return false;
+  }
+
+  int32_t behavior = CookiesBehavior(channelPrincipal);
+  if (behavior == nsICookieService::BEHAVIOR_ACCEPT) {
+    return true;
+  }
+
+  if (behavior == nsICookieService::BEHAVIOR_REJECT) {
+    return false;
+  }
+
+  nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil = services::GetThirdPartyUtil();
+  if (!thirdPartyUtil) {
+    return true;
+  }
+
+  bool thirdParty = false;
+  Unused << thirdPartyUtil->IsThirdPartyChannel(aChannel,
+                                                nullptr,
+                                                &thirdParty);
+  // Grant if it's not a 3rd party.
+  if (!thirdParty) {
+    return true;
+  }
+
+  if (behavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
+      behavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
+    // XXX For non-cookie forms of storage, we handle BEHAVIOR_LIMIT_FOREIGN by
+    // simply rejecting the request to use the storage. In the future, if we
+    // change the meaning of BEHAVIOR_LIMIT_FOREIGN to be one which makes sense
+    // for non-cookie storage types, this may change.
+    return false;
+  }
+
+  MOZ_ASSERT(behavior == nsICookieService::BEHAVIOR_REJECT_TRACKER);
+
   nsIPrincipal* parentPrincipal = loadInfo->TopLevelStorageAreaPrincipal();
   if (!parentPrincipal) {
     // parentPrincipal can be null if the parent window is not the top-level
     // window.
     if (loadInfo->TopLevelPrincipal()) {
       return false;
     }
 
     parentPrincipal = loadInfo->TriggeringPrincipal();
     if (NS_WARN_IF(!parentPrincipal)) {
       // Why we are here?!?
       return true;
     }
   }
 
+  // Not a tracker.
+  if (!aChannel->GetIsTrackingResource()) {
+    return true;
+  }
+
+  // Let's see if we have to grant the access for this particular channel.
+
   nsCOMPtr<nsIURI> trackingURI;
-  nsresult rv = aChannel->GetURI(getter_AddRefs(trackingURI));
+  rv = aChannel->GetURI(getter_AddRefs(trackingURI));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return true;
   }
 
   nsAutoString trackingOrigin;
   rv = nsContentUtils::GetUTFOrigin(trackingURI, trackingOrigin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
@@ -281,39 +441,59 @@ AntiTrackingCommon::IsFirstPartyStorageA
   rv = pm->TestPermissionFromPrincipal(parentPrincipal, type.get(), &result);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   return result == nsIPermissionManager::ALLOW_ACTION;
 }
 
+bool
+AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal)
+{
+  MOZ_ASSERT(aPrincipal);
+
+  nsCookieAccess access = CheckCookiePermissionForPrincipal(aPrincipal);
+  if (access != nsICookiePermission::ACCESS_DEFAULT) {
+    return access != nsICookiePermission::ACCESS_DENY;
+  }
+
+  int32_t behavior = CookiesBehavior(aPrincipal);
+  return behavior != nsICookieService::BEHAVIOR_REJECT;
+}
+
 /* static */ bool
 AntiTrackingCommon::MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow,
                                                              nsIURI* aURI)
 {
   MOZ_ASSERT(aFirstPartyWindow);
   MOZ_ASSERT(!nsContentUtils::IsTrackingResourceWindow(aFirstPartyWindow));
   MOZ_ASSERT(aURI);
 
-  if (!StaticPrefs::privacy_restrict3rdpartystorage_enabled()) {
+  if (StaticPrefs::network_cookie_cookieBehavior() !=
+        nsICookieService::BEHAVIOR_REJECT_TRACKER) {
     return true;
   }
 
   if (!nsContentUtils::IsThirdPartyWindowOrChannel(aFirstPartyWindow,
                                                    nullptr, aURI)) {
     return true;
   }
 
   nsCOMPtr<nsIPrincipal> parentPrincipal =
     nsGlobalWindowInner::Cast(aFirstPartyWindow)->GetPrincipal();
   if (NS_WARN_IF(!parentPrincipal)) {
     return false;
   }
 
+  nsCookieAccess access = CheckCookiePermissionForPrincipal(parentPrincipal);
+  if (access != nsICookiePermission::ACCESS_DEFAULT) {
+    return access != nsICookiePermission::ACCESS_DENY;
+  }
+
   nsAutoString origin;
   nsresult rv = nsContentUtils::GetUTFOrigin(aURI, origin);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   NS_ConvertUTF16toUTF8 utf8Origin(origin);
 
--- a/toolkit/components/antitracking/AntiTrackingCommon.h
+++ b/toolkit/components/antitracking/AntiTrackingCommon.h
@@ -41,22 +41,25 @@ public:
   // For first party window, it's impossible to know if the aURI is a tracking
   // resource synchronously, so here we return the best guest: if we are sure
   // that the permission is granted for the origin of aURI, this method returns
   // true, otherwise false.
   static bool
   MaybeIsFirstPartyStorageAccessGrantedFor(nsPIDOMWindowInner* aFirstPartyWindow,
                                            nsIURI* aURI);
 
-  // This can be called only if the a3rdPartyTrackingChannel is _really_ a 3rd
-  // party context and marked as tracking resource.
   // It returns true if the URI has access to the first party storage.
+  // aChannel can be a 3rd party channel, or not.
   static bool
-  IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* a3rdPartyTrackingChannel,
-                                      nsIURI* aURI);
+  IsFirstPartyStorageAccessGrantedFor(nsIHttpChannel* aChannel, nsIURI* aURI);
+
+  // This method checks if the principal has the permission to access to the
+  // first party storage.
+  static bool
+  IsFirstPartyStorageAccessGrantedFor(nsIPrincipal* aPrincipal);
 
   // Grant the permission for aOrigin to have access to the first party storage.
   // This method can handle 2 different scenarios:
   // - aParentWindow is a 3rd party context, it opens an aOrigin window and the
   //   user interacts with it. We want to grant the permission at the
   //   combination: top-level + aParentWindow + aOrigin.
   //   Ex: example.net loads an iframe tracker.com, which opens a popup
   //   tracker.prg and the user interacts with it. tracker.org is allowed if
--- a/toolkit/components/antitracking/test/browser/3rdParty.html
+++ b/toolkit/components/antitracking/test/browser/3rdParty.html
@@ -16,16 +16,16 @@ function ok(what, msg) {
 
 function is(a, b, msg) {
   ok(a === b, msg);
 }
 
 onmessage = function(e) {
   let runnableStr = `(() => {return (${e.data});})();`;
   let runnable = eval(runnableStr); // eslint-disable-line no-eval
-  runnable.call(this).then(_ => {
+  runnable.call(this, /* Phase */ 1).then(_ => {
     parent.postMessage({ type: "finish" }, "*");
   });
 };
 
 </script>
 </body>
 </html>
--- a/toolkit/components/antitracking/test/browser/3rdPartyOpen.html
+++ b/toolkit/components/antitracking/test/browser/3rdPartyOpen.html
@@ -1,15 +1,17 @@
 <html>
 <head>
   <title>A popup!</title>
 </head>
 <body>
 <h1>hi!</h1>
 <script>
 
-opener.postMessage("hello!", "*");
+if (opener) {
+  opener.postMessage("hello!", "*");
+}
 window.close();
 
 </script>
 </body>
 </html>
 
--- a/toolkit/components/antitracking/test/browser/3rdPartyUI.html
+++ b/toolkit/components/antitracking/test/browser/3rdPartyUI.html
@@ -16,16 +16,16 @@ function ok(what, msg) {
 
 function is(a, b, msg) {
   ok(a === b, msg);
 }
 
 onmessage = function(e) {
   let runnableStr = `(() => {return (${e.data.callback});})();`;
   let runnable = eval(runnableStr); // eslint-disable-line no-eval
-  runnable.call(this).then(_ => {
+  runnable.call(this, /* Phase */ 3).then(_ => {
     parent.postMessage({ type: "finish" }, "*");
   });
 };
 
 </script>
 </body>
 </html>
--- a/toolkit/components/antitracking/test/browser/3rdPartyWO.html
+++ b/toolkit/components/antitracking/test/browser/3rdPartyWO.html
@@ -16,27 +16,36 @@ function ok(what, msg) {
 
 function is(a, b, msg) {
   ok(a === b, msg);
 }
 
 onmessage = function(e) {
   let runnableStr = `(() => {return (${e.data.blockingCallback});})();`;
   let runnable = eval(runnableStr); // eslint-disable-line no-eval
-  runnable.call(this).then(_ => {
+  runnable.call(this, /* Phase */ 2).then(_ => {
     info("Let's do a window.open()");
     return new Promise(resolve => {
-      onmessage = resolve;
-      window.open("3rdPartyOpen.html");
+
+      if (location.search == "?noopener") {
+        let features = "noopener";
+
+        window.open("3rdPartyOpen.html", undefined, features);
+        setTimeout(resolve, 1000);
+      } else {
+        onmessage = resolve;
+
+        window.open("3rdPartyOpen.html");
+      }
     });
   }).then(_ => {
     info("The popup has been dismissed!");
     let runnableStr = `(() => {return (${e.data.nonBlockingCallback});})();`;
     let runnable = eval(runnableStr); // eslint-disable-line no-eval
-    return runnable.call(this);
+    return runnable.call(this, /* Phase */ 2);
   }).then(_ => {
     parent.postMessage({ type: "finish" }, "*");
   });
 };
 
 </script>
 </body>
 </html>
--- a/toolkit/components/antitracking/test/browser/browser.ini
+++ b/toolkit/components/antitracking/test/browser/browser.ini
@@ -11,14 +11,16 @@ support-files =
   popup.html
 
 [browser_blockingCookies.js]
 support-files = server.sjs
 [browser_blockingIndexedDb.js]
 [browser_blockingStorage.js]
 [browser_blockingWorkers.js]
 [browser_blockingMessaging.js]
+[browser_blockingNoOpener.js]
+[browser_existingCookiesForSubresources.js]
 [browser_imageCache.js]
 support-files = image.sjs
 [browser_subResources.js]
 support-files = subResources.sjs
 [browser_script.js]
 support-files = tracker.js
new file mode 100644
--- /dev/null
+++ b/toolkit/components/antitracking/test/browser/browser_blockingNoOpener.js
@@ -0,0 +1,35 @@
+gFeatures = "noopener";
+
+AntiTracking.runTest("Blocking in the case of noopener windows",
+  async _ => {
+    try {
+      localStorage.foo = 42;
+      ok(false, "LocalStorage cannot be used!");
+    } catch (e) {
+      ok(true, "LocalStorage cannot be used!");
+      is(e.name, "SecurityError", "We want a security error message.");
+    }
+  },
+  async phase => {
+    switch (phase) {
+      case 1:
+        localStorage.foo = 42;
+        ok(true, "LocalStorage is allowed");
+        break;
+      case 2:
+        try {
+          localStorage.foo = 42;
+          ok(false, "LocalStorage cannot be used!");
+        } catch (e) {
+          ok(true, "LocalStorage cannot be used!");
+          is(e.name, "SecurityError", "We want a security error message.");
+        }
+        break;
+    }
+  },
+  async _ => {
+    await new Promise(resolve => {
+      Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
+    });
+  },
+  null, true, false);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/antitracking/test/browser/browser_existingCookiesForSubresources.js
@@ -0,0 +1,183 @@
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+add_task(async function() {
+  info("Starting subResources test");
+
+  await SpecialPowers.flushPrefEnv();
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["privacy.trackingprotection.enabled", false],
+    ["privacy.trackingprotection.pbmode.enabled", false],
+    ["privacy.trackingprotection.annotate_channels", true],
+  ]});
+
+  await UrlClassifierTestUtils.addTestTrackers();
+
+  info("Creating a new tab");
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_3RD_PARTY_PAGE);
+  gBrowser.selectedTab = tab;
+
+  let browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  info("Loading tracking scripts and tracking images before restricting 3rd party cookies");
+  await ContentTask.spawn(browser, null, async function() {
+    // Let's load the script twice here.
+    {
+      let src = content.document.createElement("script");
+      let p = new content.Promise(resolve => { src.onload = resolve; });
+      content.document.body.appendChild(src);
+      src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script";
+      await p;
+    }
+    {
+      let src = content.document.createElement("script");
+      let p = new content.Promise(resolve => { src.onload = resolve; });
+      content.document.body.appendChild(src);
+      src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script";
+      await p;
+    }
+
+    // Let's load an image twice here.
+    {
+      let img = content.document.createElement("img");
+      let p = new content.Promise(resolve => { img.onload = resolve; });
+      content.document.body.appendChild(img);
+      img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image";
+      await p;
+    }
+    {
+      let img = content.document.createElement("img");
+      let p = new content.Promise(resolve => { img.onload = resolve; });
+      content.document.body.appendChild(img);
+      img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image";
+      await p;
+    }
+  });
+
+  await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=image")
+    .then(r => r.text())
+    .then(text => {
+      is(text, 1, "Cookies received for images");
+    });
+
+  await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=script")
+    .then(r => r.text())
+    .then(text => {
+      is(text, 1, "Cookies received for scripts");
+    });
+
+  info("Removing the tab");
+  BrowserTestUtils.removeTab(tab);
+
+  Services.perms.removeAll();
+
+  // Now set up our prefs
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
+  ]});
+
+  info("Creating a new tab");
+  tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
+  gBrowser.selectedTab = tab;
+
+  browser = gBrowser.getBrowserForTab(tab);
+  await BrowserTestUtils.browserLoaded(browser);
+
+  info("Creating a 3rd party content");
+  await ContentTask.spawn(browser,
+                          { page: TEST_3RD_PARTY_PAGE,
+                            callback: (async _ => {}).toString(),
+                          },
+                          async function(obj) {
+    await new content.Promise(resolve => {
+      let ifr = content.document.createElement("iframe");
+      ifr.onload = function() {
+        info("Sending code to the 3rd party content");
+        ifr.contentWindow.postMessage(obj.callback, "*");
+      };
+
+      content.addEventListener("message", function msg(event) {
+        if (event.data.type == "finish") {
+          content.removeEventListener("message", msg);
+          resolve();
+          return;
+        }
+
+        if (event.data.type == "ok") {
+          ok(event.data.what, event.data.msg);
+          return;
+        }
+
+        if (event.data.type == "info") {
+          info(event.data.msg);
+          return;
+        }
+
+        ok(false, "Unknown message");
+      });
+
+      content.document.body.appendChild(ifr);
+      ifr.src = obj.page;
+    });
+  });
+
+  info("Loading tracking scripts and tracking images again");
+  await ContentTask.spawn(browser, null, async function() {
+    // Let's load the script twice here.
+    {
+      let src = content.document.createElement("script");
+      let p = new content.Promise(resolve => { src.onload = resolve; });
+      content.document.body.appendChild(src);
+      src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script";
+      await p;
+    }
+    {
+      let src = content.document.createElement("script");
+      let p = new content.Promise(resolve => { src.onload = resolve; });
+      content.document.body.appendChild(src);
+      src.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=script";
+      await p;
+    }
+
+    // Let's load an image twice here.
+    {
+      let img = content.document.createElement("img");
+      let p = new content.Promise(resolve => { img.onload = resolve; });
+      content.document.body.appendChild(img);
+      img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image";
+      await p;
+    }
+    {
+      let img = content.document.createElement("img");
+      let p = new content.Promise(resolve => { img.onload = resolve; });
+      content.document.body.appendChild(img);
+      img.src = "https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?what=image";
+      await p;
+    }
+  });
+
+  await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=image")
+    .then(r => r.text())
+    .then(text => {
+      is(text, 0, "No cookie received for images.");
+    });
+
+  await fetch("https://tracking.example.org/browser/toolkit/components/antitracking/test/browser/subResources.sjs?result&what=script")
+    .then(r => r.text())
+    .then(text => {
+      is(text, 0, "No cookie received received for scripts.");
+    });
+
+  info("Removing the tab");
+  BrowserTestUtils.removeTab(tab);
+
+  UrlClassifierTestUtils.cleanupTestTrackers();
+});
+
+add_task(async function() {
+  info("Cleaning up.");
+  await new Promise(resolve => {
+    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
+  });
+});
+
--- a/toolkit/components/antitracking/test/browser/browser_script.js
+++ b/toolkit/components/antitracking/test/browser/browser_script.js
@@ -1,16 +1,16 @@
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 add_task(async function() {
   info("Starting subResources test");
 
   await SpecialPowers.flushPrefEnv();
   await SpecialPowers.pushPrefEnv({"set": [
-    ["privacy.restrict3rdpartystorage.enabled", true],
+    ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
     ["privacy.trackingprotection.enabled", false],
     ["privacy.trackingprotection.pbmode.enabled", false],
     ["privacy.trackingprotection.annotate_channels", true],
   ]});
 
   await UrlClassifierTestUtils.addTestTrackers();
 
   info("Creating a new tab");
--- a/toolkit/components/antitracking/test/browser/browser_subResources.js
+++ b/toolkit/components/antitracking/test/browser/browser_subResources.js
@@ -1,16 +1,16 @@
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 add_task(async function() {
   info("Starting subResources test");
 
   await SpecialPowers.flushPrefEnv();
   await SpecialPowers.pushPrefEnv({"set": [
-    ["privacy.restrict3rdpartystorage.enabled", true],
+    ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
     ["privacy.trackingprotection.enabled", false],
     ["privacy.trackingprotection.pbmode.enabled", false],
     ["privacy.trackingprotection.annotate_channels", true],
   ]});
 
   await UrlClassifierTestUtils.addTestTrackers();
 
   info("Creating a new tab");
--- a/toolkit/components/antitracking/test/browser/head.js
+++ b/toolkit/components/antitracking/test/browser/head.js
@@ -4,47 +4,51 @@ const TEST_3RD_PARTY_DOMAIN = "https://t
 const TEST_PATH = "browser/toolkit/components/antitracking/test/browser/";
 
 const TEST_TOP_PAGE = TEST_DOMAIN + TEST_PATH + "page.html";
 const TEST_POPUP_PAGE = TEST_DOMAIN + TEST_PATH + "popup.html";
 const TEST_3RD_PARTY_PAGE = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdParty.html";
 const TEST_3RD_PARTY_PAGE_WO = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyWO.html";
 const TEST_3RD_PARTY_PAGE_UI = TEST_3RD_PARTY_DOMAIN + TEST_PATH + "3rdPartyUI.html";
 
+var gFeatures = undefined;
+
 let {UrlClassifierTestUtils} = ChromeUtils.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
 
 this.AntiTracking = {
   runTest(name, callbackTracking, callbackNonTracking, cleanupFunction, extraPrefs, windowOpenTest = true, userInteractionTest = true) {
     // Here we want to test that a 3rd party context is simply blocked.
     this._createTask(name, true, callbackTracking, extraPrefs);
     this._createCleanupTask(cleanupFunction);
 
     if (callbackNonTracking) {
-      // Here we want to test that a 3rd party context is not blocked if pref is off.
+      // Phase 1: Here we want to test that a 3rd party context is not blocked if pref is off.
       this._createTask(name, false, callbackNonTracking);
       this._createCleanupTask(cleanupFunction);
 
-      // Permission granted when there is a window.open()
+      // Phase 2: Here we want to test that a third-party context doesn't
+      // get blocked with when the same origin is opened through window.open().
       if (windowOpenTest) {
         this._createWindowOpenTask(name, callbackTracking, callbackNonTracking, extraPrefs);
         this._createCleanupTask(cleanupFunction);
       }
 
-      // Permission granted when there is user-interaction.
+      // Phase 3: Here we want to test that a third-party context doesn't
+      // get blocked with user interaction present
       if (userInteractionTest) {
         this._createUserInteractionTask(name, callbackTracking, callbackNonTracking, extraPrefs);
         this._createCleanupTask(cleanupFunction);
       }
     }
   },
 
   async _setupTest(blocking, extraPrefs) {
     await SpecialPowers.flushPrefEnv();
     await SpecialPowers.pushPrefEnv({"set": [
-      ["privacy.restrict3rdpartystorage.enabled", blocking],
+      ["network.cookie.cookieBehavior", blocking ? Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER : Ci.nsICookieService.BEHAVIOR_ACCEPT],
       ["privacy.trackingprotection.enabled", false],
       ["privacy.trackingprotection.pbmode.enabled", false],
       ["privacy.trackingprotection.annotate_channels", blocking],
     ]});
 
     if (extraPrefs && Array.isArray(extraPrefs) && extraPrefs.length) {
       await SpecialPowers.pushPrefEnv({"set": extraPrefs });
     }
@@ -125,19 +129,24 @@ this.AntiTracking = {
 
       info("Creating a new tab");
       let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
       gBrowser.selectedTab = tab;
 
       let browser = gBrowser.getBrowserForTab(tab);
       await BrowserTestUtils.browserLoaded(browser);
 
+      let pageURL = TEST_3RD_PARTY_PAGE_WO;
+      if (gFeatures == "noopener") {
+        pageURL += "?noopener";
+      }
+
       info("Creating a 3rd party content");
       await ContentTask.spawn(browser,
-                              { page: TEST_3RD_PARTY_PAGE_WO,
+                              { page: pageURL,
                                 blockingCallback: blockingCallback.toString(),
                                 nonBlockingCallback: nonBlockingCallback.toString(),
                               },
                               async function(obj) {
         await new content.Promise(resolve => {
           let ifr = content.document.createElement("iframe");
           ifr.onload = function() {
             info("Sending code to the 3rd party content");
--- a/toolkit/crashreporter/CrashAnnotations.yaml
+++ b/toolkit/crashreporter/CrashAnnotations.yaml
@@ -573,16 +573,21 @@ ProxyStreamUnmarshalStatus:
     the various value this annotation can take.
   type: string
 
 ProxyStreamValid:
   description: >
     Set to "false" when encountering an invalid IPC proxy stream.
   type: string
 
+RecordReplayError:
+  description: >
+    Any fatal error that occurred while recording/replaying a tab.
+  type: string
+
 ReleaseChannel:
   description: >
     Application release channel (e.g. default, beta, ...)
   type: string
   ping: true
 
 RemoteType:
   description: >
--- a/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc
+++ b/toolkit/crashreporter/breakpad-client/mac/crash_generation/crash_generation_client.cc
@@ -27,16 +27,18 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "mac/crash_generation/crash_generation_client.h"
 
 #include "mac/crash_generation/crash_generation_server.h"
 #include "common/mac/MachIPC.h"
 
+#include "mozilla/recordreplay/ChildIPC.h"
+
 namespace google_breakpad {
 
 bool CrashGenerationClient::RequestDumpForException(
     int exception_type,
     int exception_code,
     int exception_subcode,
     mach_port_t crashing_thread) {
   // The server will send a message to this port indicating that it
@@ -48,16 +50,24 @@ bool CrashGenerationClient::RequestDumpF
   message.AddDescriptor(crashing_thread);             // crashing thread
   message.AddDescriptor(MACH_PORT_NULL);              // handler thread
   message.AddDescriptor(acknowledge_port.GetPort());  // message receive port
 
   ExceptionInfo info;
   info.exception_type = exception_type;
   info.exception_code = exception_code;
   info.exception_subcode = exception_subcode;
+  info.