REGRESSION (172175-172177): Change in for...in processing causes properties added...
authormsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Mar 2015 10:05:21 +0000 (10:05 +0000)
committermsaboff@apple.com <msaboff@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 Mar 2015 10:05:21 +0000 (10:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142856

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Refactored the way the for .. in enumeration over objects is done.  We used to make three C++ calls to
get info for three loops to iterate over indexed properties, structure properties and other properties,
respectively.  We still have the three loops, but now we make one C++ call to get all the info needed
for all loops before we exectue any enumeration.

The JSPropertyEnumerator has a count of the indexed properties and a list of named properties.
The named properties are one list, with structured properties in the range [0,m_endStructurePropertyIndex)
and the generic properties in the range [m_endStructurePropertyIndex, m_endGenericPropertyIndex);

Eliminated the bytecodes op_get_structure_property_enumerator, op_get_generic_property_enumerator and
op_next_enumerator_pname.
Added the bytecodes op_get_property_enumerator, op_enumerator_structure_pname and op_enumerator_generic_pname.
The bytecodes op_enumerator_structure_pname and op_enumerator_generic_pname are similar except for what
end value we stop iterating on.

Made corresponding node changes to the DFG and FTL for the bytecode changes.

* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetPropertyEnumerator):
(JSC::BytecodeGenerator::emitEnumeratorStructurePropertyName):
(JSC::BytecodeGenerator::emitEnumeratorGenericPropertyName):
(JSC::BytecodeGenerator::emitGetStructurePropertyEnumerator): Deleted.
(JSC::BytecodeGenerator::emitGetGenericPropertyEnumerator): Deleted.
(JSC::BytecodeGenerator::emitNextEnumeratorPropertyName): Deleted.
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ForInNode::emitMultiLoopBytecode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLAbstractHeapRepository.h:
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength):
(JSC::FTL::LowerDFGToLLVM::compileGetPropertyEnumerator):
(JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorStructurePname):
(JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorGenericPname):
(JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator): Deleted.
(JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator): Deleted.
(JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname): Deleted.
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_enumerator_structure_pname):
(JSC::JIT::emit_op_enumerator_generic_pname):
(JSC::JIT::emit_op_get_property_enumerator):
(JSC::JIT::emit_op_next_enumerator_pname): Deleted.
(JSC::JIT::emit_op_get_structure_property_enumerator): Deleted.
(JSC::JIT::emit_op_get_generic_property_enumerator): Deleted.
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_enumerator_structure_pname):
(JSC::JIT::emit_op_enumerator_generic_pname):
(JSC::JIT::emit_op_next_enumerator_pname): Deleted.
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* llint/LowLevelInterpreter.asm:
* runtime/CommonSlowPaths.cpp:
(JSC::SLOW_PATH_DECL):
* runtime/CommonSlowPaths.h:
* runtime/JSPropertyNameEnumerator.cpp:
(JSC::JSPropertyNameEnumerator::create):
(JSC::JSPropertyNameEnumerator::finishCreation):
* runtime/JSPropertyNameEnumerator.h:
(JSC::JSPropertyNameEnumerator::indexedLength):
(JSC::JSPropertyNameEnumerator::endStructurePropertyIndex):
(JSC::JSPropertyNameEnumerator::endGenericPropertyIndex):
(JSC::JSPropertyNameEnumerator::indexedLengthOffset):
(JSC::JSPropertyNameEnumerator::endStructurePropertyIndexOffset):
(JSC::JSPropertyNameEnumerator::endGenericPropertyIndexOffset):
(JSC::JSPropertyNameEnumerator::cachedInlineCapacityOffset):
(JSC::propertyNameEnumerator):
(JSC::JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset): Deleted.
(JSC::structurePropertyNameEnumerator): Deleted.
(JSC::genericPropertyNameEnumerator): Deleted.
* runtime/Structure.cpp:
(JSC::Structure::setCachedPropertyNameEnumerator):
(JSC::Structure::cachedPropertyNameEnumerator):
(JSC::Structure::canCachePropertyNameEnumerator):
(JSC::Structure::setCachedStructurePropertyNameEnumerator): Deleted.
(JSC::Structure::cachedStructurePropertyNameEnumerator): Deleted.
(JSC::Structure::setCachedGenericPropertyNameEnumerator): Deleted.
(JSC::Structure::cachedGenericPropertyNameEnumerator): Deleted.
(JSC::Structure::canCacheStructurePropertyNameEnumerator): Deleted.
(JSC::Structure::canCacheGenericPropertyNameEnumerator): Deleted.
* runtime/Structure.h:
* runtime/StructureRareData.cpp:
(JSC::StructureRareData::visitChildren):
(JSC::StructureRareData::cachedPropertyNameEnumerator):
(JSC::StructureRareData::setCachedPropertyNameEnumerator):
(JSC::StructureRareData::cachedStructurePropertyNameEnumerator): Deleted.
(JSC::StructureRareData::setCachedStructurePropertyNameEnumerator): Deleted.
(JSC::StructureRareData::cachedGenericPropertyNameEnumerator): Deleted.
(JSC::StructureRareData::setCachedGenericPropertyNameEnumerator): Deleted.
* runtime/StructureRareData.h:
* tests/stress/for-in-delete-during-iteration.js:

LayoutTests:

New tests and rebased one test.

* js/for-in-modify-in-loop-expected.txt: Added.
* js/for-in-modify-in-loop.html: Added.
* js/script-tests/for-in-modify-in-loop.js: Added.
(haveSameProperties):
(each):
(testAdd):
(testAddDelete):
* http/tests/security/cross-frame-access-enumeration-expected.txt: Rebased.

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

42 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
LayoutTests/js/for-in-modify-in-loop-expected.txt [new file with mode: 0644]
LayoutTests/js/for-in-modify-in-loop.html [new file with mode: 0644]
LayoutTests/js/script-tests/for-in-modify-in-loop.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/runtime/CommonSlowPaths.cpp
Source/JavaScriptCore/runtime/CommonSlowPaths.h
Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.cpp
Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureRareData.cpp
Source/JavaScriptCore/runtime/StructureRareData.h
Source/JavaScriptCore/tests/stress/for-in-delete-during-iteration.js

index 46821b1..99a3a07 100644 (file)
@@ -1,3 +1,21 @@
+2015-03-24  Michael Saboff  <msaboff@apple.com>
+
+        REGRESSION (172175-172177): Change in for...in processing causes properties added in loop to be enumerated
+        https://bugs.webkit.org/show_bug.cgi?id=142856
+
+        Reviewed by Filip Pizlo.
+
+        New tests and rebased one test.
+
+        * js/for-in-modify-in-loop-expected.txt: Added.
+        * js/for-in-modify-in-loop.html: Added.
+        * js/script-tests/for-in-modify-in-loop.js: Added.
+        (haveSameProperties):
+        (each):
+        (testAdd):
+        (testAddDelete):
+        * http/tests/security/cross-frame-access-enumeration-expected.txt: Rebased.
+
 2015-03-24  Saam Barati  <saambarati1@gmail.com>
 
         Improve error messages in JSC
index c651544..a3c57ba 100644 (file)
@@ -9,6 +9,7 @@ CONSOLE MESSAGE: line 75: Blocked a frame with origin "http://127.0.0.1:8000" fr
 CONSOLE MESSAGE: line 82: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 29: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 29: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 29: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 102: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 CONSOLE MESSAGE: line 109: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
 This tests that variable names can't be enumerated cross domain (see http://bugs.webkit.org/show_bug.cgi?id=16387)
diff --git a/LayoutTests/js/for-in-modify-in-loop-expected.txt b/LayoutTests/js/for-in-modify-in-loop-expected.txt
new file mode 100644 (file)
index 0000000..ceff430
--- /dev/null
@@ -0,0 +1,12 @@
+Check for ... in will properly enumerate elements added or deleted during the loop
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS haveSameProperties(testAdd(), { a: 1, m : 1, z : 1 }) is true
+PASS haveSameProperties(testDelete(), { a: 1, b : 1, d : 1 }) is true
+PASS haveSameProperties(testAddDelete(), { a: 1, b : 1, j : 1 }) is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/for-in-modify-in-loop.html b/LayoutTests/js/for-in-modify-in-loop.html
new file mode 100644 (file)
index 0000000..64100a8
--- /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/for-in-modify-in-loop.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/script-tests/for-in-modify-in-loop.js b/LayoutTests/js/script-tests/for-in-modify-in-loop.js
new file mode 100644 (file)
index 0000000..0713968
--- /dev/null
@@ -0,0 +1,97 @@
+description("Check for ... in will properly enumerate elements added or deleted during the loop");
+
+function haveSameProperties(a, b) {
+    var p;
+
+    for (p in a) {
+        if (!b.hasOwnProperty(p))
+            return false;
+    }
+
+    for (p in b) {
+        if (!a.hasOwnProperty(p))
+            return false;
+    }
+
+    return true;
+}
+
+function each(o, callback) {
+    var result = {};
+
+    for (var property in o) {
+        callback(property, o);
+        if (result.hasOwnProperty(property))
+            throw "Duplicate property \"" + property + "\" enumerated";
+        result[property] = 1;
+    }
+
+    return result;
+}
+
+function testAdd()
+{
+    var obj = { a : "First" };
+    obj["m"] = "Second";
+    obj["z"] = "Third";
+
+    var elementsToAdd = [ "c", "t", "k" ];
+    var addIndex = 0;
+
+    var result = {};
+
+    return each(obj, function(p, o) {
+        if (addIndex < elementsToAdd.length)
+            o[elementsToAdd[addIndex++]] = "Added #" + addIndex;
+    });
+}
+
+function testDelete()
+{
+    var obj = { a : "First" };
+    obj["b"] = "Second";
+    obj["c"] = "Third";
+    obj["d"] = "Fourth";
+
+    var elementsToDelete = [ "c" ];
+    var deleteIndex = 0;
+
+    return each(obj, function(p, o) {
+        if (deleteIndex < elementsToDelete.length)
+            delete o[elementsToDelete[deleteIndex++]];
+   });
+}
+
+function testAddDelete()
+{
+    var obj = { a : "First", b : "Second", c : "Third", j : "Fourth", z : "Fifth", lastOne : "The End" };
+
+    elementsToAdd = [ "d", "p" ];
+    elementsToDelete = [ "z", "lastOne", "c" ];
+    var loopIndex = 0;
+
+    return each(obj, function(p, o) {
+        if (loopIndex++ == 1) {
+            for (var i = 0; i < elementsToAdd.length; i++)
+                o[elementsToAdd[i]] = "Added #" + i;
+            for (var i = 0; i < elementsToDelete.length; i++)
+                delete o[elementsToDelete[i]];
+        }
+   });
+}
+
+shouldBeTrue("haveSameProperties(testAdd(), { a: 1, m : 1, z : 1 })");
+shouldBeTrue("haveSameProperties(testDelete(), { a: 1, b : 1, d : 1 })");
+shouldBeTrue("haveSameProperties(testAddDelete(), { a: 1, b : 1, j : 1 })");
+
+for (var i = 0; i < 10000; i++) {
+    if (!haveSameProperties(testAdd(), { a: 1, m : 1, z : 1 }))
+        shouldBeTrue("haveSameProperties(testAdd(), { a: 1, m : 1, z : 1 })");
+
+    if (!haveSameProperties(testDelete(), { a: 1, b : 1, d : 1 }))
+        shouldBeTrue("haveSameProperties(testDelete(), { a: 1, b : 1, d : 1 })");
+
+    if (!haveSameProperties(testAddDelete(), { a: 1, b : 1, j : 1 }))
+        shouldBeTrue("haveSameProperties(testAddDelete(), { a: 1, b : 1, j : 1 })");
+}
+
index 25659af..49cf8d9 100644 (file)
@@ -1,5 +1,135 @@
 2015-03-24  Michael Saboff  <msaboff@apple.com>
 
