Generator object "next" method takes optional send value
authorwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 10 Jun 2013 09:26:18 +0000 (09:26 +0000)
committerwingo@igalia.com <wingo@igalia.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 10 Jun 2013 09:26:18 +0000 (09:26 +0000)
Update the generators implementation to make "next" also do the job of
what was previously called "send" by taking an optional argument.
Remove send, and do a bunch of renamings.

R=rossberg@chromium.org
BUG=v8:2355, v8:2715

Review URL: https://codereview.chromium.org/16136011

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15028 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/arm/full-codegen-arm.cc
src/full-codegen.cc
src/generator.js
src/heap.h
src/hydrogen.cc
src/ia32/full-codegen-ia32.cc
src/objects.h
src/runtime.cc
src/runtime.h
src/x64/full-codegen-x64.cc
test/mjsunit/harmony/generators-iteration.js
test/mjsunit/harmony/generators-objects.js
test/mjsunit/harmony/generators-runtime.js

index c2124e5..8f11769 100644 (file)
@@ -2029,10 +2029,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // [sp + 1 * kPointerSize] iter
       // [sp + 0 * kPointerSize] g
 
-      Label l_catch, l_try, l_resume, l_send, l_call, l_loop;
+      Label l_catch, l_try, l_resume, l_next, l_call, l_loop;
       // Initial send value is undefined.
       __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
-      __ b(&l_send);
+      __ b(&l_next);
 
       // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
       __ bind(&l_catch);
@@ -2063,15 +2063,15 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ bind(&l_resume);                                // received in r0
       __ PopTryHandler();
 
-      // receiver = iter; f = iter.send; arg = received;
-      __ bind(&l_send);
+      // receiver = iter; f = iter.next; arg = received;
+      __ bind(&l_next);
       __ ldr(r3, MemOperand(sp, 1 * kPointerSize));      // iter
       __ push(r3);                                       // iter
       __ push(r0);                                       // received
       __ mov(r0, r3);                                    // iter
-      __ LoadRoot(r2, Heap::ksend_stringRootIndex);      // "send"
-      Handle<Code> send_ic = isolate()->builtins()->LoadIC_Initialize();
-      CallIC(send_ic);                                   // iter.send in r0
+      __ LoadRoot(r2, Heap::knext_stringRootIndex);      // "next"
+      Handle<Code> next_ic = isolate()->builtins()->LoadIC_Initialize();
+      CallIC(next_ic);                                   // iter.next in r0
 
       // result = f.call(receiver, arg);
       __ bind(&l_call);
@@ -2174,7 +2174,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
 
   // If we are sending a value and there is no operand stack, we can jump back
   // in directly.
-  if (resume_mode == JSGeneratorObject::SEND) {
+  if (resume_mode == JSGeneratorObject::NEXT) {
     Label slow_resume;
     __ cmp(r3, Operand(0));
     __ b(ne, &slow_resume);
index fe3c43f..bad634c 100644 (file)
@@ -926,10 +926,10 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
 }
 
 
-void FullCodeGenerator::EmitGeneratorSend(CallRuntime* expr) {
+void FullCodeGenerator::EmitGeneratorNext(CallRuntime* expr) {
   ZoneList<Expression*>* args = expr->arguments();
   ASSERT(args->length() == 2);
-  EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::SEND);
+  EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::NEXT);
 }
 
 
index 5e61091..cc31a44 100644 (file)
 // ----------------------------------------------------------------------------
 
 
-// TODO(wingo): Give link to specification. For now, the following diagram is
-// the spec:
-// http://wiki.ecmascript.org/lib/exe/fetch.php?cache=cache&media=harmony:es6_generator_object_model_3-29-13.png
+// Generator functions and objects are specified by ES6, sections 15.19.3 and
+// 15.19.4.
 
-function GeneratorObjectNext() {
+function GeneratorObjectNext(value) {
   if (!IS_GENERATOR(this)) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['[Generator].prototype.next', this]);
   }
 
