Separate out array iteration intrinsics
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Oct 2013 21:08:37 +0000 (21:08 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 14 Oct 2013 21:08:37 +0000 (21:08 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@157420 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/jit/ThunkGenerators.cpp
Source/JavaScriptCore/jit/ThunkGenerators.h
Source/JavaScriptCore/runtime/ArrayIteratorPrototype.cpp
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/JSArrayIterator.cpp
Source/JavaScriptCore/runtime/VM.cpp

index 8df6ee3..195c37e 100644 (file)
@@ -1,3 +1,35 @@
+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  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         llint_slow_path_put_by_id can deadlock on a ConcurrentJITLock
index 31b01bb..79be6d9 100644 (file)
@@ -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 == ArrayIterateValue);
     
     // 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);
 }
     
 }
index 69da39d..b8f6cc4 100644 (file)
@@ -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)
index 0871da6..1ccb791 100644 (file)
@@ -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());
index fb23e0b..cd06c7e 100644 (file)
@@ -49,7 +49,9 @@ enum Intrinsic {
     RegExpTestIntrinsic,
     StringPrototypeValueOfIntrinsic,
     IMulIntrinsic,
-    ArrayIteratorNextIntrinsic
+    ArrayIteratorNextValueIntrinsic,
+    ArrayIteratorNextKeyIntrinsic,
+    ArrayIteratorNextGenericIntrinsic
 };
 
 } // namespace JSC
index 28fb19d..c1bf5b3 100644 (file)
@@ -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);
+}
+
 }
index 0332535..36831e8 100644 (file)
@@ -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;
     }