+        REGRESSION (172175-172177): Change in for...in processing causes properties added in loop to be enumerated
+        https://bugs.webkit.org/show_bug.cgi?id=142856
+
+        Reviewed by Filip Pizlo.
+
+        Refactored the way the for .. in enumeration over objects is done.  We used to make three C++ calls to
+        get info for three loops to iterate over indexed properties, structure properties and other properties,
+        respectively.  We still have the three loops, but now we make one C++ call to get all the info needed
+        for all loops before we exectue any enumeration.
+
+        The JSPropertyEnumerator has a count of the indexed properties and a list of named properties.
+        The named properties are one list, with structured properties in the range [0,m_endStructurePropertyIndex)
+        and the generic properties in the range [m_endStructurePropertyIndex, m_endGenericPropertyIndex);
+
+        Eliminated the bytecodes op_get_structure_property_enumerator, op_get_generic_property_enumerator and
+        op_next_enumerator_pname.
+        Added the bytecodes op_get_property_enumerator, op_enumerator_structure_pname and op_enumerator_generic_pname.
+        The bytecodes op_enumerator_structure_pname and op_enumerator_generic_pname are similar except for what
+        end value we stop iterating on.
+
+        Made corresponding node changes to the DFG and FTL for the bytecode changes.
+
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitGetPropertyEnumerator):
+        (JSC::BytecodeGenerator::emitEnumeratorStructurePropertyName):
+        (JSC::BytecodeGenerator::emitEnumeratorGenericPropertyName):
+        (JSC::BytecodeGenerator::emitGetStructurePropertyEnumerator): Deleted.
+        (JSC::BytecodeGenerator::emitGetGenericPropertyEnumerator): Deleted.
+        (JSC::BytecodeGenerator::emitNextEnumeratorPropertyName): Deleted.
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ForInNode::emitMultiLoopBytecode):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLAbstractHeapRepository.h:
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileGetEnumerableLength):
+        (JSC::FTL::LowerDFGToLLVM::compileGetPropertyEnumerator):
+        (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorStructurePname):
+        (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorGenericPname):
+        (JSC::FTL::LowerDFGToLLVM::compileGetStructurePropertyEnumerator): Deleted.
+        (JSC::FTL::LowerDFGToLLVM::compileGetGenericPropertyEnumerator): Deleted.
+        (JSC::FTL::LowerDFGToLLVM::compileGetEnumeratorPname): Deleted.
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_enumerator_structure_pname):
+        (JSC::JIT::emit_op_enumerator_generic_pname):
+        (JSC::JIT::emit_op_get_property_enumerator):
+        (JSC::JIT::emit_op_next_enumerator_pname): Deleted.
+        (JSC::JIT::emit_op_get_structure_property_enumerator): Deleted.
+        (JSC::JIT::emit_op_get_generic_property_enumerator): Deleted.
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_enumerator_structure_pname):
+        (JSC::JIT::emit_op_enumerator_generic_pname):
+        (JSC::JIT::emit_op_next_enumerator_pname): Deleted.
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * llint/LowLevelInterpreter.asm:
+        * runtime/CommonSlowPaths.cpp:
+        (JSC::SLOW_PATH_DECL):
+        * runtime/CommonSlowPaths.h:
+        * runtime/JSPropertyNameEnumerator.cpp:
+        (JSC::JSPropertyNameEnumerator::create):
+        (JSC::JSPropertyNameEnumerator::finishCreation):
+        * runtime/JSPropertyNameEnumerator.h:
+        (JSC::JSPropertyNameEnumerator::indexedLength):
+        (JSC::JSPropertyNameEnumerator::endStructurePropertyIndex):
+        (JSC::JSPropertyNameEnumerator::endGenericPropertyIndex):
+        (JSC::JSPropertyNameEnumerator::indexedLengthOffset):
+        (JSC::JSPropertyNameEnumerator::endStructurePropertyIndexOffset):
+        (JSC::JSPropertyNameEnumerator::endGenericPropertyIndexOffset):
+        (JSC::JSPropertyNameEnumerator::cachedInlineCapacityOffset):
+        (JSC::propertyNameEnumerator):
+        (JSC::JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset): Deleted.
+        (JSC::structurePropertyNameEnumerator): Deleted.
+        (JSC::genericPropertyNameEnumerator): Deleted.
+        * runtime/Structure.cpp:
+        (JSC::Structure::setCachedPropertyNameEnumerator):
+        (JSC::Structure::cachedPropertyNameEnumerator):
+        (JSC::Structure::canCachePropertyNameEnumerator):
+        (JSC::Structure::setCachedStructurePropertyNameEnumerator): Deleted.
+        (JSC::Structure::cachedStructurePropertyNameEnumerator): Deleted.
+        (JSC::Structure::setCachedGenericPropertyNameEnumerator): Deleted.
+        (JSC::Structure::cachedGenericPropertyNameEnumerator): Deleted.
+        (JSC::Structure::canCacheStructurePropertyNameEnumerator): Deleted.
+        (JSC::Structure::canCacheGenericPropertyNameEnumerator): Deleted.
+        * runtime/Structure.h:
+        * runtime/StructureRareData.cpp:
+        (JSC::StructureRareData::visitChildren):
+        (JSC::StructureRareData::cachedPropertyNameEnumerator):
+        (JSC::StructureRareData::setCachedPropertyNameEnumerator):
+        (JSC::StructureRareData::cachedStructurePropertyNameEnumerator): Deleted.
+        (JSC::StructureRareData::setCachedStructurePropertyNameEnumerator): Deleted.
+        (JSC::StructureRareData::cachedGenericPropertyNameEnumerator): Deleted.
+        (JSC::StructureRareData::setCachedGenericPropertyNameEnumerator): Deleted.
+        * runtime/StructureRareData.h:
+        * tests/stress/for-in-delete-during-iteration.js:
+
+2015-03-24  Michael Saboff  <msaboff@apple.com>
+
         Unreviewed build fix for debug builds.
 
         * runtime/ExceptionHelpers.cpp:
index 954267f..fed6c46 100644 (file)
             { "name" : "op_has_structure_property", "length" : 5 },
             { "name" : "op_has_generic_property", "length" : 4 },
             { "name" : "op_get_direct_pname", "length" : 7 },
-            { "name" : "op_get_structure_property_enumerator", "length" : 4 },
-            { "name" : "op_get_generic_property_enumerator", "length" : 5 },
-            { "name" : "op_next_enumerator_pname", "length" : 4 },
+            { "name" : "op_get_property_enumerator", "length" : 3 },
+            { "name" : "op_enumerator_structure_pname", "length" : 4 },
+            { "name" : "op_enumerator_generic_pname", "length" : 4 },
             { "name" : "op_to_index_string", "length" : 3 }
         ]
     },
index 8952cda..79c7b7d 100644 (file)
@@ -113,6 +113,7 @@ void computeUsesForBytecodeOffset(
         return;
     }
     case op_create_lexical_environment:
+    case op_get_property_enumerator:
     case op_get_enumerable_length:
     case op_new_func_exp:
     case op_to_index_string:
@@ -149,9 +150,9 @@ void computeUsesForBytecodeOffset(
         return;
     }
     case op_has_generic_property:
-    case op_get_structure_property_enumerator:
     case op_has_indexed_property:
-    case op_next_enumerator_pname:
+    case op_enumerator_structure_pname:
+    case op_enumerator_generic_pname:
     case op_get_by_val:
     case op_in:
     case op_instanceof:
@@ -182,7 +183,6 @@ void computeUsesForBytecodeOffset(
     }
     case op_has_structure_property:
     case op_get_argument_by_val:
-    case op_get_generic_property_enumerator:
     case op_construct_varargs:
     case op_call_varargs: {
         functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
@@ -291,14 +291,14 @@ void computeDefsForBytecodeOffset(CodeBlock* codeBlock, unsigned bytecodeOffset,
         return;
     // These all have a single destination for the first argument.
     case op_to_index_string:
-    case op_get_generic_property_enumerator:
     case op_get_enumerable_length:
     case op_has_indexed_property:
     case op_has_structure_property:
     case op_has_generic_property:
     case op_get_direct_pname:
-    case op_get_structure_property_enumerator:
-    case op_next_enumerator_pname:
+    case op_get_property_enumerator:
+    case op_enumerator_structure_pname:
+    case op_enumerator_generic_pname:
     case op_pop_scope:
     case op_push_name_scope:
     case op_push_with_scope:
index 5ce2cc4..708b6e3 100644 (file)
@@ -1408,31 +1408,30 @@ void CodeBlock::dumpBytecode(
             break;
 
         }
-        case op_get_structure_property_enumerator: {
+        case op_get_property_enumerator: {
             int dst = it[1].u.operand;
             int base = it[2].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_get_structure_property_enumerator");
+            printLocationAndOp(out, exec, location, it, "op_get_property_enumerator");
             out.printf("%s, %s", registerName(dst).data(), registerName(base).data());
-            it += OPCODE_LENGTH(op_get_structure_property_enumerator) - 1;
+            it += OPCODE_LENGTH(op_get_property_enumerator) - 1;
             break;
         }
-        case op_get_generic_property_enumerator: {
+        case op_enumerator_structure_pname: {
             int dst = it[1].u.operand;
-            int base = it[2].u.operand;
-            int length = it[3].u.operand;
-            int structureEnumerator = it[4].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_get_generic_property_enumerator");
-            out.printf("%s, %s, %s, %s", registerName(dst).data(), registerName(base).data(), registerName(length).data(), registerName(structureEnumerator).data());
-            it += OPCODE_LENGTH(op_get_generic_property_enumerator) - 1;
+            int enumerator = it[2].u.operand;
+            int index = it[3].u.operand;
+            printLocationAndOp(out, exec, location, it, "op_enumerator_structure_pname");
+            out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data());
+            it += OPCODE_LENGTH(op_enumerator_structure_pname) - 1;
             break;
         }
-        case op_next_enumerator_pname: {
+        case op_enumerator_generic_pname: {
             int dst = it[1].u.operand;
             int enumerator = it[2].u.operand;
             int index = it[3].u.operand;
-            printLocationAndOp(out, exec, location, it, "op_next_enumerator_pname");
+            printLocationAndOp(out, exec, location, it, "op_enumerator_generic_pname");
             out.printf("%s, %s, %s", registerName(dst).data(), registerName(enumerator).data(), registerName(index).data());
-            it += OPCODE_LENGTH(op_next_enumerator_pname) - 1;
+            it += OPCODE_LENGTH(op_enumerator_generic_pname) - 1;
             break;
         }
         case op_to_index_string: {
index f44d970..c26dc35 100644 (file)
@@ -2701,28 +2701,26 @@ RegisterID* BytecodeGenerator::emitHasStructureProperty(RegisterID* dst, Registe
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length)
+RegisterID* BytecodeGenerator::emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base)
 {
-    emitOpcode(op_get_structure_property_enumerator);
+    emitOpcode(op_get_property_enumerator);
     instructions().append(dst->index());
     instructions().append(base->index());
-    instructions().append(length->index());
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator)
+RegisterID* BytecodeGenerator::emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
 {
-    emitOpcode(op_get_generic_property_enumerator);
+    emitOpcode(op_enumerator_structure_pname);
     instructions().append(dst->index());
-    instructions().append(base->index());
-    instructions().append(length->index());
-    instructions().append(structureEnumerator->index());
+    instructions().append(enumerator->index());
+    instructions().append(index->index());
     return dst;
 }
 
-RegisterID* BytecodeGenerator::emitNextEnumeratorPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
+RegisterID* BytecodeGenerator::emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index)
 {
-    emitOpcode(op_next_enumerator_pname);
+    emitOpcode(op_enumerator_generic_pname);
     instructions().append(dst->index());
     instructions().append(enumerator->index());
     instructions().append(index->index());
index 5f21b5a..190b436 100644 (file)
@@ -531,10 +531,12 @@ namespace JSC {
         RegisterID* emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName);
         RegisterID* emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator);
         RegisterID* emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName);
+        RegisterID* emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base);
         RegisterID* emitGetEnumerableLength(RegisterID* dst, RegisterID* base);
         RegisterID* emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length);
         RegisterID* emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator);
-        RegisterID* emitNextEnumeratorPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index);
+        RegisterID* emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index);
+        RegisterID* emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index);
         RegisterID* emitToIndexString(RegisterID* dst, RegisterID* index);
 
         RegisterID* emitIsObject(RegisterID* dst, RegisterID* src);
index abed72c..02e447a 100644 (file)
@@ -2183,19 +2183,23 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
 
     RefPtr<RegisterID> base = generator.newTemporary();
     RefPtr<RegisterID> length;
-    RefPtr<RegisterID> structureEnumerator;
+    RefPtr<RegisterID> enumerator;
     generator.emitNode(base.get(), m_expr);
     RefPtr<RegisterID> local = this->tryGetBoundLocal(generator);
+    RefPtr<RegisterID> enumeratorIndex;
 
     int profilerStartOffset = m_statement->startOffset();
     int profilerEndOffset = m_statement->endOffset() + (m_statement->isBlock() ? 1 : 0);
+
+    enumerator = generator.emitGetPropertyEnumerator(generator.newTemporary(), base.get());
+
     // Indexed property loop.
     {
         LabelScopePtr scope = generator.newLabelScope(LabelScope::Loop);
         RefPtr<Label> loopStart = generator.newLabel();
         RefPtr<Label> loopEnd = generator.newLabel();
 
-        length = generator.emitGetEnumerableLength(generator.newTemporary(), base.get());
+        length = generator.emitGetEnumerableLength(generator.newTemporary(), enumerator.get());
         RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0));
         RefPtr<RegisterID> propertyName = generator.newTemporary();
 
@@ -2233,32 +2237,31 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
         RefPtr<Label> loopStart = generator.newLabel();
         RefPtr<Label> loopEnd = generator.newLabel();
 
-        structureEnumerator = generator.emitGetStructurePropertyEnumerator(generator.newTemporary(), base.get(), length.get());
-        RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0));
+        enumeratorIndex = generator.emitLoad(generator.newTemporary(), jsNumber(0));
         RefPtr<RegisterID> propertyName = generator.newTemporary();
-        generator.emitNextEnumeratorPropertyName(propertyName.get(), structureEnumerator.get(), i.get());
+        generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
 
         generator.emitLabel(loopStart.get());
         generator.emitLoopHint();
 
         RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get());
         generator.emitJumpIfTrue(result.get(), loopEnd.get());
-        generator.emitHasStructureProperty(result.get(), base.get(), propertyName.get(), structureEnumerator.get());
+        generator.emitHasStructureProperty(result.get(), base.get(), propertyName.get(), enumerator.get());
         generator.emitJumpIfFalse(result.get(), scope->continueTarget());
 
         this->emitLoopHeader(generator, propertyName.get());
 
         generator.emitProfileControlFlow(profilerStartOffset);
 
-        generator.pushStructureForInScope(local.get(), i.get(), propertyName.get(), structureEnumerator.get());
+        generator.pushStructureForInScope(local.get(), enumeratorIndex.get(), propertyName.get(), enumerator.get());
         generator.emitNode(dst, m_statement);
         generator.popStructureForInScope(local.get());
 
         generator.emitProfileControlFlow(profilerEndOffset);
 
         generator.emitLabel(scope->continueTarget());
-        generator.emitInc(i.get());
-        generator.emitNextEnumeratorPropertyName(propertyName.get(), structureEnumerator.get(), i.get());
+        generator.emitInc(enumeratorIndex.get());
+        generator.emitEnumeratorStructurePropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
         generator.emitJump(loopStart.get());
         
         generator.emitLabel(scope->breakTarget());
@@ -2272,17 +2275,19 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
         RefPtr<Label> loopStart = generator.newLabel();
         RefPtr<Label> loopEnd = generator.newLabel();
 
-        RefPtr<RegisterID> genericEnumerator = generator.emitGetGenericPropertyEnumerator(generator.newTemporary(), base.get(), length.get(), structureEnumerator.get());
-        RefPtr<RegisterID> i = generator.emitLoad(generator.newTemporary(), jsNumber(0));
         RefPtr<RegisterID> propertyName = generator.newTemporary();
 
-        generator.emitNextEnumeratorPropertyName(propertyName.get(), genericEnumerator.get(), i.get());
-        RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get());
-        generator.emitJumpIfTrue(result.get(), loopEnd.get());
+        generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
 
         generator.emitLabel(loopStart.get());
         generator.emitLoopHint();
 
+        RefPtr<RegisterID> result = generator.emitUnaryOp(op_eq_null, generator.newTemporary(), propertyName.get());
+        generator.emitJumpIfTrue(result.get(), loopEnd.get());
+
+        generator.emitHasGenericProperty(result.get(), base.get(), propertyName.get());
+        generator.emitJumpIfFalse(result.get(), scope->continueTarget());
+
         this->emitLoopHeader(generator, propertyName.get());
 
         generator.emitProfileControlFlow(profilerStartOffset);
