/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include "JSCell.h"
+#include "CallFrame.h"
+#include "JSGlobalObject.h"
+#include "NullGetterFunction.h"
+#include "NullSetterFunction.h"
+#include "Structure.h"
+
namespace JSC {
- class JSObject;
+class JSObject;
+
+// This is an internal value object which stores getter and setter functions
+// for a property. Instances of this class have the property that once a getter
+// or setter is set to a non-null value, then they cannot be changed. This means
+// that if a property holding a GetterSetter reference is constant-inferred and
+// that constant is observed to have a non-null setter (or getter) then we can
+// constant fold that setter (or getter).
+class GetterSetter final : public JSCell {
+ friend class JIT;
+
+private:
+ GetterSetter(VM& vm, JSGlobalObject* globalObject)
+ : JSCell(vm, vm.getterSetterStructure.get())
+ {
+ m_getter.set(vm, this, globalObject->nullGetterFunction());
+ m_setter.set(vm, this, globalObject->nullSetterFunction());
+ }
+
+public:
+ typedef JSCell Base;
+ static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+ static GetterSetter* create(VM& vm, JSGlobalObject* globalObject)
+ {
+ GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(vm.heap)) GetterSetter(vm, globalObject);
+ getterSetter->finishCreation(vm);
+ return getterSetter;
+ }
- // This is an internal value object which stores getter and setter functions
- // for a property.
- class GetterSetter : public JSCell {
- public:
- GetterSetter()
- : JSCell(0)
- , m_getter(0)
- , m_setter(0)
- {
- }
+ static void visitChildren(JSCell*, SlotVisitor&);
- virtual void mark();
+ JSObject* getter() const { return m_getter.get(); }
- JSObject* getter() const { return m_getter; }
- void setGetter(JSObject* getter) { m_getter = getter; }
- JSObject* setter() const { return m_setter; }
- void setSetter(JSObject* setter) { m_setter = setter; }
+ JSObject* getterConcurrently() const
+ {
+ JSObject* result = getter();
+ WTF::loadLoadFence();
+ return result;
+ }
- private:
- virtual bool isGetterSetter() const;
+ bool isGetterNull() const { return !!jsDynamicCast<NullGetterFunction*>(m_getter.get()); }
+ bool isSetterNull() const { return !!jsDynamicCast<NullSetterFunction*>(m_setter.get()); }
- virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
- virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
- virtual bool toBoolean(ExecState*) const;
- virtual double toNumber(ExecState*) const;
- virtual UString toString(ExecState*) const;
- virtual JSObject* toObject(ExecState*) const;
+ // Set the getter. It's only valid to call this if you've never set the getter on this
+ // object.
+ void setGetter(VM& vm, JSGlobalObject* globalObject, JSObject* getter)
+ {
+ if (!getter)
+ getter = jsCast<JSObject*>(globalObject->nullGetterFunction());
- JSObject* m_getter;
- JSObject* m_setter;
- };
+ RELEASE_ASSERT(isGetterNull());
+ WTF::storeStoreFence();
+ m_getter.set(vm, this, getter);
+ }
- GetterSetter* asGetterSetter(JSValue);
+ JSObject* setter() const { return m_setter.get(); }
- inline GetterSetter* asGetterSetter(JSValue value)
+ JSObject* setterConcurrently() const
{
- ASSERT(asCell(value)->isGetterSetter());
- return static_cast<GetterSetter*>(asCell(value));
+ JSObject* result = setter();
+ WTF::loadLoadFence();
+ return result;
}
+ // Set the setter. It's only valid to call this if you've never set the setter on this
+ // object.
+ void setSetter(VM& vm, JSGlobalObject* globalObject, JSObject* setter)
+ {
+ if (!setter)
+ setter = jsCast<JSObject*>(globalObject->nullSetterFunction());
+
+ RELEASE_ASSERT(isSetterNull());
+ WTF::storeStoreFence();
+ m_setter.set(vm, this, setter);
+ }
+
+ GetterSetter* withGetter(VM&, JSGlobalObject*, JSObject* getter);
+ GetterSetter* withSetter(VM&, JSGlobalObject*, JSObject* setter);
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType), info());
+ }
+
+ static ptrdiff_t offsetOfGetter()
+ {
+ return OBJECT_OFFSETOF(GetterSetter, m_getter);
+ }
+
+ static ptrdiff_t offsetOfSetter()
+ {
+ return OBJECT_OFFSETOF(GetterSetter, m_setter);
+ }
+
+ DECLARE_INFO;
+
+private:
+ WriteBarrier<JSObject> m_getter;
+ WriteBarrier<JSObject> m_setter;
+};
+
+GetterSetter* asGetterSetter(JSValue);
+
+inline GetterSetter* asGetterSetter(JSValue value)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(value.asCell()->isGetterSetter());
+ return static_cast<GetterSetter*>(value.asCell());
+}
+
+JSValue callGetter(ExecState*, JSValue base, JSValue getterSetter);
+void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue, ECMAMode);
} // namespace JSC