Bug 1292995 - Replace Iterator() with Object.{values,entries} in services/; r?arai draft
authorSumit Tiwari <sumi29@gmail.com>
Mon, 08 Aug 2016 22:40:23 -0400
changeset 398385 ce48c048a83877a7a0c264b2dba13cbc79569b40
parent 397811 5f03251f933e8cdee46b89b7a8eb2293b0b69eb2
child 398971 99ba34feabe951e15f9b67aa2eea586886138b16
child 399429 3d2729adeabb9e67d6648ef9a0da8c33545b88f8
push id25512
push userbmo:sumi29@gmail.com
push dateTue, 09 Aug 2016 02:41:18 +0000
reviewersarai
bugs1292995
milestone51.0a1
Bug 1292995 - Replace Iterator() with Object.{values,entries} in services/; r?arai MozReview-Commit-ID: 3VEOjAJROld
services/common/modules-testing/storageserver.js
services/common/tests/unit/test_utils_encodeBase64URL.js
services/fxaccounts/FxAccounts.jsm
services/fxaccounts/FxAccountsStorage.jsm
services/fxaccounts/tests/xpcshell/test_accounts.js
services/fxaccounts/tests/xpcshell/test_accounts_device_registration.js
services/fxaccounts/tests/xpcshell/test_oauth_token_storage.js
services/fxaccounts/tests/xpcshell/test_oauth_tokens.js
services/sync/modules-testing/rotaryengine.js
services/sync/modules-testing/utils.js
services/sync/modules/SyncedTabs.jsm
services/sync/modules/addonsreconciler.js
services/sync/modules/constants.js
services/sync/modules/engines.js
services/sync/modules/engines/addons.js
services/sync/modules/engines/bookmarks.js
services/sync/modules/engines/clients.js
services/sync/modules/record.js
services/sync/modules/resource.js
services/sync/tests/unit/head_http_server.js
services/sync/tests/unit/test_syncedtabs.js
services/sync/tps/extensions/tps/resource/modules/tabs.jsm
--- a/services/common/modules-testing/storageserver.js
+++ b/services/common/modules-testing/storageserver.js
@@ -206,17 +206,17 @@ ServerBSO.prototype = {
       code = 204;
       status = "No Content";
     } else {
       code = 201;
       status = "Created";
     }
 
     // Alert when we see unrecognized fields.
