Skip to content

Commit a2a7643

Browse files
committed
Separate out array iteration intrinsics
https://bugs.webkit.org/show_bug.cgi?id=122656 Reviewed by Michael Saboff. Separate out the intrinsics for key and values iteration of arrays. This requires moving moving array iteration into the iterator instance, rather than the prototype, but this is essentially unobservable so we'll live with it for now. * jit/ThunkGenerators.cpp: (JSC::arrayIteratorNextThunkGenerator): (JSC::arrayIteratorNextKeyThunkGenerator): (JSC::arrayIteratorNextValueThunkGenerator): * jit/ThunkGenerators.h: * runtime/ArrayIteratorPrototype.cpp: (JSC::ArrayIteratorPrototype::finishCreation): * runtime/Intrinsic.h: * runtime/JSArrayIterator.cpp: (JSC::JSArrayIterator::finishCreation): (JSC::createIteratorResult): (JSC::arrayIteratorNext): (JSC::arrayIteratorNextKey): (JSC::arrayIteratorNextValue): (JSC::arrayIteratorNextGeneric): * runtime/VM.cpp: (JSC::thunkGeneratorForIntrinsic): Canonical link: https://commits.webkit.org/140889@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@157420 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent ed8d72d commit a2a7643

7 files changed

Lines changed: 173 additions & 98 deletions

File tree

‎Source/JavaScriptCore/ChangeLog‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,35 @@
1+
2013-10-11 Oliver Hunt <oliver@apple.com>
2+
3+
Separate out array iteration intrinsics
4+
https://bugs.webkit.org/show_bug.cgi?id=122656
5+
6+
Reviewed by Michael Saboff.
7+
8+
Separate out the intrinsics for key and values iteration
9+
of arrays.
10+
11+
This requires moving moving array iteration into the iterator
12+
instance, rather than the prototype, but this is essentially
13+
unobservable so we'll live with it for now.
14+
15+
* jit/ThunkGenerators.cpp:
16+
(JSC::arrayIteratorNextThunkGenerator):
17+
(JSC::arrayIteratorNextKeyThunkGenerator):
18+
(JSC::arrayIteratorNextValueThunkGenerator):
19+
* jit/ThunkGenerators.h:
20+
* runtime/ArrayIteratorPrototype.cpp:
21+
(JSC::ArrayIteratorPrototype::finishCreation):
22+
* runtime/Intrinsic.h:
23+
* runtime/JSArrayIterator.cpp:
24+
(JSC::JSArrayIterator::finishCreation):
25+
(JSC::createIteratorResult):
26+
(JSC::arrayIteratorNext):
27+
(JSC::arrayIteratorNextKey):
28+
(JSC::arrayIteratorNextValue):
29+
(JSC::arrayIteratorNextGeneric):
30+
* runtime/VM.cpp:
31+
(JSC::thunkGeneratorForIntrinsic):
32+
133
2013-10-11 Mark Hahnenberg <mhahnenberg@apple.com>
234

335
llint_slow_path_put_by_id can deadlock on a ConcurrentJITLock

