Web Inspector: ES6: Improved Support for Iterator Objects
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 7 Mar 2015 04:02:53 +0000 (04:02 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 7 Mar 2015 04:02:53 +0000 (04:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142420

Patch by Joseph Pecoraro <pecoraro@apple.com> on 2015-03-06
Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

* inspector/protocol/Runtime.json:
Add new object subtype "iterator" for built-in iterator objects.

* inspector/InjectedScriptSource.js:
Return iterator values as Entry objects.

* inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::subtype):
Identify "iterator" typed objects.

(Inspector::JSInjectedScriptHost::getInternalProperties):
Provide internal properties for the different Iterator objects.

(Inspector::JSInjectedScriptHost::iteratorEntries):
Fetch the next few iterator entries of a built-in iterator object.

* inspector/JSInjectedScriptHost.h:
* inspector/JSInjectedScriptHostPrototype.cpp:
(Inspector::JSInjectedScriptHostPrototype::finishCreation):
(Inspector::jsInjectedScriptHostPrototypeFunctionIteratorEntries):
Call through to JSInjectedScriptHost.

* runtime/JSArgumentsIterator.cpp:
(JSC::JSArgumentsIterator::clone):
* runtime/JSArgumentsIterator.h:
(JSC::JSArgumentsIterator::iteratedValue):
* runtime/JSArrayIterator.cpp:
(JSC::JSArrayIterator::kind):
(JSC::JSArrayIterator::iteratedValue):
(JSC::JSArrayIterator::clone):
* runtime/JSArrayIterator.h:
* runtime/JSMapIterator.cpp:
(JSC::JSMapIterator::finishCreation):
(JSC::JSMapIterator::clone):
* runtime/JSMapIterator.h:
(JSC::JSMapIterator::kind):
(JSC::JSMapIterator::iteratedValue):
* runtime/JSSetIterator.cpp:
(JSC::JSSetIterator::finishCreation):
(JSC::JSSetIterator::clone):
* runtime/JSSetIterator.h:
(JSC::JSSetIterator::kind):
(JSC::JSSetIterator::iteratedValue):
* runtime/JSStringIterator.cpp:
(JSC::JSStringIterator::iteratedValue):
(JSC::JSStringIterator::clone):
* runtime/JSStringIterator.h:
Add accessors for internal properties and provide a way to clone the
iterator so we can be at the same index and peek at the next few
objects without modifying the original iterator object.

Source/WebInspectorUI:

* UserInterface/Views/ConsoleMessageImpl.js:
(WebInspector.ConsoleMessageImpl):
Treat an iterator like an object.

* UserInterface/Views/ObjectPreviewView.js:
Output iterator previews with []s, not {}s.

LayoutTests:

* inspector/model/remote-object.html:
Update tests to include iterator objects.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181203 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/model/remote-object-expected.txt
LayoutTests/inspector/model/remote-object.html
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/InjectedScriptSource.js
Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp
Source/JavaScriptCore/inspector/JSInjectedScriptHost.h
Source/JavaScriptCore/inspector/JSInjectedScriptHostPrototype.cpp
Source/JavaScriptCore/inspector/protocol/Runtime.json
Source/JavaScriptCore/runtime/JSArgumentsIterator.cpp
Source/JavaScriptCore/runtime/JSArgumentsIterator.h
Source/JavaScriptCore/runtime/JSArrayIterator.cpp
Source/JavaScriptCore/runtime/JSArrayIterator.h
Source/JavaScriptCore/runtime/JSMapIterator.cpp
Source/JavaScriptCore/runtime/JSMapIterator.h
Source/JavaScriptCore/runtime/JSSetIterator.cpp
Source/JavaScriptCore/runtime/JSSetIterator.h
Source/JavaScriptCore/runtime/JSStringIterator.cpp
Source/JavaScriptCore/runtime/JSStringIterator.h
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Views/ConsoleMessageImpl.js
Source/WebInspectorUI/UserInterface/Views/ObjectPreviewView.js

index 9023eb5..be5f57c 100644 (file)
@@ -1,3 +1,13 @@
+2015-03-06  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: ES6: Improved Support for Iterator Objects
+        https://bugs.webkit.org/show_bug.cgi?id=142420
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/model/remote-object.html:
+        Update tests to include iterator objects.
+
 2015-03-06  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] Mark svg/fonts/svg-font-horiz-orig.html as Image-only failing.
index 66589bd..636bf08 100644 (file)
@@ -2776,6 +2776,901 @@ EXPRESSION: set = new Set; for (var i = 0; i <= 100; i++) set.add(i); set
 }
 
 -----------------------------------------------------
+EXPRESSION: 'a'[Symbol.iterator]()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "StringIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "StringIterator",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "string",
+        "_type": "string",
+        "_value": "a",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "a",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: 'long string'[Symbol.iterator]()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "StringIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "StringIterator",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
+      {
+        "_name": "string",
+        "_type": "string",
+        "_value": "long string",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "l",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "o",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "n",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "g",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": " ",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: [][Symbol.iterator]()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "ArrayIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "ArrayIterator",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "array",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "value",
+        "_internal": true
+      }
+    ],
+    "_entries": []
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: [1][Symbol.iterator]()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "ArrayIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "ArrayIterator",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "array",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "value",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: [1, 'two', 3, 'four', 5, 'size'][Symbol.iterator]()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "ArrayIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "ArrayIterator",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
+      {
+        "_name": "array",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "value",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "two",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "3",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "four",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "5",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: [1, 'two', 3, 'four', 5, 'size'].keys()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "ArrayIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "ArrayIterator",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
+      {
+        "_name": "array",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "key",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "0",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "3",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "4",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: [1, 'two', 3, 'four', 5, 'size'].entries()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "ArrayIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "ArrayIterator",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
+      {
+        "_name": "array",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Array",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "key+value",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "number",
+              "_value": "0"
+            },
+            {
+              "_name": "1",
+              "_type": "number",
+              "_value": "1"
+            }
+          ],
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "number",
+              "_value": "1"
+            },
+            {
+              "_name": "1",
+              "_type": "string",
+              "_value": "two"
+            }
+          ],
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "number",
+              "_value": "2"
+            },
+            {
+              "_name": "1",
+              "_type": "number",
+              "_value": "3"
+            }
+          ],
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "number",
+              "_value": "3"
+            },
+            {
+              "_name": "1",
+              "_type": "string",
+              "_value": "four"
+            }
+          ],
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "number",
+              "_value": "4"
+            },
+            {
+              "_name": "1",
+              "_type": "number",
+              "_value": "5"
+            }
+          ],
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: map = new Map; map.set(1, 2); map.set('key', 'value'); map.values()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "Map Iterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "Map Iterator",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "map",
+        "_type": "object",
+        "_subtype": "map",
+        "_value": "Map",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "value",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "value",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: map.keys()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "Map Iterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "Map Iterator",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "map",
+        "_type": "object",
+        "_subtype": "map",
+        "_value": "Map",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "key",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "key",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: map.entries()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "Map Iterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "Map Iterator",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "map",
+        "_type": "object",
+        "_subtype": "map",
+        "_value": "Map",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "key+value",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "number",
+              "_value": "1"
+            },
+            {
+              "_name": "1",
+              "_type": "number",
+              "_value": "2"
+            }
+          ],
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "string",
+              "_value": "key"
+            },
+            {
+              "_name": "1",
+              "_type": "string",
+              "_value": "value"
+            }
+          ],
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: set = new Set; for (var i = 0; i <= 100; i++) set.add(i); set.values()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "Set Iterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "Set Iterator",
+    "_lossless": false,
+    "_overflow": true,
+    "_properties": [
+      {
+        "_name": "set",
+        "_type": "object",
+        "_subtype": "set",
+        "_value": "Set",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "value",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "0",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "2",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "3",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "4",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: map.entries()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "Map Iterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "Map Iterator",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "map",
+        "_type": "object",
+        "_subtype": "map",
+        "_value": "Map",
+        "_internal": true
+      },
+      {
+        "_name": "kind",
+        "_type": "string",
+        "_value": "key+value",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "number",
+              "_value": "1"
+            },
+            {
+              "_name": "1",
+              "_type": "number",
+              "_value": "2"
+            }
+          ],
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "object",
+          "_subtype": "array",
+          "_description": "Array",
+          "_lossless": true,
+          "_overflow": false,
+          "_size": 2,
+          "_properties": [
+            {
+              "_name": "0",
+              "_type": "string",
+              "_value": "key"
+            },
+            {
+              "_name": "1",
+              "_type": "string",
+              "_value": "value"
+            }
+          ],
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
+EXPRESSION: x = undefined; (function() { x = arguments; })(1, 'two'); x[Symbol.iterator]()
+{
+  "_type": "object",
+  "_subtype": "iterator",
+  "_objectId": "<filtered>",
+  "_description": "ArgumentsIterator",
+  "_preview": {
+    "_type": "object",
+    "_subtype": "iterator",
+    "_description": "ArgumentsIterator",
+    "_lossless": false,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "arguments",
+        "_type": "object",
+        "_subtype": "array",
+        "_value": "Arguments",
+        "_internal": true
+      }
+    ],
+    "_entries": [
+      {
+        "_value": {
+          "_type": "number",
+          "_description": "1",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      },
+      {
+        "_value": {
+          "_type": "string",
+          "_description": "two",
+          "_lossless": true,
+          "_overflow": false,
+          "_properties": null,
+          "_entries": null
+        }
+      }
+    ]
+  }
+}
+
+-----------------------------------------------------
 EXPRESSION: new Promise(function(){})
 {
   "_type": "object",
index ae0f52d..3531f0c 100644 (file)
@@ -129,6 +129,21 @@ function test()
         {expression: "set = new Set; set.add({a:1}); set.add(document.body); set.add([1,2]); set"},
         {expression: "set = new Set; for (var i = 0; i <= 100; i++) set.add(i); set"},
 
+        // Iterators
+        {expression: "'a'[Symbol.iterator]()"},
+        {expression: "'long string'[Symbol.iterator]()"},
+        {expression: "[][Symbol.iterator]()"},
+        {expression: "[1][Symbol.iterator]()"},
+        {expression: "[1, 'two', 3, 'four', 5, 'size'][Symbol.iterator]()"},
+        {expression: "[1, 'two', 3, 'four', 5, 'size'].keys()"},
+        {expression: "[1, 'two', 3, 'four', 5, 'size'].entries()"},
+        {expression: "map = new Map; map.set(1, 2); map.set('key', 'value'); map.values()"},
+        {expression: "map.keys()"},
+        {expression: "map.entries()"},
+        {expression: "set = new Set; for (var i = 0; i <= 100; i++) set.add(i); set.values()"},
+        {expression: "map.entries()"},
+        {expression: "x = undefined; (function() { x = arguments; })(1, 'two'); x[Symbol.iterator]()"},
+
         // Promise
         {expression: "new Promise(function(){})"},
         {expression: "Promise.reject()"},
@@ -159,30 +174,34 @@ function test()
         return value;
     }
 
-    function runNextStep() {
-        if (currentStepIndex >= steps.length) {
-            InspectorTest.completeTest();
-            return;
-        }
+    function runSteps() {
 
-        var step = steps[currentStepIndex++];
-        if (step.browserOnly) {
-            runNextStep();
-            return;
+        function afterStep() {
+            if (++currentStepIndex >= steps.length)
+                InspectorTest.completeTest();
         }
 
-        InspectorTest.log("");
-        InspectorTest.log("-----------------------------------------------------");
-        InspectorTest.log("EXPRESSION: " + step.expression);
+        function runStep(step) {
+            if (step.browserOnly) {
+                afterStep();
+                return;
+            }
+
+            WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, true, false, function(remoteObject, wasThrown) {
+                InspectorTest.log("");
+                InspectorTest.log("-----------------------------------------------------");
+                InspectorTest.log("EXPRESSION: " + step.expression);
+                InspectorTest.assert(remoteObject instanceof WebInspector.RemoteObject);
+                InspectorTest.log(JSON.stringify(remoteObject, remoteObjectJSONFilter, "  "));
+                afterStep();
+            });
+        }
 
-        WebInspector.runtimeManager.evaluateInInspectedWindow(step.expression, "test", false, true, false, true, false, function(remoteObject, wasThrown) {
-            InspectorTest.assert(remoteObject instanceof WebInspector.RemoteObject);
-            InspectorTest.log(JSON.stringify(remoteObject, remoteObjectJSONFilter, "  "));
-            runNextStep();
-        });
+        for (var step of steps)
+            runStep(step);
     }
 
-    runNextStep();
+    runSteps();
 }
 
 function runInBrowserTest()
index 46f979d..81bac19 100644 (file)
@@ -1,3 +1,61 @@
+2015-03-06  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: ES6: Improved Support for Iterator Objects
+        https://bugs.webkit.org/show_bug.cgi?id=142420
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/protocol/Runtime.json:
+        Add new object subtype "iterator" for built-in iterator objects.
+
+        * inspector/InjectedScriptSource.js:
+        Return iterator values as Entry objects.
+
+        * inspector/JSInjectedScriptHost.cpp:
+        (Inspector::JSInjectedScriptHost::subtype):
+        Identify "iterator" typed objects.
+
+        (Inspector::JSInjectedScriptHost::getInternalProperties):
+        Provide internal properties for the different Iterator objects.
+
+        (Inspector::JSInjectedScriptHost::iteratorEntries):
+        Fetch the next few iterator entries of a built-in iterator object.
+
+        * inspector/JSInjectedScriptHost.h:
+        * inspector/JSInjectedScriptHostPrototype.cpp:
+        (Inspector::JSInjectedScriptHostPrototype::finishCreation):
+        (Inspector::jsInjectedScriptHostPrototypeFunctionIteratorEntries):
+        Call through to JSInjectedScriptHost.
+
+        * runtime/JSArgumentsIterator.cpp:
+        (JSC::JSArgumentsIterator::clone):
+        * runtime/JSArgumentsIterator.h:
+        (JSC::JSArgumentsIterator::iteratedValue):
+        * runtime/JSArrayIterator.cpp:
+        (JSC::JSArrayIterator::kind):
+        (JSC::JSArrayIterator::iteratedValue):
+        (JSC::JSArrayIterator::clone):
+        * runtime/JSArrayIterator.h:
+        * runtime/JSMapIterator.cpp:
+        (JSC::JSMapIterator::finishCreation):
+        (JSC::JSMapIterator::clone):
+        * runtime/JSMapIterator.h:
+        (JSC::JSMapIterator::kind):
+        (JSC::JSMapIterator::iteratedValue):
+        * runtime/JSSetIterator.cpp:
+        (JSC::JSSetIterator::finishCreation):
+        (JSC::JSSetIterator::clone):
+        * runtime/JSSetIterator.h:
+        (JSC::JSSetIterator::kind):
+        (JSC::JSSetIterator::iteratedValue):
+        * runtime/JSStringIterator.cpp:
+        (JSC::JSStringIterator::iteratedValue):
+        (JSC::JSStringIterator::clone):
+        * runtime/JSStringIterator.h:
+        Add accessors for internal properties and provide a way to clone the
+        iterator so we can be at the same index and peek at the next few
+        objects without modifying the original iterator object.
+
 2015-03-06  Ryosuke Niwa  <rniwa@webkit.org>
 
         REGRESSION(r180595): construct varargs fails in FTL
