1/*
2 * Copyright (C) 2003, 2008, 2016 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 "runtime_array.h"
28
29#include "JSDOMBinding.h"
30#include <JavaScriptCore/ArrayPrototype.h>
31#include <JavaScriptCore/Error.h>
32#include <JavaScriptCore/PropertyNameArray.h>
33
34using namespace WebCore;
35
36namespace JSC {
37
38const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, nullptr, nullptr, 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(vm, 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
63EncodedJSValue RuntimeArray::lengthGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName)
64{
65 VM& vm = exec->vm();
66 auto scope = DECLARE_THROW_SCOPE(vm);
67
68 RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(vm, JSValue::decode(thisValue));
69 if (!thisObject)
70 return throwVMTypeError(exec, scope);
71 return JSValue::encode(jsNumber(thisObject->getLength()));
72}
73
74void RuntimeArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
75{
76 VM& vm = exec->vm();
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(vm.propertyNames->length);
84
85 JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
86}
87
88bool RuntimeArray::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
89{
90 VM& vm = exec->vm();
91 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
92 if (propertyName == vm.propertyNames->length) {
93 slot.setCacheableCustom(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum, thisObject->lengthGetter);
94 return true;
95 }
96
97 Optional<uint32_t> index = parseIndex(propertyName);
98 if (index && index.value() < thisObject->getLength()) {
99 slot.setValue(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum,
100 thisObject->getConcreteArray()->valueAt(exec, index.value()));
101 return true;
102 }
103
104 return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
105}
106
107bool RuntimeArray::getOwnPropertySlotByIndex(JSObject* object, ExecState *exec, unsigned index, PropertySlot& slot)
108{
109 RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
110 if (index < thisObject->getLength()) {
111 slot.setValue(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum,
112 thisObject->getConcreteArray()->valueAt(exec, index));
113 return true;
114 }
115
116 return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
117}
118
119bool RuntimeArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
120{
121 VM& vm = exec->vm();
122 auto scope = DECLARE_THROW_SCOPE(vm);
123
124 RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell);
125 if (propertyName == vm.propertyNames->length) {
126 throwException(exec, scope, createRangeError(exec, "Range error"));
127 return false;
128 }
129
130 if (Optional<uint32_t> index = parseIndex(propertyName))
131 return thisObject->getConcreteArray()->setValueAt(exec, index.value(), value);
132
133 RELEASE_AND_RETURN(scope, JSObject::put(thisObject, exec, propertyName, value, slot));
134}
135
136bool RuntimeArray::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool)
137{
138 VM& vm = exec->vm();
139 auto scope = DECLARE_THROW_SCOPE(vm);
140
141 RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell);
142 if (index >= thisObject->getLength()) {
143 throwException(exec, scope, createRangeError(exec, "Range error"));
144 return false;
145 }
146
147 return thisObject->getConcreteArray()->setValueAt(exec, index, value);
148}
149
150bool RuntimeArray::deleteProperty(JSCell*, ExecState*, PropertyName)
151{
152 return false;
153}
154
155bool RuntimeArray::deletePropertyByIndex(JSCell*, ExecState*, unsigned)
156{
157 return false;
158}
159
160}
161