Bug 1370752: Part 2 - Allow fallback serializer when JSON.serialize fails. r=aswan
☠☠ backed out by 43fca39fe75c ☠ ☠
authorKris Maglione <maglione.k@gmail.com>
Fri, 09 Jun 2017 18:19:11 -0700
changeset 368047 9c4bf59ab966a8ec17181d85cc1fc4be7450cca3
parent 368046 bc535203a6eff61f308eb8ddf13afe8268cccb9f
child 368048 42d3c1599af53b047d7ccd6b1c92ab08975284d7
push id92393
push usermaglione.k@gmail.com
push dateMon, 10 Jul 2017 19:25:58 +0000
treeherdermozilla-inbound@42d3c1599af5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaswan
bugs1370752
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1370752: Part 2 - Allow fallback serializer when JSON.serialize fails. r=aswan Currently, we need to be able to handle serializing non-JSON-compatible objects without catastrophically failing to save the storage file. Ideally, we would ensure this in the ordinary toJSON method. However, that would require a unnecessary extra calls to JSON.stringify for each object that needs to be sanitized before returning a JSON-safe value, which is more expensive than we can afford. The fallback toJSONSafe method allows us to do this only when necessary, due to an initial failed JSON serialization. MozReview-Commit-ID: JXQ001dOGtW
toolkit/modules/JSONFile.jsm
--- a/toolkit/modules/JSONFile.jsm
+++ b/toolkit/modules/JSONFile.jsm
@@ -281,18 +281,30 @@ JSONFile.prototype = {
    *
    * If an error occurs, the previous file is not deleted.
    *
    * @return {Promise}
    * @resolves When the operation finished successfully.
    * @rejects JavaScript exception.
    */
   async _save() {
+    let json;
+    try {
+      json = JSON.stringify(this._data);
+    } catch (e) {
+      // If serialization fails, try fallback safe JSON converter.
+      if (typeof this._data.toJSONSafe == "function") {
+        json = JSON.stringify(this._data.toJSONSafe());
+      } else {
+        throw e;
+      }
+    }
+
     // Create or overwrite the file.
-    let bytes = gTextEncoder.encode(JSON.stringify(this._data));
+    let bytes = gTextEncoder.encode(json);
     if (this._beforeSave) {
       await Promise.resolve(this._beforeSave());
     }
     await OS.File.writeAtomic(this.path, bytes,
                               Object.assign(
                                 { tmpPath: this.path + ".tmp" },
                                 this._options));
   },