Merge inbound to mozilla-central r=merge a=merge
authorCoroiu Cristina <ccoroiu@mozilla.com>
Sun, 12 Nov 2017 00:05:11 +0200
changeset 444691 f2eacbcd8f3d65d25bac4d9f49d0f692f109af3c
parent 444690 58b6b371c2f85614ab52dc2d6235e12af020dc1f (current diff)
parent 444685 e2dc5d006fc76e2e013d0d07a9707c20c2b3227c (diff)
child 444692 aabfc14671b55983e1c3053989a4c3b7c5691aaa
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central r=merge a=merge
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,11 +1,11 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Taken from upstream commit: be179268c9b89390c13bdc9c4cca6000f6f583e5
+Taken from upstream commit: 09d6d4f93135367b2639d78ad884434f73ab449c
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.0
 - babel-preset-react @6.24.1
 - react @15.6.2
 - react-dom @15.6.2
 - webpack @3.8.1
--- a/devtools/client/debugger/new/debugger.css
+++ b/devtools/client/debugger/new/debugger.css
@@ -3734,10 +3734,8 @@ html[dir="rtl"] .dropdown {
 
 .search-bar .result-list {
   border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .theme-dark .result-list {
   background-color: var(--theme-body-background);
 }
-
-/*# sourceMappingURL=debugger.css.map*/
\ No newline at end of file
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -17607,17 +17607,17 @@ exports.default = _Svg2.default;
 
 const {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId
 } = __webpack_require__(1389);
 
-const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1363);
+const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1390);
 
 const dispatcher = new WorkerDispatcher();
 
 const getOriginalURLs = dispatcher.task("getOriginalURLs");
 const getGeneratedLocation = dispatcher.task("getGeneratedLocation");
 const getOriginalLocation = dispatcher.task("getOriginalLocation");
 const getLocationScopes = dispatcher.task("getLocationScopes");
 const getOriginalSourceText = dispatcher.task("getOriginalSourceText");
@@ -18272,19 +18272,19 @@ WorkerDispatcher.prototype = {
         this.worker.postMessage({ id, method, args });
 
         const listener = ({ data: result }) => {
           if (result.id !== id) {
             return;
           }
 
           if (!this.worker) {
-            reject("Oops, The worker has shutdown!");
             return;
           }
+
           this.worker.removeEventListener("message", listener);
           if (result.error) {
             reject(result.error);
           } else {
             resolve(result.response);
           }
         };
 
@@ -20805,19 +20805,191 @@ module.exports = {
   generatedToOriginalId,
   isOriginalId,
   isGeneratedId,
   getContentType,
   contentMapForTesting: contentMap
 };
 
 /***/ }),
-/* 1390 */,
-/* 1391 */,
-/* 1392 */,
+/* 1390 */
+/***/ (function(module, exports, __webpack_require__) {
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+const networkRequest = __webpack_require__(1391);
+const workerUtils = __webpack_require__(1392);
+
+module.exports = {
+  networkRequest,
+  workerUtils
+};
+
+/***/ }),
+/* 1391 */
+/***/ (function(module, exports) {
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+function networkRequest(url, opts) {
+  return fetch(url, {
+    cache: opts.loadFromCache ? "default" : "no-cache"
+  }).then(res => {
+    if (res.status >= 200 && res.status < 300) {
+      return res.text().then(text => ({ content: text }));
+    }
+    return Promise.reject(`request failed with status ${res.status}`);
+  });
+}
+
+module.exports = networkRequest;
+
+/***/ }),
+/* 1392 */
+/***/ (function(module, exports) {
+
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
+function WorkerDispatcher() {
+  this.msgId = 1;
+  this.worker = null;
+} /* This Source Code Form is subject to the terms of the Mozilla Public
+   * 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/. */
+
+WorkerDispatcher.prototype = {
+  start(url) {
+    this.worker = new Worker(url);
+    this.worker.onerror = () => {
+      console.error(`Error in worker ${url}`);
+    };
+  },
+
+  stop() {
+    if (!this.worker) {
+      return;
+    }
+
+    this.worker.terminate();
+    this.worker = null;
+  },
+
+  task(method) {
+    return (...args) => {
+      return new Promise((resolve, reject) => {
+        const id = this.msgId++;
+        this.worker.postMessage({ id, method, args });
+
+        const listener = ({ data: result }) => {
+          if (result.id !== id) {
+            return;
+          }
+
+          if (!this.worker) {
+            reject("Oops, The worker has shutdown!");
+            return;
+          }
+          this.worker.removeEventListener("message", listener);
+          if (result.error) {
+            reject(result.error);
+          } else {
+            resolve(result.response);
+          }
+        };
+
+        this.worker.addEventListener("message", listener);
+      });
+    };
+  }
+};
+
+function workerHandler(publicInterface) {
+  return function (msg) {
+    const { id, method, args } = msg.data;
+    try {
+      const response = publicInterface[method].apply(undefined, args);
+      if (response instanceof Promise) {
+        response.then(val => self.postMessage({ id, response: val }),
+        // Error can't be sent via postMessage, so be sure to
+        // convert to string.
+        err => self.postMessage({ id, error: err.toString() }));
+      } else {
+        self.postMessage({ id, response });
+      }
+    } catch (error) {
+      // Error can't be sent via postMessage, so be sure to convert to
+      // string.
+      self.postMessage({ id, error: error.toString() });
+    }
+  };
+}
+
+function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker = self) {
+  let streamingWorker = (() => {
+    var _ref = _asyncToGenerator(function* (id, tasks) {
+      let isWorking = true;
+
+      const intervalId = setTimeout(function () {
+        isWorking = false;
+      }, timeout);
+
+      const results = [];
+      while (tasks.length !== 0 && isWorking) {
+        const { callback, context, args } = tasks.shift();
+        const result = yield callback.call(context, args);
+        results.push(result);
+      }
+      worker.postMessage({ id, status: "pending", data: results });
+      clearInterval(intervalId);
+
+      if (tasks.length !== 0) {
+        yield streamingWorker(id, tasks);
+      }
+    });
+
+    return function streamingWorker(_x, _x2) {
+      return _ref.apply(this, arguments);
+    };
+  })();
+
+  return (() => {
+    var _ref2 = _asyncToGenerator(function* (msg) {
+      const { id, method, args } = msg.data;
+      const workerMethod = publicInterface[method];
+      if (!workerMethod) {
+        console.error(`Could not find ${method} defined in worker.`);
+      }
+      worker.postMessage({ id, status: "start" });
+
+      try {
+        const tasks = workerMethod(args);
+        yield streamingWorker(id, tasks);
+        worker.postMessage({ id, status: "done" });
+      } catch (error) {
+        worker.postMessage({ id, status: "error", error });
+      }
+    });
+
+    return function (_x3) {
+      return _ref2.apply(this, arguments);
+    };
+  })();
+}
+
+module.exports = {
+  WorkerDispatcher,
+  workerHandler,
+  streamingWorkerHandler
+};
+
+/***/ }),
 /* 1393 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -21815,16 +21987,19 @@ function setSymbols(sourceId) {
 
     const symbols = await (0, _parser.getSymbols)(source);
 
     dispatch({
       type: "SET_SYMBOLS",
       source,
       symbols
     });
+
+    dispatch(setEmptyLines(source.id));
+    dispatch(setSourceMetaData(source.id));
   };
 }
 
 function setEmptyLines(sourceId) {
   return async ({ dispatch, getState }) => {
     const sourceRecord = (0, _selectors.getSource)(getState(), sourceId);
     if (!sourceRecord) {
       return;
@@ -24777,19 +24952,17 @@ function loadSourceText(source) {
     });
 
     const newSource = (0, _selectors.getSource)(getState(), source.id).toJS();
     if (newSource.isWasm) {
       return;
     }
 
     await (0, _parser.setSource)(newSource);
-    await dispatch((0, _ast.setSymbols)(source.id));
-    await dispatch((0, _ast.setEmptyLines)(source.id));
-    await dispatch((0, _ast.setSourceMetaData)(source.id));
+    dispatch((0, _ast.setSymbols)(source.id));
   };
 }
 
 /***/ }),
 /* 1436 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -45762,10 +45935,9 @@ function timing(store) {
     mark(`${action.type}_end`);
     measure(`${action.type}`, `${action.type}_start`, `${action.type}_end`);
     return result;
   };
 }
 
 /***/ })
 /******/ ]);