index b4b7ae3..4473523 100644 (file)
@@ -286,7 +286,7 @@ InjectedScript.prototype = {
         if (typeof object !== "object")
             return;
 
-        var entries = this._getCollectionEntries(object, InjectedScriptHost.subtype(object), startIndex, numberToFetch);
+        var entries = this._entries(object, InjectedScriptHost.subtype(object), startIndex, numberToFetch);
         return entries.map(function(entry) {
             entry.value = injectedScript._wrapObject(entry.value, objectGroupName, false, true);
             if ("key" in entry)
@@ -828,7 +828,12 @@ InjectedScript.prototype = {
         return InjectedScriptHost.weakMapEntries(object, numberToFetch);
     },
 
-    _getCollectionEntries: function(object, subtype, startIndex, numberToFetch)
+    _getIteratorEntries: function(object, numberToFetch)
+    {
+        return InjectedScriptHost.iteratorEntries(object, numberToFetch);
+    },
+
+    _entries: function(object, subtype, startIndex, numberToFetch)
     {
         if (subtype === "set")
             return this._getSetEntries(object, startIndex, numberToFetch);
@@ -836,6 +841,8 @@ InjectedScript.prototype = {
             return this._getMapEntries(object, startIndex, numberToFetch);
         if (subtype === "weakmap")
             return this._getWeakMapEntries(object, numberToFetch);
+        if (subtype === "iterator")
+            return this._getIteratorEntries(object, numberToFetch);
 
         throw "unexpected type";
     },
@@ -961,8 +968,8 @@ InjectedScript.RemoteObject.prototype = {
         };
 
         try {
-            // Maps and Sets have entries.
-            if (this.subtype === "map" || this.subtype === "set" || this.subtype === "weakmap")
+            // Maps, Sets, and Iterators have entries.
+            if (this.subtype === "map" || this.subtype === "set" || this.subtype === "weakmap" || this.subtype === "iterator")
                 this._appendEntryPreviews(object, preview);
 
             preview.properties = [];
@@ -1112,7 +1119,7 @@ InjectedScript.RemoteObject.prototype = {
     _appendEntryPreviews: function(object, preview)
     {
         // Fetch 6, but only return 5, so we can tell if we overflowed.
-        var entries = injectedScript._getCollectionEntries(object, this.subtype, 0, 6);
+        var entries = injectedScript._entries(object, this.subtype, 0, 6);
         if (!entries)
             return;
 
index 83b204f..d15af32 100644 (file)
 #include "DateInstance.h"
 #include "Error.h"
 #include "InjectedScriptHost.h"
+#include "IteratorOperations.h"
+#include "JSArgumentsIterator.h"
 #include "JSArray.h"
+#include "JSArrayIterator.h"
 #include "JSBoundFunction.h"
 #include "JSCInlines.h"
 #include "JSFunction.h"
 #include "JSInjectedScriptHostPrototype.h"
 #include "JSMap.h"
+#include "JSMapIterator.h"
 #include "JSSet.h"
+#include "JSSetIterator.h"
+#include "JSStringIterator.h"
 #include "JSTypedArrays.h"
 #include "JSWeakMap.h"
 #include "ObjectConstructor.h"
@@ -147,6 +153,13 @@ JSValue JSInjectedScriptHost::subtype(ExecState* exec)
     if (value.inherits(JSWeakMap::info()))
         return jsNontrivialString(exec, ASCIILiteral("weakmap"));
 
+    if (value.inherits(JSArrayIterator::info())
+        || value.inherits(JSMapIterator::info())
+        || value.inherits(JSSetIterator::info())
+        || value.inherits(JSStringIterator::info())
+        || value.inherits(JSArgumentsIterator::info()))
+        return jsNontrivialString(exec, ASCIILiteral("iterator"));
+
     if (value.inherits(JSInt8Array::info()) || value.inherits(JSInt16Array::info()) || value.inherits(JSInt32Array::info()))
         return jsNontrivialString(exec, ASCIILiteral("array"));
     if (value.inherits(JSUint8Array::info()) || value.inherits(JSUint16Array::info()) || value.inherits(JSUint32Array::info()))
@@ -250,6 +263,80 @@ JSValue JSInjectedScriptHost::getInternalProperties(ExecState* exec)
         return array;
     }
 
+    if (JSArrayIterator* arrayIterator = jsDynamicCast<JSArrayIterator*>(value)) {
+        String kind;
+        switch (arrayIterator->kind(exec)) {
+        case ArrayIterateKey:
+            kind = ASCIILiteral("key");
+            break;
+        case ArrayIterateValue:
+            kind = ASCIILiteral("value");
+            break;
+        case ArrayIterateKeyValue:
+            kind = ASCIILiteral("key+value");
+            break;
+        }
+        unsigned index = 0;
+        JSArray* array = constructEmptyArray(exec, nullptr, 2);
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "array", arrayIterator->iteratedValue(exec)));
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "kind", jsNontrivialString(exec, kind)));
+        return array;
+    }
+
+    if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value)) {
+        String kind;
+        switch (mapIterator->kind()) {
+        case MapIterateKey:
+            kind = ASCIILiteral("key");
+            break;
+        case MapIterateValue:
+            kind = ASCIILiteral("value");
+            break;
+        case MapIterateKeyValue:
+            kind = ASCIILiteral("key+value");
+            break;
+        }
+        unsigned index = 0;
+        JSArray* array = constructEmptyArray(exec, nullptr, 2);
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "map", mapIterator->iteratedValue()));
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "kind", jsNontrivialString(exec, kind)));
+        return array;
+    }
+        
+    if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value)) {
+        String kind;
+        switch (setIterator->kind()) {
+        case SetIterateKey:
+            kind = ASCIILiteral("key");
+            break;
+        case SetIterateValue:
+            kind = ASCIILiteral("value");
+            break;
+        case SetIterateKeyValue:
+            kind = ASCIILiteral("key+value");
+            break;
+        }
+        unsigned index = 0;
+        JSArray* array = constructEmptyArray(exec, nullptr, 2);
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "set", setIterator->iteratedValue()));
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "kind", jsNontrivialString(exec, kind)));
+        return array;
+    }
+
+    if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value)) {
+        unsigned index = 0;
+        JSArray* array = constructEmptyArray(exec, nullptr, 1);
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "string", stringIterator->iteratedValue(exec)));
+        return array;
+    }
+
+    if (JSArgumentsIterator* argumentsIterator = jsDynamicCast<JSArgumentsIterator*>(value)) {
+        unsigned index = 0;
+        JSArray* array = constructEmptyArray(exec, nullptr, 1);
+        array->putDirectIndex(exec, index++, constructInternalProperty(exec, "arguments", argumentsIterator->iteratedValue()));
+        return array;
+    }
+
     return jsUndefined();
 }
 
@@ -297,6 +384,55 @@ JSValue JSInjectedScriptHost::weakMapEntries(ExecState* exec)
     return array;
 }
 
+JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
+{
+    if (exec->argumentCount() < 1)
+        return jsUndefined();
+
+    JSValue iterator;
+    JSValue value = exec->uncheckedArgument(0);
+    if (JSArrayIterator* arrayIterator = jsDynamicCast<JSArrayIterator*>(value))
+        iterator = arrayIterator->clone(exec);
+    else if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value))
+        iterator = mapIterator->clone(exec);
+    else if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value))
+        iterator = setIterator->clone(exec);
+    else if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value))
+        iterator = stringIterator->clone(exec);
+    else if (JSArgumentsIterator* argumentsIterator = jsDynamicCast<JSArgumentsIterator*>(value))
+        iterator = argumentsIterator->clone(exec);
+    else
+        return jsUndefined();
+
+    unsigned numberToFetch = 5;
+    JSValue numberToFetchArg = exec->argument(1);
+    double fetchDouble = numberToFetchArg.toInteger(exec);
+    if (fetchDouble >= 0)
+        numberToFetch = static_cast<unsigned>(fetchDouble);
+
+    JSArray* array = constructEmptyArray(exec, nullptr);
+
+    for (unsigned i = 0; i < numberToFetch; ++i) {
+        JSValue next = iteratorStep(exec, iterator);
+        if (exec->hadException())
+            break;
+        if (next.isFalse())
+            break;
+
+        JSValue nextValue = iteratorValue(exec, next);
+        if (exec->hadException())
+            break;
+
+        JSObject* entry = constructEmptyObject(exec);
+        entry->putDirect(exec->vm(), Identifier(exec, "value"), nextValue);
+        array->putDirectIndex(exec, i, entry);
+    }
+
+    iteratorClose(exec, iterator);
+
+    return array;
+}
+
 JSValue toJS(ExecState* exec, JSGlobalObject* globalObject, InjectedScriptHost* impl)
 {
     if (!impl)
index 8c8d8b0..0456a3e 100644 (file)
@@ -67,6 +67,7 @@ public:
     JSC::JSValue getInternalProperties(JSC::ExecState*);
     JSC::JSValue weakMapSize(JSC::ExecState*);
     JSC::JSValue weakMapEntries(JSC::ExecState*);
+    JSC::JSValue iteratorEntries(JSC::ExecState*);
 
 protected:
     static const unsigned StructureFlags = Base::StructureFlags;
index 2f857ff..4bffad1 100644 (file)
@@ -45,6 +45,7 @@ static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionInterna
 static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection(ExecState*);
 static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapSize(ExecState*);
 static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapEntries(ExecState*);
+static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIteratorEntries(ExecState*);
 
 static EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeAttributeEvaluate(ExecState*);
 
@@ -63,6 +64,7 @@ void JSInjectedScriptHostPrototype::finishCreation(VM& vm, JSGlobalObject* globa
     JSC_NATIVE_FUNCTION("isHTMLAllCollection", jsInjectedScriptHostPrototypeFunctionIsHTMLAllCollection, DontEnum, 1);
     JSC_NATIVE_FUNCTION("weakMapSize", jsInjectedScriptHostPrototypeFunctionWeakMapSize, DontEnum, 1);
     JSC_NATIVE_FUNCTION("weakMapEntries", jsInjectedScriptHostPrototypeFunctionWeakMapEntries, DontEnum, 1);
+    JSC_NATIVE_FUNCTION("iteratorEntries", jsInjectedScriptHostPrototypeFunctionIteratorEntries, DontEnum, 1);
 
     Identifier evaluateIdentifier(&vm, "evaluate");
     GetterSetter* accessor = GetterSetter::create(vm, globalObject);
@@ -126,6 +128,17 @@ EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionWeakMapEntries
     return JSValue::encode(castedThis->weakMapEntries(exec));
 }
 
+EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionIteratorEntries(ExecState* exec)
+{
+    JSValue thisValue = exec->thisValue();
+    JSInjectedScriptHost* castedThis = jsDynamicCast<JSInjectedScriptHost*>(thisValue);
+    if (!castedThis)
+        return throwVMTypeError(exec);
+
+    ASSERT_GC_OBJECT_INHERITS(castedThis, JSInjectedScriptHost::info());
+    return JSValue::encode(castedThis->iteratorEntries(exec));
+}
+
 EncodedJSValue JSC_HOST_CALL jsInjectedScriptHostPrototypeFunctionSubtype(ExecState* exec)
 {
     JSValue thisValue = exec->thisValue();
index 69fe926..f29adc7 100644 (file)
@@ -13,7 +13,7 @@
             "description": "Mirror object referencing original JavaScript object.",
             "properties": [
                 { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." },
-                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
+                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap", "iterator"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
                 { "name": "className", "type": "string", "optional": true, "description": "Object class (constructor) name. Specified for <code>object</code> type values only." },
                 { "name": "value", "type": "any", "optional": true, "description": "Remote object value (in case of primitive values or JSON values if it was requested)." },
                 { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." },
@@ -28,7 +28,7 @@
             "description": "Object containing abbreviated remote object value.",
             "properties": [
                 { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol"], "description": "Object type." },
-                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
+                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap", "iterator"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
                 { "name": "description", "type": "string", "optional": true, "description": "String representation of the object." },
                 { "name": "lossless", "type": "boolean", "description": "Determines whether preview is lossless (contains all information of the original object)." },
                 { "name": "overflow", "type": "boolean", "optional": true, "description": "True iff some of the properties of the original did not fit." },
@@ -43,7 +43,7 @@
             "properties": [
                 { "name": "name", "type": "string", "description": "Property name." },
                 { "name": "type", "type": "string", "enum": ["object", "function", "undefined", "string", "number", "boolean", "symbol", "accessor"], "description": "Object type." },
-                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
+                { "name": "subtype", "type": "string", "optional": true, "enum": ["array", "null", "node", "regexp", "date", "error", "map", "set", "weakmap", "iterator"], "description": "Object subtype hint. Specified for <code>object</code> type values only." },
                 { "name": "value", "type": "string", "optional": true, "description": "User-friendly property value string." },
                 { "name": "valuePreview", "$ref": "ObjectPreview", "optional": true, "description": "Nested value preview." },
                 { "name": "internal", "type": "boolean", "optional": true, "description": "True if this is an internal property." }
index 3efab22..4ccb622 100644 (file)
@@ -39,4 +39,11 @@ void JSArgumentsIterator::finishCreation(VM& vm, Arguments* arguments)
     m_arguments.set(vm, this, arguments);
 }
 
+JSArgumentsIterator* JSArgumentsIterator::clone(ExecState* exec)
+{
+    auto clone = JSArgumentsIterator::create(exec->vm(), exec->callee()->globalObject()->argumentsIteratorStructure(), m_arguments.get());
+    clone->m_nextIndex = m_nextIndex;
+    return clone;
+}
+
 }
index 0eed745..6bdce7d 100644 (file)
@@ -58,6 +58,9 @@ public:
         return true;
     }
 
+    JSValue iteratedValue() const { return m_arguments.get(); }
+    JSArgumentsIterator* clone(ExecState*);
+
 private:
 
     static const unsigned StructureFlags = Base::StructureFlags;
index dac562b..f2039e1 100644 (file)
@@ -45,4 +45,26 @@ void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject*, ArrayIterationKind
     putDirect(vm, vm.propertyNames->arrayIterationKindPrivateName, jsNumber(kind));
 }
 
+ArrayIterationKind JSArrayIterator::kind(ExecState* exec) const
+{
+    JSValue kindValue = getDirect(exec->vm(), exec->vm().propertyNames->arrayIterationKindPrivateName);
+    return static_cast<ArrayIterationKind>(kindValue.asInt32());
+}
+
+JSValue JSArrayIterator::iteratedValue(ExecState* exec) const
+{
+    return getDirect(exec->vm(), exec->vm().propertyNames->iteratedObjectPrivateName);
+}
+
+JSArrayIterator* JSArrayIterator::clone(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    JSValue iteratedObject = getDirect(vm, vm.propertyNames->iteratedObjectPrivateName);
+    JSValue nextIndex = getDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName);
+
+    auto clone = JSArrayIterator::create(exec, exec->callee()->globalObject()->arrayIteratorStructure(), kind(exec), asObject(iteratedObject));
+    clone->putDirect(vm, vm.propertyNames->arrayIteratorNextIndexPrivateName, nextIndex);
+    return clone;
+}
+
 }
index 2e976be..0166bd2 100644 (file)
@@ -55,6 +55,10 @@ public:
         return instance;
     }
 
+    ArrayIterationKind kind(ExecState*) const;
+    JSValue iteratedValue(ExecState*) const;
+    JSArrayIterator* clone(ExecState*);
+
     using JSNonFinalObject::arrayStorageOrNull;
 private:
     JSArrayIterator(VM& vm, Structure* structure)
index 4d76565..c167acb 100644 (file)
@@ -39,6 +39,7 @@ const ClassInfo JSMapIterator::s_info = { "Map Iterator", &Base::s_info, 0, CREA
 void JSMapIterator::finishCreation(VM& vm, JSMap* iteratedObject)
 {
     Base::finishCreation(vm);
+    m_map.set(vm, this, iteratedObject);
     m_iteratedObjectData.set(vm, this, iteratedObject->mapData());
 }
 
@@ -59,4 +60,11 @@ JSValue JSMapIterator::createPair(CallFrame* callFrame, JSValue key, JSValue val
     return constructArray(callFrame, 0, globalObject, args);
 }
 
+JSMapIterator* JSMapIterator::clone(ExecState* exec)
+{
+    auto clone = JSMapIterator::create(exec->vm(), exec->callee()->globalObject()->mapIteratorStructure(), m_map.get(), m_kind);
+    clone->m_iterator = m_iterator;
+    return clone;
+}
+
 }
index 3e2c9f7..63dd5e8 100644 (file)
@@ -75,6 +75,10 @@ public:
         m_iterator.finish();
     }
 