‎Source/JavaScriptCore/jit/ThunkGenerators.cpp‎

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ MacroAssemblerCodeRef imulThunkGenerator(VM* vm)
988988
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "imul");
989989
}
990990
991-
MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm)
991+
static MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm, ArrayIterationKind kind)
992992
{
993993
typedef SpecializedThunkJIT::TrustedImm32 TrustedImm32;
994994
typedef SpecializedThunkJIT::TrustedImmPtr TrustedImmPtr;
@@ -1014,22 +1014,21 @@ MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm)
10141014
jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2);
10151015
10161016
jit.and32(TrustedImm32(IndexingShapeMask), SpecializedThunkJIT::regT3);
1017-
1017+
10181018
Jump notDone = jit.branch32(SpecializedThunkJIT::Below, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfPublicLength()));
10191019
// Return the termination signal to indicate that we've finished
10201020
jit.move(TrustedImmPtr(vm->iterationTerminator.get()), SpecializedThunkJIT::regT0);
10211021
jit.returnJSCell(SpecializedThunkJIT::regT0);
10221022
10231023
notDone.link(&jit);
10241024
1025-
1026-
Jump notKey = jit.branch32(SpecializedThunkJIT::NotEqual, Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfIterationKind()), TrustedImm32(ArrayIterateKey));
1027-
// If we're doing key iteration we just need to increment m_nextIndex and return the current value
1028-
jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
1029-
jit.returnInt32(SpecializedThunkJIT::regT1);
1030-
1031-
notKey.link(&jit);
1032-
1025+
if (kind == ArrayIterateKey) {
1026+
jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
1027+
jit.returnInt32(SpecializedThunkJIT::regT1);
1028+
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "array-iterator-next-key");
1029+
1030+
}
1031+
ASSERT(kind == ArrayIterateValue);
10331032
10341033
// Okay, now we're returning a value so make sure we're inside the vector size
10351034
jit.appendFailure(jit.branch32(SpecializedThunkJIT::AboveOrEqual, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfVectorLength())));
@@ -1077,7 +1076,17 @@ MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm)
10771076
jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
10781077
jit.returnDouble(SpecializedThunkJIT::fpRegT0);
10791078
1080-
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "array-iterator-next");
1079+
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "array-iterator-next-value");
1080+
}
1081+
1082+
MacroAssemblerCodeRef arrayIteratorNextKeyThunkGenerator(VM* vm)
1083+
{
1084+
return arrayIteratorNextThunkGenerator(vm, ArrayIterateKey);
1085+
}
1086+
1087+
MacroAssemblerCodeRef arrayIteratorNextValueThunkGenerator(VM* vm)
1088+
{
1089+
return arrayIteratorNextThunkGenerator(vm, ArrayIterateValue);
10811090
}
10821091
10831092
}

‎Source/JavaScriptCore/jit/ThunkGenerators.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ MacroAssemblerCodeRef roundThunkGenerator(VM*);
5858
MacroAssemblerCodeRef sqrtThunkGenerator(VM*);
5959
MacroAssemblerCodeRef powThunkGenerator(VM*);
6060
MacroAssemblerCodeRef imulThunkGenerator(VM*);
61-
MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM*);
61+
MacroAssemblerCodeRef arrayIteratorNextKeyThunkGenerator(VM*);
62+
MacroAssemblerCodeRef arrayIteratorNextValueThunkGenerator(VM*);
6263

6364
}
6465
#endif // ENABLE(JIT)

‎Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp‎

Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ namespace JSC {
3636

3737
const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArrayIteratorPrototype) };
3838

39-
static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeNext(ExecState*);
4039
static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(ExecState*);
4140

4241
void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
@@ -45,90 +44,9 @@ void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject
4544
ASSERT(inherits(info()));
4645
vm.prototypeMap.addPrototype(this);
4746

48-
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorPrototypeNext, DontEnum, 0, ArrayIteratorNextIntrinsic);
49-
5047
JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayIteratorPrototypeIterate, DontEnum, 0);
5148
}
5249