-});
-//# sourceMappingURL=debugger.js.map
\ No newline at end of file
+});
\ No newline at end of file
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -35427,19 +35427,19 @@ WorkerDispatcher.prototype = {
         this.worker.postMessage({ id, method, args });
 
         const listener = ({ data: result }) => {
           if (result.id !== id) {
             return;
           }
 
           if (!this.worker) {
-            reject("Oops, The worker has shutdown!");
             return;
           }
+
           this.worker.removeEventListener("message", listener);
           if (result.error) {
             reject(result.error);
           } else {
             resolve(result.response);
           }
         };
 
@@ -41819,10 +41819,9 @@ function extendsComponent(classes) {
     }
   });
 
   return result;
 }
 
 /***/ })
 /******/ ]);
-});
-//# sourceMappingURL=parser-worker.js.map
\ No newline at end of file
+});
\ No newline at end of file
--- a/devtools/client/debugger/new/pretty-print-worker.js
+++ b/devtools/client/debugger/new/pretty-print-worker.js
@@ -158,19 +158,19 @@ WorkerDispatcher.prototype = {
         this.worker.postMessage({ id, method, args });
 
         const listener = ({ data: result }) => {
           if (result.id !== id) {
             return;
           }
 
           if (!this.worker) {
-            reject("Oops, The worker has shutdown!");
             return;
           }
+
           this.worker.removeEventListener("message", listener);
           if (result.error) {
             reject(result.error);
           } else {
             resolve(result.response);
           }
         };
 
@@ -7586,10 +7586,9 @@ SourceNode.prototype.toStringWithSourceM
 };
 
 exports.SourceNode = SourceNode;
 
 
 /***/ })
 
 /******/ });
-});
-//# sourceMappingURL=pretty-print-worker.js.map
\ No newline at end of file
+});
\ No newline at end of file
--- a/devtools/client/debugger/new/search-worker.js
+++ b/devtools/client/debugger/new/search-worker.js
@@ -741,17 +741,17 @@ exports.isLoaded = isLoaded;
 
 const {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId
 } = __webpack_require__(1389);
 
-const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1363);
+const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1390);
 
 const dispatcher = new WorkerDispatcher();
 
 const getOriginalURLs = dispatcher.task("getOriginalURLs");
 const getGeneratedLocation = dispatcher.task("getGeneratedLocation");
 const getOriginalLocation = dispatcher.task("getOriginalLocation");
 const getLocationScopes = dispatcher.task("getLocationScopes");
 const getOriginalSourceText = dispatcher.task("getOriginalSourceText");
@@ -940,19 +940,19 @@ WorkerDispatcher.prototype = {
         this.worker.postMessage({ id, method, args });
 
         const listener = ({ data: result }) => {
           if (result.id !== id) {
             return;
           }
 
           if (!this.worker) {
-            reject("Oops, The worker has shutdown!");
             return;
           }
+
           this.worker.removeEventListener("message", listener);
           if (result.error) {
             reject(result.error);
           } else {
             resolve(result.response);
           }
         };
 
@@ -1119,16 +1119,194 @@ module.exports = {
   isOriginalId,
   isGeneratedId,
   getContentType,
   contentMapForTesting: contentMap
 };
 
 /***/ }),
 
+/***/ 1390:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+const networkRequest = __webpack_require__(1391);
+const workerUtils = __webpack_require__(1392);
+
+module.exports = {
+  networkRequest,
+  workerUtils
+};
+
+/***/ }),
+
+/***/ 1391:
+/***/ (function(module, exports) {
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+function networkRequest(url, opts) {
+  return fetch(url, {
+    cache: opts.loadFromCache ? "default" : "no-cache"
+  }).then(res => {
+    if (res.status >= 200 && res.status < 300) {
+      return res.text().then(text => ({ content: text }));
+    }
+    return Promise.reject(`request failed with status ${res.status}`);
+  });
+}
+
+module.exports = networkRequest;
+
+/***/ }),
+
+/***/ 1392:
+/***/ (function(module, exports) {
+
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
+function WorkerDispatcher() {
+  this.msgId = 1;
+  this.worker = null;
+} /* This Source Code Form is subject to the terms of the Mozilla Public
+   * 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/. */
+
+WorkerDispatcher.prototype = {
+  start(url) {
+    this.worker = new Worker(url);
+    this.worker.onerror = () => {
+      console.error(`Error in worker ${url}`);
+    };
+  },
+
+  stop() {
+    if (!this.worker) {
+      return;
+    }
+
+    this.worker.terminate();
+    this.worker = null;
+  },
+
+  task(method) {
+    return (...args) => {
+      return new Promise((resolve, reject) => {
+        const id = this.msgId++;
+        this.worker.postMessage({ id, method, args });
+
+        const listener = ({ data: result }) => {
+          if (result.id !== id) {
+            return;
+          }
+
+          if (!this.worker) {
+            reject("Oops, The worker has shutdown!");
+            return;
+          }
+          this.worker.removeEventListener("message", listener);
+          if (result.error) {
+            reject(result.error);
+          } else {
+            resolve(result.response);
+          }
+        };
+
+        this.worker.addEventListener("message", listener);
+      });
+    };
+  }
+};
+
+function workerHandler(publicInterface) {
+  return function (msg) {
+    const { id, method, args } = msg.data;
+    try {
+      const response = publicInterface[method].apply(undefined, args);
+      if (response instanceof Promise) {
+        response.then(val => self.postMessage({ id, response: val }),
+        // Error can't be sent via postMessage, so be sure to
+        // convert to string.
+        err => self.postMessage({ id, error: err.toString() }));
+      } else {
+        self.postMessage({ id, response });
+      }
+    } catch (error) {
+      // Error can't be sent via postMessage, so be sure to convert to
+      // string.
+      self.postMessage({ id, error: error.toString() });
+    }
+  };
+}
+
+function streamingWorkerHandler(publicInterface, { timeout = 100 } = {}, worker = self) {
+  let streamingWorker = (() => {
+    var _ref = _asyncToGenerator(function* (id, tasks) {
+      let isWorking = true;
+
+      const intervalId = setTimeout(function () {
+        isWorking = false;
+      }, timeout);
+
+      const results = [];
+      while (tasks.length !== 0 && isWorking) {
+        const { callback, context, args } = tasks.shift();
+        const result = yield callback.call(context, args);
+        results.push(result);
+      }
+      worker.postMessage({ id, status: "pending", data: results });
+      clearInterval(intervalId);
+
+      if (tasks.length !== 0) {
+        yield streamingWorker(id, tasks);
+      }
+    });
+
+    return function streamingWorker(_x, _x2) {
+      return _ref.apply(this, arguments);
+    };
+  })();
+
+  return (() => {
+    var _ref2 = _asyncToGenerator(function* (msg) {
+      const { id, method, args } = msg.data;
+      const workerMethod = publicInterface[method];
+      if (!workerMethod) {
+        console.error(`Could not find ${method} defined in worker.`);
+      }
+      worker.postMessage({ id, status: "start" });
+
+      try {
+        const tasks = workerMethod(args);
+        yield streamingWorker(id, tasks);
+        worker.postMessage({ id, status: "done" });
+      } catch (error) {
+        worker.postMessage({ id, status: "error", error });
+      }
+    });
+
+    return function (_x3) {
+      return _ref2.apply(this, arguments);
+    };
+  })();
+}
+
+module.exports = {
+  WorkerDispatcher,
+  workerHandler,
+  streamingWorkerHandler
+};
+
+/***/ }),
+
 /***/ 1393:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -3288,10 +3466,9 @@ module.exports = freeGlobal;
 
 }(this));
 
 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(793)(module), __webpack_require__(792)))
 
 /***/ })
 
 /******/ });
