From dfe5b037ca2b38fa0a40f439d330dd1eeba96209 Mon Sep 17 00:00:00 2001 From: Morgan Phillips Date: Wed, 19 Aug 2015 10:52:52 -0700 Subject: [PATCH] Bug 1191486 - Generators should not have [[Construct]]; r=jorendorff generator function do not have a [[construct]] trap, so `new` throws called a generator. This is unexpected behavior, so a TypeError is preferred. --HG-- extra : rebase_source : 200c1a59db9dd2a0559de3aa52c8f2c466f76289 --- js/src/frontend/Parser.cpp | 12 ++++++------ js/src/jsfun.h | 3 ++- js/src/tests/ecma_6/Class/methDefnGen.js | 11 +++-------- js/src/tests/ecma_6/Class/methodsPrototype.js | 14 ++++---------- js/src/tests/ecma_6/Class/newTargetGenerators.js | 4 ---- js/src/tests/ecma_6/Generators/objects.js | 8 -------- js/src/tests/ecma_6/Generators/runtime.js | 16 ++++------------ 7 files changed, 19 insertions(+), 49 deletions(-) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index b4c561115f2a..73b11a09e57e 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1292,10 +1292,9 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, break; case Method: MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator); - if (generatorKind == NotGenerator) - flags = JSFunction::INTERPRETED_METHOD; - else - flags = JSFunction::INTERPRETED_METHOD_GENERATOR; + flags = (generatorKind == NotGenerator + ? JSFunction::INTERPRETED_METHOD + : JSFunction::INTERPRETED_METHOD_GENERATOR); allocKind = gc::AllocKind::FUNCTION_EXTENDED; break; case ClassConstructor: @@ -1312,8 +1311,9 @@ Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, allocKind = gc::AllocKind::FUNCTION_EXTENDED; break; default: - flags = JSFunction::INTERPRETED_NORMAL; - break; + flags = (generatorKind == NotGenerator + ? JSFunction::INTERPRETED_NORMAL + : JSFunction::INTERPRETED_GENERATOR); } fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto, diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 1cabe8a5716a..5fbb086baa23 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -81,13 +81,14 @@ class JSFunction : public js::NativeObject ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR, ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA, INTERPRETED_METHOD = INTERPRETED | METHOD_KIND, - INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND | CONSTRUCTOR, + INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND, INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR, INTERPRETED_GETTER = INTERPRETED | GETTER_KIND, INTERPRETED_SETTER = INTERPRETED | SETTER_KIND, INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR, INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND, INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR, + INTERPRETED_GENERATOR = INTERPRETED, NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME, STABLE_ACROSS_CLONES = IS_FUN_PROTO | CONSTRUCTOR | EXPR_BODY | HAS_GUESSED_ATOM | diff --git a/js/src/tests/ecma_6/Class/methDefnGen.js b/js/src/tests/ecma_6/Class/methDefnGen.js index 8afd94198a83..cee1e2e7a8ff 100644 --- a/js/src/tests/ecma_6/Class/methDefnGen.js +++ b/js/src/tests/ecma_6/Class/methDefnGen.js @@ -67,7 +67,7 @@ assertEq(next.value.hello, 2); assertEq(next.value.world, 3); // prototype property -assertEq(b.g.hasOwnProperty("prototype"), true); +assertEq(b.g.hasOwnProperty("prototype"), false); // Strict mode a = {*b(c){"use strict";yield c;}}; @@ -75,13 +75,8 @@ assertEq(a.b(1).next().value, 1); a = {*["b"](c){"use strict";return c;}}; assertEq(a.b(1).next().value, 1); -// Constructing +// Generators should not have [[Construct]] a = {*g() { yield 1; }} -it = new a.g; -next = it.next(); -assertEq(next.done, false); -assertEq(next.value, 1); -next = it.next(); -assertEq(next.done, true); +assertThrowsInstanceOf(() => { new a.g }, TypeError); reportCompare(0, 0, "ok"); diff --git a/js/src/tests/ecma_6/Class/methodsPrototype.js b/js/src/tests/ecma_6/Class/methodsPrototype.js index 65d5f465d771..121497bbf63c 100644 --- a/js/src/tests/ecma_6/Class/methodsPrototype.js +++ b/js/src/tests/ecma_6/Class/methodsPrototype.js @@ -13,23 +13,17 @@ class TestClass { var test = new TestClass(); -var hasPrototype = [ - test.constructor, - test.generator, - TestClass.staticGenerator -] - -for (var fun of hasPrototype) { - assertEq(fun.hasOwnProperty('prototype'), true); -} +assertEq(test.constructor.hasOwnProperty('prototype'), true); var hasNoPrototype = [ test.method, + test.generator, + TestClass.staticGenerator, Object.getOwnPropertyDescriptor(test.__proto__, 'getter').get, Object.getOwnPropertyDescriptor(test.__proto__, 'setter').set, TestClass.staticMethod, Object.getOwnPropertyDescriptor(TestClass, 'staticGetter').get, - Object.getOwnPropertyDescriptor(TestClass, 'staticSetter').set, + Object.getOwnPropertyDescriptor(TestClass, 'staticSetter').set ] for (var fun of hasNoPrototype) { diff --git a/js/src/tests/ecma_6/Class/newTargetGenerators.js b/js/src/tests/ecma_6/Class/newTargetGenerators.js index da611c09ecd4..a8dbc6ad6867 100644 --- a/js/src/tests/ecma_6/Class/newTargetGenerators.js +++ b/js/src/tests/ecma_6/Class/newTargetGenerators.js @@ -10,10 +10,6 @@ const ITERATIONS = 25; for (let i = 0; i < ITERATIONS; i++) assertEq(generatorNewTarget(undefined).next().value(), undefined); -for (let i = 0; i < ITERATIONS; i++) - assertEq(new generatorNewTarget(generatorNewTarget).next().value(), - generatorNewTarget); - // also check to make sure it's useful in yield inside generators. // Plus, this code is so ugly, how could it not be a test? ;) // Thanks to anba for supplying this ludicrous expression. diff --git a/js/src/tests/ecma_6/Generators/objects.js b/js/src/tests/ecma_6/Generators/objects.js index 20ca01cfda3f..1ffdf48fabb0 100644 --- a/js/src/tests/ecma_6/Generators/objects.js +++ b/js/src/tests/ecma_6/Generators/objects.js @@ -15,14 +15,6 @@ function TestGeneratorObject() { assertEq(String(iter), "[object Generator]"); assertDeepEq(Object.getOwnPropertyNames(iter), []); assertNotEq(g(), iter); - - // g() is the same as new g(). - iter = new g(); - assertEq(Object.getPrototypeOf(iter), g.prototype); - assertTrue(iter instanceof g); - assertEq(String(iter), "[object Generator]"); - assertDeepEq(Object.getOwnPropertyNames(iter), []); - assertNotEq(new g(), iter); } TestGeneratorObject(); diff --git a/js/src/tests/ecma_6/Generators/runtime.js b/js/src/tests/ecma_6/Generators/runtime.js index 9c5c3198caf1..9f07ebe78622 100644 --- a/js/src/tests/ecma_6/Generators/runtime.js +++ b/js/src/tests/ecma_6/Generators/runtime.js @@ -18,11 +18,12 @@ var GeneratorFunctionPrototype = Object.getPrototypeOf(g); var GeneratorFunction = GeneratorFunctionPrototype.constructor; var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype; - // A generator function should have the same set of properties as any -// other function. +// other function, minus a prototype. function TestGeneratorFunctionInstance() { var f_own_property_names = Object.getOwnPropertyNames(f); + f_own_property_names.splice(f_own_property_names.indexOf("prototype"), 1); + var g_own_property_names = Object.getOwnPropertyNames(g); f_own_property_names.sort(); @@ -41,7 +42,6 @@ function TestGeneratorFunctionInstance() { } TestGeneratorFunctionInstance(); - // Generators have an additional object interposed in the chain between // themselves and Function.prototype. function TestGeneratorFunctionPrototype() { @@ -112,15 +112,7 @@ TestGeneratorFunction(); function TestPerGeneratorPrototype() { - assertNotEq((function*(){}).prototype, (function*(){}).prototype); - assertNotEq((function*(){}).prototype, g.prototype); - assertEq(typeof GeneratorFunctionPrototype, "object"); - assertEq(g.prototype.__proto__.constructor, GeneratorFunctionPrototype, "object"); - assertEq(Object.getPrototypeOf(g.prototype), GeneratorObjectPrototype); - assertFalse(g.prototype instanceof Function); - assertEq(typeof (g.prototype), "object"); - - assertDeepEq(Object.getOwnPropertyNames(g.prototype), []); + assertEq(g.hasOwnProperty("prototype"), false); } TestPerGeneratorPrototype();