From d73dace0f51f5a0389922ade9562c571377abf8a Mon Sep 17 00:00:00 2001 From: "wingo@igalia.com" Date: Thu, 13 Jun 2013 10:57:11 +0000 Subject: [PATCH] Delegating yield does not re-box result objects Delegating yield (yield*) should just pass on the iterator results it receives instead of re-boxing them. R=rossberg@chromium.org TEST=mjsunit/harmony/generators-iteration BUG= Review URL: https://codereview.chromium.org/16695006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15113 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 20 +++++++++---------- src/ia32/full-codegen-ia32.cc | 20 +++++++++---------- src/x64/full-codegen-x64.cc | 20 +++++++++---------- test/mjsunit/harmony/generators-iteration.js | 30 ++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 33 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 3a2601d..468fa77 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -2044,9 +2044,11 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ push(r0); // exception __ jmp(&l_call); - // try { received = yield result.value } + // try { received = %yield result } + // Shuffle the received result above a try handler and yield it without + // re-boxing. __ bind(&l_try); - EmitCreateIteratorResult(false); // pop and box to r0 + __ pop(r0); // result __ PushTryHandler(StackHandler::CATCH, expr->index()); const int handler_size = StackHandlerConstants::kSize; __ push(r0); // result @@ -2075,16 +2077,9 @@ void FullCodeGenerator::VisitYield(Yield* expr) { CallIC(ic); __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - // val = result.value; if (!result.done) goto l_try; + // if (!result.done) goto l_try; __ bind(&l_loop); - // result.value __ push(r0); // save result - __ LoadRoot(r2, Heap::kvalue_stringRootIndex); // "value" - Handle value_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(value_ic); // result.value in r0 - __ pop(r1); // result - __ push(r0); // result.value - __ mov(r0, r1); // result __ LoadRoot(r2, Heap::kdone_stringRootIndex); // "done" Handle done_ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(done_ic); // result.done in r0 @@ -2094,7 +2089,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ b(eq, &l_try); // result.value - __ pop(r0); // result.value + __ pop(r0); // result + __ LoadRoot(r2, Heap::kvalue_stringRootIndex); // "value" + Handle value_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(value_ic); // result.value in r0 context()->DropAndPlug(2, r0); // drop iter and g break; } diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 2743041..c4c1e87 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -2003,9 +2003,11 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ push(eax); // exception __ jmp(&l_call); - // try { received = yield result.value } + // try { received = %yield result } + // Shuffle the received result above a try handler and yield it without + // re-boxing. __ bind(&l_try); - EmitCreateIteratorResult(false); // pop and box to eax + __ pop(eax); // result __ PushTryHandler(StackHandler::CATCH, expr->index()); const int handler_size = StackHandlerConstants::kSize; __ push(eax); // result @@ -2034,17 +2036,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); __ Drop(1); // The key is still on the stack; drop it. - // val = result.value; if (!result.done) goto l_try; + // if (!result.done) goto l_try; __ bind(&l_loop); - // result.value __ push(eax); // save result __ mov(edx, eax); // result - __ mov(ecx, isolate()->factory()->value_string()); // "value" - Handle value_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(value_ic); // result.value in eax - __ pop(ebx); // result - __ push(eax); // result.value - __ mov(edx, ebx); // result __ mov(ecx, isolate()->factory()->done_string()); // "done" Handle done_ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(done_ic); // result.done in eax @@ -2054,7 +2049,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ j(zero, &l_try); // result.value - __ pop(eax); // result.value + __ pop(edx); // result + __ mov(ecx, isolate()->factory()->value_string()); // "value" + Handle value_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(value_ic); // result.value in eax context()->DropAndPlug(2, eax); // drop iter and g break; } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 36f707f..4afcadb 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -2026,9 +2026,11 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ push(rax); // exception __ jmp(&l_call); - // try { received = yield result.value } + // try { received = %yield result } + // Shuffle the received result above a try handler and yield it without + // re-boxing. __ bind(&l_try); - EmitCreateIteratorResult(false); // pop and box to rax + __ pop(rax); // result __ PushTryHandler(StackHandler::CATCH, expr->index()); const int handler_size = StackHandlerConstants::kSize; __ push(rax); // result @@ -2057,16 +2059,9 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); __ Drop(1); // The key is still on the stack; drop it. - // val = result.value; if (!result.done) goto l_try; + // if (!result.done) goto l_try; __ bind(&l_loop); - // result.value __ push(rax); // save result - __ LoadRoot(rcx, Heap::kvalue_stringRootIndex); // "value" - Handle value_ic = isolate()->builtins()->LoadIC_Initialize(); - CallIC(value_ic); // result.value in rax - __ pop(rbx); // result - __ push(rax); // result.value - __ movq(rax, rbx); // result __ LoadRoot(rcx, Heap::kdone_stringRootIndex); // "done" Handle done_ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(done_ic); // result.done in rax @@ -2076,7 +2071,10 @@ void FullCodeGenerator::VisitYield(Yield* expr) { __ j(zero, &l_try); // result.value - __ pop(rax); // result.value + __ pop(rax); // result + __ LoadRoot(rcx, Heap::kvalue_stringRootIndex); // "value" + Handle value_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(value_ic); // result.value in rax context()->DropAndPlug(2, rax); // drop iter and g break; } diff --git a/test/mjsunit/harmony/generators-iteration.js b/test/mjsunit/harmony/generators-iteration.js index 2ca35f2..dc210d5 100644 --- a/test/mjsunit/harmony/generators-iteration.js +++ b/test/mjsunit/harmony/generators-iteration.js @@ -346,6 +346,36 @@ TestGenerator( "foo", [3, undefined]); +// Test that yield* re-yields received results without re-boxing. +function TestDelegatingYield() { + function results(results) { + var i = 0; + function next() { + return results[i++]; + } + return { next: next } + } + function* yield_results(expected) { + return yield* results(expected); + } + function collect_results(iter) { + var ret = []; + var result; + do { + result = iter.next(); + ret.push(result); + } while (!result.done); + return ret; + } + // We have to put a full result for the end, because the return will re-box. + var expected = [{value: 1}, 13, "foo", {value: 34, done: true}]; + + // Sanity check. + assertEquals(expected, collect_results(results(expected))); + assertEquals(expected, collect_results(yield_results(expected))); +} +TestDelegatingYield(); + function TestTryCatch(instantiate) { function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; } function Sentinel() {} -- 2.7.4