From 57a7714e064c4ee4715854dc9013a5deaaa5dcca Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Wed, 17 Apr 2013 15:01:25 +0000 Subject: [PATCH] Generator objects have [[Class]] === "Generator" 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 . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14309 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/compiler.cc | 2 ++ src/factory.cc | 4 ++++ src/factory.h | 1 + src/generator.js | 20 ++++++++++++++++ src/heap.cc | 1 + src/heap.h | 3 ++- src/macros.py | 1 + src/parser.cc | 5 ++-- test/mjsunit/harmony/generators-objects.js | 27 +++++++++++++++++++++- 9 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/compiler.cc b/src/compiler.cc index 184429b417..270c7957b9 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -553,6 +553,7 @@ static Handle 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 Compiler::BuildFunctionInfo(FunctionLiteral* literal, Handle result = FACTORY->NewSharedFunctionInfo(literal->name(), literal->materialized_literal_count(), + literal->is_generator(), info.code(), scope_info); SetFunctionInfo(result, literal, false, script); diff --git a/src/factory.cc b/src/factory.cc index 5e2a2b1874..01b885cafd 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1078,6 +1078,7 @@ void Factory::SetIdentityHash(Handle object, Smi* hash) { Handle Factory::NewSharedFunctionInfo( Handle name, int number_of_literals, + bool is_generator, Handle code, Handle scope_info) { Handle shared = NewSharedFunctionInfo(name); @@ -1091,6 +1092,9 @@ Handle 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; } diff --git a/src/factory.h b/src/factory.h index 8695bcd520..afe58477a9 100644 --- a/src/factory.h +++ b/src/factory.h @@ -454,6 +454,7 @@ class Factory { Handle NewSharedFunctionInfo( Handle name, int number_of_literals, + bool is_generator, Handle code, Handle scope_info); Handle NewSharedFunctionInfo(Handle name); diff --git a/src/generator.js b/src/generator.js index d579928cba..481d4d37f8 100644 --- a/src/generator.js +++ b/src/generator.js @@ -39,18 +39,38 @@ // 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. } diff --git a/src/heap.cc b/src/heap.cc index 453d985647..c7a8b002c9 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -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); diff --git a/src/heap.h b/src/heap.h index 7b4b70d61c..9dfbe1e89b 100644 --- a/src/heap.h +++ b/src/heap.h @@ -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; diff --git a/src/macros.py b/src/macros.py index 92ed437b0f..0c52f3822e 100644 --- a/src/macros.py +++ b/src/macros.py @@ -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); diff --git a/src/parser.cc b/src/parser.cc index 06dcced8ff..b63911bc97 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1872,9 +1872,10 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) { const int literals = fun->NumberOfLiterals(); Handle code = Handle(fun->shared()->code()); Handle construct_stub = Handle(fun->shared()->construct_stub()); + bool is_generator = false; Handle shared = - isolate()->factory()->NewSharedFunctionInfo(name, literals, code, - Handle(fun->shared()->scope_info())); + isolate()->factory()->NewSharedFunctionInfo(name, literals, is_generator, + code, Handle(fun->shared()->scope_info())); shared->set_construct_stub(*construct_stub); // Copy the function data to the shared function info. diff --git a/test/mjsunit/harmony/generators-objects.js b/test/mjsunit/harmony/generators-objects.js index 0c36818c8e..b717c303c8 100644 --- a/test/mjsunit/harmony/generators-objects.js +++ b/test/mjsunit/harmony/generators-objects.js @@ -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();