Support for-of syntax
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Oct 2013 20:35:24 +0000 (20:35 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Oct 2013 20:35:24 +0000 (20:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=122339

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Add support for for-of syntax to JSC.  As part of doing this I had to make
us support unique empty strings as identifiers.  In a follow on patch i'm
going to remove the distinction entirely as it's purely a complicating
separation.

Otherwise the logic here is fairly self-explanatory.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::addConstant):
(JSC::BytecodeGenerator::emitCall):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::CallArguments::CallArguments):
(JSC::ForOfNode::emitBytecode):
* jit/JITOperations.cpp:
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createForOfLoop):
* parser/NodeConstructors.h:
(JSC::EnumerationNode::EnumerationNode):
(JSC::ForInNode::ForInNode):
(JSC::ForOfNode::ForOfNode):
* parser/Nodes.h:
* parser/Parser.cpp:
(JSC::::parseVarDeclarationList):
(JSC::::parseForStatement):
* parser/Parser.h:
(JSC::Parser::isofToken):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createForOfLoop):
* runtime/ArrayIteratorPrototype.cpp:
(JSC::ArrayIteratorPrototype::finishCreation):
(JSC::arrayIteratorPrototypeIterate):
* runtime/ArrayPrototype.cpp:
(JSC::ArrayPrototype::create):
(JSC::ArrayPrototype::finishCreation):
* runtime/ArrayPrototype.h:
* runtime/CommonIdentifiers.cpp:
(JSC::CommonIdentifiers::CommonIdentifiers):
* runtime/CommonIdentifiers.h:
* runtime/Identifier.h:
(JSC::Identifier::from):
* runtime/JSCJSValue.cpp:
(JSC::JSValue::dumpInContext):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectNativeFunction):
* runtime/PrivateName.h:
(JSC::PrivateName::PrivateName):
* runtime/PropertyName.h:
(JSC::PropertyName::PropertyName):

Source/WTF:

Update assertions and add a helper function to StringImpl
to save repeated unique or identifier calls.

* wtf/text/StringImpl.h:
(WTF::StringImpl::isIdentifierOrUnique):
(WTF::StringImpl::setIsIdentifier):
(WTF::StringImpl::setIsAtomic):

LayoutTests:

Add test cases for the one type that supports for-of so far

* js/basic-for-of-expected.txt: Added.
* js/basic-for-of.html: Added.
* js/regress/for-of-iterate-array-entries.html: Added.
* js/regress/for-of-iterate-array-keys.html: Added.
* js/regress/for-of-iterate-array-values.html: Added.
* js/regress/script-tests/for-of-iterate-array-entries.js: Added.
(foo):
* js/regress/script-tests/for-of-iterate-array-keys.js: Added.
(foo):
* js/regress/script-tests/for-of-iterate-array-values.js: Added.
(foo):

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

40 files changed:
LayoutTests/ChangeLog
LayoutTests/js/basic-for-of-expected.txt [new file with mode: 0644]
LayoutTests/js/basic-for-of.html [new file with mode: 0644]
LayoutTests/js/parser-syntax-check-expected.txt
LayoutTests/js/regress/for-of-iterate-array-entries-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/for-of-iterate-array-entries.html [new file with mode: 0644]
LayoutTests/js/regress/for-of-iterate-array-keys-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/for-of-iterate-array-keys.html [new file with mode: 0644]
LayoutTests/js/regress/for-of-iterate-array-values-expected.txt [new file with mode: 0644]
LayoutTests/js/regress/for-of-iterate-array-values.html [new file with mode: 0644]
LayoutTests/js/regress/script-tests/for-of-iterate-array-entries.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/for-of-iterate-array-keys.js [new file with mode: 0644]
LayoutTests/js/regress/script-tests/for-of-iterate-array-values.js [new file with mode: 0644]
LayoutTests/js/script-tests/parser-syntax-check.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/SyntaxChecker.h
Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp
Source/JavaScriptCore/runtime/ArrayPrototype.cpp
Source/JavaScriptCore/runtime/ArrayPrototype.h
Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/Identifier.h
Source/JavaScriptCore/runtime/JSArrayIterator.cpp
Source/JavaScriptCore/runtime/JSArrayIterator.h
Source/JavaScriptCore/runtime/JSCJSValue.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/PrivateName.h
Source/JavaScriptCore/runtime/PropertyName.h
Source/WTF/ChangeLog
Source/WTF/wtf/text/StringImpl.h

index 1872d64..055a482 100644 (file)
@@ -1,3 +1,24 @@
+2013-10-04  Oliver Hunt  <oliver@apple.com>
+
+        Support for-of syntax
+        https://bugs.webkit.org/show_bug.cgi?id=122339
+
+        Reviewed by Geoffrey Garen.
+
+        Add test cases for the one type that supports for-of so far
+
+        * js/basic-for-of-expected.txt: Added.
+        * js/basic-for-of.html: Added.
+        * js/regress/for-of-iterate-array-entries.html: Added.
+        * js/regress/for-of-iterate-array-keys.html: Added.
+        * js/regress/for-of-iterate-array-values.html: Added.
+        * js/regress/script-tests/for-of-iterate-array-entries.js: Added.
+        (foo):
+        * js/regress/script-tests/for-of-iterate-array-keys.js: Added.
+        (foo):
+        * js/regress/script-tests/for-of-iterate-array-values.js: Added.
+        (foo):
+
 2013-10-04  Bear Travis  <betravis@adobe.com>
 
         [CSS Shapes] Shape Outside should relayout when set dynamically
diff --git a/LayoutTests/js/basic-for-of-expected.txt b/LayoutTests/js/basic-for-of-expected.txt
new file mode 100644 (file)
index 0000000..bebc3d4
--- /dev/null
@@ -0,0 +1,76 @@
+This test checks the behavior of the for-of construct.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS value is testArray[0]
+PASS value is testArray[1]
+PASS value is testArray[2]
+PASS value is testArray[3]
+PASS value is testArray[4]
+PASS value is testArray[5]
+PASS testArray.length is 6
+PASS value is testArray[0]
+PASS value is testArray[1]
+PASS value is testArray[2]
+PASS value is testArray[3]
+PASS value is testArray[4]
+PASS value is testArray[5]
+PASS testArray.length is 6
+PASS key is 0
+PASS key is 1
+PASS key is 2
+PASS key is 3
+PASS key is 4
+PASS key is 5
+PASS testArray.length is 6
+PASS this.prop1 is 0
+PASS this.prop1 is 1
+PASS this.prop1 is 2
+PASS this.prop1 is 3
+PASS this.prop1 is 4
+PASS this.prop1 is 5
+PASS testArray.length is 6
+PASS this[prop2] is 0
+PASS this[prop2] is 1
+PASS this[prop2] is 2
+PASS this[prop2] is 3
+PASS this[prop2] is 4
+PASS this[prop2] is 5
+PASS testArray.length is 6
+PASS key is 0
+PASS value is 1
+PASS key is 1
+PASS value is 2
+PASS key is 2
+PASS value is 3
+PASS key is 3
+PASS value is 4
+PASS key is 4
+PASS value is 5
+PASS key is 5
+PASS value is 6
+PASS testArray.length is 6
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS value is testArray[key]
+PASS key is i
+PASS testArray.length is 9
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/basic-for-of.html b/LayoutTests/js/basic-for-of.html
new file mode 100644 (file)
index 0000000..138b8a0
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/basic-for-of.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index 526821a..7c1be54 100644 (file)
@@ -579,6 +579,58 @@ PASS Invalid: "var a.b = c"
 PASS Invalid: "function f() { var a.b = c }"
 PASS Invalid: "var a.b;"
 PASS Invalid: "function f() { var a.b; }"
+PASS Valid:   "for (of of of){}"
+PASS Valid:   "function f() { for (of of of){} }"
+PASS Valid:   "for (of; of; of){}"
+PASS Valid:   "function f() { for (of; of; of){} }"
+PASS Valid:   "for (var of of of){}"
+PASS Valid:   "function f() { for (var of of of){} }"
+PASS Valid:   "for (var of; of; of){}"
+PASS Valid:   "function f() { for (var of; of; of){} }"
+PASS Invalid: "for (var of.of of of){}"
+PASS Invalid: "function f() { for (var of.of of of){} }"
+PASS Invalid: "for (var of[of] of of){}"
+PASS Invalid: "function f() { for (var of[of] of of){} }"
+PASS Valid:   "for (of.of of of){}"
+PASS Valid:   "function f() { for (of.of of of){} }"
+PASS Valid:   "for (of[of] of of){}"
+PASS Valid:   "function f() { for (of[of] of of){} }"
+PASS Valid:   "for (var [of] of of){}"
+PASS Valid:   "function f() { for (var [of] of of){} }"
+PASS Valid:   "for (var {of} of of){}"
+PASS Valid:   "function f() { for (var {of} of of){} }"
+PASS Valid:   "for (of in of){}"
+PASS Valid:   "function f() { for (of in of){} }"
+PASS Valid:   "for (var of in of){}"
+PASS Valid:   "function f() { for (var of in of){} }"
+PASS Invalid: "for (var of.of in of){}"
+PASS Invalid: "function f() { for (var of.of in of){} }"
+PASS Valid:   "for (of.of in of){}"
+PASS Valid:   "function f() { for (of.of in of){} }"
+PASS Valid:   "for (of[of] in of){}"
+PASS Valid:   "function f() { for (of[of] in of){} }"
+PASS Invalid: "for (var of[of] in of){}"
+PASS Invalid: "function f() { for (var of[of] in of){} }"
+PASS Valid:   "for (var [of] in of){}"
+PASS Valid:   "function f() { for (var [of] in of){} }"
+PASS Valid:   "for (var {of} in of){}"
+PASS Valid:   "function f() { for (var {of} in of){} }"
+PASS Invalid: "for (of of of of){}"
+PASS Invalid: "function f() { for (of of of of){} }"
+PASS Invalid: "for (of of; of; of){}"
+PASS Invalid: "function f() { for (of of; of; of){} }"
+PASS Invalid: "for (of of []; of; of){}"
+PASS Invalid: "function f() { for (of of []; of; of){} }"
+PASS Invalid: "for (of of){}"
+PASS Invalid: "function f() { for (of of){} }"
+PASS Invalid: "for (var of of){}"
+PASS Invalid: "function f() { for (var of of){} }"
+PASS Invalid: "for (of of in of){}"
+PASS Invalid: "function f() { for (of of in of){} }"
+PASS Invalid: "for (of in){}"
+PASS Invalid: "function f() { for (of in){} }"
+PASS Invalid: "for (var of in){}"
+PASS Invalid: "function f() { for (var of in){} }"
 PASS e.line is 1
 PASS foo is 'PASS'
 PASS bar is 'PASS'
