#include "GetterSetter.h"
#include "JSObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC {
-unsigned PropertyDescriptor::defaultAttributes = (DontDelete << 1) - 1;
+unsigned PropertyDescriptor::defaultAttributes = DontDelete | DontEnum | ReadOnly;
bool PropertyDescriptor::writable() const
{
return m_setter;
}
+JSObject* PropertyDescriptor::getterObject() const
+{
+ ASSERT(isAccessorDescriptor() && getterPresent());
+ return m_getter.isObject() ? asObject(m_getter) : 0;
+}
+
+JSObject* PropertyDescriptor::setterObject() const
+{
+ ASSERT(isAccessorDescriptor() && setterPresent());
+ return m_setter.isObject() ? asObject(m_setter) : 0;
+}
+
void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
{
ASSERT(value);
+ ASSERT(value.isGetterSetter() == !!(attributes & Accessor));
+
m_attributes = attributes;
- if (attributes & (Getter | Setter)) {
+ if (value.isGetterSetter()) {
+ m_attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
+
GetterSetter* accessor = asGetterSetter(value);
- m_getter = accessor->getter();
- m_setter = accessor->setter();
- ASSERT(m_getter || m_setter);
+ m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
+ m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
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)
+void PropertyDescriptor::setCustomDescriptor(unsigned attributes)
{
- ASSERT(attributes & (Getter | Setter));
- ASSERT(getter || setter);
- m_attributes = attributes;
- m_getter = getter;
- m_setter = setter;
+ m_attributes = attributes | Accessor | CustomAccessor;
m_attributes &= ~ReadOnly;
m_seenAttributes = EnumerablePresent | ConfigurablePresent;
+ setGetter(jsUndefined());
+ setSetter(jsUndefined());
+ m_value = JSValue();
+}
+
+void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes)
+{
+ ASSERT(attributes & Accessor);
+ attributes &= ~ReadOnly; // FIXME: we should be able to ASSERT this!
+
+ m_attributes = attributes;
+ m_getter = !accessor->isGetterNull() ? accessor->getter() : jsUndefined();
+ m_setter = !accessor->isSetterNull() ? accessor->setter() : jsUndefined();
+ m_seenAttributes = EnumerablePresent | ConfigurablePresent;
}
void PropertyDescriptor::setWritable(bool writable)
void PropertyDescriptor::setSetter(JSValue setter)
{
m_setter = setter;
- m_attributes |= Setter;
+ m_attributes |= Accessor;
m_attributes &= ~ReadOnly;
}
void PropertyDescriptor::setGetter(JSValue getter)
{
m_getter = getter;
- m_attributes |= Getter;
+ m_attributes |= Accessor;
m_attributes &= ~ReadOnly;
}
+// See ES5.1 9.12
+bool sameValue(ExecState* exec, JSValue a, JSValue b)
+{
+ if (!a.isNumber())
+ return JSValue::strictEqual(exec, a, b);
+ if (!b.isNumber())
+ return false;
+ double x = a.asNumber();
+ double y = b.asNumber();
+ bool xIsNaN = std::isnan(x);
+ bool yIsNaN = std::isnan(y);
+ if (xIsNaN || yIsNaN)
+ return xIsNaN && yIsNaN;
+ return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y);
+}
+
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)
+ if (other.m_value.isEmpty() != m_value.isEmpty()
+ || other.m_getter.isEmpty() != m_getter.isEmpty()
+ || other.m_setter.isEmpty() != m_setter.isEmpty())
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);
+ return (!m_value || sameValue(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
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;
+unsigned PropertyDescriptor::attributesOverridingCurrent(const PropertyDescriptor& current) const
+{
+ unsigned currentAttributes = current.m_attributes;
+ if (isDataDescriptor() && current.isAccessorDescriptor())
+ currentAttributes |= ReadOnly;
+ unsigned overrideMask = 0;
+ if (writablePresent())
+ overrideMask |= ReadOnly;
+ if (enumerablePresent())
+ overrideMask |= DontEnum;
+ if (configurablePresent())
+ overrideMask |= DontDelete;
+ if (isAccessorDescriptor())
+ overrideMask |= Accessor;
+ return (m_attributes & overrideMask) | (currentAttributes & ~overrideMask);
}
}