[ES6] Implement Reflect.enumerate
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Jul 2015 06:01:34 +0000 (06:01 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Jul 2015 06:01:34 +0000 (06:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147347

Reviewed by Sam Weinig.

This patch implements Reflect.enumerate.
It returns the iterator that iterates the enumerable keys of the given object.
It follows the for-in's enumeration order.

To implement it, we write down the same logic to the for-in's enumeration code in C++.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::propertyNameIteratorStructure):
* runtime/JSPropertyNameIterator.cpp: Added.
(JSC::JSPropertyNameIterator::JSPropertyNameIterator):
(JSC::JSPropertyNameIterator::clone):
(JSC::JSPropertyNameIterator::create):
(JSC::JSPropertyNameIterator::finishCreation):
(JSC::JSPropertyNameIterator::visitChildren):
(JSC::JSPropertyNameIterator::next):
(JSC::propertyNameIteratorFuncNext):
* runtime/JSPropertyNameIterator.h: Added.
(JSC::JSPropertyNameIterator::createStructure):
* runtime/ReflectObject.cpp:
(JSC::reflectObjectEnumerate):
* tests/stress/reflect-enumerate.js: Added.
(shouldBe):
(shouldThrow):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@187483 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj
Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/JSPropertyNameIterator.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/ReflectObject.cpp
Source/JavaScriptCore/tests/stress/reflect-enumerate.js [new file with mode: 0644]

index 9770918..c365475 100644 (file)
@@ -516,6 +516,7 @@ set(JavaScriptCore_RUNTIME_SOURCES
     runtime/JSPromiseDeferred.cpp
     runtime/JSPromisePrototype.cpp
     runtime/JSPropertyNameEnumerator.cpp
+    runtime/JSPropertyNameIterator.cpp
     runtime/JSProxy.cpp
     runtime/JSScope.cpp
     runtime/JSSegmentedVariableObject.cpp
index 60d82b5..1fc478b 100644 (file)
@@ -1,5 +1,43 @@
 2015-07-27  Yusuke Suzuki  <utatane.tea@gmail.com>
 
+        [ES6] Implement Reflect.enumerate
+        https://bugs.webkit.org/show_bug.cgi?id=147347
+
+        Reviewed by Sam Weinig.
+
+        This patch implements Reflect.enumerate.
+        It returns the iterator that iterates the enumerable keys of the given object.
+        It follows the for-in's enumeration order.
+
+        To implement it, we write down the same logic to the for-in's enumeration code in C++.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildren):
+        * runtime/JSGlobalObject.h:
+        (JSC::JSGlobalObject::propertyNameIteratorStructure):
+        * runtime/JSPropertyNameIterator.cpp: Added.
+        (JSC::JSPropertyNameIterator::JSPropertyNameIterator):
+        (JSC::JSPropertyNameIterator::clone):
+        (JSC::JSPropertyNameIterator::create):
+        (JSC::JSPropertyNameIterator::finishCreation):
+        (JSC::JSPropertyNameIterator::visitChildren):
+        (JSC::JSPropertyNameIterator::next):
+        (JSC::propertyNameIteratorFuncNext):
+        * runtime/JSPropertyNameIterator.h: Added.
+        (JSC::JSPropertyNameIterator::createStructure):
+        * runtime/ReflectObject.cpp:
+        (JSC::reflectObjectEnumerate):
+        * tests/stress/reflect-enumerate.js: Added.
+        (shouldBe):
+        (shouldThrow):
+
+2015-07-27  Yusuke Suzuki  <utatane.tea@gmail.com>
+
         [ES6] Implement Reflect.preventExtensions
         https://bugs.webkit.org/show_bug.cgi?id=147331
 
index 118a913..244ba19 100644 (file)
     <ClCompile Include="..\runtime\JSPromiseDeferred.cpp" />
     <ClCompile Include="..\runtime\JSPromisePrototype.cpp" />
     <ClCompile Include="..\runtime\JSPropertyNameEnumerator.cpp" />
+    <ClCompile Include="..\runtime\JSPropertyNameIterator.cpp" />
     <ClCompile Include="..\runtime\JSProxy.cpp" />
     <ClCompile Include="..\runtime\JSScope.cpp" />
     <ClCompile Include="..\runtime\JSSegmentedVariableObject.cpp" />
     <ClInclude Include="..\runtime\JSPromiseDeferred.h" />
     <ClInclude Include="..\runtime\JSPromisePrototype.h" />
     <ClInclude Include="..\runtime\JSPropertyNameEnumerator.h" />
+    <ClInclude Include="..\runtime\JSPropertyNameIterator.h" />
     <ClInclude Include="..\runtime\JSProxy.h" />
     <ClInclude Include="..\runtime\JSScope.h" />
     <ClInclude Include="..\runtime\JSSegmentedVariableObject.h" />
index 60c649a..c5bd549 100644 (file)
     <ClCompile Include="..\runtime\JSPropertyNameEnumerator.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
+    <ClCompile Include="..\runtime\JSPropertyNameIterator.cpp">
+      <Filter>runtime</Filter>
+    </ClCompile>
     <ClCompile Include="..\runtime\JSProxy.cpp">
       <Filter>runtime</Filter>
     </ClCompile>
     <ClInclude Include="..\runtime\JSPropertyNameEnumerator.h">
       <Filter>runtime</Filter>
     </ClInclude>
+    <ClInclude Include="..\runtime\JSPropertyNameIterator.h">
+      <Filter>runtime</Filter>
+    </ClInclude>
     <ClInclude Include="..\runtime\JSProxy.h">
       <Filter>runtime</Filter>
     </ClInclude>
index b4a328b..b4acc19 100644 (file)
                E33637A51B63220200EE0840 /* ReflectObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E33637A31B63220200EE0840 /* ReflectObject.cpp */; };
                E33637A61B63220200EE0840 /* ReflectObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E33637A41B63220200EE0840 /* ReflectObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E354622B1B6065D100545386 /* ConstructAbility.h in Headers */ = {isa = PBXBuildFile; fileRef = E354622A1B6065D100545386 /* ConstructAbility.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               E3EF88741B66DF23003F26CB /* JSPropertyNameIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3EF88721B66DF23003F26CB /* JSPropertyNameIterator.cpp */; };
+               E3EF88751B66DF23003F26CB /* JSPropertyNameIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E3EF88731B66DF23003F26CB /* JSPropertyNameIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E49DC16B12EF293E00184A1F /* SourceProviderCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E49DC15512EF277200184A1F /* SourceProviderCache.cpp */; };
                E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC15112EF272200184A1F /* SourceProviderCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */ = {isa = PBXBuildFile; fileRef = E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E33637A31B63220200EE0840 /* ReflectObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReflectObject.cpp; sourceTree = "<group>"; };
                E33637A41B63220200EE0840 /* ReflectObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReflectObject.h; sourceTree = "<group>"; };
                E354622A1B6065D100545386 /* ConstructAbility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstructAbility.h; sourceTree = "<group>"; };
+               E3EF88721B66DF23003F26CB /* JSPropertyNameIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPropertyNameIterator.cpp; sourceTree = "<group>"; };
+               E3EF88731B66DF23003F26CB /* JSPropertyNameIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPropertyNameIterator.h; sourceTree = "<group>"; };
                E49DC14912EF261A00184A1F /* SourceProviderCacheItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceProviderCacheItem.h; sourceTree = "<group>"; };
                E49DC15112EF272200184A1F /* SourceProviderCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourceProviderCache.h; sourceTree = "<group>"; };
                E49DC15512EF277200184A1F /* SourceProviderCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SourceProviderCache.cpp; sourceTree = "<group>"; };
                                7C184E1D17BEE22E007CB63A /* JSPromisePrototype.h */,
                                2A05ABD31961DF2400341750 /* JSPropertyNameEnumerator.cpp */,
                                2A05ABD41961DF2400341750 /* JSPropertyNameEnumerator.h */,
+                               E3EF88721B66DF23003F26CB /* JSPropertyNameIterator.cpp */,
+                               E3EF88731B66DF23003F26CB /* JSPropertyNameIterator.h */,
                                862553CE16136AA5009F17D0 /* JSProxy.cpp */,
                                862553CF16136AA5009F17D0 /* JSProxy.h */,
                                14874AE115EBDE4A002E3587 /* JSScope.cpp */,
                                2AD2EDFB19799E38004D6478 /* EnumerationMode.h in Headers */,
                                A5EF9B181A1D440600702E90 /* generate_cpp_protocol_types_header.py in Headers */,
                                A5EF9B191A1D440700702E90 /* generate_cpp_protocol_types_implementation.py in Headers */,
+                               E3EF88751B66DF23003F26CB /* JSPropertyNameIterator.h in Headers */,
                                C4F4B6F61A05C984005CAB76 /* objc_generator_templates.py in Headers */,
                                70DC3E0A1B2DF2C700054299 /* IteratorPrototype.h in Headers */,
                                A5EF9B171A1D440300702E90 /* generate_cpp_frontend_dispatcher_implementation.py in Headers */,
                                0F2B670417B6B5AB00A7AE3F /* SimpleTypedArrayController.cpp in Sources */,
                                C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */,
                                9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */,
+                               E3EF88741B66DF23003F26CB /* JSPropertyNameIterator.cpp in Sources */,
                                0F8F2B9E17306C8D007DBDA5 /* SourceCode.cpp in Sources */,
                                0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */,
                                E49DC16B12EF293E00184A1F /* SourceProviderCache.cpp in Sources */,
index 3efa667..26183ef 100644 (file)
@@ -85,6 +85,7 @@
 #include "JSPromise.h"
 #include "JSPromiseConstructor.h"
 #include "JSPromisePrototype.h"
+#include "JSPropertyNameIterator.h"
 #include "JSSet.h"
 #include "JSSetIterator.h"
 #include "JSStringIterator.h"
@@ -359,6 +360,7 @@ m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, th
 m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, this, m_ ## lowerName ## Prototype.get()));
     
     FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE)
+    m_propertyNameIteratorStructure.set(vm, this, JSPropertyNameIterator::createStructure(vm, this, m_iteratorPrototype.get()));
     
 #undef CREATE_PROTOTYPE_FOR_DERIVED_ITERATOR_TYPE
 
@@ -784,6 +786,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_callbackConstructorStructure);
     visitor.append(&thisObject->m_callbackFunctionStructure);
     visitor.append(&thisObject->m_callbackObjectStructure);