-});
-//# sourceMappingURL=search-worker.js.map
\ No newline at end of file
+});
\ No newline at end of file
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -96,16 +96,29 @@ void* get_proc_address_from_glcontext(vo
   mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
   if (!glcontext) {
     return nullptr;
   }
   PRFuncPtr p = glcontext->LookupSymbol(procname);
   return reinterpret_cast<void*>(p);
 }
 
+void
+gecko_profiler_register_thread(const char* name)
+{
+  char stackTop;
+  profiler_register_thread(name, &stackTop);
+}
+
+void
+gecko_profiler_unregister_thread()
+{
+  profiler_unregister_thread();
+}
+
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender
 {
 public:
--- a/gfx/thebes/gfxCoreTextShaper.cpp
+++ b/gfx/thebes/gfxCoreTextShaper.cpp
@@ -239,16 +239,18 @@ gfxCoreTextShaper::ShapeText(DrawTarget 
                             // without requiring a separate allocation
 
 nsresult
 gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
                                     uint32_t       aOffset,
                                     uint32_t       aLength,
                                     CTRunRef       aCTRun)
 {
+    typedef gfxShapedText::CompressedGlyph CompressedGlyph;
+
     int32_t direction = aShapedText->IsRightToLeft() ? -1 : 1;
 
     int32_t numGlyphs = ::CTRunGetGlyphCount(aCTRun);
     if (numGlyphs == 0) {
         return NS_OK;
     }
 
     int32_t wordLength = aLength;
@@ -314,18 +316,17 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxS
         ::CTRunGetStringIndices(aCTRun, ::CFRangeMake(0, 0), glyphToCharArray.get());
         glyphToChar = glyphToCharArray.get();
     }
 
     double runWidth = ::CTRunGetTypographicBounds(aCTRun, ::CFRangeMake(0, 0),
                                                   nullptr, nullptr, nullptr);
 
     AutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
-    gfxShapedText::CompressedGlyph *charGlyphs =
-        aShapedText->GetCharacterGlyphs() + aOffset;
+    CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
 
     // CoreText gives us the glyphindex-to-charindex mapping, which relates each glyph
     // to a source text character; we also need the charindex-to-glyphindex mapping to
     // find the glyph for a given char. Note that some chars may not map to any glyph
     // (ligature continuations), and some may map to several glyphs (eg Indic split vowels).
     // We set the glyph index to NO_GLYPH for chars that have no associated glyph, and we
     // record the last glyph index for cases where the char maps to several glyphs,
     // so that our clumping will include all the glyph fragments for the character.
@@ -535,28 +536,28 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxS
                 if (glyphStart < numGlyphs-1) {
                     toNextGlyph = positions[glyphStart+1].x - positions[glyphStart].x;
                 } else {
                     toNextGlyph = positions[0].x + runWidth - positions[glyphStart].x;
                 }
                 advance = int32_t(toNextGlyph * appUnitsPerDevUnit);
             }
 
-            gfxTextRun::CompressedGlyph textRunGlyph;
-            textRunGlyph.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
-                                    true, detailedGlyphs.Length());
-            aShapedText->SetGlyphs(aOffset + baseCharIndex, textRunGlyph,
+            bool isClusterStart = charGlyphs[baseCharIndex].IsClusterStart();
+            aShapedText->SetGlyphs(aOffset + baseCharIndex,
+                                   CompressedGlyph::MakeComplex(isClusterStart, true,
+                                                                detailedGlyphs.Length()),
                                    detailedGlyphs.Elements());
 
             detailedGlyphs.Clear();
         }
 
         // the rest of the chars in the group are ligature continuations, no associated glyphs
         while (++baseCharIndex != endCharIndex && baseCharIndex < wordLength) {
-            gfxShapedText::CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex];
+            CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex];
             NS_ASSERTION(!shapedTextGlyph.IsSimpleGlyph(), "overwriting a simple glyph");
             shapedTextGlyph.SetComplex(inOrder && shapedTextGlyph.IsClusterStart(), false, 0);
         }
 
         glyphStart = glyphEnd;
         charStart = charEnd;
     }
 
