Revision: 23341
Author:   [email protected]
Date:     Mon Aug 25 09:12:22 2014 UTC
Log:      Arguments object has @@iterator

[email protected], [email protected], [email protected]
BUG=v8:3391
LOG=N
TEST=mjsunit/harmony/arguments-iterator.js

Review URL: https://codereview.chromium.org/342453002
https://code.google.com/p/v8/source/detail?r=23341

Added:
 /branches/bleeding_edge/test/mjsunit/es6/arguments-iterator.js
Modified:
 /branches/bleeding_edge/src/accessors.cc
 /branches/bleeding_edge/src/accessors.h
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/contexts.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/test/mjsunit/mjsunit.status

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/es6/arguments-iterator.js Mon Aug 25 09:12:22 2014 UTC
@@ -0,0 +1,230 @@
+// 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.
+
+// Flags: --allow-natives-syntax
+
+
+// Note in general that "arguments.foo" and "var o = arguments; o.foo"
+// are treated differently by full-codegen, and so both cases need to be
+// tested.
+
+function TestDirectArgumentsIteratorProperty() {
+  assertTrue(arguments.hasOwnProperty(Symbol.iterator));
+  assertFalse(arguments.propertyIsEnumerable(Symbol.iterator));
+ var descriptor = Object.getOwnPropertyDescriptor(arguments, Symbol.iterator);
+  assertTrue(descriptor.writable);
+  assertFalse(descriptor.enumerable);
+  assertTrue(descriptor.configurable);
+  assertEquals(descriptor.value, [].values);
+  assertEquals(arguments[Symbol.iterator], [].values);
+}
+TestDirectArgumentsIteratorProperty();
+
+
+function TestIndirectArgumentsIteratorProperty() {
+  var o = arguments;
+  assertTrue(o.hasOwnProperty(Symbol.iterator));
+  assertFalse(o.propertyIsEnumerable(Symbol.iterator));
+  assertEquals(o[Symbol.iterator], [].values);
+}
+TestIndirectArgumentsIteratorProperty();
+
+
+function assertIteratorResult(value, done, result) {
+  assertEquals({value: value, done: done}, result);
+}
+
+
+function TestDirectValues1(a, b, c) {
+  var iterator = arguments[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+  assertIteratorResult(c, false, iterator.next());
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestDirectValues1(1, 2, 3);
+
+
+function TestIndirectValues1(a, b, c) {
+  var args = arguments;
+  var iterator = args[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+  assertIteratorResult(c, false, iterator.next());
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestIndirectValues1(1, 2, 3);
+
+
+function TestDirectValues2(a, b, c) {
+  var iterator = arguments[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+  assertIteratorResult(c, false, iterator.next());
+  assertIteratorResult(undefined, true, iterator.next());
+
+  arguments[3] = 4;
+  arguments.length = 4;
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestDirectValues2(1, 2, 3);
+
+
+function TestIndirectValues2(a, b, c) {
+  var args = arguments;
+  var iterator = args[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+  assertIteratorResult(c, false, iterator.next());
+  assertIteratorResult(undefined, true, iterator.next());
+
+  arguments[3] = 4;
+  arguments.length = 4;
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestIndirectValues2(1, 2, 3);
+
+
+function TestDirectValues3(a, b, c) {
+  var iterator = arguments[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+
+  arguments.length = 2;
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestDirectValues3(1, 2, 3);
+
+
+function TestIndirectValues3(a, b, c) {
+  var args = arguments;
+  var iterator = args[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+
+  arguments.length = 2;
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestIndirectValues3(1, 2, 3);
+
+
+function TestDirectValues4(a, b, c) {
+  var iterator = arguments[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+  assertIteratorResult(c, false, iterator.next());
+
+  arguments.length = 4;
+  assertIteratorResult(undefined, false, iterator.next());
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestDirectValues4(1, 2, 3);
+
+
+function TestIndirectValues4(a, b, c) {
+  var args = arguments;
+  var iterator = args[Symbol.iterator]();
+  assertIteratorResult(a, false, iterator.next());
+  assertIteratorResult(b, false, iterator.next());
+  assertIteratorResult(c, false, iterator.next());
+
+  arguments.length = 4;
+  assertIteratorResult(undefined, false, iterator.next());
+  assertIteratorResult(undefined, true, iterator.next());
+}
+TestIndirectValues4(1, 2, 3);
+
+
+function TestForOf() {
+  var i = 0;
+  for (var value of arguments) {
+    assertEquals(arguments[i++], value);
+  }
+
+  assertEquals(arguments.length, i);
+}
+TestForOf(1, 2, 3, 4, 5);
+
+
+function TestAssignmentToIterator() {
+  var i = 0;
+  arguments[Symbol.iterator] = [].entries;
+  for (var entry of arguments) {
+    assertEquals([i, arguments[i]], entry);
+    i++;
+  }
+
+  assertEquals(arguments.length, i);
+}
+TestAssignmentToIterator(1, 2, 3, 4, 5);
+
+
+function TestArgumentsMutation() {
+  var i = 0;
+  for (var x of arguments) {
+    assertEquals(arguments[i], x);
+    arguments[i+1] *= 2;
+    i++;
+  }
+
+  assertEquals(arguments.length, i);
+}
+TestArgumentsMutation(1, 2, 3, 4, 5);
+
+
+function TestSloppyArgumentsAliasing(a0, a1, a2, a3, a4) {
+  var i = 0;
+  for (var x of arguments) {
+    assertEquals(arguments[i], x);
+    a0 = a1; a1 = a2; a3 = a4;
+    i++;
+  }
+
+  assertEquals(arguments.length, i);
+}
+TestSloppyArgumentsAliasing(1, 2, 3, 4, 5);
+
+
+function TestStrictArgumentsAliasing(a0, a1, a2, a3, a4) {
+  "use strict";
+  var i = 0;
+  for (var x of arguments) {
+    a0 = a1; a1 = a2; a3 = a4;
+    assertEquals(arguments[i], x);
+    i++;
+  }
+
+  assertEquals(arguments.length, i);
+}
+TestStrictArgumentsAliasing(1, 2, 3, 4, 5);
+
+
+function TestArgumentsAsProto() {
+  "use strict";
+
+  var o = {__proto__:arguments};
+  assertSame([].values, o[Symbol.iterator]);
+  // Make o dict-mode.
+  %OptimizeObjectForAddingMultipleProperties(o, 0);
+  assertFalse(o.hasOwnProperty(Symbol.iterator));
+  assertSame([].values, o[Symbol.iterator]);
+  o[Symbol.iterator] = 10;
+  assertTrue(o.hasOwnProperty(Symbol.iterator));
+  assertEquals(10, o[Symbol.iterator]);
+  assertSame([].values, arguments[Symbol.iterator]);
+
+  // Frozen o.
+  o = Object.freeze({__proto__:arguments});
+  assertSame([].values, o[Symbol.iterator]);
+  assertFalse(o.hasOwnProperty(Symbol.iterator));
+  assertSame([].values, o[Symbol.iterator]);
+  // This should throw, but currently it doesn't, because
+  // ExecutableAccessorInfo callbacks don't see the current strict mode.
+  // See note in accessors.cc:SetPropertyOnInstanceIfInherited.
+  o[Symbol.iterator] = 10;
+  assertFalse(o.hasOwnProperty(Symbol.iterator));
+  assertEquals([].values, o[Symbol.iterator]);
+  assertSame([].values, arguments[Symbol.iterator]);
+}
+TestArgumentsAsProto();
=======================================
--- /branches/bleeding_edge/src/accessors.cc    Wed Aug 20 15:25:13 2014 UTC
+++ /branches/bleeding_edge/src/accessors.cc    Mon Aug 25 09:12:22 2014 UTC
@@ -153,6 +153,46 @@
   }
   return true;
 }
+
+
+//
+// Accessors::ArgumentsIterator
+//
+
+
+void Accessors::ArgumentsIteratorGetter(
+ v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
+  DisallowHeapAllocation no_allocation;
+  HandleScope scope(isolate);
+  Object* result = isolate->native_context()->array_values_iterator();
+ info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
+}
+
+
+void Accessors::ArgumentsIteratorSetter(
+    v8::Local<v8::Name> name, v8::Local<v8::Value> val,
+    const v8::PropertyCallbackInfo<void>& info) {
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
+  HandleScope scope(isolate);
+  Handle<JSObject> object = Utils::OpenHandle(*info.This());
+  Handle<Object> value = Utils::OpenHandle(*val);
+
+  if (SetPropertyOnInstanceIfInherited(isolate, info, name, value)) return;
+
+  LookupIterator it(object, Utils::OpenHandle(*name));
+  CHECK(it.HasProperty());
+  DCHECK(it.HolderIsReceiverOrHiddenPrototype());
+  Object::SetDataProperty(&it, value);
+}
+
+
+Handle<AccessorInfo> Accessors::ArgumentsIteratorInfo(
+    Isolate* isolate, PropertyAttributes attributes) {
+  Handle<Name> name(isolate->native_context()->iterator_symbol(), isolate);
+  return MakeAccessor(isolate, name, &ArgumentsIteratorGetter,
+                      &ArgumentsIteratorSetter, attributes);
+}


 //
=======================================
--- /branches/bleeding_edge/src/accessors.h     Wed Aug 20 15:25:13 2014 UTC
+++ /branches/bleeding_edge/src/accessors.h     Mon Aug 25 09:12:22 2014 UTC
@@ -13,27 +13,28 @@

 // The list of accessor descriptors. This is a second-order macro
 // taking a macro to be applied to all accessor descriptor names.
-#define ACCESSOR_INFO_LIST(V)       \
-  V(ArrayLength)                    \
-  V(FunctionArguments)              \
-  V(FunctionCaller)                 \
-  V(FunctionName)                   \
-  V(FunctionLength)                 \
-  V(FunctionPrototype)              \
-  V(ScriptColumnOffset)             \
-  V(ScriptCompilationType)          \
-  V(ScriptContextData)              \
-  V(ScriptEvalFromScript)           \
-  V(ScriptEvalFromScriptPosition)   \
-  V(ScriptEvalFromFunctionName)     \
-  V(ScriptId)                       \
-  V(ScriptLineEnds)                 \
-  V(ScriptLineOffset)               \
-  V(ScriptName)                     \
-  V(ScriptSource)                   \
-  V(ScriptType)                     \
-  V(ScriptSourceUrl)                \
-  V(ScriptSourceMappingUrl)         \
+#define ACCESSOR_INFO_LIST(V)     \
+  V(ArgumentsIterator)            \
+  V(ArrayLength)                  \
+  V(FunctionArguments)            \
+  V(FunctionCaller)               \
+  V(FunctionName)                 \
+  V(FunctionLength)               \
+  V(FunctionPrototype)            \
+  V(ScriptColumnOffset)           \
+  V(ScriptCompilationType)        \
+  V(ScriptContextData)            \
+  V(ScriptEvalFromScript)         \
+  V(ScriptEvalFromScriptPosition) \
+  V(ScriptEvalFromFunctionName)   \
+  V(ScriptId)                     \
+  V(ScriptLineEnds)               \
+  V(ScriptLineOffset)             \
+  V(ScriptName)                   \
+  V(ScriptSource)                 \
+  V(ScriptType)                   \
+  V(ScriptSourceUrl)              \
+  V(ScriptSourceMappingUrl)       \
   V(StringLength)

 // Accessors contains all predefined proxy accessors.
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Thu Aug 21 12:39:33 2014 UTC
+++ /branches/bleeding_edge/src/bootstrapper.cc Mon Aug 25 09:12:22 2014 UTC
@@ -1204,6 +1204,7 @@
                         DONT_ENUM, Representation::Tagged());
       map->AppendDescriptor(&d);
     }
+    // @@iterator method is added later.

     map->set_function_with_prototype(true);
     map->set_pre_allocated_property_fields(2);
@@ -1262,6 +1263,7 @@
       CallbacksDescriptor d(factory->caller_string(), caller, attributes);
       map->AppendDescriptor(&d);
     }
+    // @@iterator method is added later.

     map->set_function_with_prototype(true);
     map->set_prototype(native_context()->object_function()->prototype());
@@ -1596,6 +1598,7 @@

   INSTALL_NATIVE(Symbol, "symbolIterator", iterator_symbol);
   INSTALL_NATIVE(Symbol, "symbolUnscopables", unscopables_symbol);
+  INSTALL_NATIVE(JSFunction, "ArrayValues", array_values_iterator);

   INSTALL_NATIVE_MATH(abs)
   INSTALL_NATIVE_MATH(acos)
@@ -2038,6 +2041,34 @@

     native_context()->set_regexp_result_map(*initial_map);
   }
+
+  // Add @@iterator method to the arguments object maps.
+  {
+    PropertyAttributes attribs = DONT_ENUM;
+    Handle<AccessorInfo> arguments_iterator =
+        Accessors::ArgumentsIteratorInfo(isolate(), attribs);
+    {
+ CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()),
+                            arguments_iterator, attribs);
+      Handle<Map> map(native_context()->sloppy_arguments_map());
+      Map::EnsureDescriptorSlack(map, 1);
+      map->AppendDescriptor(&d);
+    }
+    {
+ CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()),
+                            arguments_iterator, attribs);
+      Handle<Map> map(native_context()->aliased_arguments_map());
+      Map::EnsureDescriptorSlack(map, 1);
+      map->AppendDescriptor(&d);
+    }
+    {
+ CallbacksDescriptor d(Handle<Name>(native_context()->iterator_symbol()),
+                            arguments_iterator, attribs);
+      Handle<Map> map(native_context()->strict_arguments_map());
+      Map::EnsureDescriptorSlack(map, 1);
+      map->AppendDescriptor(&d);
+    }
+  }

 #ifdef VERIFY_HEAP
   builtins->ObjectVerify();
=======================================
--- /branches/bleeding_edge/src/contexts.h      Mon Aug 11 14:54:15 2014 UTC
+++ /branches/bleeding_edge/src/contexts.h      Mon Aug 25 09:12:22 2014 UTC
@@ -201,7 +201,8 @@
V(MAP_ITERATOR_MAP_INDEX, Map, map_iterator_map) \ V(SET_ITERATOR_MAP_INDEX, Map, set_iterator_map) \ V(ITERATOR_SYMBOL_INDEX, Symbol, iterator_symbol) \
-  V(UNSCOPABLES_SYMBOL_INDEX, Symbol, unscopables_symbol)
+ V(UNSCOPABLES_SYMBOL_INDEX, Symbol, unscopables_symbol) \
+  V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator)

 // JSFunctions are pairs (context, function code), sometimes also called
 // closures. A Context object is used to represent function contexts and
@@ -396,6 +397,7 @@
     SET_ITERATOR_MAP_INDEX,
     ITERATOR_SYMBOL_INDEX,
     UNSCOPABLES_SYMBOL_INDEX,
+    ARRAY_VALUES_ITERATOR_INDEX,

     // Properties from here are treated as weak references by the full GC.
     // Scavenge treats them as strong references.
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Mon Aug 25 07:04:21 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc      Mon Aug 25 09:12:22 2014 UTC
@@ -6011,6 +6011,10 @@

   HandleScope scope(isolate);
   if (raw_key->IsSymbol()) {
+    Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
+    if (symbol->Equals(isolate->native_context()->iterator_symbol())) {
+      return isolate->native_context()->array_values_iterator();
+    }
     // Lookup in the initial Object.prototype object.
     Handle<Object> result;
     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
=======================================
--- /branches/bleeding_edge/test/mjsunit/mjsunit.status Mon Aug 25 07:02:19 2014 UTC +++ /branches/bleeding_edge/test/mjsunit/mjsunit.status Mon Aug 25 09:12:22 2014 UTC
@@ -160,6 +160,7 @@
   'es6/iteration-semantics': [PASS, NO_VARIANTS],
   'es6/string-iterator': [PASS, NO_VARIANTS],
   'es6/typed-array-iterator': [PASS, NO_VARIANTS],
+  'es6/arguments-iterator': [PASS, NO_VARIANTS],

##############################################################################
   # Too slow in debug mode with --stress-opt mode.

--
--
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/d/optout.

Reply via email to