Bug 1265526 - Correctly categorize blob URLs and wasm frames as user content; r?julienw draft
authorGreg Tatum <tatum.creative@gmail.com>
Fri, 26 May 2017 18:07:56 -0500
changeset 590409 76b4fa4330ba4d696ac884bf12d4566071767af9
parent 584507 f7adbf457ee20eeffde72694e0d17d73616e3cfd
child 632239 df81f354fa52966e97d07f2a39c3817eff44e44e
push id62757
push userbmo:gtatum@mozilla.com
push dateWed, 07 Jun 2017 20:15:53 +0000
reviewersjulienw
bugs1265526
milestone55.0a1
Bug 1265526 - Correctly categorize blob URLs and wasm frames as user content; r?julienw asm.js and wasm frames were not being correctly identified as user content in the perf devtool. This patch correctly finds blob urls that were being mis-identified as platform content, and wasm frames, which do not have any identifying information other than their function name containing wasm-function. MozReview-Commit-ID: 4DjqATCKBK0
devtools/client/performance/modules/logic/frame-utils.js
devtools/client/shared/source-utils.js
devtools/client/shared/test/unit/test_source-utils.js
--- a/devtools/client/performance/modules/logic/frame-utils.js
+++ b/devtools/client/performance/modules/logic/frame-utils.js
@@ -1,17 +1,17 @@
 /* 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 global = require("devtools/client/performance/modules/global");
 const demangle = require("devtools/client/shared/demangle");
 const { assert } = require("devtools/shared/DevToolsUtils");
-const { isChromeScheme, isContentScheme, parseURL } =
+const { isChromeScheme, isContentScheme, isWASM, parseURL } =
   require("devtools/client/shared/source-utils");
 
 const { CATEGORY_MASK, CATEGORY_MAPPINGS } = require("devtools/client/performance/modules/categories");
 
 // Character codes used in various parsing helper functions.
 const CHAR_CODE_R = "r".charCodeAt(0);
 const CHAR_CODE_0 = "0".charCodeAt(0);
 const CHAR_CODE_9 = "9".charCodeAt(0);
@@ -216,17 +216,19 @@ function computeIsContentAndCategory(fra
         break;
       }
     }
   } else {
     // Cases 2) and 3)
     schemeStartIndex = 0;
   }
 
-  if (isContentScheme(location, schemeStartIndex)) {
+  // We can't know if WASM frames are content or not at the time of this writing, so label
+  // them all as content.
+  if (isContentScheme(location, schemeStartIndex) || isWASM(location)) {
     frame.isContent = true;
     return;
   }
 
   if (schemeStartIndex !== 0) {
     for (let j = schemeStartIndex; j < location.length; j++) {
       if (location.charCodeAt(j) === CHAR_CODE_R &&
           isChromeScheme(location, j) &&
--- a/devtools/client/shared/source-utils.js
+++ b/devtools/client/shared/source-utils.js
@@ -5,32 +5,37 @@
 
 const { LocalizationHelper } = require("devtools/shared/l10n");
 
 const l10n = new LocalizationHelper("devtools/client/locales/components.properties");
 const UNKNOWN_SOURCE_STRING = l10n.getStr("frame.unknownSource");
 
 // Character codes used in various parsing helper functions.
 const CHAR_CODE_A = "a".charCodeAt(0);
+const CHAR_CODE_B = "b".charCodeAt(0);
 const CHAR_CODE_C = "c".charCodeAt(0);
 const CHAR_CODE_D = "d".charCodeAt(0);
 const CHAR_CODE_E = "e".charCodeAt(0);
 const CHAR_CODE_F = "f".charCodeAt(0);
 const CHAR_CODE_H = "h".charCodeAt(0);
 const CHAR_CODE_I = "i".charCodeAt(0);
 const CHAR_CODE_J = "j".charCodeAt(0);
 const CHAR_CODE_L = "l".charCodeAt(0);
 const CHAR_CODE_M = "m".charCodeAt(0);
+const CHAR_CODE_N = "n".charCodeAt(0);
 const CHAR_CODE_O = "o".charCodeAt(0);
 const CHAR_CODE_P = "p".charCodeAt(0);
 const CHAR_CODE_R = "r".charCodeAt(0);
 const CHAR_CODE_S = "s".charCodeAt(0);
 const CHAR_CODE_T = "t".charCodeAt(0);
 const CHAR_CODE_U = "u".charCodeAt(0);
+const CHAR_CODE_W = "w".charCodeAt(0);
 const CHAR_CODE_COLON = ":".charCodeAt(0);
+const CHAR_CODE_DASH = "-".charCodeAt(0);
+const CHAR_CODE_L_SQUARE_BRACKET = "[".charCodeAt(0);
 const CHAR_CODE_SLASH = "/".charCodeAt(0);
 const CHAR_CODE_CAP_S = "S".charCodeAt(0);
 
 // The cache used in the `parseURL` function.
 const gURLStore = new Map();
 // The cache used in the `getSourceNames` function.
 const gSourceNamesStore = new Map();
 
@@ -243,16 +248,28 @@ function isContentScheme(location, i = 0
     // "app://"
     case CHAR_CODE_A:
       if (location.charCodeAt(++i) == CHAR_CODE_P &&
           location.charCodeAt(++i) == CHAR_CODE_P) {
         return isColonSlashSlash(location, i);
       }
       return false;
 
+    // "blob:"
+    case CHAR_CODE_B:
+      if (
+        location.charCodeAt(++i) == CHAR_CODE_L &&
+        location.charCodeAt(++i) == CHAR_CODE_O &&
+        location.charCodeAt(++i) == CHAR_CODE_B &&
+        location.charCodeAt(++i) == CHAR_CODE_COLON
+      ) {
+        return isContentScheme(location, i + 1);
+      }
+      return false;
+
     default:
       return false;
   }
 }
 
 function isChromeScheme(location, i = 0) {
   let firstChar = location.charCodeAt(i);
 
@@ -294,16 +311,36 @@ function isChromeScheme(location, i = 0)
       }
       return false;
 
     default:
       return false;
   }
 }
 
+function isWASM(location, i = 0) {
+  return (
+    // "wasm-function["
+    location.charCodeAt(i) === CHAR_CODE_W &&
+    location.charCodeAt(++i) === CHAR_CODE_A &&
+    location.charCodeAt(++i) === CHAR_CODE_S &&
+    location.charCodeAt(++i) === CHAR_CODE_M &&
+    location.charCodeAt(++i) === CHAR_CODE_DASH &&
+    location.charCodeAt(++i) === CHAR_CODE_F &&
+    location.charCodeAt(++i) === CHAR_CODE_U &&
+    location.charCodeAt(++i) === CHAR_CODE_N &&
+    location.charCodeAt(++i) === CHAR_CODE_C &&
+    location.charCodeAt(++i) === CHAR_CODE_T &&
+    location.charCodeAt(++i) === CHAR_CODE_I &&
+    location.charCodeAt(++i) === CHAR_CODE_O &&
+    location.charCodeAt(++i) === CHAR_CODE_N &&
+    location.charCodeAt(++i) === CHAR_CODE_L_SQUARE_BRACKET
+  );
+}
+
 /**
  * A utility method to get the file name from a sourcemapped location
  * The sourcemap location can be in any form. This method returns a
  * formatted file name for different cases like Windows or OSX.
  * @param source
  * @returns String
  */
 function getSourceMappedFile(source) {
@@ -319,10 +356,11 @@ function getSourceMappedFile(source) {
   return source;
 }
 
 exports.parseURL = parseURL;
 exports.getSourceNames = getSourceNames;
 exports.isScratchpadScheme = isScratchpadScheme;
 exports.isChromeScheme = isChromeScheme;
 exports.isContentScheme = isContentScheme;
+exports.isWASM = isWASM;
 exports.isDataScheme = isDataScheme;
 exports.getSourceMappedFile = getSourceMappedFile;
--- a/devtools/client/shared/test/unit/test_source-utils.js
+++ b/devtools/client/shared/test/unit/test_source-utils.js
@@ -14,17 +14,18 @@ function run_test() {
   run_next_test();
 }
 
 const CHROME_URLS = [
   "chrome://foo", "resource://baz", "jar:file:///Users/root"
 ];
 
 const CONTENT_URLS = [
-  "http://mozilla.org", "https://mozilla.org", "file:///Users/root", "app://fxosapp"
+  "http://mozilla.org", "https://mozilla.org", "file:///Users/root", "app://fxosapp",
+  "blob:http://mozilla.org", "blob:https://mozilla.org"
 ];
 
 // Test `sourceUtils.parseURL`
 add_task(function* () {
   let parsed = sourceUtils.parseURL("https://foo.com:8888/boo/bar.js?q=query");
   equal(parsed.fileName, "bar.js", "parseURL parsed valid fileName");
   equal(parsed.host, "foo.com:8888", "parseURL parsed valid host");
   equal(parsed.hostname, "foo.com", "parseURL parsed valid hostname");
@@ -56,16 +57,23 @@ add_task(function* () {
     ok(sourceUtils.isChromeScheme(url), `${url} correctly identified as chrome scheme`);
   }
   for (let url of CONTENT_URLS) {
     ok(!sourceUtils.isChromeScheme(url),
        `${url} correctly identified as not chrome scheme`);
   }
 });
 
+// Test `sourceUtils.isWASM`.
+add_task(function* () {
+  ok(sourceUtils.isWASM("wasm-function[66240] (?:13870536)"),
+                        "wasm function correctly identified");
+  ok(!sourceUtils.isWASM(CHROME_URLS[0]), `A chrome url does not identify as wasm.`);
+});
+
 // Test `sourceUtils.isDataScheme`.
 add_task(function* () {
   let dataURI = "data:text/html;charset=utf-8,<!DOCTYPE html></html>";
   ok(sourceUtils.isDataScheme(dataURI), `${dataURI} correctly identified as data scheme`);
 
   for (let url of CHROME_URLS) {
     ok(!sourceUtils.isDataScheme(url), `${url} correctly identified as not data scheme`);
   }