+    MapIterationKind kind() const { return m_kind; }
+    JSValue iteratedValue() const { return m_map.get(); }
+    JSMapIterator* clone(ExecState*);
+
 private:
     JSMapIterator(VM& vm, Structure* structure, JSMap* iteratedObject, MapIterationKind kind)
         : Base(vm, structure)
@@ -87,6 +91,7 @@ private:
     JSValue createPair(CallFrame*, JSValue, JSValue);
     static void visitChildren(JSCell*, SlotVisitor&);
 
+    WriteBarrier<JSMap> m_map;
     WriteBarrier<MapData> m_iteratedObjectData;
     MapData::const_iterator m_iterator;
     MapIterationKind m_kind;
index 621b75f..2fc2989 100644 (file)
@@ -39,6 +39,7 @@ const ClassInfo JSSetIterator::s_info = { "Set Iterator", &Base::s_info, 0, CREA
 void JSSetIterator::finishCreation(VM& vm, JSSet* iteratedObject)
 {
     Base::finishCreation(vm);
+    m_set.set(vm, this, iteratedObject);
     m_iteratedObjectData.set(vm, this, iteratedObject->mapData());
 }
 
@@ -59,4 +60,11 @@ JSValue JSSetIterator::createPair(CallFrame* callFrame, JSValue key, JSValue val
     return constructArray(callFrame, 0, globalObject, args);
 }
 
+JSSetIterator* JSSetIterator::clone(ExecState* exec)
+{
+    auto clone = JSSetIterator::create(exec->vm(), exec->callee()->globalObject()->setIteratorStructure(), m_set.get(), m_kind);
+    clone->m_iterator = m_iterator;
+    return clone;
+}
+
 }
