diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 0bc1f48c87..da2d3fd62c 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1961,8 +1961,102 @@ void FullCodeGenerator::VisitYield(Yield* expr) { break; } - case Yield::DELEGATING: - UNIMPLEMENTED(); + case Yield::DELEGATING: { + VisitForStackValue(expr->generator_object()); + + // Initial stack layout is as follows: + // [sp + 1 * kPointerSize] iter + // [sp + 0 * kPointerSize] g + + Label l_catch, l_try, l_resume, l_send, l_call, l_loop; + // Initial send value is undefined. + __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); + __ b(&l_send); + + // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; } + __ bind(&l_catch); + handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); + __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter + __ push(r3); // iter + __ push(r0); // exception + __ mov(r0, r3); // iter + __ push(r0); // push LoadIC state + __ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw" + Handle throw_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(throw_ic); // iter.throw in r0 + __ add(sp, sp, Operand(kPointerSize)); // drop LoadIC state + __ jmp(&l_call); + + // try { received = yield result.value } + __ bind(&l_try); + __ pop(r0); // result.value + __ PushTryHandler(StackHandler::CATCH, expr->index()); + const int handler_size = StackHandlerConstants::kSize; + __ push(r0); // result.value + __ ldr(r3, MemOperand(sp, (0 + 1) * kPointerSize + handler_size)); // g + __ push(r3); // g + __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); + __ ldr(context_register(), + MemOperand(fp, StandardFrameConstants::kContextOffset)); + __ CompareRoot(r0, Heap::kTheHoleValueRootIndex); + __ b(ne, &l_resume); + EmitReturnIteratorResult(false); + __ bind(&l_resume); // received in r0 + __ PopTryHandler(); + + // receiver = iter; f = iter.send; arg = received; + __ bind(&l_send); + __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter + __ push(r3); // iter + __ push(r0); // received + __ mov(r0, r3); // iter + __ push(r0); // push LoadIC state + __ LoadRoot(r2, Heap::ksend_stringRootIndex); // "send" + Handle send_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(send_ic); // iter.send in r0 + __ add(sp, sp, Operand(kPointerSize)); // drop LoadIC state + + // result = f.call(receiver, arg); + __ bind(&l_call); + Label l_call_runtime; + __ JumpIfSmi(r0, &l_call_runtime); + __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); + __ b(ne, &l_call_runtime); + __ mov(r1, r0); + ParameterCount count(1); + __ InvokeFunction(r1, count, CALL_FUNCTION, + NullCallWrapper(), CALL_AS_METHOD); + __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); + __ jmp(&l_loop); + __ bind(&l_call_runtime); + __ push(r0); + __ CallRuntime(Runtime::kCall, 3); + + // val = result.value; 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 + __ push(r0); // push LoadIC state + __ LoadRoot(r2, Heap::kdone_stringRootIndex); // "done" + Handle done_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(done_ic); // result.done in r0 + __ add(sp, sp, Operand(kPointerSize)); // drop LoadIC state + ToBooleanStub stub(r0); + __ CallStub(&stub); + __ cmp(r0, Operand(0)); + __ b(eq, &l_try); + + // result.value + __ pop(r0); // result.value + context()->DropAndPlug(2, r0); // drop iter and g + break; + } } } diff --git a/src/ast.h b/src/ast.h index 9ffb00db0d..a32540c5a4 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1992,6 +1992,18 @@ class Yield: public Expression { Kind yield_kind() const { return yield_kind_; } virtual int position() const { return pos_; } + // Delegating yield surrounds the "yield" in a "try/catch". This index + // locates the catch handler in the handler table, and is equivalent to + // TryCatchStatement::index(). + int index() const { + ASSERT(yield_kind() == DELEGATING); + return index_; + } + void set_index(int index) { + ASSERT(yield_kind() == DELEGATING); + index_ = index; + } + protected: Yield(Isolate* isolate, Expression* generator_object, @@ -2002,12 +2014,14 @@ class Yield: public Expression { generator_object_(generator_object), expression_(expression), yield_kind_(yield_kind), + index_(-1), pos_(pos) { } private: Expression* generator_object_; Expression* expression_; Kind yield_kind_; + int index_; int pos_; }; diff --git a/src/heap.h b/src/heap.h index add42c01d6..3af0999f2f 100644 --- a/src/heap.h +++ b/src/heap.h @@ -273,7 +273,11 @@ namespace internal { V(minus_infinity_string, "-Infinity") \ V(hidden_stack_trace_string, "v8::hidden_stack_trace") \ V(query_colon_string, "(?:)") \ - V(Generator_string, "Generator") + V(Generator_string, "Generator") \ + V(send_string, "send") \ + V(throw_string, "throw") \ + V(done_string, "done") \ + V(value_string, "value") // Forward declarations. class GCTracer; diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index 5a780197c3..e5a999ef4b 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1922,8 +1922,95 @@ void FullCodeGenerator::VisitYield(Yield* expr) { break; } - case Yield::DELEGATING: - UNIMPLEMENTED(); + case Yield::DELEGATING: { + VisitForStackValue(expr->generator_object()); + + // Initial stack layout is as follows: + // [sp + 1 * kPointerSize] iter + // [sp + 0 * kPointerSize] g + + Label l_catch, l_try, l_resume, l_send, l_call, l_loop; + // Initial send value is undefined. + __ mov(eax, isolate()->factory()->undefined_value()); + __ jmp(&l_send); + + // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; } + __ bind(&l_catch); + handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); + __ mov(edx, Operand(esp, 1 * kPointerSize)); // iter + __ push(edx); // iter + __ push(eax); // exception + __ mov(ecx, isolate()->factory()->throw_string()); // "throw" + Handle throw_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(throw_ic); // iter.throw in eax + __ jmp(&l_call); + + // try { received = yield result.value } + __ bind(&l_try); + __ pop(eax); // result.value + __ PushTryHandler(StackHandler::CATCH, expr->index()); + const int handler_size = StackHandlerConstants::kSize; + __ push(eax); // result.value + __ push(Operand(esp, (0 + 1) * kPointerSize + handler_size)); // g + __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); + __ mov(context_register(), + Operand(ebp, StandardFrameConstants::kContextOffset)); + __ CompareRoot(eax, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &l_resume); + EmitReturnIteratorResult(false); + __ bind(&l_resume); // received in eax + __ PopTryHandler(); + + // receiver = iter; f = iter.send; arg = received; + __ bind(&l_send); + __ 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 + + // result = f.call(receiver, arg); + __ bind(&l_call); + Label l_call_runtime; + __ JumpIfSmi(eax, &l_call_runtime); + __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); + __ j(not_equal, &l_call_runtime); + __ mov(edi, eax); + ParameterCount count(1); + __ InvokeFunction(edi, count, CALL_FUNCTION, + NullCallWrapper(), CALL_AS_METHOD); + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); + __ jmp(&l_loop); + __ bind(&l_call_runtime); + __ push(eax); + __ CallRuntime(Runtime::kCall, 3); + + // val = result.value; 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 + ToBooleanStub stub(eax); + __ push(eax); + __ CallStub(&stub); + __ test(eax, eax); + __ j(zero, &l_try); + + // result.value + __ pop(eax); // result.value + context()->DropAndPlug(2, eax); // drop iter and g + break; + } } } diff --git a/src/parser.cc b/src/parser.cc index cff51bc9c3..86a486fcf9 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -3113,7 +3113,12 @@ Expression* Parser::ParseYieldExpression(bool* ok) { Expression* generator_object = factory()->NewVariableProxy( current_function_state_->generator_object_variable()); Expression* expression = ParseAssignmentExpression(false, CHECK_OK); - return factory()->NewYield(generator_object, expression, kind, position); + Yield* yield = + factory()->NewYield(generator_object, expression, kind, position); + if (kind == Yield::DELEGATING) { + yield->set_index(current_function_state_->NextHandlerIndex()); + } + return yield; } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 19fa0aaddd..a296c07b38 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1946,8 +1946,96 @@ void FullCodeGenerator::VisitYield(Yield* expr) { break; } - case Yield::DELEGATING: - UNIMPLEMENTED(); + case Yield::DELEGATING: { + VisitForStackValue(expr->generator_object()); + + // Initial stack layout is as follows: + // [sp + 1 * kPointerSize] iter + // [sp + 0 * kPointerSize] g + + Label l_catch, l_try, l_resume, l_send, l_call, l_loop; + // Initial send value is undefined. + __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); + __ jmp(&l_send); + + // catch (e) { receiver = iter; f = iter.throw; arg = e; goto l_call; } + __ bind(&l_catch); + handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); + __ movq(rcx, Operand(rsp, 1 * kPointerSize)); // iter + __ push(rcx); // iter + __ push(rax); // exception + __ movq(rax, rcx); // iter + __ LoadRoot(rcx, Heap::kthrow_stringRootIndex); // "throw" + Handle throw_ic = isolate()->builtins()->LoadIC_Initialize(); + CallIC(throw_ic); // iter.throw in rax + __ jmp(&l_call); + + // try { received = yield result.value } + __ bind(&l_try); + __ pop(rax); // result.value + __ PushTryHandler(StackHandler::CATCH, expr->index()); + const int handler_size = StackHandlerConstants::kSize; + __ push(rax); // result.value + __ push(Operand(rsp, (0 + 1) * kPointerSize + handler_size)); // g + __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); + __ movq(context_register(), + Operand(rbp, StandardFrameConstants::kContextOffset)); + __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); + __ j(not_equal, &l_resume); + EmitReturnIteratorResult(false); + __ bind(&l_resume); // received in rax + __ PopTryHandler(); + + // receiver = iter; f = iter.send; arg = received; + __ bind(&l_send); + __ 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 + + // result = f.call(receiver, arg); + __ bind(&l_call); + Label l_call_runtime; + __ JumpIfSmi(rax, &l_call_runtime); + __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); + __ j(not_equal, &l_call_runtime); + __ movq(rdi, rax); + ParameterCount count(1); + __ InvokeFunction(rdi, count, CALL_FUNCTION, + NullCallWrapper(), CALL_AS_METHOD); + __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); + __ jmp(&l_loop); + __ bind(&l_call_runtime); + __ push(rax); + __ CallRuntime(Runtime::kCall, 3); + + // val = result.value; 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 + ToBooleanStub stub(rax); + __ push(rax); + __ CallStub(&stub); + __ testq(rax, rax); + __ j(zero, &l_try); + + // result.value + __ pop(rax); // result.value + 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 d120ac7b3b..e717f1b4a3 100644 --- a/test/mjsunit/harmony/generators-iteration.js +++ b/test/mjsunit/harmony/generators-iteration.js @@ -86,6 +86,10 @@ function TestGenerator(g, expected_values_for_next, testSend(g); testThrow(g); + testNext(function*() { return yield* g(); }); + testSend(function*() { return yield* g(); }); + testThrow(function*() { return yield* g(); }); + if (g instanceof GeneratorFunction) { testNext(function() { return new g(); }); testSend(function() { return new g(); }); @@ -320,125 +324,158 @@ TestGenerator( "foo", [2, "1foo3", 5, "4foo6", "foofoo"]); -function TestTryCatch() { +function TestTryCatch(instantiate) { function* g() { yield 1; try { yield 2; } catch (e) { yield e; } yield 3; } function Sentinel() {} - var iter; - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); - assertThrows(function() { iter.next(); }, Error); + function Test1(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(undefined, true, iter.next()); + assertThrows(function() { iter.next(); }, Error); + } + Test1(instantiate(g)); - iter = g(); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test2(iter) { + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test2(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test3(iter) { + assertIteratorResult(1, false, iter.next()); + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test3(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - var exn = new Sentinel; - assertIteratorResult(exn, false, iter.throw(exn)); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); - assertThrows(function() { iter.next(); }, Error); + function Test4(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + var exn = new Sentinel; + assertIteratorResult(exn, false, iter.throw(exn)); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(undefined, true, iter.next()); + assertThrows(function() { iter.next(); }, Error); + } + Test4(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - var exn = new Sentinel; - assertIteratorResult(exn, false, iter.throw(exn)); - assertIteratorResult(3, false, iter.next()); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test5(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + var exn = new Sentinel; + assertIteratorResult(exn, false, iter.throw(exn)); + assertIteratorResult(3, false, iter.next()); + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - var exn = new Sentinel; - assertIteratorResult(exn, false, iter.throw(exn)); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + } + Test5(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); - assertThrows(function() { iter.next(); }, Error); + function Test6(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + var exn = new Sentinel; + assertIteratorResult(exn, false, iter.throw(exn)); + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test6(instantiate(g)); + + function Test7(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(undefined, true, iter.next()); + assertThrows(function() { iter.next(); }, Error); + } + Test7(instantiate(g)); } -TestTryCatch(); +TestTryCatch(function (g) { return g(); }); +TestTryCatch(function* (g) { return yield* g(); }); -function TestTryFinally() { +function TestTryFinally(instantiate) { function* g() { yield 1; try { yield 2; } finally { yield 3; } yield 4; } function Sentinel() {} function Sentinel2() {} - var iter; - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(4, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); - assertThrows(function() { iter.next(); }, Error); + function Test1(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(4, false, iter.next()); + assertIteratorResult(undefined, true, iter.next()); + assertThrows(function() { iter.next(); }, Error); + } + Test1(instantiate(g)); - iter = g(); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test2(iter) { + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test2(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test3(iter) { + assertIteratorResult(1, false, iter.next()); + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test3(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.throw(new Sentinel)); - assertThrows(function() { iter.next(); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test4(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.throw(new Sentinel)); + assertThrows(function() { iter.next(); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.throw(new Sentinel)); - assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2); - assertThrows(function() { iter.next(); }, Error); + } + Test4(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.next()); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test5(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.throw(new Sentinel)); + assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2); + assertThrows(function() { iter.next(); }, Error); + } + Test5(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(4, false, iter.next()); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test6(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.next()); + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test6(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(4, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); - assertThrows(function() { iter.next(); }, Error); + function Test7(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(4, false, iter.next()); + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test7(instantiate(g)); + + function Test8(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(4, false, iter.next()); + assertIteratorResult(undefined, true, iter.next()); + assertThrows(function() { iter.next(); }, Error); + + } + Test8(instantiate(g)); } -TestTryFinally(); +TestTryFinally(function (g) { return g(); }); +TestTryFinally(function* (g) { return yield* g(); }); -function TestNestedTry() { +function TestNestedTry(instantiate) { function* g() { try { yield 1; @@ -451,66 +488,82 @@ function TestNestedTry() { } function Sentinel() {} function Sentinel2() {} - var iter; - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(4, false, iter.next()); - assertIteratorResult(5, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); - assertThrows(function() { iter.next(); }, Error); + function Test1(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(4, false, iter.next()); + assertIteratorResult(5, false, iter.next()); + assertIteratorResult(undefined, true, iter.next()); + assertThrows(function() { iter.next(); }, Error); + } + Test1(instantiate(g)); - iter = g(); - assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test2(iter) { + assertThrows(function() { iter.throw(new Sentinel); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test2(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(4, false, iter.throw(new Sentinel)); - assertThrows(function() { iter.next(); }, Sentinel); - assertThrows(function() { iter.next(); }, Error); + function Test3(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(4, false, iter.throw(new Sentinel)); + assertThrows(function() { iter.next(); }, Sentinel); + assertThrows(function() { iter.next(); }, Error); + } + Test3(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(4, false, iter.throw(new Sentinel)); - assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2); - assertThrows(function() { iter.next(); }, Error); + function Test4(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(4, false, iter.throw(new Sentinel)); + assertThrows(function() { iter.throw(new Sentinel2); }, Sentinel2); + assertThrows(function() { iter.next(); }, Error); + } + Test4(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - var exn = new Sentinel; - assertIteratorResult(exn, false, iter.throw(exn)); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(4, false, iter.next()); - assertIteratorResult(5, false, iter.next()); - assertIteratorResult(undefined, true, iter.next()); - assertThrows(function() { iter.next(); }, Error); + function Test5(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + var exn = new Sentinel; + assertIteratorResult(exn, false, iter.throw(exn)); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(4, false, iter.next()); + assertIteratorResult(5, false, iter.next()); + assertIteratorResult(undefined, true, iter.next()); + assertThrows(function() { iter.next(); }, Error); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - var exn = new Sentinel; - assertIteratorResult(exn, false, iter.throw(exn)); - assertIteratorResult(4, false, iter.throw(new Sentinel2)); - assertThrows(function() { iter.next(); }, Sentinel2); - assertThrows(function() { iter.next(); }, Error); + } + Test5(instantiate(g)); - iter = g(); - assertIteratorResult(1, false, iter.next()); - assertIteratorResult(2, false, iter.next()); - var exn = new Sentinel; - assertIteratorResult(exn, false, iter.throw(exn)); - assertIteratorResult(3, false, iter.next()); - assertIteratorResult(4, false, iter.throw(new Sentinel2)); - assertThrows(function() { iter.next(); }, Sentinel2); - assertThrows(function() { iter.next(); }, Error); + function Test6(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + var exn = new Sentinel; + assertIteratorResult(exn, false, iter.throw(exn)); + assertIteratorResult(4, false, iter.throw(new Sentinel2)); + assertThrows(function() { iter.next(); }, Sentinel2); + assertThrows(function() { iter.next(); }, Error); + } + Test6(instantiate(g)); + + function Test7(iter) { + assertIteratorResult(1, false, iter.next()); + assertIteratorResult(2, false, iter.next()); + var exn = new Sentinel; + assertIteratorResult(exn, false, iter.throw(exn)); + assertIteratorResult(3, false, iter.next()); + assertIteratorResult(4, false, iter.throw(new Sentinel2)); + assertThrows(function() { iter.next(); }, Sentinel2); + assertThrows(function() { iter.next(); }, Error); + + } + Test7(instantiate(g)); // That's probably enough. } -TestNestedTry(); +TestNestedTry(function (g) { return g(); }); +TestNestedTry(function* (g) { return yield* g(); }); function TestRecursion() { function TestNextRecursion() {