@@ -2290,15 +2295,10 @@ void ForInNode::emitMultiLoopBytecode(BytecodeGenerator& generator, RegisterID*
         generator.emitNode(dst, m_statement);
 
         generator.emitLabel(scope->continueTarget());
-        generator.emitInc(i.get());
-        generator.emitNextEnumeratorPropertyName(propertyName.get(), genericEnumerator.get(), i.get());
-        generator.emitUnaryOp(op_eq_null, result.get(), propertyName.get());
-        generator.emitJumpIfTrue(result.get(), loopEnd.get());
+        generator.emitInc(enumeratorIndex.get());
+        generator.emitEnumeratorGenericPropertyName(propertyName.get(), enumerator.get(), enumeratorIndex.get());
+        generator.emitJump(loopStart.get());
 
-        generator.emitHasGenericProperty(result.get(), base.get(), propertyName.get());
-        generator.emitJumpIfTrue(result.get(), loopStart.get());
-        generator.emitJump(scope->continueTarget());
-        
         generator.emitLabel(scope->breakTarget());
         generator.emitJump(end.get());
         generator.emitLabel(loopEnd.get());
index e3542d1..3769378 100644 (file)
@@ -1966,15 +1966,15 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         forNode(node).makeHeapTop();
         break;
     }
-    case GetStructurePropertyEnumerator: {
+    case GetPropertyEnumerator: {
         forNode(node).setType(SpecCell);
         break;
     }
-    case GetGenericPropertyEnumerator: {
-        forNode(node).setType(SpecCell);
+    case GetEnumeratorStructurePname: {
+        forNode(node).setType(SpecString | SpecOther);
         break;
     }
-    case GetEnumeratorPname: {
+    case GetEnumeratorGenericPname: {
         forNode(node).setType(SpecString | SpecOther);
         break;
     }
index 4387cf9..151f162 100644 (file)
@@ -3770,28 +3770,26 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_get_direct_pname);
         }
 
-        case op_get_structure_property_enumerator: {
-            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetStructurePropertyEnumerator, 
-                get(VirtualRegister(currentInstruction[2].u.operand)),
-                get(VirtualRegister(currentInstruction[3].u.operand))));
-            NEXT_OPCODE(op_get_structure_property_enumerator);
+        case op_get_property_enumerator: {
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetPropertyEnumerator, 
+                get(VirtualRegister(currentInstruction[2].u.operand))));
+            NEXT_OPCODE(op_get_property_enumerator);
         }
 
-        case op_get_generic_property_enumerator: {
-            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetGenericPropertyEnumerator, 
+        case op_enumerator_structure_pname: {
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumeratorStructurePname,
                 get(VirtualRegister(currentInstruction[2].u.operand)),
-                get(VirtualRegister(currentInstruction[3].u.operand)),
-                get(VirtualRegister(currentInstruction[4].u.operand))));
-            NEXT_OPCODE(op_get_generic_property_enumerator);
+                get(VirtualRegister(currentInstruction[3].u.operand))));
+            NEXT_OPCODE(op_enumerator_structure_pname);
         }
 
-        case op_next_enumerator_pname: {
-            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumeratorPname, 
+        case op_enumerator_generic_pname: {
+            set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetEnumeratorGenericPname,
                 get(VirtualRegister(currentInstruction[2].u.operand)),
                 get(VirtualRegister(currentInstruction[3].u.operand))));
-            NEXT_OPCODE(op_next_enumerator_pname);
+            NEXT_OPCODE(op_enumerator_generic_pname);
         }
-
+            
         case op_to_index_string: {
             set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ToIndexString, 
                 get(VirtualRegister(currentInstruction[2].u.operand))));
index a476572..f54b223 100644 (file)
@@ -202,9 +202,9 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_has_structure_property:
     case op_has_indexed_property:
     case op_get_direct_pname:
-    case op_get_structure_property_enumerator:
-    case op_get_generic_property_enumerator:
-    case op_next_enumerator_pname:
+    case op_get_property_enumerator:
+    case op_enumerator_structure_pname:
+    case op_enumerator_generic_pname:
     case op_to_index_string:
     case op_new_func:
     case op_new_func_exp:
index 625e221..a695607 100644 (file)
@@ -162,8 +162,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     case HasGenericProperty:
     case HasStructureProperty:
     case GetEnumerableLength:
-    case GetStructurePropertyEnumerator:
-    case GetGenericPropertyEnumerator: {
+    case GetPropertyEnumerator: {
         read(Heap);
         write(SideState);
         return;
@@ -178,7 +177,8 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
     }
 
     case ToIndexString:
-    case GetEnumeratorPname: {
+    case GetEnumeratorStructurePname:
+    case GetEnumeratorGenericPname: {
         def(PureValue(node));
         return;
     }
index 8f70a18..375ac75 100644 (file)
@@ -231,9 +231,9 @@ bool doesGC(Graph& graph, Node* node)
     case NewFunctionExpression:
     case NewTypedArray:
     case ThrowReferenceError:
-    case GetStructurePropertyEnumerator:
-    case GetGenericPropertyEnumerator:
-    case GetEnumeratorPname:
+    case GetPropertyEnumerator:
+    case GetEnumeratorStructurePname:
+    case GetEnumeratorGenericPname:
     case ToIndexString:
     case MaterializeNewObject:
         return true;
index b36fd91..191925a 100644 (file)
@@ -1091,7 +1091,7 @@ private:
             break;
         }
         case HasGenericProperty: {
-            fixEdge<StringUse>(node->child2());
+            fixEdge<CellUse>(node->child2());
             break;
         }
         case HasStructureProperty: {
@@ -1123,18 +1123,16 @@ private:
             fixEdge<KnownCellUse>(enumerator);
             break;
         }
-        case GetStructurePropertyEnumerator: {
+        case GetPropertyEnumerator: {
             fixEdge<CellUse>(node->child1());
-            fixEdge<KnownInt32Use>(node->child2());
             break;
         }
-        case GetGenericPropertyEnumerator: {
-            fixEdge<CellUse>(node->child1());
+        case GetEnumeratorStructurePname: {
+            fixEdge<KnownCellUse>(node->child1());
             fixEdge<KnownInt32Use>(node->child2());
-            fixEdge<KnownCellUse>(node->child3());
             break;
         }
-        case GetEnumeratorPname: {
+        case GetEnumeratorGenericPname: {
             fixEdge<KnownCellUse>(node->child1());
             fixEdge<KnownInt32Use>(node->child2());
             break;
index 339ce62..7b09dd7 100644 (file)
@@ -322,9 +322,9 @@ namespace JSC { namespace DFG {
     macro(HasStructureProperty, NodeResultBoolean) \
     macro(HasGenericProperty, NodeResultBoolean) \
     macro(GetDirectPname, NodeMustGenerate | NodeHasVarArgs | NodeResultJS) \
-    macro(GetStructurePropertyEnumerator, NodeMustGenerate | NodeResultJS) \
-    macro(GetGenericPropertyEnumerator, NodeMustGenerate | NodeResultJS) \
-    macro(GetEnumeratorPname, NodeMustGenerate | NodeResultJS) \
+    macro(GetPropertyEnumerator, NodeMustGenerate | NodeResultJS) \
+    macro(GetEnumeratorStructurePname, NodeMustGenerate | NodeResultJS) \
+    macro(GetEnumeratorGenericPname, NodeMustGenerate | NodeResultJS) \
     macro(ToIndexString, NodeResultJS)
 
 // This enum generates a monotonically increasing id for all Node types,
index de7fbd8..5a6271f 100644 (file)
@@ -583,12 +583,15 @@ private:
             changed |= setPrediction(SpecBoolean);
             break;
         }
-        case GetStructurePropertyEnumerator:
-        case GetGenericPropertyEnumerator: {
+        case GetPropertyEnumerator: {
             changed |= setPrediction(SpecCell);
             break;
         }
-        case GetEnumeratorPname: {
+        case GetEnumeratorStructurePname: {
+            changed |= setPrediction(SpecCell | SpecOther);
+            break;
+        }
+        case GetEnumeratorGenericPname: {
             changed |= setPrediction(SpecCell | SpecOther);
             break;
         }
index f5dbfcb..b1e1e9e 100644 (file)
@@ -272,9 +272,9 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case HasStructureProperty:
     case HasIndexedProperty:
     case GetDirectPname:
-    case GetStructurePropertyEnumerator:
-    case GetGenericPropertyEnumerator:
-    case GetEnumeratorPname:
+    case GetPropertyEnumerator:
+    case GetEnumeratorStructurePname:
+    case GetEnumeratorGenericPname:
     case ToIndexString:
     case PhantomNewObject:
     case PutHint:
index 44e8b26..b624de4 100644 (file)
@@ -4715,12 +4715,11 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case GetEnumerableLength: {
-        SpeculateCellOperand base(this, node->child1());
+        SpeculateCellOperand enumerator(this, node->child1());
         GPRFlushedCallResult result(this);
         GPRReg resultGPR = result.gpr();
 
-        flushRegisters();
-        callOperation(operationGetEnumerableLength, resultGPR, base.gpr());
+        m_jit.load32(MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR);
         int32Result(resultGPR, node);
         break;
     }
@@ -4912,30 +4911,18 @@ void SpeculativeJIT::compile(Node* node)
         jsValueResult(resultTagGPR, resultPayloadGPR, node);
         break;
     }
-    case GetStructurePropertyEnumerator: {
-        SpeculateCellOperand base(this, node->child1());
-        SpeculateInt32Operand length(this, node->child2());
-        GPRFlushedCallResult result(this);
-        GPRReg resultGPR = result.gpr();
-
-        flushRegisters();
-        callOperation(operationGetStructurePropertyEnumerator, resultGPR, base.gpr(), length.gpr());
-        cellResult(resultGPR, node);
-        break;
-    }
-    case GetGenericPropertyEnumerator: {
+    case GetPropertyEnumerator: {
         SpeculateCellOperand base(this, node->child1());
-        SpeculateInt32Operand length(this, node->child2());
-        SpeculateCellOperand enumerator(this, node->child3());
         GPRFlushedCallResult result(this);
         GPRReg resultGPR = result.gpr();
 
         flushRegisters();
-        callOperation(operationGetGenericPropertyEnumerator, resultGPR, base.gpr(), length.gpr(), enumerator.gpr());
+        callOperation(operationGetPropertyEnumerator, resultGPR, base.gpr());
         cellResult(resultGPR, node);
         break;
     }
-    case GetEnumeratorPname: {
+    case GetEnumeratorStructurePname:
+    case GetEnumeratorGenericPname: {
         SpeculateCellOperand enumerator(this, node->child1());
         SpeculateInt32Operand index(this, node->child2());
         GPRTemporary scratch(this);
@@ -4948,8 +4935,10 @@ void SpeculativeJIT::compile(Node* node)
         GPRReg resultTagGPR = resultTag.gpr();
         GPRReg resultPayloadGPR = resultPayload.gpr();
 
-        MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, 
-            indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+        MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR,
+            MacroAssembler::Address(enumeratorGPR, (op == GetEnumeratorStructurePname)
+                ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset()
+                : JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
 
         m_jit.move(MacroAssembler::TrustedImm32(JSValue::NullTag), resultTagGPR);
         m_jit.move(MacroAssembler::TrustedImm32(0), resultPayloadGPR);
index 17b7eed..96e05c0 100644 (file)
@@ -4772,12 +4772,11 @@ void SpeculativeJIT::compile(Node* node)
     }
 
     case GetEnumerableLength: {
-        SpeculateCellOperand base(this, node->child1());
+        SpeculateCellOperand enumerator(this, node->child1());
         GPRFlushedCallResult result(this);
         GPRReg resultGPR = result.gpr();
 
-        flushRegisters();
-        callOperation(operationGetEnumerableLength, resultGPR, base.gpr());
+        m_jit.load32(MacroAssembler::Address(enumerator.gpr(), JSPropertyNameEnumerator::indexedLengthOffset()), resultGPR);
         int32Result(resultGPR, node);
         break;
     }
@@ -4948,30 +4947,18 @@ void SpeculativeJIT::compile(Node* node)
         jsValueResult(resultGPR, node);
         break;
     }
-    case GetStructurePropertyEnumerator: {
-        SpeculateCellOperand base(this, node->child1());
-        SpeculateInt32Operand length(this, node->child2());
-        GPRFlushedCallResult result(this);
-        GPRReg resultGPR = result.gpr();
-
-        flushRegisters();
-        callOperation(operationGetStructurePropertyEnumerator, resultGPR, base.gpr(), length.gpr());
-        cellResult(resultGPR, node);
-        break;
-    }
-    case GetGenericPropertyEnumerator: {
+    case GetPropertyEnumerator: {
         SpeculateCellOperand base(this, node->child1());
-        SpeculateInt32Operand length(this, node->child2());
-        SpeculateCellOperand enumerator(this, node->child3());
         GPRFlushedCallResult result(this);
         GPRReg resultGPR = result.gpr();
 
         flushRegisters();
-        callOperation(operationGetGenericPropertyEnumerator, resultGPR, base.gpr(), length.gpr(), enumerator.gpr());
+        callOperation(operationGetPropertyEnumerator, resultGPR, base.gpr());
         cellResult(resultGPR, node);
         break;
     }
-    case GetEnumeratorPname: {
+    case GetEnumeratorStructurePname:
+    case GetEnumeratorGenericPname: {
         SpeculateCellOperand enumerator(this, node->child1());
         SpeculateStrictInt32Operand index(this, node->child2());
         GPRTemporary scratch1(this);
@@ -4982,8 +4969,10 @@ void SpeculativeJIT::compile(Node* node)
         GPRReg scratch1GPR = scratch1.gpr();
         GPRReg resultGPR = result.gpr();
 
-        MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, 
-            indexGPR, MacroAssembler::Address(enumeratorGPR, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+        MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, indexGPR,
+            MacroAssembler::Address(enumeratorGPR, (op == GetEnumeratorStructurePname)
+                ? JSPropertyNameEnumerator::endStructurePropertyIndexOffset()
+                : JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
 
         m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsNull())), resultGPR);
 
index 658cf29..19c1ff0 100644 (file)
@@ -61,9 +61,11 @@ namespace JSC { namespace FTL {
     macro(JSFunction_scope, JSFunction::offsetOfScopeChain()) \
     macro(JSObject_butterfly, JSObject::butterflyOffset()) \
     macro(JSPropertyNameEnumerator_cachedInlineCapacity, JSPropertyNameEnumerator::cachedInlineCapacityOffset()) \
-    macro(JSPropertyNameEnumerator_cachedPropertyNamesLength, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()) \
     macro(JSPropertyNameEnumerator_cachedPropertyNamesVector, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()) \
     macro(JSPropertyNameEnumerator_cachedStructureID, JSPropertyNameEnumerator::cachedStructureIDOffset()) \
+    macro(JSPropertyNameEnumerator_endGenericPropertyIndex, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()) \
+    macro(JSPropertyNameEnumerator_endStructurePropertyIndex, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()) \
+    macro(JSPropertyNameEnumerator_indexLength, JSPropertyNameEnumerator::indexedLengthOffset()) \
     macro(JSScope_next, JSScope::offsetOfNext()) \
     macro(JSString_flags, JSString::offsetOfFlags()) \
     macro(JSString_length, JSString::offsetOfLength()) \
index c2b1c16..e0a21db 100644 (file)
@@ -171,9 +171,9 @@ inline CapabilityLevel canCompile(Node* node)
     case HasStructureProperty:
     case GetDirectPname:
     case GetEnumerableLength:
-    case GetStructurePropertyEnumerator:
-    case GetGenericPropertyEnumerator:
-    case GetEnumeratorPname:
+    case GetPropertyEnumerator:
+    case GetEnumeratorStructurePname:
+    case GetEnumeratorGenericPname:
     case ToIndexString:
     case BottomValue:
     case PhantomNewObject:
index 95b1e6f..252c31d 100644 (file)
@@ -803,14 +803,14 @@ private:
         case GetEnumerableLength:
             compileGetEnumerableLength();
             break;
-        case GetStructurePropertyEnumerator:
-            compileGetStructurePropertyEnumerator();
+        case GetPropertyEnumerator:
+            compileGetPropertyEnumerator();
             break;
-        case GetGenericPropertyEnumerator:
-            compileGetGenericPropertyEnumerator();
+        case GetEnumeratorStructurePname:
+            compileGetEnumeratorStructurePname();
             break;
-        case GetEnumeratorPname:
-            compileGetEnumeratorPname();
+        case GetEnumeratorGenericPname:
+            compileGetEnumeratorGenericPname();
             break;
         case ToIndexString:
             compileToIndexString();
@@ -4526,41 +4526,59 @@ private:
 
     void compileGetEnumerableLength()
     {
-        LValue base = lowCell(m_node->child1());
-        setInt32(vmCall(m_out.operation(operationGetEnumerableLength), m_callFrame, base));
+        LValue enumerator = lowCell(m_node->child1());
+        setInt32(m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_indexLength));
     }
 
-    void compileGetStructurePropertyEnumerator()
+    void compileGetPropertyEnumerator()
     {
         LValue base = lowCell(m_node->child1());
-        LValue length = lowInt32(m_node->child2());
-        setJSValue(vmCall(m_out.operation(operationGetStructurePropertyEnumerator), m_callFrame, base, length));
+        setJSValue(vmCall(m_out.operation(operationGetPropertyEnumerator), m_callFrame, base));
     }
 
-    void compileGetGenericPropertyEnumerator()
+    void compileGetEnumeratorStructurePname()
     {
-        LValue base = lowCell(m_node->child1());
-        LValue length = lowInt32(m_node->child2());
-        LValue enumerator = lowCell(m_node->child3());
-        setJSValue(vmCall(m_out.operation(operationGetGenericPropertyEnumerator), m_callFrame, base, length, enumerator));
+        LValue enumerator = lowCell(m_node->child1());
+        LValue index = lowInt32(m_node->child2());
+
+        LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname in bounds"));
+        LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname out of bounds"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorStructurePname continuation"));
+
+        m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endStructurePropertyIndex)),
+            usually(inBounds), rarely(outOfBounds));
+
+        LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
+        LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
+        ValueFromBlock inBoundsResult = m_out.anchor(
+            m_out.load64(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector, 
+                storage, m_out.signExt(index, m_out.int64), ScaleEight)));
+        m_out.jump(continuation);
+
+        m_out.appendTo(outOfBounds, continuation);
+        ValueFromBlock outOfBoundsResult = m_out.anchor(m_out.constInt64(ValueNull));
+        m_out.jump(continuation);
+        
+        m_out.appendTo(continuation, lastNext);
+        setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult));
     }
 
-    void compileGetEnumeratorPname()
+    void compileGetEnumeratorGenericPname()
     {
         LValue enumerator = lowCell(m_node->child1());
         LValue index = lowInt32(m_node->child2());
 
-        LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname in bounds"));
-        LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname out of bounds"));
-        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorPname continuation"));
+        LBasicBlock inBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname in bounds"));
+        LBasicBlock outOfBounds = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname out of bounds"));
+        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("GetEnumeratorGenericPname continuation"));
 
-        m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesLength)),
+        m_out.branch(m_out.below(index, m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_endGenericPropertyIndex)),
             usually(inBounds), rarely(outOfBounds));
 
         LBasicBlock lastNext = m_out.appendTo(inBounds, outOfBounds);
         LValue storage = m_out.loadPtr(enumerator, m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector);
         ValueFromBlock inBoundsResult = m_out.anchor(
-            m_out.load64(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector, 
+            m_out.load64(m_out.baseIndex(m_heaps.JSPropertyNameEnumerator_cachedPropertyNamesVector,
                 storage, m_out.signExt(index, m_out.int64), ScaleEight)));
         m_out.jump(continuation);
 
@@ -4571,7 +4589,7 @@ private:
         m_out.appendTo(continuation, lastNext);
         setJSValue(m_out.phi(m_out.int64, inBoundsResult, outOfBoundsResult));
     }
-
+    
     void compileToIndexString()
     {
         LValue index = lowInt32(m_node->child1());
index 36dd4f8..b6469a1 100644 (file)
@@ -306,9 +306,9 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_has_structure_property)
         DEFINE_OP(op_has_indexed_property)
         DEFINE_OP(op_get_direct_pname)
-        DEFINE_OP(op_get_structure_property_enumerator)
-        DEFINE_OP(op_get_generic_property_enumerator)
-        DEFINE_OP(op_next_enumerator_pname)
+        DEFINE_OP(op_get_property_enumerator)
+        DEFINE_OP(op_enumerator_structure_pname)
+        DEFINE_OP(op_enumerator_generic_pname)
         DEFINE_OP(op_to_index_string)
         default:
             RELEASE_ASSERT_NOT_REACHED();
index 0fd77a6..193a0ff 100644 (file)
@@ -557,9 +557,9 @@ namespace JSC {
         void emit_op_has_structure_property(Instruction*);
         void emit_op_has_indexed_property(Instruction*);
         void emit_op_get_direct_pname(Instruction*);
-        void emit_op_get_structure_property_enumerator(Instruction*);
-        void emit_op_get_generic_property_enumerator(Instruction*);
-        void emit_op_next_enumerator_pname(Instruction*);
+        void emit_op_get_property_enumerator(Instruction*);
+        void emit_op_enumerator_structure_pname(Instruction*);
+        void emit_op_enumerator_generic_pname(Instruction*);
         void emit_op_to_index_string(Instruction*);
 
         void emitSlow_op_add(Instruction*, Vector<SlowCaseEntry>::iterator&);
index d02d436..b09ee2b 100644 (file)
@@ -1284,7 +1284,7 @@ void JIT::emitSlow_op_get_direct_pname(Instruction* currentInstruction, Vector<S
     slowPathCall.call();
 }
 
-void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
+void JIT::emit_op_enumerator_structure_pname(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
     int enumerator = currentInstruction[2].u.operand;
@@ -1292,7 +1292,7 @@ void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
 
     emitGetVirtualRegister(index, regT0);
     emitGetVirtualRegister(enumerator, regT1);
-    Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+    Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()));
 
     move(TrustedImm64(JSValue::encode(jsNull())), regT0);
 
@@ -1307,6 +1307,29 @@ void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
     emitPutVirtualRegister(dst);
 }
 