diff --git a/LayoutTests/js/regress/for-of-iterate-array-entries-expected.txt b/LayoutTests/js/regress/for-of-iterate-array-entries-expected.txt
new file mode 100644 (file)
index 0000000..f2806f1
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/for-of-iterate-array-entries
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/for-of-iterate-array-entries.html b/LayoutTests/js/regress/for-of-iterate-array-entries.html
new file mode 100644 (file)
index 0000000..13108e7
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/for-of-iterate-array-entries.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/for-of-iterate-array-keys-expected.txt b/LayoutTests/js/regress/for-of-iterate-array-keys-expected.txt
new file mode 100644 (file)
index 0000000..ed028d8
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/for-of-iterate-array-keys
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/for-of-iterate-array-keys.html b/LayoutTests/js/regress/for-of-iterate-array-keys.html
new file mode 100644 (file)
index 0000000..b01e89c
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/for-of-iterate-array-keys.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/for-of-iterate-array-values-expected.txt b/LayoutTests/js/regress/for-of-iterate-array-values-expected.txt
new file mode 100644 (file)
index 0000000..420c4ea
--- /dev/null
@@ -0,0 +1,10 @@
+JSRegress/for-of-iterate-array-values
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/regress/for-of-iterate-array-values.html b/LayoutTests/js/regress/for-of-iterate-array-values.html
new file mode 100644 (file)
index 0000000..f32342b
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="resources/regress-pre.js"></script>
+<script src="script-tests/for-of-iterate-array-values.js"></script>
+<script src="resources/regress-post.js"></script>
+<script src="../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/regress/script-tests/for-of-iterate-array-entries.js b/LayoutTests/js/regress/script-tests/for-of-iterate-array-entries.js
new file mode 100644 (file)
index 0000000..da3e4cb
--- /dev/null
@@ -0,0 +1,16 @@
+function foo() {
+    var array = [];
+    for (var i = 0; i < 25000; i++)
+        array.push(i);
+    
+    var result = 0;
+    for (var [key, value] of array.entries())
+        result += key + value + array[key];
+    
+    return result;
+}
+
+var result = foo() + foo();
+if (result != 1874925000)
+    throw "Bad result: " + result;
+
diff --git a/LayoutTests/js/regress/script-tests/for-of-iterate-array-keys.js b/LayoutTests/js/regress/script-tests/for-of-iterate-array-keys.js
new file mode 100644 (file)
index 0000000..a36c6cb
--- /dev/null
@@ -0,0 +1,16 @@
+function foo() {
+    var array = [];
+    for (var i = 0; i < 25000; i++)
+        array.push(i);
+    
+    var result = 0;
+    for (var key of array.keys())
+        result += key + array[key];
+    
+    return result;
+}
+
+var result = foo() + foo();
+if (result != 1249950000)
+    throw "Bad result: " + result;
+
diff --git a/LayoutTests/js/regress/script-tests/for-of-iterate-array-values.js b/LayoutTests/js/regress/script-tests/for-of-iterate-array-values.js
new file mode 100644 (file)
index 0000000..67e5b47
--- /dev/null
@@ -0,0 +1,16 @@
+function foo() {
+    var array = [];
+    for (var i = 0; i < 25000; i++)
+        array.push(i);
+    
+    var result = 0;
+    for (var i of array)
+        result += i;
+    
+    return result;
+}
+
+var result = foo() + foo();
+if (result != 624975000)
+    throw "Bad result: " + result;
+
index a7bf763..36cf9e9 100644 (file)
@@ -369,6 +369,37 @@ valid("({a: 1 || 1}.a = 1)");
 invalid("var a.b = c");
 invalid("var a.b;");
 
+valid("for (of of of){}")
+valid("for (of; of; of){}")
+valid("for (var of of of){}")
+valid("for (var of; of; of){}")
+invalid("for (var of.of of of){}")
+invalid("for (var of[of] of of){}")
+valid("for (of.of of of){}")
+valid("for (of[of] of of){}")
+valid("for (var [of] of of){}")
+valid("for (var {of} of of){}")
+valid("for (of in of){}")
+valid("for (var of in of){}")
+invalid("for (var of.of in of){}")
+valid("for (of.of in of){}")
+valid("for (of[of] in of){}")
+invalid("for (var of[of] in of){}")
+valid("for (var [of] in of){}")
+valid("for (var {of} in of){}")
+
+
+invalid("for (of of of of){}")
+invalid("for (of of; of; of){}")
+invalid("for (of of []; of; of){}")
+invalid("for (of of){}")
+invalid("for (var of of){}")
+invalid("for (of of in of){}")
+invalid("for (of in){}")
+invalid("for (var of in){}")
+
+
+
 try { eval("a.b.c = {};"); } catch(e1) { e=e1; shouldBe("e.line", "1") }
 foo = 'FAIL';
 bar = 'PASS';