index d6fd3b8..9c70c26 100644 (file)
@@ -73,6 +73,10 @@ public:
         m_iterator.finish();
     }
 
+    SetIterationKind kind() const { return m_kind; }
+    JSValue iteratedValue() const { return m_set.get(); }
+    JSSetIterator* clone(ExecState*);
+
 private:
     JSSetIterator(VM& vm, Structure* structure, JSSet* iteratedObject, SetIterationKind kind)
         : Base(vm, structure)
@@ -85,6 +89,7 @@ private:
     JSValue createPair(CallFrame*, JSValue, JSValue);
     static void visitChildren(JSCell*, SlotVisitor&);
 
+    WriteBarrier<JSSet> m_set;
     WriteBarrier<MapData> m_iteratedObjectData;
     MapData::const_iterator m_iterator;
     SetIterationKind m_kind;
index d967ce7..62d7486 100644 (file)
@@ -42,4 +42,20 @@ void JSStringIterator::finishCreation(VM& vm, JSGlobalObject*, JSString* iterate
     putDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName, jsNumber(0));
 }
 
+JSValue JSStringIterator::iteratedValue(ExecState* exec) const
+{
+    return getDirect(exec->vm(), exec->vm().propertyNames->iteratedStringPrivateName);
+}
+
+JSStringIterator* JSStringIterator::clone(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    JSValue iteratedString = getDirect(vm, vm.propertyNames->iteratedStringPrivateName);
+    JSValue nextIndex = getDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName);
+
+    auto clone = JSStringIterator::create(exec, exec->callee()->globalObject()->stringIteratorStructure(), asString(iteratedString));
+    clone->putDirect(vm, vm.propertyNames->stringIteratorNextIndexPrivateName, nextIndex);
+    return clone;
+}
+
 } // namespace JSC