+void JIT::emit_op_enumerator_generic_pname(Instruction* currentInstruction)
+{
+    int dst = currentInstruction[1].u.operand;
+    int enumerator = currentInstruction[2].u.operand;
+    int index = currentInstruction[3].u.operand;
+
+    emitGetVirtualRegister(index, regT0);
+    emitGetVirtualRegister(enumerator, regT1);
+    Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
+
+    move(TrustedImm64(JSValue::encode(jsNull())), regT0);
+
+    Jump done = jump();
+    inBounds.link(this);
+
+    loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
+    signExtend32ToPtr(regT0, regT0);
+    load64(BaseIndex(regT1, regT0, TimesEight), regT0);
+    
+    done.link(this);
+    emitPutVirtualRegister(dst);
+}
+
 void JIT::emit_op_profile_type(Instruction* currentInstruction)
 {
     TypeLocation* cachedTypeLocation = currentInstruction[2].u.location;
@@ -1392,15 +1415,9 @@ void JIT::emit_op_has_generic_property(Instruction* currentInstruction)
     slowPathCall.call();
 }
 
-void JIT::emit_op_get_structure_property_enumerator(Instruction* currentInstruction)
-{
-    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_structure_property_enumerator);
-    slowPathCall.call();
-}
-
-void JIT::emit_op_get_generic_property_enumerator(Instruction* currentInstruction)
+void JIT::emit_op_get_property_enumerator(Instruction* currentInstruction)
 {
-    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_generic_property_enumerator);
+    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_property_enumerator);
     slowPathCall.call();
 }
 
index b57f8b1..17abda9 100644 (file)
@@ -1259,7 +1259,7 @@ void JIT::emitSlow_op_get_direct_pname(Instruction* currentInstruction, Vector<S
     slowPathCall.call();
 }
 
-void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
+void JIT::emit_op_enumerator_structure_pname(Instruction* currentInstruction)
 {
     int dst = currentInstruction[1].u.operand;
     int enumerator = currentInstruction[2].u.operand;
@@ -1267,7 +1267,7 @@ void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
 
     emitLoadPayload(index, regT0);
     emitLoadPayload(enumerator, regT1);
-    Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesLengthOffset()));
+    Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endStructurePropertyIndexOffset()));
 
     move(TrustedImm32(JSValue::NullTag), regT2);
     move(TrustedImm32(0), regT0);
@@ -1283,6 +1283,30 @@ void JIT::emit_op_next_enumerator_pname(Instruction* currentInstruction)
     emitStore(dst, regT2, regT0);
 }
 
+void JIT::emit_op_enumerator_generic_pname(Instruction* currentInstruction)
+{
+    int dst = currentInstruction[1].u.operand;
+    int enumerator = currentInstruction[2].u.operand;
+    int index = currentInstruction[3].u.operand;
+
+    emitLoadPayload(index, regT0);
+    emitLoadPayload(enumerator, regT1);
+    Jump inBounds = branch32(Below, regT0, Address(regT1, JSPropertyNameEnumerator::endGenericPropertyIndexOffset()));
+
+    move(TrustedImm32(JSValue::NullTag), regT2);
+    move(TrustedImm32(0), regT0);
+
+    Jump done = jump();
+    inBounds.link(this);
+
+    loadPtr(Address(regT1, JSPropertyNameEnumerator::cachedPropertyNamesVectorOffset()), regT1);
+    loadPtr(BaseIndex(regT1, regT0, timesPtr()), regT0);
+    move(TrustedImm32(JSValue::CellTag), regT2);
+    
+    done.link(this);
+    emitStore(dst, regT2, regT0);
+}
+
 void JIT::emit_op_profile_type(Instruction* currentInstruction)
 {
     TypeLocation* cachedTypeLocation = currentInstruction[2].u.location;
index e481aa7..c77c6ae 100644 (file)
@@ -1847,14 +1847,6 @@ void JIT_OPERATION operationExceptionFuzz()
 #endif // COMPILER(CLANG)
 }
 
-int32_t JIT_OPERATION operationGetEnumerableLength(ExecState* exec, JSCell* baseCell)
-{
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(&vm, exec);
-    JSObject* base = baseCell->toObject(exec, exec->lexicalGlobalObject());
-    return base->methodTable(vm)->getEnumerableLength(exec, base);
-}
-
 EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState* exec, EncodedJSValue encodedBaseValue, JSCell* propertyName)
 {
     VM& vm = exec->vm();
@@ -1875,26 +1867,14 @@ EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState* exec, JSCell
     return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript)));
 }
     
-JSCell* JIT_OPERATION operationGetStructurePropertyEnumerator(ExecState* exec, JSCell* cell, int32_t length)
+JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState* exec, JSCell* cell)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
-        
-    JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject());
-    ASSERT(length >= 0);
 
-    return structurePropertyNameEnumerator(exec, base, static_cast<uint32_t>(length));
-}
-
-JSCell* JIT_OPERATION operationGetGenericPropertyEnumerator(ExecState* exec, JSCell* baseCell, int32_t length, JSCell* structureEnumeratorCell)
-{
-    VM& vm = exec->vm();
-    NativeCallFrameTracer tracer(&vm, exec);
-    
-    JSObject* base = baseCell->toObject(exec, exec->lexicalGlobalObject());
-    ASSERT(length >= 0);
+    JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject());
 
-    return genericPropertyNameEnumerator(exec, base, length, jsCast<JSPropertyNameEnumerator*>(structureEnumeratorCell));
+    return propertyNameEnumerator(exec, base);
 }
 
 EncodedJSValue JIT_OPERATION operationNextEnumeratorPname(ExecState* exec, JSCell* enumeratorCell, int32_t index)
index ca23bdd..e289979 100644 (file)
@@ -327,11 +327,9 @@ void JIT_OPERATION operationInitGlobalConst(ExecState*, Instruction*);
 
 void JIT_OPERATION operationExceptionFuzz();
 
-int32_t JIT_OPERATION operationGetEnumerableLength(ExecState*, JSCell*);
 EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState*, EncodedJSValue, JSCell*);
 EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState*, JSCell*, int32_t);
-JSCell* JIT_OPERATION operationGetStructurePropertyEnumerator(ExecState*, JSCell*, int32_t);
-JSCell* JIT_OPERATION operationGetGenericPropertyEnumerator(ExecState*, JSCell*, int32_t, JSCell*);
+JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState*, JSCell*);
 EncodedJSValue JIT_OPERATION operationNextEnumeratorPname(ExecState*, JSCell*, int32_t);
 JSCell* JIT_OPERATION operationToIndexString(ExecState*, int32_t);
 
index d71a3ef..4a74ba0 100644 (file)
@@ -1334,19 +1334,19 @@ _llint_op_get_direct_pname:
     callSlowPath(_slow_path_get_direct_pname)
     dispatch(7)
 
-_llint_op_get_structure_property_enumerator:
+_llint_op_get_property_enumerator:
     traceExecution()
-    callSlowPath(_slow_path_get_structure_property_enumerator)
-    dispatch(4)
+    callSlowPath(_slow_path_get_property_enumerator)
+    dispatch(3)
 
-_llint_op_get_generic_property_enumerator:
+_llint_op_enumerator_structure_pname:
     traceExecution()