index 91d0dbc..627d509 100644 (file)
@@ -1,3 +1,62 @@
+2013-10-04  Oliver Hunt  <oliver@apple.com>
+
+        Support for-of syntax
+        https://bugs.webkit.org/show_bug.cgi?id=122339
+
+        Reviewed by Geoffrey Garen.
+
+        Add support for for-of syntax to JSC.  As part of doing this I had to make
+        us support unique empty strings as identifiers.  In a follow on patch i'm
+        going to remove the distinction entirely as it's purely a complicating
+        separation.
+
+        Otherwise the logic here is fairly self-explanatory.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::addConstant):
+        (JSC::BytecodeGenerator::emitCall):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::CallArguments::CallArguments):
+        (JSC::ForOfNode::emitBytecode):
+        * jit/JITOperations.cpp:
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createForOfLoop):
+        * parser/NodeConstructors.h:
+        (JSC::EnumerationNode::EnumerationNode):
+        (JSC::ForInNode::ForInNode):
+        (JSC::ForOfNode::ForOfNode):
+        * parser/Nodes.h:
+        * parser/Parser.cpp:
+        (JSC::::parseVarDeclarationList):
+        (JSC::::parseForStatement):
+        * parser/Parser.h:
+        (JSC::Parser::isofToken):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createForOfLoop):
+        * runtime/ArrayIteratorPrototype.cpp:
+        (JSC::ArrayIteratorPrototype::finishCreation):
+        (JSC::arrayIteratorPrototypeIterate):
+        * runtime/ArrayPrototype.cpp:
+        (JSC::ArrayPrototype::create):
+        (JSC::ArrayPrototype::finishCreation):
+        * runtime/ArrayPrototype.h:
+        * runtime/CommonIdentifiers.cpp:
+        (JSC::CommonIdentifiers::CommonIdentifiers):
+        * runtime/CommonIdentifiers.h:
+        * runtime/Identifier.h:
+        (JSC::Identifier::from):
+        * runtime/JSCJSValue.cpp:
+        (JSC::JSValue::dumpInContext):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::reset):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::putDirectNativeFunction):
+        * runtime/PrivateName.h:
+        (JSC::PrivateName::PrivateName):
+        * runtime/PropertyName.h:
+        (JSC::PropertyName::PropertyName):
+
 2013-10-04  Michael Saboff  <msaboff@apple.com>
 
         FTL::OSRExit::convertToForward() shouldn't misuse Operands<>::operator[]
index 2125c4f..b4a55e7 100644 (file)
@@ -957,7 +957,7 @@ unsigned BytecodeGenerator::addConstant(const Identifier& ident)
     StringImpl* rep = ident.impl();
     IdentifierMap::AddResult result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers());
     if (result.isNewEntry)
-        m_codeBlock->addIdentifier(Identifier(m_vm, rep));
+        m_codeBlock->addIdentifier(ident);
 
     return result.iterator->value;
 }
@@ -1693,9 +1693,11 @@ RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Regi
 
     // Generate code for arguments.
     unsigned argument = 0;
-    for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next)
-        emitNode(callArguments.argumentRegister(argument++), n);
-
+    if (callArguments.argumentsNode()) {
+        for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next)
+            emitNode(callArguments.argumentRegister(argument++), n);
+    }
+    
     // Reserve space for call frame.
     Vector<RefPtr<RegisterID>, JSStack::CallFrameHeaderSize, UnsafeVectorOverflow> callFrame;
     for (int i = 0; i < JSStack::CallFrameHeaderSize; ++i)
index fcc17df..38b9294 100644 (file)
@@ -62,7 +62,7 @@ namespace JSC {
 
     class CallArguments {
     public:
-        CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode);
+        CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0);
 
         RegisterID* thisRegister() { return m_argv[0].get(); }
         RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); }
index 7410216..e86ce53 100644 (file)
@@ -379,13 +379,13 @@ RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
     return generator.emitConstruct(returnValue.get(), func.get(), expectedFunction, callArguments, divot(), divotStart(), divotEnd());
 }
 
-inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode)
+inline CallArguments::CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode, unsigned additionalArguments)
     : m_argumentsNode(argumentsNode)
 {
     if (generator.shouldEmitProfileHooks())
         m_profileHookRegister = generator.newTemporary();
 
-    size_t argumentCountIncludingThis = 1; // 'this' register.
+    size_t argumentCountIncludingThis = 1 + additionalArguments; // 'this' register.
     if (argumentsNode) {
         for (ArgumentListNode* node = argumentsNode->m_listNode; node; node = node->m_next)
             ++argumentCountIncludingThis;
@@ -1759,6 +1759,81 @@ void ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     generator.emitLabel(scope->breakTarget());
 }
 
+// ------------------------------ ForOfNode ------------------------------------
+
+void ForOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+    LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
+    
+    if (!m_lexpr->isLocation()) {
+        emitThrowReferenceError(generator, "Left side of for-of statement is not a reference.");
+        return;
+    }
+    
+    generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
+    RefPtr<RegisterID> subject = generator.emitNode(m_expr);
+    RefPtr<RegisterID> iterator = generator.emitGetById(generator.newTemporary(), subject.get(), generator.propertyNames().iteratorPrivateName);
+    {
+        CallArguments args(generator, 0);
+        generator.emitMove(args.thisRegister(), subject.get());
+        generator.emitCall(iterator.get(), iterator.get(), NoExpectedFunction, args, divot(), divotStart(), divotEnd());
+    }
+    RefPtr<RegisterID> iteratorNext = generator.emitGetById(generator.newTemporary(), iterator.get(), generator.propertyNames().next);
+    RefPtr<RegisterID> value = generator.newTemporary();
+    generator.emitLoad(value.get(), jsUndefined());
+    
+    generator.emitJump(scope->continueTarget());
+    
+    RefPtr<Label> loopStart = generator.newLabel();
+    generator.emitLabel(loopStart.get());
+    generator.emitLoopHint();
+    
+    if (m_lexpr->isResolveNode()) {
+        const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier();
+        if (Local local = generator.local(ident))
+            generator.emitMove(local.get(), value.get());
+        else {
+            if (generator.isStrictMode())
+                generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+            RegisterID* scope = generator.emitResolveScope(generator.newTemporary(), ident);
+            generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
+            generator.emitPutToScope(scope, ident, value.get(), generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound);
+        }
+    } else if (m_lexpr->isDotAccessorNode()) {
+        DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr);
+        const Identifier& ident = assignNode->identifier();
+        RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
+        
+        generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
+        generator.emitPutById(base.get(), ident, value.get());
+    } else if (m_lexpr->isBracketAccessorNode()) {
+        BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr);
+        RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
+        RegisterID* subscript = generator.emitNode(assignNode->subscript());
+        
+        generator.emitExpressionInfo(assignNode->divot(), assignNode->divotStart(), assignNode->divotEnd());
+        generator.emitPutByVal(base.get(), subscript, value.get());
+    } else {
+        ASSERT(m_lexpr->isDeconstructionNode());
+        DeconstructingAssignmentNode* assignNode = static_cast<DeconstructingAssignmentNode*>(m_lexpr);
+        assignNode->bindings()->emitBytecode(generator, value.get());
+    }
+    
+    generator.emitNode(dst, m_statement);
+    
+    generator.emitLabel(scope->continueTarget());
+    RefPtr<RegisterID> result = generator.newTemporary();
+    CallArguments nextArguments(generator, 0, 1);
+    generator.emitMove(nextArguments.thisRegister(), iterator.get());
+    generator.emitMove(nextArguments.argumentRegister(0), value.get());
+    generator.emitCall(result.get(), iteratorNext.get(), NoExpectedFunction, nextArguments, divot(), divotStart(), divotEnd());
+    generator.emitGetById(value.get(), result.get(), generator.propertyNames().value);
+    RefPtr<RegisterID> done = generator.emitGetById(generator.newTemporary(), result.get(), generator.propertyNames().done);
+    generator.emitJumpIfFalse(done.get(), loopStart.get());
+    generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
+    generator.emitLabel(scope->breakTarget());
+}
+
 // ------------------------------ ContinueNode ---------------------------------
 
 Label* ContinueNode::trivialTarget(BytecodeGenerator& generator)
index ba8fc63..a87be25 100644 (file)
@@ -74,8 +74,7 @@ EncodedJSValue JIT_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState
 {
     VM* vm = &exec->vm();
     NativeCallFrameTracer tracer(vm, exec);
-
-    Identifier ident(vm, uid);
+    Identifier ident = uid->isEmptyUnique() ? Identifier::from(PrivateName(uid)) : Identifier(vm, uid);
     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
 
index a37cdc7..48a83ec 100644 (file)
@@ -380,6 +380,22 @@ public:
         setExceptionLocation(result, eStart, eDivot, eEnd);
         return result;
     }
+    
+    StatementNode* createForOfLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
+    {
+        ForOfNode* result = new (m_vm) ForOfNode(location, lhs, iter, statements);
+        result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+        setExceptionLocation(result, eStart, eDivot, eEnd);
+        return result;
+    }
+    
+    StatementNode* createForOfLoop(const JSTokenLocation& location, PassRefPtr<DeconstructionPatternNode> pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end)
+    {
+        ForOfNode* result = new (m_vm) ForOfNode(m_vm, location, pattern.get(), iter, statements);
+        result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+        setExceptionLocation(result, eStart, eDivot, eEnd);
+        return result;
+    }
 
     StatementNode* createEmptyStatement(const JSTokenLocation& location) { return new (m_vm) EmptyStatementNode(location); }
 
index 0ce20eb..863aa9f 100644 (file)
@@ -811,7 +811,7 @@ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifie
     {
     }
 
-    inline ForInNode::ForInNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
+    inline EnumerationNode::EnumerationNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
         : StatementNode(location)
         , m_lexpr(l)
         , m_expr(expr)
@@ -820,7 +820,7 @@ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifie
         ASSERT(l);
     }
     
-    inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
+    inline EnumerationNode::EnumerationNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
         : StatementNode(location)
         , m_lexpr(new (vm) DeconstructingAssignmentNode(location, pattern, 0))
         , m_expr(expr)
@@ -829,6 +829,26 @@ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifie
         ASSERT(pattern);
     }
     
+    inline ForInNode::ForInNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
+        : EnumerationNode(location, l, expr, statement)
+    {
+    }
+    
+    inline ForInNode::ForInNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
+        : EnumerationNode(vm, location, pattern, expr, statement)
+    {
+    }
+    
+    inline ForOfNode::ForOfNode(const JSTokenLocation& location, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
+        : EnumerationNode(location, l, expr, statement)
+    {
+    }
+    
+    inline ForOfNode::ForOfNode(VM* vm, const JSTokenLocation& location, DeconstructionPatternNode* pattern, ExpressionNode* expr, StatementNode* statement)
+        : EnumerationNode(vm, location, pattern, expr, statement)
+    {
+    }
+    
     inline DeconstructionPatternNode::DeconstructionPatternNode(VM*)
     {
     }
index e702e3f..5d4416b 100644 (file)
@@ -1242,18 +1242,34 @@ namespace JSC {
     };
     
     class DeconstructionPatternNode;
-
-    class ForInNode : public StatementNode, public ThrowableExpressionData {
+    
+    class EnumerationNode : public StatementNode, public ThrowableExpressionData {
+    public:
+        EnumerationNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
+        EnumerationNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
+        
+    protected:
+        ExpressionNode* m_lexpr;
+        ExpressionNode* m_expr;
+        StatementNode* m_statement;
+    };
+    
+    class ForInNode : public EnumerationNode {
     public:
         ForInNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
         ForInNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
 
     private:
         virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
-
-        ExpressionNode* m_lexpr;
-        ExpressionNode* m_expr;
-        StatementNode* m_statement;
+    };
+    
+    class ForOfNode : public EnumerationNode {
+    public:
+        ForOfNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*);
+        ForOfNode(VM*, const JSTokenLocation&, DeconstructionPatternNode*, ExpressionNode*, StatementNode*);
+        
+    private:
+        virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0);
     };
 
     class ContinueNode : public StatementNode, public ThrowableExpressionData {
index 2619834..4af2aa2 100644 (file)
@@ -294,7 +294,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarati
             next();
             hasInitializer = match(EQUAL);
             failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode.");
-            context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
+            context.addVar(name, (hasInitializer || (!m_allowsIn && (match(INTOKEN) || isofToken()))) ? DeclarationStacks::HasInitializer : 0);
             if (hasInitializer) {
                 JSTextPosition varDivot = tokenStartPosition() + 1;
                 initStart = tokenStartPosition();
@@ -317,7 +317,6 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarati
                 TreeExpression rhs = parseExpression(context);
                 node = context.createDeconstructingAssignment(location, pattern, rhs);
             }
-            ASSERT(node);
         }
         
         if (hasInitializer) {
@@ -501,7 +500,12 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
         
         // Handle for-in with var declaration
         JSTextPosition inLocation = tokenStartPosition();
-        consumeOrFail(INTOKEN);
+        bool isOfEnumeration = false;
+        if (!consume(INTOKEN)) {
+            failIfFalseWithMessage(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+            isOfEnumeration = true;
+            next();
+        }
         
         TreeExpression expr = parseExpression(context);
         failIfFalse(expr);
@@ -515,6 +519,8 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
         TreeStatement statement = parseStatement(context, unused);
         endLoop();
         failIfFalse(statement);
+        if (isOfEnumeration)
+            return context.createForOfLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine);
         return context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine);
     }
     
@@ -556,7 +562,12 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
     
     // For-in loop
     failIfFalse(nonLHSCount == m_nonLHSCount);
-    consumeOrFail(INTOKEN);
+    bool isOfEnumeration = false;
+    if (!consume(INTOKEN)) {
+        failIfFalseWithMessage(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+        isOfEnumeration = true;
+        next();
+    }
     TreeExpression expr = parseExpression(context);
     failIfFalse(expr);
     JSTextPosition exprEnd = lastTokenEndPosition();
@@ -567,7 +578,8 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(
     TreeStatement statement = parseStatement(context, unused);
     endLoop();
     failIfFalse(statement);
-    
+    if (isOfEnumeration)
+        return context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
     return context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
 }
 
index 818948b..1aad225 100644 (file)
@@ -555,6 +555,11 @@ private:
         return m_token.m_type == expected;
     }
     
+    ALWAYS_INLINE bool isofToken()
+    {
+        return m_token.m_type == IDENT && *m_token.m_data.ident == m_vm->propertyNames->of;
+    }
+    
     ALWAYS_INLINE unsigned tokenStart()
     {
         return m_token.m_location.startOffset;
index 965ff0d..2d05ce7 100644 (file)
@@ -189,6 +189,7 @@ public:
     int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return 1; }
     int createForLoop(const JSTokenLocation&, int, int, int, int, int, int) { return 1; }
     int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return 1; }