-  return %_GeneratorSend(this, void 0);
-}
-
-function GeneratorObjectSend(value) {
-  if (!IS_GENERATOR(this)) {
-    throw MakeTypeError('incompatible_method_receiver',
-                        ['[Generator].prototype.send', this]);
-  }
-
-  return %_GeneratorSend(this, value);
+  return %_GeneratorNext(this, value);
 }
 
 function GeneratorObjectThrow(exn) {
@@ -71,7 +61,6 @@ function SetUpGenerators() {
   InstallFunctions(GeneratorObjectPrototype,
                    DONT_ENUM | DONT_DELETE | READ_ONLY,
                    ["next", GeneratorObjectNext,
-                    "send", GeneratorObjectSend,
                     "throw", GeneratorObjectThrow]);
   %SetProperty(GeneratorObjectPrototype, "constructor",
                GeneratorFunctionPrototype, DONT_ENUM | DONT_DELETE | READ_ONLY);
index 65deb1a..da10efc 100644 (file)
@@ -293,7 +293,6 @@ namespace internal {
   V(hidden_stack_trace_string, "v8::hidden_stack_trace")                 \
   V(query_colon_string, "(?:)")                                          \
   V(Generator_string, "Generator")                                       \
-  V(send_string, "send")                                                 \
   V(throw_string, "throw")                                               \
   V(done_string, "done")                                                 \
   V(value_string, "value")                                               \
index f656fb0..ba2ef50 100644 (file)
@@ -10917,8 +10917,8 @@ void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
 
 
 // Support for generators.
-void HOptimizedGraphBuilder::GenerateGeneratorSend(CallRuntime* call) {
-  return Bailout("inlined runtime function: GeneratorSend");
+void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) {
+  return Bailout("inlined runtime function: GeneratorNext");
 }
 
 
index 82ef657..7aff6e1 100644 (file)
@@ -1988,10 +1988,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // [sp + 1 * kPointerSize] iter
       // [sp + 0 * kPointerSize] g
 
-      Label l_catch, l_try, l_resume, l_send, l_call, l_loop;
+      Label l_catch, l_try, l_resume, l_next, l_call, l_loop;
       // Initial send value is undefined.
       __ mov(eax, isolate()->factory()->undefined_value());
-      __ jmp(&l_send);
+      __ jmp(&l_next);
 
       // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
       __ bind(&l_catch);
@@ -2020,14 +2020,14 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ bind(&l_resume);                                // received in eax
       __ PopTryHandler();
 
-      // receiver = iter; f = iter.send; arg = received;
-      __ bind(&l_send);
+      // receiver = iter; f = iter.next; arg = received;
+      __ bind(&l_next);
       __ mov(edx, Operand(esp, 1 * kPointerSize));       // iter
       __ push(edx);                                      // iter
       __ push(eax);                                      // received
-      __ mov(ecx, isolate()->factory()->send_string());  // "send"
-      Handle<Code> send_ic = isolate()->builtins()->LoadIC_Initialize();
-      CallIC(send_ic);                                   // iter.send in eax
+      __ mov(ecx, isolate()->factory()->next_string());  // "next"
+      Handle<Code> next_ic = isolate()->builtins()->LoadIC_Initialize();
+      CallIC(next_ic);                                   // iter.next in eax
 
       // result = f.call(receiver, arg);
       __ bind(&l_call);
@@ -2129,7 +2129,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
 
   // If we are sending a value and there is no operand stack, we can jump back
   // in directly.
-  if (resume_mode == JSGeneratorObject::SEND) {
+  if (resume_mode == JSGeneratorObject::NEXT) {
     Label slow_resume;
     __ cmp(edx, Immediate(0));
     __ j(not_zero, &slow_resume);
index 3ebe9c0..88feac5 100644 (file)
@@ -6529,7 +6529,7 @@ class JSGeneratorObject: public JSObject {
   static const int kSize = kStackHandlerIndexOffset + kPointerSize;
 
   // Resume mode, for use by runtime functions.
-  enum ResumeMode { SEND, THROW };
+  enum ResumeMode { NEXT, THROW };
 
   // Yielding from a generator returns an object with the following inobject
   // properties.  See Context::generator_result_map() for the map.
index ff55fab..074d8dc 100644 (file)
@@ -2641,9 +2641,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SuspendJSGeneratorObject) {
 // called if the suspended activation had operands on the stack, stack handlers
 // needing rewinding, or if the resume should throw an exception.  The fast path
 // is handled directly in FullCodeGenerator::EmitGeneratorResume(), which is
-// inlined into GeneratorNext, GeneratorSend, and GeneratorThrow.
-// EmitGeneratorResumeResume is called in any case, as it needs to reconstruct
-// the stack frame and make space for arguments and operands.
+// inlined into GeneratorNext and GeneratorThrow.  EmitGeneratorResumeResume is
+// called in any case, as it needs to reconstruct the stack frame and make space
+// for arguments and operands.
 RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) {
   SealHandleScope shs(isolate);
   ASSERT(args.length() == 3);
@@ -2676,7 +2676,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ResumeJSGeneratorObject) {
   JSGeneratorObject::ResumeMode resume_mode =
       static_cast<JSGeneratorObject::ResumeMode>(resume_mode_int);
   switch (resume_mode) {
-    case JSGeneratorObject::SEND:
+    case JSGeneratorObject::NEXT:
       return value;
     case JSGeneratorObject::THROW:
       return isolate->Throw(value);
index 8ef4c81..c52bbe7 100644 (file)
@@ -572,7 +572,7 @@ namespace internal {
   F(HasCachedArrayIndex, 1, 1)                                               \
   F(GetCachedArrayIndex, 1, 1)                                               \
   F(FastAsciiArrayJoin, 2, 1)                                                \
-  F(GeneratorSend, 2, 1)                                                     \
+  F(GeneratorNext, 2, 1)                                                     \
   F(GeneratorThrow, 2, 1)
 
 
index 62c6073..53d7027 100644 (file)
@@ -2012,10 +2012,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       // [sp + 1 * kPointerSize] iter
       // [sp + 0 * kPointerSize] g
 
-      Label l_catch, l_try, l_resume, l_send, l_call, l_loop;
+      Label l_catch, l_try, l_resume, l_next, l_call, l_loop;
       // Initial send value is undefined.
       __ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
-      __ jmp(&l_send);
+      __ jmp(&l_next);
 
       // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; }
       __ bind(&l_catch);
@@ -2045,15 +2045,15 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
       __ bind(&l_resume);                                // received in rax
       __ PopTryHandler();
 
-      // receiver = iter; f = iter.send; arg = received;
-      __ bind(&l_send);
+      // receiver = iter; f = iter.next; arg = received;
+      __ bind(&l_next);
       __ movq(rcx, Operand(rsp, 1 * kPointerSize));      // iter
       __ push(rcx);                                      // iter
       __ push(rax);                                      // received
       __ movq(rax, rcx);                                 // iter
-      __ LoadRoot(rcx, Heap::ksend_stringRootIndex);     // "send"
-      Handle<Code> send_ic = isolate()->builtins()->LoadIC_Initialize();
-      CallIC(send_ic);                                   // iter.send in rax
+      __ LoadRoot(rcx, Heap::knext_stringRootIndex);     // "next"
+      Handle<Code> next_ic = isolate()->builtins()->LoadIC_Initialize();
+      CallIC(next_ic);                                   // iter.next in rax
 
       // result = f.call(receiver, arg);
       __ bind(&l_call);
@@ -2155,7 +2155,7 @@ void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
 
   // If we are sending a value and there is no operand stack, we can jump back
   // in directly.
-  if (resume_mode == JSGeneratorObject::SEND) {
+  if (resume_mode == JSGeneratorObject::NEXT) {
     Label slow_resume;
     __ cmpq(rdx, Immediate(0));
     __ j(not_zero, &slow_resume);
index e717f1b..01facd0 100644 (file)
@@ -64,9 +64,9 @@ function TestGenerator(g, expected_values_for_next,
     for (var i = 0; i < expected_values_for_send.length; i++) {
       assertIteratorResult(expected_values_for_send[i],
                            i == expected_values_for_send.length - 1,
-                           iter.send(send_val));
+                           iter.next(send_val));
     }
-    assertThrows(function() { iter.send(send_val); }, Error);
+    assertThrows(function() { iter.next(send_val); }, Error);
   }
   function testThrow(thunk) {
     for (var i = 0; i < expected_values_for_next.length; i++) {
@@ -572,7 +572,7 @@ function TestRecursion() {
     return iter.next();
   }
   function TestSendRecursion() {
-    function* g() { yield iter.send(42); }
+    function* g() { yield iter.next(42); }
     var iter = g();
     return iter.next();
   }
index b717c30..bb29bed 100644 (file)
@@ -79,7 +79,7 @@ function TestGeneratorObjectMethods() {
 
   function TestNonGenerator(non_generator) {
     assertThrows(function() { iter.next.call(non_generator); }, TypeError);
-    assertThrows(function() { iter.send.call(non_generator, 1); }, TypeError);
+    assertThrows(function() { iter.next.call(non_generator, 1); }, TypeError);
     assertThrows(function() { iter.throw.call(non_generator, 1); }, TypeError);
     assertThrows(function() { iter.close.call(non_generator); }, TypeError);
   }
index b4e8f95..7667deb 100644 (file)
@@ -84,7 +84,7 @@ function TestGeneratorObjectPrototype() {
   assertSame(GeneratorObjectPrototype,
              Object.getPrototypeOf((function*(){yield 1}).prototype));
 
-  var expected_property_names = ["next", "send", "throw", "constructor"];
+  var expected_property_names = ["next", "throw", "constructor"];
   var found_property_names =
       Object.getOwnPropertyNames(GeneratorObjectPrototype);