-    callSlowPath(_slow_path_get_generic_property_enumerator)
-    dispatch(5)
+    callSlowPath(_slow_path_next_structure_enumerator_pname)
+    dispatch(4)
 
-_llint_op_next_enumerator_pname:
+_llint_op_enumerator_generic_pname:
     traceExecution()
-    callSlowPath(_slow_path_next_enumerator_pname)
+    callSlowPath(_slow_path_next_generic_enumerator_pname)
     dispatch(4)
 
 _llint_op_to_index_string:
index 09a08d7..8abd816 100644 (file)
@@ -520,12 +520,13 @@ SLOW_PATH_DECL(slow_path_enter)
 SLOW_PATH_DECL(slow_path_get_enumerable_length)
 {
     BEGIN();
-    JSValue baseValue = OP(2).jsValue();
-    if (baseValue.isUndefinedOrNull())
+    JSValue enumeratorValue = OP(2).jsValue();
+    if (enumeratorValue.isUndefinedOrNull())
         RETURN(jsNumber(0));
 
-    JSObject* base = baseValue.toObject(exec);
-    RETURN(jsNumber(base->methodTable(vm)->getEnumerableLength(exec, base)));
+    JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorValue.asCell());
+
+    RETURN(jsNumber(enumerator->indexedLength()));
 }
 
 SLOW_PATH_DECL(slow_path_has_indexed_property)
@@ -574,39 +575,39 @@ SLOW_PATH_DECL(slow_path_get_direct_pname)
     RETURN(baseValue.get(exec, property.toPropertyKey(exec)));
 }
 
-SLOW_PATH_DECL(slow_path_get_structure_property_enumerator)
+SLOW_PATH_DECL(slow_path_get_property_enumerator)
 {
     BEGIN();
     JSValue baseValue = OP(2).jsValue();
     if (baseValue.isUndefinedOrNull())
         RETURN(JSPropertyNameEnumerator::create(vm));
-        
+
     JSObject* base = baseValue.toObject(exec);
-    uint32_t length = OP(3).jsValue().asUInt32();
 
-    RETURN(structurePropertyNameEnumerator(exec, base, length));
+    RETURN(propertyNameEnumerator(exec, base));
 }
 
-SLOW_PATH_DECL(slow_path_get_generic_property_enumerator)
+SLOW_PATH_DECL(slow_path_next_structure_enumerator_pname)
 {
     BEGIN();
-    JSValue baseValue = OP(2).jsValue();
-    if (baseValue.isUndefinedOrNull())
-        RETURN(JSPropertyNameEnumerator::create(vm));
-    
-    JSObject* base = baseValue.toObject(exec);
-    uint32_t length = OP(3).jsValue().asUInt32();
-    JSPropertyNameEnumerator* structureEnumerator = jsCast<JSPropertyNameEnumerator*>(OP(4).jsValue().asCell());
+    JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell());
+    uint32_t index = OP(3).jsValue().asUInt32();
 
-    RETURN(genericPropertyNameEnumerator(exec, base, length, structureEnumerator));
+    JSString* propertyName = nullptr;
+    if (index < enumerator->endStructurePropertyIndex())
+        propertyName = enumerator->propertyNameAtIndex(index);
+    RETURN(propertyName ? propertyName : jsNull());
 }
 
-SLOW_PATH_DECL(slow_path_next_enumerator_pname)
+SLOW_PATH_DECL(slow_path_next_generic_enumerator_pname)
 {
     BEGIN();
     JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(OP(2).jsValue().asCell());
     uint32_t index = OP(3).jsValue().asUInt32();
-    JSString* propertyName = enumerator->propertyNameAtIndex(index);
+
+    JSString* propertyName = nullptr;
+    if (enumerator->endStructurePropertyIndex() <= index && index < enumerator->endGenericPropertyIndex())
+        propertyName = enumerator->propertyNameAtIndex(index);
     RETURN(propertyName ? propertyName : jsNull());
 }
 
index 940710d..94fadec 100644 (file)
@@ -226,9 +226,9 @@ SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property);
 SLOW_PATH_HIDDEN_DECL(slow_path_has_structure_property);
 SLOW_PATH_HIDDEN_DECL(slow_path_has_indexed_property);
 SLOW_PATH_HIDDEN_DECL(slow_path_get_direct_pname);
-SLOW_PATH_HIDDEN_DECL(slow_path_get_structure_property_enumerator);
-SLOW_PATH_HIDDEN_DECL(slow_path_get_generic_property_enumerator);
-SLOW_PATH_HIDDEN_DECL(slow_path_next_enumerator_pname);
+SLOW_PATH_HIDDEN_DECL(slow_path_get_property_enumerator);
+SLOW_PATH_HIDDEN_DECL(slow_path_next_structure_enumerator_pname);
+SLOW_PATH_HIDDEN_DECL(slow_path_next_generic_enumerator_pname);
 SLOW_PATH_HIDDEN_DECL(slow_path_to_index_string);
 SLOW_PATH_HIDDEN_DECL(slow_path_profile_type_clear_log);
 
index affa8d1..860382f 100644 (file)
@@ -37,18 +37,18 @@ JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm)
 {
     if (!vm.emptyPropertyNameEnumerator.get()) {
         PropertyNameArray propertyNames(&vm);
-        vm.emptyPropertyNameEnumerator = Strong<JSCell>(vm, create(vm, 0, propertyNames));
+        vm.emptyPropertyNameEnumerator = Strong<JSCell>(vm, create(vm, 0, 0, 0, propertyNames));
     }
     return jsCast<JSPropertyNameEnumerator*>(vm.emptyPropertyNameEnumerator.get());
 }
 
-JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm, Structure* structure, PropertyNameArray& propertyNames)
+JSPropertyNameEnumerator* JSPropertyNameEnumerator::create(VM& vm, Structure* structure, uint32_t indexedLength, uint32_t numberStructureProperties, PropertyNameArray& propertyNames)
 {
     StructureID structureID = structure ? structure->id() : 0;
     uint32_t inlineCapacity = structure ? structure->inlineCapacity() : 0;
     JSPropertyNameEnumerator* enumerator = new (NotNull, 
         allocateCell<JSPropertyNameEnumerator>(vm.heap)) JSPropertyNameEnumerator(vm, structureID, inlineCapacity, propertyNames.identifierSet());
-    enumerator->finishCreation(vm, propertyNames.data());
+    enumerator->finishCreation(vm, indexedLength, numberStructureProperties, propertyNames.data());
     return enumerator;
 }
 
@@ -60,12 +60,17 @@ JSPropertyNameEnumerator::JSPropertyNameEnumerator(VM& vm, StructureID structure
 {
 }
 
-void JSPropertyNameEnumerator::finishCreation(VM& vm, PassRefPtr<PropertyNameArrayData> idents)
+void JSPropertyNameEnumerator::finishCreation(VM& vm, uint32_t indexedLength, uint32_t endStructurePropertyIndex, PassRefPtr<PropertyNameArrayData> idents)
 {
     Base::finishCreation(vm);
 
     RefPtr<PropertyNameArrayData> identifiers = idents;
     PropertyNameArrayData::PropertyNameVector& vector = identifiers->propertyNameVector();
+
+    m_indexedLength = indexedLength;
+    m_endStructurePropertyIndex = endStructurePropertyIndex;
+    m_endGenericPropertyIndex = vector.size();
+
     m_propertyNames.resize(vector.size());
     for (unsigned i = 0; i < vector.size(); ++i) {
         const Identifier& identifier = vector[i];
index ee18abf..1460cea 100644 (file)
@@ -40,7 +40,7 @@ public:
     typedef JSCell Base;
 
     static JSPropertyNameEnumerator* create(VM&);
-    static JSPropertyNameEnumerator* create(VM&, Structure*, PropertyNameArray&);
+    static JSPropertyNameEnumerator* create(VM&, Structure*, uint32_t, uint32_t, PropertyNameArray&);
 
     static const bool needsDestruction = true;
     static const bool hasImmortalStructure = true;
@@ -75,13 +75,15 @@ public:
         return vm.heap.structureIDTable().get(m_cachedStructureID);
     }
     StructureID cachedStructureID() const { return m_cachedStructureID; }
+    uint32_t indexedLength() const { return m_indexedLength; }
+    uint32_t endStructurePropertyIndex() const { return m_endStructurePropertyIndex; }
+    uint32_t endGenericPropertyIndex() const { return m_endGenericPropertyIndex; }
     uint32_t cachedInlineCapacity() const { return m_cachedInlineCapacity; }
     static ptrdiff_t cachedStructureIDOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedStructureID); }
+    static ptrdiff_t indexedLengthOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_indexedLength); }
+    static ptrdiff_t endStructurePropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endStructurePropertyIndex); }
+    static ptrdiff_t endGenericPropertyIndexOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_endGenericPropertyIndex); }
     static ptrdiff_t cachedInlineCapacityOffset() { return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_cachedInlineCapacity); }
-    static ptrdiff_t cachedPropertyNamesLengthOffset()
-    {
-        return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames) + Vector<WriteBarrier<JSString>>::sizeMemoryOffset();
-    }
     static ptrdiff_t cachedPropertyNamesVectorOffset()
     {
         return OBJECT_OFFSETOF(JSPropertyNameEnumerator, m_propertyNames) + Vector<WriteBarrier<JSString>>::dataMemoryOffset();
@@ -93,65 +95,53 @@ private:
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
     JSPropertyNameEnumerator(VM&, StructureID, uint32_t, RefCountedIdentifierSet*);
-    void finishCreation(VM&, PassRefPtr<PropertyNameArrayData>);
+    void finishCreation(VM&, uint32_t, uint32_t, PassRefPtr<PropertyNameArrayData>);
 
     Vector<WriteBarrier<JSString>> m_propertyNames;
     RefPtr<RefCountedIdentifierSet> m_identifierSet;
     StructureID m_cachedStructureID;
     WriteBarrier<StructureChain> m_prototypeChain;
+    uint32_t m_indexedLength;
+    uint32_t m_endStructurePropertyIndex;
+    uint32_t m_endGenericPropertyIndex;
     uint32_t m_cachedInlineCapacity;
 };
 
-inline JSPropertyNameEnumerator* structurePropertyNameEnumerator(ExecState* exec, JSObject* base, uint32_t length)
+inline JSPropertyNameEnumerator* propertyNameEnumerator(ExecState* exec, JSObject* base)
 {
     VM& vm = exec->vm();
+
+    uint32_t indexedLength = base->methodTable(vm)->getEnumerableLength(exec, base);
+
+    JSPropertyNameEnumerator* enumerator = nullptr;
+
     Structure* structure = base->structure(vm);
-    if (JSPropertyNameEnumerator* enumerator = structure->cachedStructurePropertyNameEnumerator())
+    if (!indexedLength
+        && (enumerator = structure->cachedPropertyNameEnumerator())
+        && enumerator->cachedPrototypeChain() == structure->prototypeChain(exec))
         return enumerator;
 
-    if (!structure->canAccessPropertiesQuickly() || length != base->getArrayLength())
-        return JSPropertyNameEnumerator::create(vm);
+    uint32_t numberStructureProperties = 0;
 
     PropertyNameArray propertyNames(exec);
-    base->methodTable(vm)->getStructurePropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
 
-    JSPropertyNameEnumerator* enumerator = JSPropertyNameEnumerator::create(vm, structure, propertyNames);
-    if (structure->canCacheStructurePropertyNameEnumerator())
-        structure->setCachedStructurePropertyNameEnumerator(vm, enumerator);
-    return enumerator;
-}
+    if (structure->canAccessPropertiesQuickly() && indexedLength == base->getArrayLength()) {
+        base->methodTable(vm)->getStructurePropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
 
-inline JSPropertyNameEnumerator* genericPropertyNameEnumerator(ExecState* exec, JSObject* base, uint32_t length, JSPropertyNameEnumerator* structureEnumerator)
-{
-    VM& vm = exec->vm();
-    Structure* structure = base->structure(vm);
-    if (JSPropertyNameEnumerator* enumerator = structure->cachedGenericPropertyNameEnumerator()) {
-        if (!length && enumerator->cachedPrototypeChain() == structure->prototypeChain(exec))
-            return enumerator;
-    }
+        numberStructureProperties = propertyNames.size();
 
-    PropertyNameArray propertyNames(exec);
-    propertyNames.setPreviouslyEnumeratedLength(length);
-    propertyNames.setPreviouslyEnumeratedProperties(structureEnumerator);
-
-    // If we still have the same Structure that we started with, our Structure allows us to access its properties 
-    // quickly (i.e. the Structure property loop was able to do things), and we iterated the full length of the 
-    // object (i.e. there are no more own indexed properties that need to be enumerated), then the generic property 
-    // iteration can skip any properties it would get from the JSObject base class. This turns out to be important 
-    // for hot loops because most of our time is then dominated by trying to add the own Structure properties to 
-    // the new generic PropertyNameArray and failing because we've already visited them.
-    Structure* cachedStructure = structureEnumerator->cachedStructure(vm);
-    if (structure == cachedStructure && structure->canAccessPropertiesQuickly() && static_cast<uint32_t>(length) == base->getArrayLength())
         base->methodTable(vm)->getGenericPropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
-    else
+    else
         base->methodTable(vm)->getPropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
-    
+
+    ASSERT(propertyNames.size() < UINT32_MAX);
+
     normalizePrototypeChain(exec, structure);
 
-    JSPropertyNameEnumerator* enumerator = JSPropertyNameEnumerator::create(vm, base->structure(vm), propertyNames);
+    enumerator = JSPropertyNameEnumerator::create(vm, structure, indexedLength, numberStructureProperties, propertyNames);
     enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(exec));
-    if (!length && structure->canCacheGenericPropertyNameEnumerator())
-        structure->setCachedGenericPropertyNameEnumerator(vm, enumerator);
+    if (!indexedLength && structure->canCachePropertyNameEnumerator())
+        structure->setCachedPropertyNameEnumerator(vm, enumerator);
     return enumerator;
 }
 
index 00e8186..dce51b5 100644 (file)
@@ -1216,47 +1216,25 @@ bool ClassInfo::hasStaticSetterOrReadonlyProperties() const
     return false;
 }
 
-void Structure::setCachedStructurePropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+void Structure::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
 {
     ASSERT(!isDictionary());
     if (!hasRareData())
         allocateRareData(vm);
-    rareData()->setCachedStructurePropertyNameEnumerator(vm, enumerator);
+    rareData()->setCachedPropertyNameEnumerator(vm, enumerator);
 }
 
-JSPropertyNameEnumerator* Structure::cachedStructurePropertyNameEnumerator() const
+JSPropertyNameEnumerator* Structure::cachedPropertyNameEnumerator() const
 {
     if (!hasRareData())
         return nullptr;
-    return rareData()->cachedStructurePropertyNameEnumerator();
+    return rareData()->cachedPropertyNameEnumerator();
 }
 
-void Structure::setCachedGenericPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
-{
-    ASSERT(!isDictionary());
-    if (!hasRareData())
-        allocateRareData(vm);
-    rareData()->setCachedGenericPropertyNameEnumerator(vm, enumerator);
-}
-
-JSPropertyNameEnumerator* Structure::cachedGenericPropertyNameEnumerator() const
-{
-    if (!hasRareData())
-        return nullptr;
-    return rareData()->cachedGenericPropertyNameEnumerator();
-}
-
-bool Structure::canCacheStructurePropertyNameEnumerator() const
+bool Structure::canCachePropertyNameEnumerator() const
 {
     if (isDictionary())
         return false;
-    return true;
-}
-
-bool Structure::canCacheGenericPropertyNameEnumerator() const
-{
-    if (!canCacheStructurePropertyNameEnumerator())
-        return false;
 
     if (hasIndexedProperties(indexingType()))
         return false;
@@ -1274,10 +1252,10 @@ bool Structure::canCacheGenericPropertyNameEnumerator() const
             return false;
         structure++;
     }
-
+    
     return true;
 }
-
+    
 bool Structure::canAccessPropertiesQuickly() const
 {
     if (hasNonEnumerableProperties())
index 4d7e5c1..7b48d34 100644 (file)
@@ -315,12 +315,9 @@ public:
         return !JSC::isValidOffset(m_offset);
     }
 
-    void setCachedStructurePropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
-    void setCachedGenericPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
-    JSPropertyNameEnumerator* cachedStructurePropertyNameEnumerator() const;
-    JSPropertyNameEnumerator* cachedGenericPropertyNameEnumerator() const;
-    bool canCacheStructurePropertyNameEnumerator() const;
-    bool canCacheGenericPropertyNameEnumerator() const;
+    void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+    JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
+    bool canCachePropertyNameEnumerator() const;
     bool canAccessPropertiesQuickly() const;
 
     void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
index ed15302..20a5371 100644 (file)
@@ -66,28 +66,18 @@ void StructureRareData::visitChildren(JSCell* cell, SlotVisitor& visitor)
     JSCell::visitChildren(thisObject, visitor);
     visitor.append(&thisObject->m_previous);
     visitor.append(&thisObject->m_objectToStringValue);
-    visitor.append(&thisObject->m_cachedStructurePropertyNameEnumerator);
+    visitor.append(&thisObject->m_cachedPropertyNameEnumerator);
     visitor.append(&thisObject->m_cachedGenericPropertyNameEnumerator);
 }
 
-JSPropertyNameEnumerator* StructureRareData::cachedStructurePropertyNameEnumerator() const
+JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
 {
-    return m_cachedStructurePropertyNameEnumerator.get();
+    return m_cachedPropertyNameEnumerator.get();
 }
 
-void StructureRareData::setCachedStructurePropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
+void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
 {
-    m_cachedStructurePropertyNameEnumerator.set(vm, this, enumerator);
-}
-
-JSPropertyNameEnumerator* StructureRareData::cachedGenericPropertyNameEnumerator() const
-{
-    return m_cachedGenericPropertyNameEnumerator.get();
-}
-
-void StructureRareData::setCachedGenericPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
-{
-    m_cachedGenericPropertyNameEnumerator.set(vm, this, enumerator);
+    m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
 }
 
 } // namespace JSC
index dab3e5f..23f05f9 100644 (file)
@@ -55,10 +55,8 @@ public:
     JSString* objectToStringValue() const;
     void setObjectToStringValue(VM&, JSString* value);
 
-    JSPropertyNameEnumerator* cachedStructurePropertyNameEnumerator() const;
-    JSPropertyNameEnumerator* cachedGenericPropertyNameEnumerator() const;
-    void setCachedStructurePropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
-    void setCachedGenericPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
+    JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
+    void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
 
     DECLARE_EXPORT_INFO;
 
@@ -71,7 +69,7 @@ private:
 
     WriteBarrier<Structure> m_previous;
     WriteBarrier<JSString> m_objectToStringValue;
-    WriteBarrier<JSPropertyNameEnumerator> m_cachedStructurePropertyNameEnumerator;
+    WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator;
     WriteBarrier<JSPropertyNameEnumerator> m_cachedGenericPropertyNameEnumerator;
     
     typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap;
index 13d5049..5ad3566 100644 (file)
@@ -36,8 +36,7 @@
     };
     noInline(foo);
     for (var i = 0; i < 10000; ++i) {
-        // Note: it's undefined whether we visit o.a or not. Currently we do.
-        if (foo() !== "xza")
+        if (foo() !== "xz")
             throw new Error("bad result");
     }
 })();