Skip to content

Commit 98dd526

Browse files
committed
[JSC] Introduce JSArrayIterator
https://bugs.webkit.org/show_bug.cgi?id=204043 Reviewed by Yusuke Suzuki. JSTests: * stress/array-iterator-materialize-at-osr-exit.js: Added. (shouldBe): (test): * stress/array-iterator-materialize-one-path.js: Added. (shouldBe): (test): * stress/array-iterator-materialize.js: Added. (shouldBe): (test): * stress/array-iterator-sinking.js: Added. (shouldBe): (test): * stress/array-iterators-next-error-messages.js: (catch): * stress/array-iterators-next-with-call.js: * stress/for-of-iteration.js: Added. (shouldBe): (test1): (test2): (test3): * stress/typedarray-functions-with-neutered.js: (checkProtoFunc): Source/JavaScriptCore: This patch introduces JSArrayIterator that changes the iterator object from a JSFinalObject to an InternalFieldsObject. This makes accessing it much easier from C++ code and makes the iterator object smaller. It also means that the JS code for the next function is much simpler and can *almost* be inlined without shenanigans. As part of this patch the keys/values/entries functions have been converted to C++ with intrinsics since that's slightly more efficient in the LLInt/Baseline. Lastly, this patch also add a custom ISOSubspace for JSArrayIterator objects. * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: * builtins/ArrayIteratorPrototype.js: (next): (globalPrivate.arrayIteratorNextHelper): (globalPrivate.arrayIteratorValueNext): Deleted. (globalPrivate.arrayIteratorKeyNext): Deleted. (globalPrivate.arrayIteratorKeyValueNext): Deleted. * builtins/ArrayPrototype.js: (globalPrivate.ArrayIterator): Deleted. (values): Deleted. (keys): Deleted. (entries): Deleted. * builtins/TypedArrayPrototype.js: (values): Deleted. (keys): Deleted. (entries): Deleted. * bytecode/BytecodeIntrinsicRegistry.cpp: (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry): * bytecode/BytecodeIntrinsicRegistry.h: * bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::emitIsArrayIterator): * bytecompiler/NodesCodegen.cpp: (JSC::arrayIteratorInternalFieldIndex): (JSC::BytecodeIntrinsicNode::emit_intrinsic_getArrayIteratorInternalField): (JSC::BytecodeIntrinsicNode::emit_intrinsic_putArrayIteratorInternalField): (JSC::BytecodeIntrinsicNode::emit_intrinsic_isGenerator): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isAsyncGenerator): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isJSArray): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isPromise): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isProxyObject): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isRegExpObject): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isObject): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isDerivedArray): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isMap): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isSet): Deleted. (JSC::BytecodeIntrinsicNode::emit_intrinsic_isUndefinedOrNull): Deleted. * dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::handleIntrinsicCall): * dfg/DFGClobberize.h: (JSC::DFG::clobberize): * dfg/DFGClobbersExitState.cpp: (JSC::DFG::clobbersExitState): * dfg/DFGConstantFoldingPhase.cpp: (JSC::DFG::ConstantFoldingPhase::foldConstants): * dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.cpp: (JSC::DFG::Graph::dump): * dfg/DFGHeapLocation.cpp: (WTF::printInternal): * dfg/DFGHeapLocation.h: * dfg/DFGMayExit.cpp: * dfg/DFGNode.h: (JSC::DFG::Node::convertToPhantomNewObject): (JSC::DFG::Node::convertToPhantomNewArrayIterator): (JSC::DFG::Node::convertToPhantomCreateActivation): (JSC::DFG::Node::hasStructure): (JSC::DFG::Node::hasObjectMaterializationData): (JSC::DFG::Node::isPhantomAllocation): * dfg/DFGNodeType.h: * dfg/DFGObjectAllocationSinkingPhase.cpp: * dfg/DFGOperations.cpp: * dfg/DFGOperations.h: * dfg/DFGPredictionPropagationPhase.cpp: * dfg/DFGPromotedHeapLocation.cpp: (WTF::printInternal): * dfg/DFGPromotedHeapLocation.h: (JSC::DFG::PromotedLocationDescriptor::neededForMaterialization const): * dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileCheckNeutered): (JSC::DFG::SpeculativeJIT::compileToObjectOrCallObjectConstructor): (JSC::DFG::SpeculativeJIT::compileNewInternalFieldObject): (JSC::DFG::SpeculativeJIT::compileNewArrayIterator): * dfg/DFGSpeculativeJIT.h: * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGStoreBarrierInsertionPhase.cpp: * dfg/DFGTypeCheckHoistingPhase.cpp: (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantStructureChecks): (JSC::DFG::TypeCheckHoistingPhase::identifyRedundantArrayChecks): * dfg/DFGValidate.cpp: * ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNode): (JSC::FTL::DFG::LowerDFGToB3::compileToObjectOrCallObjectConstructor): (JSC::FTL::DFG::LowerDFGToB3::compileCheckArray): (JSC::FTL::DFG::LowerDFGToB3::compileCheckNeutered): (JSC::FTL::DFG::LowerDFGToB3::compileNewInternalFieldObject): (JSC::FTL::DFG::LowerDFGToB3::compileNewArrayIterator): (JSC::FTL::DFG::LowerDFGToB3::compileCreateInternalFieldObject): (JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewInternalFieldObjectImpl): (JSC::FTL::DFG::LowerDFGToB3::compileMaterializeNewInternalFieldObject): * ftl/FTLOperations.cpp: (JSC::FTL::operationPopulateObjectInOSR): (JSC::FTL::operationMaterializeObjectInOSR): * inspector/JSInjectedScriptHost.cpp: (Inspector::JSInjectedScriptHost::subtype): (Inspector::JSInjectedScriptHost::getInternalProperties): (Inspector::cloneArrayIteratorObject): (Inspector::JSInjectedScriptHost::iteratorEntries): * runtime/ArrayPrototype.cpp: (JSC::ArrayPrototype::finishCreation): (JSC::createArrayIteratorObject): (JSC::arrayProtoFuncValues): (JSC::arrayProtoFuncEntries): (JSC::arrayProtoFuncKeys): * runtime/CommonIdentifiers.h: * runtime/Intrinsic.cpp: (JSC::intrinsicName): * runtime/Intrinsic.h: * runtime/IterationKind.h: (): Deleted. * runtime/JSArrayIterator.cpp: Added. (JSC::JSArrayIterator::create): (JSC::JSArrayIterator::createWithInitialValues): (JSC::JSArrayIterator::createStructure): (JSC::JSArrayIterator::JSArrayIterator): (JSC::JSArrayIterator::finishCreation): (JSC::JSArrayIterator::visitChildren): * runtime/JSArrayIterator.h: Added. * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildren): * runtime/JSGlobalObject.h: (JSC::JSGlobalObject::arrayIteratorPrototype const): (JSC::JSGlobalObject::arrayIteratorStructure const): * runtime/JSMapIterator.h: * runtime/JSSetIterator.h: * runtime/JSType.cpp: (WTF::printInternal): * runtime/JSType.h: * runtime/JSTypedArrayViewPrototype.cpp: (JSC::createTypedArrayIteratorObject): (JSC::typedArrayViewProtoFuncValues): (JSC::typedArrayProtoViewFuncEntries): (JSC::typedArrayViewProtoFuncKeys): (JSC::JSTypedArrayViewPrototype::finishCreation): * runtime/VM.cpp: * runtime/VM.h: Source/WebCore: JSDOMIterator should just use the JSC IterationKind enum. Also, update other files for the enum member name changes. * bindings/js/JSDOMIterator.h: (WebCore::IteratorTraits>::asJS): * bindings/js/SerializedScriptValue.cpp: (WebCore::CloneSerializer::serialize): * bindings/scripts/CodeGeneratorJS.pm: (GenerateIterableDefinition): * bindings/scripts/test/JS/JSTestInterface.cpp: (WebCore::jsTestInterfacePrototypeFunctionEntriesCaller): (WebCore::jsTestInterfacePrototypeFunctionKeysCaller): (WebCore::jsTestInterfacePrototypeFunctionValuesCaller): * bindings/scripts/test/JS/JSTestIterable.cpp: (WebCore::jsTestIterablePrototypeFunctionEntriesCaller): (WebCore::jsTestIterablePrototypeFunctionKeysCaller): (WebCore::jsTestIterablePrototypeFunctionValuesCaller): * bindings/scripts/test/JS/JSTestNode.cpp: (WebCore::jsTestNodePrototypeFunctionEntriesCaller): (WebCore::jsTestNodePrototypeFunctionKeysCaller): (WebCore::jsTestNodePrototypeFunctionValuesCaller): LayoutTests: Change the labels of iteration kinds to match what JS refers to them as. * inspector/model/remote-object/iterator-expected.txt: * inspector/model/remote-object/iterator-large-expected.txt: * inspector/model/remote-object/iterators-mutated-expected.txt: Canonical link: https://commits.webkit.org/219108@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@254252 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 999f708 commit 98dd526