--- a/gfx/thebes/gfxFT2Fonts.cpp
+++ b/gfx/thebes/gfxFT2Fonts.cpp
@@ -61,23 +61,24 @@ gfxFT2Font::ShapeText(DrawTarget     *aD
 
     return true;
 }
 
 void
 gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
                      uint32_t aLength, gfxShapedText *aShapedText)
 {
+    typedef gfxShapedText::CompressedGlyph CompressedGlyph;
+
     const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
     // we'll pass this in/figure it out dynamically, but at this point there can be only one face.
     gfxFT2LockedFace faceLock(this);
     FT_Face face = faceLock.get();
 
-    gfxShapedText::CompressedGlyph *charGlyphs =
-        aShapedText->GetCharacterGlyphs();
+    CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs();
 
     const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
 
     FT_UInt spaceGlyph = GetSpaceGlyph();
 
     for (uint32_t i = 0; i < aLength; i++, aOffset++) {
         char16_t ch = aText[i];
 
@@ -134,31 +135,33 @@ gfxFT2Font::AddRange(const char16_t *aTe
 
             // convert 26.6 fixed point to app units
             // round rather than truncate to nearest pixel
             // because these advances are often scaled
             advance = ((advance * appUnitsPerDevUnit + 32) >> 6);
         }
 
         if (advance >= 0 &&
-            gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
-            gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) {
+            CompressedGlyph::IsSimpleAdvance(advance) &&
+            CompressedGlyph::IsSimpleGlyphID(gid)) {
             charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
         } else if (gid == 0) {
             // gid = 0 only happens when the glyph is missing from the font
             aShapedText->SetMissingGlyph(aOffset, ch, this);
         } else {
             gfxTextRun::DetailedGlyph details;
             details.mGlyphID = gid;
             NS_ASSERTION(details.mGlyphID == gid,
                          "Seriously weird glyph ID detected!");
             details.mAdvance = advance;
-            gfxShapedText::CompressedGlyph g;
-            g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1);
-            aShapedText->SetGlyphs(aOffset, g, &details);
+            bool isClusterStart = charGlyphs[aOffset].IsClusterStart();
+            aShapedText->SetGlyphs(aOffset,
+                                   CompressedGlyph::MakeComplex(isClusterStart,
+                                                                true, 1),
+                                   &details);
         }
     }
 }
 
 gfxFT2Font::gfxFT2Font(const RefPtr<UnscaledFontFreeType>& aUnscaledFont,
                        cairo_scaled_font_t *aCairoFont,
                        FT2FontEntry *aFontEntry,
                        const gfxFontStyle *aFontStyle,
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -566,20 +566,20 @@ gfxFontShaper::MergeFontFeatures(
     }
 }
 
 void
 gfxShapedText::SetupClusterBoundaries(uint32_t        aOffset,
                                       const char16_t *aString,
                                       uint32_t        aLength)
 {
-    CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
-
-    gfxTextRun::CompressedGlyph extendCluster;
-    extendCluster.SetComplex(false, true, 0);
+    CompressedGlyph* glyphs = GetCharacterGlyphs() + aOffset;
+
+    CompressedGlyph extendCluster =
+        CompressedGlyph::MakeComplex(false, true, 0);
 
     ClusterIterator iter(aString, aLength);
 
     // the ClusterIterator won't be able to tell us if the string
     // _begins_ with a cluster-extender, so we handle that here
     if (aLength) {
         uint32_t ch = *aString;
         if (aLength > 1 && NS_IS_HIGH_SURROGATE(ch) &&
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -758,18 +758,16 @@ public:
      * A character can be "missing", indicating that the system is unable
      * to render the character.
      * 
      * All characters in a ligature group conceptually share all the glyphs
      * associated with the characters in a group.
      */
     class CompressedGlyph {
     public:
-        CompressedGlyph() { mValue = 0; }
-
         enum {
             // Indicates that a cluster and ligature group starts at this
             // character; this character has a single glyph with a reasonable
             // advance and zero offsets. A "reasonable" advance
             // is one that fits in the available bits (currently 12) (specified
             // in appunits).
             FLAG_IS_SIMPLE_GLYPH  = 0x80000000U,
 
@@ -889,35 +887,62 @@ public:
             NS_ASSERTION(aCanBreakBefore <= 2,
                          "Bogus break-before value!");
             uint32_t breakMask = (uint32_t(aCanBreakBefore) << FLAGS_CAN_BREAK_SHIFT);
             uint32_t toggle = breakMask ^ (mValue & FLAGS_CAN_BREAK_BEFORE);
             mValue ^= toggle;
             return toggle;
         }
 
-        CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) {
+        // Create a CompressedGlyph value representing a simple glyph with
+        // no extra flags (line-break or is_space) set.
+        static CompressedGlyph
+        MakeSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) {
             NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow");
             NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
+            CompressedGlyph g;
+            g.mValue = FLAG_IS_SIMPLE_GLYPH |
+                       (aAdvanceAppUnits << ADVANCE_SHIFT) |
+                       aGlyph;
+            return g;
+        }
+
+        // Assign a simple glyph value to an existing CompressedGlyph record,
+        // preserving line-break/is-space flags if present.
+        CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits,
+                                        uint32_t aGlyph) {
             NS_ASSERTION(!CharTypeFlags(), "Char type flags lost");
             mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
-                FLAG_IS_SIMPLE_GLYPH |
-                (aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
+                MakeSimpleGlyph(aAdvanceAppUnits, aGlyph).mValue;
             return *this;
         }
+
+        // Create a CompressedGlyph value representing a complex glyph record,
+        // without any line-break or char-type flags.
+        static CompressedGlyph
+        MakeComplex(bool aClusterStart, bool aLigatureStart,
+                    uint32_t aGlyphCount) {
+            CompressedGlyph g;
+            g.mValue = FLAG_NOT_MISSING |
+                       (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
+                       (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
+                       (aGlyphCount << GLYPH_COUNT_SHIFT);
+            return g;
+        }
+
+        // Assign a complex glyph value to an existing CompressedGlyph record,
+        // preserving line-break/char-type flags if present.
         CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart,
-                uint32_t aGlyphCount) {
+                                    uint32_t aGlyphCount) {
             mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
-                FLAG_NOT_MISSING |
                 CharTypeFlags() |
-                (aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
-                (aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
-                (aGlyphCount << GLYPH_COUNT_SHIFT);
+                MakeComplex(aClusterStart, aLigatureStart, aGlyphCount).mValue;
             return *this;
         }
+
         /**
          * Missing glyphs are treated as ligature group starts; don't mess with
          * the cluster-start flag (see bugs 618870 and 619286).
          */
         CompressedGlyph& SetMissing(uint32_t aGlyphCount) {
             mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_NOT_CLUSTER_START |
                                 FLAG_CHAR_IS_SPACE)) |
                 CharTypeFlags() |
--- a/gfx/thebes/gfxGraphiteShaper.cpp
+++ b/gfx/thebes/gfxGraphiteShaper.cpp
@@ -211,16 +211,18 @@ struct Cluster {
 nsresult
 gfxGraphiteShaper::SetGlyphsFromSegment(gfxShapedText   *aShapedText,
                                         uint32_t         aOffset,
                                         uint32_t         aLength,
                                         const char16_t *aText,
                                         gr_segment      *aSegment,
                                         RoundingFlags    aRounding)
 {
+    typedef gfxShapedText::CompressedGlyph CompressedGlyph;
+
     int32_t dev2appUnits = aShapedText->GetAppUnitsPerDevUnit();
     bool rtl = aShapedText->IsRightToLeft();
 
     uint32_t glyphCount = gr_seg_n_slots(aSegment);
 
     // identify clusters; graphite may have reordered/expanded/ligated glyphs.
     AutoTArray<Cluster,SMALL_GLYPH_RUN> clusters;
     AutoTArray<uint16_t,SMALL_GLYPH_RUN> gids;
@@ -284,18 +286,17 @@ gfxGraphiteShaper::SetGlyphsFromSegment(
             after++;
         }
         // extend cluster if necessary to reach the glyph's "after" index
         if (clusters[cIndex].baseChar + clusters[cIndex].nChars < after + 1) {
             clusters[cIndex].nChars = after + 1 - clusters[cIndex].baseChar;
         }
     }
 
-    gfxShapedText::CompressedGlyph *charGlyphs =
-        aShapedText->GetCharacterGlyphs() + aOffset;
+    CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
 
     bool roundX = bool(aRounding & RoundingFlags::kRoundX);
     bool roundY = bool(aRounding & RoundingFlags::kRoundY);
 
     // now put glyphs into the textrun, one cluster at a time
     for (uint32_t i = 0; i <= cIndex; ++i) {
         const Cluster& c = clusters[i];
 
@@ -321,18 +322,18 @@ gfxGraphiteShaper::SetGlyphsFromSegment(
         if (c.nGlyphs == 1 && c.nChars == 1 &&
             aShapedText->FilterIfIgnorable(aOffset + offs, aText[offs])) {
             continue;
         }
 
         uint32_t appAdvance = roundX ? NSToIntRound(adv) * dev2appUnits
                                      : NSToIntRound(adv * dev2appUnits);
         if (c.nGlyphs == 1 &&
-            gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
-            gfxShapedText::CompressedGlyph::IsSimpleAdvance(appAdvance) &&
+            CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
+            CompressedGlyph::IsSimpleAdvance(appAdvance) &&
             charGlyphs[offs].IsClusterStart() &&
             yLocs[c.baseGlyph] == 0)
         {
             charGlyphs[offs].SetSimpleGlyph(appAdvance, gids[c.baseGlyph]);
         } else {
             // not a one-to-one mapping with simple metrics: use DetailedGlyph
             AutoTArray<gfxShapedText::DetailedGlyph,8> details;
             float clusterLoc;
@@ -347,25 +348,27 @@ gfxGraphiteShaper::SetGlyphsFromSegment(
                 } else {
                     float dx = rtl ? (xLocs[j] - clusterLoc) :
                                      (xLocs[j] - clusterLoc - adv);
                     d->mOffset.x = roundX ? NSToIntRound(dx) * dev2appUnits
                                           : dx * dev2appUnits;
                     d->mAdvance = 0;
                 }
             }
-            gfxShapedText::CompressedGlyph g;
-            g.SetComplex(charGlyphs[offs].IsClusterStart(),
-                         true, details.Length());
-            aShapedText->SetGlyphs(aOffset + offs, g, details.Elements());
+            bool isClusterStart = charGlyphs[offs].IsClusterStart();
+            aShapedText->SetGlyphs(aOffset + offs,
+                                   CompressedGlyph::MakeComplex(isClusterStart,
+                                                                true,
+                                                                details.Length()),
+                                   details.Elements());
         }
 
         for (uint32_t j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) {
             NS_ASSERTION(j < aLength, "unexpected offset");
-            gfxShapedText::CompressedGlyph &g = charGlyphs[j];
+            CompressedGlyph &g = charGlyphs[j];
             NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
             g.SetComplex(g.IsClusterStart(), false, 0);
         }
     }
 
     return NS_OK;
 }
 
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -1524,16 +1524,18 @@ gfxHarfBuzzShaper::ShapeText(DrawTarget 
 nsresult
 gfxHarfBuzzShaper::SetGlyphsFromRun(gfxShapedText  *aShapedText,
                                     uint32_t        aOffset,
                                     uint32_t        aLength,
                                     const char16_t *aText,
                                     bool            aVertical,
                                     RoundingFlags   aRounding)
 {
+    typedef gfxShapedText::CompressedGlyph CompressedGlyph;
+
     uint32_t numGlyphs;
     const hb_glyph_info_t *ginfo = hb_buffer_get_glyph_infos(mBuffer, &numGlyphs);
     if (numGlyphs == 0) {
         return NS_OK;
     }
 
     AutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
 
@@ -1564,18 +1566,17 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxS
         roundI = bool(aRounding & RoundingFlags::kRoundY);
         roundB = bool(aRounding & RoundingFlags::kRoundX);
     } else {
         roundI = bool(aRounding & RoundingFlags::kRoundX);
         roundB = bool(aRounding & RoundingFlags::kRoundY);
     }
 
     int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
-    gfxShapedText::CompressedGlyph *charGlyphs =
-        aShapedText->GetCharacterGlyphs() + aOffset;
+    CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
 
     // factor to convert 16.16 fixed-point pixels to app units
     // (only used if not rounding)
     double hb2appUnits = FixedToFloat(aShapedText->GetAppUnitsPerDevUnit());
 
     // Residual from rounding of previous advance, for use in rounding the
     // subsequent offset or advance appropriately.  16.16 fixed-point
     //
@@ -1713,18 +1714,18 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxS
             residual = width - FloatToFixed(intWidth);
             advance = appUnitsPerDevUnit * intWidth + iOffset;
         } else {
             iOffset = floor(hb2appUnits * i_offset + 0.5);
             advance = floor(hb2appUnits * i_advance + 0.5);
         }
         // Check if it's a simple one-to-one mapping
         if (glyphsInClump == 1 &&
-            gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
-            gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
+            CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
+            CompressedGlyph::IsSimpleAdvance(advance) &&
             charGlyphs[baseCharIndex].IsClusterStart() &&
             iOffset == 0 && b_offset == 0 &&
             b_advance == 0 && bPos == 0)
         {
             charGlyphs[baseCharIndex].SetSimpleGlyph(advance,
                                                      ginfo[glyphStart].codepoint);
         } else {
             // Collect all glyphs in a list to be assigned to the first char;
@@ -1784,30 +1785,31 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxS
                     residual = i_advance - FloatToFixed(intAdvance);
                     advance = appUnitsPerDevUnit * intAdvance;
                 } else {
                     iOffset = floor(hb2appUnits * i_offset + 0.5);
                     advance = floor(hb2appUnits * i_advance + 0.5);
                 }
             }
 
-            gfxShapedText::CompressedGlyph g;
-            g.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
-                         true, detailedGlyphs.Length());
+            bool isClusterStart = charGlyphs[baseCharIndex].IsClusterStart();
             aShapedText->SetGlyphs(aOffset + baseCharIndex,
-                                   g, detailedGlyphs.Elements());
+                                   CompressedGlyph::MakeComplex(isClusterStart,
+                                                                true,
+                                                                detailedGlyphs.Length()),
+                                   detailedGlyphs.Elements());
 
             detailedGlyphs.Clear();
         }
 
         // the rest of the chars in the group are ligature continuations,
         // no associated glyphs
         while (++baseCharIndex != endCharIndex &&
                baseCharIndex < int32_t(wordLength)) {
-            gfxShapedText::CompressedGlyph &g = charGlyphs[baseCharIndex];
+            CompressedGlyph &g = charGlyphs[baseCharIndex];
             NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
             g.SetComplex(g.IsClusterStart(), false, 0);
         }
 
         glyphStart = glyphEnd;
         charStart = charEnd;
     }
 
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1653,18 +1653,18 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFon
         NS_lroundf(aFont->GetMetrics(fontOrientation).spaceWidth *
                    mAppUnitsPerDevUnit);
     if (!CompressedGlyph::IsSimpleAdvance(spaceWidthAppUnits)) {
         return false;
     }
 
     AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false,
                 aOrientation);
-    CompressedGlyph g;
-    g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
+    CompressedGlyph g =
+        CompressedGlyph::MakeSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
     if (aSpaceChar == ' ') {
         g.SetIsSpace();
     }
     GetCharacterGlyphs()[aCharIndex] = g;
     return true;
 }
 
 void
@@ -2751,18 +2751,18 @@ gfxFontGroup::InitScriptRun(DrawTarget* 
                         if (gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance)) {
                             aTextRun->GetCharacterGlyphs()[aOffset + index].
                                 SetSimpleGlyph(advance,
                                                mainFont->GetSpaceGlyph());
                         } else {
                             gfxTextRun::DetailedGlyph detailedGlyph;
                             detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph();
                             detailedGlyph.mAdvance = advance;
-                            gfxShapedText::CompressedGlyph g;
-                            g.SetComplex(true, true, 1);
+                            CompressedGlyph g =
+                                CompressedGlyph::MakeComplex(true, true, 1);
                             aTextRun->SetGlyphs(aOffset + index,
                                                 g, &detailedGlyph);
                         }
                         continue;
                     }
                 }
 
                 if (IsInvalidChar(ch)) {
--- a/gfx/thebes/gfxTextRun.h
+++ b/gfx/thebes/gfxTextRun.h
@@ -837,16 +837,17 @@ private:
     // shaping state for handling variant fallback features
     // such as subscript/superscript variant glyphs
     ShapingState      mShapingState;
 };
 
 class gfxFontGroup final : public gfxTextRunFactory {
 public:
     typedef mozilla::unicode::Script Script;
+    typedef gfxShapedText::CompressedGlyph CompressedGlyph;
 
     static void Shutdown(); // platform must call this to release the languageAtomService
 
     gfxFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                  const gfxFontStyle* aStyle,
                  gfxTextPerfMetrics* aTextPerf,
                  gfxUserFontSet* aUserFontSet,
                  gfxFloat aDevToCssSize);
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -2,17 +2,17 @@ use std::ffi::{CStr, CString};
 use std::{mem, slice};
 use std::path::PathBuf;
 use std::ptr;
 use std::sync::Arc;
 use std::os::raw::{c_void, c_char, c_float};
 use gleam::gl;
 
 use webrender_api::*;