+    int createForOfLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int) { return 1; }
     int createEmptyStatement(const JSTokenLocation&) { return 1; }
     int createVarStatement(const JSTokenLocation&, int, int, int) { return 1; }
     int createReturnStatement(const JSTokenLocation&, int, int, int) { return 1; }
index 2c8fa15..6f495ca 100644 (file)
@@ -37,6 +37,7 @@ namespace JSC {
 const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArrayIteratorPrototype) };
 
 static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeNext(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(ExecState*);
 
 void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
@@ -45,6 +46,7 @@ void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject
     vm.prototypeMap.addPrototype(this);
 
     JSC_NATIVE_FUNCTION(vm.propertyNames->next, arrayIteratorPrototypeNext, DontEnum, 0);
+    JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayIteratorPrototypeIterate, DontEnum, 0);
 }
 
 static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationKind kind, size_t index, JSValue result, bool done)
@@ -76,7 +78,7 @@ static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationK
     }
     return JSValue::encode(resultObject);
 }
-    
+
 EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeNext(CallFrame* callFrame)
 {
     JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue());
@@ -129,4 +131,9 @@ EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeNext(CallFrame* callFrame)
     return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length);
 }
 
+EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(CallFrame* callFrame)
+{
+    return JSValue::encode(callFrame->thisValue());
+}
+
 }
index b2f6a98..339da74 100644 (file)
@@ -122,10 +122,10 @@ const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecStat
 @end
 */
 
-ArrayPrototype* ArrayPrototype::create(VM& vm, Structure* structure)
+ArrayPrototype* ArrayPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
 {
     ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(vm.heap)) ArrayPrototype(vm, structure);
-    prototype->finishCreation(vm);
+    prototype->finishCreation(vm, globalObject);
     return prototype;
 }
 
@@ -135,11 +135,12 @@ ArrayPrototype::ArrayPrototype(VM& vm, Structure* structure)
 {
 }
 
-void ArrayPrototype::finishCreation(VM& vm)
+void ArrayPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(info()));
     vm.prototypeMap.addPrototype(this);
+    JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayProtoFuncValues, DontEnum, 0);
 }
 
 bool ArrayPrototype::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
index 545f019..472a1dd 100644 (file)
@@ -33,7 +33,7 @@ private:
 public:
     typedef JSArray Base;
 
-    static ArrayPrototype* create(VM&, Structure*);
+    static ArrayPrototype* create(VM&, JSGlobalObject*, Structure*);
         
     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
 
@@ -45,7 +45,7 @@ public:
     }
 
 protected:
-    void finishCreation(VM&);
+    void finishCreation(VM&, JSGlobalObject*);
 };
 
 } // namespace JSC
index e19df1c..b5eb72f 100644 (file)
@@ -21,6 +21,8 @@
 #include "config.h"
 #include "CommonIdentifiers.h"
 
+#include "PrivateName.h"
+
 namespace JSC {
 
 #define INITIALIZE_PROPERTY_NAME(name) , name(vm, #name)
@@ -32,6 +34,8 @@ CommonIdentifiers::CommonIdentifiers(VM* vm)
     , underscoreProto(vm, "__proto__")
     , thisIdentifier(vm, "this")
     , useStrictIdentifier(vm, "use strict")
+    , iteratorPrivateName(Identifier::from(PrivateName()))
+    , hasNextIdentifier(vm, "hasNext")
     JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(INITIALIZE_KEYWORD)
     JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
 {
index d87d0b4..2f60900 100644 (file)
     macro(numInlinedCalls) \
     macro(numInlinedGetByIds) \
     macro(numInlinedPutByIds) \
+    macro(of) \
     macro(opcode) \
     macro(origin) \
     macro(osrExitSites) \
@@ -211,7 +212,8 @@ namespace JSC {
         const Identifier underscoreProto;
         const Identifier thisIdentifier;
         const Identifier useStrictIdentifier;
-        const PrivateName iteratorPrivateName;
+        const Identifier iteratorPrivateName;
+        const Identifier hasNextIdentifier;
 
         
 #define JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL(name) const Identifier name##Keyword;
index bd1eecc..03b1b63 100644 (file)
@@ -61,9 +61,11 @@ namespace JSC {
         CString ascii() const { return m_string.ascii(); }
         CString utf8() const { return m_string.utf8(); }
         
-        static Identifier createEmptyUnique(VM* vm)
+        static Identifier from(const PrivateName& name)
         {
-            return Identifier(vm, String(StringImpl::createEmptyUnique()));
+            Identifier result;
+            result.m_string = name.uid();
+            return result;
         }
 
         static Identifier createLCharFromUChar(VM* vm, const UChar* s, int length) { return Identifier(vm, add8(vm, s, length)); }
index 5a59f1e..5cf8fe3 100644 (file)
@@ -39,5 +39,18 @@ void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject*, ArrayIterationKind
     m_iterationKind = kind;
     m_iteratedObject.set(vm, this, iteratedObject);
 }
+    
+    
+void JSArrayIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    JSArrayIterator* thisObject = jsCast<JSArrayIterator*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+    ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+        
+    Base::visitChildren(thisObject, visitor);
+    visitor.append(&thisObject->m_iteratedObject);
+
+}
 
 }
index 1ef0557..ba85646 100644 (file)
@@ -69,7 +69,7 @@ public:
 
 private:
 
-    static const unsigned StructureFlags = Base::StructureFlags;
+    static const unsigned StructureFlags = Base::StructureFlags | OverridesVisitChildren;
 
     JSArrayIterator(VM& vm, Structure* structure)
         : Base(vm, structure)
@@ -78,6 +78,7 @@ private:
     }
 
     void finishCreation(VM&, JSGlobalObject*, ArrayIterationKind, JSObject* iteratedObject);
+    static void visitChildren(JSCell*, SlotVisitor&);
     
     ArrayIterationKind m_iterationKind;
     WriteBarrier<JSObject> m_iteratedObject;
index 8f20f63..1f9cc80 100644 (file)
@@ -216,6 +216,8 @@ void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const
                     out.print(" (atomic)");
                 if (impl->isIdentifier())
                     out.print(" (identifier)");
+                if (impl->isEmptyUnique())
+                    out.print(" (unique)");
             } else
                 out.print(" (unresolved)");
             out.print(": ", impl);
index 92f5aba..1924460 100644 (file)
@@ -286,7 +286,7 @@ void JSGlobalObject::reset(JSValue prototype)
     m_objcWrapperObjectStructure.set(vm, this, JSCallbackObject<JSAPIWrapperObject>::createStructure(vm, this, m_objectPrototype.get()));
 #endif
 
-    m_arrayPrototype.set(vm, this, ArrayPrototype::create(vm, ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
+    m_arrayPrototype.set(vm, this, ArrayPrototype::create(vm, this, ArrayPrototype::createStructure(vm, this, m_objectPrototype.get())));
     
     m_originalArrayStructureForIndexingShape[UndecidedShape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithUndecided));
     m_originalArrayStructureForIndexingShape[Int32Shape >> IndexingShapeShift].set(vm, this, JSArray::createStructure(vm, this, m_arrayPrototype.get(), ArrayWithInt32));
index 23c78fa..be6d550 100644 (file)
@@ -2204,6 +2204,8 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV
 void JSObject::putDirectNativeFunction(VM& vm, JSGlobalObject* globalObject, const PropertyName& propertyName, unsigned functionLength, NativeFunction nativeFunction, Intrinsic intrinsic, unsigned attributes)
 {
     StringImpl* name = propertyName.publicName();
+    if (!name)
+        name = vm.propertyNames->anonymous.impl();
     ASSERT(name);
 
     JSFunction* function = JSFunction::create(vm, globalObject, functionLength, name, nativeFunction, intrinsic);
index 91254fc..5d2774a 100644 (file)
@@ -36,6 +36,11 @@ public:
         : m_impl(StringImpl::createEmptyUnique())
     {
     }
+    explicit PrivateName(StringImpl* uid)
+        : m_impl(uid)
+    {
+        ASSERT(m_impl->isEmptyUnique());
+    }
 
     StringImpl* uid() const { return m_impl.get(); }
 
index 7253756..e4d5fab 100644 (file)
@@ -81,7 +81,7 @@ public:
     PropertyName(const Identifier& propertyName)
         : m_impl(propertyName.impl())
     {
-        ASSERT(!m_impl || m_impl->isIdentifier());
+        ASSERT(!m_impl || m_impl->isIdentifier() || m_impl->isEmptyUnique());
     }
 
     PropertyName(const PrivateName& propertyName)
index 0818b1d..84b0147 100644 (file)
@@ -1,3 +1,18 @@
+2013-10-04  Oliver Hunt  <oliver@apple.com>
+
+        Support for-of syntax
+        https://bugs.webkit.org/show_bug.cgi?id=122339
+
+        Reviewed by Geoffrey Garen.
+
+        Update assertions and add a helper function to StringImpl
+        to save repeated unique or identifier calls.
+
+        * wtf/text/StringImpl.h:
+        (WTF::StringImpl::isIdentifierOrUnique):
+        (WTF::StringImpl::setIsIdentifier):
+        (WTF::StringImpl::setIsAtomic):
+
 2013-10-02  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] Update solutions and projects to support 64-bit build.
index 8766612..eceff59 100644 (file)
@@ -501,9 +501,11 @@ public:
     bool has16BitShadow() const { return m_hashAndFlags & s_hashFlagHas16BitShadow; }
     WTF_EXPORT_STRING_API void upconvertCharacters(unsigned, unsigned) const;
     bool isIdentifier() const { return m_hashAndFlags & s_hashFlagIsIdentifier; }
+    bool isIdentifierOrUnique() const { return isIdentifier() || isEmptyUnique(); }
     void setIsIdentifier(bool isIdentifier)
     {
         ASSERT(!isStatic());
+        ASSERT(!isEmptyUnique());
         if (isIdentifier)
             m_hashAndFlags |= s_hashFlagIsIdentifier;
         else
@@ -519,6 +521,7 @@ public:
     void setIsAtomic(bool isAtomic)
     {
         ASSERT(!isStatic());
+        ASSERT(!isEmptyUnique());
         if (isAtomic)
             m_hashAndFlags |= s_hashFlagIsAtomic;
         else