78 files changed

Lines changed: 1316 additions & 377 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎JSTests/ChangeLog‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
2020-01-08 Keith Miller <keith_miller@apple.com>
2+
3+
[JSC] Introduce JSArrayIterator
4+
https://bugs.webkit.org/show_bug.cgi?id=204043
5+
6+
Reviewed by Yusuke Suzuki.
7+
8+
* stress/array-iterator-materialize-at-osr-exit.js: Added.
9+
(shouldBe):
10+
(test):
11+
* stress/array-iterator-materialize-one-path.js: Added.
12+
(shouldBe):
13+
(test):
14+
* stress/array-iterator-materialize.js: Added.
15+
(shouldBe):
16+
(test):
17+
* stress/array-iterator-sinking.js: Added.
18+
(shouldBe):
19+
(test):
20+
* stress/array-iterators-next-error-messages.js:
21+
(catch):
22+
* stress/array-iterators-next-with-call.js:
23+
* stress/for-of-iteration.js: Added.
24+
(shouldBe):
25+
(test1):
26+
(test2):
27+
(test3):
28+
* stress/typedarray-functions-with-neutered.js:
29+
(checkProtoFunc):
30+
131
2020-01-08 Saam Barati <sbarati@apple.com>
232

333
Unreviewed follow up on r254188. I accidentally included the same test
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
function shouldBe(actual, expected)
2+
{
3+
if (actual !== expected)
4+
throw new Error('bad value: ' + actual);
5+
}
6+
7+
function test(array, flag)
8+
{
9+
var iterator = array.values();
10+
iterator.next();
11+
if (flag) {
12+
OSRExit();
13+
return iterator;
14+
}
15+
return iterator.next().done;
16+
}
17+
noInline(test);
18+
19+
var array = [0];
20+
for (var i = 0; i < 1e5; ++i)
21+
shouldBe(test(array, false), true);
22+
23+
var iterator = test(array, true);
24+
shouldBe(iterator.__proto__, [].values().__proto__);
25+
shouldBe(iterator.next().done, true);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
function shouldBe(actual, expected) {
2+
if (actual !== expected)
3+
throw new Error('bad value: ' + actual);
4+
}
5+
6+
function test(array, index, flag)
7+
{
8+
var iterator = array.values();
9+
var result = iterator.next().value;
10+
if (index % 100 === 0)
11+
iterator.next();
12+
if (flag)
13+
return iterator;
14+
return result;
15+
}
16+
noInline(test);
17+
18+
var array = [1, 2, 3];
19+
var iterator = array.values();
20+
var ArrayIteratorPrototype = iterator.__proto__;
21+
for (var i = 0; i < 1e6; ++i) {
22+
var flag = i % 10000 === 0;
23+
var result = test(array, i, flag);
24+
if (flag) {
25+
shouldBe(typeof result, "object");
26+
shouldBe(result.next().value, 3);
27+
shouldBe(result.__proto__, ArrayIteratorPrototype);
28+
} else
29+
shouldBe(result, 1);
30+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function shouldBe(actual, expected) {
2+
if (actual !== expected)
3+
throw new Error('bad value: ' + actual);
4+
}
5+
6+
function test(array, flag)
7+
{
8+
var iterator = array.values();
9+
var result = iterator.next().value;
10+
if (flag)
11+
return iterator;
12+
return result;
13+
}
14+
noInline(test);
15+
16+
var array = [1, 2, 3];
17+
var iterator = array.values();
18+
var ArrayIteratorPrototype = iterator.__proto__;
19+
for (var i = 0; i < 1e6; ++i) {
20+
var flag = i % 10000 === 0;
21+
var result = test(array, flag);
22+
if (flag) {
23+
shouldBe(typeof result, "object");
24+
shouldBe(result.next().value, 2);
25+
shouldBe(result.__proto__, ArrayIteratorPrototype);
26+
} else
27+
shouldBe(result, 1);
28+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
function shouldBe(actual, expected) {
2+
if (actual !== expected)
3+
throw new Error('bad value: ' + actual);
4+
}
5+
6+
function test(array)
7+
{
8+
var iterator = array.values();
9+
return iterator.next().value;
10+
}
11+
noInline(test);
12+
13+
var array = [1, 2, 3];
14+
for (var i = 0; i < 1e6; ++i)
15+
shouldBe(test(array), 1);

‎JSTests/stress/array-iterators-next-error-messages.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ next = [].values().next;
88
try {
99
next.call(null);
1010
} catch(e) {
11-
assert(e, "TypeError: %ArrayIteratorPrototype%.next requires that |this| not be null or undefined");
11+
assert(e, "TypeError: %ArrayIteratorPrototype%.next requires that |this| be an Array Iterator instance");
1212
}
1313

1414
try {
1515
next.call(undefined);
1616
} catch(e) {
17-
assert(e, "TypeError: %ArrayIteratorPrototype%.next requires that |this| not be null or undefined");
17+
assert(e, "TypeError: %ArrayIteratorPrototype%.next requires that |this| be an Array Iterator instance");
1818
}

‎JSTests/stress/array-iterators-next-with-call.js‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,8 @@ for (var primitive of primitives) {
8484
if (!didThrow)
8585
throw "Error: no error thrown";
8686
var expectedMessage = 'TypeError: %ArrayIteratorPrototype%.next requires that |this| be an Array Iterator instance';
87-
if (primitive === null)
88-
expectedMessage = 'TypeError: %ArrayIteratorPrototype%.next requires that |this| not be null or undefined';
89-
if (primitive === undefined)
90-
expectedMessage = 'TypeError: %ArrayIteratorPrototype%.next requires that |this| not be null or undefined';
9187
if (String(didThrow) !== expectedMessage)
92-
throw "Error: bad error thrown: " + didThrow;
88+
throw new Error("bad error thrown: " + didThrow + " expected: " + expectedMessage);
9389
}
9490

9591
var nonRelatedObjects = [
@@ -113,5 +109,5 @@ for (var object of nonRelatedObjects) {
113109
if (!didThrow)
114110
throw "Error: no error thrown";
115111
if (String(didThrow) !== 'TypeError: %ArrayIteratorPrototype%.next requires that |this| be an Array Iterator instance')
116-
throw "Error: bad error thrown: " + didThrow;
112+
throw new Error("bad error thrown: " + didThrow);
117113
}

‎JSTests/stress/for-of-iteration.js‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function shouldBe(actual, expected) {
2+
if (actual !== expected)
3+
throw new Error('bad value: ' + actual);
4+
}
5+
6+
function test1(array)
7+
{
8+
var sum = 0;
9+
for (var value of array)
10+
sum += value;
11+
return sum;
12+
}
13+
noInline(test1);
14+
15+
function test2(array)
16+
{
17+
var sum = 0;
18+
for (var value of array.keys())
19+
sum += value;
20+
return sum;
21+
}
22+
noInline(test2);
23+
24+
function test3(array)
25+
{
26+
var sum = 0;
27+
for (var [key, value] of array.entries())
28+
sum += (value + key);
29+
return sum;
30+
}
31+
noInline(test3);
32+
33+
var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
34+
for (var i = 0; i < 1e5; ++i) {
35+
shouldBe(test1(array), 55);
36+
shouldBe(test2(array), 55);
37+
shouldBe(test3(array), 110);
38+
}

‎JSTests/stress/typedarray-functions-with-neutered.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function checkProtoFunc(testArgs) {
6363
}
6464

6565
if (!arrays.every(throwsCorrectError))
66-
throw "bad" + testArgs.func.name;
66+
throw new Error("bad " + testArgs.func.name);
6767
}
6868

6969
function test() {

‎LayoutTests/ChangeLog‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
2020-01-08 Keith Miller <keith_miller@apple.com>
2+
3+
[JSC] Introduce JSArrayIterator
4+
https://bugs.webkit.org/show_bug.cgi?id=204043
5+
6+
Reviewed by Yusuke Suzuki.
7+
8+
Change the labels of iteration kinds to match what JS refers to them as.
9+
10+
* inspector/model/remote-object/iterator-expected.txt:
11+
* inspector/model/remote-object/iterator-large-expected.txt:
12+
* inspector/model/remote-object/iterators-mutated-expected.txt:
13+
114
2020-01-08 Ryan Haddad <ryanhaddad@apple.com>
215

316
few web-platform-tests are failing on iOS

0 commit comments

Comments
 (0)