Bug 1300336 - Allow pseudo-arrays to have a length property. r=fitzgen
authorOriol <oriol-bugzilla@hotmail.com>
Sat, 03 Sep 2016 12:46:00 -0400
changeset 313006 99c542fa43a72ee863c813b5624048d1b443549b
parent 313005 16a1a91f9269ab95dd83eb29dc5d0227665f7d94
child 313007 a6b6a93eb41a05e310a11f0172f01ba9b21d3eac
push id81509
push usercbook@mozilla.com
push dateWed, 07 Sep 2016 15:23:10 +0000
treeherdermozilla-inbound@80dccdd8c94a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfitzgen
bugs1300336
milestone51.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 1300336 - Allow pseudo-arrays to have a length property. r=fitzgen
devtools/client/webconsole/test/browser_webconsole_output_06.js
devtools/server/actors/object.js
--- a/devtools/client/webconsole/test/browser_webconsole_output_06.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_06.js
@@ -106,38 +106,40 @@ var inputTests = [
     variablesViewLabel: "Array[6]"
   },
 
   // 12 - array with long strings as elements
   {
     input: '["' + testStrIn + '", "' + testStrIn + '", "' + testStrIn + '"]',
     output: 'Array [ "' + testStrOut + '", "' + testStrOut + '", "' +
             testStrOut + '" ]',
-    inspectable: false,
+    inspectable: true,
     printOutput: "SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\nLINE ONLY. ESCAPE " +
                  "ALL NEWLINE,SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\nLINE ONLY. " +
                  "ESCAPE ALL NEWLINE,SHOW\nALL\nOF\nTHIS\nON\nA\nSINGLE\n" +
                  "LINE ONLY. ESCAPE ALL NEWLINE",
     variablesViewLabel: "Array[3]"
   },
 
   // 13
   {
     input: '({0: "a", 1: "b"})',
     output: 'Object [ "a", "b" ]',
     printOutput: "[object Object]",
-    inspectable: false,
+    inspectable: true,
+    variablesViewLabel: "Object[2]",
   },
 
   // 14
   {
     input: '({0: "a", 42: "b"})',
     output: 'Object { 0: "a", 42: "b" }',
     printOutput: "[object Object]",
-    inspectable: false,
+    inspectable: true,
+    variablesViewLabel: "Object",
   },
 
   // 15
   {
     input: '({0: "a", 1: "b", 2: "c", 3: "d", 4: "e", 5: "f", 6: "g", ' +
            '7: "h", 8: "i", 9: "j", 10: "k", 11: "l"})',
     output: 'Object [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", ' +
             "2 more\u2026 ]",
@@ -160,16 +162,106 @@ var inputTests = [
   // 17
   {
     input: '({" ": "a"})',
     output: 'Object {  : "a" }',
     printOutput: "[object Object]",
     inspectable: true,
     variablesViewLabel: "Object",
   },
+
+  // 18
+  {
+    input: '({})',
+    output: 'Object {  }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 19
+  {
+    input: '({length: 0})',
+    output: 'Object [  ]',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object[0]",
+  },
+
+  // 20
+  {
+    input: '({length: 1})',
+    output: 'Object { length: 1 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 21
+  {
+    input: '({0: "a", 1: "b", length: 1})',
+    output: 'Object { 1: "b", length: 1, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 22
+  {
+    input: '({0: "a", 1: "b", length: 2})',
+    output: 'Object [ "a", "b" ]',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object[2]",
+  },
+
+  // 23
+  {
+    input: '({0: "a", 1: "b", length: 3})',
+    output: 'Object { length: 3, 2 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 24
+  {
+    input: '({0: "a", 2: "b", length: 2})',
+    output: 'Object { 2: "b", length: 2, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 25
+  {
+    input: '({0: "a", 2: "b", length: 3})',
+    output: 'Object { length: 3, 2 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 26
+  {
+    input: '({0: "a", b: "b", length: 1})',
+    output: 'Object { b: "b", length: 1, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
+
+  // 27
+  {
+    input: '({0: "a", b: "b", length: 2})',
+    output: 'Object { b: "b", length: 2, 1 more\u2026 }',
+    printOutput: "[object Object]",
+    inspectable: true,
+    variablesViewLabel: "Object",
+  },
 ];
 
 function test() {
   requestLongerTimeout(2);
   Task.spawn(function* () {
     let {tab} = yield loadTab(TEST_URI);
     let hud = yield openConsole(tab);
     return checkOutputForInputs(hud, inputTests);
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -1795,23 +1795,37 @@ DebuggerServer.ObjectActorPreviewers.Obj
   function PseudoArray({obj, hooks}, grip, rawObj) {
     let length = 0;
 
     let keys = obj.getOwnPropertyNames();
     if (keys.length == 0) {
       return false;
     }
 
-    // Making sure that all keys are array indices, that is:
-    // `ToString(ToUint32(key)) === key  &&  key !== "4294967295"`.
-    // Also ensuring that the keys are consecutive and start at "0",
-    // this implies checking `key !== "4294967295"` is not necessary.
+    // Pseudo-arrays should only have array indices and, optionally, a "length" property.
+    // Since array indices are sorted first, check if the last property is "length".
+    if(keys[keys.length-1] === "length") {
+      keys.pop();
+      // The value of "length" should equal the number of other properties. If eventually
+      // we allow sparse pseudo-arrays, we should check whether it's a Uint32 instead.
+      if(rawObj.length !== keys.length) {
+        return false;
+      }
+    }
+
+    // Ensure that the keys are consecutive integers starting at "0". If eventually we
+    // allow sparse pseudo-arrays, we should check that they are array indices, that is:
+    // `(key >>> 0) + '' === key && key !== "4294967295"`.
+    // Checking the last property first allows us to avoid useless iterations when
+    // there is any property which is not an array index.
+    if(keys.length && keys[keys.length-1] !== keys.length - 1 + '') {
+      return false;
+    }
     for (let key of keys) {
-      let numKey = key >>> 0; // ToUint32(key)
-      if (numKey + '' != key || numKey != length++) {
+      if (key !== (length++) + '') {
         return false;
       }
     }
 
     grip.preview = {
       kind: "ArrayLike",
       length: length,
     };