/* * Copyright (C) 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "PropertyDescriptor.h" #include "GetterSetter.h" #include "JSObject.h" #include "Operations.h" namespace JSC { unsigned PropertyDescriptor::defaultAttributes = (DontDelete << 1) - 1; bool PropertyDescriptor::writable() const { ASSERT(!isAccessorDescriptor()); return !(m_attributes & ReadOnly); } bool PropertyDescriptor::enumerable() const { return !(m_attributes & DontEnum); } bool PropertyDescriptor::configurable() const { return !(m_attributes & DontDelete); } bool PropertyDescriptor::isDataDescriptor() const { return m_value || (m_seenAttributes & WritablePresent); } bool PropertyDescriptor::isGenericDescriptor() const { return !isAccessorDescriptor() && !isDataDescriptor(); } bool PropertyDescriptor::isAccessorDescriptor() const { return m_getter || m_setter; } void PropertyDescriptor::setUndefined() { m_value = jsUndefined(); m_attributes = ReadOnly | DontDelete | DontEnum; } JSValue PropertyDescriptor::getter() const { ASSERT(isAccessorDescriptor()); return m_getter; } JSValue PropertyDescriptor::setter() const { ASSERT(isAccessorDescriptor()); return m_setter; } void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) { ASSERT(value); m_attributes = attributes; if (attributes & (Getter | Setter)) { GetterSetter* accessor = asGetterSetter(value); m_getter = accessor->getter(); m_setter = accessor->setter(); ASSERT(m_getter || m_setter); m_seenAttributes = EnumerablePresent | ConfigurablePresent; m_attributes &= ~ReadOnly; } else { m_value = value; m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent; } } void PropertyDescriptor::setAccessorDescriptor(JSValue getter, JSValue setter, unsigned attributes) { ASSERT(attributes & (Getter | Setter)); ASSERT(getter || setter); m_attributes = attributes; m_getter = getter; m_setter = setter; m_attributes &= ~ReadOnly; m_seenAttributes = EnumerablePresent | ConfigurablePresent; } void PropertyDescriptor::setWritable(bool writable) { if (writable) m_attributes &= ~ReadOnly; else m_attributes |= ReadOnly; m_seenAttributes |= WritablePresent; } void PropertyDescriptor::setEnumerable(bool enumerable) { if (enumerable) m_attributes &= ~DontEnum; else m_attributes |= DontEnum; m_seenAttributes |= EnumerablePresent; } void PropertyDescriptor::setConfigurable(bool configurable) { if (configurable) m_attributes &= ~DontDelete; else m_attributes |= DontDelete; m_seenAttributes |= ConfigurablePresent; } void PropertyDescriptor::setSetter(JSValue setter) { m_setter = setter; m_attributes |= Setter; m_attributes &= ~ReadOnly; } void PropertyDescriptor::setGetter(JSValue getter) { m_getter = getter; m_attributes |= Getter; m_attributes &= ~ReadOnly; } bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const { if (!other.m_value == m_value || !other.m_getter == m_getter || !other.m_setter == m_setter) return false; return (!m_value || JSValue::strictEqual(exec, other.m_value, m_value)) && (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter)) && (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter)) && attributesEqual(other); } bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const { unsigned mismatch = other.m_attributes ^ m_attributes; unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes; if (sharedSeen & WritablePresent && mismatch & ReadOnly) return false; if (sharedSeen & ConfigurablePresent && mismatch & DontDelete) return false; if (sharedSeen & EnumerablePresent && mismatch & DontEnum) return false; return true; } unsigned PropertyDescriptor::attributesWithOverride(const PropertyDescriptor& other) const { unsigned mismatch = other.m_attributes ^ m_attributes; unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes; unsigned newAttributes = m_attributes & defaultAttributes; if (sharedSeen & WritablePresent && mismatch & ReadOnly) newAttributes ^= ReadOnly; if (sharedSeen & ConfigurablePresent && mismatch & DontDelete) newAttributes ^= DontDelete; if (sharedSeen & EnumerablePresent && mismatch & DontEnum) newAttributes ^= DontEnum; return newAttributes; } }