-use webrender::{ReadPixelsFormat, Renderer, RendererOptions};
+use webrender::{ReadPixelsFormat, Renderer, RendererOptions, ThreadListener};
 use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::DebugFlags;
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
 use thread_profiler::register_thread_with_profiler;
 use moz2d_renderer::Moz2dImageRenderer;
 use app_units::Au;
 use rayon;
 use euclid::SideOffsets2D;
@@ -582,24 +582,58 @@ pub unsafe extern "C" fn wr_rendered_epo
 }
 
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
 #[no_mangle]
 pub unsafe extern "C" fn wr_rendered_epochs_delete(pipeline_epochs: *mut WrRenderedEpochs) {
     Box::from_raw(pipeline_epochs);
 }
 
+extern "C" {
+    fn gecko_profiler_register_thread(name: *const ::std::os::raw::c_char);
+    fn gecko_profiler_unregister_thread();
+}
+
+struct GeckoProfilerThreadListener {}
+
+impl GeckoProfilerThreadListener {
+    pub fn new() -> GeckoProfilerThreadListener {
+        GeckoProfilerThreadListener{}
+    }
+}
+
+impl ThreadListener for GeckoProfilerThreadListener {
+    fn thread_started(&self, thread_name: &str) {
+        let name = CString::new(thread_name).unwrap();
+        unsafe {
+            // gecko_profiler_register_thread copies the passed name here.
+            gecko_profiler_register_thread(name.as_ptr());
+        }
+    }
+
+    fn thread_stopped(&self, _: &str) {
+        unsafe {
+            gecko_profiler_unregister_thread();
+        }
+    }
+}
+
 pub struct WrThreadPool(Arc<rayon::ThreadPool>);
 
 #[no_mangle]
 pub unsafe extern "C" fn wr_thread_pool_new() -> *mut WrThreadPool {
     let worker_config = rayon::Configuration::new()
-        .thread_name(|idx|{ format!("WebRender:Worker#{}", idx) })
+        .thread_name(|idx|{ format!("WRWorker#{}", idx) })
         .start_handler(|idx| {
-            register_thread_with_profiler(format!("WebRender:Worker#{}", idx));
+            let name = format!("WRWorker#{}", idx);
+            register_thread_with_profiler(name.clone());
+            gecko_profiler_register_thread(CString::new(name).unwrap().as_ptr());
+        })
+        .exit_handler(|_idx| {
+            gecko_profiler_unregister_thread();
         });
 
     let workers = Arc::new(rayon::ThreadPool::new(worker_config).unwrap());
 
     Box::into_raw(Box::new(WrThreadPool(workers)))
 }
 
 /// cbindgen:postfix=WR_DESTRUCTOR_SAFE_FUNC
