]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - runtime/PropertyDescriptor.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / PropertyDescriptor.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2009 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
27#include "config.h"
28
29#include "PropertyDescriptor.h"
30
31#include "GetterSetter.h"
32#include "JSObject.h"
33#include "JSCInlines.h"
34
35namespace JSC {
36unsigned PropertyDescriptor::defaultAttributes = DontDelete | DontEnum | ReadOnly;
37
38bool PropertyDescriptor::writable() const
39{
40 ASSERT(!isAccessorDescriptor());
41 return !(m_attributes & ReadOnly);
42}
43
44bool PropertyDescriptor::enumerable() const
45{
46 return !(m_attributes & DontEnum);
47}
48
49bool PropertyDescriptor::configurable() const
50{
51 return !(m_attributes & DontDelete);
52}
53
54bool PropertyDescriptor::isDataDescriptor() const
55{
56 return m_value || (m_seenAttributes & WritablePresent);
57}
58
59bool PropertyDescriptor::isGenericDescriptor() const
60{
61 return !isAccessorDescriptor() && !isDataDescriptor();
62}
63
64bool PropertyDescriptor::isAccessorDescriptor() const
65{
66 return m_getter || m_setter;
67}
68
69void PropertyDescriptor::setUndefined()
70{
71 m_value = jsUndefined();
72 m_attributes = ReadOnly | DontDelete | DontEnum;
73}
74
75JSValue PropertyDescriptor::getter() const
76{
77 ASSERT(isAccessorDescriptor());
78 return m_getter;
79}
80
81JSValue PropertyDescriptor::setter() const
82{
83 ASSERT(isAccessorDescriptor());
84 return m_setter;
85}
86
87JSObject* PropertyDescriptor::getterObject() const
88{
89 ASSERT(isAccessorDescriptor() && getterPresent());
90 return m_getter.isObject() ? asObject(m_getter) : 0;
91}
92
93JSObject* PropertyDescriptor::setterObject() const
94{
95 ASSERT(isAccessorDescriptor() && setterPresent());
96 return m_setter.isObject() ? asObject(m_setter) : 0;
97}
98
99void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
100{
101 ASSERT(value);
102 ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
103
104 m_attributes = attributes;
105 if (value.isGetterSetter()) {
106 m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
107
108 GetterSetter* accessor = asGetterSetter(value);
109 m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
110 m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
111 m_seenAttributes = EnumerablePresent | ConfigurablePresent;
112 } else {
113 m_value = value;
114 m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent;
115 }
116}
117
118void PropertyDescriptor::setCustomDescriptor(unsigned attributes)
119{
120 m_attributes = attributes | Accessor | CustomAccessor;
121 m_attributes &= ~ReadOnly;
122 m_seenAttributes = EnumerablePresent | ConfigurablePresent;
123 setGetter(jsUndefined());
124 setSetter(jsUndefined());
125 m_value = JSValue();
126}
127
128void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes)
129{
130 ASSERT(attributes & Accessor);
131 attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
132
133 m_attributes = attributes;
134 m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
135 m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
136 m_seenAttributes = EnumerablePresent | ConfigurablePresent;
137}
138
139void PropertyDescriptor::setWritable(bool writable)
140{
141 if (writable)
142 m_attributes &= ~ReadOnly;
143 else
144 m_attributes |= ReadOnly;
145 m_seenAttributes |= WritablePresent;
146}
147
148void PropertyDescriptor::setEnumerable(bool enumerable)
149{
150 if (enumerable)
151 m_attributes &= ~DontEnum;
152 else
153 m_attributes |= DontEnum;
154 m_seenAttributes |= EnumerablePresent;
155}
156
157void PropertyDescriptor::setConfigurable(bool configurable)
158{
159 if (configurable)
160 m_attributes &= ~DontDelete;
161 else
162 m_attributes |= DontDelete;
163 m_seenAttributes |= ConfigurablePresent;
164}
165
166void PropertyDescriptor::setSetter(JSValue setter)
167{
168 m_setter = setter;
169 m_attributes |= Accessor;
170 m_attributes &= ~ReadOnly;
171}
172
173void PropertyDescriptor::setGetter(JSValue getter)
174{
175 m_getter = getter;
176 m_attributes |= Accessor;
177 m_attributes &= ~ReadOnly;
178}
179
180// See ES5.1 9.12
181bool sameValue(ExecState* exec, JSValue a, JSValue b)
182{
183 if (!a.isNumber())
184 return JSValue::strictEqual(exec, a, b);
185 if (!b.isNumber())
186 return false;
187 double x = a.asNumber();
188 double y = b.asNumber();
189 bool xIsNaN = std::isnan(x);
190 bool yIsNaN = std::isnan(y);
191 if (xIsNaN || yIsNaN)
192 return xIsNaN && yIsNaN;
193 return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y);
194}
195
196bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const
197{
198 if (other.m_value.isEmpty() != m_value.isEmpty()
199 || other.m_getter.isEmpty() != m_getter.isEmpty()
200 || other.m_setter.isEmpty() != m_setter.isEmpty())
201 return false;
202 return (!m_value || sameValue(exec, other.m_value, m_value))
203 && (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter))
204 && (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter))
205 && attributesEqual(other);
206}
207
208bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const
209{
210 unsigned mismatch = other.m_attributes ^ m_attributes;
211 unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes;
212 if (sharedSeen & WritablePresent && mismatch & ReadOnly)
213 return false;
214 if (sharedSeen & ConfigurablePresent && mismatch & DontDelete)
215 return false;
216 if (sharedSeen & EnumerablePresent && mismatch & DontEnum)
217 return false;
218 return true;
219}
220
221unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const
222{
223 unsigned currentAttributes = current.m_attributes;
224 if (isDataDescriptor() && current.isAccessorDescriptor())
225 currentAttributes |= ReadOnly;
226 unsigned overrideMask = 0;
227 if (writablePresent())
228 overrideMask |= ReadOnly;
229 if (enumerablePresent())
230 overrideMask |= DontEnum;
231 if (configurablePresent())
232 overrideMask |= DontDelete;
233 if (isAccessorDescriptor())
234 overrideMask |= Accessor;
235 return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask);
236}
237
238}