/*
* 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, 2009 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;
-
- // This is an internal value object which stores getter and setter functions
- // for a property.
- class GetterSetter : public JSCell {
- friend class JIT;
-
- private:
- GetterSetter(VM& vm)
- : JSCell(vm, vm.getterSetterStructure.get())
- {
- }
-
- public:
- typedef JSCell Base;
-
- static GetterSetter* create(VM& vm)
- {
- GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(vm.heap)) GetterSetter(vm);
- getterSetter->finishCreation(vm);
- return getterSetter;
- }
-
- static void visitChildren(JSCell*, SlotVisitor&);
-
- JSObject* getter() const { return m_getter.get(); }
- void setGetter(VM& vm, JSObject* getter) { m_getter.setMayBeNull(vm, this, getter); }
- JSObject* setter() const { return m_setter.get(); }
- void setSetter(VM& vm, JSObject* setter) { m_setter.setMayBeNull(vm, this, setter); }
- static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
- {
- return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), 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)
+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;
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ JSObject* getter() const { return m_getter.get(); }
+
+ JSObject* getterConcurrently() const
+ {
+ JSObject* result = getter();
+ WTF::loadLoadFence();
+ return result;
+ }
+
+ bool isGetterNull() const { return !!jsDynamicCast<NullGetterFunction*>(m_getter.get()); }
+ bool isSetterNull() const { return !!jsDynamicCast<NullSetterFunction*>(m_setter.get()); }
+
+ // 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());
+
+ RELEASE_ASSERT(isGetterNull());
+ WTF::storeStoreFence();
+ m_getter.set(vm, this, getter);
+ }
+
+ JSObject* setter() const { return m_setter.get(); }
+
+ JSObject* setterConcurrently() const
+ {
+ 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)
{
- ASSERT_WITH_SECURITY_IMPLICATION(value.asCell()->isGetterSetter());
- return static_cast<GetterSetter*>(value.asCell());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(GetterSetterType), info());
}
- JSValue callGetter(ExecState*, JSValue base, JSValue getterSetter);
- void callSetter(ExecState*, JSValue base, JSValue getterSetter, JSValue value, ECMAMode);
+ 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