We should support CreateThis in the FTL
[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     m_attributes = attributes;
113     if (value.isGetterSetter()) {
114         m_attributes &= ~PropertyAttribute::ReadOnly; // FIXME: we should be able to ASSERT this!
115
116         GetterSetter* accessor = jsCast<GetterSetter*>(value);
117         m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
118         m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
119         m_seenAttributes = EnumerablePresent | ConfigurablePresent;
120     } else {
121         m_value = value;
122         m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent;
123     }
124 }
125
126 void PropertyDescriptor::setCustomDescriptor(unsigned attributes)
127 {
128     m_attributes = attributes | PropertyAttribute::Accessor | PropertyAttribute::CustomAccessor;
129     m_attributes &= ~PropertyAttribute::ReadOnly;
130     m_seenAttributes = EnumerablePresent | ConfigurablePresent;
131     setGetter(jsUndefined());
132     setSetter(jsUndefined());
133     m_value = JSValue();
134 }
135
136 void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes)
137 {
138     ASSERT(attributes & PropertyAttribute::Accessor);
139     attributes &= ~PropertyAttribute::ReadOnly; // FIXME: we should be able to ASSERT this!
140
141     m_attributes = attributes;
142     m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
143     m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
144     m_seenAttributes = EnumerablePresent | ConfigurablePresent;
145 }
146
147 void PropertyDescriptor::setWritable(bool writable)
148 {
149     if (writable)
150         m_attributes &= ~PropertyAttribute::ReadOnly;
151     else
152         m_attributes |= PropertyAttribute::ReadOnly;
153     m_seenAttributes |= WritablePresent;
154 }
155
156 void PropertyDescriptor::setEnumerable(bool enumerable)
157 {
158     if (enumerable)
159         m_attributes &= ~PropertyAttribute::DontEnum;
160     else
161         m_attributes |= PropertyAttribute::DontEnum;
162     m_seenAttributes |= EnumerablePresent;
163 }
164
165 void PropertyDescriptor::setConfigurable(bool configurable)
166 {
167     if (configurable)
168         m_attributes &= ~PropertyAttribute::DontDelete;
169     else
170         m_attributes |= PropertyAttribute::DontDelete;
171     m_seenAttributes |= ConfigurablePresent;
172 }
173
174 void PropertyDescriptor::setSetter(JSValue setter)
175 {
176     m_setter = setter;
177     m_attributes |= PropertyAttribute::Accessor;
178     m_attributes &= ~PropertyAttribute::ReadOnly;
179 }
180
181 void PropertyDescriptor::setGetter(JSValue getter)
182 {
183     m_getter = getter;
184     m_attributes |= PropertyAttribute::Accessor;
185     m_attributes &= ~PropertyAttribute::ReadOnly;
186 }
187
188 bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const
189 {
190     if (other.m_value.isEmpty() != m_value.isEmpty()
191         || other.m_getter.isEmpty() != m_getter.isEmpty()
192         || other.m_setter.isEmpty() != m_setter.isEmpty())
193         return false;
194     return (!m_value || sameValue(exec, other.m_value, m_value))
195         && (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter))
196         && (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter))
197         && attributesEqual(other);
198 }
199
200 bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const
201 {
202     unsigned mismatch = other.m_attributes ^ m_attributes;
203     unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes;
204     if (sharedSeen & WritablePresent && mismatch & PropertyAttribute::ReadOnly)
205         return false;
206     if (sharedSeen & ConfigurablePresent && mismatch & PropertyAttribute::DontDelete)
207         return false;
208     if (sharedSeen & EnumerablePresent && mismatch & PropertyAttribute::DontEnum)
209         return false;
210     return true;
211 }
212
213 unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const
214 {
215     unsigned currentAttributes = current.m_attributes;
216     if (isDataDescriptor() && current.isAccessorDescriptor())
217         currentAttributes |= PropertyAttribute::ReadOnly;
218     unsigned overrideMask = 0;
219     if (writablePresent())
220         overrideMask |= PropertyAttribute::ReadOnly;
221     if (enumerablePresent())
222         overrideMask |= PropertyAttribute::DontEnum;
223     if (configurablePresent())
224         overrideMask |= PropertyAttribute::DontDelete;
225     if (isAccessorDescriptor())
226         overrideMask |= PropertyAttribute::Accessor;
227     return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask & ~PropertyAttribute::CustomAccessor);
228 }
229
230 }