Bug 1314176 - convert AddonManager to ES6 classes r?aswan draft
authorRobert Helmer <rhelmer@mozilla.com>
Sat, 12 Nov 2016 00:54:11 -0800
changeset 438471 55f88b8446d46e8d23c4eef69bab0a4bcb48ad88
parent 438469 feddafb5cb546b15b160260da8632beb6b89bd71
child 536930 a641a4dff53bb01e2d1271cd4f7c186c9545b78c
push id35737
push userrhelmer@mozilla.com
push dateMon, 14 Nov 2016 16:56:35 +0000
reviewersaswan
bugs1314176
milestone53.0a1
Bug 1314176 - convert AddonManager to ES6 classes r?aswan MozReview-Commit-ID: EsYF26vRRNy
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/DeferredSave.jsm
toolkit/mozapps/extensions/LightweightThemeManager.jsm
toolkit/mozapps/extensions/internal/AddonLogging.jsm
toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
toolkit/mozapps/extensions/internal/GMPProvider.jsm
toolkit/mozapps/extensions/internal/PluginProvider.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/internal/XPIProviderUtils.js
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -339,280 +339,234 @@ function webAPIForAddon(addon) {
   result.canUninstall = Boolean(addon.permissions & AddonManager.PERM_CAN_UNINSTALL);
 
   return result;
 }
 
 /**
  * A helper class to repeatedly call a listener with each object in an array
  * optionally checking whether the object has a method in it.
- *
- * @param  aObjects
- *         The array of objects to iterate through
- * @param  aMethod
- *         An optional method name, if not null any objects without this method
- *         will not be passed to the listener
- * @param  aListener
- *         A listener implementing nextObject and noMoreObjects methods. The
- *         former will be called with the AsyncObjectCaller as the first
- *         parameter and the object as the second. noMoreObjects will be passed
- *         just the AsyncObjectCaller
  */
-function AsyncObjectCaller(aObjects, aMethod, aListener) {
-  this.objects = [...aObjects];
-  this.method = aMethod;
-  this.listener = aListener;
-
-  this.callNext();
-}
-
-AsyncObjectCaller.prototype = {
-  objects: null,
-  method: null,
-  listener: null,
+ class AsyncObjectCaller {
+  /**
+   * @param  aObjects
+   *         The array of objects to iterate through
+   * @param  aMethod
+   *         An optional method name, if not null any objects without this method
+   *         will not be passed to the listener
+   * @param  aListener
+   *         A listener implementing nextObject and noMoreObjects methods. The
+   *         former will be called with the AsyncObjectCaller as the first
+   *         parameter and the object as the second. noMoreObjects will be passed
+   *         just the AsyncObjectCaller
+   */
+  constructor(aObjects, aMethod, aListener) {
+    this.objects = [...aObjects];
+    this.method = aMethod;
+    this.listener = aListener;
+
+    this.callNext();
+  }
 
   /**
    * Passes the next object to the listener or calls noMoreObjects if there
    * are none left.
    */
-  callNext: function() {
+  callNext() {
     if (this.objects.length == 0) {
       this.listener.noMoreObjects(this);
       return;
     }
 
     let object = this.objects.shift();
     if (!this.method || this.method in object)
       this.listener.nextObject(this, object);
     else
       this.callNext();
   }
-};
+}
 
 /**
  * Listens for a browser changing origin and cancels the installs that were
  * started by it.
  */
-function BrowserListener(aBrowser, aInstallingPrincipal, aInstalls) {
-  this.browser = aBrowser;
-  this.principal = aInstallingPrincipal;
-  this.installs = aInstalls;
-  this.installCount = aInstalls.length;
-
-  aBrowser.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION);
-  Services.obs.addObserver(this, "message-manager-close", true);
-
-  for (let install of this.installs)
-    install.addListener(this);
-
-  this.registered = true;
-}
-
-BrowserListener.prototype = {
-  browser: null,
-  installs: null,
-  installCount: null,
-  registered: false,
-
-  unregister: function() {
+ class BrowserListener {
+   constructor(aBrowser, aInstallingPrincipal, aInstalls) {
+     this.browser = aBrowser;
+     this.principal = aInstallingPrincipal;
+     this.installs = aInstalls;
+     this.installCount = aInstalls.length;
+
+     aBrowser.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_LOCATION);
+     Services.obs.addObserver(this, "message-manager-close", true);
+
+     for (let install of this.installs)
+       install.addListener(this);
+
+     this.registered = true;
+  }
+
+  unregister() {
     if (!this.registered)
       return;
     this.registered = false;
 
     Services.obs.removeObserver(this, "message-manager-close");
     // The browser may have already been detached
     if (this.browser.removeProgressListener)
       this.browser.removeProgressListener(this);
 
     for (let install of this.installs)
       install.removeListener(this);
     this.installs = null;
-  },
-
-  cancelInstalls: function() {
+  }
+
+  cancelInstalls() {
     for (let install of this.installs) {
       try {
         install.cancel();
       }
       catch (e) {
         // Some installs may have already failed or been cancelled, ignore these
       }
     }
-  },
-
-  observe: function(subject, topic, data) {
+  }
+
+  observe(subject, topic, data) {
     if (subject != this.browser.messageManager)
       return;
 
     // The browser's message manager has closed and so the browser is
     // going away, cancel all installs
     this.cancelInstalls();
-  },
-
-  onLocationChange: function(webProgress, request, location) {
+  }
+
+  onLocationChange(webProgress, request, location) {
     if (this.browser.contentPrincipal && this.principal.subsumes(this.browser.contentPrincipal))
       return;
 
     // The browser has navigated to a new origin so cancel all installs
     this.cancelInstalls();
-  },
-
-  onDownloadCancelled: function(install) {
+  }
+
+  onDownloadCancelled(install) {
     // Don't need to hear more events from this install
     install.removeListener(this);
 
     // Once all installs have ended unregister everything
     if (--this.installCount == 0)
       this.unregister();
-  },
-
-  onDownloadFailed: function(install) {
+  }
+
+  onDownloadFailed(install) {
     this.onDownloadCancelled(install);
-  },
-
-  onInstallFailed: function(install) {
+  }
+
+  onInstallFailed(install) {
     this.onDownloadCancelled(install);
-  },
-
-  onInstallEnded: function(install) {
+  }
+
+  onInstallEnded(install) {
     this.onDownloadCancelled(install);
-  },
-
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
-                                         Ci.nsIWebProgressListener,
-                                         Ci.nsIObserver])
-};
+  }
+
+  get QueryInterface() {
+    XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
+                           Ci.nsIWebProgressListener,
+                           Ci.nsIObserver])
+  }
+}
 
 /**
  * This represents an author of an add-on (e.g. creator or developer)
- *
- * @param  aName
- *         The name of the author
- * @param  aURL
- *         The URL of the author's profile page
  */
-function AddonAuthor(aName, aURL) {
-  this.name = aName;
-  this.url = aURL;
-}
-
-AddonAuthor.prototype = {
-  name: null,
-  url: null,
+ class AddonAuthor {
+  /**
+   * @param  aName
+   *         The name of the author
+   * @param  aURL
+   *         The URL of the author's profile page
+   */
+  constructor(aName, aURL) {
+    this.name = aName;
+    this.url = aURL;
+  }
 
   // Returns the author's name, defaulting to the empty string
-  toString: function() {
+  toString() {
     return this.name || "";
   }
 }
 
 /**
  * This represents an screenshot for an add-on
- *
- * @param  aURL
- *         The URL to the full version of the screenshot
- * @param  aWidth
- *         The width in pixels of the screenshot
- * @param  aHeight
- *         The height in pixels of the screenshot
- * @param  aThumbnailURL
- *         The URL to the thumbnail version of the screenshot
- * @param  aThumbnailWidth
- *         The width in pixels of the thumbnail version of the screenshot
- * @param  aThumbnailHeight
- *         The height in pixels of the thumbnail version of the screenshot
- * @param  aCaption
- *         The caption of the screenshot
  */
-function AddonScreenshot(aURL, aWidth, aHeight, aThumbnailURL,
-                         aThumbnailWidth, aThumbnailHeight, aCaption) {
-  this.url = aURL;
-  if (aWidth) this.width = aWidth;
-  if (aHeight) this.height = aHeight;
-  if (aThumbnailURL) this.thumbnailURL = aThumbnailURL;
-  if (aThumbnailWidth) this.thumbnailWidth = aThumbnailWidth;
-  if (aThumbnailHeight) this.thumbnailHeight = aThumbnailHeight;
-  if (aCaption) this.caption = aCaption;
-}
-
-AddonScreenshot.prototype = {
-  url: null,
-  width: null,
-  height: null,
-  thumbnailURL: null,
-  thumbnailWidth: null,
-  thumbnailHeight: null,
-  caption: null,
+class AddonScreenshot {
+  /**
+   * @param  aURL
+   *         The URL to the full version of the screenshot
+   * @param  aWidth
+   *         The width in pixels of the screenshot
+   * @param  aHeight
+   *         The height in pixels of the screenshot
+   * @param  aThumbnailURL
+   *         The URL to the thumbnail version of the screenshot
+   * @param  aThumbnailWidth
+   *         The width in pixels of the thumbnail version of the screenshot
+   * @param  aThumbnailHeight
+   *         The height in pixels of the thumbnail version of the screenshot
+   * @param  aCaption
+   *         The caption of the screenshot
+   */
+  constructor(aURL, aWidth, aHeight, aThumbnailURL,
+                           aThumbnailWidth, aThumbnailHeight, aCaption) {
+    this.url = aURL;
+    if (aWidth) this.width = aWidth;
+    if (aHeight) this.height = aHeight;
+    if (aThumbnailURL) this.thumbnailURL = aThumbnailURL;
+    if (aThumbnailWidth) this.thumbnailWidth = aThumbnailWidth;
+    if (aThumbnailHeight) this.thumbnailHeight = aThumbnailHeight;
+    if (aCaption) this.caption = aCaption;
+  }
 
   // Returns the screenshot URL, defaulting to the empty string
-  toString: function() {
+  toString() {
     return this.url || "";
   }
 }
 
 
 /**
  * This represents a compatibility override for an addon.
- *
- * @param  aType
- *         Overrride type - "compatible" or "incompatible"
- * @param  aMinVersion
- *         Minimum version of the addon to match
- * @param  aMaxVersion
- *         Maximum version of the addon to match
- * @param  aAppID
- *         Application ID used to match appMinVersion and appMaxVersion
- * @param  aAppMinVersion
- *         Minimum version of the application to match
- * @param  aAppMaxVersion
- *         Maximum version of the application to match
  */
-function AddonCompatibilityOverride(aType, aMinVersion, aMaxVersion, aAppID,
-                                    aAppMinVersion, aAppMaxVersion) {
-  this.type = aType;
-  this.minVersion = aMinVersion;
-  this.maxVersion = aMaxVersion;
-  this.appID = aAppID;
-  this.appMinVersion = aAppMinVersion;
-  this.appMaxVersion = aAppMaxVersion;
-}
-
-AddonCompatibilityOverride.prototype = {
+class AddonCompatibilityOverride {
   /**
-   * Type of override - "incompatible" or "compatible".
-   * Only "incompatible" is supported for now.
+   * @param  aType
+   *         Overrride type - "compatible" or "incompatible"
+   * @param  aMinVersion
+   *         Minimum version of the addon to match
+   * @param  aMaxVersion
+   *         Maximum version of the addon to match
+   * @param  aAppID
+   *         Application ID used to match appMinVersion and appMaxVersion
+   * @param  aAppMinVersion
+   *         Minimum version of the application to match
+   * @param  aAppMaxVersion
+   *         Maximum version of the application to match
    */
-  type: null,
-
-  /**
-   * Min version of the addon to match.
-   */
-  minVersion: null,
-
-  /**
-   * Max version of the addon to match.
-   */
-  maxVersion: null,
-
-  /**
-   * Application ID to match.
-   */
-  appID: null,
-
-  /**
-   * Min version of the application to match.
-   */
-  appMinVersion: null,
-
-  /**
-   * Max version of the application to match.
-   */
-  appMaxVersion: null
-};
-
+  constructor(aType, aMinVersion, aMaxVersion, aAppID,
+              aAppMinVersion, aAppMaxVersion) {
+    this.type = aType;
+    this.minVersion = aMinVersion;
+    this.maxVersion = aMaxVersion;
+    this.appID = aAppID;
+    this.appMinVersion = aAppMinVersion;
+    this.appMaxVersion = aAppMaxVersion;
+  }
+}
 
 /**
  * A type of add-on, used by the UI to determine how to display different types
  * of add-ons.
  *
  * @param  aID
  *         The add-on type ID
  * @param  aLocaleURI
--- a/toolkit/mozapps/extensions/DeferredSave.jsm
+++ b/toolkit/mozapps/extensions/DeferredSave.jsm
@@ -83,125 +83,125 @@ var PrefObserver = {
 PrefObserver.init();
 
 /**
  * A module to manage deferred, asynchronous writing of data files
  * to disk. Writing is deferred by waiting for a specified delay after
  * a request to save the data, before beginning to write. If more than
  * one save request is received during the delay, all requests are
  * fulfilled by a single write.
- *
- * @constructor
- * @param aPath
- *        String representing the full path of the file where the data
- *        is to be written.
- * @param aDataProvider
- *        Callback function that takes no argument and returns the data to
- *        be written. If aDataProvider returns an ArrayBufferView, the
- *        bytes it contains are written to the file as is.
- *        If aDataProvider returns a String the data are UTF-8 encoded
- *        and then written to the file.
- * @param [optional] aDelay
- *        The delay in milliseconds between the first saveChanges() call
- *        that marks the data as needing to be saved, and when the DeferredSave
- *        begins writing the data to disk. Default 50 milliseconds.
  */
-this.DeferredSave = function(aPath, aDataProvider, aDelay) {
-  // Create a new logger (child of 'DeferredSave' logger)
-  // for use by this particular instance of DeferredSave object
-  let leafName = OS.Path.basename(aPath);
-  let logger_id = DEFERREDSAVE_PARENT_LOGGER_ID + "." + leafName;
-  this.logger = Log.repository.getLogger(logger_id);
+class DeferredSave {
+  /**
+   * @param aPath
+   *        String representing the full path of the file where the data
+   *        is to be written.
+   * @param aDataProvider
+   *        Callback function that takes no argument and returns the data to
+   *        be written. If aDataProvider returns an ArrayBufferView, the
+   *        bytes it contains are written to the file as is.
+   *        If aDataProvider returns a String the data are UTF-8 encoded
+   *        and then written to the file.
+   * @param [optional] aDelay
+   *        The delay in milliseconds between the first saveChanges() call
+   *        that marks the data as needing to be saved, and when the DeferredSave
+   *        begins writing the data to disk. Default 50 milliseconds.
+   */
+   constructor(aPath, aDataProvider, aDelay) {
+    // Create a new logger (child of 'DeferredSave' logger)
+    // for use by this particular instance of DeferredSave object
+    let leafName = OS.Path.basename(aPath);
+    let logger_id = DEFERREDSAVE_PARENT_LOGGER_ID + "." + leafName;
+    this.logger = Log.repository.getLogger(logger_id);
 
-  // @type {Deferred|null}, null when no data needs to be written
-  // @resolves with the result of OS.File.writeAtomic when all writes complete
-  // @rejects with the error from OS.File.writeAtomic if the write fails,
-  //          or with the error from aDataProvider() if that throws.
-  this._pending = null;
+    // @type {Deferred|null}, null when no data needs to be written
+    // @resolves with the result of OS.File.writeAtomic when all writes complete
+    // @rejects with the error from OS.File.writeAtomic if the write fails,
+    //          or with the error from aDataProvider() if that throws.
+    this._pending = null;
 
-  // @type {Promise}, completes when the in-progress write (if any) completes,
-  //       kept as a resolved promise at other times to simplify logic.
-  //       Because _deferredSave() always uses _writing.then() to execute
-  //       its next action, we don't need a special case for whether a write
-  //       is in progress - if the previous write is complete (and the _writing
-  //       promise is already resolved/rejected), _writing.then() starts
-  //       the next action immediately.
-  //
-  // @resolves with the result of OS.File.writeAtomic
-  // @rejects with the error from OS.File.writeAtomic
-  this._writing = Promise.resolve(0);
+    // @type {Promise}, completes when the in-progress write (if any) completes,
+    //       kept as a resolved promise at other times to simplify logic.
+    //       Because _deferredSave() always uses _writing.then() to execute
+    //       its next action, we don't need a special case for whether a write
+    //       is in progress - if the previous write is complete (and the _writing
+    //       promise is already resolved/rejected), _writing.then() starts
+    //       the next action immediately.
+    //
+    // @resolves with the result of OS.File.writeAtomic
+    // @rejects with the error from OS.File.writeAtomic
+    this._writing = Promise.resolve(0);
 
-  // Are we currently waiting for a write to complete
-  this.writeInProgress = false;
+    // Are we currently waiting for a write to complete
+    this.writeInProgress = false;
 
-  this._path = aPath;
-  this._dataProvider = aDataProvider;
+    this._path = aPath;
+    this._dataProvider = aDataProvider;
 
-  this._timer = null;
+    this._timer = null;
 
-  // Some counters for telemetry
-  // The total number of times the file was written
-  this.totalSaves = 0;
+    // Some counters for telemetry
+    // The total number of times the file was written
+    this.totalSaves = 0;
 
-  // The number of times the data became dirty while
-  // another save was in progress
-  this.overlappedSaves = 0;
+    // The number of times the data became dirty while
+    // another save was in progress
+    this.overlappedSaves = 0;
 
-  // Error returned by the most recent write (if any)
-  this._lastError = null;
+    // Error returned by the most recent write (if any)
+    this._lastError = null;
 
-  if (aDelay && (aDelay > 0))
-    this._delay = aDelay;
-  else
-    this._delay = DEFAULT_SAVE_DELAY_MS;
-}
+    if (aDelay && (aDelay > 0))
+      this._delay = aDelay;
+    else
+      this._delay = DEFAULT_SAVE_DELAY_MS;
+  }
 
-this.DeferredSave.prototype = {
   get dirty() {
     return this._pending || this.writeInProgress;
-  },
+  }
 
   get lastError() {
     return this._lastError;
-  },
+  }
 
   // Start the pending timer if data is dirty
-  _startTimer: function() {
+  _startTimer() {
     if (!this._pending) {
       return;
     }
 
       this.logger.debug("Starting timer");
     if (!this._timer)
       this._timer = MakeTimer();
     this._timer.initWithCallback(() => this._deferredSave(),
                                  this._delay, Ci.nsITimer.TYPE_ONE_SHOT);
-  },
+  }
 
   /**
    * Mark the current stored data dirty, and schedule a flush to disk
    * @return A Promise<integer> that will be resolved after the data is written to disk;
    *         the promise is resolved with the number of bytes written.
    */
-  saveChanges: function() {
+  saveChanges() {
       this.logger.debug("Save changes");
     if (!this._pending) {
       if (this.writeInProgress) {
           this.logger.debug("Data changed while write in progress");
         this.overlappedSaves++;
       }
       this._pending = Promise.defer();
       // Wait until the most recent write completes or fails (if it hasn't already)
       // and then restart our timer
       this._writing.then(count => this._startTimer(), error => this._startTimer());
     }
     return this._pending.promise;
-  },
+  }
 
-  _deferredSave: function() {
+  _deferredSave() {
     let pending = this._pending;
     this._pending = null;
     let writing = this._writing;
     this._writing = pending.promise;
 
     // In either the success or the exception handling case, we don't need to handle
     // the error from _writing here; it's already being handled in another then()
     let toSave = null;
@@ -233,17 +233,17 @@ this.DeferredSave.prototype = {
         },
         error => {
           this._lastError = error;
           this.writeInProgress = false;
               this.logger.warn("Write failed", error);
           pending.reject(error);
         });
     });
-  },
+  }
 
   /**
    * Immediately save the dirty data to disk, skipping
    * the delay of normal operation. Note that the write
    * still happens asynchronously in the worker
    * thread from OS.File.
    *
    * There are four possible situations:
@@ -252,24 +252,24 @@ this.DeferredSave.prototype = {
    * 3) Data is currently being written, in-memory copy is clean
    * 4) Data is being written and in-memory copy is dirty
    *
    * @return Promise<integer> that will resolve when all in-memory data
    *         has finished being flushed, returning the number of bytes
    *         written. If all in-memory data is clean, completes with the
    *         result of the most recent write.
    */
-  flush: function() {
+  flush() {
     // If we have pending changes, cancel our timer and set up the write
     // immediately (_deferredSave queues the write for after the most
     // recent write completes, if it hasn't already)
     if (this._pending) {
         this.logger.debug("Flush called while data is dirty");
       if (this._timer) {
         this._timer.cancel();
         this._timer = null;
       }
       this._deferredSave();
     }
 
     return this._writing;
   }
-};
+}
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -459,175 +459,175 @@ this.LightweightThemeManager = {
 
 const wrapperMap = new WeakMap();
 let themeFor = wrapper => wrapperMap.get(wrapper);
 
 /**
  * The AddonWrapper wraps lightweight theme to provide the data visible to
  * consumers of the AddonManager API.
  */
-function AddonWrapper(aTheme) {
-  wrapperMap.set(this, aTheme);
-}
+class AddonWrapper {
+  constructor(aTheme) {
+    wrapperMap.set(this, aTheme);
+  }
 
-AddonWrapper.prototype = {
   get id() {
     return themeFor(this).id + ID_SUFFIX;
-  },
+  }
 
   get type() {
     return ADDON_TYPE;
-  },
+  }
 
   get isActive() {
     let current = LightweightThemeManager.currentTheme;
     if (current)
       return themeFor(this).id == current.id;
     return false;
-  },
+  }
 
   get name() {
     return themeFor(this).name;
-  },
+  }
 
   get version() {
     let theme = themeFor(this);
     return "version" in theme ? theme.version : "";
-  },
+  }
 
   get creator() {
     let theme = themeFor(this);
     return "author" in theme ? new AddonManagerPrivate.AddonAuthor(theme.author) : null;
-  },
+  }
 
   get screenshots() {
     let url = themeFor(this).previewURL;
     return [new AddonManagerPrivate.AddonScreenshot(url)];
-  },
+  }
 
   get pendingOperations() {
     let pending = AddonManager.PENDING_NONE;
     if (this.isActive == this.userDisabled)
       pending |= this.isActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE;
     return pending;
-  },
+  }
 
   get operationsRequiringRestart() {
     // If a non-default theme is in use then a restart will be required to
     // enable lightweight themes unless dynamic theme switching is enabled
     if (Services.prefs.prefHasUserValue(PREF_GENERAL_SKINS_SELECTEDSKIN)) {
       try {
         if (Services.prefs.getBoolPref(PREF_EM_DSS_ENABLED))
           return AddonManager.OP_NEEDS_RESTART_NONE;
       }
       catch (e) {
       }
       return AddonManager.OP_NEEDS_RESTART_ENABLE;
     }
 
     return AddonManager.OP_NEEDS_RESTART_NONE;
-  },
+  }
 
   get size() {
     // The size changes depending on whether the theme is in use or not, this is
     // probably not worth exposing.
     return null;
-  },
+  }
 
   get permissions() {
     let permissions = 0;
 
     // Do not allow uninstall of builtIn themes.
     if (!LightweightThemeManager._builtInThemes.has(themeFor(this).id))
       permissions = AddonManager.PERM_CAN_UNINSTALL;
     if (this.userDisabled)
       permissions |= AddonManager.PERM_CAN_ENABLE;
     else
       permissions |= AddonManager.PERM_CAN_DISABLE;
     return permissions;
-  },
+  }
 
   get userDisabled() {
     let id = themeFor(this).id;
     if (_themeIDBeingEnabled == id)
       return false;
     if (_themeIDBeingDisabled == id)
       return true;
 
     try {
       let toSelect = Services.prefs.getCharPref(PREF_LWTHEME_TO_SELECT);
       return id != toSelect;
     }
     catch (e) {
       let current = LightweightThemeManager.currentTheme;
       return !current || current.id != id;
     }
-  },
+  }
 
   set userDisabled(val) {
     if (val == this.userDisabled)
       return val;
 
     if (val)
       LightweightThemeManager.currentTheme = null;
     else
       LightweightThemeManager.currentTheme = themeFor(this);
 
     return val;
-  },
+  }
 
   // Lightweight themes are never disabled by the application
   get appDisabled() {
     return false;
-  },
+  }
 
   // Lightweight themes are always compatible
   get isCompatible() {
     return true;
-  },
+  }
 
   get isPlatformCompatible() {
     return true;
-  },
+  }
 
   get scope() {
     return AddonManager.SCOPE_PROFILE;
-  },
+  }
 
   get foreignInstall() {
     return false;
-  },
+  }
 
