[es6] Iterators and generators should "extend" %IteratorPrototype%
authorarv <arv@chromium.org>
Fri, 15 May 2015 15:09:46 +0000 (08:09 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 15 May 2015 15:09:38 +0000 (15:09 +0000)
All the builtin iterators as well as the generator objects have an
object called %IteratorPrototype% in the spec between them and
%ObjectPrototype%.

BUG=v8:3568
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#28426}

BUILD.gn
src/array-iterator.js
src/bootstrapper.cc
src/collection-iterator.js
src/generator.js
src/iterator-prototype.js [new file with mode: 0644]
src/string-iterator.js
test/mjsunit/es6/generators-runtime.js
test/mjsunit/es6/iterator-prototype.js [new file with mode: 0644]
tools/gyp/v8.gyp

index c0d86ea..2fbf6e5 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -202,7 +202,7 @@ action("js2c") {
 
   sources = [
     "src/macros.py",
-    "src/messages.h",  
+    "src/messages.h",
     "src/runtime.js",
     "src/v8natives.js",
     "src/symbol.js",
@@ -215,6 +215,7 @@ action("js2c") {
     "src/regexp.js",
     "src/arraybuffer.js",
     "src/typedarray.js",
+    "src/iterator-prototype.js",
     "src/generator.js",
     "src/object-observe.js",
     "src/collection.js",
@@ -264,7 +265,7 @@ action("js2c_experimental") {
 
   sources = [
     "src/macros.py",
-    "src/messages.h",  
+    "src/messages.h",
     "src/proxy.js",
     "src/generator.js",
     "src/harmony-array.js",
index 24bf7e5..2d1a2a6 100644 (file)
@@ -12,7 +12,6 @@ var $arrayValues;
 %CheckIsBootstrapping();
 
 var GlobalArray = global.Array;
-var GlobalObject = global.Object;
 
 macro TYPED_ARRAYS(FUNCTION)
   FUNCTION(Uint8Array)
@@ -122,7 +121,7 @@ function ArrayKeys() {
 }
 
 
-%FunctionSetPrototype(ArrayIterator, new GlobalObject());
+%FunctionSetPrototype(ArrayIterator, {__proto__: $iteratorPrototype});
 %FunctionSetInstanceClassName(ArrayIterator, 'Array Iterator');
 
 $installFunctions(ArrayIterator.prototype, DONT_ENUM, [
index f2e5196..55b5b31 100644 (file)
@@ -2129,10 +2129,17 @@ bool Genesis::InstallNatives() {
   {
     // Create generator meta-objects and install them on the builtins object.
     Handle<JSObject> builtins(native_context()->builtins());
+    Handle<JSObject> iterator_prototype =
+        factory()->NewJSObject(isolate()->object_function(), TENURED);
     Handle<JSObject> generator_object_prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
     Handle<JSObject> generator_function_prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
+    SetObjectPrototype(generator_object_prototype, iterator_prototype);
+    JSObject::AddProperty(
+        builtins, factory()->InternalizeUtf8String("$iteratorPrototype"),
+        iterator_prototype,
+        static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY));
     JSObject::AddProperty(
         builtins,
         factory()->InternalizeUtf8String("GeneratorFunctionPrototype"),
index 7aa5208..b48b85c 100644 (file)
@@ -14,7 +14,6 @@ var $setValues;
 %CheckIsBootstrapping();
 
 var GlobalMap = global.Map;
-var GlobalObject = global.Object;
 var GlobalSet = global.Set;
 
 // -------------------------------------------------------------------
@@ -49,11 +48,6 @@ function SetIteratorNextJS() {
 }
 
 
-function SetIteratorSymbolIterator() {
-  return this;
-}
-
-
 function SetEntries() {
   if (!IS_SET(this)) {
     throw MakeTypeError(kIncompatibleMethodReceiver,
@@ -74,15 +68,12 @@ function SetValues() {
 // -------------------------------------------------------------------
 
 %SetCode(SetIterator, SetIteratorConstructor);
-%FunctionSetPrototype(SetIterator, new GlobalObject());
+%FunctionSetPrototype(SetIterator, {__proto__: $iteratorPrototype});
 %FunctionSetInstanceClassName(SetIterator, 'Set Iterator');
 $installFunctions(SetIterator.prototype, DONT_ENUM, [
   'next', SetIteratorNextJS
 ]);
 
-$setFunctionName(SetIteratorSymbolIterator, symbolIterator);
-%AddNamedProperty(SetIterator.prototype, symbolIterator,
-    SetIteratorSymbolIterator, DONT_ENUM);
 %AddNamedProperty(SetIterator.prototype, symbolToStringTag,
     "Set Iterator", READ_ONLY | DONT_ENUM);
 
@@ -104,11 +95,6 @@ function MapIteratorConstructor(map, kind) {
 }
 
 
-function MapIteratorSymbolIterator() {
-  return this;
-}
-
-
 function MapIteratorNextJS() {
   if (!IS_MAP_ITERATOR(this)) {
     throw MakeTypeError(kIncompatibleMethodReceiver,
@@ -164,15 +150,12 @@ function MapValues() {
 // -------------------------------------------------------------------
 
 %SetCode(MapIterator, MapIteratorConstructor);
-%FunctionSetPrototype(MapIterator, new GlobalObject());
+%FunctionSetPrototype(MapIterator, {__proto__: $iteratorPrototype});
 %FunctionSetInstanceClassName(MapIterator, 'Map Iterator');
 $installFunctions(MapIterator.prototype, DONT_ENUM, [
   'next', MapIteratorNextJS
 ]);
 
-$setFunctionName(MapIteratorSymbolIterator, symbolIterator);
-%AddNamedProperty(MapIterator.prototype, symbolIterator,
-    MapIteratorSymbolIterator, DONT_ENUM);
 %AddNamedProperty(MapIterator.prototype, symbolToStringTag,
     "Map Iterator", READ_ONLY | DONT_ENUM);
 
index ae34ed3..ef276da 100644 (file)
@@ -66,11 +66,6 @@ function GeneratorObjectThrow(exn) {
 }
 
 
-function GeneratorObjectIterator() {
-  return this;
-}
-
-
 function GeneratorFunctionConstructor(arg1) {  // length == 1
   var source = $newFunctionString(arguments, 'function*');
   var global_proxy = %GlobalProxy(GeneratorFunctionConstructor);
@@ -95,9 +90,6 @@ $installFunctions(GeneratorObjectPrototype,
                  ["next", GeneratorObjectNext,
                   "throw", GeneratorObjectThrow]);
 
-$setFunctionName(GeneratorObjectIterator, symbolIterator);
-%AddNamedProperty(GeneratorObjectPrototype, symbolIterator,
-    GeneratorObjectIterator, DONT_ENUM | DONT_DELETE | READ_ONLY);
 %AddNamedProperty(GeneratorObjectPrototype, "constructor",
     GeneratorFunctionPrototype, DONT_ENUM | READ_ONLY);
 %AddNamedProperty(GeneratorObjectPrototype,
diff --git a/src/iterator-prototype.js b/src/iterator-prototype.js
new file mode 100644 (file)
index 0000000..1c9314a
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var $iteratorPrototype;
+
+(function(global, shared, exports) {
+  "use strict";
+  %CheckIsBootstrapping();
+
+  var GlobalObject = global.Object;
+
+  // 25.1.2.1 %IteratorPrototype% [ @@iterator ] ( )
+  function IteratorPrototypeIterator() {
+    return this;
+  }
+
+  $setFunctionName(IteratorPrototypeIterator, symbolIterator);
+  %AddNamedProperty($iteratorPrototype, symbolIterator,
+      IteratorPrototypeIterator, DONT_ENUM);
+})
index c19e808..8249356 100644 (file)
@@ -8,7 +8,6 @@
 
 %CheckIsBootstrapping();
 
-var GlobalObject = global.Object;
 var GlobalString = global.String;
 
 //-------------------------------------------------------------------
@@ -31,12 +30,6 @@ function CreateStringIterator(string) {
 }
 
 
-// 21.1.5.2.2 %StringIteratorPrototype%[@@iterator]
-function StringIteratorIterator() {
-  return this;
-}
-
-
 // 21.1.5.2.1 %StringIteratorPrototype%.next( )
 function StringIteratorNext() {
   var iterator = $toObject(this);
@@ -85,15 +78,12 @@ function StringPrototypeIterator() {
 
 //-------------------------------------------------------------------
 
-%FunctionSetPrototype(StringIterator, new GlobalObject());
+%FunctionSetPrototype(StringIterator, {__proto__: $iteratorPrototype});
 %FunctionSetInstanceClassName(StringIterator, 'String Iterator');
 
 $installFunctions(StringIterator.prototype, DONT_ENUM, [
   'next', StringIteratorNext
 ]);
-$setFunctionName(StringIteratorIterator, symbolIterator);
-%AddNamedProperty(StringIterator.prototype, symbolIterator,
-                  StringIteratorIterator, DONT_ENUM);
 %AddNamedProperty(StringIterator.prototype, symbolToStringTag,
                   "String Iterator", READ_ONLY | DONT_ENUM);
 
index 115c7a4..72a47d0 100644 (file)
@@ -35,6 +35,7 @@ function* g() { yield 1; }
 var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
 var GeneratorFunction = GeneratorFunctionPrototype.constructor;
 var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
+var IteratorPrototype = Object.getPrototypeOf(GeneratorObjectPrototype);
 
 // A generator function should have the same set of properties as any
 // other function.
@@ -100,7 +101,7 @@ TestGeneratorFunctionPrototype();
 // Functions that we associate with generator objects are actually defined by
 // a common prototype.
 function TestGeneratorObjectPrototype() {
-  assertSame(Object.prototype,
+  assertSame(IteratorPrototype,
              Object.getPrototypeOf(GeneratorObjectPrototype));
   assertSame(GeneratorObjectPrototype,
              Object.getPrototypeOf((function*(){yield 1}).prototype));
@@ -134,16 +135,6 @@ function TestGeneratorObjectPrototype() {
   assertTrue(throw_desc.writable);
   assertFalse(throw_desc.enumerable);
   assertTrue(throw_desc.configurable);
-
-  var iterator_desc = Object.getOwnPropertyDescriptor(GeneratorObjectPrototype,
-      Symbol.iterator);
-  assertTrue(iterator_desc !== undefined);
-  assertFalse(iterator_desc.writable);
-  assertFalse(iterator_desc.enumerable);
-  assertFalse(iterator_desc.configurable);
-
-  // The generator object's "iterator" function is just the identity.
-  assertSame(iterator_desc.value.call(42), 42);
 }
 TestGeneratorObjectPrototype();
 
diff --git a/test/mjsunit/es6/iterator-prototype.js b/test/mjsunit/es6/iterator-prototype.js
new file mode 100644 (file)
index 0000000..0b266e9
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var arrayIteratorPrototype = [].entries().__proto__;
+var iteratorPrototype = arrayIteratorPrototype.__proto__;
+
+assertSame(Object.prototype, Object.getPrototypeOf(iteratorPrototype));
+assertTrue(Object.isExtensible(iteratorPrototype));
+assertSame(0, Object.getOwnPropertyNames(iteratorPrototype).length);
+assertSame(1, Object.getOwnPropertySymbols(iteratorPrototype).length);
+assertSame(Symbol.iterator,
+             Object.getOwnPropertySymbols(iteratorPrototype)[0]);
+
+var descr = Object.getOwnPropertyDescriptor(iteratorPrototype, Symbol.iterator);
+assertTrue(descr.configurable);
+assertFalse(descr.enumerable);
+assertTrue(descr.writable);
+
+var iteratorFunction = descr.value;
+assertSame('function', typeof iteratorFunction);
+assertSame(0, iteratorFunction.length);
+assertSame('[Symbol.iterator]', iteratorFunction.name);
+
+var obj = {};
+assertSame(obj, iteratorFunction.call(obj));
+assertSame(iteratorPrototype, iteratorPrototype[Symbol.iterator]());
+
+var mapIteratorPrototype = new Map().entries().__proto__;
+var setIteratorPrototype = new Set().values().__proto__;
+var stringIteratorPrototype = 'abc'[Symbol.iterator]().__proto__;
+assertSame(iteratorPrototype, mapIteratorPrototype.__proto__);
+assertSame(iteratorPrototype, setIteratorPrototype.__proto__);
+assertSame(iteratorPrototype, stringIteratorPrototype.__proto__);
+
+var typedArrays = [
+  Float32Array,
+  Float64Array,
+  Int16Array,
+  Int32Array,
+  Int8Array,
+  Uint16Array,
+  Uint32Array,
+  Uint8Array,
+  Uint8ClampedArray,
+];
+
+for (var constructor of typedArrays) {
+  var array = new constructor();
+  var iterator = array[Symbol.iterator]();
+  assertSame(iteratorPrototype, iterator.__proto__.__proto__);
+}
+
+function* gen() {}
+assertSame(iteratorPrototype, gen.prototype.__proto__.__proto__);
+var g = gen();
+assertSame(gen.prototype, g.__proto__);
+assertSame(iteratorPrototype, g.__proto__.__proto__.__proto__);
index 589601a..4528f38 100644 (file)
           '../../src/regexp.js',
           '../../src/arraybuffer.js',
           '../../src/typedarray.js',
+          '../../src/iterator-prototype.js',
           '../../src/generator.js',
           '../../src/object-observe.js',
           '../../src/collection.js',