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
35namespace JSC {
36unsigned PropertyDescriptor::defaultAttributes = (DontDelete << 1) - 1;
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
87void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
88{
89    ASSERT(value);
90    m_attributes = attributes;
91    if (attributes & (Getter | Setter)) {
92        GetterSetter* accessor = asGetterSetter(value);
93        m_getter = accessor->getter();
94        m_setter = accessor->setter();
95        ASSERT(m_getter || m_setter);
96        m_seenAttributes = EnumerablePresent | ConfigurablePresent;
97        m_attributes &= ~ReadOnly;
98    } else {
99        m_value = value;
100        m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent;
101    }
102}
103
104void PropertyDescriptor::setAccessorDescriptor(JSValue getter, JSValue setter, unsigned attributes)
105{
106    ASSERT(attributes & (Getter | Setter));
107    ASSERT(getter || setter);
108    m_attributes = attributes;
109    m_getter = getter;
110    m_setter = setter;
111    m_attributes &= ~ReadOnly;
112    m_seenAttributes = EnumerablePresent | ConfigurablePresent;
113}
114
115void PropertyDescriptor::setWritable(bool writable)
116{
117    if (writable)
118        m_attributes &= ~ReadOnly;
119    else
120        m_attributes |= ReadOnly;
121    m_seenAttributes |= WritablePresent;
122}
123
124void PropertyDescriptor::setEnumerable(bool enumerable)
125{
126    if (enumerable)
127        m_attributes &= ~DontEnum;
128    else
129        m_attributes |= DontEnum;
130    m_seenAttributes |= EnumerablePresent;
131}
132
133void PropertyDescriptor::setConfigurable(bool configurable)
134{
135    if (configurable)
136        m_attributes &= ~DontDelete;
137    else
138        m_attributes |= DontDelete;
139    m_seenAttributes |= ConfigurablePresent;
140}
141
142void PropertyDescriptor::setSetter(JSValue setter)
143{
144    m_setter = setter;
145    m_attributes |= Setter;
146    m_attributes &= ~ReadOnly;
147}
148
149void PropertyDescriptor::setGetter(JSValue getter)
150{
151    m_getter = getter;
152    m_attributes |= Getter;
153    m_attributes &= ~ReadOnly;
154}
155
156bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const
157{
158    if (!other.m_value == m_value ||
159        !other.m_getter == m_getter ||
160        !other.m_setter == m_setter)
161        return false;
162    return (!m_value || JSValue::strictEqual(exec, other.m_value, m_value)) &&
163           (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter)) &&
164           (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter)) &&
165           attributesEqual(other);
166}
167
168bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const
169{
170    unsigned mismatch = other.m_attributes ^ m_attributes;
171    unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes;
172    if (sharedSeen & WritablePresent && mismatch & ReadOnly)
173        return false;
174    if (sharedSeen & ConfigurablePresent && mismatch & DontDelete)
175        return false;
176    if (sharedSeen & EnumerablePresent && mismatch & DontEnum)
177        return false;
178    return true;
179}
180
181unsigned PropertyDescriptor::attributesWithOverride(const PropertyDescriptor& other) const
182{
183    unsigned mismatch = other.m_attributes ^ m_attributes;
184    unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes;
185    unsigned newAttributes = m_attributes & defaultAttributes;
186    if (sharedSeen & WritablePresent && mismatch & ReadOnly)
187        newAttributes ^= ReadOnly;
188    if (sharedSeen & ConfigurablePresent && mismatch & DontDelete)
189        newAttributes ^= DontDelete;
190    if (sharedSeen & EnumerablePresent && mismatch & DontEnum)
191        newAttributes ^= DontEnum;
192    return newAttributes;
193}
194
195}
196