2 * Copyright (C) 2013 Apple, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "JSArrayIterator.h"
29 #include "JSCJSValueInlines.h"
30 #include "JSCellInlines.h"
31 #include "SlotVisitorInlines.h"
32 #include "StructureInlines.h"
36 const ClassInfo
JSArrayIterator::s_info
= { "ArrayIterator", &Base::s_info
, 0, 0, CREATE_METHOD_TABLE(JSArrayIterator
) };
38 static EncodedJSValue JSC_HOST_CALL
arrayIteratorNextKey(ExecState
*);
39 static EncodedJSValue JSC_HOST_CALL
arrayIteratorNextValue(ExecState
*);
40 static EncodedJSValue JSC_HOST_CALL
arrayIteratorNextGeneric(ExecState
*);
42 void JSArrayIterator::finishCreation(VM
& vm
, JSGlobalObject
* globalObject
, ArrayIterationKind kind
, JSObject
* iteratedObject
)
44 Base::finishCreation(vm
);
45 ASSERT(inherits(info()));
46 m_iterationKind
= kind
;
47 m_iteratedObject
.set(vm
, this, iteratedObject
);
50 JSC_NATIVE_INTRINSIC_FUNCTION(vm
.propertyNames
->iteratorNextPrivateName
, arrayIteratorNextKey
, DontEnum
, 0, ArrayIteratorNextKeyIntrinsic
);
52 case ArrayIterateValue
:
53 JSC_NATIVE_INTRINSIC_FUNCTION(vm
.propertyNames
->iteratorNextPrivateName
, arrayIteratorNextValue
, DontEnum
, 0, ArrayIteratorNextValueIntrinsic
);
56 JSC_NATIVE_INTRINSIC_FUNCTION(vm
.propertyNames
->iteratorNextPrivateName
, arrayIteratorNextGeneric
, DontEnum
, 0, ArrayIteratorNextGenericIntrinsic
);
63 void JSArrayIterator::visitChildren(JSCell
* cell
, SlotVisitor
& visitor
)
65 JSArrayIterator
* thisObject
= jsCast
<JSArrayIterator
*>(cell
);
66 ASSERT_GC_OBJECT_INHERITS(thisObject
, info());
67 COMPILE_ASSERT(StructureFlags
& OverridesVisitChildren
, OverridesVisitChildrenWithoutSettingFlag
);
68 ASSERT(thisObject
->structure()->typeInfo().overridesVisitChildren());
70 Base::visitChildren(thisObject
, visitor
);
71 visitor
.append(&thisObject
->m_iteratedObject
);
75 static EncodedJSValue
createIteratorResult(CallFrame
* callFrame
, ArrayIterationKind kind
, size_t index
, JSValue result
, bool done
)
78 return JSValue::encode(callFrame
->vm().iterationTerminator
.get());
80 switch (kind
& ~ArrayIterateSparseTag
) {
82 return JSValue::encode(jsNumber(index
));
84 case ArrayIterateValue
:
85 return JSValue::encode(result
);
87 case ArrayIterateKeyValue
: {
88 MarkedArgumentBuffer args
;
89 args
.append(jsNumber(index
));
91 JSGlobalObject
* globalObject
= callFrame
->callee()->globalObject();
92 return JSValue::encode(constructArray(callFrame
, 0, globalObject
, args
));
96 RELEASE_ASSERT_NOT_REACHED();
98 return JSValue::encode(JSValue());
101 static inline EncodedJSValue JSC_HOST_CALL
arrayIteratorNext(CallFrame
* callFrame
)
103 JSArrayIterator
* iterator
= jsDynamicCast
<JSArrayIterator
*>(callFrame
->thisValue());
105 ASSERT_NOT_REACHED();
106 return JSValue::encode(throwTypeError(callFrame
, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object")));
108 JSObject
* iteratedObject
= iterator
->iteratedObject();
109 size_t index
= iterator
->nextIndex();
110 ArrayIterationKind kind
= iterator
->iterationKind();
111 JSValue jsLength
= JSValue(iteratedObject
).get(callFrame
, callFrame
->propertyNames().length
);
112 if (callFrame
->hadException())
113 return JSValue::encode(jsNull());
115 size_t length
= jsLength
.toUInt32(callFrame
);
116 if (callFrame
->hadException())
117 return JSValue::encode(jsNull());
119 if (index
>= length
) {
121 return createIteratorResult(callFrame
, kind
, index
, jsUndefined(), true);
123 if (JSValue result
= iteratedObject
->tryGetIndexQuickly(index
)) {
124 iterator
->setNextIndex(index
+ 1);
125 return createIteratorResult(callFrame
, kind
, index
, result
, false);
128 JSValue result
= jsUndefined();
129 PropertySlot
slot(iteratedObject
);
130 if (kind
> ArrayIterateSparseTag
) {
131 // We assume that the indexed property will be an own property so cache the getOwnProperty
133 auto getOwnPropertySlotByIndex
= iteratedObject
->methodTable()->getOwnPropertySlotByIndex
;
134 while (index
< length
) {
135 if (getOwnPropertySlotByIndex(iteratedObject
, callFrame
, index
, slot
)) {
136 result
= slot
.getValue(callFrame
, index
);
139 if (iteratedObject
->getPropertySlot(callFrame
, index
, slot
)) {
140 result
= slot
.getValue(callFrame
, index
);
145 } else if (iteratedObject
->getPropertySlot(callFrame
, index
, slot
))
146 result
= slot
.getValue(callFrame
, index
);
151 iterator
->setNextIndex(index
+ 1);
152 return createIteratorResult(callFrame
, kind
, index
, jsUndefined(), index
== length
);
155 EncodedJSValue JSC_HOST_CALL
arrayIteratorNextKey(CallFrame
* callFrame
)
157 return arrayIteratorNext(callFrame
);
160 EncodedJSValue JSC_HOST_CALL
arrayIteratorNextValue(CallFrame
* callFrame
)
162 return arrayIteratorNext(callFrame
);
165 EncodedJSValue JSC_HOST_CALL
arrayIteratorNextGeneric(CallFrame
* callFrame
)
167 return arrayIteratorNext(callFrame
);