Generator objects have [[Class]] === "Generator"
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Apr 2013 15:01:25 +0000 (15:01 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Apr 2013 15:01:25 +0000 (15:01 +0000)
Generator object maps now link to their constructors, which are created
with a "Generator" class name.  This does not cause a per-generator
constructor property to be set.

BUG=v8:2355
TEST=mjsunit/harmony/generators-objects

Review URL: https://codereview.chromium.org/14262004

Patch from Andy Wingo <wingo@igalia.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14309 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler.cc
src/factory.cc
src/factory.h
src/generator.js
src/heap.cc
src/heap.h
src/macros.py
src/parser.cc
test/mjsunit/harmony/generators-objects.js

index 184429b..270c795 100644 (file)
@@ -553,6 +553,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
       isolate->factory()->NewSharedFunctionInfo(
           lit->name(),
           lit->materialized_literal_count(),
+          lit->is_generator(),
           info->code(),
           ScopeInfo::Create(info->scope(), info->zone()));
 
@@ -1074,6 +1075,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
   Handle<SharedFunctionInfo> result =
       FACTORY->NewSharedFunctionInfo(literal->name(),
                                      literal->materialized_literal_count(),
+                                     literal->is_generator(),
                                      info.code(),
                                      scope_info);
   SetFunctionInfo(result, literal, false, script);
index 5e2a2b1..01b885c 100644 (file)
@@ -1078,6 +1078,7 @@ void Factory::SetIdentityHash(Handle<JSObject> object, Smi* hash) {
 Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
     Handle<String> name,
     int number_of_literals,
+    bool is_generator,
     Handle<Code> code,
     Handle<ScopeInfo> scope_info) {
   Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(name);
@@ -1091,6 +1092,9 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
     literals_array_size += JSFunction::kLiteralsPrefixSize;
   }
   shared->set_num_literals(literals_array_size);
+  if (is_generator) {
+    shared->set_instance_class_name(isolate()->heap()->Generator_string());
+  }
   return shared;
 }
 
index 8695bcd..afe5847 100644 (file)
@@ -454,6 +454,7 @@ class Factory {
   Handle<SharedFunctionInfo> NewSharedFunctionInfo(
       Handle<String> name,
       int number_of_literals,
+      bool is_generator,
       Handle<Code> code,
       Handle<ScopeInfo> scope_info);
   Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
index d579928..481d4d3 100644 (file)
 // http://wiki.ecmascript.org/lib/exe/fetch.php?cache=cache&media=harmony:es6_generator_object_model_3-29-13.png
 
 function GeneratorObjectNext() {
+  if (!IS_GENERATOR(this)) {
+    throw MakeTypeError('incompatible_method_receiver',
+                        ['[Generator].prototype.next', this]);
+  }
+
   // TODO(wingo): Implement.
 }
 
 function GeneratorObjectSend(value) {
+  if (!IS_GENERATOR(this)) {
+    throw MakeTypeError('incompatible_method_receiver',
+                        ['[Generator].prototype.send', this]);
+  }
+
   // TODO(wingo): Implement.
 }
 
 function GeneratorObjectThrow(exn) {
+  if (!IS_GENERATOR(this)) {
+    throw MakeTypeError('incompatible_method_receiver',
+                        ['[Generator].prototype.throw', this]);
+  }
+
   // TODO(wingo): Implement.
 }
 
 function GeneratorObjectClose() {
+  if (!IS_GENERATOR(this)) {
+    throw MakeTypeError('incompatible_method_receiver',
+                        ['[Generator].prototype.close', this]);
+  }
+
   // TODO(wingo): Implement.
 }
 
index 453d985..c7a8b00 100644 (file)
@@ -4358,6 +4358,7 @@ MaybeObject* Heap::AllocateJSGeneratorObject(JSFunction *function) {
     MaybeObject* maybe_map = AllocateInitialMap(function);
     if (!maybe_map->To(&map)) return maybe_map;
     function->set_initial_map(map);
+    map->set_constructor(function);
   }
   ASSERT(map->instance_type() == JS_GENERATOR_OBJECT_TYPE);
   return AllocateJSObjectFromMap(map);
index 7b4b70d..9dfbe1e 100644 (file)
@@ -268,7 +268,8 @@ namespace internal {
   V(infinity_string, "Infinity")                                         \
   V(minus_infinity_string, "-Infinity")                                  \
   V(hidden_stack_trace_string, "v8::hidden_stack_trace")                 \
-  V(query_colon_string, "(?:)")
+  V(query_colon_string, "(?:)")                                          \
+  V(Generator_string, "Generator")
 
 // Forward declarations.
 class GCTracer;
index 92ed437..0c52f38 100644 (file)
@@ -117,6 +117,7 @@ macro IS_SCRIPT(arg)            = (%_ClassOf(arg) === 'Script');
 macro IS_ARGUMENTS(arg)         = (%_ClassOf(arg) === 'Arguments');
 macro IS_GLOBAL(arg)            = (%_ClassOf(arg) === 'global');
 macro IS_ARRAYBUFFER(arg)       = (%_ClassOf(arg) === '__ArrayBuffer');
+macro IS_GENERATOR(arg)         = (%_ClassOf(arg) === 'Generator');
 macro IS_UNDETECTABLE(arg)      = (%_IsUndetectableObject(arg));
 macro FLOOR(arg)                = $floor(arg);
 
index 06dcced..b63911b 100644 (file)
@@ -1872,9 +1872,10 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
   const int literals = fun->NumberOfLiterals();
   Handle<Code> code = Handle<Code>(fun->shared()->code());
   Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
+  bool is_generator = false;
   Handle<SharedFunctionInfo> shared =
-      isolate()->factory()->NewSharedFunctionInfo(name, literals, code,
-          Handle<ScopeInfo>(fun->shared()->scope_info()));
+      isolate()->factory()->NewSharedFunctionInfo(name, literals, is_generator,
+          code, Handle<ScopeInfo>(fun->shared()->scope_info()));
   shared->set_construct_stub(*construct_stub);
 
   // Copy the function data to the shared function info.
index 0c36818..b717c30 100644 (file)
@@ -25,7 +25,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --harmony-generators --harmony-scoping
+// Flags: --harmony-generators --harmony-scoping --allow-natives-syntax
 
 // Test instantations of generators.
 
@@ -55,6 +55,8 @@ function TestGeneratorObject() {
   var iter = g();
   assertSame(g.prototype, Object.getPrototypeOf(iter));
   assertTrue(iter instanceof g);
+  assertEquals("Generator", %ClassOf(iter));
+  assertEquals("[object Generator]", String(iter));
   assertEquals([], Object.getOwnPropertyNames(iter));
   assertTrue(iter !== g());
 
@@ -62,7 +64,30 @@ function TestGeneratorObject() {
   iter = new g();
   assertSame(g.prototype, Object.getPrototypeOf(iter));
   assertTrue(iter instanceof g);
+  assertEquals("Generator", %ClassOf(iter));
+  assertEquals("[object Generator]", String(iter));
   assertEquals([], Object.getOwnPropertyNames(iter));
   assertTrue(iter !== new g());
 }
 TestGeneratorObject();
+
+
+// Test the methods of generator objects.
+function TestGeneratorObjectMethods() {
+  function* g() { yield 1; }
+  var iter = g();
+
+  function TestNonGenerator(non_generator) {
+    assertThrows(function() { iter.next.call(non_generator); }, TypeError);
+    assertThrows(function() { iter.send.call(non_generator, 1); }, TypeError);
+    assertThrows(function() { iter.throw.call(non_generator, 1); }, TypeError);
+    assertThrows(function() { iter.close.call(non_generator); }, TypeError);
+  }
+
+  TestNonGenerator(1);
+  TestNonGenerator({});
+  TestNonGenerator(function(){});
+  TestNonGenerator(g);
+  TestNonGenerator(g.prototype);
+}
+TestGeneratorObjectMethods();