@@ -645,28 +679,30 @@ pub extern "C" fn wr_window_new(window_i
     };
 
     let opts = RendererOptions {
         enable_aa: true,
         enable_subpixel_aa: true,
         recorder: recorder,
         blob_image_renderer: Some(Box::new(Moz2dImageRenderer::new(workers.clone()))),
         workers: Some(workers.clone()),
+        thread_listener: Some(Box::new(GeckoProfilerThreadListener::new())),
         enable_render_on_scroll: false,
         resource_override_path: unsafe {
             let override_charptr = gfx_wr_resource_path_override();
             if override_charptr.is_null() {
                 None
             } else {
                 match CStr::from_ptr(override_charptr).to_str() {
                     Ok(override_str) => Some(PathBuf::from(override_str)),
                     _ => None
                 }
             }
         },
+        renderer_id: Some(window_id.0),
         ..Default::default()
     };
 
     let notifier = Box::new(CppNotifier {
         window_id: window_id,
     });
     let (renderer, sender) = match Renderer::new(gl, notifier, opts) {
         Ok((renderer, sender)) => (renderer, sender),
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -21,16 +21,18 @@ bool is_in_main_thread();
 bool is_in_render_thread();
 bool is_glcontext_egl(void* glcontext_ptr);
 bool gfx_use_wrench();
 const char* gfx_wr_resource_path_override();
 void gfx_critical_note(const char* msg);
 void gfx_critical_error(const char* msg);
 void gecko_printf_stderr_output(const char* msg);
 void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
+void gecko_profiler_register_thread(const char* threadname);
+void gecko_profiler_unregister_thread();
 
 } // extern "C"
 
 // Some useful defines to stub out webrender binding functions for when we
 // build gecko without webrender. We try to tell the compiler these functions
 // are unreachable in that case, but VC++ emits a warning if it finds any
 // unreachable functions invoked from destructors. That warning gets turned into
 // an error and causes the build to fail. So for wr_* functions called by
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -938,16 +938,20 @@ extern void AddFontData(WrFontKey aKey,
 extern void AddNativeFontHandle(WrFontKey aKey,
                                 void *aHandle,
                                 uint32_t aIndex);
 
 extern void DeleteFontData(WrFontKey aKey);
 
 extern void gecko_printf_stderr_output(const char *aMsg);
 
+extern void gecko_profiler_register_thread(const char *aName);
+
+extern void gecko_profiler_unregister_thread();
+
 extern void gfx_critical_error(const char *aMsg);
 
 extern void gfx_critical_note(const char *aMsg);
 
 extern bool gfx_use_wrench();
 
 extern const char *gfx_wr_resource_path_override();
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3668,17 +3668,18 @@ CreateArrayPrototype(JSContext* cx, JSPr
 
     return arrayProto;
 }
 
 static bool
 array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
 {
     // Add Array.prototype[@@unscopables]. ECMA-262 draft (2016 Mar 19) 22.1.3.32.
-    RootedObject unscopables(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr, TenuredObject));
+    RootedObject unscopables(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr,
+                                                                      SingletonObject));
     if (!unscopables)
         return false;
 
     RootedValue value(cx, BooleanValue(true));
     if (!DefineDataProperty(cx, unscopables, cx->names().copyWithin, value) ||
         !DefineDataProperty(cx, unscopables, cx->names().entries, value) ||
         !DefineDataProperty(cx, unscopables, cx->names().fill, value) ||
         !DefineDataProperty(cx, unscopables, cx->names().find, value) ||
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -176,31 +176,33 @@ void counters_dump(int) {
 void counters_reset(int) {
     /* Do nothing */
 }
 #endif
 
 static void
 InstallCoverageSignalHandlers()
 {
+#ifndef XP_WIN
     fprintf(stderr, "[CodeCoverage] Setting handlers for process %d.\n", getpid());
 
     struct sigaction dump_sa;
     dump_sa.sa_handler = counters_dump;
     dump_sa.sa_flags = SA_RESTART;
     sigemptyset(&dump_sa.sa_mask);
     mozilla::DebugOnly<int> r1 = sigaction(SIGUSR1, &dump_sa, nullptr);
     MOZ_ASSERT(r1 == 0, "Failed to install GCOV SIGUSR1 handler");
 
     struct sigaction reset_sa;
     reset_sa.sa_handler = counters_reset;
     reset_sa.sa_flags = SA_RESTART;
     sigemptyset(&reset_sa.sa_mask);
     mozilla::DebugOnly<int> r2 = sigaction(SIGUSR2, &reset_sa, nullptr);
     MOZ_ASSERT(r2 == 0, "Failed to install GCOV SIGUSR2 handler");
+#endif
 }
 #endif
 
 class OffThreadState {
     enum State {
         IDLE,           /* ready to work; no token, no source */
         COMPILING,      /* working; no token, have source */
         DONE            /* compilation done: have token and source */
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -583,19 +583,19 @@ nsOpenTypeTable::MakeTextRun(DrawTarget*
                               // We don't care about CSS writing mode here;
                               // math runs are assumed to be horizontal.
   gfxTextRun::DetailedGlyph detailedGlyph;
   detailedGlyph.mGlyphID = aGlyph.glyphID;
   detailedGlyph.mAdvance =
     NSToCoordRound(aAppUnitsPerDevPixel *
                    aFontGroup->GetFirstValidFont()->
                    GetGlyphHAdvance(aDrawTarget, aGlyph.glyphID));
-  gfxShapedText::CompressedGlyph g;
-  g.SetComplex(true, true, 1);
-  textRun->SetGlyphs(0, g, &detailedGlyph);
+  textRun->SetGlyphs(0,
+                     gfxShapedText::CompressedGlyph::MakeComplex(true, true, 1),
+                     &detailedGlyph);
 
   return textRun.forget();
 }
 
 // -----------------------------------------------------------------------------
 // This is the list of all the applicable glyph tables.
 // We will maintain a single global instance that will only reveal those
 // glyph tables that are associated to fonts currently installed on the
new file mode 100644
--- /dev/null
+++ b/testing/config/tooltool-manifests/win32/ccov.manifest
@@ -0,0 +1,9 @@
+[
+  {
+    "size": 271486,
+    "digest": "6956eb1cab16dff465861cd1966e3115f31b533334089553b8b94897bc138c6dec279bf7c60b34fe3fc67c8cb0d41e30f55982adaad07320090dab053e018dec",
+    "algorithm": "sha512",
+    "filename": "grcov-win-i686.tar.bz2",
+    "unpack": false
+  }
+]
--- a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py
+++ b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py
@@ -1,17 +1,20 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # 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/.
 
 import os
 import shutil
+import sys
+import tarfile
 import tempfile
 
+import mozinfo
 from mozharness.base.script import (
     PreScriptAction,
     PostScriptAction,
 )
 from mozharness.mozilla.tooltool import TooltoolMixin
 
 code_coverage_config_options = [
     [["--code-coverage"],
@@ -45,17 +48,17 @@ class CodeCoverageMixin(object):
 
     @property
     def code_coverage_enabled(self):
         try:
             if self.config.get('code_coverage'):
                 return True
 
             # XXX workaround because bug 1110465 is hard
-            return self.buildbot_config['properties']['stage_platform'] in ('linux64-ccov',)
+            return 'ccov' in self.buildbot_config['properties']['stage_platform']
         except (AttributeError, KeyError, TypeError):
             return False
 
     @property
     def ccov_upload_disabled(self):
         try:
             if self.config.get('disable_ccov_upload'):
                 return True
@@ -65,17 +68,17 @@ class CodeCoverageMixin(object):
 
     @property
     def jsd_code_coverage_enabled(self):
         try:
             if self.config.get('jsd_code_coverage'):
                 return True
 
             # XXX workaround because bug 1110465 is hard
-            return self.buildbot_config['properties']['stage_platform'] in ('linux64-jsdcov',)
+            return 'jsdcov' in self.buildbot_config['properties']['stage_platform']
         except (AttributeError, KeyError, TypeError):
             return False
 
     @PreScriptAction('run-tests')
     def _set_gcov_prefix(self, action):
         if not self.code_coverage_enabled:
             return
         # Set the GCOV directory.
@@ -89,25 +92,34 @@ class CodeCoverageMixin(object):
         # Install grcov on the test machine
         # Get the path to the build machines gcno files.
         self.url_to_gcno = self.query_build_dir_url('target.code-coverage-gcno.zip')
         dirs = self.query_abs_dirs()
 
         # Create the grcov directory, get the tooltool manifest, and finally
         # download and unpack the grcov binary.
         self.grcov_dir = tempfile.mkdtemp()
+
+        if mozinfo.os == 'linux':
+            platform = 'linux64'
+            tar_file = 'grcov-linux-standalone-x86_64.tar.bz2'
+        elif mozinfo.os == 'win':
+            platform = 'win32'
+            tar_file = 'grcov-win-i686.tar.bz2'
+
         manifest = os.path.join(dirs.get('abs_test_install_dir', os.path.join(dirs['abs_work_dir'], 'tests')), \
-            'config/tooltool-manifests/linux64/ccov.manifest')
+            'config/tooltool-manifests/%s/ccov.manifest' % platform)
 
         tooltool_path = self._fetch_tooltool_py()
-        cmd = [tooltool_path, '--url', 'https://tooltool.mozilla-releng.net/', 'fetch', \
+        cmd = [sys.executable, tooltool_path, '--url', 'https://tooltool.mozilla-releng.net/', 'fetch', \
             '-m', manifest, '-o', '-c', '/builds/worker/tooltool-cache']
         self.run_command(cmd, cwd=self.grcov_dir)
-        self.run_command(['tar', '-jxvf', os.path.join(self.grcov_dir, 'grcov-linux-standalone-x86_64.tar.bz2'), \
-            '-C', self.grcov_dir], cwd=self.grcov_dir)
+
+        with tarfile.open(os.path.join(self.grcov_dir, tar_file)) as tar:
+            tar.extractall(self.grcov_dir)
 
     @PostScriptAction('run-tests')
     def _package_coverage_data(self, action, success=None):
         if self.jsd_code_coverage_enabled:
             # Setup the command for compression
             dirs = self.query_abs_dirs()
             jsdcov_dir = dirs['abs_blob_upload_dir']
             zipFile = os.path.join(jsdcov_dir, "jsdcov_artifacts.zip")
@@ -121,69 +133,79 @@ class CodeCoverageMixin(object):
                 if filename.startswith("jscov") and filename.endswith(".json"):
                     os.remove(os.path.join(jsdcov_dir, filename))
 
             self.info("Completed compression of JSDCov artifacts!")
             self.info("Path to JSDCov compressed artifacts: " + zipFile)
 
         if not self.code_coverage_enabled:
             return
+
         del os.environ['GCOV_PREFIX']
         del os.environ['JS_CODE_COVERAGE_OUTPUT_DIR']
 
         if not self.ccov_upload_disabled:
             # TODO This is fragile, find rel_topsrcdir properly somehow
             # We need to find the path relative to the gecko topsrcdir. Use
             # some known gecko directories as a test.
             canary_dirs = ['browser', 'docshell', 'dom', 'js', 'layout', 'toolkit', 'xpcom', 'xpfe']
             rel_topsrcdir = None
             for root, dirs, files in os.walk(self.gcov_dir):
                 # need to use 'any' in case no gcda data was generated in that subdir.
                 if any(d in dirs for d in canary_dirs):
                     rel_topsrcdir = root
                     break
-            else:
+
+            if rel_topsrcdir is None:
                 # Unable to upload code coverage files. Since this is the whole
                 # point of code coverage, making this fatal.
-                self.fatal("Could not find relative topsrcdir in code coverage "
-                           "data!")
+                self.fatal("Could not find relative topsrcdir in code coverage data!")
+
+            dirs = self.query_abs_dirs()
 
             # Package GCOV coverage data.
-            dirs = self.query_abs_dirs()
-            file_path_gcda = os.path.join(
-                dirs['abs_blob_upload_dir'], 'code-coverage-gcda.zip')
-            command = ['zip', '-r', file_path_gcda, '.']
-            self.run_command(command, cwd=rel_topsrcdir)
+            file_path_gcda = os.path.join(dirs['abs_blob_upload_dir'], 'code-coverage-gcda.zip')
+            self.run_command(['zip', '-r', file_path_gcda, '.'], cwd=rel_topsrcdir)
 
             # Package JSVM coverage data.
-            dirs = self.query_abs_dirs()
-            file_path_jsvm = os.path.join(
-                dirs['abs_blob_upload_dir'], 'code-coverage-jsvm.zip')
-            command = ['zip', '-r', file_path_jsvm, '.']
-            self.run_command(command, cwd=self.jsvm_dir)
+            file_path_jsvm = os.path.join(dirs['abs_blob_upload_dir'], 'code-coverage-jsvm.zip')
+            self.run_command(['zip', '-r', file_path_jsvm, '.'], cwd=self.jsvm_dir)
 
             # GRCOV post-processing
             # Download the gcno fom the build machine.
             self.download_file(self.url_to_gcno, file_name=None, parent_dir=self.grcov_dir)
 
+            if mozinfo.os == 'linux':
+                prefix = '/builds/worker/workspace/build/src/'
+            elif mozinfo.os == 'win':
+                prefix = 'z:/build/build/src/'
+
             # Run grcov on the zipped .gcno and .gcda files.
             grcov_command = [
                 os.path.join(self.grcov_dir, 'grcov'),
                 '-t', 'lcov',
-                '-p', '/builds/worker/workspace/build/src/',
+                '-p', prefix,
                 '--ignore-dir', 'gcc',
                 os.path.join(self.grcov_dir, 'target.code-coverage-gcno.zip'), file_path_gcda
             ]
 
             # 'grcov_output' will be a tuple, the first variable is the path to the lcov output,
             # the other is the path to the standard error output.
-            grcov_output = self.get_output_from_command(grcov_command, cwd=self.grcov_dir, \
-                silent=True, tmpfile_base_path=os.path.join(self.grcov_dir, 'grcov_lcov_output'), \
-                save_tmpfiles=True, return_type='files')
+            grcov_output = self.get_output_from_command(
+                grcov_command,
+                cwd=self.grcov_dir,
+                silent=True,
+                tmpfile_base_path=os.path.join(self.grcov_dir, 'grcov_lcov_output'),
+                save_tmpfiles=True,
+                return_type='files'
+            )
             new_output_name = grcov_output[0] + '.info'
             os.rename(grcov_output[0], new_output_name)
 
             # Zip the grcov output and upload it.
-            command = ['zip', os.path.join(dirs['abs_blob_upload_dir'], 'code-coverage-grcov.zip'), new_output_name]
-            self.run_command(command, cwd=self.grcov_dir)
+            self.run_command(
+                ['zip', os.path.join(dirs['abs_blob_upload_dir'], 'code-coverage-grcov.zip'), new_output_name],
+                cwd=self.grcov_dir
+            )
+
         shutil.rmtree(self.gcov_dir)
         shutil.rmtree(self.jsvm_dir)
         shutil.rmtree(self.grcov_dir)
--- a/tools/code-coverage/CodeCoverageHandler.cpp
+++ b/tools/code-coverage/CodeCoverageHandler.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 <stdio.h>
+#ifndef XP_WIN
 #include <signal.h>
-#include <stdio.h>
 #include <unistd.h>
+#endif
 #include "mozilla/CodeCoverageHandler.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "nsAppRunner.h"
 
 using namespace mozilla;
 
 // The __gcov_dump function writes the coverage counters to gcda files.
@@ -57,31 +59,33 @@ void CodeCoverageHandler::ResetCounters(
 
   printf_stderr("[CodeCoverage] Requested reset.\n");
   counters_reset();
   printf_stderr("[CodeCoverage] Reset completed.\n");
 }
 
 void CodeCoverageHandler::SetSignalHandlers()
 {
+#ifndef XP_WIN
   printf_stderr("[CodeCoverage] Setting handlers for process %d.\n", getpid());
 
   struct sigaction dump_sa;
   dump_sa.sa_handler = CodeCoverageHandler::DumpCounters;
   dump_sa.sa_flags = SA_RESTART;
   sigemptyset(&dump_sa.sa_mask);
   DebugOnly<int> r1 = sigaction(SIGUSR1, &dump_sa, nullptr);
   MOZ_ASSERT(r1 == 0, "Failed to install GCOV SIGUSR1 handler");
 
   struct sigaction reset_sa;
   reset_sa.sa_handler = CodeCoverageHandler::ResetCounters;
   reset_sa.sa_flags = SA_RESTART;
   sigemptyset(&reset_sa.sa_mask);
   DebugOnly<int> r2 = sigaction(SIGUSR2, &reset_sa, nullptr);
   MOZ_ASSERT(r2 == 0, "Failed to install GCOV SIGUSR2 handler");
+#endif
 }
 
 CodeCoverageHandler::CodeCoverageHandler()
   : mGcovLock("GcovLock")
 {
   SetSignalHandlers();
 }