-  uninstall: function() {
+  uninstall() {
     LightweightThemeManager.forgetUsedTheme(themeFor(this).id);
-  },
+  }
 
-  cancelUninstall: function() {
+  cancelUninstall() {
     throw new Error("Theme is not marked to be uninstalled");
-  },
+  }
 
-  findUpdates: function(listener, reason, appVersion, platformVersion) {
+  findUpdates(listener, reason, appVersion, platformVersion) {
     AddonManagerPrivate.callNoUpdateListeners(this, listener, reason, appVersion, platformVersion);
-  },
+  }
 
   // Lightweight themes are always compatible
-  isCompatibleWith: function(appVersion, platformVersion) {
+  isCompatibleWith(appVersion, platformVersion) {
     return true;
-  },
+  }
 
   // Lightweight themes are always securely updated
   get providesUpdatesSecurely() {
     return true;
-  },
+  }
 
   // Lightweight themes are never blocklisted
   get blocklistState() {
     return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
   }
-};
+}
 
 ["description", "homepageURL", "iconURL"].forEach(function(prop) {
   Object.defineProperty(AddonWrapper.prototype, prop, {
     get: function() {
       let theme = themeFor(this);
       return prop in theme ? theme[prop] : null;
     },
     enumarable: true,
--- a/toolkit/mozapps/extensions/internal/AddonLogging.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonLogging.jsm
@@ -69,24 +69,22 @@ function getStackDetails(aException) {
   catch (e) {
     return {
       sourceName: null,
       lineNumber: 0
     };
   }
 }
 
-function AddonLogger(aName) {
-  this.name = aName;
-}
+class AddonLogger {
+  constructor(aName) {
+    this.name = aName;
+  }
 
-AddonLogger.prototype = {
-  name: null,
-
-  error: function(aStr, aException) {
+  error(aStr, aException) {
     let message = formatLogMessage("error", this.name, aStr, aException);
 
     let stack = getStackDetails(aException);
 
     let consoleMessage = Cc["@mozilla.org/scripterror;1"].
                          createInstance(Ci.nsIScriptError);
     consoleMessage.init(message, stack.sourceName, null, stack.lineNumber, 0,
                         Ci.nsIScriptError.errorFlag, "component javascript");
@@ -117,41 +115,41 @@ AddonLogger.prototype = {
                    createInstance(Ci.nsIConverterOutputStream);
       writer.init(stream, "UTF-8", 0, 0x0000);
       writer.writeString(formatTimestamp(tstamp) + " " +
                          message + " at " + stack.sourceName + ":" +
                          stack.lineNumber + "\n");
       writer.close();
     }
     catch (e) { }
-  },
+  }
 
-  warn: function(aStr, aException) {
+  warn(aStr, aException) {
     let message = formatLogMessage("warn", this.name, aStr, aException);
 
     let stack = getStackDetails(aException);
 
     let consoleMessage = Cc["@mozilla.org/scripterror;1"].
                          createInstance(Ci.nsIScriptError);
     consoleMessage.init(message, stack.sourceName, null, stack.lineNumber, 0,
                         Ci.nsIScriptError.warningFlag, "component javascript");
     Services.console.logMessage(consoleMessage);
 
     if (gDebugLogEnabled)
       dump("*** " + message + "\n");
-  },
+  }
 
-  log: function(aStr, aException) {
+  log(aStr, aException) {
     if (gDebugLogEnabled) {
       let message = formatLogMessage("log", this.name, aStr, aException);
       dump("*** " + message + "\n");
       Services.console.logStringMessage(message);
     }
   }
-};
+}
 
 this.LogManager = {
   getLogger: function(aName, aTarget) {
     let logger = new AddonLogger(aName);
 
     if (aTarget) {
       ["error", "warn", "log"].forEach(function(name) {
         let fname = name.toUpperCase();
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -467,48 +467,51 @@ var AddonTestUtils = {
             Services.obs.notifyObservers(file, "flush-cache-entry", "cert-override");
         }
       }
 
       return [callback, result, cert];
     }).bind(this);
 
 
-    function FakeCertDB() {
-      for (let property of Object.keys(realCertDB)) {
-        if (property in this)
-          continue;
+    class FakeCertDB {
+      constructor() {
+        for (let property of Object.keys(realCertDB)) {
+          if (property in this)
+            continue;
 
-        if (typeof realCertDB[property] == "function")
-          this[property] = realCertDB[property].bind(realCertDB);
+          if (typeof realCertDB[property] == "function")
+            this[property] = realCertDB[property].bind(realCertDB);
+        }
       }
-    }
-    FakeCertDB.prototype = {
+
       openSignedAppFileAsync(root, file, callback) {
         // First try calling the real cert DB
         realCertDB.openSignedAppFileAsync(root, file, (result, zipReader, cert) => {
           verifyCert(file.clone(), result, cert, callback)
             .then(([callback, result, cert]) => {
               callback.openSignedAppFileFinished(result, zipReader, cert);
             });
         });
-      },
+      }
 
       verifySignedDirectoryAsync(root, dir, callback) {
         // First try calling the real cert DB
         realCertDB.verifySignedDirectoryAsync(root, dir, (result, cert) => {
           verifyCert(dir.clone(), result, cert, callback)
             .then(([callback, result, cert]) => {
               callback.verifySignedDirectoryFinished(result, cert);
             });
         });
-      },
+      }
 
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIX509CertDB]),
-    };
+      get QueryInterface() {
+        return XPCOMUtils.generateQI([Ci.nsIX509CertDB]);
+      }
+    }
 
     let certDBFactory = XPCOMUtils.generateSingletonFactory(FakeCertDB);
     registrar.registerFactory(CERTDB_CID, "CertDB",
                               CERTDB_CONTRACTID, certDBFactory);
   },
 
   /**
    * Starts up the add-on manager as if it was started by the application.
--- a/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
@@ -56,79 +56,78 @@ var logger = Log.repository.getLogger(LO
 /**
  * A serialisation method for RDF data that produces an identical string
  * for matching RDF graphs.
  * The serialisation is not complete, only assertions stemming from a given
  * resource are included, multiple references to the same resource are not
  * permitted, and the RDF prolog and epilog are not included.
  * RDF Blob and Date literals are not supported.
  */
-function RDFSerializer() {
-  this.cUtils = Cc["@mozilla.org/rdf/container-utils;1"].
-                getService(Ci.nsIRDFContainerUtils);
-  this.resources = [];
-}
-
-RDFSerializer.prototype = {
-  INDENT: "  ",      // The indent used for pretty-printing
-  resources: null,   // Array of the resources that have been found
+class RDFSerializer {
+  constructor() {
+    this.cUtils = Cc["@mozilla.org/rdf/container-utils;1"].
+                  getService(Ci.nsIRDFContainerUtils);
+    this.resources = [];
+    this.INDENT = "  ";      // The indent used for pretty-printing
+    this.resources = null;   // Array of the resources that have been found
+  }
 
   /**
    * Escapes characters from a string that should not appear in XML.
    *
    * @param  aString
    *         The string to be escaped
    * @return a string with all characters invalid in XML character data
    *         converted to entity references.
    */
-  escapeEntities: function(aString) {
+  escapeEntities(aString) {
     aString = aString.replace(/&/g, "&amp;");
     aString = aString.replace(/</g, "&lt;");
     aString = aString.replace(/>/g, "&gt;");
     return aString.replace(/"/g, "&quot;");
-  },
+  }
 
   /**
    * Serializes all the elements of an RDF container.
    *
    * @param  aDs
    *         The RDF datasource
    * @param  aContainer
    *         The RDF container to output the child elements of
    * @param  aIndent
    *         The current level of indent for pretty-printing
    * @return a string containing the serialized elements.
    */
-  serializeContainerItems: function(aDs, aContainer, aIndent) {
+  serializeContainerItems(aDs, aContainer, aIndent) {
     var result = "";
     var items = aContainer.GetElements();
     while (items.hasMoreElements()) {
       var item = items.getNext().QueryInterface(Ci.nsIRDFResource);
       result += aIndent + "<RDF:li>\n"
       result += this.serializeResource(aDs, item, aIndent + this.INDENT);
       result += aIndent + "</RDF:li>\n"
     }
     return result;
-  },
+  }
 
   /**
    * Serializes all em:* (see EM_NS) properties of an RDF resource except for
    * the em:signature property. As this serialization is to be compared against
    * the manifest signature it cannot contain the em:signature property itself.
    *
    * @param  aDs
    *         The RDF datasource
    * @param  aResource
    *         The RDF resource that contains the properties to serialize
    * @param  aIndent
    *         The current level of indent for pretty-printing
    * @return a string containing the serialized properties.
    * @throws if the resource contains a property that cannot be serialized
    */
-  serializeResourceProperties: function(aDs, aResource, aIndent) {
+  serializeResourceProperties(aDs, aResource, aIndent) {
     var result = "";
     var items = [];
     var arcs = aDs.ArcLabelsOut(aResource);
     while (arcs.hasMoreElements()) {
       var arc = arcs.getNext().QueryInterface(Ci.nsIRDFResource);
       if (arc.ValueUTF8.substring(0, PREFIX_NS_EM.length) != PREFIX_NS_EM)
         continue;
       var prop = arc.ValueUTF8.substring(PREFIX_NS_EM.length);
@@ -155,34 +154,34 @@ RDFSerializer.prototype = {
         else {
           throw Components.Exception("Cannot serialize unknown literal type");
         }
       }
     }
     items.sort();
     result += items.join("");
     return result;
-  },
+  }
 
   /**
    * Recursively serializes an RDF resource and all resources it links to.
    * This will only output EM_NS properties and will ignore any em:signature
    * property.
    *
    * @param  aDs
    *         The RDF datasource
    * @param  aResource
    *         The RDF resource to serialize
    * @param  aIndent
    *         The current level of indent for pretty-printing. If undefined no
    *         indent will be added
    * @return a string containing the serialized resource.
    * @throws if the RDF data contains multiple references to the same resource.
    */
-  serializeResource: function(aDs, aResource, aIndent) {
+  serializeResource(aDs, aResource, aIndent) {
     if (this.resources.indexOf(aResource) != -1 ) {
       // We cannot output multiple references to the same resource.
       throw Components.Exception("Cannot serialize multiple references to " + aResource.Value);
     }
     if (aIndent === undefined)
       aIndent = "";
 
     this.resources.push(aResource);
@@ -548,72 +547,68 @@ function parseJSONManifest(aId, aUpdateK
     results.push(result);
   }
   return results;
 }
 
 /**
  * Starts downloading an update manifest and then passes it to an appropriate
  * parser to convert to an array of update objects
- *
- * @param  aId
- *         The ID of the add-on being checked for updates
- * @param  aUpdateKey
- *         An optional update key for the add-on
- * @param  aUrl
- *         The URL of the update manifest
- * @param  aObserver
- *         An observer to pass results to
  */
-function UpdateParser(aId, aUpdateKey, aUrl, aObserver) {
-  this.id = aId;
-  this.updateKey = aUpdateKey;
-  this.observer = aObserver;
-  this.url = aUrl;
-
-  let requireBuiltIn = true;
-  try {
-    requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS);
-  }
-  catch (e) {
-  }
+class UpdateParser {
+  /**
+   *
+   * @param  aId
+   *         The ID of the add-on being checked for updates
+   * @param  aUpdateKey
+   *         An optional update key for the add-on
+   * @param  aUrl
+   *         The URL of the update manifest
+   * @param  aObserver
+   *         An observer to pass results to
+   */
+  constructor(aId, aUpdateKey, aUrl, aObserver) {
+    this.id = aId;
+    this.updateKey = aUpdateKey;
+    this.observer = aObserver;
+    this.url = aUrl;
 
-  logger.debug("Requesting " + aUrl);
-  try {
-    this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
-                   createInstance(Ci.nsIXMLHttpRequest);
-    this.request.open("GET", this.url, true);
-    this.request.channel.notificationCallbacks = new CertUtils.BadCertHandler(!requireBuiltIn);
-    this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
-    // Prevent the request from writing to cache.
-    this.request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
-    this.request.overrideMimeType("text/plain");
-    this.request.setRequestHeader("Moz-XPI-Update", "1", true);
-    this.request.timeout = TIMEOUT;
-    this.request.addEventListener("load", () => this.onLoad(), false);
-    this.request.addEventListener("error", () => this.onError(), false);
-    this.request.addEventListener("timeout", () => this.onTimeout(), false);
-    this.request.send(null);
+    let requireBuiltIn = true;
+    try {
+      requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS);
+    }
+    catch (e) {
+    }
+
+    logger.debug("Requesting " + aUrl);
+    try {
+      this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
+                     createInstance(Ci.nsIXMLHttpRequest);
+      this.request.open("GET", this.url, true);
+      this.request.channel.notificationCallbacks = new CertUtils.BadCertHandler(!requireBuiltIn);
+      this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
+      // Prevent the request from writing to cache.
+      this.request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
+      this.request.overrideMimeType("text/plain");
+      this.request.setRequestHeader("Moz-XPI-Update", "1", true);
+      this.request.timeout = TIMEOUT;
+      this.request.addEventListener("load", () => this.onLoad(), false);
+      this.request.addEventListener("error", () => this.onError(), false);
+      this.request.addEventListener("timeout", () => this.onTimeout(), false);
+      this.request.send(null);
+    }
+    catch (e) {
+      logger.error("Failed to request update manifest", e);
+    }
   }
-  catch (e) {
-    logger.error("Failed to request update manifest", e);
-  }
-}
-
-UpdateParser.prototype = {
-  id: null,
-  updateKey: null,
-  observer: null,
-  request: null,
-  url: null,
 
   /**
    * Called when the manifest has been successfully loaded.
    */
-  onLoad: function() {
+  onLoad() {
     let request = this.request;
     this.request = null;
     this._doneAt = new Error("place holder");
 
     let requireBuiltIn = true;
     try {
       requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS);
     }
@@ -684,32 +679,32 @@ UpdateParser.prototype = {
       }
       catch (e) {
         logger.warn("onUpdateCheckComplete notification failed", e);
       }
     }
     else {
       logger.warn("onUpdateCheckComplete may not properly cancel", new Error("stack marker"));
     }
-  },
+  }
 
   /**
    * Called when the request times out
    */
-  onTimeout: function() {
+  onTimeout() {
     this.request = null;
     this._doneAt = new Error("Timed out");
     logger.warn("Request for " + this.url + " timed out");
     this.notifyError(AddonUpdateChecker.ERROR_TIMEOUT);
-  },
+  }
 
   /**
    * Called when the manifest failed to load.
    */
-  onError: function() {
+  onError() {
     if (!Components.isSuccessCode(this.request.status)) {
       logger.warn("Request failed: " + this.url + " - " + this.request.status);
     }
     else if (this.request.channel instanceof Ci.nsIHttpChannel) {
       try {
         if (this.request.channel.requestSucceeded) {
           logger.warn("Request failed: " + this.url + " - " +
                this.request.channel.responseStatus + ": " +
@@ -723,46 +718,46 @@ UpdateParser.prototype = {
     else {
       logger.warn("Request failed for an unknown reason");
     }
 
     this.request = null;
     this._doneAt = new Error("UP_onError");
 
     this.notifyError(AddonUpdateChecker.ERROR_DOWNLOAD_ERROR);
-  },
+  }
 
   /**
    * Helper method to notify the observer that an error occured.
    */
-  notifyError: function(aStatus) {
+  notifyError(aStatus) {
     if ("onUpdateCheckError" in this.observer) {
       try {
         this.observer.onUpdateCheckError(aStatus);
       }
       catch (e) {
         logger.warn("onUpdateCheckError notification failed", e);
       }
     }
-  },
+  }
 
   /**
    * Called to cancel an in-progress update check.
    */
-  cancel: function() {
+  cancel() {
     if (!this.request) {
       logger.error("Trying to cancel already-complete request", this._doneAt);
       return;
     }
     this.request.abort();
     this.request = null;
     this._doneAt = new Error("UP_cancel");
     this.notifyError(AddonUpdateChecker.ERROR_CANCELLED);
   }
-};
+}
 
 /**
  * Tests if an update matches a version of the application or platform
  *
  * @param  aUpdate
  *         The available update
  * @param  aAppVersion
  *         The application version to use
--- a/toolkit/mozapps/extensions/internal/GMPProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/GMPProvider.jsm
@@ -113,154 +113,155 @@ function configureLogging() {
 }
 
 
 
 /**
  * The GMPWrapper provides the info for the various GMP plugins to public
  * callers through the API.
  */
-function GMPWrapper(aPluginInfo) {
-  this._plugin = aPluginInfo;
-  this._log =
-    Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP",
-                                              "GMPWrapper(" +
-                                              this._plugin.id + ") ");
-  Preferences.observe(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED,
-                                          this._plugin.id),
-                      this.onPrefEnabledChanged, this);
-  Preferences.observe(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION,
-                                          this._plugin.id),
-                      this.onPrefVersionChanged, this);
-  if (this._plugin.isEME) {
-    Preferences.observe(GMPPrefs.KEY_EME_ENABLED,
-                        this.onPrefEMEGlobalEnabledChanged, this);
-    messageManager.addMessageListener("EMEVideo:ContentMediaKeysRequest", this);
+ class GMPWrapper {
+  constructor(aPluginInfo) {
+    // An active task that checks for plugin updates and installs them.
+    this._updateTask = null;
+    this._gmpPath = null;
+    this._isUpdateCheckPending = false;
+
+    this.optionsType = AddonManager.OPTIONS_TYPE_INLINE;
+
+    this._plugin = aPluginInfo;
+    this._log =
+      Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP",
+                                                "GMPWrapper(" +
+                                                this._plugin.id + ") ");
+    Preferences.observe(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED,
+                                            this._plugin.id),
+                        this.onPrefEnabledChanged, this);
+    Preferences.observe(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION,
+                                            this._plugin.id),
+                        this.onPrefVersionChanged, this);
+    if (this._plugin.isEME) {
+      Preferences.observe(GMPPrefs.KEY_EME_ENABLED,
+                          this.onPrefEMEGlobalEnabledChanged, this);
+      messageManager.addMessageListener("EMEVideo:ContentMediaKeysRequest", this);
+    }
   }
-}
 
-GMPWrapper.prototype = {
-  // An active task that checks for plugin updates and installs them.
-  _updateTask: null,
-  _gmpPath: null,
-  _isUpdateCheckPending: false,
+  get optionsURL() { return this._plugin.optionsURL; }
 
-  optionsType: AddonManager.OPTIONS_TYPE_INLINE,
-  get optionsURL() { return this._plugin.optionsURL; },
-
-  set gmpPath(aPath) { this._gmpPath = aPath; },
+  set gmpPath(aPath) { this._gmpPath = aPath; }
   get gmpPath() {
     if (!this._gmpPath && this.isInstalled) {
       this._gmpPath = OS.Path.join(OS.Constants.Path.profileDir,
                                    this._plugin.id,
                                    GMPPrefs.get(GMPPrefs.KEY_PLUGIN_VERSION,
                                                 null, this._plugin.id));
     }
     return this._gmpPath;
-  },
+  }
 
-  get id() { return this._plugin.id; },
-  get type() { return "plugin"; },
-  get isGMPlugin() { return true; },
-  get name() { return this._plugin.name; },
-  get creator() { return null; },
-  get homepageURL() { return this._plugin.homepageURL; },
+  get id() { return this._plugin.id; }
+  get type() { return "plugin"; }
+  get isGMPlugin() { return true; }
+  get name() { return this._plugin.name; }
+  get creator() { return null; }
+  get homepageURL() { return this._plugin.homepageURL; }
 
-  get description() { return this._plugin.description; },
-  get fullDescription() { return this._plugin.fullDescription; },
+  get description() { return this._plugin.description; }
+  get fullDescription() { return this._plugin.fullDescription; }
 
   get version() { return GMPPrefs.get(GMPPrefs.KEY_PLUGIN_VERSION, null,
-                                      this._plugin.id); },
+                                      this._plugin.id); }
 
   get isActive() {
     return !this.appDisabled &&
            !this.userDisabled &&
            !GMPUtils.isPluginHidden(this._plugin);
-  },
+  }
   get appDisabled() {
     if (this._plugin.isEME && !GMPPrefs.get(GMPPrefs.KEY_EME_ENABLED, true)) {
       // If "media.eme.enabled" is false, all EME plugins are disabled.
       return true;
     }
     return false;
-  },
+  }
 
   get userDisabled() {
     return !GMPPrefs.get(GMPPrefs.KEY_PLUGIN_ENABLED, true, this._plugin.id);
-  },
+  }
   set userDisabled(aVal) { GMPPrefs.set(GMPPrefs.KEY_PLUGIN_ENABLED,
                                         aVal === false,
-                                        this._plugin.id); },
+                                        this._plugin.id); }
 
