1/*
2 * Copyright (C) 2003, 2008 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 COMPUTER, 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 COMPUTER, 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 "runtime_array.h"
28
29#include <runtime/ArrayPrototype.h>
30#include <runtime/Error.h>
31#include <runtime/PropertyNameArray.h>
32#include "JSDOMBinding.h"
33
34using namespace WebCore;
35
36namespace JSC {
37
38const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(RuntimeArray) };
39
40RuntimeArray::RuntimeArray(ExecState* exec, Structure* structure)
41    : JSArray(exec->vm(), structure, 0)
42    , m_array(0)
43{
44}
45
46void RuntimeArray::finishCreation(VM& vm, Bindings::Array* array)
47{
48    Base::finishCreation(vm);
49    ASSERT(inherits(&s_info));
50    m_array = array;
51}
52
53RuntimeArray::~RuntimeArray()
54{
55    delete getConcreteArray();
56}
57
58void RuntimeArray::destroy(JSCell* cell)
59{
60    static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
61}
62
63JSValue RuntimeArray::lengthGetter(ExecState*, JSValue slotBase, PropertyName)
64{
65    RuntimeArray* thisObj = static_cast<RuntimeArray*>(asObject(slotBase));
66    return jsNumber(thisObj->getLength());
67}
68
69JSValue RuntimeArray::indexGetter(ExecState* exec, JSValue slotBase, unsigned index)
70{
71    RuntimeArray* thisObj = static_cast<RuntimeArray*>(asObject(slotBase));
72    return thisObj->getConcreteArray()->valueAt(exec, index);
73}
74
75void RuntimeArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
76{
77    RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
78    unsigned length = thisObject->getLength();
79    for (unsigned i = 0; i < length; ++i)
80        propertyNames.add(Identifier::from(exec, i));
81
82    if (mode == IncludeDontEnumProperties)
83        propertyNames.add(exec->propertyNames().length);
84
85    JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
86}
87
88bool RuntimeArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
89{
90    RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell);
91    if (propertyName == exec->propertyNames().length) {
92        slot.setCacheableCustom(thisObject, thisObject->lengthGetter);
93        return true;
94    }
95
96    unsigned index = propertyName.asIndex();
97    if (index < thisObject->getLength()) {
98        ASSERT(index != PropertyName::NotAnIndex);
99        slot.setCustomIndex(thisObject, index, thisObject->indexGetter);
100        return true;
101    }
102
103    return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
104}
105
106bool RuntimeArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
107{
108    RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
109    if (propertyName == exec->propertyNames().length) {
110        PropertySlot slot;
111        slot.setCustom(thisObject, lengthGetter);
112        descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum);
113        return true;
114    }
115
116    unsigned index = propertyName.asIndex();
117    if (index < thisObject->getLength()) {
118        ASSERT(index != PropertyName::NotAnIndex);
119        PropertySlot slot;
120        slot.setCustomIndex(thisObject, index, indexGetter);
121        descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | DontEnum);
122        return true;
123    }
124
125    return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
126}
127
128bool RuntimeArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState *exec, unsigned index, PropertySlot& slot)
129{
130    RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell);
131    if (index < thisObject->getLength()) {
132        slot.setCustomIndex(thisObject, index, thisObject->indexGetter);
133        return true;
134    }
135
136    return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
137}
138
139void RuntimeArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
140{
141    RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell);
142    if (propertyName == exec->propertyNames().length) {
143        throwError(exec, createRangeError(exec, "Range error"));
144        return;
145    }
146
147    unsigned index = propertyName.asIndex();
148    if (index != PropertyName::NotAnIndex) {
149        thisObject->getConcreteArray()->setValueAt(exec, index, value);
150        return;
151    }
152
153    JSObject::put(thisObject, exec, propertyName, value, slot);
154}
155
156void RuntimeArray::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool)
157{
158    RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell);
159    if (index >= thisObject->getLength()) {
160        throwError(exec, createRangeError(exec, "Range error"));
161        return;
162    }
163
164    thisObject->getConcreteArray()->setValueAt(exec, index, value);
165}
166
167bool RuntimeArray::deleteProperty(JSCell*, ExecState*, PropertyName)
168{
169    return false;
170}
171
172bool RuntimeArray::deletePropertyByIndex(JSCell*, ExecState*, unsigned)
173{
174    return false;
175}
176
177}
178