[ESNext] Async iteration - Implement Async Generator - optimization
authorgskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Sep 2017 15:05:53 +0000 (15:05 +0000)
committergskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 23 Sep 2017 15:05:53 +0000 (15:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175891

Reviewed by Yusuke Suzuki.

Add small optimization for async generators:
1. merging async generator queue to async generator itself
generator.@first / generator.@last is enough, by doing so,
  we remove one unnecessary object alloc.
2. merging request with queue.

* builtins/AsyncGeneratorPrototype.js:
(globalPrivate.asyncGeneratorQueueIsEmpty):
(globalPrivate.asyncGeneratorQueueCreateItem):
(globalPrivate.asyncGeneratorQueueEnqueue):
(globalPrivate.asyncGeneratorQueueDequeue):
(globalPrivate.asyncGeneratorDequeue):
(globalPrivate.isSuspendYieldState):
(globalPrivate.asyncGeneratorEnqueue):
* builtins/BuiltinNames.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitPutAsyncGeneratorFields):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionNode::emitBytecode):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/AsyncGeneratorPrototype.js
Source/JavaScriptCore/builtins/BuiltinNames.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

index ca48b69..ad0527f 100644 (file)
@@ -1,3 +1,31 @@
+2017-09-23  Oleksandr Skachkov  <gskachkov@gmail.com>
+
+        [ESNext] Async iteration - Implement Async Generator - optimization
+        https://bugs.webkit.org/show_bug.cgi?id=175891
+
+        Reviewed by Yusuke Suzuki.
+
+        Add small optimization for async generators:
+        1. merging async generator queue to async generator itself
+        generator.@first / generator.@last is enough, by doing so,
+          we remove one unnecessary object alloc.
+        2. merging request with queue.
+
+        * builtins/AsyncGeneratorPrototype.js:
+        (globalPrivate.asyncGeneratorQueueIsEmpty):
+        (globalPrivate.asyncGeneratorQueueCreateItem):
+        (globalPrivate.asyncGeneratorQueueEnqueue):
+        (globalPrivate.asyncGeneratorQueueDequeue):
+        (globalPrivate.asyncGeneratorDequeue):
+        (globalPrivate.isSuspendYieldState):
+        (globalPrivate.asyncGeneratorEnqueue):
+        * builtins/BuiltinNames.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitPutAsyncGeneratorFields):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::FunctionNode::emitBytecode):
+
 2017-09-23  Joseph Pecoraro  <pecoraro@apple.com>
 
         test262: $.agent became $262.agent in test262 update
index 95c29d4..1459747 100644 (file)
  */
 
 @globalPrivate
-function createAsyncGeneratorQueue()
+function asyncGeneratorQueueIsEmpty(generator)
 {
     "use strict";
 
-    return { first: null, last: null };
+    return generator.@asyncGeneratorQueueLast === null;
 }
 
 @globalPrivate