-    for (let [key, value] in Iterator(parsed)) {
+    for (let [key, value] of Object.entries(parsed)) {
       switch (key) {
         case "payload":
           if (typeof(value) != "string") {
             sendMozSvcError(request, response, "8");
             return true;
           }
 
           this.payload = value;
@@ -320,17 +320,17 @@ StorageServerCollection.prototype = {
    * @param filter
    *        A predicate function (applied to the ID and BSO) which dictates
    *        whether to include the BSO's ID in the output.
    *
    * @return an array of IDs.
    */
   keys: function keys(filter) {
     let ids = [];
-    for (let [id, bso] in Iterator(this._bsos)) {
+    for (let [id, bso] of Object.entries(this._bsos)) {
       if (!bso.deleted && (!filter || filter(id, bso))) {
         ids.push(id);
       }
     }
     return ids;
   },
 
   /**
@@ -340,17 +340,17 @@ StorageServerCollection.prototype = {
    * @param filter
    *        A predicate function, applied to the BSO, which dictates whether to
    *        include the BSO in the output.
    *
    * @return an array of ServerBSOs.
    */
   bsos: function bsos(filter) {
     let os = [];
-    for (let [id, bso] in Iterator(this._bsos)) {
+    for (let [id, bso] of Object.entries(this._bsos)) {
       if (!bso.deleted) {
         os.push(bso);
       }
     }
 
     if (!filter) {
       return os;
     }
@@ -435,17 +435,17 @@ StorageServerCollection.prototype = {
     }
 
     return true;
   },
 
   count: function count(options) {
     options = options || {};
     let c = 0;
-    for (let [id, bso] in Iterator(this._bsos)) {
+    for (let [id, bso] of Object.entries(this._bsos)) {
       if (bso.modified && this._inResultSet(bso, options)) {
         c++;
       }
     }
     return c;
   },
 
   get: function get(options) {
@@ -593,17 +593,17 @@ StorageServerCollection.prototype = {
       throw new Error("Malformed client request.");
     }
 
     if (options.ids && options.ids.length > this.BATCH_MAX_COUNT) {
       throw HTTP_400;
     }
 
     let deleted = [];
-    for (let [id, bso] in Iterator(this._bsos)) {
+    for (let [id, bso] of Object.entries(this._bsos)) {
       if (this._inResultSet(bso, options)) {
         this._log.debug("Deleting " + JSON.stringify(bso));
         deleted.push(bso.id);
         bso.delete();
       }
     }
     return deleted;
   },
@@ -1047,20 +1047,20 @@ StorageServer.prototype = {
    * If a collection already exists, no error is raised.
    * If a BSO already exists, it will be updated to the new contents.
    */
   createContents: function createContents(username, collections) {
     if (!(username in this.users)) {
       throw new Error("Unknown user.");
     }
     let userCollections = this.users[username].collections;
-    for (let [id, contents] in Iterator(collections)) {
+    for (let [id, contents] of Object.entries(collections)) {
       let coll = userCollections[id] ||
                  this._insertCollection(userCollections, id);
-      for (let [bsoID, payload] in Iterator(contents)) {
+      for (let [bsoID, payload] of Object.entries(contents)) {
         coll.insert(bsoID, payload);
       }
     }
   },
 
   /**
    * Insert a BSO in an existing collection.
    */
@@ -1131,32 +1131,32 @@ StorageServer.prototype = {
     this._log.trace("StorageServer: info/collections returning " +
                     JSON.stringify(responseObject));
     return responseObject;
   },
 
   infoCounts: function infoCounts(username) {
     let data = {};
     let collections = this.users[username].collections;
-    for (let [k, v] in Iterator(collections)) {
+    for (let [k, v] of Object.entries(collections)) {
       let count = v.count();
       if (!count) {
         continue;
       }
 
       data[k] = count;
     }
 
     return data;
   },
 
   infoUsage: function infoUsage(username) {
     let data = {};
     let collections = this.users[username].collections;
-    for (let [k, v] in Iterator(collections)) {
+    for (let [k, v] of Object.entries(collections)) {
       data[k] = v.totalPayloadSize;
     }
 
     return data;
   },
 
   infoQuota: function infoQuota(username) {
     let total = 0;
@@ -1663,15 +1663,15 @@ StorageServer.prototype = {
 /**
  * Helper to create a storage server for a set of users.
  *
  * Each user is specified by a map of username to password.
  */
 this.storageServerForUsers =
  function storageServerForUsers(users, contents, callback) {
   let server = new StorageServer(callback);
-  for (let [user, pass] in Iterator(users)) {
+  for (let [user, pass] of Object.entries(users)) {
     server.registerUser(user, pass);
     server.createContents(user, contents);
   }
   server.start();
   return server;
 }
--- a/services/common/tests/unit/test_utils_encodeBase64URL.js
+++ b/services/common/tests/unit/test_utils_encodeBase64URL.js
@@ -8,17 +8,17 @@ function run_test() {
 }
 
 add_test(function test_simple() {
   let expected = {
     hello: "aGVsbG8=",
     "<>?": "PD4_",
   };
 
-  for (let [k, v] in Iterator(expected)) {
+  for (let [k,v] of Object.entries(expected)) {
     do_check_eq(CommonUtils.encodeBase64URL(k), v);
   }
 
   run_next_test();
 });
 
 add_test(function test_no_padding() {
   do_check_eq(CommonUtils.encodeBase64URL("hello", false), "aGVsbG8");
--- a/services/fxaccounts/FxAccounts.jsm
+++ b/services/fxaccounts/FxAccounts.jsm
@@ -226,17 +226,17 @@ AccountState.prototype = {
     return null;
   },
 
   // Remove a cached token from the cache.  Does *not* revoke it from anywhere.
   // Returns the entire token entry if found, null otherwise.
   removeCachedToken(token) {
     this._cachePreamble();
     let data = this.oauthTokens;
-    for (let [key, tokenValue] in Iterator(data)) {
+    for (let [key, tokenValue] of Object.entries(data)) {
       if (tokenValue.token == token) {
         delete data[key];
         // And a background save...
         this._persistCachedTokens();
         return tokenValue;
       }
     }
     return null;
@@ -708,17 +708,17 @@ FxAccountsInternal.prototype = {
       client_id: FX_OAUTH_CLIENT_ID
     });
     return client.destroyToken(tokenData.token)
   },
 
   _destroyAllOAuthTokens: function(tokenInfos) {
     // let's just destroy them all in parallel...
     let promises = [];
-    for (let [key, tokenInfo] in Iterator(tokenInfos || {})) {
+    for (let [key, tokenInfo] of Object.entries(tokenInfos || {})) {
       promises.push(this._destroyOAuthToken(tokenInfo));
     }
     return Promise.all(promises);
   },
 
   signOut: function signOut(localOnly) {
     let currentState = this.currentAccountState;
     let sessionToken;
--- a/services/fxaccounts/FxAccountsStorage.jsm
+++ b/services/fxaccounts/FxAccountsStorage.jsm
@@ -67,17 +67,17 @@ this.FxAccountsStorageManager.prototype 
 
   _initialize: Task.async(function* (accountData) {
     log.trace("initializing new storage manager");
     try {
       if (accountData) {
         // If accountData is passed we don't need to read any storage.
         this._needToReadSecure = false;
         // split it into the 2 parts, write it and we are done.
-        for (let [name, val] of Iterator(accountData)) {
+        for (let [name, val] of Object.entries(accountData)) {
           if (FXA_PWDMGR_PLAINTEXT_FIELDS.has(name)) {
             this.cachedPlain[name] = val;
           } else if (FXA_PWDMGR_SECURE_FIELDS.has(name)) {
             this.cachedSecure[name] = val;
           } else {
             // Hopefully it's an "in memory" field. If it's not we log a warning
             // but still treat it as such (so it will still be available in this
             // session but isn't persisted anywhere.)
@@ -151,25 +151,25 @@ this.FxAccountsStorageManager.prototype 
     // and doesn't need to be read (it was read if necessary by initialize).
     // So if there's no uid, there's no user signed in.
     if (!('uid' in this.cachedPlain)) {
       return null;
     }
     let result = {};
     if (fieldNames === null) {
       // The "old" deprecated way of fetching a logged in user.
-      for (let [name, value] of Iterator(this.cachedPlain)) {
+      for (let [name, value] of Object.entries(this.cachedPlain)) {
         result[name] = value;
       }
       // But the secure data may not have been read, so try that now.
       yield this._maybeReadAndUpdateSecure();
       // .cachedSecure now has as much as it possibly can (which is possibly
       // nothing if (a) secure storage remains locked and (b) we've never updated
       // a field to be stored in secure storage.)
-      for (let [name, value] of Iterator(this.cachedSecure)) {
+      for (let [name, value] of Object.entries(this.cachedSecure)) {
         result[name] = value;
       }
       // Note we don't return cachedMemory fields here - they must be explicitly
       // requested.
       return result;
     }
     // The new explicit way of getting attributes.
     if (!Array.isArray(fieldNames)) {
@@ -213,17 +213,17 @@ this.FxAccountsStorageManager.prototype 
     if (!newFields || 'uid' in newFields || 'email' in newFields) {
       // Once we support
       // user changing email address this may need to change, but it's not
       // clear how we would be told of such a change anyway...
       throw new Error("Can't change uid or email address");
     }
     log.debug("_updateAccountData with items", Object.keys(newFields));
     // work out what bucket.
-    for (let [name, value] of Iterator(newFields)) {
+    for (let [name, value] of Object.entries(newFields)) {
       if (FXA_PWDMGR_MEMORY_FIELDS.has(name)) {
         if (value == null) {
           delete this.cachedMemory[name];
         } else {
           this.cachedMemory[name] = value;
         }
       } else if (FXA_PWDMGR_PLAINTEXT_FIELDS.has(name)) {
         if (value == null) {
@@ -290,17 +290,17 @@ this.FxAccountsStorageManager.prototype 
     // We need to update our .cachedPlain, but can't just assign to it as
     // it may need to be the exact same object as .cachedSecure
     // As a sanity check, .cachedPlain must be empty (as we are called by init)
     // XXX - this would be a good use-case for a RuntimeAssert or similar, as
     // being added in bug 1080457.
     if (Object.keys(this.cachedPlain).length != 0) {
       throw new Error("should be impossible to have cached data already.")
     }
-    for (let [name, value] of Iterator(got.accountData)) {
+    for (let [name, value] of Object.entries(got.accountData)) {
       this.cachedPlain[name] = value;
     }
     return true;
   }),
 
   /* If we haven't managed to read the secure storage, try now, so
      we can merge our cached data with the data that's already been set.
   */
@@ -332,17 +332,17 @@ this.FxAccountsStorageManager.prototype 
       // wins (including the fact it may be null or undefined, the latter
       // which means it will be removed from storage.
       if (readSecure && readSecure.version != DATA_FORMAT_VERSION) {
         log.warn("got secure data but the data format version doesn't match");
         readSecure = null;
       }
       if (readSecure && readSecure.accountData) {
         log.debug("secure read fetched items", Object.keys(readSecure.accountData));
-        for (let [name, value] of Iterator(readSecure.accountData)) {
+        for (let [name, value] of Object.entries(readSecure.accountData)) {
           if (!(name in this.cachedSecure)) {
             this.cachedSecure[name] = value;
           }
         }
         if (needWrite) {
           log.debug("successfully read secure data; writing updated data back")
           yield this._doWriteSecure();
         }
@@ -385,17 +385,17 @@ this.FxAccountsStorageManager.prototype 
     }
   }),
 
   /* Do the actual write of secure data. Caller is expected to check if we actually
      need to write and to ensure we are in a queued storage operation.
   */
   _doWriteSecure: Task.async(function* () {
     // We need to remove null items here.
-    for (let [name, value] of Iterator(this.cachedSecure)) {
+    for (let [name, value] of Object.entries(this.cachedSecure)) {
       if (value == null) {
         delete this.cachedSecure[name];
       }
     }
     log.debug("writing secure storage", Object.keys(this.cachedSecure));
     let toWriteSecure = {
       version: DATA_FORMAT_VERSION,
       accountData: this.cachedSecure,
--- a/services/fxaccounts/tests/xpcshell/test_accounts.js
+++ b/services/fxaccounts/tests/xpcshell/test_accounts.js
@@ -65,17 +65,17 @@ MockStorageManager.prototype = {
     return Promise.resolve();
   },
 
   getAccountData() {
     return Promise.resolve(this.accountData);
   },
 
   updateAccountData(updatedFields) {
-    for (let [name, value] of Iterator(updatedFields)) {
+    for (let [name, value] of Object.entries(updatedFields)) {
       if (value == null) {
         delete this.accountData[name];
       } else {
         this.accountData[name] = value;
       }
     }
     return Promise.resolve();
   },
--- a/services/fxaccounts/tests/xpcshell/test_accounts_device_registration.js
+++ b/services/fxaccounts/tests/xpcshell/test_accounts_device_registration.js
@@ -41,17 +41,17 @@ MockStorageManager.prototype = {
     return Promise.resolve();
   },
 
   getAccountData() {
     return Promise.resolve(this.accountData);
   },
 
   updateAccountData(updatedFields) {
-    for (let [name, value] of Iterator(updatedFields)) {
+    for (let [name, value] of Object.entries(updatedFields)) {
       if (value == null) {
         delete this.accountData[name];
       } else {
         this.accountData[name] = value;
       }
     }
     return Promise.resolve();
   },
--- a/services/fxaccounts/tests/xpcshell/test_oauth_token_storage.js
+++ b/services/fxaccounts/tests/xpcshell/test_oauth_token_storage.js
@@ -36,17 +36,17 @@ MockStorageManager.prototype = {
     return Promise.resolve();
   },
 
   getAccountData() {
     return Promise.resolve(this.accountData);
   },
 
   updateAccountData(updatedFields) {
-    for (let [name, value] of Iterator(updatedFields)) {
+    for (let [name, value] of Object.entries(updatedFields)) {
       if (value == null) {
         delete this.accountData[name];
       } else {
         this.accountData[name] = value;
       }
     }
     return Promise.resolve();
   },
--- a/services/fxaccounts/tests/xpcshell/test_oauth_tokens.js
+++ b/services/fxaccounts/tests/xpcshell/test_oauth_tokens.js
@@ -35,17 +35,17 @@ MockStorageManager.prototype = {
     return Promise.resolve();
   },
 
   getAccountData() {
     return Promise.resolve(this.accountData);
   },
 
   updateAccountData(updatedFields) {
-    for (let [name, value] of Iterator(updatedFields)) {
+    for (let [name, value] of Object.entries(updatedFields)) {
       if (value == null) {
         delete this.accountData[name];
       } else {
         this.accountData[name] = value;
       }
     }
     return Promise.resolve();
   },
--- a/services/sync/modules-testing/rotaryengine.js
+++ b/services/sync/modules-testing/rotaryengine.js
@@ -110,15 +110,15 @@ RotaryEngine.prototype = {
 
   _findDupe: function _findDupe(item) {
     // This is a semaphore used for testing proper reconciling on dupe
     // detection.
     if (item.id == "DUPE_INCOMING") {
       return "DUPE_LOCAL";
     }
 
-    for (let [id, value] in Iterator(this._store.items)) {
+    for (let [id, value] of Object.entries(this._store.items)) {
       if (item.denomination == value) {
         return id;
       }
     }
   }
 };
--- a/services/sync/modules-testing/utils.js
+++ b/services/sync/modules-testing/utils.js
@@ -57,17 +57,17 @@ MockFxaStorageManager.prototype = {
     return Promise.resolve();
   },
 
   getAccountData() {
     return Promise.resolve(this.accountData);
   },
 
   updateAccountData(updatedFields) {
-    for (let [name, value] of Iterator(updatedFields)) {
+    for (let [name, value] of Object.entries(updatedFields)) {
       if (value == null) {
         delete this.accountData[name];
       } else {
         this.accountData[name] = value;
       }
     }
     return Promise.resolve();
   },
--- a/services/sync/modules/SyncedTabs.jsm
+++ b/services/sync/modules/SyncedTabs.jsm
@@ -108,17 +108,17 @@ let SyncedTabsInternal = {
     const showRemoteIcons = Preferences.get("services.sync.syncedTabs.showRemoteIcons", true);
 
     let engine = Weave.Service.engineManager.get("tabs");
 
     let seenURLs = new Set();
     let parentIndex = 0;
     let ntabs = 0;
 
-    for (let [guid, client] in Iterator(engine.getAllClients())) {
+    for (let [guid, client] of Object.entries(engine.getAllClients())) {
       if (!Weave.Service.clientsEngine.remoteClientExists(client.id)) {
         continue;
       }
       let clientRepr = yield this._makeClient(client);
       log.debug("Processing client", clientRepr);
 
       for (let tab of client.tabs) {
         let url = tab.urlHistory[0];
--- a/services/sync/modules/addonsreconciler.js
+++ b/services/sync/modules/addonsreconciler.js
@@ -242,19 +242,19 @@ AddonsReconciler.prototype = {
    * @param  callback
    *         Function to be invoked on save completion. No parameters will be
    *         passed to callback.
    */
   saveState: function saveState(path, callback) {
     let file = path || DEFAULT_STATE_FILE;
     let state = {version: 1, addons: {}, changes: []};
 
-    for (let [id, record] in Iterator(this._addons)) {
+    for (let [id, record] of Object.entries(this._addons)) {
       state.addons[id] = {};
-      for (let [k, v] in Iterator(record)) {
+      for (let [k, v] of Object.entries(record)) {
         if (k == "modified") {
           state.addons[id][k] = v.getTime();
         }
         else {
           state.addons[id][k] = v;
         }
       }
     }
@@ -353,17 +353,17 @@ AddonsReconciler.prototype = {
 
       for (let addon of addons) {
         ids[addon.id] = true;
         this.rectifyStateFromAddon(addon);
       }
 
       // Look for locally-defined add-ons that no longer exist and update their
       // record.
-      for (let [id, addon] in Iterator(this._addons)) {
+      for (let [id, addon] of Object.entries(this._addons)) {
         if (id in ids) {
           continue;
         }
 
         // If the id isn't in ids, it means that the add-on has been deleted or
         // the add-on is in the process of being installed. We detect the
         // latter by seeing if an AddonInstall is found for this add-on.
 
--- a/services/sync/modules/constants.js
+++ b/services/sync/modules/constants.js
@@ -1,16 +1,16 @@
 #filter substitution
 /* 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/. */
 
 // Process each item in the "constants hash" to add to "global" and give a name
 this.EXPORTED_SYMBOLS = [];
-for (let [key, val] in Iterator({
+for (let [key, val] of Object.entries({
 
 WEAVE_VERSION:                         "@weave_version@",
 
 // Sync Server API version that the client supports.
 SYNC_API_VERSION:                      "1.1",
 USER_API_VERSION:                      "1.0",
 MISC_API_VERSION:                      "1.0",
 
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -482,17 +482,17 @@ EngineManager.prototype = {
         this._log.debug("Engines are: " + JSON.stringify(Object.keys(this._engines)));
       }
     }
     return engine;
   },
 
   getAll: function () {
     let engines = [];
-    for (let [name, engine] in Iterator(this._engines)) {
+    for (let [, engine] of Object.entries(this._engines)) {
       engines.push(engine);
     }
     return engines;
   },
 
   /**
    * N.B., does not pay attention to the declined list.
    */
@@ -1518,17 +1518,17 @@ SyncEngine.prototype = {
     this._tracker.resetScore();
 
     let doDelete = Utils.bind2(this, function(key, val) {
       let coll = new Collection(this.engineURL, this._recordObj, this.service);
       coll[key] = val;
       coll.delete();
     });
 
-    for (let [key, val] in Iterator(this._delete)) {
+    for (let [key, val] of Object.entries(this._delete)) {
       // Remove the key for future uses
       delete this._delete[key];
 
       // Send a simple delete for the property
       if (key != "ids" || val.length <= 100)
         doDelete(key, val);
       else {
         // For many ids, split into chunks of at most 100
@@ -1541,17 +1541,17 @@ SyncEngine.prototype = {
   },
 
   _syncCleanup: function () {
     if (!this._modified) {
       return;
     }
 
     // Mark failed WBOs as changed again so they are reuploaded next time.
-    for (let [id, when] in Iterator(this._modified)) {
+    for (let [id, when] of Object.entries(this._modified)) {
       this._tracker.addChangedID(id, when);
     }
     this._modified = {};
   },
 
   _sync: function () {
     try {
       this._syncStartup();
--- a/services/sync/modules/engines/addons.js
+++ b/services/sync/modules/engines/addons.js
@@ -148,17 +148,17 @@ AddonsEngine.prototype = {
   },
 
   /**
    * Override getChangedIDs to pull in tracker changes plus changes from the
    * reconciler log.
    */
   getChangedIDs: function getChangedIDs() {
     let changes = {};
-    for (let [id, modified] in Iterator(this._tracker.changedIDs)) {
+    for (let [id, modified] of Object.entries(this._tracker.changedIDs)) {
       changes[id] = modified;
     }
 
     let lastSyncDate = new Date(this.lastSync * 1000);
 
     // The reconciler should have been refreshed at the beginning of a sync and
     // we assume this function is only called from within a sync.
     let reconcilerChanges = this._reconciler.getChangesSinceDate(lastSyncDate);
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -843,17 +843,17 @@ BookmarksStore.prototype = {
     this._log.trace("Updating " + record.id + " (" + itemId + ")");
 
     // Move the bookmark to a new parent or new position if necessary
     if (record._parent > 0 &&
         PlacesUtils.bookmarks.getFolderIdForItem(itemId) != record._parent) {
       this._reparentItem(itemId, record._parent);
     }
 
-    for (let [key, val] in Iterator(record.cleartext)) {
+    for (let [key, val] of Object.entries(record.cleartext)) {
       switch (key) {
       case "title":
         PlacesUtils.bookmarks.setItemTitle(itemId, val);
         break;
       case "bmkUri":
         PlacesUtils.bookmarks.changeBookmarkURI(itemId, Utils.makeURI(val));
         break;
       case "tags":
@@ -891,17 +891,17 @@ BookmarksStore.prototype = {
           itemId, BookmarkAnnos.SMART_BOOKMARKS_ANNO, val, 0,
           PlacesUtils.annotations.EXPIRE_NEVER);
         break;
       }
     }
   },
 
   _orderChildren: function _orderChildren() {
-    for (let [guid, children] in Iterator(this._childrenToOrder)) {
+    for (let [guid, children] of Object.entries(this._childrenToOrder)) {
       // Reorder children according to the GUID list. Gracefully deal
       // with missing items, e.g. locally deleted.
       let delta = 0;
       let parent = null;
       for (let idx = 0; idx < children.length; idx++) {
         let itemid = this.idForGUID(children[idx]);
         if (itemid == -1) {
           delta += 1;
--- a/services/sync/modules/engines/clients.js
+++ b/services/sync/modules/engines/clients.js
@@ -461,17 +461,17 @@ ClientEngine.prototype = {
       this._log.error("Expected " + commandData.args + " args for '" +
                       command + "', but got " + args);
       return;
     }
 
     if (clientId) {
       this._sendCommandToClient(command, args, clientId);
     } else {
-      for (let [id, record] in Iterator(this._store._remoteClients)) {
+      for (let [id, record] of Object.entries(this._store._remoteClients)) {
         if (!record.stale) {
           this._sendCommandToClient(command, args, id);
         }
       }
     }
   },
 
   /**
--- a/services/sync/modules/record.js
+++ b/services/sync/modules/record.js
@@ -81,17 +81,17 @@ WBORecord.prototype = {
       // The payload is likely to be JSON, but if not, keep it as a string
       this.payload = JSON.parse(this.payload);
     } catch(ex) {}
   },
 
   toJSON: function toJSON() {
     // Copy fields from data to be stringified, making sure payload is a string
     let obj = {};
-    for (let [key, val] in Iterator(this.data))
+    for (let [key, val] of Object.entries(this.data))
       obj[key] = key == "payload" ? JSON.stringify(val) : val;
     if (this.ttl)
       obj.ttl = this.ttl;
     return obj;
   },
 
   toString: function toString() {
     return "{ " +
--- a/services/sync/modules/resource.js
+++ b/services/sync/modules/resource.js
@@ -150,25 +150,25 @@ AsyncResource.prototype = {
       channel.setRequestHeader("user-agent", Utils.userAgent, false);
     }
 
     let headers = this.headers;
 
     if (this.authenticator) {
       let result = this.authenticator(this, method);
       if (result && result.headers) {
-        for (let [k, v] in Iterator(result.headers)) {
+        for (let [k, v] of Object.entries(result.headers)) {
           headers[k.toLowerCase()] = v;
         }
       }
     } else {
       this._log.debug("No authenticator found.");
     }
 
-    for (let [key, value] in Iterator(headers)) {
+    for (let [key, value] of Object.entries(headers)) {
       if (key == 'authorization')
         this._log.trace("HTTP Header " + key + ": ***** (suppressed)");
       else
         this._log.trace("HTTP Header " + key + ": " + headers[key]);
       channel.setRequestHeader(key, headers[key], false);
     }
     return channel;
   },
--- a/services/sync/tests/unit/head_http_server.js
+++ b/services/sync/tests/unit/head_http_server.js
@@ -174,17 +174,17 @@ ServerCollection.prototype = {
    * @param filter
    *        A predicate function (applied to the ID and WBO) which dictates
    *        whether to include the WBO's ID in the output.
    *
    * @return an array of IDs.
    */
   keys: function keys(filter) {
     let ids = [];
-    for (let [id, wbo] in Iterator(this._wbos)) {
+    for (let [id, wbo] of Object.entries(this._wbos)) {
       if (wbo.payload && (!filter || filter(id, wbo))) {
         ids.push(id);
       }
     }
     return ids;
   },
 
   /**
@@ -194,17 +194,17 @@ ServerCollection.prototype = {
    * @param filter
    *        A predicate function, applied to the WBO, which dictates whether to
    *        include the WBO in the output.
    *
    * @return an array of ServerWBOs.
    */
   wbos: function wbos(filter) {
     let os = [];
-    for (let [id, wbo] in Iterator(this._wbos)) {
+    for (let [id, wbo] of Object.entries(this._wbos)) {
       if (wbo.payload) {
         os.push(wbo);
       }
     }
 
     if (filter) {
       return os.filter(filter);
     }
@@ -271,45 +271,45 @@ ServerCollection.prototype = {
     return wbo.payload
            && (!options.ids || (options.ids.indexOf(wbo.id) != -1))
            && (!options.newer || (wbo.modified > options.newer));
   },
 
   count: function(options) {
     options = options || {};
     let c = 0;
-    for (let [id, wbo] in Iterator(this._wbos)) {
+    for (let [id, wbo] of Object.entries(this._wbos)) {
       if (wbo.modified && this._inResultSet(wbo, options)) {
         c++;
       }
     }
     return c;
   },
 
   get: function(options) {
     let result;
     if (options.full) {
       let data = [];
-      for (let [id, wbo] in Iterator(this._wbos)) {
+      for (let [id, wbo] of Object.entries(this._wbos)) {
         // Drop deleted.
         if (wbo.modified && this._inResultSet(wbo, options)) {
           data.push(wbo.get());
         }
       }
       if (options.limit) {
         data = data.slice(0, options.limit);
       }
       // Our implementation of application/newlines.
       result = data.join("\n") + "\n";
 
       // Use options as a backchannel to report count.
       options.recordCount = data.length;
     } else {
       let data = [];
-      for (let [id, wbo] in Iterator(this._wbos)) {
+      for (let [id, wbo] of Object.entries(this._wbos)) {
         if (this._inResultSet(wbo, options)) {
           data.push(id);
         }
       }
       if (options.limit) {
         data = data.slice(0, options.limit);
       }
       result = JSON.stringify(data);
@@ -344,17 +344,17 @@ ServerCollection.prototype = {
     }
     return {modified: new_timestamp(),
             success: success,
             failed: failed};
   },
 
   delete: function(options) {
     let deleted = [];
-    for (let [id, wbo] in Iterator(this._wbos)) {
+    for (let [id, wbo] of Object.entries(this._wbos)) {
       if (this._inResultSet(wbo, options)) {
         this._log.debug("Deleting " + JSON.stringify(wbo));
         deleted.push(wbo.id);
         wbo.delete();
       }
     }
     return deleted;
   },
@@ -679,20 +679,20 @@ SyncServer.prototype = {
    * If a collection already exists, no error is raised.
    * If a WBO already exists, it will be updated to the new contents.
    */
   createContents: function createContents(username, collections) {
     if (!(username in this.users)) {
       throw new Error("Unknown user.");
     }
     let userCollections = this.users[username].collections;
-    for (let [id, contents] in Iterator(collections)) {
+    for (let [id, contents] of Object.entries(collections)) {
       let coll = userCollections[id] ||
                  this._insertCollection(userCollections, id);
-      for (let [wboID, payload] in Iterator(contents)) {
+      for (let [wboID, payload] of Object.entries(contents)) {
         coll.insert(wboID, payload);
       }
     }
   },
 
   /**
    * Insert a WBO in an existing collection.
    */
@@ -1011,15 +1011,15 @@ SyncServer.prototype = {
   }
 };
 
 /**
  * Test helper.
  */
 function serverForUsers(users, contents, callback) {
   let server = new SyncServer(callback);
-  for (let [user, pass] in Iterator(users)) {
+  for (let [user, pass] of Object.entries(users)) {
     server.registerUser(user, pass);
     server.createContents(user, contents);
   }
   server.start();
   return server;
 }
--- a/services/sync/tests/unit/test_syncedtabs.js
+++ b/services/sync/tests/unit/test_syncedtabs.js
@@ -65,17 +65,17 @@ let weaveXPCService = Cc["@mozilla.org/w
                         .getService(Ci.nsISupports)
                         .wrappedJSObject;
 weaveXPCService.ready = true;
 
 function configureClients(clients, clientSettings = {}) {
   // Configure the instance Sync created.
   let engine = Weave.Service.engineManager.get("tabs");
   // each client record is expected to have an id.
-  for (let [guid, client] in Iterator(clients)) {
+  for (let [guid, client] of Object.entries(clients)) {
     client.id = guid;
   }
   engine.clients = clients;
   // Apply clients collection overrides.
   MockClientsEngine.clientSettings = clientSettings;
   // Send an observer that pretends the engine just finished a sync.
   Services.obs.notifyObservers(null, "weave:engine:sync:finish", "tabs");
 }
--- a/services/sync/tps/extensions/tps/resource/modules/tabs.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/tabs.jsm
@@ -44,17 +44,17 @@ var BrowserTabs = {
    * @param uri The uri of the tab to find
    * @param title The page title of the tab to find
    * @param profile The profile to search for tabs
    * @return true if the specified tab could be found, otherwise false
    */
   Find: function(uri, title, profile) {
     // Find the uri in Weave's list of tabs for the given profile.
     let engine = Weave.Service.engineManager.get("tabs");
-    for (let [guid, client] in Iterator(engine.getAllClients())) {
+    for (let [guid, client] of Object.entries(engine.getAllClients())) {
       if (!client.tabs) {
         continue;
       }
       for (let key in client.tabs) {
         let tab = client.tabs[key];
         let weaveTabUrl = tab.urlHistory[0];
         if (uri == weaveTabUrl && profile == client.clientName)
           if (title == undefined || title == tab.title)