From f88bca95766ae004051e44be5bc269e4b630dafc Mon Sep 17 00:00:00 2001 From: "wingo@igalia.com" Date: Mon, 10 Jun 2013 09:26:18 +0000 Subject: [PATCH] Generator object "next" method takes optional send value 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 --- src/arm/full-codegen-arm.cc | 16 ++++++++-------- src/full-codegen.cc | 4 ++-- src/generator.js | 19 ++++--------------- src/heap.h | 1 - src/hydrogen.cc | 4 ++-- src/ia32/full-codegen-ia32.cc | 16 ++++++++-------- src/objects.h | 2 +- src/runtime.cc | 8 ++++---- src/runtime.h | 2 +- src/x64/full-codegen-x64.cc | 16 ++++++++-------- test/mjsunit/harmony/generators-iteration.js | 6 +++--- test/mjsunit/harmony/generators-objects.js | 2 +- test/mjsunit/harmony/generators-runtime.js | 2 +- 13 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index c2124e5..8f11769 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -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 send_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(send_ic); // iter.send in r0 + __ LoadRoot(r2, Heap::knext_stringRootIndex); // "next" + Handle 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); diff --git a/src/full-codegen.cc b/src/full-codegen.cc index fe3c43f..bad634c 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -926,10 +926,10 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) { } -void FullCodeGenerator::EmitGeneratorSend(CallRuntime* expr) { +void FullCodeGenerator::EmitGeneratorNext(CallRuntime* expr) { ZoneList* 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); } diff --git a/src/generator.js b/src/generator.js index 5e61091..cc31a44 100644 --- a/src/generator.js +++ b/src/generator.js @@ -34,26 +34,16 @@ // ---------------------------------------------------------------------------- -// 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); diff --git a/src/heap.h b/src/heap.h index 65deb1a..da10efc 100644 --- a/src/heap.h +++ b/src/heap.h @@ -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") \ diff --git a/src/hydrogen.cc b/src/hydrogen.cc index f656fb0..ba2ef50 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -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"); } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 82ef657..7aff6e1 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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 send_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(send_ic); // iter.send in eax + __ mov(ecx, isolate()->factory()->next_string()); // "next" + Handle 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); diff --git a/src/objects.h b/src/objects.h index 3ebe9c0..88feac5 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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. diff --git a/src/runtime.cc b/src/runtime.cc index ff55fab..074d8dc 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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(resume_mode_int); switch (resume_mode) { - case JSGeneratorObject::SEND: + case JSGeneratorObject::NEXT: return value; case JSGeneratorObject::THROW: return isolate->Throw(value); diff --git a/src/runtime.h b/src/runtime.h index 8ef4c81..c52bbe7 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -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) diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 62c6073..53d7027 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -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 send_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(send_ic); // iter.send in rax + __ LoadRoot(rcx, Heap::knext_stringRootIndex); // "next" + Handle 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); diff --git a/test/mjsunit/harmony/generators-iteration.js b/test/mjsunit/harmony/generators-iteration.js index e717f1b..01facd0 100644 --- a/test/mjsunit/harmony/generators-iteration.js +++ b/test/mjsunit/harmony/generators-iteration.js @@ -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(); } diff --git a/test/mjsunit/harmony/generators-objects.js b/test/mjsunit/harmony/generators-objects.js index b717c30..bb29bed 100644 --- a/test/mjsunit/harmony/generators-objects.js +++ b/test/mjsunit/harmony/generators-objects.js @@ -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); } diff --git a/test/mjsunit/harmony/generators-runtime.js b/test/mjsunit/harmony/generators-runtime.js index b4e8f95..7667deb 100644 --- a/test/mjsunit/harmony/generators-runtime.js +++ b/test/mjsunit/harmony/generators-runtime.js @@ -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); -- 2.7.4