-function asyncGeneratorQueueIsEmpty(queue)
+function asyncGeneratorQueueEnqueue(generator, item)
 {
     "use strict";
 
-    return queue.last === null;
-}
-
-@globalPrivate
-function asyncGeneratorQueueCreateItem(value, previous)
-{
-    "use strict";
+    @assert(item.@asyncGeneratorQueueItemNext === null && item.@asyncGeneratorQueueItemPrevious === null);
 
-    return { value, previous, next: null };
-}
+    if (generator.@asyncGeneratorQueueFirst === null) {
+        @assert(generator.@asyncGeneratorQueueLast === null);
 
-@globalPrivate
-function asyncGeneratorQueueEnqueue(queue, value)
-{
-    "use strict";
-
-    if (queue.first === null && queue.last === null) {
-        queue.first = @asyncGeneratorQueueCreateItem(value, null);
-        queue.last = queue.first;
+        generator.@asyncGeneratorQueueFirst = item;
+        generator.@asyncGeneratorQueueLast = item;
     } else {
-        const item = @asyncGeneratorQueueCreateItem(value, queue.last);
-
-        queue.last.next = item;
-        queue.last = item;
+        item.@asyncGeneratorQueueItemPrevious = generator.@asyncGeneratorQueueLast;
+        generator.@asyncGeneratorQueueLast.@asyncGeneratorQueueItemNext = item;
+        generator.@asyncGeneratorQueueLast = item;
     }
-
 }
 
 @globalPrivate
-function asyncGeneratorQueueDequeue(queue)
+function asyncGeneratorQueueDequeue(generator)
 {
     "use strict";
 
-    if (queue.first === null)
+    if (generator.@asyncGeneratorQueueFirst === null)
         return null;
 
-    const result = queue.first;
-    queue.first = result.next;
-
-    if (queue.first === null)
-        queue.last = null;
-
-    return result.value;
-}
-
+    const result = generator.@asyncGeneratorQueueFirst;
+    generator.@asyncGeneratorQueueFirst = result.@asyncGeneratorQueueItemNext;
 
-@globalPrivate
-function asyncGeneratorQueueGetFirstValue(queue)
-{
-    "use strict";
+    if (generator.@asyncGeneratorQueueFirst === null)
+        generator.@asyncGeneratorQueueLast = null;
 
-    return queue.first !== null ? queue.first.value : @undefined;
+    return result;
 }
 
 @globalPrivate
@@ -97,9 +74,9 @@ function asyncGeneratorDequeue(generator)
 
     const queue = generator.@asyncGeneratorQueue;
 
-    @assert(queue !== @undefined && !@asyncGeneratorQueueIsEmpty(queue), "Async genetator's Queue is an empty List.");
+    @assert(!@asyncGeneratorQueueIsEmpty(generator), "Async genetator's Queue is an empty List.");
     
-    return @asyncGeneratorQueueDequeue(queue);
+    return @asyncGeneratorQueueDequeue(generator);
 }
 
 @globalPrivate
@@ -118,7 +95,7 @@ function isSuspendYieldState(generator)
     "use strict";
 
     return (generator.@generatorState > 0 && generator.@asyncGeneratorSuspendReason === @AsyncGeneratorSuspendReasonYield)
-         || generator.@generatorState === @AsyncGeneratorStateSuspendedYield;
+        || generator.@generatorState === @AsyncGeneratorStateSuspendedYield;
 }
 
 @globalPrivate
@@ -235,12 +212,10 @@ function asyncGeneratorResumeNext(generator)
     if (state === @AsyncGeneratorStateAwaitingReturn)
         return @undefined;
 
-    const queue = generator.@asyncGeneratorQueue;
-
-    if (@asyncGeneratorQueueIsEmpty(queue))
+    if (@asyncGeneratorQueueIsEmpty(generator))
         return @undefined;
 
-    const next = @asyncGeneratorQueueGetFirstValue(queue);
+    const next = generator.@asyncGeneratorQueueFirst;
 
     if (next.resumeMode !== @GeneratorResumeModeNormal) {
         if (state === @AsyncGeneratorStateSuspendedStart) {
@@ -289,7 +264,7 @@ function asyncGeneratorEnqueue(generator, value, resumeMode)
         return promiseCapability.@promise;
     }
 
-    @asyncGeneratorQueueEnqueue(generator.@asyncGeneratorQueue, {resumeMode, value, promiseCapability});
+    @asyncGeneratorQueueEnqueue(generator, {resumeMode, value, promiseCapability, @asyncGeneratorQueueItemNext: null, @asyncGeneratorQueueItemPrevious: null});
 
     if (!@isExecutionState(generator))
         @asyncGeneratorResumeNext(generator);
index 2f316c9..a18513b 100644 (file)
@@ -126,6 +126,10 @@ namespace JSC {
     macro(asyncGeneratorState) \
     macro(asyncGeneratorSuspendReason) \
     macro(asyncGeneratorQueue) \
+    macro(asyncGeneratorQueueFirst) \
+    macro(asyncGeneratorQueueLast) \
+    macro(asyncGeneratorQueueItemNext) \
+    macro(asyncGeneratorQueueItemPrevious) \
     macro(promiseCapability) \
     macro(generatorResumeMode) \
     macro(Collator) \
index 6160639..b6c66f6 100644 (file)
@@ -2871,23 +2871,7 @@ void BytecodeGenerator::emitPutGeneratorFields(RegisterID* nextFunction)
     emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().generatorFramePrivateName(), emitLoad(nullptr, jsNull()), PropertyNode::KnownDirect);
 }
 
