[ES6] Implement Reflect.enumerate
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSPropertyNameIterator.cpp
1 /*
2  * Copyright (C) 2015 Apple, Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSPropertyNameIterator.h"
28
29 #include "IdentifierInlines.h"
30 #include "IteratorOperations.h"
31 #include "JSCJSValueInlines.h"
32 #include "JSCellInlines.h"
33 #include "JSPropertyNameEnumerator.h"
34 #include "SlotVisitorInlines.h"
35 #include "StructureInlines.h"
36
37 namespace JSC {
38
39 static EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState*);
40
41 const ClassInfo JSPropertyNameIterator::s_info = { "PropertyName Iterator", &Base::s_info, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) };
42
43 JSPropertyNameIterator::JSPropertyNameIterator(VM& vm, Structure* structure, JSObject* object, JSPropertyNameEnumerator* enumerator)
44     : Base(vm, structure)
45     , m_iteratedObject(vm, this, object)
46     , m_propertyNameEnumerator(vm, this, enumerator)
47     , m_enumerationPhase(EnumerationPhase::IndexedNames)
48     , m_cursor(0)
49 {
50 }
51
52 JSPropertyNameIterator* JSPropertyNameIterator::clone(ExecState* exec)
53 {
54     auto iterator = JSPropertyNameIterator::create(exec, exec->callee()->globalObject()->propertyNameIteratorStructure(), m_iteratedObject.get(), m_propertyNameEnumerator.get());
55     iterator->m_enumerationPhase = m_enumerationPhase;
56     iterator->m_cursor = m_cursor;
57     return iterator;
58 }
59
60 JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject)
61 {
62     return JSPropertyNameIterator::create(exec, structure, iteratedObject, propertyNameEnumerator(exec, iteratedObject));
63 }
64
65 JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject, JSPropertyNameEnumerator* enumerator)
66 {
67     VM& vm = exec->vm();
68     JSPropertyNameIterator* instance = new (NotNull, allocateCell<JSPropertyNameIterator>(vm.heap)) JSPropertyNameIterator(vm, structure, iteratedObject, enumerator);
69     instance->finishCreation(vm, structure->globalObject());
70     return instance;
71 }
72
73 void JSPropertyNameIterator::finishCreation(VM& vm, JSGlobalObject* globalObject)
74 {
75     Base::finishCreation(vm);
76     ASSERT(inherits(info()));
77     JSC_NATIVE_FUNCTION(vm.propertyNames->next, propertyNameIteratorFuncNext, DontEnum, 0);
78 }
79
80 void JSPropertyNameIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
81 {
82     JSPropertyNameIterator* thisObject = jsCast<JSPropertyNameIterator*>(cell);
83     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
84     Base::visitChildren(thisObject, visitor);
85     visitor.append(&thisObject->m_iteratedObject);
86     visitor.append(&thisObject->m_propertyNameEnumerator);
87 }
88
89 bool JSPropertyNameIterator::next(ExecState* exec, JSValue& output)
90 {
91     if (m_enumerationPhase == EnumerationPhase::IndexedNames) {
92         for (; m_cursor < m_propertyNameEnumerator->indexedLength();) {
93             uint32_t index = m_cursor++;
94             if (m_iteratedObject->hasProperty(exec, index)) {
95                 output = jsString(exec, Identifier::from(exec, index).string());
96                 return true;
97             }
98         }
99         m_cursor = 0;
100         m_enumerationPhase = EnumerationPhase::StructureNames;
101     }
102
103     if (m_enumerationPhase == EnumerationPhase::StructureNames) {
104         for (; m_cursor < m_propertyNameEnumerator->endStructurePropertyIndex();) {
105             uint32_t index = m_cursor++;
106             JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
107             ASSERT(propertyName);
108             if (m_iteratedObject->structure(exec->vm())->id() == m_propertyNameEnumerator->cachedStructureID()) {
109                 output = propertyName;
110                 return true;
111             }
112
113             if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
114                 output = propertyName;
115                 return true;
116             }
117         }
118         ASSERT(m_cursor >= m_propertyNameEnumerator->endStructurePropertyIndex());
119         // Use the same m_cursor in the GenericNames phase.
120         m_enumerationPhase = EnumerationPhase::GenericNames;
121     }
122
123     if (m_enumerationPhase == EnumerationPhase::GenericNames) {
124         for (; m_cursor < m_propertyNameEnumerator->endGenericPropertyIndex();) {
125             uint32_t index = m_cursor++;
126             JSString* propertyName = m_propertyNameEnumerator->propertyNameAtIndex(index);
127             ASSERT(propertyName);
128             if (m_iteratedObject->hasProperty(exec, propertyName->toIdentifier(exec))) {
129                 output = propertyName;
130                 return true;
131             }
132         }
133         m_enumerationPhase = EnumerationPhase::Done;
134     }
135
136     return false;
137 }
138
139 // ------------------------------ PropertyNameIterator Functions ----------------------------
140
141 EncodedJSValue JSC_HOST_CALL propertyNameIteratorFuncNext(ExecState* exec)
142 {
143     JSPropertyNameIterator* iterator = jsDynamicCast<JSPropertyNameIterator*>(exec->thisValue());
144     if (!iterator)
145         return JSValue::encode(throwTypeError(exec, ASCIILiteral("Cannot call PropertyNameIterator.next() on a non-PropertyNameIterator object")));
146
147     JSValue result;
148     if (iterator->next(exec, result))
149         return JSValue::encode(createIteratorResultObject(exec, result, false));
150     return JSValue::encode(createIteratorResultObject(exec, jsUndefined(), true));
151 }
152
153 } // namespace JSC