]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/PropertyDescriptor.cpp
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / runtime / PropertyDescriptor.cpp
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
35 namespace JSC {
36 unsigned PropertyDescriptor::defaultAttributes = DontDelete | DontEnum | ReadOnly;
37
38 bool PropertyDescriptor::writable() const
39 {
40 ASSERT(!isAccessorDescriptor());
41 return !(m_attributes & ReadOnly);
42 }
43
44 bool PropertyDescriptor::enumerable() const
45 {
46 return !(m_attributes & DontEnum);
47 }
48
49 bool PropertyDescriptor::configurable() const
50 {
51 return !(m_attributes & DontDelete);
52 }
53
54 bool PropertyDescriptor::isDataDescriptor() const
55 {
56 return m_value || (m_seenAttributes & WritablePresent);
57 }
58
59 bool PropertyDescriptor::isGenericDescriptor() const
60 {
61 return !isAccessorDescriptor() && !isDataDescriptor();
62 }
63
64 bool PropertyDescriptor::isAccessorDescriptor() const
65 {
66 return m_getter || m_setter;
67 }
68
69 void PropertyDescriptor::setUndefined()
70 {
71 m_value = jsUndefined();
72 m_attributes = ReadOnly | DontDelete | DontEnum;
73 }
74
75 JSValue PropertyDescriptor::getter() const
76 {
77 ASSERT(isAccessorDescriptor());
78 return m_getter;
79 }
80
81 JSValue PropertyDescriptor::setter() const
82 {
83 ASSERT(isAccessorDescriptor());
84 return m_setter;
85 }
86
87 JSObject* PropertyDescriptor::getterObject() const
88 {
89 ASSERT(isAccessorDescriptor() && getterPresent());
90 return m_getter.isObject() ? asObject(m_getter) : 0;
91 }
92
93 JSObject* PropertyDescriptor::setterObject() const
94 {
95 ASSERT(isAccessorDescriptor() && setterPresent());
96 return m_setter.isObject() ? asObject(m_setter) : 0;
97 }
98
99 void 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->getter() ? accessor->getter() : jsUndefined();
110 m_setter = accessor->setter() ? accessor->setter() : jsUndefined();
111 m_seenAttributes = EnumerablePresent | ConfigurablePresent;
112 } else {
113 m_value = value;
114 m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent;
115 }
116 }
117
118 void 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
128 void 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->getter() ? accessor->getter() : jsUndefined();
135 m_setter = accessor->setter() ? accessor->setter() : jsUndefined();
136 m_seenAttributes = EnumerablePresent | ConfigurablePresent;
137 }
138
139 void PropertyDescriptor::setWritable(bool writable)
140 {
141 if (writable)
142 m_attributes &= ~ReadOnly;
143 else
144 m_attributes |= ReadOnly;
145 m_seenAttributes |= WritablePresent;
146 }
147
148 void PropertyDescriptor::setEnumerable(bool enumerable)
149 {
150 if (enumerable)
151 m_attributes &= ~DontEnum;
152 else
153 m_attributes |= DontEnum;
154 m_seenAttributes |= EnumerablePresent;
155 }
156
157 void PropertyDescriptor::setConfigurable(bool configurable)
158 {
159 if (configurable)
160 m_attributes &= ~DontDelete;
161 else
162 m_attributes |= DontDelete;
163 m_seenAttributes |= ConfigurablePresent;
164 }
165
166 void PropertyDescriptor::setSetter(JSValue setter)
167 {
168 m_setter = setter;
169 m_attributes |= Accessor;
170 m_attributes &= ~ReadOnly;
171 }
172
173 void 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
181 bool 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 if (std::isnan(x))
190 return std::isnan(y);
191 return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y);
192 }
193
194 bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const
195 {
196 if (other.m_value.isEmpty() != m_value.isEmpty()
197 || other.m_getter.isEmpty() != m_getter.isEmpty()
198 || other.m_setter.isEmpty() != m_setter.isEmpty())
199 return false;
200 return (!m_value || sameValue(exec, other.m_value, m_value))
201 && (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter))
202 && (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter))
203 && attributesEqual(other);
204 }
205
206 bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const
207 {
208 unsigned mismatch = other.m_attributes ^ m_attributes;
209 unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes;
210 if (sharedSeen & WritablePresent && mismatch & ReadOnly)
211 return false;
212 if (sharedSeen & ConfigurablePresent && mismatch & DontDelete)
213 return false;
214 if (sharedSeen & EnumerablePresent && mismatch & DontEnum)
215 return false;
216 return true;
217 }
218
219 unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const
220 {
221 unsigned currentAttributes = current.m_attributes;
222 if (isDataDescriptor() && current.isAccessorDescriptor())
223 currentAttributes |= ReadOnly;
224 unsigned overrideMask = 0;
225 if (writablePresent())
226 overrideMask |= ReadOnly;
227 if (enumerablePresent())
228 overrideMask |= DontEnum;
229 if (configurablePresent())
230 overrideMask |= DontDelete;
231 if (isAccessorDescriptor())
232 overrideMask |= Accessor;
233 return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask);
234 }
235
236 }