-RegisterID* BytecodeGenerator::emitCreateAsyncGeneratorQueue(const JSTextPosition& divot)
-{
-    auto varCreateAsyncGeneratorQueue = variable(propertyNames().builtinNames().createAsyncGeneratorQueuePrivateName());
-    RefPtr<RegisterID> scope = newTemporary();
-    RefPtr<RegisterID> queue = newTemporary();
-    moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), varCreateAsyncGeneratorQueue));
-    RefPtr<RegisterID> createAsyncGeneratorQueue = emitGetFromScope(newTemporary(), scope.get(), varCreateAsyncGeneratorQueue, ThrowIfNotFound);
-
-    CallArguments args(*this, nullptr, 0);
-    emitLoad(args.thisRegister(), jsUndefined());
-
-    emitCall(queue.get(), createAsyncGeneratorQueue.get(), NoExpectedFunction, args, divot, divot, divot, DebuggableCall::No);
-
-    return queue.get();
-}
-
-void BytecodeGenerator::emitPutAsyncGeneratorFields(RegisterID* nextFunction, const JSTextPosition& divot)
+void BytecodeGenerator::emitPutAsyncGeneratorFields(RegisterID* nextFunction)
 {
     ASSERT(isAsyncGeneratorFunctionParseMode(parseMode()));
 
@@ -2901,8 +2885,8 @@ void BytecodeGenerator::emitPutAsyncGeneratorFields(RegisterID* nextFunction, co
 
     emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().asyncGeneratorSuspendReasonPrivateName(), emitLoad(nullptr, jsNumber(static_cast<int32_t>(JSAsyncGeneratorFunction::AsyncGeneratorSuspendReason::None))), PropertyNode::KnownDirect);
 
-
-    emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().asyncGeneratorQueuePrivateName(), emitCreateAsyncGeneratorQueue(divot), PropertyNode::KnownDirect);
+    emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().asyncGeneratorQueueFirstPrivateName(), emitLoad(nullptr, jsNull()), PropertyNode::KnownDirect);
+    emitDirectPutById(m_generatorRegister, propertyNames().builtinNames().asyncGeneratorQueueLastPrivateName(), emitLoad(nullptr, jsNull()), PropertyNode::KnownDirect);
 }
 
 RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
index 89ef1bd..57ce852 100644 (file)
@@ -607,7 +607,6 @@ namespace JSC {
 
     private:
         void emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot);
-        RegisterID* emitCreateAsyncGeneratorQueue(const JSTextPosition&);
     public:
 
         // This doesn't emit expression info. If using this, make sure you shouldn't be emitting text offset.
@@ -704,7 +703,7 @@ namespace JSC {
         // Initialize object with generator fields (@generatorThis, @generatorNext, @generatorState, @generatorFrame)
         void emitPutGeneratorFields(RegisterID* nextFunction);
         
-        void emitPutAsyncGeneratorFields(RegisterID* nextFunction, const JSTextPosition&);
+        void emitPutAsyncGeneratorFields(RegisterID* nextFunction);
 
         ExpectedFunction expectedFunctionForIdentifier(const Identifier&);
         RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall);
index e4883a1..9c8d0cd 100644 (file)
@@ -3602,7 +3602,7 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
             generator.emitPutGeneratorFields(next.get());
         else {
             ASSERT(isAsyncGeneratorFunctionParseMode(generator.parseMode()));
-            generator.emitPutAsyncGeneratorFields(next.get(), JSTextPosition(startLine(), startStartOffset(), startLineStartOffset()));
+            generator.emitPutAsyncGeneratorFields(next.get());
         }
         
         ASSERT(startOffset() >= lineStartOffset());