-  get blocklistState() { return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; },
-  get size() { return 0; },
-  get scope() { return AddonManager.SCOPE_APPLICATION; },
-  get pendingOperations() { return AddonManager.PENDING_NONE; },
+  get blocklistState() { return Ci.nsIBlocklistService.STATE_NOT_BLOCKED; }
+  get size() { return 0; }
+  get scope() { return AddonManager.SCOPE_APPLICATION; }
+  get pendingOperations() { return AddonManager.PENDING_NONE; }
 
-  get operationsRequiringRestart() { return AddonManager.OP_NEEDS_RESTART_NONE },
+  get operationsRequiringRestart() { return AddonManager.OP_NEEDS_RESTART_NONE }
 
   get permissions() {
     let permissions = 0;
     if (!this.appDisabled) {
       permissions |= AddonManager.PERM_CAN_UPGRADE;
       permissions |= this.userDisabled ? AddonManager.PERM_CAN_ENABLE :
                                          AddonManager.PERM_CAN_DISABLE;
     }
     return permissions;
-  },
+  }
 
   get updateDate() {
     let time = Number(GMPPrefs.get(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, null,
                                    this._plugin.id));
     if (!isNaN(time) && this.isInstalled) {
       return new Date(time * 1000)
     }
     return null;
-  },
+  }
 
   get isCompatible() {
     return true;
-  },
+  }
 
   get isPlatformCompatible() {
     return true;
-  },
+  }
 
   get providesUpdatesSecurely() {
     return true;
-  },
+  }
 
   get foreignInstall() {
     return false;
-  },
+  }
 
-  isCompatibleWith: function(aAppVersion, aPlatformVersion) {
+  isCompatibleWith(aAppVersion, aPlatformVersion) {
     return true;
-  },
+  }
 
   get applyBackgroundUpdates() {
     if (!GMPPrefs.isSet(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, this._plugin.id)) {
       return AddonManager.AUTOUPDATE_DEFAULT;
     }
 
     return GMPPrefs.get(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, this._plugin.id) ?
       AddonManager.AUTOUPDATE_ENABLE : AddonManager.AUTOUPDATE_DISABLE;
-  },
+  }
 
   set applyBackgroundUpdates(aVal) {
     if (aVal == AddonManager.AUTOUPDATE_DEFAULT) {
       GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, this._plugin.id);
     } else if (aVal == AddonManager.AUTOUPDATE_ENABLE) {
       GMPPrefs.set(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, this._plugin.id);
     } else if (aVal == AddonManager.AUTOUPDATE_DISABLE) {
       GMPPrefs.set(GMPPrefs.KEY_PLUGIN_AUTOUPDATE, false, this._plugin.id);
     }
-  },
+  }
 
-  findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
+  findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) {
     this._log.trace("findUpdates() - " + this._plugin.id + " - reason=" +
                     aReason);
 
     AddonManagerPrivate.callNoUpdateListeners(this, aListener);
 
     if (aReason === AddonManager.UPDATE_WHEN_PERIODIC_UPDATE) {
       if (!AddonManager.shouldAutoUpdate(this)) {
         this._log.trace("findUpdates() - " + this._plugin.id +
@@ -308,41 +309,41 @@ GMPWrapper.prototype = {
         throw e;
       } finally {
         this._updateTask = null;
         return true;
       }
     }.bind(this));
 
     return this._updateTask;
-  },
+  }
 
-  get pluginMimeTypes() { return []; },
+  get pluginMimeTypes() { return []; }
   get pluginLibraries() {
     if (this.isInstalled) {
       let path = this.version;
       return [path];
     }
     return [];
-  },
+  }
   get pluginFullpath() {
     if (this.isInstalled) {
       let path = OS.Path.join(OS.Constants.Path.profileDir,
                               this._plugin.id,
                               this.version);
       return [path];
     }
     return [];
-  },
+  }
 
   get isInstalled() {
     return this.version && this.version.length > 0;
-  },
+  }
 
-  _handleEnabledChanged: function() {
+  _handleEnabledChanged() {
     this._log.info("_handleEnabledChanged() id=" +
       this._plugin.id + " isActive=" + this.isActive);
 
     AddonManagerPrivate.callAddonListeners(this.isActive ?
                                            "onEnabling" : "onDisabling",
                                            this, false);
     if (this._gmpPath) {
       if (this.isActive) {
@@ -353,19 +354,19 @@ GMPWrapper.prototype = {
         this._log.info("onPrefEnabledChanged() - removing gmp directory " +
                        this._gmpPath);
         gmpService.removePluginDirectory(this._gmpPath);
       }
     }
     AddonManagerPrivate.callAddonListeners(this.isActive ?
                                            "onEnabled" : "onDisabled",
                                            this);
-  },
+  }
 
-  onPrefEMEGlobalEnabledChanged: function() {
+  onPrefEMEGlobalEnabledChanged() {
     this._log.info("onPrefEMEGlobalEnabledChanged() id=" + this._plugin.id +
       " appDisabled=" + this.appDisabled + " isActive=" + this.isActive +
       " hidden=" + GMPUtils.isPluginHidden(this._plugin));
 
     AddonManagerPrivate.callAddonListeners("onPropertyChanged", this,
                                            ["appDisabled"]);
     // If EME or the GMP itself are disabled, uninstall the GMP.
     // Otherwise, check for updates, so we download and install the GMP.
@@ -376,59 +377,59 @@ GMPWrapper.prototype = {
                                                null, false);
       AddonManagerPrivate.callAddonListeners("onInstalling", this, false);
       AddonManagerPrivate.callAddonListeners("onInstalled", this);
       this.checkForUpdates(GMP_CHECK_DELAY);
     }
     if (!this.userDisabled) {
       this._handleEnabledChanged();
     }
-  },
+  }
 
-  checkForUpdates: function(delay) {
+  checkForUpdates(delay) {
     if (this._isUpdateCheckPending) {
       return;
     }
     this._isUpdateCheckPending = true;
     GMPPrefs.reset(GMPPrefs.KEY_UPDATE_LAST_CHECK, null);
     // Delay this in case the user changes his mind and doesn't want to
     // enable EME after all.
     setTimeout(() => {
       if (!this.appDisabled) {
         let gmpInstallManager = new GMPInstallManager();
         // We don't really care about the results, if someone is interested
         // they can check the log.
         gmpInstallManager.simpleCheckAndInstall().then(null, () => {});
       }
       this._isUpdateCheckPending = false;
     }, delay);
-  },
+  }
 
-  receiveMessage: function({target: browser, data: data}) {
+  receiveMessage({target: browser, data: data}) {
     this._log.trace("receiveMessage() data=" + data);
     let parsedData;
     try {
       parsedData = JSON.parse(data);
     } catch (ex) {
       this._log.error("Malformed EME video message with data: " + data);
       return;
     }
     let {status: status, keySystem: keySystem} = parsedData;
     if (status == "cdm-not-installed") {
       this.checkForUpdates(0);
     }
-  },
+  }
 
-  onPrefEnabledChanged: function() {
+  onPrefEnabledChanged() {
     if (!this._plugin.isEME || !this.appDisabled) {
       this._handleEnabledChanged();
     }
-  },
+  }
 
-  onPrefVersionChanged: function() {
+  onPrefVersionChanged() {
     AddonManagerPrivate.callAddonListeners("onUninstalling", this, false);
     if (this._gmpPath) {
       this._log.info("onPrefVersionChanged() - unregistering gmp directory " +
                      this._gmpPath);
       gmpService.removeAndDeletePluginDirectory(this._gmpPath, true /* can defer */);
     }
     AddonManagerPrivate.callAddonListeners("onUninstalled", this);
 
@@ -443,47 +444,47 @@ GMPWrapper.prototype = {
                                                 null, this._plugin.id));
     }
     if (this._gmpPath && this.isActive) {
       this._log.info("onPrefVersionChanged() - registering gmp directory " +
                      this._gmpPath);
       gmpService.addPluginDirectory(this._gmpPath);
     }
     AddonManagerPrivate.callAddonListeners("onInstalled", this);
-  },
+  }
 
-  uninstallPlugin: function() {
+  uninstallPlugin() {
     AddonManagerPrivate.callAddonListeners("onUninstalling", this, false);
     if (this.gmpPath) {
       this._log.info("uninstallPlugin() - unregistering gmp directory " +
                      this.gmpPath);
       gmpService.removeAndDeletePluginDirectory(this.gmpPath);
     }
     GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_VERSION, this.id);
     GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_ABI, this.id);
     GMPPrefs.reset(GMPPrefs.KEY_PLUGIN_LAST_UPDATE, this.id);
     AddonManagerPrivate.callAddonListeners("onUninstalled", this);
-  },
+  }
 
-  shutdown: function() {
+  shutdown() {
     Preferences.ignore(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_ENABLED,
                                            this._plugin.id),
                        this.onPrefEnabledChanged, this);
     Preferences.ignore(GMPPrefs.getPrefKey(GMPPrefs.KEY_PLUGIN_VERSION,
                                            this._plugin.id),
                        this.onPrefVersionChanged, this);
     if (this._plugin.isEME) {
       Preferences.ignore(GMPPrefs.KEY_EME_ENABLED,
                          this.onPrefEMEGlobalEnabledChanged, this);
       messageManager.removeMessageListener("EMEVideo:ContentMediaKeysRequest", this);
     }
     return this._updateTask;
-  },
+  }
 