+    visitor.append(&thisObject->m_propertyNameIteratorStructure);
 #if JSC_OBJC_API_ENABLED
     visitor.append(&thisObject->m_objcCallbackFunctionStructure);
     visitor.append(&thisObject->m_objcWrapperObjectStructure);
index 6e695d4..99879d1 100644 (file)
@@ -225,6 +225,7 @@ protected:
     WriteBarrier<Structure> m_callbackConstructorStructure;
     WriteBarrier<Structure> m_callbackFunctionStructure;
     WriteBarrier<Structure> m_callbackObjectStructure;
+    WriteBarrier<Structure> m_propertyNameIteratorStructure;
 #if JSC_OBJC_API_ENABLED
     WriteBarrier<Structure> m_objcCallbackFunctionStructure;
     WriteBarrier<Structure> m_objcWrapperObjectStructure;
@@ -451,6 +452,7 @@ public:
     Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
     Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
     Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
+    Structure* propertyNameIteratorStructure() const { return m_propertyNameIteratorStructure.get(); }
 #if JSC_OBJC_API_ENABLED
     Structure* objcCallbackFunctionStructure() const { return m_objcCallbackFunctionStructure.get(); }
     Structure* objcWrapperObjectStructure() const { return m_objcWrapperObjectStructure.get(); }
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
new file mode 100644 (file)
index 0000000..a9749a5
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 Apple, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSPropertyNameIterator.h"
+
+#include "IdentifierInlines.h"
+#include "IteratorOperations.h"
+#include "JSCJSValueInlines.h"
+#include "JSCellInlines.h"
+#include "JSPropertyNameEnumerator.h"
+#include "SlotVisitorInlines.h"
+#include "StructureInlines.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState*);
+
+const ClassInfo JSPropertyNameIterator::s_info = { "PropertyName Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) };
+
+JSPropertyNameIterator::JSPropertyNameIterator(VM& vm, Structure* structure, JSObject* object, JSPropertyNameEnumerator* enumerator)
+    : Base(vm, structure)
+    , m_iteratedObject(vm, this, object)
+    , m_propertyNameEnumerator(vm, this, enumerator)
+    , m_enumerationPhase(EnumerationPhase::IndexedNames)
+    , m_cursor(0)
+{
+}
+
+JSPropertyNameIterator* JSPropertyNameIterator::clone(ExecState* exec)
+{
+    auto iterator = JSPropertyNameIterator::create(exec, exec->callee()->globalObject()->propertyNameIteratorStructure(), m_iteratedObject.get(), m_propertyNameEnumerator.get());
+    iterator->m_enumerationPhase = m_enumerationPhase;
+    iterator->m_cursor = m_cursor;
+    return iterator;
+}
+
+JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject)
+{
+    return JSPropertyNameIterator::create(exec, structure, iteratedObject, propertyNameEnumerator(exec, iteratedObject));
+}
+
+JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject, JSPropertyNameEnumerator* enumerator)
+{
+    VM& vm = exec->vm();
+    JSPropertyNameIterator* instance = new (NotNull, allocateCell<JSPropertyNameIterator>(vm.heap)) JSPropertyNameIterator(vm, structure, iteratedObject, enumerator);
+    instance->finishCreation(vm, structure->globalObject());
+    return instance;
+}
+
+void JSPropertyNameIterator::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(info()));
+    JSC_NATIVE_FUNCTION(vm.propertyNames->next, propertyNameIteratorFuncNext, DontEnum, 0);
+}
+
+void JSPropertyNameIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    JSPropertyNameIterator* thisObject = jsCast<JSPropertyNameIterator*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+    visitor.append(&thisObject->m_iteratedObject);
+    visitor.append(&thisObject->m_propertyNameEnumerator);
+}
+
+bool JSPropertyNameIterator::next(ExecState* exec, JSValue& output)
+{
+    if (m_enumerationPhase == EnumerationPhase::IndexedNames) {
+        for (; m_cursor < m_propertyNameEnumerator->indexedLength();) {
+            uint32_t index = m_cursor++;
+            if (m_iteratedObject->hasProperty(exec, index)) {
+                output = jsString(exec, Identifier::from(exec, index).string());
+                return true;
+            }
+        }
+        m_cursor = 0;
+        m_enumerationPhase = EnumerationPhase::StructureNames;
+    }
+
+    if (m_enumerationPhase == EnumerationPhase::StructureNames) {
+        for (; m_cursor < m_propertyNameEnumerator->endStructurePropertyIndex();) {
+            uint32_t index = m_cursor++;
+            JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
+            ASSERT(propertyName);
+            if (m_iteratedObject->structure(exec->vm())->id() == m_propertyNameEnumerator->cachedStructureID()) {
+                output = propertyName;
+                return true;
+            }
+
+            if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
+                output = propertyName;
+                return true;
+            }
+        }
+        ASSERT(m_cursor >= m_propertyNameEnumerator->endStructurePropertyIndex());
+        // Use the same m_cursor in the GenericNames phase.
+        m_enumerationPhase = EnumerationPhase::GenericNames;
+    }
+
+    if (m_enumerationPhase == EnumerationPhase::GenericNames) {
+        for (; m_cursor < m_propertyNameEnumerator->endGenericPropertyIndex();) {
+            uint32_t index = m_cursor++;
+            JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
+            ASSERT(propertyName);
+            if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
+                output = propertyName;
+                return true;
+            }
+        }
+        m_enumerationPhase = EnumerationPhase::Done;
+    }
+
+    return false;
+}
+
+// ------------------------------ PropertyNameIterator Functions ----------------------------
+
+EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState* exec)
+{
+    JSPropertyNameIterator* iterator = jsDynamicCast<JSPropertyNameIterator*>(exec->thisValue());
+    if (!iterator)
+        return JSValue::encode(throwTypeError(exec, ASCIILiteral("Cannot call PropertyNameIterator.next() on a non-PropertyNameIterator object")));
+
+    JSValue result;
+    if (iterator->next(exec, result))
+        return JSValue::encode(createIteratorResultObject(exec, result, false));
+    return JSValue::encode(createIteratorResultObject(exec, jsUndefined(), true));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
new file mode 100644 (file)
index 0000000..5d7aeb1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 Apple, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSPropertyNameIterator_h
+#define JSPropertyNameIterator_h
+
+#include "JSObject.h"
+#include "JSPropertyNameEnumerator.h"
+
+namespace JSC {
+
+class JSPropertyNameIterator : public JSNonFinalObject {
+public:
+    typedef JSNonFinalObject Base;
+
+    enum class EnumerationPhase : uint32_t {
+        IndexedNames,
+        StructureNames,
+        GenericNames,
+        Done
+    };
+
+    DECLARE_EXPORT_INFO;
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+    {
+        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+    }
+
+    static JSPropertyNameIterator* create(ExecState*, Structure*, JSObject*);
+
+    JSPropertyNameIterator* clone(ExecState*);
+    bool next(ExecState*, JSValue&);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+    JSPropertyNameIterator(VM&, Structure*, JSObject*, JSPropertyNameEnumerator*);
+
+    void finishCreation(VM&, JSGlobalObject*);
+
+    static JSPropertyNameIterator* create(ExecState*, Structure*, JSObject*, JSPropertyNameEnumerator*);
+
+    WriteBarrier<JSObject> m_iteratedObject;
+    WriteBarrier<JSPropertyNameEnumerator> m_propertyNameEnumerator;
+    EnumerationPhase m_enumerationPhase;
+    uint32_t m_cursor;
+};
+
+}
+
+#endif // JSPropertyNameIterator_h
index 19c31ab..f52c6da 100644 (file)
 #include "ReflectObject.h"
 
 #include "JSCInlines.h"
+#include "JSPropertyNameIterator.h"
 #include "Lookup.h"
 #include "ObjectConstructor.h"
 
 namespace JSC {
 
+static EncodedJSValue JSC_HOST_CALL reflectObjectEnumerate(ExecState*);
 static EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState*);
 static EncodedJSValue JSC_HOST_CALL reflectObjectOwnKeys(ExecState*);
 static EncodedJSValue JSC_HOST_CALL reflectObjectPreventExtensions(ExecState*);
@@ -50,6 +52,7 @@ const ClassInfo ReflectObject::s_info = { "Reflect", &Base::s_info, &reflectObje
 @begin reflectObjectTable
     apply             reflectObjectApply             DontEnum|Function 3
     deleteProperty    reflectObjectDeleteProperty    DontEnum|Function 2
+    enumerate         reflectObjectEnumerate         DontEnum|Function 1
     isExtensible      reflectObjectIsExtensible      DontEnum|Function 1
     ownKeys           reflectObjectOwnKeys           DontEnum|Function 1
     preventExtensions reflectObjectPreventExtensions DontEnum|Function 1
@@ -74,6 +77,14 @@ bool ReflectObject::getOwnPropertySlot(JSObject* object, ExecState* exec, Proper
 
 // ------------------------------ Functions --------------------------------
 
+EncodedJSValue JSC_HOST_CALL reflectObjectEnumerate(ExecState* exec)
+{
+    JSValue target = exec->argument(0);
+    if (!target.isObject())
+        return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.enumerate requires the first argument be an object")));
+    return JSValue::encode(JSPropertyNameIterator::create(exec, exec->lexicalGlobalObject()->propertyNameIteratorStructure(), asObject(target)));
+}
+
 EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState* exec)
 {
     JSValue target = exec->argument(0);
diff --git a/Source/JavaScriptCore/tests/stress/reflect-enumerate.js b/Source/JavaScriptCore/tests/stress/reflect-enumerate.js
new file mode 100644 (file)
index 0000000..4ffe168
--- /dev/null
@@ -0,0 +1,54 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, message) {
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        error = e;
+    }
+    if (!error)
+        throw new Error("not thrown.");
+    if (String(error) !== message)
+        throw new Error("bad error: " + String(error));
+}
+
+shouldBe(Reflect.enumerate.length, 1);
+
+shouldThrow(() => {
+    Reflect.enumerate("hello");
+}, `TypeError: Reflect.enumerate requires the first argument be an object`);
+
+var iterator = Reflect.enumerate({});
+var iteratorPrototype = [][Symbol.iterator]().__proto__.__proto__;
+shouldBe(iterator.__proto__ === iteratorPrototype, true);
+shouldBe(iterator.hasOwnProperty('next'), true);
+shouldBe(iterator.next.length, 0);
+shouldBe(iterator[Symbol.iterator]() === iterator, true);
+
+function testIterator(object, expected) {
+    var index = 0;
+    for (var name of Reflect.enumerate(object))
+        shouldBe(name === expected[index++], true);
+    shouldBe(index, expected.length);
+}
+
+testIterator({ hello:42, 0: 0 }, ['0', 'hello']);
+testIterator({ 1:1, hello:42, 0: 0 }, ['0', '1', 'hello']);
+testIterator({ 1:1, hello:42, 0: 0, world: 'ok', 100000:0 }, ['0', '1', '100000', 'hello', 'world']);
+
+testIterator({ 1:1, hello:42, 0: 0, [Symbol.unscopables]: 42, world: 'ok', 100000:0 }, ['0', '1', '100000', 'hello', 'world']);
+
+var object = { 1:1, hello:42, 0: 0, [Symbol.unscopables]: 42, world: 'ok', 100000:0 };
+Object.defineProperty(object, 'hidden', {
+    value: 42,
+    enumerable: false
+});
+testIterator(object, ['0', '1', '100000', 'hello', 'world']);
+
+testIterator({ hello:42, 0: 0, __proto__: { 1: 1, world: 42 } }, ['0', 'hello', '1', 'world']);
+testIterator({}, []);
+testIterator([], []);