#ifndef PropertySlot_h
#define PropertySlot_h
-#include "Identifier.h"
-#include "JSValue.h"
+#include "JSCJSValue.h"
+#include "PropertyName.h"
+#include "PropertyOffset.h"
#include "Register.h"
#include <wtf/Assertions.h>
-#include <wtf/NotFound.h>
namespace JSC {
- class ExecState;
- class JSObject;
-
-#define JSC_VALUE_SLOT_MARKER 0
-#define JSC_REGISTER_SLOT_MARKER reinterpret_cast<GetValueFunc>(1)
-
- class PropertySlot {
- public:
- PropertySlot()
- {
- clearBase();
- clearOffset();
- clearValue();
- }
-
- explicit PropertySlot(const JSValue base)
- : m_slotBase(base)
- {
- clearOffset();
- clearValue();
- }
-
- typedef JSValue (*GetValueFunc)(ExecState*, const Identifier&, const PropertySlot&);
-
- JSValue getValue(ExecState* exec, const Identifier& propertyName) const
- {
- if (m_getValue == JSC_VALUE_SLOT_MARKER)
- return *m_data.valueSlot;
- if (m_getValue == JSC_REGISTER_SLOT_MARKER)
- return (*m_data.registerSlot).jsValue();
- return m_getValue(exec, propertyName, *this);
- }
-
- JSValue getValue(ExecState* exec, unsigned propertyName) const
- {
- if (m_getValue == JSC_VALUE_SLOT_MARKER)
- return *m_data.valueSlot;
- if (m_getValue == JSC_REGISTER_SLOT_MARKER)
- return (*m_data.registerSlot).jsValue();
- return m_getValue(exec, Identifier::from(exec, propertyName), *this);
- }
-
- bool isCacheable() const { return m_offset != WTF::notFound; }
- size_t cachedOffset() const
- {
- ASSERT(isCacheable());
- return m_offset;
- }
-
- void setValueSlot(JSValue* valueSlot)
- {
- ASSERT(valueSlot);
- clearBase();
- clearOffset();
- m_getValue = JSC_VALUE_SLOT_MARKER;
- m_data.valueSlot = valueSlot;
- }
-
- void setValueSlot(JSValue slotBase, JSValue* valueSlot)
- {
- ASSERT(valueSlot);
- m_getValue = JSC_VALUE_SLOT_MARKER;
- m_slotBase = slotBase;
- m_data.valueSlot = valueSlot;
- }
-
- void setValueSlot(JSValue slotBase, JSValue* valueSlot, size_t offset)
- {
- ASSERT(valueSlot);
- m_getValue = JSC_VALUE_SLOT_MARKER;
- m_slotBase = slotBase;
- m_data.valueSlot = valueSlot;
- m_offset = offset;
- }
-
- void setValue(JSValue value)
- {
- ASSERT(value);
- clearBase();
- clearOffset();
- m_getValue = JSC_VALUE_SLOT_MARKER;
- m_value = value;
- m_data.valueSlot = &m_value;
- }
-
- void setRegisterSlot(Register* registerSlot)
- {
- ASSERT(registerSlot);
- clearBase();
- clearOffset();
- m_getValue = JSC_REGISTER_SLOT_MARKER;
- m_data.registerSlot = registerSlot;
- }
-
- void setCustom(JSValue slotBase, GetValueFunc getValue)
- {
- ASSERT(slotBase);
- ASSERT(getValue);
- m_getValue = getValue;
- m_slotBase = slotBase;
- }
-
- void setCustomIndex(JSValue slotBase, unsigned index, GetValueFunc getValue)
- {
- ASSERT(slotBase);
- ASSERT(getValue);
- m_getValue = getValue;
- m_slotBase = slotBase;
- m_data.index = index;
- }
-
- void setGetterSlot(JSObject* getterFunc)
- {
- ASSERT(getterFunc);
- m_getValue = functionGetter;
- m_data.getterFunc = getterFunc;
- }
-
- void setUndefined()
- {
- setValue(jsUndefined());
- }
-
- JSValue slotBase() const
- {
- return m_slotBase;
- }
-
- void setBase(JSValue base)
- {
- ASSERT(m_slotBase);
- ASSERT(base);
- m_slotBase = base;
- }
-
- void clearBase()
- {
-#ifndef NDEBUG
- m_slotBase = JSValue();
-#endif
- }
-
- void clearValue()
- {
-#ifndef NDEBUG
- m_value = JSValue();
-#endif
- }
-
- void clearOffset()
- {
- // Clear offset even in release builds, in case this PropertySlot has been used before.
- // (For other data members, we don't need to clear anything because reuse would meaningfully overwrite them.)
- m_offset = WTF::notFound;
- }
-
- unsigned index() const { return m_data.index; }
-
- private:
- static JSValue functionGetter(ExecState*, const Identifier&, const PropertySlot&);
-
- GetValueFunc m_getValue;
-
- JSValue m_slotBase;
- union {
- JSObject* getterFunc;
- JSValue* valueSlot;
- Register* registerSlot;
- unsigned index;
- } m_data;
-
- JSValue m_value;
-
- size_t m_offset;
+class ExecState;
+class GetterSetter;
+class JSObject;
+
+// ECMA 262-3 8.6.1
+// Property attributes
+enum Attribute {
+ None = 0,
+ ReadOnly = 1 << 1, // property can be only read, not written
+ DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
+ DontDelete = 1 << 3, // property can't be deleted
+ Function = 1 << 4, // property is a function - only used by static hashtables
+ Accessor = 1 << 5, // property is a getter/setter
+ CustomAccessor = 1 << 6,
+ Builtin = 1 << 7, // property is a builtin function - only used by static hashtables
+ ConstantInteger = 1 << 8, // property is a constant integer - only used by static hashtables
+ BuiltinOrFunction = Builtin | Function, // helper only used by static hashtables
+ BuiltinOrFunctionOrConstant = Builtin | Function | ConstantInteger, // helper only used by static hashtables
+};
+
+class PropertySlot {
+ enum PropertyType {
+ TypeUnset,
+ TypeValue,
+ TypeGetter,
+ TypeCustom
};
+ enum CacheabilityType {
+ CachingDisallowed,
+ CachingAllowed
+ };
+
+public:
+ explicit PropertySlot(const JSValue thisValue)
+ : m_propertyType(TypeUnset)
+ , m_offset(invalidOffset)
+ , m_thisValue(thisValue)
+ , m_watchpointSet(nullptr)
+ , m_cacheability(CachingAllowed)
+ {
+ }
+
+ typedef EncodedJSValue (*GetValueFunc)(ExecState*, JSObject* slotBase, EncodedJSValue thisValue, PropertyName);
+
+ JSValue getValue(ExecState*, PropertyName) const;
+ JSValue getValue(ExecState*, unsigned propertyName) const;
+
+ bool isCacheable() const { return m_cacheability == CachingAllowed && m_offset != invalidOffset; }
+ bool isValue() const { return m_propertyType == TypeValue; }
+ bool isAccessor() const { return m_propertyType == TypeGetter; }
+ bool isCustom() const { return m_propertyType == TypeCustom; }
+ bool isCacheableValue() const { return isCacheable() && isValue(); }
+ bool isCacheableGetter() const { return isCacheable() && isAccessor(); }
+ bool isCacheableCustom() const { return isCacheable() && isCustom(); }
+
+ void disableCaching()
+ {
+ m_cacheability = CachingDisallowed;
+ }
+
+ unsigned attributes() const { return m_attributes; }
+
+ PropertyOffset cachedOffset() const
+ {
+ ASSERT(isCacheable());
+ return m_offset;
+ }
+
+ GetterSetter* getterSetter() const
+ {
+ ASSERT(isAccessor());
+ return m_data.getter.getterSetter;
+ }
+
+ GetValueFunc customGetter() const
+ {
+ ASSERT(isCacheableCustom());
+ return m_data.custom.getValue;
+ }
+
+ JSObject* slotBase() const
+ {
+ ASSERT(m_propertyType != TypeUnset);
+ return m_slotBase;
+ }
+
+ WatchpointSet* watchpointSet() const
+ {
+ return m_watchpointSet;
+ }
+
+ void setValue(JSObject* slotBase, unsigned attributes, JSValue value)
+ {
+ ASSERT(value);
+ m_data.value = JSValue::encode(value);
+ m_attributes = attributes;
+
+ ASSERT(slotBase);
+ m_slotBase = slotBase;
+ m_propertyType = TypeValue;
+ m_offset = invalidOffset;
+ }
+
+ void setValue(JSObject* slotBase, unsigned attributes, JSValue value, PropertyOffset offset)
+ {
+ ASSERT(value);
+ m_data.value = JSValue::encode(value);
+ m_attributes = attributes;
+
+ ASSERT(slotBase);
+ m_slotBase = slotBase;
+ m_propertyType = TypeValue;
+ m_offset = offset;
+ }
+
+ void setValue(JSString*, unsigned attributes, JSValue value)
+ {
+ ASSERT(value);
+ m_data.value = JSValue::encode(value);
+ m_attributes = attributes;
+
+ m_slotBase = 0;
+ m_propertyType = TypeValue;
+ m_offset = invalidOffset;
+ }
+
+ void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
+ {
+ ASSERT(getValue);
+ m_data.custom.getValue = getValue;
+ m_attributes = attributes;
+
+ ASSERT(slotBase);
+ m_slotBase = slotBase;
+ m_propertyType = TypeCustom;
+ m_offset = invalidOffset;
+ }
+
+ void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
+ {
+ ASSERT(getValue);
+ m_data.custom.getValue = getValue;
+ m_attributes = attributes;
+
+ ASSERT(slotBase);
+ m_slotBase = slotBase;
+ m_propertyType = TypeCustom;
+ m_offset = !invalidOffset;
+ }
+
+ void setGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter)
+ {
+ ASSERT(getterSetter);
+ m_data.getter.getterSetter = getterSetter;
+ m_attributes = attributes;
+
+ ASSERT(slotBase);
+ m_slotBase = slotBase;
+ m_propertyType = TypeGetter;
+ m_offset = invalidOffset;
+ }
+
+ void setCacheableGetterSlot(JSObject* slotBase, unsigned attributes, GetterSetter* getterSetter, PropertyOffset offset)
+ {
+ ASSERT(getterSetter);
+ m_data.getter.getterSetter = getterSetter;
+ m_attributes = attributes;
+
+ ASSERT(slotBase);
+ m_slotBase = slotBase;
+ m_propertyType = TypeGetter;
+ m_offset = offset;
+ }
+
+ void setUndefined()
+ {
+ m_data.value = JSValue::encode(jsUndefined());
+ m_attributes = ReadOnly | DontDelete | DontEnum;
+
+ m_slotBase = 0;
+ m_propertyType = TypeValue;
+ m_offset = invalidOffset;
+ }
+
+ void setWatchpointSet(WatchpointSet& set)
+ {
+ m_watchpointSet = &set;
+ }
+
+private:
+ JS_EXPORT_PRIVATE JSValue functionGetter(ExecState*) const;
+
+ unsigned m_attributes;
+ union {
+ EncodedJSValue value;
+ struct {
+ GetterSetter* getterSetter;
+ } getter;
+ struct {
+ GetValueFunc getValue;
+ } custom;
+ } m_data;
+
+ PropertyType m_propertyType;
+ PropertyOffset m_offset;
+ const JSValue m_thisValue;
+ JSObject* m_slotBase;
+ WatchpointSet* m_watchpointSet;
+ CacheabilityType m_cacheability;
+};
+
} // namespace JSC
#endif // PropertySlot_h