-  _arePluginFilesOnDisk: function() {
+  _arePluginFilesOnDisk() {
     let fileExists = function(aGmpPath, aFileName) {
       let f = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
       let path = OS.Path.join(aGmpPath, aFileName);
       f.initWithPath(path);
       return f.exists();
     };
 
     let id = this._plugin.id.substring(4);
@@ -493,19 +494,19 @@ GMPWrapper.prototype = {
       infoName = "manifest.json";
     } else {
       infoName = id + ".info";
     }
 
     return fileExists(this.gmpPath, libName) &&
            fileExists(this.gmpPath, infoName) &&
            (this._plugin.id != EME_ADOBE_ID || fileExists(this.gmpPath, id + ".voucher"));
-  },
+  }
 
-  validate: function() {
+  validate() {
     if (!this.isInstalled) {
       // Not installed -> Valid.
       return {
         installed: false,
         valid: true
       };
     }
 
@@ -521,18 +522,18 @@ GMPWrapper.prototype = {
     }
 
     // Installed -> Check if files are missing.
     let filesOnDisk = this._arePluginFilesOnDisk();
     return {
       installed: true,
       valid: filesOnDisk
     };
-  },
-};
+  }
+}
 
 var GMPProvider = {
   get name() { return "GMPProvider"; },
 
   _plugins: null,
 
   startup: function() {
     configureLogging();
--- a/toolkit/mozapps/extensions/internal/PluginProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/PluginProvider.jsm
@@ -295,75 +295,75 @@ function canDisableFlashProtectedMode(aP
 
 const wrapperMap = new WeakMap();
 let pluginFor = wrapper => wrapperMap.get(wrapper);
 
 /**
  * The PluginWrapper wraps a set of nsIPluginTags to provide the data visible to
  * public callers through the API.
  */
-function PluginWrapper(id, name, description, tags) {
-  wrapperMap.set(this, { id, name, description, tags });
-}
+class PluginWrapper {
+  constructor(id, name, description, tags) {
+    wrapperMap.set(this, { id, name, description, tags });
+  }
 
-PluginWrapper.prototype = {
   get id() {
     return pluginFor(this).id;
-  },
+  }
 
   get type() {
     return "plugin";
-  },
+  }
 
   get name() {
     return pluginFor(this).name;
-  },
+  }
 
   get creator() {
     return null;
-  },
+  }
 
   get description() {
     return pluginFor(this).description.replace(/<\/?[a-z][^>]*>/gi, " ");
-  },
+  }
 
   get version() {
     let { tags: [tag] } = pluginFor(this);
     return tag.version;
-  },
+  }
 
   get homepageURL() {
     let { description } = pluginFor(this);
     if (/<A\s+HREF=[^>]*>/i.test(description))
       return /<A\s+HREF=["']?([^>"'\s]*)/i.exec(description)[1];
     return null;
-  },
+  }
 
   get isActive() {
     let { tags: [tag] } = pluginFor(this);
     return !tag.blocklisted && !tag.disabled;
-  },
+  }
 
   get appDisabled() {
     let { tags: [tag] } = pluginFor(this);
     return tag.blocklisted;
-  },
+  }
 
   get userDisabled() {
     let { tags: [tag] } = pluginFor(this);
     if (tag.disabled)
       return true;
 
     if ((Services.prefs.getBoolPref("plugins.click_to_play") && tag.clicktoplay) ||
         this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE ||
         this.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE)
       return AddonManager.STATE_ASK_TO_ACTIVATE;
 
     return false;
-  },
+  }
 
   set userDisabled(val) {
     let previousVal = this.userDisabled;
     if (val === previousVal)
       return val;
 
     let { tags } = pluginFor(this);
 
@@ -393,31 +393,31 @@ PluginWrapper.prototype = {
     // If the 'userDisabled' value involved AddonManager.STATE_ASK_TO_ACTIVATE,
     // call the onPropertyChanged listeners.
     if (previousVal == AddonManager.STATE_ASK_TO_ACTIVATE ||
         val == AddonManager.STATE_ASK_TO_ACTIVATE) {
       AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["userDisabled"]);
     }
 
     return val;
-  },
+  }
 
   get blocklistState() {
     let { tags: [tag] } = pluginFor(this);
     let bs = Cc["@mozilla.org/extensions/blocklist;1"].
              getService(Ci.nsIBlocklistService);
     return bs.getPluginBlocklistState(tag);
-  },
+  }
 
   get blocklistURL() {
     let { tags: [tag] } = pluginFor(this);
     let bs = Cc["@mozilla.org/extensions/blocklist;1"].
              getService(Ci.nsIBlocklistService);
     return bs.getPluginBlocklistURL(tag);
-  },
+  }
 
   get size() {
     function getDirectorySize(aFile) {
       let size = 0;
       let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
       let entry;
       while ((entry = entries.nextFile)) {
         if (entry.isSymlink() || !entry.isDirectory())
@@ -434,31 +434,31 @@ PluginWrapper.prototype = {
     for (let tag of pluginFor(this).tags) {
       file.initWithPath(tag.fullpath);
       if (file.isDirectory())
         size += getDirectorySize(file);
       else
         size += file.fileSize;
     }
     return size;
-  },
+  }
 
   get pluginLibraries() {
     let libs = [];
     for (let tag of pluginFor(this).tags)
       libs.push(tag.filename);
     return libs;
-  },
+  }
 
   get pluginFullpath() {
     let paths = [];
     for (let tag of pluginFor(this).tags)
       paths.push(tag.fullpath);
     return paths;
-  },
+  }
 
   get pluginMimeTypes() {
     let types = [];
     for (let tag of pluginFor(this).tags) {
       let mimeTypes = tag.getMimeTypes({});
       let mimeDescriptions = tag.getMimeDescriptions({});
       let extensions = tag.getExtensions({});
       for (let i = 0; i < mimeTypes.length; i++) {
@@ -466,25 +466,25 @@ PluginWrapper.prototype = {
         type.type = mimeTypes[i];
         type.description = mimeDescriptions[i];
         type.suffixes = extensions[i];
 
         types.push(type);
       }
     }
     return types;
-  },
+  }
 
   get installDate() {
     let date = 0;
     for (let tag of pluginFor(this).tags) {
       date = Math.max(date, tag.lastModifiedTime);
     }
     return new Date(date);
-  },
+  }
 
   get scope() {
     let { tags: [tag] } = pluginFor(this);
     let path = tag.fullpath;
     // Plugins inside the application directory are in the application scope
     let dir = Services.dirsvc.get("APlugns", Ci.nsIFile);
     if (path.startsWith(dir.path))
       return AddonManager.SCOPE_APPLICATION;
@@ -503,25 +503,25 @@ PluginWrapper.prototype = {
     } catch (e) {
       if (!e.result || e.result != Components.results.NS_ERROR_FAILURE)
         throw e;
       // Do nothing: missing "Home".
     }
 
     // Any other locations are system scope
     return AddonManager.SCOPE_SYSTEM;
-  },
+  }
 
   get pendingOperations() {
     return AddonManager.PENDING_NONE;
-  },
+  }
 
   get operationsRequiringRestart() {
     return AddonManager.OP_NEEDS_RESTART_NONE;
-  },
+  }
 
   get permissions() {
     let { tags: [tag] } = pluginFor(this);
     let permissions = 0;
     if (tag.isEnabledStateLocked) {
       return permissions;
     }
     if (!this.appDisabled) {
@@ -540,61 +540,61 @@ PluginWrapper.prototype = {
         permissions |= AddonManager.PERM_CAN_ASK_TO_ACTIVATE;
       }
 
       if (this.userDisabled !== false && !isCTPBlocklisted) {
         permissions |= AddonManager.PERM_CAN_ENABLE;
       }
     }
     return permissions;
-  },
+  }
 
   get optionsType() {
     if (canDisableFlashProtectedMode(this)) {
       return AddonManager.OPTIONS_TYPE_INLINE;
     }
     return AddonManager.OPTIONS_TYPE_INLINE_INFO;
-  },
+  }
 
   get optionsURL() {
     return "chrome://mozapps/content/extensions/pluginPrefs.xul";
-  },
+  }
 
   get updateDate() {
     return this.installDate;
-  },
+  }
 
   get isCompatible() {
     return true;
-  },
+  }
 
   get isPlatformCompatible() {
     return true;
-  },
+  }
 
   get providesUpdatesSecurely() {
     return true;
-  },
+  }
 
   get foreignInstall() {
     return true;
-  },
+  }
 
-  isCompatibleWith: function(aAppVersion, aPlatformVersion) {
+  isCompatibleWith(aAppVersion, aPlatformVersion) {
     return true;
-  },
+  }
 
-  findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
+  findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) {
     if ("onNoCompatibilityUpdateAvailable" in aListener)
       aListener.onNoCompatibilityUpdateAvailable(this);
     if ("onNoUpdateAvailable" in aListener)
       aListener.onNoUpdateAvailable(this);
     if ("onUpdateFinished" in aListener)
       aListener.onUpdateFinished(this);
   }
-};
+}
 
 AddonManagerPrivate.registerProvider(PluginProvider, [
   new AddonManagerPrivate.AddonType("plugin", URI_EXTENSION_STRINGS,
                                     STRING_TYPE_NAME,
                                     AddonManager.VIEW_TYPE_LIST, 6000,
                                     AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE)
 ]);
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -1,9 +1,9 @@
- /* This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/. */
 
 "use strict";
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
@@ -443,26 +443,23 @@ function writeStringToFile(file, string)
  * directory. The file or directory is moved or copied recursively and if
  * anything fails an attempt is made to rollback the entire operation. The
  * operation may also be rolled back to its original state after it has
  * completed by calling the rollback method.
  *
  * Operations can be chained. Calling move or copy multiple times will remember
  * the whole set and if one fails all of the operations will be rolled back.
  */
-function SafeInstallOperation() {
-  this._installedFiles = [];
-  this._createdDirs = [];
-}
-
-SafeInstallOperation.prototype = {
-  _installedFiles: null,
-  _createdDirs: null,
-
-  _installFile: function(aFile, aTargetDirectory, aCopy) {
+class SafeInstallOperation {
+  constructor() {
+    this._installedFiles = [];
+    this._createdDirs = [];
+  }
+
+  _installFile(aFile, aTargetDirectory, aCopy) {
     let oldFile = aCopy ? null : aFile.clone();
     let newFile = aFile.clone();
     try {
       if (aCopy) {
         newFile.copyTo(aTargetDirectory, null);
         // copyTo does not update the nsIFile with the new.
         newFile = aTargetDirectory.clone();
         newFile.append(aFile.leafName);
@@ -475,19 +472,19 @@ SafeInstallOperation.prototype = {
       }
     }
     catch (e) {
       logger.error("Failed to " + (aCopy ? "copy" : "move") + " file " + aFile.path +
             " to " + aTargetDirectory.path, e);
       throw e;
     }
     this._installedFiles.push({ oldFile: oldFile, newFile: newFile });
-  },
-
-  _installDirectory: function(aDirectory, aTargetDirectory, aCopy) {
+  }
+
+  _installDirectory(aDirectory, aTargetDirectory, aCopy) {
     if (aDirectory.contains(aTargetDirectory)) {
       let err = new Error(`Not installing ${aDirectory} into its own descendent ${aTargetDirectory}`);
       logger.error(err);
       throw err;
     }
 
     let newDir = aTargetDirectory.clone();
     newDir.append(aDirectory.leafName);
@@ -529,19 +526,19 @@ SafeInstallOperation.prototype = {
     catch (e) {
       logger.error("Failed to remove directory " + aDirectory.path, e);
       throw e;
     }
 
     // Note we put the directory move in after all the file moves so the
     // directory is recreated before all the files are moved back
     this._installedFiles.push({ oldFile: aDirectory, newFile: newDir });
-  },
-
-  _installDirEntry: function(aDirEntry, aTargetDirectory, aCopy) {
+  }
+
+  _installDirEntry(aDirEntry, aTargetDirectory, aCopy) {
     let isDir = null;
 
     try {
       isDir = aDirEntry.isDirectory() && !aDirEntry.isSymlink();
     }
     catch (e) {
       // If the file has already gone away then don't worry about it, this can
       // happen on OSX where the resource fork is automatically moved with the
@@ -560,85 +557,85 @@ SafeInstallOperation.prototype = {
       else
         this._installFile(aDirEntry, aTargetDirectory, aCopy);
     }
     catch (e) {
       logger.error("Failure " + (aCopy ? "copying" : "moving") + " " + aDirEntry.path +
             " to " + aTargetDirectory.path);
       throw e;
     }
-  },
+  }
 
   /**
    * Moves a file or directory into a new directory. If an error occurs then all
    * files that have been moved will be moved back to their original location.
    *
    * @param  aFile
    *         The file or directory to be moved.
    * @param  aTargetDirectory
    *         The directory to move into, this is expected to be an empty
    *         directory.
    */
-  moveUnder: function(aFile, aTargetDirectory) {
+  moveUnder(aFile, aTargetDirectory) {
     try {
       this._installDirEntry(aFile, aTargetDirectory, false);
     }
     catch (e) {
       this.rollback();
       throw e;
     }
-  },
+  }
 
   /**
    * Renames a file to a new location.  If an error occurs then all
    * files that have been moved will be moved back to their original location.
    *
    * @param  aOldLocation
    *         The old location of the file.
    * @param  aNewLocation
    *         The new location of the file.
    */
-  moveTo: function(aOldLocation, aNewLocation) {
+  moveTo(aOldLocation, aNewLocation) {
     try {
       let oldFile = aOldLocation.clone(), newFile = aNewLocation.clone();
       oldFile.moveTo(newFile.parent, newFile.leafName);
       this._installedFiles.push({ oldFile: oldFile, newFile: newFile, isMoveTo: true});
     }
     catch (e) {
       this.rollback();
       throw e;
     }
-  },
+  }
 
   /**
    * Copies a file or directory into a new directory. If an error occurs then
    * all new files that have been created will be removed.
    *
    * @param  aFile
    *         The file or directory to be copied.
    * @param  aTargetDirectory
    *         The directory to copy into, this is expected to be an empty
    *         directory.
    */
-  copy: function(aFile, aTargetDirectory) {
+  copy(aFile, aTargetDirectory) {
     try {
       this._installDirEntry(aFile, aTargetDirectory, true);
     }
     catch (e) {
       this.rollback();
       throw e;
     }
-  },
+  }
 
   /**
    * Rolls back all the moves that this operation performed. If an exception
    * occurs here then both old and new directories are left in an indeterminate
    * state
    */
-  rollback: function() {
+  rollback() {
     while (this._installedFiles.length > 0) {
       let move = this._installedFiles.pop();
       if (move.isMoveTo) {
         move.newFile.moveTo(move.oldDir.parent, move.oldDir.leafName);
       }
       else if (move.newFile.isDirectory() && !move.newFile.isSymlink()) {
         let oldDir = move.oldFile.parent.clone();
         oldDir.append(move.oldFile.leafName);
@@ -651,17 +648,17 @@ SafeInstallOperation.prototype = {
       else {
         move.newFile.moveTo(move.oldFile.parent, null);
       }
     }
 
     while (this._createdDirs.length > 0)
       recursiveRemove(this._createdDirs.pop());
   }
-};
+}
 
 /**
  * Sets the userDisabled and softDisabled properties of an add-on based on what
  * values those properties had for a previous instance of the add-on. The
  * previous instance may be a previous install or in the case of an application
  * version change the same add-on.
  *
  * NOTE: this may modify aNewAddon in place; callers should save the database if
@@ -2104,49 +2101,52 @@ function recordAddonTelemetry(aAddon) {
       XPIProvider.setTelemetry(aAddon.id, "creator", locale.creator);
   }
 }
 
 /**
  * The on-disk state of an individual XPI, created from an Object
  * as stored in the 'extensions.xpiState' pref.
  */
-function XPIState(saved) {
-  for (let [short, long] of XPIState.prototype.fields) {
-    if (short in saved) {
-      this[long] = saved[short];
-    }
-  }
-}
-
-XPIState.prototype = {
-  fields: [['d', 'descriptor'],
-           ['e', 'enabled'],
-           ['v', 'version'],
-           ['st', 'scanTime'],
-           ['mt', 'manifestTime']],
+class XPIState {
+  constructor(saved) {
+    for (let [short, long] of XPIState.fields) {
+      if (short in saved) {
+        this[long] = saved[short];
+      }
+    }
+  }
+
+  static get fields() {
+    return [['d', 'descriptor'],
+            ['e', 'enabled'],
+            ['v', 'version'],
+            ['st', 'scanTime'],
+            ['mt', 'manifestTime']];
+  }
+
   /**
    * Return the last modified time, based on enabled/disabled
    */
   get mtime() {
     if (!this.enabled && ('manifestTime' in this) && this.manifestTime > this.scanTime) {
       return this.manifestTime;
     }
     return this.scanTime;
-  },
+  }
 
   toJSON() {
     let json = {};
-    for (let [short, long] of XPIState.prototype.fields) {
+    for (let [short, long] of XPIState.fields) {
       if (long in this) {
         json[short] = this[long];
       }
     }
     return json;
-  },
+  }
 
   /**
    * Update the last modified time for an add-on on disk.
    * @param aFile: nsIFile path of the add-on.
    * @param aId: The add-on ID.
    * @return True if the time stamp has changed.
    */
   getModTime(aFile, aId) {
@@ -2191,17 +2191,17 @@ XPIState.prototype = {
         changed = true;
         this.scanTime = 0;
       }
     }
     // Record duration of file-modified check
     XPIProvider.setTelemetry(aId, "scan_MS", Math.round(Cu.now() - scanStarted));
 
     return changed;
-  },
+  }
 
   /**
    * Update the XPIState to match an XPIDatabase entry; if 'enabled' is changed to true,
    * update the last-modified time. This should probably be made async, but for now we
    * don't want to maintain parallel sync and async versions of the scan.
    * Caller is responsible for doing XPIStates.save() if necessary.
    * @param aDBAddon The DBAddonInternal for this add-on.
    * @param aUpdated The add-on was updated, so we must record new modified time.
@@ -2218,18 +2218,18 @@ XPIState.prototype = {
     // XXX Eventually also copy bootstrap, etc.
     if (aUpdated || mustGetMod) {
       this.getModTime(new nsIFile(this.descriptor), aDBAddon.id);
       if (this.scanTime != aDBAddon.updateDate) {
         aDBAddon.updateDate = this.scanTime;
         XPIDatabase.saveChanges();
       }
     }
-  },
-};
+  }
+}
 
 // Constructor for an ES6 Map that knows how to convert itself into a
 // regular object for toJSON().
 function SerializableMap() {
   let m = new Map();
   m.toJSON = function() {
     let out = {}
     for (let [key, val] of m) {
@@ -6866,98 +6866,93 @@ AddonInstallWrapper.prototype = {
       return installFor(this)[aProp];
     },
     enumerable: true,
   });
 });
 
 /**
  * Creates a new update checker.
- *
- * @param  aAddon
- *         The add-on to check for updates
- * @param  aListener
- *         An UpdateListener to notify of updates
- * @param  aReason
- *         The reason for the update check
- * @param  aAppVersion
- *         An optional application version to check for updates for
- * @param  aPlatformVersion
- *         An optional platform version to check for updates for
- * @throws if the aListener or aReason arguments are not valid
  */
-function UpdateChecker(aAddon, aListener, aReason, aAppVersion, aPlatformVersion) {
-  if (!aListener || !aReason)
-    throw Cr.NS_ERROR_INVALID_ARG;
-
-  Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm");
-
-  this.addon = aAddon;
-  aAddon._updateCheck = this;
-  XPIProvider.doing(this);
-  this.listener = aListener;
-  this.appVersion = aAppVersion;
-  this.platformVersion = aPlatformVersion;
-  this.syncCompatibility = (aReason == AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
-
-  let updateURL = aAddon.updateURL;
-  if (!updateURL) {
-    if (aReason == AddonManager.UPDATE_WHEN_PERIODIC_UPDATE &&
-        Services.prefs.getPrefType(PREF_EM_UPDATE_BACKGROUND_URL) == Services.prefs.PREF_STRING) {
-      updateURL = Services.prefs.getCharPref(PREF_EM_UPDATE_BACKGROUND_URL);
-    } else {
-      updateURL = Services.prefs.getCharPref(PREF_EM_UPDATE_URL);
-    }
-  }
-
-  const UPDATE_TYPE_COMPATIBILITY = 32;
-  const UPDATE_TYPE_NEWVERSION = 64;
-
-  aReason |= UPDATE_TYPE_COMPATIBILITY;
-  if ("onUpdateAvailable" in this.listener)
-    aReason |= UPDATE_TYPE_NEWVERSION;
-
-  let url = escapeAddonURI(aAddon, updateURL, aReason, aAppVersion);
-  this._parser = AddonUpdateChecker.checkForUpdates(aAddon.id, aAddon.updateKey,
-                                                    url, this);
-}
-
-UpdateChecker.prototype = {
-  addon: null,
-  listener: null,
-  appVersion: null,
-  platformVersion: null,
-  syncCompatibility: null,
+class UpdateChecker {
+  /**
+   * @param  aAddon
+   *         The add-on to check for updates
+   * @param  aListener
+   *         An UpdateListener to notify of updates
+   * @param  aReason
+   *         The reason for the update check
+   * @param  aAppVersion
+   *         An optional application version to check for updates for
+   * @param  aPlatformVersion
+   *         An optional platform version to check for updates for
+   * @throws if the aListener or aReason arguments are not valid
+   */
+  constructor(aAddon, aListener, aReason, aAppVersion, aPlatformVersion) {
+    if (!aListener || !aReason)
+      throw Cr.NS_ERROR_INVALID_ARG;
+
+    Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm");
+
+    this.addon = aAddon;
+    aAddon._updateCheck = this;
+    XPIProvider.doing(this);
+    this.listener = aListener;
+    this.appVersion = aAppVersion;
+    this.platformVersion = aPlatformVersion;
+    this.syncCompatibility = (aReason == AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
+
+    let updateURL = aAddon.updateURL;
+    if (!updateURL) {
+      if (aReason == AddonManager.UPDATE_WHEN_PERIODIC_UPDATE &&
+          Services.prefs.getPrefType(PREF_EM_UPDATE_BACKGROUND_URL) == Services.prefs.PREF_STRING) {
+        updateURL = Services.prefs.getCharPref(PREF_EM_UPDATE_BACKGROUND_URL);
+      } else {
+        updateURL = Services.prefs.getCharPref(PREF_EM_UPDATE_URL);
+      }
+    }
+
+    const UPDATE_TYPE_COMPATIBILITY = 32;
+    const UPDATE_TYPE_NEWVERSION = 64;
+
+    aReason |= UPDATE_TYPE_COMPATIBILITY;
+    if ("onUpdateAvailable" in this.listener)
+      aReason |= UPDATE_TYPE_NEWVERSION;
+
+    let url = escapeAddonURI(aAddon, updateURL, aReason, aAppVersion);
+    this._parser = AddonUpdateChecker.checkForUpdates(aAddon.id, aAddon.updateKey,
+                                                      url, this);
+  }
 
   /**
    * Calls a method on the listener passing any number of arguments and
    * consuming any exceptions.
    *
    * @param  aMethod
    *         The method to call on the listener
    */
-  callListener: function(aMethod, ...aArgs) {
+  callListener(aMethod, ...aArgs) {
     if (!(aMethod in this.listener))
       return;
 
     try {
       this.listener[aMethod].apply(this.listener, aArgs);
     }
     catch (e) {
       logger.warn("Exception calling UpdateListener method " + aMethod, e);
     }
-  },
+  }
 
   /**
    * Called when AddonUpdateChecker completes the update check
    *
    * @param  updates
    *         The list of update details for the add-on
    */
-  onUpdateCheckComplete: function(aUpdates) {
+  onUpdateCheckComplete(aUpdates) {
     XPIProvider.done(this.addon._updateCheck);
     this.addon._updateCheck = null;
     let AUC = AddonUpdateChecker;
 
     let ignoreMaxVersion = false;
     let ignoreStrictCompat = false;
     if (!AddonManager.checkCompatibility) {
       ignoreMaxVersion = true;
@@ -7043,93 +7038,96 @@ UpdateChecker.prototype = {
 
       createUpdate(aInstall => {
         sendUpdateAvailableMessages(this, aInstall);
       }, this.addon, update);
     }
     else {
       sendUpdateAvailableMessages(this, null);
     }
-  },
+  }
 
   /**
    * Called when AddonUpdateChecker fails the update check
    *
    * @param  aError
    *         An error status
    */
-  onUpdateCheckError: function(aError) {
+  onUpdateCheckError(aError) {
     XPIProvider.done(this.addon._updateCheck);
     this.addon._updateCheck = null;
     this.callListener("onNoCompatibilityUpdateAvailable", this.addon.wrapper);
     this.callListener("onNoUpdateAvailable", this.addon.wrapper);
     this.callListener("onUpdateFinished", this.addon.wrapper, aError);
-  },
+  }
 
   /**
    * Called to cancel an in-progress update check
    */
-  cancel: function() {
+  cancel() {
     let parser = this._parser;
     if (parser) {
       this._parser = null;
       // This will call back to onUpdateCheckError with a CANCELLED error
       parser.cancel();
     }
   }
-};
+}
 
 /**
  * The AddonInternal is an internal only representation of add-ons. It may
  * have come from the database (see DBAddonInternal in XPIProviderUtils.jsm)
  * or an install manifest.
  */
-function AddonInternal() {
-  this._hasResourceCache = new Map();
-
-  XPCOMUtils.defineLazyGetter(this, "wrapper", () => {
-    return new AddonWrapper(this);
-  });
-}
-
-AddonInternal.prototype = {
-  _selectedLocale: null,
-  _hasResourceCache: null,
-  active: false,
-  visible: false,
-  userDisabled: false,
-  appDisabled: false,
-  softDisabled: false,
-  sourceURI: null,
-  releaseNotesURI: null,
-  foreignInstall: false,
-  seen: true,
-  skinnable: false,
-
+class AddonInternal {
+  constructor() {
+    this._hasResourceCache = new Map();
+
+    XPCOMUtils.defineLazyGetter(this, "wrapper", () => {
+      return new AddonWrapper(this);
+    });
+
+    this._selectedLocale = null;
+    this.active = false;
+    this.visible = false;
+    this.userDisabled = false;
+    this.appDisabled = false;
+    this.softDisabled = false;
+    this.sourceURI = null;
+    this.releaseNotesURI = null;
+    this.foreignInstall = false;
+    this.seen = true;
+    this.skinnable = false;
+  }
   /**
    * @property {Array<string>} dependencies
    *   An array of bootstrapped add-on IDs on which this add-on depends.
    *   The add-on will remain appDisabled if any of the dependent
    *   add-ons is not installed and enabled.
    */
-  dependencies: Object.freeze([]),
-  hasEmbeddedWebExtension: false,
+  static get dependencies() {
+    return Object.freeze([]);
+  }
+
+  static get hasEmbeddedWebExtension() {
+    return false;
+  }
 
   get selectedLocale() {
     if (this._selectedLocale)
       return this._selectedLocale;
     let locale = Locale.findClosestLocale(this.locales);
     this._selectedLocale = locale ? locale : this.defaultLocale;
     return this._selectedLocale;
-  },
+  }
 
   get providesUpdatesSecurely() {
     return !!(this.updateKey || !this.updateURL ||
               this.updateURL.substring(0, 6) == "https:");
-  },
+  }
 
   get isCorrectlySigned() {
     switch (this._installLocation.name) {
       case KEY_APP_SYSTEM_ADDONS:
         // System add-ons must be signed by the system key.
         return this.signedState == AddonManager.SIGNEDSTATE_SYSTEM
 
       case KEY_APP_SYSTEM_DEFAULTS:
@@ -7145,25 +7143,25 @@ AddonInternal.prototype = {
         if (Services.appinfo.OS != "Darwin")
           return true;
         break;
     }
 
     if (this.signedState === AddonManager.SIGNEDSTATE_NOT_REQUIRED)
       return true;
     return this.signedState > AddonManager.SIGNEDSTATE_MISSING;
-  },
+  }
 
   get isCompatible() {
     return this.isCompatibleWith();
-  },
+  }
 
   get disabled() {
     return (this.userDisabled || this.appDisabled || this.softDisabled);
-  },
+  }
 
   get isPlatformCompatible() {
     if (this.targetPlatforms.length == 0)
       return true;
 
     let matchedOS = false;
 
     // If any targetPlatform matches the OS and contains an ABI then we will
@@ -7196,19 +7194,19 @@ AddonInternal.prototype = {
                     + JSON.stringify(this.targetPlatforms);
       logger.error(message, e);
       AddonManagerPrivate.recordException("XPI", message, e);
       // don't trust this add-on
       return false;
     }
 
     return matchedOS && !needsABI;
-  },
-
-  isCompatibleWith: function(aAppVersion, aPlatformVersion) {
+  }
+
+  isCompatibleWith(aAppVersion, aPlatformVersion) {
     let app = this.matchingTargetApplication;
     if (!app)
       return false;
 
     // set reasonable defaults for minVersion and maxVersion
     let minVersion = app.minVersion || "0";
     let maxVersion = app.maxVersion || "*";
 
@@ -7251,92 +7249,92 @@ AddonInternal.prototype = {
           Services.vc.compare(minCompatVersion, maxVersion) > 0)
         return false;
 
       return Services.vc.compare(version, minVersion) >= 0;
     }
 
     return (Services.vc.compare(version, minVersion) >= 0) &&
            (Services.vc.compare(version, maxVersion) <= 0)
-  },
+  }
 
   get matchingTargetApplication() {
     let app = null;
     for (let targetApp of this.targetApplications) {
       if (targetApp.id == Services.appinfo.ID)
         return targetApp;
       if (targetApp.id == TOOLKIT_ID)
         app = targetApp;
     }
     return app;
-  },
+  }
 
   get blocklistState() {
     let staticItem = findMatchingStaticBlocklistItem(this);
     if (staticItem)
       return staticItem.level;
 
     return Blocklist.getAddonBlocklistState(this.wrapper);
-  },
+  }
 
   get blocklistURL() {
     let staticItem = findMatchingStaticBlocklistItem(this);
     if (staticItem) {
       let url = Services.urlFormatter.formatURLPref("extensions.blocklist.itemURL");
       return url.replace(/%blockID%/g, staticItem.blockID);
     }
 
     return Blocklist.getAddonBlocklistURL(this.wrapper);
-  },
-
-  applyCompatibilityUpdate: function(aUpdate, aSyncCompatibility) {
+  }
+
+  applyCompatibilityUpdate(aUpdate, aSyncCompatibility) {
     for (let targetApp of this.targetApplications) {
       for (let updateTarget of aUpdate.targetApplications) {
         if (targetApp.id == updateTarget.id && (aSyncCompatibility ||
             Services.vc.compare(targetApp.maxVersion, updateTarget.maxVersion) < 0)) {
           targetApp.minVersion = updateTarget.minVersion;
           targetApp.maxVersion = updateTarget.maxVersion;
         }
       }
     }
     if (aUpdate.multiprocessCompatible !== undefined)
       this.multiprocessCompatible = aUpdate.multiprocessCompatible;
     this.appDisabled = !isUsableAddon(this);
-  },
+  }
 
   /**
    * getDataDirectory tries to execute the callback with two arguments:
    * 1) the path of the data directory within the profile,
    * 2) any exception generated from trying to build it.
    */
-  getDataDirectory: function(callback) {
+  getDataDirectory(callback) {
     let parentPath = OS.Path.join(OS.Constants.Path.profileDir, "extension-data");
     let dirPath = OS.Path.join(parentPath, this.id);
 
     Task.spawn(function*() {
       yield OS.File.makeDir(parentPath, {ignoreExisting: true});
       yield OS.File.makeDir(dirPath, {ignoreExisting: true});
     }).then(() => callback(dirPath, null),
             e => callback(dirPath, e));
-  },
+  }
 
   /**
    * toJSON is called by JSON.stringify in order to create a filtered version
    * of this object to be serialized to a JSON file. A new object is returned
    * with copies of all non-private properties. Functions, getters and setters
    * are not copied.
    *
    * @param  aKey
    *         The key that this object is being serialized as in the JSON.
    *         Unused here since this is always the main object serialized
    *
    * @return an object containing copies of the properties of this object
    *         ignoring private properties, functions, getters and setters
    */
-  toJSON: function(aKey) {
+  toJSON(aKey) {
     let obj = {};
     for (let prop in this) {
       // Ignore the wrapper property
       if (prop == "wrapper")
         continue;
 
       // Ignore private properties
       if (prop.substring(0, 1) == "_")
@@ -7353,39 +7351,39 @@ AddonInternal.prototype = {
       // Ignore functions
       if (typeof this[prop] == "function")
         continue;
 
       obj[prop] = this[prop];
     }
 
     return obj;
-  },
+  }
 
   /**
    * When an add-on install is pending its metadata will be cached in a file.
    * This method reads particular properties of that metadata that may be newer
    * than that in the install manifest, like compatibility information.
    *
    * @param  aObj
    *         A JS object containing the cached metadata
    */
-  importMetadata: function(aObj) {
+  importMetadata(aObj) {
     for (let prop of PENDING_INSTALL_METADATA) {
       if (!(prop in aObj))
         continue;
 
       this[prop] = aObj[prop];
     }
 
     // Compatibility info may have changed so update appDisabled
     this.appDisabled = !isUsableAddon(this);
-  },
-
-  permissions: function() {
+  }
+
+  permissions() {
     let permissions = 0;
 
     // Add-ons that aren't installed cannot be modified in any way
     if (!(this.inDatabase))
       return permissions;
 
     if (!this.appDisabled) {
       if (this.userDisabled || this.softDisabled) {
@@ -7408,60 +7406,60 @@ AddonInternal.prototype = {
           !this._installLocation.isLinkedAddon(this.id) && !isSystem) {
         permissions |= AddonManager.PERM_CAN_UPGRADE;
       }
 
       permissions |= AddonManager.PERM_CAN_UNINSTALL;
     }
 
     return permissions;
-  },
-};
+  }
+}
 
 /**
  * The AddonWrapper wraps an Addon to provide the data visible to consumers of
  * the public API.
  */
-function AddonWrapper(aAddon) {
-  wrapperMap.set(this, aAddon);
-}
-
-AddonWrapper.prototype = {
+class AddonWrapper {
+  constructor(aAddon) {
+    wrapperMap.set(this, aAddon);
+  }
+
   get __AddonInternal__() {
     return AppConstants.DEBUG ? addonFor(this) : undefined;
-  },
+  }
 
   get seen() {
     return addonFor(this).seen;
-  },
+  }
 
   get hasEmbeddedWebExtension() {
     return addonFor(this).hasEmbeddedWebExtension;
-  },
-
-  markAsSeen: function() {
+  }
+
+  markAsSeen() {
     addonFor(this).seen = true;
     XPIDatabase.saveChanges();
-  },
+  }
 
   get type() {
     return getExternalType(addonFor(this).type);
-  },
+  }
 
   get isWebExtension() {
     return addonFor(this).type == "webextension";
-  },
+  }
 
   get temporarilyInstalled() {
     return addonFor(this)._installLocation == TemporaryInstallLocation;
-  },
+  }
 
   get aboutURL() {
     return this.isActive ? addonFor(this)["aboutURL"] : null;
-  },
+  }
 
   get optionsURL() {
     if (!this.isActive) {
       return null;
     }
 
     let addon = addonFor(this);
     if (addon.optionsURL) {
@@ -7478,17 +7476,17 @@ AddonWrapper.prototype = {
       }
       return addon.optionsURL;
     }
 
     if (this.hasResource("options.xul"))
       return this.getResourceURI("options.xul").spec;
 
     return null;
-  },
+  }
 
   get optionsType() {
     if (!this.isActive)
       return null;
 
     let addon = addonFor(this);
     let hasOptionsXUL = this.hasResource("options.xul");
     let hasOptionsURL = !!this.optionsURL;
@@ -7508,25 +7506,25 @@ AddonWrapper.prototype = {
 
     if (hasOptionsXUL)
       return AddonManager.OPTIONS_TYPE_INLINE;
 
     if (hasOptionsURL)
       return AddonManager.OPTIONS_TYPE_DIALOG;
 
     return null;
-  },
+  }
 
   get iconURL() {
     return AddonManager.getPreferredIconURL(this, 48);
-  },
+  }
 
   get icon64URL() {
     return AddonManager.getPreferredIconURL(this, 64);
-  },
+  }
 
   get icons() {
     let addon = addonFor(this);
     let icons = {};
 
     if (addon._repositoryAddon) {
       for (let size in addon._repositoryAddon.icons) {
         icons[size] = addon._repositoryAddon.icons[size];
@@ -7553,38 +7551,39 @@ AddonWrapper.prototype = {
     }
 
     if (this.isActive && addon.icon64URL) {
       icons[64] = addon.icon64URL;
     }
 
     Object.freeze(icons);
     return icons;
-  },
+  }
 
   get screenshots() {
     let addon = addonFor(this);
     let repositoryAddon = addon._repositoryAddon;
     if (repositoryAddon && ("screenshots" in repositoryAddon)) {
       let repositoryScreenshots = repositoryAddon.screenshots;
       if (repositoryScreenshots && repositoryScreenshots.length > 0)
         return repositoryScreenshots;
     }
 
     if (addon.type == "theme" && this.hasResource("preview.png")) {
       let url = this.getResourceURI("preview.png").spec;
       return [new AddonManagerPrivate.AddonScreenshot(url)];
     }
 
     return null;
-  },
+  }
 
   get applyBackgroundUpdates() {
     return addonFor(this).applyBackgroundUpdates;
-  },
+  }
+
   set applyBackgroundUpdates(val) {
     let addon = addonFor(this);
     if (this.type == "experiment") {
       logger.warn("Setting applyBackgroundUpdates on an experiment is not supported.");
       return addon.applyBackgroundUpdates;
     }
 
     if (val != AddonManager.AUTOUPDATE_DEFAULT &&
@@ -7598,50 +7597,50 @@ AddonWrapper.prototype = {
       return val;
 
     XPIDatabase.setAddonProperties(addon, {
       applyBackgroundUpdates: val
     });
     AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["applyBackgroundUpdates"]);
 
     return val;
-  },
+  }
 
   set syncGUID(val) {
     let addon = addonFor(this);
     if (addon.syncGUID == val)
       return val;
 
     if (addon.inDatabase)
       XPIDatabase.setAddonSyncGUID(addon, val);
 
     addon.syncGUID = val;
 
     return val;
-  },
+  }
 
   get install() {
     let addon = addonFor(this);
     if (!("_install" in addon) || !addon._install)
       return null;
     return addon._install.wrapper;
-  },
+  }
 
   get pendingUpgrade() {
     let addon = addonFor(this);
     return addon.pendingUpgrade ? addon.pendingUpgrade.wrapper : null;
-  },
+  }
 
   get scope() {
     let addon = addonFor(this);
     if (addon._installLocation)
       return addon._installLocation.scope;
 
     return AddonManager.SCOPE_PROFILE;
-  },
+  }
 
   get pendingOperations() {
     let addon = addonFor(this);
     let pending = 0;
     if (!(addon.inDatabase)) {
       // Add-on is pending install if there is no associated install (shouldn't
       // happen here) or if the install is in the process of or has successfully
       // completed the install. If an add-on is pending install then we ignore
@@ -7660,54 +7659,55 @@ AddonWrapper.prototype = {
       pending |= AddonManager.PENDING_DISABLE;
     else if (!addon.active && !addon.disabled)
       pending |= AddonManager.PENDING_ENABLE;
 
     if (addon.pendingUpgrade)
       pending |= AddonManager.PENDING_UPGRADE;
 
     return pending;
-  },
+  }
 
   get operationsRequiringRestart() {
     let addon = addonFor(this);
     let ops = 0;
     if (XPIProvider.installRequiresRestart(addon))
       ops |= AddonManager.OP_NEEDS_RESTART_INSTALL;
     if (XPIProvider.uninstallRequiresRestart(addon))
       ops |= AddonManager.OP_NEEDS_RESTART_UNINSTALL;
     if (XPIProvider.enableRequiresRestart(addon))
       ops |= AddonManager.OP_NEEDS_RESTART_ENABLE;
     if (XPIProvider.disableRequiresRestart(addon))
       ops |= AddonManager.OP_NEEDS_RESTART_DISABLE;
 
     return ops;
-  },
+  }
 
   get isDebuggable() {
     return this.isActive && addonFor(this).bootstrap;
-  },
+  }
 
   get permissions() {
     return addonFor(this).permissions();
-  },
+  }
 
   get isActive() {
     let addon = addonFor(this);
     if (!addon.active)
       return false;
     if (!Services.appinfo.inSafeMode)
       return true;
     return addon.bootstrap && canRunInSafeMode(addon);
-  },
+  }
 
   get userDisabled() {
     let addon = addonFor(this);
     return addon.softDisabled || addon.userDisabled;
-  },
+  }
+
   set userDisabled(val) {
     let addon = addonFor(this);
     if (val == this.userDisabled) {
       return val;
     }
 
     if (addon.inDatabase) {
       if (addon.type == "theme" && val) {
@@ -7727,17 +7727,17 @@ AddonWrapper.prototype = {
     else {
       addon.userDisabled = val;
       // When enabling remove the softDisabled flag
       if (!val)
         addon.softDisabled = false;
     }
 
     return val;
-  },
+  }
 
   set softDisabled(val) {
     let addon = addonFor(this);
     if (val == addon.softDisabled)
       return val;
 
     if (addon.inDatabase) {
       // When softDisabling a theme just enable the active theme
@@ -7751,81 +7751,81 @@ AddonWrapper.prototype = {
       }
     }
     else if (!addon.userDisabled) {
       // Only set softDisabled if not already disabled
       addon.softDisabled = val;
     }
 
     return val;
-  },
+  }
 
   get hidden() {
     let addon = addonFor(this);
     if (addon._installLocation.name == KEY_APP_TEMPORARY)
       return false;
 
     return (addon._installLocation.name == KEY_APP_SYSTEM_DEFAULTS ||
             addon._installLocation.name == KEY_APP_SYSTEM_ADDONS);
-  },
+  }
 
   get isSystem() {
     let addon = addonFor(this);
     return (addon._installLocation.name == KEY_APP_SYSTEM_DEFAULTS ||
             addon._installLocation.name == KEY_APP_SYSTEM_ADDONS);
-  },
+  }
 
   // Returns true if Firefox Sync should sync this addon. Only non-hotfixes
   // directly in the profile are considered syncable.
   get isSyncable() {
     let addon = addonFor(this);
     let hotfixID = Preferences.get(PREF_EM_HOTFIX_ID, undefined);
     if (hotfixID && hotfixID == addon.id) {
       return false;
     }
     return (addon._installLocation.name == KEY_APP_PROFILE);
-  },
-
-  isCompatibleWith: function(aAppVersion, aPlatformVersion) {
+  }
+
+  isCompatibleWith(aAppVersion, aPlatformVersion) {
     return addonFor(this).isCompatibleWith(aAppVersion, aPlatformVersion);
-  },
-
-  uninstall: function(alwaysAllowUndo) {
+  }
+
+  uninstall(alwaysAllowUndo) {
     let addon = addonFor(this);
     XPIProvider.uninstallAddon(addon, alwaysAllowUndo);
-  },
-
-  cancelUninstall: function() {
+  }
+
+  cancelUninstall() {
     let addon = addonFor(this);
     XPIProvider.cancelUninstallAddon(addon);
-  },
-
-  findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
+  }
+
+  findUpdates(aListener, aReason, aAppVersion, aPlatformVersion) {
     // Short-circuit updates for experiments because updates are handled
     // through the Experiments Manager.
     if (this.type == "experiment") {
       AddonManagerPrivate.callNoUpdateListeners(this, aListener, aReason,
                                                 aAppVersion, aPlatformVersion);
       return;
     }
 
     new UpdateChecker(addonFor(this), aListener, aReason, aAppVersion, aPlatformVersion);
-  },
+  }
 
   // Returns true if there was an update in progress, false if there was no update to cancel