53-
static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationKind kind, size_t index, JSValue result, bool done)
54-
{
55-
callFrame->setArgument(callFrame->argumentCount() - 1, jsBoolean(done));
56-
if (done)
57-
return JSValue::encode(callFrame->vm().iterationTerminator.get());
58-
59-
switch (kind & ~ArrayIterateSparseTag) {
60-
case ArrayIterateKey:
61-
return JSValue::encode(jsNumber(index));
62-
63-
case ArrayIterateValue:
64-
return JSValue::encode(result);
65-
66-
case ArrayIterateKeyValue: {
67-
MarkedArgumentBuffer args;
68-
args.append(jsNumber(index));
69-
args.append(result);
70-
JSGlobalObject* globalObject = callFrame->callee()->globalObject();
71-
return JSValue::encode(constructArray(callFrame, 0, globalObject, args));
72-
73-
}
74-
default:
75-
RELEASE_ASSERT_NOT_REACHED();
76-
}
77-
return JSValue::encode(JSValue());
78-
}
79-
80-
EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeNext(CallFrame* callFrame)
81-
{
82-
JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue());
83-
if (!iterator)
84-
throwTypeError(callFrame, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object"));
85-
JSObject* iteratedObject = iterator->iteratedObject();
86-
size_t index = iterator->nextIndex();
87-
ArrayIterationKind kind = iterator->iterationKind();
88-
JSValue jsLength = JSValue(iteratedObject).get(callFrame, callFrame->propertyNames().length);
89-
if (callFrame->hadException())
90-
return JSValue::encode(jsNull());
91-
92-
size_t length = jsLength.toUInt32(callFrame);
93-
if (callFrame->hadException())
94-
return JSValue::encode(jsNull());
95-
96-
if (index >= length) {
97-
iterator->finish();
98-
return createIteratorResult(callFrame, kind, index, jsUndefined(), true);
99-
}
100-
if (JSValue result = iteratedObject->tryGetIndexQuickly(index)) {
101-
iterator->setNextIndex(index + 1);
102-
return createIteratorResult(callFrame, kind, index, result, false);
103-
}
104-
105-
JSValue result = jsUndefined();
106-
PropertySlot slot(iteratedObject);
107-
if (kind > ArrayIterateSparseTag) {
108-
// We assume that the indexed property will be an own property so cache the getOwnProperty
109-
// method locally
110-
auto getOwnPropertySlotByIndex = iteratedObject->methodTable()->getOwnPropertySlotByIndex;
111-
while (index < length) {
112-
if (getOwnPropertySlotByIndex(iteratedObject, callFrame, index, slot)) {
113-
result = slot.getValue(callFrame, index);
114-
break;
115-
}
116-
if (iteratedObject->getPropertySlot(callFrame, index, slot)) {
117-
result = slot.getValue(callFrame, index);
118-
break;
119-
}
120-
index++;
121-
}
122-
} else if (iteratedObject->getPropertySlot(callFrame, index, slot))
123-
result = slot.getValue(callFrame, index);
124-
125-
if (index == length)
126-
iterator->finish();
127-
else
128-
iterator->setNextIndex(index + 1);
129-
return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length);
130-
}
131-
13250
EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(CallFrame* callFrame)
13351
{
13452
return JSValue::encode(callFrame->thisValue());

‎Source/JavaScriptCore/runtime/Intrinsic.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ enum Intrinsic {
4949
RegExpTestIntrinsic,
5050
StringPrototypeValueOfIntrinsic,
5151
IMulIntrinsic,
52-
ArrayIteratorNextIntrinsic
52+
ArrayIteratorNextValueIntrinsic,
53+
ArrayIteratorNextKeyIntrinsic,
54+
ArrayIteratorNextGenericIntrinsic
5355
};
5456

5557
} // namespace JSC

‎Source/JavaScriptCore/runtime/JSArrayIterator.cpp‎

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,28 @@ namespace JSC {
3434

3535
const ClassInfo JSArrayIterator::s_info = { "ArrayIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayIterator) };
3636

37-
void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject*, ArrayIterationKind kind, JSObject* iteratedObject)
37+
static EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(ExecState*);
38+
static EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(ExecState*);
39+
static EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(ExecState*);
40+
41+
void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayIterationKind kind, JSObject* iteratedObject)
3842
{
3943
Base::finishCreation(vm);
44+
ASSERT(inherits(info()));
4045
m_iterationKind = kind;
4146
m_iteratedObject.set(vm, this, iteratedObject);
47+
switch (kind) {
48+
case ArrayIterateKey:
49+
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextKey, DontEnum, 0, ArrayIteratorNextKeyIntrinsic);
50+
break;
51+
case ArrayIterateValue:
52+
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextValue, DontEnum, 0, ArrayIteratorNextValueIntrinsic);
53+
break;
54+
default:
55+
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextGeneric, DontEnum, 0, ArrayIteratorNextGenericIntrinsic);
56+
break;
57+
}
58+
4259
}
4360

4461

@@ -54,4 +71,98 @@ void JSArrayIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
5471

5572
}
5673

74+
static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationKind kind, size_t index, JSValue result, bool done)
75+
{
76+
callFrame->setArgument(callFrame->argumentCount() - 1, jsBoolean(done));
77+
if (done)
78+
return JSValue::encode(callFrame->vm().iterationTerminator.get());
79+
80+
switch (kind & ~ArrayIterateSparseTag) {
81+
case ArrayIterateKey:
82+
return JSValue::encode(jsNumber(index));
83+
84+
case ArrayIterateValue:
85+
return JSValue::encode(result);
86+
87+
case ArrayIterateKeyValue: {
88+
MarkedArgumentBuffer args;
89+
args.append(jsNumber(index));
90+
args.append(result);
91+
JSGlobalObject* globalObject = callFrame->callee()->globalObject();
92+
return JSValue::encode(constructArray(callFrame, 0, globalObject, args));
93+
94+
}
95+
default:
96+
RELEASE_ASSERT_NOT_REACHED();
97+
}
98+
return JSValue::encode(JSValue());
99+
}
100+
101+
static inline EncodedJSValue JSC_HOST_CALL arrayIteratorNext(CallFrame* callFrame)
102+
{
103+
JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue());
104+
if (!iterator)
105+
throwTypeError(callFrame, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object"));
106+
JSObject* iteratedObject = iterator->iteratedObject();
107+
size_t index = iterator->nextIndex();
108+
ArrayIterationKind kind = iterator->iterationKind();
109+
JSValue jsLength = JSValue(iteratedObject).get(callFrame, callFrame->propertyNames().length);
110+
if (callFrame->hadException())
111+
return JSValue::encode(jsNull());
112+
113+
size_t length = jsLength.toUInt32(callFrame);
114+
if (callFrame->hadException())
115+
return JSValue::encode(jsNull());
116+
117+
if (index >= length) {
118+
iterator->finish();
119+
return createIteratorResult(callFrame, kind, index, jsUndefined(), true);
120+
}
121+
if (JSValue result = iteratedObject->tryGetIndexQuickly(index)) {
122+
iterator->setNextIndex(index + 1);
123+
return createIteratorResult(callFrame, kind, index, result, false);
124+
}
125+
126+
JSValue result = jsUndefined();
127+
PropertySlot slot(iteratedObject);
128+
if (kind > ArrayIterateSparseTag) {
129+
// We assume that the indexed property will be an own property so cache the getOwnProperty
130+
// method locally
131+
auto getOwnPropertySlotByIndex = iteratedObject->methodTable()->getOwnPropertySlotByIndex;
132+
while (index < length) {
133+
if (getOwnPropertySlotByIndex(iteratedObject, callFrame, index, slot)) {
134+
result = slot.getValue(callFrame, index);
135+
break;
136+
}
137+
if (iteratedObject->getPropertySlot(callFrame, index, slot)) {
138+
result = slot.getValue(callFrame, index);
139+
break;
140+
}
141+
index++;
142+
}
143+
} else if (iteratedObject->getPropertySlot(callFrame, index, slot))
144+
result = slot.getValue(callFrame, index);
145+
146+
if (index == length)
147+
iterator->finish();
148+
else
149+
iterator->setNextIndex(index + 1);
150+
return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length);
151+
}
152+
153+
EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(CallFrame* callFrame)
154+
{
155+
return arrayIteratorNext(callFrame);
156+
}
157+
158+
EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(CallFrame* callFrame)
159+
{
160+
return arrayIteratorNext(callFrame);
161+
}
162+
163+
EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(CallFrame* callFrame)
164+
{
165+
return arrayIteratorNext(callFrame);
166+
}
167+
57168
}

‎Source/JavaScriptCore/runtime/VM.cpp‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,10 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
425425
return logThunkGenerator;
426426
case IMulIntrinsic:
427427
return imulThunkGenerator;
428-
case ArrayIteratorNextIntrinsic:
429-
return arrayIteratorNextThunkGenerator;
428+
case ArrayIteratorNextKeyIntrinsic:
429+
return arrayIteratorNextKeyThunkGenerator;
430+
case ArrayIteratorNextValueIntrinsic:
431+
return arrayIteratorNextValueThunkGenerator;
430432
default:
431433
return 0;
432434
}

0 commit comments

Comments
 (0)