Revision: 14669
Author:   [email protected]
Date:     Tue May 14 09:26:56 2013
Log:      Implement yield* (delegating yield)

Ideally this would have been implemented via desugaring at parse-time,
but yield* is an expression, and its desugaring includes statements like
while and try/catch.  We'd have to have BlockExpression in the AST to
support that, and it's not worth it for this feature.

So instead we implement all of the logic in
FullCodeGenerator::VisitYield.  Delegating yield AST nodes now have a
try handler index, for the try/catch.  Otherwise the implementation is
straightforward.

[email protected]
BUG=v8:2355
TEST=mjsunit/harmony/generators-iteration

Review URL: https://codereview.chromium.org/14582007
http://code.google.com/p/v8/source/detail?r=14669

Modified:
 /branches/bleeding_edge/src/arm/full-codegen-arm.cc
 /branches/bleeding_edge/src/ast.h
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/x64/full-codegen-x64.cc
 /branches/bleeding_edge/test/mjsunit/harmony/generators-iteration.js

=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue May 14 09:17:26 2013 +++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Tue May 14 09:26:56 2013
@@ -1961,8 +1961,102 @@
       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<Code> 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<Code> 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<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
+ __ push(r0); // push LoadIC state
+      __ LoadRoot(r2, Heap::kdone_stringRootIndex);      // "done"
+      Handle<Code> 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;
+    }
   }
 }

=======================================
--- /branches/bleeding_edge/src/ast.h   Tue May 14 09:17:26 2013
+++ /branches/bleeding_edge/src/ast.h   Tue May 14 09:26:56 2013
@@ -1991,6 +1991,18 @@
   Expression* expression() const { return 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,
@@ -2002,12 +2014,14 @@
         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_;
 };

=======================================
--- /branches/bleeding_edge/src/heap.h  Tue May 14 09:17:26 2013
+++ /branches/bleeding_edge/src/heap.h  Tue May 14 09:26:56 2013
@@ -273,7 +273,11 @@
   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;
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue May 14 09:17:26 2013 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue May 14 09:26:56 2013
@@ -1922,8 +1922,95 @@
       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<Code> 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<Code> 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<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
+      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;
+    }
   }
 }

=======================================
--- /branches/bleeding_edge/src/parser.cc       Tue May 14 09:17:26 2013
+++ /branches/bleeding_edge/src/parser.cc       Tue May 14 09:26:56 2013
@@ -3113,7 +3113,12 @@
   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;
 }


=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue May 14 09:17:26 2013 +++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Tue May 14 09:26:56 2013
@@ -1946,8 +1946,96 @@
       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<Code> 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<Code> 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<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
+      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;
+    }
   }
 }

=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/generators-iteration.js Tue May 14 09:17:26 2013 +++ /branches/bleeding_edge/test/mjsunit/harmony/generators-iteration.js Tue May 14 09:26:56 2013
@@ -86,6 +86,10 @@
   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 @@
     "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));
+
+  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));
+
+  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());
-  assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
-  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));

-  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 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);

-  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);
+  }
+  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 Sentinel() {}
   function Sentinel2() {}
-  var iter;
+
+  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));
+
+  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(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 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();
-  assertThrows(function() { iter.throw(new Sentinel); }, Sentinel);
-  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(4, false, iter.throw(new Sentinel));
-  assertThrows(function() { iter.next(); }, 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());
+    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(4, 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());
-  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 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));

-  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);
+  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);

-  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);
+  }
+  Test7(instantiate(g));

   // That's probably enough.
 }
-TestNestedTry();
+TestNestedTry(function (g) { return g(); });
+TestNestedTry(function* (g) { return yield* g(); });

 function TestRecursion() {
   function TestNextRecursion() {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to