-  cancelUpdate: function() {
+  cancelUpdate() {
     let addon = addonFor(this);
     if (addon._updateCheck) {
       addon._updateCheck.cancel();
       return true;
     }
     return false;
-  },
-
-  hasResource: function(aPath) {
+  }
+
+  hasResource(aPath) {
     let addon = addonFor(this);
     if (addon._hasResourceCache.has(aPath))
       return addon._hasResourceCache.get(aPath);
 
     let bundle = addon._sourceBundle.clone();
 
     // Bundle may not exist any more if the addon has just been uninstalled,
     // but explicitly first checking .exists() results in unneeded file I/O.
@@ -7854,95 +7854,94 @@ AddonWrapper.prototype = {
     }
     catch (e) {
       addon._hasResourceCache.set(aPath, false);
       return false;
     }
     finally {
       zipReader.close();
     }
-  },
+  }
 
   /**
    * Reloads the add-on.
    *
    * For temporarily installed add-ons, this uninstalls and re-installs the
    * add-on. Otherwise, the addon is disabled and then re-enabled, and the cache
    * is flushed.
    *
    * @return Promise
    */
-  reload: function() {
+  reload() {
     return new Promise((resolve) => {
       const addon = addonFor(this);
 
       logger.debug(`reloading add-on ${addon.id}`);
 
       if (!this.temporarilyInstalled) {
         let addonFile = addon.getResourceURI;
         XPIProvider.updateAddonDisabledState(addon, true);
         Services.obs.notifyObservers(addonFile, "flush-cache-entry", null);
         XPIProvider.updateAddonDisabledState(addon, false)
         resolve();
       } else {
         // This function supports re-installing an existing add-on.
         resolve(AddonManager.installTemporaryAddon(addon._sourceBundle));
       }
     });
-  },
+  }
 
   /**
    * Returns a URI to the selected resource or to the add-on bundle if aPath
    * is null. URIs to the bundle will always be file: URIs. URIs to resources
    * will be file: URIs if the add-on is unpacked or jar: URIs if the add-on is
    * still an XPI file.
    *
    * @param  aPath
    *         The path in the add-on to get the URI for or null to get a URI to
    *         the file or directory the add-on is installed as.
    * @return an nsIURI
    */
-  getResourceURI: function(aPath) {
+  getResourceURI(aPath) {
     let addon = addonFor(this);
     if (!aPath)
       return NetUtil.newURI(addon._sourceBundle);
 
     return getURIForResourceInFile(addon._sourceBundle, aPath);
   }
-};
+}
 
 /**
  * The PrivateWrapper is used to expose certain functionality only when being
  * called with the add-on instanceID, disallowing other add-ons to access it.
  */
-function PrivateWrapper(aAddon) {
-  AddonWrapper.call(this, aAddon);
-}
-
-PrivateWrapper.prototype = Object.create(AddonWrapper.prototype);
-Object.assign(PrivateWrapper.prototype, {
+class PrivateWrapper {
+  constructor(aAddon) {
+    AddonWrapper.call(this, aAddon);
+  }
+
   addonId() {
     return this.id;
-  },
+  }
 
   /**
    * Retrieves the preferred global context to be used from the
    * add-on debugging window.
    *
    * @returns  global
    *         The object set as global context. Must be a window object.
    */
   getDebugGlobal(global) {
     let activeAddon = XPIProvider.activeAddons.get(this.id);
     if (activeAddon) {
       return activeAddon.debugGlobal;
     }
 
     return null;
-  },
+  }
 
   /**
    * Defines a global context to be used in the console
    * of the add-on debugging window.
    *
    * @param  global
    *         The object to set as global context. Must be a window object.
    */
@@ -7964,17 +7963,17 @@ Object.assign(PrivateWrapper.prototype, 
         if (globalChanged) {
           AddonManagerPrivate.callAddonListeners("onPropertyChanged",
                                                  addonFor(this),
                                                  ["debugGlobal"]);
         }
       }
     }
   }
-});
+}
 
 function chooseValue(aAddon, aObj, aProp) {
   let repositoryAddon = aAddon._repositoryAddon;
   let objValue = aObj[aProp];
 
   if (repositoryAddon && (aProp in repositoryAddon) &&
       (objValue === undefined || objValue === null)) {
     return [repositoryAddon[aProp], true];
@@ -8109,58 +8108,56 @@ PROP_LOCALE_MULTI.forEach(function(aProp
     return results;
   });
 });
 
 /**
  * An object which identifies a directory install location for add-ons. The
  * location consists of a directory which contains the add-ons installed in the
  * location.
- *
- * Each add-on installed in the location is either a directory containing the
- * add-on's files or a text file containing an absolute path to the directory
- * containing the add-ons files. The directory or text file must have the same
- * name as the add-on's ID.
- *
- * @param  aName
- *         The string identifier for the install location
- * @param  aDirectory
- *         The nsIFile directory for the install location
- * @param  aScope
- *         The scope of add-ons installed in this location
  */
-function DirectoryInstallLocation(aName, aDirectory, aScope) {
-  this._name = aName;
-  this.locked = true;
-  this._directory = aDirectory;
-  this._scope = aScope
-  this._IDToFileMap = {};
-  this._linkedAddons = [];
-
-  if (!aDirectory || !aDirectory.exists())
-    return;
-  if (!aDirectory.isDirectory())
-    throw new Error("Location must be a directory.");
-
-  this._readAddons();
-}
-
-DirectoryInstallLocation.prototype = {
-  _name       : "",
-  _directory   : null,
-  _IDToFileMap : null,  // mapping from add-on ID to nsIFile
+class DirectoryInstallLocation {
+
+  /**
+   * Each add-on installed in the location is either a directory containing the
+   * add-on's files or a text file containing an absolute path to the directory
+   * containing the add-ons files. The directory or text file must have the same
+   * name as the add-on's ID.
+   *
+   * @param  aName
+   *         The string identifier for the install location
+   * @param  aDirectory
+   *         The nsIFile directory for the install location
+   * @param  aScope
+   *         The scope of add-ons installed in this location
+   */
+  constructor(aName, aDirectory, aScope) {
+    this._name = aName;
+    this.locked = true;
+    this._directory = aDirectory;
+    this._scope = aScope
+    this._IDToFileMap = {}; // mapping from add-on ID to nsIFile
+    this._linkedAddons = [];
+
+    if (!aDirectory || !aDirectory.exists())
+      return;
+    if (!aDirectory.isDirectory())
+      throw new Error("Location must be a directory.");
+
+    this._readAddons();
+  }
 
   /**
    * Reads a directory linked to in a file.
    *
    * @param   file
    *          The file containing the directory path
    * @return  An nsIFile object representing the linked directory.
    */
-  _readDirectoryFromFile: function(aFile) {
+  _readDirectoryFromFile(aFile) {
     let linkedDirectory;
     if (aFile.isSymlink()) {
       linkedDirectory = aFile.clone();
       try {
         linkedDirectory.normalize();
       } catch (e) {
         logger.warn("Symbolic link " + aFile.path + " points to a path" +
              " which does not exist");
@@ -8201,22 +8198,22 @@ DirectoryInstallLocation.prototype = {
         return null;
       }
 
       return linkedDirectory;
     }
 
     logger.warn("File pointer " + aFile.path + " does not contain a path");
     return null;
-  },
+  }
 
   /**
    * Finds all the add-ons installed in this location.
    */
-  _readAddons: function() {
+  _readAddons() {
     // Use a snapshot of the directory contents to avoid possible issues with
     // iterating over a directory while removing files from it (the YAFFS2
     // embedded filesystem has this issue, see bug 772238).
     let entries = getDirectoryEntries(this._directory);
     for (let entry of entries) {
       let id = entry.leafName;
 
       if (id == DIR_STAGE || id == DIR_TRASH)
@@ -8251,136 +8248,137 @@ DirectoryInstallLocation.prototype = {
 
         entry = newEntry;
         this._linkedAddons.push(id);
       }
 
       this._IDToFileMap[id] = entry;
       XPIProvider._addURIMapping(id, entry);
     }
-  },
+  }
 
   /**
    * Gets the name of this install location.
    */
   get name() {
     return this._name;
-  },
+  }
 
   /**
    * Gets the scope of this install location.
    */
   get scope() {
     return this._scope;
-  },
+  }
 
   /**
    * Gets an array of nsIFiles for add-ons installed in this location.
    */
-  getAddonLocations: function() {
+  getAddonLocations() {
     let locations = new Map();
     for (let id in this._IDToFileMap) {
       locations.set(id, this._IDToFileMap[id].clone());
     }
     return locations;
-  },
+  }
 
   /**
    * Gets the directory that the add-on with the given ID is installed in.
    *
    * @param  aId
    *         The ID of the add-on
    * @return The nsIFile
    * @throws if the ID does not match any of the add-ons installed
    */
-  getLocationForID: function(aId) {
+  getLocationForID(aId) {
     if (aId in this._IDToFileMap)
       return this._IDToFileMap[aId].clone();
     throw new Error("Unknown add-on ID " + aId);
-  },
+  }
 
   /**
    * Returns true if the given addon was installed in this location by a text
    * file pointing to its real path.
    *
    * @param aId
    *        The ID of the addon
    */
-  isLinkedAddon: function(aId) {
+  isLinkedAddon(aId) {
     return this._linkedAddons.indexOf(aId) != -1;
   }
-};
+}
 
 /**
  * An extension of DirectoryInstallLocation which adds methods to installing
  * and removing add-ons from the directory at runtime.
- *
- * @param  aName
- *         The string identifier for the install location
- * @param  aDirectory
- *         The nsIFile directory for the install location
- * @param  aScope
- *         The scope of add-ons installed in this location
  */
