Commit 9bec8d3f authored by oliver@apple.com's avatar oliver@apple.com

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):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@157307 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 22a65e2e
2013-10-11 Oliver Hunt <oliver@apple.com>
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):
2013-10-11 Andreas Kling <akling@apple.com>
Pass VM instead of ExecState to JSGenericTypedArrayViewPrototype.
......@@ -988,7 +988,7 @@ MacroAssemblerCodeRef imulThunkGenerator(VM* vm)
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "imul");
}
MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm)
static MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm, ArrayIterationKind kind)
{
typedef SpecializedThunkJIT::TrustedImm32 TrustedImm32;
typedef SpecializedThunkJIT::TrustedImmPtr TrustedImmPtr;
......@@ -1014,7 +1014,7 @@ MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm)
jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2);
jit.and32(TrustedImm32(IndexingShapeMask), SpecializedThunkJIT::regT3);
Jump notDone = jit.branch32(SpecializedThunkJIT::Below, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfPublicLength()));
// Return the termination signal to indicate that we've finished
jit.move(TrustedImmPtr(vm->iterationTerminator.get()), SpecializedThunkJIT::regT0);
......@@ -1022,14 +1022,13 @@ MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm)
notDone.link(&jit);
Jump notKey = jit.branch32(SpecializedThunkJIT::NotEqual, Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfIterationKind()), TrustedImm32(ArrayIterateKey));
// If we're doing key iteration we just need to increment m_nextIndex and return the current value
jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
jit.returnInt32(SpecializedThunkJIT::regT1);
notKey.link(&jit);
if (kind == ArrayIterateKey) {
jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
jit.returnInt32(SpecializedThunkJIT::regT1);
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "array-iterator-next-key");
}
ASSERT(kind == ArrayIterateKeyValue);
// Okay, now we're returning a value so make sure we're inside the vector size
jit.appendFailure(jit.branch32(SpecializedThunkJIT::AboveOrEqual, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfVectorLength())));
......@@ -1077,7 +1076,17 @@ MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm)
jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
jit.returnDouble(SpecializedThunkJIT::fpRegT0);
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "array-iterator-next");
return jit.finalize(vm->jitStubs->ctiNativeCall(vm), "array-iterator-next-value");
}
MacroAssemblerCodeRef arrayIteratorNextKeyThunkGenerator(VM* vm)
{
return arrayIteratorNextThunkGenerator(vm, ArrayIterateKey);
}
MacroAssemblerCodeRef arrayIteratorNextValueThunkGenerator(VM* vm)
{
return arrayIteratorNextThunkGenerator(vm, ArrayIterateValue);
}
}
......
......@@ -58,7 +58,8 @@ MacroAssemblerCodeRef roundThunkGenerator(VM*);
MacroAssemblerCodeRef sqrtThunkGenerator(VM*);
MacroAssemblerCodeRef powThunkGenerator(VM*);
MacroAssemblerCodeRef imulThunkGenerator(VM*);
MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM*);
MacroAssemblerCodeRef arrayIteratorNextKeyThunkGenerator(VM*);
MacroAssemblerCodeRef arrayIteratorNextValueThunkGenerator(VM*);
}
#endif // ENABLE(JIT)
......
......@@ -36,7 +36,6 @@ namespace JSC {
const ClassInfo ArrayIteratorPrototype::s_info = { "Array Iterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ArrayIteratorPrototype) };
static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeNext(ExecState*);
static EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(ExecState*);
void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
......@@ -45,90 +44,9 @@ void ArrayIteratorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject
ASSERT(inherits(info()));
vm.prototypeMap.addPrototype(this);
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorPrototypeNext, DontEnum, 0, ArrayIteratorNextIntrinsic);
JSC_NATIVE_FUNCTION(vm.propertyNames->iteratorPrivateName, arrayIteratorPrototypeIterate, DontEnum, 0);
}
static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationKind kind, size_t index, JSValue result, bool done)
{
callFrame->setArgument(callFrame->argumentCount() - 1, jsBoolean(done));
if (done)
return JSValue::encode(callFrame->vm().iterationTerminator.get());
switch (kind & ~ArrayIterateSparseTag) {
case ArrayIterateKey:
return JSValue::encode(jsNumber(index));
case ArrayIterateValue:
return JSValue::encode(result);
case ArrayIterateKeyValue: {
MarkedArgumentBuffer args;
args.append(jsNumber(index));
args.append(result);
JSGlobalObject* globalObject = callFrame->callee()->globalObject();
return JSValue::encode(constructArray(callFrame, 0, globalObject, args));
}
default:
RELEASE_ASSERT_NOT_REACHED();
}
return JSValue::encode(JSValue());
}
EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeNext(CallFrame* callFrame)
{
JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue());
if (!iterator)
throwTypeError(callFrame, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object"));
JSObject* iteratedObject = iterator->iteratedObject();
size_t index = iterator->nextIndex();
ArrayIterationKind kind = iterator->iterationKind();
JSValue jsLength = JSValue(iteratedObject).get(callFrame, callFrame->propertyNames().length);
if (callFrame->hadException())
return JSValue::encode(jsNull());
size_t length = jsLength.toUInt32(callFrame);
if (callFrame->hadException())
return JSValue::encode(jsNull());
if (index >= length) {
iterator->finish();
return createIteratorResult(callFrame, kind, index, jsUndefined(), true);
}
if (JSValue result = iteratedObject->tryGetIndexQuickly(index)) {
iterator->setNextIndex(index + 1);
return createIteratorResult(callFrame, kind, index, result, false);
}
JSValue result = jsUndefined();
PropertySlot slot(iteratedObject);
if (kind > ArrayIterateSparseTag) {
// We assume that the indexed property will be an own property so cache the getOwnProperty
// method locally
auto getOwnPropertySlotByIndex = iteratedObject->methodTable()->getOwnPropertySlotByIndex;
while (index < length) {
if (getOwnPropertySlotByIndex(iteratedObject, callFrame, index, slot)) {
result = slot.getValue(callFrame, index);
break;
}
if (iteratedObject->getPropertySlot(callFrame, index, slot)) {
result = slot.getValue(callFrame, index);
break;
}
index++;
}
} else if (iteratedObject->getPropertySlot(callFrame, index, slot))
result = slot.getValue(callFrame, index);
if (index == length)
iterator->finish();
else
iterator->setNextIndex(index + 1);
return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length);
}
EncodedJSValue JSC_HOST_CALL arrayIteratorPrototypeIterate(CallFrame* callFrame)
{
return JSValue::encode(callFrame->thisValue());
......
......@@ -49,7 +49,9 @@ enum Intrinsic {
RegExpTestIntrinsic,
StringPrototypeValueOfIntrinsic,
IMulIntrinsic,
ArrayIteratorNextIntrinsic
ArrayIteratorNextValueIntrinsic,
ArrayIteratorNextKeyIntrinsic,
ArrayIteratorNextGenericIntrinsic
};
} // namespace JSC
......
......@@ -34,11 +34,28 @@ namespace JSC {
const ClassInfo JSArrayIterator::s_info = { "ArrayIterator", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSArrayIterator) };
void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject*, ArrayIterationKind kind, JSObject* iteratedObject)
static EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(ExecState*);
static EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(ExecState*);
static EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(ExecState*);
void JSArrayIterator::finishCreation(VM& vm, JSGlobalObject* globalObject, ArrayIterationKind kind, JSObject* iteratedObject)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
m_iterationKind = kind;
m_iteratedObject.set(vm, this, iteratedObject);
switch (kind) {
case ArrayIterateKey:
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextKey, DontEnum, 0, ArrayIteratorNextKeyIntrinsic);
break;
case ArrayIterateValue:
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextValue, DontEnum, 0, ArrayIteratorNextValueIntrinsic);
break;
default:
JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->iteratorNextPrivateName, arrayIteratorNextGeneric, DontEnum, 0, ArrayIteratorNextGenericIntrinsic);
break;
}
}
......@@ -54,4 +71,98 @@ void JSArrayIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
}
static EncodedJSValue createIteratorResult(CallFrame* callFrame, ArrayIterationKind kind, size_t index, JSValue result, bool done)
{
callFrame->setArgument(callFrame->argumentCount() - 1, jsBoolean(done));
if (done)
return JSValue::encode(callFrame->vm().iterationTerminator.get());
switch (kind & ~ArrayIterateSparseTag) {
case ArrayIterateKey:
return JSValue::encode(jsNumber(index));
case ArrayIterateValue:
return JSValue::encode(result);
case ArrayIterateKeyValue: {
MarkedArgumentBuffer args;
args.append(jsNumber(index));
args.append(result);
JSGlobalObject* globalObject = callFrame->callee()->globalObject();
return JSValue::encode(constructArray(callFrame, 0, globalObject, args));
}
default:
RELEASE_ASSERT_NOT_REACHED();
}
return JSValue::encode(JSValue());
}
static inline EncodedJSValue JSC_HOST_CALL arrayIteratorNext(CallFrame* callFrame)
{
JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue());
if (!iterator)
throwTypeError(callFrame, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object"));
JSObject* iteratedObject = iterator->iteratedObject();
size_t index = iterator->nextIndex();
ArrayIterationKind kind = iterator->iterationKind();
JSValue jsLength = JSValue(iteratedObject).get(callFrame, callFrame->propertyNames().length);
if (callFrame->hadException())
return JSValue::encode(jsNull());
size_t length = jsLength.toUInt32(callFrame);
if (callFrame->hadException())
return JSValue::encode(jsNull());
if (index >= length) {
iterator->finish();
return createIteratorResult(callFrame, kind, index, jsUndefined(), true);
}
if (JSValue result = iteratedObject->tryGetIndexQuickly(index)) {
iterator->setNextIndex(index + 1);
return createIteratorResult(callFrame, kind, index, result, false);
}
JSValue result = jsUndefined();
PropertySlot slot(iteratedObject);
if (kind > ArrayIterateSparseTag) {
// We assume that the indexed property will be an own property so cache the getOwnProperty
// method locally
auto getOwnPropertySlotByIndex = iteratedObject->methodTable()->getOwnPropertySlotByIndex;
while (index < length) {
if (getOwnPropertySlotByIndex(iteratedObject, callFrame, index, slot)) {
result = slot.getValue(callFrame, index);
break;
}
if (iteratedObject->getPropertySlot(callFrame, index, slot)) {
result = slot.getValue(callFrame, index);
break;
}
index++;
}
} else if (iteratedObject->getPropertySlot(callFrame, index, slot))
result = slot.getValue(callFrame, index);
if (index == length)
iterator->finish();
else
iterator->setNextIndex(index + 1);
return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length);
}
EncodedJSValue JSC_HOST_CALL arrayIteratorNextKey(CallFrame* callFrame)
{
return arrayIteratorNext(callFrame);
}
EncodedJSValue JSC_HOST_CALL arrayIteratorNextValue(CallFrame* callFrame)
{
return arrayIteratorNext(callFrame);
}
EncodedJSValue JSC_HOST_CALL arrayIteratorNextGeneric(CallFrame* callFrame)
{
return arrayIteratorNext(callFrame);
}
}
......@@ -425,8 +425,10 @@ static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
return logThunkGenerator;
case IMulIntrinsic:
return imulThunkGenerator;
case ArrayIteratorNextIntrinsic:
return arrayIteratorNextThunkGenerator;
case ArrayIteratorNextKeyIntrinsic:
return arrayIteratorNextKeyThunkGenerator;
case ArrayIteratorNextValueIntrinsic:
return arrayIteratorNextValueThunkGenerator;
default:
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment