Commit d73dace0 authored by wingo@igalia.com's avatar wingo@igalia.com

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
parent 608a6b89
......@@ -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<Code> 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<Code> 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<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(value_ic); // result.value in r0
context()->DropAndPlug(2, r0); // drop iter and g
break;
}
......
......@@ -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<Code> 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<Code> 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<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(value_ic); // result.value in eax
context()->DropAndPlug(2, eax); // drop iter and g
break;
}
......
......@@ -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<Code> 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<Code> 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<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
CallIC(value_ic); // result.value in rax
context()->DropAndPlug(2, rax); // drop iter and g
break;
}
......
......@@ -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() {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment