]>
Commit | Line | Data |
---|---|---|
f9bf01c6 A |
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 "Operations.h" | |
34 | ||
35 | namespace JSC { | |
36 | unsigned PropertyDescriptor::defaultAttributes = (DontDelete << 1) - 1; | |
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 | ||
6fe7ccc8 A |
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 | ||
f9bf01c6 A |
99 | void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) |
100 | { | |
101 | ASSERT(value); | |
6fe7ccc8 A |
102 | ASSERT(value.isGetterSetter() == !!(attributes & Accessor)); |
103 | ||
f9bf01c6 | 104 | m_attributes = attributes; |
6fe7ccc8 A |
105 | if (value.isGetterSetter()) { |
106 | m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! | |
107 | ||
f9bf01c6 | 108 | GetterSetter* accessor = asGetterSetter(value); |
6fe7ccc8 A |
109 | m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); |
110 | m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); | |
f9bf01c6 | 111 | m_seenAttributes = EnumerablePresent | ConfigurablePresent; |
f9bf01c6 A |
112 | } else { |
113 | m_value = value; | |
114 | m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent; | |
115 | } | |
116 | } | |
117 | ||
6fe7ccc8 | 118 | void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes) |
f9bf01c6 | 119 | { |
6fe7ccc8 A |
120 | ASSERT(attributes & Accessor); |
121 | attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this! | |
122 | ||
f9bf01c6 | 123 | m_attributes = attributes; |
6fe7ccc8 A |
124 | m_getter = accessor->getter() ? accessor->getter() : jsUndefined(); |
125 | m_setter = accessor->setter() ? accessor->setter() : jsUndefined(); | |
f9bf01c6 A |
126 | m_seenAttributes = EnumerablePresent | ConfigurablePresent; |
127 | } | |
128 | ||
129 | void PropertyDescriptor::setWritable(bool writable) | |
130 | { | |
131 | if (writable) | |
132 | m_attributes &= ~ReadOnly; | |
133 | else | |
134 | m_attributes |= ReadOnly; | |
135 | m_seenAttributes |= WritablePresent; | |
136 | } | |
137 | ||
138 | void PropertyDescriptor::setEnumerable(bool enumerable) | |
139 | { | |
140 | if (enumerable) | |
141 | m_attributes &= ~DontEnum; | |
142 | else | |
143 | m_attributes |= DontEnum; | |
144 | m_seenAttributes |= EnumerablePresent; | |
145 | } | |
146 | ||
147 | void PropertyDescriptor::setConfigurable(bool configurable) | |
148 | { | |
149 | if (configurable) | |
150 | m_attributes &= ~DontDelete; | |
151 | else | |
152 | m_attributes |= DontDelete; | |
153 | m_seenAttributes |= ConfigurablePresent; | |
154 | } | |
155 | ||
156 | void PropertyDescriptor::setSetter(JSValue setter) | |
157 | { | |
158 | m_setter = setter; | |
6fe7ccc8 | 159 | m_attributes |= Accessor; |
f9bf01c6 A |
160 | m_attributes &= ~ReadOnly; |
161 | } | |
162 | ||
163 | void PropertyDescriptor::setGetter(JSValue getter) | |
164 | { | |
165 | m_getter = getter; | |
6fe7ccc8 | 166 | m_attributes |= Accessor; |
f9bf01c6 A |
167 | m_attributes &= ~ReadOnly; |
168 | } | |
169 | ||
6fe7ccc8 A |
170 | // See ES5.1 9.12 |
171 | bool sameValue(ExecState* exec, JSValue a, JSValue b) | |
172 | { | |
173 | if (!a.isNumber()) | |
174 | return JSValue::strictEqual(exec, a, b); | |
175 | if (!b.isNumber()) | |
176 | return false; | |
177 | double x = a.asNumber(); | |
178 | double y = b.asNumber(); | |
179 | if (isnan(x)) | |
180 | return isnan(y); | |
181 | return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y); | |
182 | } | |
183 | ||
f9bf01c6 A |
184 | bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const |
185 | { | |
186 | if (!other.m_value == m_value || | |
187 | !other.m_getter == m_getter || | |
188 | !other.m_setter == m_setter) | |
189 | return false; | |
6fe7ccc8 A |
190 | return (!m_value || sameValue(exec, other.m_value, m_value)) |
191 | && (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter)) | |
192 | && (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter)) | |
193 | && attributesEqual(other); | |
f9bf01c6 A |
194 | } |
195 | ||
196 | bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const | |
197 | { | |
198 | unsigned mismatch = other.m_attributes ^ m_attributes; | |
199 | unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes; | |
200 | if (sharedSeen & WritablePresent && mismatch & ReadOnly) | |
201 | return false; | |
202 | if (sharedSeen & ConfigurablePresent && mismatch & DontDelete) | |
203 | return false; | |
204 | if (sharedSeen & EnumerablePresent && mismatch & DontEnum) | |
205 | return false; | |
206 | return true; | |
207 | } | |
208 | ||
6fe7ccc8 A |
209 | unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const |
210 | { | |
211 | unsigned currentAttributes = current.m_attributes; | |
212 | if (isDataDescriptor() && current.isAccessorDescriptor()) | |
213 | currentAttributes |= ReadOnly; | |
214 | unsigned overrideMask = 0; | |
215 | if (writablePresent()) | |
216 | overrideMask |= ReadOnly; | |
217 | if (enumerablePresent()) | |
218 | overrideMask |= DontEnum; | |
219 | if (configurablePresent()) | |
220 | overrideMask |= DontDelete; | |
221 | if (isAccessorDescriptor()) | |
222 | overrideMask |= Accessor; | |
223 | return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask); | |
f9bf01c6 A |
224 | } |
225 | ||
226 | } |