PropertyAttribute needs a CustomValue bit.
[WebKit-https.git] / Source / JavaScriptCore / runtime / PropertyDescriptor.cpp
1 /*
2  * Copyright (C) 2009, 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
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 = PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly;
37
38 bool PropertyDescriptor::writable() const
39 {
40     ASSERT(!isAccessorDescriptor());
41     return !(m_attributes & PropertyAttribute::ReadOnly);
42 }
43
44 bool PropertyDescriptor::enumerable() const
45 {
46     return !(m_attributes & PropertyAttribute::DontEnum);
47 }
48
49 bool PropertyDescriptor::configurable() const
50 {
51     return !(m_attributes & PropertyAttribute::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 = PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete | PropertyAttribute::DontEnum;
73 }
74
75 GetterSetter* PropertyDescriptor::slowGetterSetter(ExecState* exec)
76 {
77     VM& vm = exec->vm();
78     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
79     JSValue getter = m_getter && !m_getter.isUndefined() ? jsCast<JSObject*>(m_getter) : jsUndefined();
80     JSValue setter = m_setter && !m_setter.isUndefined() ? jsCast<JSObject*>(m_setter) : jsUndefined();
81     return GetterSetter::create(vm, globalObject, getter, setter);
82 }
83
84 JSValue PropertyDescriptor::getter() const
85 {
86     ASSERT(isAccessorDescriptor());
87     return m_getter;
88 }
89
90 JSValue PropertyDescriptor::setter() const
91 {
92     ASSERT(isAccessorDescriptor());
93     return m_setter;
94 }
95
96 JSObject* PropertyDescriptor::getterObject() const
97 {
98     ASSERT(isAccessorDescriptor() && getterPresent());
99     return m_getter.isObject() ? asObject(m_getter) : 0;
100 }
101
102 JSObject* PropertyDescriptor::setterObject() const
103 {
104     ASSERT(isAccessorDescriptor() && setterPresent());
105     return m_setter.isObject() ? asObject(m_setter) : 0;
106 }
107
108 void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
109 {
110     ASSERT(value);
111
112     // We need to mask off the PropertyAttribute::CustomValue bit because
113     // PropertyDescriptor::attributesEqual() does an equivalent test on
114     // m_attributes, and a property that has a CustomValue should be indistinguishable
115     // from a property that has a normal value as far as JS code is concerned.
116     // PropertyAttribute does not need knowledge of the underlying implementation
117     // actually being a CustomValue. So, we'll just mask it off up front here.
118     m_attributes = attributes & ~PropertyAttribute::CustomValue;
119     if (value.isGetterSetter()) {
120         m_attributes &= ~PropertyAttribute::ReadOnly; // FIXME: we should be able to ASSERT this!
121
122         GetterSetter* accessor = jsCast<GetterSetter*>(value);
123         m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
124         m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
125         m_seenAttributes = EnumerablePresent | ConfigurablePresent;
126     } else {
127         m_value = value;
128         m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent;
129     }
130 }
131
132 void PropertyDescriptor::setCustomDescriptor(unsigned attributes)
133 {
134     ASSERT(!(attributes & PropertyAttribute::CustomValue));
135     m_attributes = attributes | PropertyAttribute::Accessor | PropertyAttribute::CustomAccessor;
136     m_attributes &= ~PropertyAttribute::ReadOnly;
137     m_seenAttributes = EnumerablePresent | ConfigurablePresent;
138     setGetter(jsUndefined());
139     setSetter(jsUndefined());
140     m_value = JSValue();
141 }
142
143 void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes)
144 {
145     ASSERT(attributes & PropertyAttribute::Accessor);
146     ASSERT(!(attributes & PropertyAttribute::CustomValue));
147     attributes &= ~PropertyAttribute::ReadOnly; // FIXME: we should be able to ASSERT this!
148
149     m_attributes = attributes;
150     m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
151     m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
152     m_seenAttributes = EnumerablePresent | ConfigurablePresent;
153 }
154
155 void PropertyDescriptor::setWritable(bool writable)
156 {
157     if (writable)
158         m_attributes &= ~PropertyAttribute::ReadOnly;
159     else
160         m_attributes |= PropertyAttribute::ReadOnly;
161     m_seenAttributes |= WritablePresent;
162 }
163
164 void PropertyDescriptor::setEnumerable(bool enumerable)
165 {
166     if (enumerable)
167         m_attributes &= ~PropertyAttribute::DontEnum;
168     else
169         m_attributes |= PropertyAttribute::DontEnum;
170     m_seenAttributes |= EnumerablePresent;
171 }
172
173 void PropertyDescriptor::setConfigurable(bool configurable)
174 {
175     if (configurable)
176         m_attributes &= ~PropertyAttribute::DontDelete;
177     else
178         m_attributes |= PropertyAttribute::DontDelete;
179     m_seenAttributes |= ConfigurablePresent;
180 }
181
182 void PropertyDescriptor::setSetter(JSValue setter)
183 {
184     m_setter = setter;
185     m_attributes |= PropertyAttribute::Accessor;
186     m_attributes &= ~PropertyAttribute::ReadOnly;
187 }
188
189 void PropertyDescriptor::setGetter(JSValue getter)
190 {
191     m_getter = getter;
192     m_attributes |= PropertyAttribute::Accessor;
193     m_attributes &= ~PropertyAttribute::ReadOnly;
194 }
195
196 bool 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
208 bool 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 & PropertyAttribute::ReadOnly)
213         return false;
214     if (sharedSeen & ConfigurablePresent && mismatch & PropertyAttribute::DontDelete)
215         return false;
216     if (sharedSeen & EnumerablePresent && mismatch & PropertyAttribute::DontEnum)
217         return false;
218     return true;
219 }
220
221 unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const
222 {
223     unsigned currentAttributes = current.m_attributes;
224     if (isDataDescriptor() && current.isAccessorDescriptor())
225         currentAttributes |= PropertyAttribute::ReadOnly;
226     unsigned overrideMask = 0;
227     if (writablePresent())
228         overrideMask |= PropertyAttribute::ReadOnly;
229     if (enumerablePresent())
230         overrideMask |= PropertyAttribute::DontEnum;
231     if (configurablePresent())
232         overrideMask |= PropertyAttribute::DontDelete;
233     if (isAccessorDescriptor())
234         overrideMask |= PropertyAttribute::Accessor;
235     return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask & ~PropertyAttribute::CustomAccessor);
236 }
237
238 }