index 1de0c8a..6a789a3 100644 (file)
@@ -49,6 +49,9 @@ public:
         return instance;
     }
 
+    JSValue iteratedValue(ExecState*) const;
+    JSStringIterator* clone(ExecState*);
+
 private:
     JSStringIterator(VM& vm, Structure* structure)
         : Base(vm, structure)
index efcfc49..f873035 100644 (file)
@@ -1,5 +1,19 @@
 2015-03-06  Joseph Pecoraro  <pecoraro@apple.com>
 
+        Web Inspector: ES6: Improved Support for Iterator Objects
+        https://bugs.webkit.org/show_bug.cgi?id=142420
+
+        Reviewed by Timothy Hatcher.
+
+        * UserInterface/Views/ConsoleMessageImpl.js:
+        (WebInspector.ConsoleMessageImpl):
+        Treat an iterator like an object.
+
+        * UserInterface/Views/ObjectPreviewView.js:
+        Output iterator previews with []s, not {}s.
+
+2015-03-06  Joseph Pecoraro  <pecoraro@apple.com>
+
         Web Inspector: Adopt Object Literal Method Property Syntax
         https://bugs.webkit.org/show_bug.cgi?id=142409
 
index 4deaef1..535dbcc 100644 (file)
@@ -45,6 +45,7 @@ WebInspector.ConsoleMessageImpl = function(source, level, message, linkifier, ty
         "map": this._formatParameterAsObject,
         "set": this._formatParameterAsObject,
         "weakmap": this._formatParameterAsObject,
+        "iterator": this._formatParameterAsObject,
         "array":  this._formatParameterAsArray,
         "node":   this._formatParameterAsNode,
         "string": this._formatParameterAsString
index 6a2d9f8..9d87a45 100644 (file)
@@ -144,7 +144,9 @@ WebInspector.ObjectPreviewView.prototype = {
     {
         var lossless = preview.lossless && !preview.propertyPreviews.length;
 
-        element.appendChild(document.createTextNode("{"));
+        var isIterator = preview.subtype === "iterator";
+
+        element.appendChild(document.createTextNode(isIterator ? "[" : "{"));
 
         var limit = Math.min(preview.collectionEntryPreviews.length, this._numberOfPropertiesToShowInMode());
         for (var i = 0; i < limit; ++i) {
@@ -166,7 +168,7 @@ WebInspector.ObjectPreviewView.prototype = {
 
         if (preview.overflow)
             element.appendChild(document.createTextNode(", \u2026"));
-        element.appendChild(document.createTextNode("}"));
+        element.appendChild(document.createTextNode(isIterator ? "]" : "}"));
 
         return lossless;
     },