-function MutableDirectoryInstallLocation(aName, aDirectory, aScope) {
-  DirectoryInstallLocation.call(this, aName, aDirectory, aScope);
-  this.locked = false;
-  this._stagingDirLock = 0;
-}
-
-MutableDirectoryInstallLocation.prototype = Object.create(DirectoryInstallLocation.prototype);
-Object.assign(MutableDirectoryInstallLocation.prototype, {
+
+ class MutableDirectoryInstallLocation extends DirectoryInstallLocation {
+  /**
+   * @param  aName
+   *         The string identifier for the install location
+   * @param  aDirectory
+   *         The nsIFile directory for the install location
+   * @param  aScope
+   *         The scope of add-ons installed in this location
+   */
+   constructor(aName, aDirectory, aScope) {
+     super(aName, aDirectory, aScope);
+     this.locked = false;
+     this._stagingDirLock = 0;
+   }
+
   /**
    * Gets the staging directory to put add-ons that are pending install and
    * uninstall into.
    *
    * @return an nsIFile
    */
-  getStagingDir: function() {
+  getStagingDir() {
     let dir = this._directory.clone();
     dir.append(DIR_STAGE);
     return dir;
-  },
-
-  requestStagingDir: function() {
+  }
+
+  requestStagingDir() {
     this._stagingDirLock++;
 
     if (this._stagingDirPromise)
       return this._stagingDirPromise;
 
     OS.File.makeDir(this._directory.path);
     let stagepath = OS.Path.join(this._directory.path, DIR_STAGE);
     return this._stagingDirPromise = OS.File.makeDir(stagepath).then(null, (e) => {
       if (e instanceof OS.File.Error && e.becauseExists)
         return;
       logger.error("Failed to create staging directory", e);
       throw e;
     });
-  },
-
-  releaseStagingDir: function() {
+  }
+
+  releaseStagingDir() {
     this._stagingDirLock--;
 
     if (this._stagingDirLock == 0) {
       this._stagingDirPromise = null;
       this.cleanStagingDir();
     }
 
     return Promise.resolve();
-  },
+  }
 
   /**
    * Removes the specified files or directories in the staging directory and
    * then if the staging directory is empty attempts to remove it.
    *
    * @param  aLeafNames
    *         An array of file or directory to remove from the directory, the
    *         array may be empty
    */
-  cleanStagingDir: function(aLeafNames = []) {
+  cleanStagingDir(aLeafNames = []) {
     let dir = this.getStagingDir();
 
     for (let name of aLeafNames) {
       let file = dir.clone();
       file.append(name);
       recursiveRemove(file);
     }
 
@@ -8399,42 +8397,42 @@ Object.assign(MutableDirectoryInstallLoc
     try {
       setFilePermissions(dir, FileUtils.PERMS_DIRECTORY);
       dir.remove(false);
     }
     catch (e) {
       logger.warn("Failed to remove staging dir", e);
       // Failing to remove the staging directory is ignorable
     }
-  },
+  }
 
   /**
    * Returns a directory that is normally on the same filesystem as the rest of
    * the install location and can be used for temporarily storing files during
    * safe move operations. Calling this method will delete the existing trash
    * directory and its contents.
    *
    * @return an nsIFile
    */
-  getTrashDir: function() {
+  getTrashDir() {
     let trashDir = this._directory.clone();
     trashDir.append(DIR_TRASH);
     let trashDirExists = trashDir.exists();
     try {
       if (trashDirExists)
         recursiveRemove(trashDir);
       trashDirExists = false;
     } catch (e) {
       logger.warn("Failed to remove trash directory", e);
     }
     if (!trashDirExists)
       trashDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
 
     return trashDir;
-  },
+  }
 
   /**
    * Installs an add-on into the install location.
    *
    * @param  id
    *         The ID of the add-on to install
    * @param  source
    *         The source nsIFile to install from
@@ -8446,17 +8444,21 @@ Object.assign(MutableDirectoryInstallLoc
    *           Default action, the source files will be moved to the new
    *           location,
    *           "copy"
    *           The source files will be copied,
    *           "proxy"
    *           A "proxy file" is going to refer to the source file path
    * @return an nsIFile indicating where the add-on was installed to
    */
-  installAddon: function({ id, source, existingAddonID, action = "move" }) {
+  installAddon({id, source, existingAddonID, action}) {
+    if (!action) {
+      action = "move";
+    }
+
     let trashDir = this.getTrashDir();
 
     let transaction = new SafeInstallOperation();
 
     let moveOldAddon = aId => {
       let file = this._directory.clone();
       file.append(aId);
 
@@ -8546,26 +8548,26 @@ Object.assign(MutableDirectoryInstallLoc
     XPIProvider._addURIMapping(id, newFile);
 
     if (existingAddonID && existingAddonID != id &&
         existingAddonID in this._IDToFileMap) {
       delete this._IDToFileMap[existingAddonID];
     }
 
     return newFile;
-  },
+  }
 
   /**
    * Uninstalls an add-on from this location.
    *
    * @param  aId
    *         The ID of the add-on to uninstall
    * @throws if the ID does not match any of the add-ons installed
    */
-  uninstallAddon: function(aId) {
+  uninstallAddon(aId) {
     let file = this._IDToFileMap[aId];
     if (!file) {
       logger.warn("Attempted to remove " + aId + " from " +
            this._name + " but it was already gone");
       return;
     }
 
     file = this._directory.clone();
@@ -8600,70 +8602,71 @@ Object.assign(MutableDirectoryInstallLoc
         recursiveRemove(trashDir);
       }
       catch (e) {
         logger.warn("Failed to remove trash directory when uninstalling " + aId, e);
       }
     }
 
     delete this._IDToFileMap[aId];
-  },
-});
+  }
+}
 
 /**
  * An object which identifies a directory install location for system add-ons
  * upgrades.
  *
  * The location consists of a directory which contains the add-ons installed.
- *
- * @param  aName
- *         The string identifier for the install location
- * @param  aDirectory
- *         The nsIFile directory for the install location
- * @param  aScope
- *         The scope of add-ons installed in this location
- * @param  aResetSet
- *         True to throw away the current add-on set
  */
-function SystemAddonInstallLocation(aName, aDirectory, aScope, aResetSet) {
-  this._baseDir = aDirectory;
-  this._nextDir = null;
-
-  this._stagingDirLock = 0;
-
-  if (aResetSet)
-    this.resetAddonSet();
-
-  this._addonSet = this._loadAddonSet();
-
-  this._directory = null;
-  if (this._addonSet.directory) {
-    this._directory = aDirectory.clone();
-    this._directory.append(this._addonSet.directory);
-    logger.info("SystemAddonInstallLocation scanning directory " + this._directory.path);
-  }
-  else {
-    logger.info("SystemAddonInstallLocation directory is missing");
-  }
-
-  DirectoryInstallLocation.call(this, aName, this._directory, aScope);
-  this.locked = false;
-}
-
-SystemAddonInstallLocation.prototype = Object.create(DirectoryInstallLocation.prototype);
-Object.assign(SystemAddonInstallLocation.prototype, {
+ class SystemAddonInstallLocation extends MutableDirectoryInstallLocation {
+  /**
+   * @param  aName
+   *         The string identifier for the install location
+   * @param  aDirectory
+   *         The nsIFile directory for the install location
+   * @param  aScope
+   *         The scope of add-ons installed in this location
+   * @param  aResetSet
+   *         True to throw away the current add-on set
+   */
+  constructor(aName, aDirectory, aScope, aResetSet) {
+    super(aName, aDirectory, aScope);
+
+    this._baseDir = aDirectory;
+    this._nextDir = null;
+
+    this._stagingDirLock = 0;
+
+    if (aResetSet)
+      this.resetAddonSet();
+
+    this._addonSet = this._loadAddonSet();
+
+    this._directory = null;
+    if (this._addonSet.directory) {
+      this._directory = aDirectory.clone();
+      this._directory.append(this._addonSet.directory);
+      logger.info("SystemAddonInstallLocation scanning directory " + this._directory.path);
+    }
+    else {
+      logger.info("SystemAddonInstallLocation directory is missing");
+    }
+
+    this.locked = false;
+  }
+
   /**
    * Removes the specified files or directories in the staging directory and
    * then if the staging directory is empty attempts to remove it.
    *
    * @param  aLeafNames
    *         An array of file or directory to remove from the directory, the
    *         array may be empty
    */
-  cleanStagingDir: function(aLeafNames = []) {
+  cleanStagingDir(aLeafNames = []) {
     let dir = this.getStagingDir();
 
     for (let name of aLeafNames) {
       let file = dir.clone();
       file.append(name);
       recursiveRemove(file);
     }
 
@@ -8682,41 +8685,41 @@ Object.assign(SystemAddonInstallLocation
     try {
       setFilePermissions(dir, FileUtils.PERMS_DIRECTORY);
       dir.remove(false);
     }
     catch (e) {
       logger.warn("Failed to remove staging dir", e);
       // Failing to remove the staging directory is ignorable
     }
-  },
+  }
 
   /**
    * Gets the staging directory to put add-ons that are pending install and
    * uninstall into.
    *
    * @return {nsIFile} - staging directory for system add-on upgrades.
    */
-  getStagingDir: function() {
+  getStagingDir() {
     this._addonSet = this._loadAddonSet();
     let dir = null;
     if (this._addonSet.directory) {
       this._directory = this._baseDir.clone();
       this._directory.append(this._addonSet.directory);
       dir = this._directory.clone();
       dir.append(DIR_STAGE);
     }
     else {
       logger.info("SystemAddonInstallLocation directory is missing");
     }
 
     return dir;
-  },
-
-  requestStagingDir: function() {
+  }
+
+  requestStagingDir() {
     this._stagingDirLock++;
     if (this._stagingDirPromise)
       return this._stagingDirPromise;
 
     this._addonSet = this._loadAddonSet();
     if (this._addonSet.directory) {
       this._directory = this._baseDir.clone();
       this._directory.append(this._addonSet.directory);
@@ -8725,82 +8728,82 @@ Object.assign(SystemAddonInstallLocation
     OS.File.makeDir(this._directory.path);
     let stagepath = OS.Path.join(this._directory.path, DIR_STAGE);
     return this._stagingDirPromise = OS.File.makeDir(stagepath).then(null, (e) => {
       if (e instanceof OS.File.Error && e.becauseExists)
         return;
       logger.error("Failed to create staging directory", e);
       throw e;
     });
-  },
-
-  releaseStagingDir: function() {
+  }
+
+  releaseStagingDir() {
     this._stagingDirLock--;
 
     if (this._stagingDirLock == 0) {
       this._stagingDirPromise = null;
       this.cleanStagingDir();
     }
 
     return Promise.resolve();
-  },
+  }
 
   /**
    * Reads the current set of system add-ons
    */
-  _loadAddonSet: function() {
+  _loadAddonSet() {
     try {
       let setStr = Preferences.get(PREF_SYSTEM_ADDON_SET, null);
       if (setStr) {
         let addonSet = JSON.parse(setStr);
         if ((typeof addonSet == "object") && addonSet.schema == 1)
           return addonSet;
       }
     }
     catch (e) {
       logger.error("Malformed system add-on set, resetting.");
     }
 
     return { schema: 1, addons: {} };
-  },
+  }
 
   /**
    * Saves the current set of system add-ons
    *
    * @param {Object} aAddonSet - object containing schema, directory and set
    *                 of system add-on IDs and versions.
    */
-  _saveAddonSet: function(aAddonSet) {
+  _saveAddonSet(aAddonSet) {
     Preferences.set(PREF_SYSTEM_ADDON_SET, JSON.stringify(aAddonSet));
-  },
-
-  getAddonLocations: function() {
+  }
+
+  getAddonLocations() {
     // Updated system add-ons are ignored in safe mode
     if (Services.appinfo.inSafeMode)
       return new Map();
 
     let addons = DirectoryInstallLocation.prototype.getAddonLocations.call(this);
 
     // Strip out any unexpected add-ons from the list
     for (let id of addons.keys()) {
       if (!(id in this._addonSet.addons))
         addons.delete(id);
     }
 
     return addons;
-  },
+  }
 
   /**
    * Tests whether updated system add-ons are expected.
    */
-  isActive: function() {
+  isActive() {
     return this._directory != null;
-  },
-
-  isValidAddon: function(aAddon) {
+  }
+
+  isValidAddon(aAddon) {
     if (aAddon.appDisabled) {
       logger.warn(`System add-on ${aAddon.id} isn't compatible with the application.`);
       return false;
     }
 
     if (aAddon.unpack) {
       logger.warn(`System add-on ${aAddon.id} isn't a packed add-on.`);
       return false;
@@ -8812,22 +8815,22 @@ Object.assign(SystemAddonInstallLocation
     }
 
     if (!aAddon.multiprocessCompatible) {
       logger.warn(`System add-on ${aAddon.id} isn't multiprocess compatible.`);
       return false;
     }
 
     return true;
-  },
+  }
 
   /**
    * Tests whether the loaded add-on information matches what is expected.
    */
-  isValid: function(aAddons) {
+  isValid(aAddons) {
     for (let id of Object.keys(this._addonSet.addons)) {
       if (!aAddons.has(id)) {
         logger.warn(`Expected add-on ${id} is missing from the system add-on location.`);
         return false;
       }
 
       let addon = aAddons.get(id);
       if (addon.version != this._addonSet.addons[id].version) {
@@ -8835,22 +8838,22 @@ Object.assign(SystemAddonInstallLocation
         return false;
       }
 
       if (!this.isValidAddon(addon))
         return false;
     }
 
     return true;
-  },
+  }
 
   /**
    * Resets the add-on set so on the next startup the default set will be used.
    */
-  resetAddonSet: function() {
+  resetAddonSet() {
 
     if (this._addonSet) {
       logger.info("Removing all system add-on upgrades.");
 
       // remove everything from the pref first, if uninstall
       // fails then at least they will not be re-activated on
       // next restart.
       this._saveAddonSet({ schema: 1, addons: {} });
@@ -8858,246 +8861,252 @@ Object.assign(SystemAddonInstallLocation
       for (let id of Object.keys(this._addonSet.addons)) {
         AddonManager.getAddonByID(id, addon => {
           if (addon) {
             addon.uninstall();
           }
         });
       }
     }
-  },
+  }
 
   /**
    * Removes any directories not currently in use or pending use after a
    * restart. Any errors that happen here don't really matter as we'll attempt
    * to cleanup again next time.
    */
-  cleanDirectories: Task.async(function*() {
-
-    // System add-ons directory does not exist
-    if (!(yield OS.File.exists(this._baseDir.path))) {
-      return;
-    }
-
-    let iterator;
-    try {
-      iterator = new OS.File.DirectoryIterator(this._baseDir.path);
-    }
-    catch (e) {
-      logger.error("Failed to clean updated system add-ons directories.", e);
-      return;
-    }
-
-    try {
-      let entries = [];
-
-      yield iterator.forEach(entry => {
-        // Skip the directory currently in use
-        if (this._directory && this._directory.path == entry.path)
-          return;
-
-        // Skip the next directory
-        if (this._nextDir && this._nextDir.path == entry.path)
-          return;
-
-        entries.push(entry);
-      });
-
-      for (let entry of entries) {
-        if (entry.isDir) {
-          yield OS.File.removeDir(entry.path, {
-            ignoreAbsent: true,
-            ignorePermissions: true,
-          });
-        }
-        else {
-          yield OS.File.remove(entry.path, {
-            ignoreAbsent: true,
-          });
-        }
-      }
-    }
-    catch (e) {
-      logger.error("Failed to clean updated system add-ons directories.", e);
-    }
-    finally {
-      iterator.close();
-    }
-  }),
+  cleanDirectories() {
+    return Task.spawn(function*() {
+
+      // System add-ons directory does not exist
+      if (!(yield OS.File.exists(this._baseDir.path))) {
+        return;
+      }
+
+      let iterator;
+      try {
+        iterator = new OS.File.DirectoryIterator(this._baseDir.path);
+      }
+      catch (e) {
+        logger.error("Failed to clean updated system add-ons directories.", e);
+        return;
+      }
+
+      try {
+        let entries = [];
+
+        yield iterator.forEach(entry => {
+          // Skip the directory currently in use
+          if (this._directory && this._directory.path == entry.path)
+            return;
+
+          // Skip the next directory
+          if (this._nextDir && this._nextDir.path == entry.path)
+            return;
+
+          entries.push(entry);
+        });
+
+        for (let entry of entries) {
+          if (entry.isDir) {
+            yield OS.File.removeDir(entry.path, {
+              ignoreAbsent: true,
+              ignorePermissions: true,
+            });
+          }
+          else {
+            yield OS.File.remove(entry.path, {
+              ignoreAbsent: true,
+            });
+          }
+        }
+      }
+      catch (e) {
+        logger.error("Failed to clean updated system add-ons directories.", e);
+      }
+      finally {
+        iterator.close();
+      }
+    }).bind(this);
+  }
 
   /**
    * Installs a new set of system add-ons into the location and updates the
    * add-on set in prefs.
    *
    * @param {Array} aAddons - An array of addons to install.
    */
-  installAddonSet: Task.async(function*(aAddons) {
-    // Make sure the base dir exists
-    yield OS.File.makeDir(this._baseDir.path, { ignoreExisting: true });
-
-    let addonSet = this._loadAddonSet();
-
-    // Remove any add-ons that are no longer part of the set.
-    for (let addonID of Object.keys(addonSet.addons)) {
-      if (!aAddons.includes(addonID)) {
-        AddonManager.getAddonByID(addonID, a => a.uninstall());
-      }
-    }
-
-    let newDir = this._baseDir.clone();
-
-    let uuidGen = Cc["@mozilla.org/uuid-generator;1"].
-                  getService(Ci.nsIUUIDGenerator);
-    newDir.append("blank");
-
-    while (true) {
-      newDir.leafName = uuidGen.generateUUID().toString();
+  installAddonSet() {
+    return Task.spawn(function*(aAddons) {
+      // Make sure the base dir exists
+      yield OS.File.makeDir(this._baseDir.path, { ignoreExisting: true });
+
+      let addonSet = this._loadAddonSet();
+
+      // Remove any add-ons that are no longer part of the set.
+      for (let addonID of Object.keys(addonSet.addons)) {
+        if (!aAddons.includes(addonID)) {
+          AddonManager.getAddonByID(addonID, a => a.uninstall());
+        }
+      }
+
+      let newDir = this._baseDir.clone();
+
+      let uuidGen = Cc["@mozilla.org/uuid-generator;1"].
+                    getService(Ci.nsIUUIDGenerator);
+      newDir.append("blank");
+
+      while (true) {
+        newDir.leafName = uuidGen.generateUUID().toString();
+
+        try {
+          yield OS.File.makeDir(newDir.path, { ignoreExisting: false });
+          break;
+        }
+        catch (e) {
+          logger.debug("Could not create new system add-on updates dir, retrying", e);
+        }
+      }
+
+      // Record the new upgrade directory.
+      let state = { schema: 1, directory: newDir.leafName, addons: {} };
+      this._saveAddonSet(state);
+
+      this._nextDir = newDir;
+      let location = this;
+
+      let installs = [];
+      for (let addon of aAddons) {
+        let install = yield createLocalInstall(addon._sourceBundle, location);
+        installs.push(install);
+      }
+
+      let installAddon = Task.async(function*(install) {
+        // Make the new install own its temporary file.
+        install.ownsTempFile = true;
+        install.install();
+      });
+
+      let postponeAddon = Task.async(function*(install) {
+        let resumeFn;
+        if (AddonManagerPrivate.hasUpgradeListener(install.addon.id)) {
+          logger.info(`system add-on ${install.addon.id} has an upgrade listener, postponing upgrade set until restart`);
+          resumeFn = () => {
+            logger.info(`${install.addon.id} has resumed a previously postponed addon set`);
+            install.installLocation.resumeAddonSet(installs);
+          }
+        }
+        yield install.postpone(resumeFn);
+      });
+
+      let previousState;
 
       try {
-        yield OS.File.makeDir(newDir.path, { ignoreExisting: false });
-        break;
+        // All add-ons in position, create the new state and store it in prefs
+        state = { schema: 1, directory: newDir.leafName, addons: {} };
+        for (let addon of aAddons) {
+          state.addons[addon.id] = {
+            version: addon.version
+          }
+        }
+
+        previousState = this._loadAddonSet();
+        this._saveAddonSet(state);
+
+        let blockers = aAddons.filter(
+          addon => AddonManagerPrivate.hasUpgradeListener(addon.id)
+        );
+
+        if (blockers.length > 0) {
+          yield waitForAllPromises(installs.map(postponeAddon));
+        } else {
+          yield waitForAllPromises(installs.map(installAddon));
+        }
       }
       catch (e) {
-        logger.debug("Could not create new system add-on updates dir, retrying", e);
-      }
-    }
-
-    // Record the new upgrade directory.
-    let state = { schema: 1, directory: newDir.leafName, addons: {} };
-    this._saveAddonSet(state);
-
-    this._nextDir = newDir;
-    let location = this;
-
-    let installs = [];
-    for (let addon of aAddons) {
-      let install = yield createLocalInstall(addon._sourceBundle, location);
-      installs.push(install);
-    }
-
-    let installAddon = Task.async(function*(install) {
-      // Make the new install own its temporary file.
-      install.ownsTempFile = true;
-      install.install();
-    });
-
-    let postponeAddon = Task.async(function*(install) {
-      let resumeFn;
-      if (AddonManagerPrivate.hasUpgradeListener(install.addon.id)) {
-        logger.info(`system add-on ${install.addon.id} has an upgrade listener, postponing upgrade set until restart`);
-        resumeFn = () => {
-          logger.info(`${install.addon.id} has resumed a previously postponed addon set`);
-          install.installLocation.resumeAddonSet(installs);
-        }
-      }
-      yield install.postpone(resumeFn);
-    });
-
-    let previousState;
-
-    try {
-      // All add-ons in position, create the new state and store it in prefs
-      state = { schema: 1, directory: newDir.leafName, addons: {} };
-      for (let addon of aAddons) {
-        state.addons[addon.id] = {
-          version: addon.version
-        }
-      }
-
-      previousState = this._loadAddonSet();
-      this._saveAddonSet(state);
-
-      let blockers = aAddons.filter(
-        addon => AddonManagerPrivate.hasUpgradeListener(addon.id)
-      );
-
-      if (blockers.length > 0) {
-        yield waitForAllPromises(installs.map(postponeAddon));
-      } else {
-        yield waitForAllPromises(installs.map(installAddon));
-      }
-    }
-    catch (e) {
-      // Roll back to previous upgrade set (if present) on restart.
-      if (previousState) {
-        this._saveAddonSet(previousState);
-      }
-      // Otherwise, roll back to built-in set on restart.
-      // TODO try to do these restartlessly
-      this.resetAddonSet();
-
-      try {
-        yield OS.File.removeDir(newDir.path, { ignorePermissions: true });
-      }
-      catch (e) {
-        logger.warn(`Failed to remove failed system add-on directory ${newDir.path}.`, e);
-      }
-      throw e;
-    }
-  }),
+        // Roll back to previous upgrade set (if present) on restart.
+        if (previousState) {
+          this._saveAddonSet(previousState);
+        }
+        // Otherwise, roll back to built-in set on restart.
+        // TODO try to do these restartlessly
+        this.resetAddonSet();
+
+        try {
+          yield OS.File.removeDir(newDir.path, { ignorePermissions: true });
+        }
+        catch (e) {
+          logger.warn(`Failed to remove failed system add-on directory ${newDir.path}.`, e);
+        }
+        throw e;
+      }
+    }).bind(this);
+  }
 
  /**
   * Resumes upgrade of a previously-delayed add-on set.
   */
-  resumeAddonSet: Task.async(function*(installs) {
-    let resumeAddon = Task.async(function*(install) {
-      install.state = AddonManager.STATE_DOWNLOADED;
-      install.installLocation.releaseStagingDir();
-      install.install();
-    });
-
-    let addonSet = this._loadAddonSet();
-    let addonIDs = Object.keys(addonSet.addons);
-
-    let blockers = installs.filter(
-      install => AddonManagerPrivate.hasUpgradeListener(install.addon.id)
-    );
-
-    if (blockers.length > 1) {
-      logger.warn("Attempted to resume system add-on install but upgrade blockers are still present");
-    } else {
-      yield waitForAllPromises(installs.map(resumeAddon));
-    }
-  }),
+  resumeAddonSet() {
+    return Task.spawn(function*(installs) {
+      let resumeAddon = Task.async(function*(install) {
+        install.state = AddonManager.STATE_DOWNLOADED;
+        install.installLocation.releaseStagingDir();
+        install.install();
+      });
+
+      let addonSet = this._loadAddonSet();
+      let addonIDs = Object.keys(addonSet.addons);
+
+      let blockers = installs.filter(
+        install => AddonManagerPrivate.hasUpgradeListener(install.addon.id)
+      );
+
+      if (blockers.length > 1) {
+        logger.warn("Attempted to resume system add-on install but upgrade blockers are still present");
+      } else {
+        yield waitForAllPromises(installs.map(resumeAddon));
+      }
+    }).bind(this);
+  }
 
   /**
    * Returns a directory that is normally on the same filesystem as the rest of
    * the install location and can be used for temporarily storing files during
    * safe move operations. Calling this method will delete the existing trash
    * directory and its contents.
    *
    * @return an nsIFile
    */
-  getTrashDir: function() {
+  getTrashDir() {
     let trashDir = this._directory.clone();
     trashDir.append(DIR_TRASH);
     let trashDirExists = trashDir.exists();
     try {
       if (trashDirExists)
         recursiveRemove(trashDir);
       trashDirExists = false;
     } catch (e) {
       logger.warn("Failed to remove trash directory", e);
     }
     if (!trashDirExists)
       trashDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
 
     return trashDir;
-  },
+  }
 
   /**
    * Installs an add-on into the install location.
    *
    * @param  id
    *         The ID of the add-on to install
    * @param  source
    *         The source nsIFile to install from
    * @return an nsIFile indicating where the add-on was installed to
    */
-  installAddon: function({id, source}) {
+  installAddon({id, source}) {
     let trashDir = this.getTrashDir();
     let transaction = new SafeInstallOperation();
 
     // If any of these operations fails the finally block will clean up the
     // temporary directory
     try {
       if (source.isFile()) {
         flushJarCache(source);
@@ -9123,21 +9132,21 @@ Object.assign(SystemAddonInstallLocation
       newFile.lastModifiedTime = Date.now();
     } catch (e)  {
       logger.warn("failed to set lastModifiedTime on " + newFile.path, e);
     }
     this._IDToFileMap[id] = newFile;
     XPIProvider._addURIMapping(id, newFile);
 
     return newFile;
-  },
+  }
 
   // old system add-on upgrade dirs get automatically removed
-  uninstallAddon: (aAddon) => {},
-});
+  uninstallAddon(aAddon) {}
+}
 
 /**
  * An object which identifies an install location for temporary add-ons.
  */
 const TemporaryInstallLocation = {
   locked: false,
   name: KEY_APP_TEMPORARY,
   scope: AddonManager.SCOPE_TEMPORARY,
@@ -9147,128 +9156,123 @@ const TemporaryInstallLocation = {
   uninstallAddon: (aAddon) => {},
   getStagingDir: () => {},
 }
 
 /**
  * An object that identifies a registry install location for add-ons. The location
  * consists of a registry key which contains string values mapping ID to the
  * path where an add-on is installed
- *
- * @param  aName
- *         The string identifier of this Install Location.
- * @param  aRootKey
- *         The root key (one of the ROOT_KEY_ values from nsIWindowsRegKey).
- * @param  scope
- *         The scope of add-ons installed in this location
  */
-function WinRegInstallLocation(aName, aRootKey, aScope) {
-  this.locked = true;
-  this._name = aName;
-  this._rootKey = aRootKey;
-  this._scope = aScope;
-  this._IDToFileMap = {};
-
-  let path = this._appKeyPath + "\\Extensions";
-  let key = Cc["@mozilla.org/windows-registry-key;1"].
-            createInstance(Ci.nsIWindowsRegKey);
-
-  // Reading the registry may throw an exception, and that's ok.  In error
-  // cases, we just leave ourselves in the empty state.
-  try {
-    key.open(this._rootKey, path, Ci.nsIWindowsRegKey.ACCESS_READ);
-  }
-  catch (e) {
-    return;
-  }
-
-  this._readAddons(key);
-  key.close();
-}
-
-WinRegInstallLocation.prototype = {
-  _name       : "",
-  _rootKey    : null,
-  _scope      : null,
-  _IDToFileMap : null,  // mapping from ID to nsIFile
-
+class WinRegInstallLocation {
+  /**
+   * @param  aName
+   *         The string identifier of this Install Location.
+   * @param  aRootKey
+   *         The root key (one of the ROOT_KEY_ values from nsIWindowsRegKey).
+   * @param  scope
+   *         The scope of add-ons installed in this location
+   */
+  constructor(aName, aRootKey, aScope) {
+    this.locked = true;
+    this._name = aName;
+    this._rootKey = aRootKey;
+    this._scope = aScope;
+    this._IDToFileMap = {}; // mapping from ID to nsIFile
+
+    let path = this._appKeyPath + "\\Extensions";
+    let key = Cc["@mozilla.org/windows-registry-key;1"].
+              createInstance(Ci.nsIWindowsRegKey);
+
+    // Reading the registry may throw an exception, and that's ok.  In error
+    // cases, we just leave ourselves in the empty state.
+    try {
+      key.open(this._rootKey, path, Ci.nsIWindowsRegKey.ACCESS_READ);
+    }
+    catch (e) {
+      return;
+    }
+
+    this._readAddons(key);
+    key.close();
+  }
   /**
    * Retrieves the path of this Application's data key in the registry.
    */
   get _appKeyPath() {
     let appVendor = Services.appinfo.vendor;
     let appName = Services.appinfo.name;
 
     // XXX Thunderbird doesn't specify a vendor string
     if (AppConstants.MOZ_APP_NAME == "thunderbird" && appVendor == "")
       appVendor = "Mozilla";
 
     // XULRunner-based apps may intentionally not specify a vendor
     if (appVendor != "")
       appVendor += "\\";
 
     return "SOFTWARE\\" + appVendor + appName;
-  },
+  }
 
   /**
    * Read the registry and build a mapping between ID and path for each
    * installed add-on.
    *
    * @param  key
    *         The key that contains the ID to path mapping
    */
-  _readAddons: function(aKey) {
+  _readAddons(aKey) {
     let count = aKey.valueCount;
     for (let i = 0; i < count; ++i) {
       let id = aKey.getValueName(i);
 
       let file = new nsIFile(aKey.readStringValue(id));
 
       if (!file.exists()) {
         logger.warn("Ignoring missing add-on in " + file.path);
         continue;
       }
 
       this._IDToFileMap[id] = file;
       XPIProvider._addURIMapping(id, file);
     }
-  },
+  }
 
   /**
    * Gets the name of this install location.
    */
   get name() {
     return this._name;
-  },
+  }
 
   /**
    * Gets the scope of this install location.
    */
   get scope() {
     return this._scope;
-  },
+  }
 
   /**
    * Gets an array of nsIFiles for add-ons installed in this location.
    */
-  getAddonLocations: function() {
+  getAddonLocations() {
     let locations = new Map();
     for (let id in this._IDToFileMap) {
       locations.set(id, this._IDToFileMap[id].clone());
     }
     return locations;
-  },
+  }
 
   /**
    * @see DirectoryInstallLocation
    */
-  isLinkedAddon: function(aId) {
+  isLinkedAddon(aId) {
     return true;
   }
-};
+}
 
 var addonTypes = [
   new AddonManagerPrivate.AddonType("extension", URI_EXTENSION_STRINGS,
                                     STRING_TYPE_NAME,
                                     AddonManager.VIEW_TYPE_LIST, 4000,
                                     AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL),
   new AddonManagerPrivate.AddonType("theme", URI_EXTENSION_STRINGS,
                                     STRING_TYPE_NAME,
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -317,62 +317,62 @@ function copyRowProperties(aRow, aProper
   return aTarget;
 }
 
 /**
  * The DBAddonInternal is a special AddonInternal that has been retrieved from
  * the database. The constructor will initialize the DBAddonInternal with a set
  * of fields, which could come from either the JSON store or as an
  * XPIProvider.AddonInternal created from an addon's manifest
- * @constructor
- * @param aLoaded
- *        Addon data fields loaded from JSON or the addon manifest.
  */
-function DBAddonInternal(aLoaded) {
-  AddonInternal.call(this);
+ class DBAddonInternal extends AddonInternal {
+  /**
+   * @param aLoaded
+   *        Addon data fields loaded from JSON or the addon manifest.
+   */
+  constructor(aLoaded) {
+    super();
 
-  copyProperties(aLoaded, PROP_JSON_FIELDS, this);
+    copyProperties(aLoaded, PROP_JSON_FIELDS, this);
+
+    if (!this.dependencies)
+      this.dependencies = [];
+    Object.freeze(this.dependencies);
 
-  if (!this.dependencies)
-    this.dependencies = [];
-  Object.freeze(this.dependencies);
+    if (aLoaded._installLocation) {
+      this._installLocation = aLoaded._installLocation;
+      this.location = aLoaded._installLocation.name;
+    }
+    else if (aLoaded.location) {
+      this._installLocation = XPIProvider.installLocationsByName[this.location];
+    }
+
+    this._key = this.location + ":" + this.id;
+
+    if (!aLoaded._sourceBundle) {
+      throw new Error("Expected passed argument to contain a descriptor");
+    }
 
-  if (aLoaded._installLocation) {
-    this._installLocation = aLoaded._installLocation;
-    this.location = aLoaded._installLocation.name;
-  }
-  else if (aLoaded.location) {
-    this._installLocation = XPIProvider.installLocationsByName[this.location];
+    this._sourceBundle = aLoaded._sourceBundle;
+
+    XPCOMUtils.defineLazyGetter(this, "pendingUpgrade", function() {
+        for (let install of XPIProvider.installs) {
+          if (install.state == AddonManager.STATE_INSTALLED &&
+              !(install.addon.inDatabase) &&
+              install.addon.id == this.id &&
+              install.installLocation == this._installLocation) {
+            delete this.pendingUpgrade;
+            return this.pendingUpgrade = install.addon;
+          }
+        }
+        return null;
+      });
   }
 
-  this._key = this.location + ":" + this.id;
-
-  if (!aLoaded._sourceBundle) {
-    throw new Error("Expected passed argument to contain a descriptor");
-  }
-
-  this._sourceBundle = aLoaded._sourceBundle;
-
-  XPCOMUtils.defineLazyGetter(this, "pendingUpgrade", function() {
-      for (let install of XPIProvider.installs) {
-        if (install.state == AddonManager.STATE_INSTALLED &&
-            !(install.addon.inDatabase) &&
-            install.addon.id == this.id &&
-            install.installLocation == this._installLocation) {
-          delete this.pendingUpgrade;
-          return this.pendingUpgrade = install.addon;
-        }
-      }
-      return null;
-    });
-}
-
-DBAddonInternal.prototype = Object.create(AddonInternal.prototype);
-Object.assign(DBAddonInternal.prototype, {
-  applyCompatibilityUpdate: function(aUpdate, aSyncCompatibility) {
+  applyCompatibilityUpdate(aUpdate, aSyncCompatibility) {
     let wasCompatible = this.isCompatible;
 
     this.targetApplications.forEach(function(aTargetApp) {
       aUpdate.targetApplications.forEach(function(aUpdateTarget) {
         if (aTargetApp.id == aUpdateTarget.id && (aSyncCompatibility ||
             Services.vc.compare(aTargetApp.maxVersion, aUpdateTarget.maxVersion) < 0)) {
           aTargetApp.minVersion = aUpdateTarget.minVersion;
           aTargetApp.maxVersion = aUpdateTarget.maxVersion;
@@ -383,35 +383,35 @@ Object.assign(DBAddonInternal.prototype,
     if (aUpdate.multiprocessCompatible !== undefined &&
         aUpdate.multiprocessCompatible != this.multiprocessCompatible) {
       this.multiprocessCompatible = aUpdate.multiprocessCompatible;
       XPIDatabase.saveChanges();
     }
 
     if (wasCompatible != this.isCompatible)
       XPIProvider.updateAddonDisabledState(this);
-  },
+  }
 
-  toJSON: function() {
+  toJSON() {
     let jsonData = copyProperties(this, PROP_JSON_FIELDS);
 
     // Experiments are serialized as disabled so they aren't run on the next
     // startup.
     if (this.type == "experiment") {
       jsonData.userDisabled = true;
       jsonData.active = false;
     }
 
     return jsonData;
-  },
+  }
 
   get inDatabase() {
     return true;
   }
-});
+}
 
 /**
  * Internal interface: find an addon from an already loaded addonDB
  */
 function _findAddon(addonDB, aFilter) {
   for (let addon of addonDB.values()) {
     if (aFilter(addon)) {
       return addon;