summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/runtime/JSObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/runtime/JSObject.h')
-rw-r--r--JavaScriptCore/runtime/JSObject.h149
1 files changed, 115 insertions, 34 deletions
diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h
index 2b31a65..803abfd 100644
--- a/JavaScriptCore/runtime/JSObject.h
+++ b/JavaScriptCore/runtime/JSObject.h
@@ -26,6 +26,7 @@
#include "ArgList.h"
#include "ClassInfo.h"
#include "CommonIdentifiers.h"
+#include "Completion.h"
#include "CallFrame.h"
#include "JSCell.h"
#include "JSNumberCell.h"
@@ -35,6 +36,7 @@
#include "ScopeChain.h"
#include "Structure.h"
#include "JSGlobalData.h"
+#include "JSString.h"
#include <wtf/StdLibExtras.h>
namespace JSC {
@@ -53,6 +55,9 @@ namespace JSC {
class Structure;
struct HashTable;
+ JSObject* throwTypeError(ExecState*, const UString&);
+ extern const char* StrictModeReadonlyPropertyWriteError;
+
// ECMA 262-3 8.6.1
// Property attributes
enum Attribute {
@@ -72,6 +77,7 @@ namespace JSC {
friend class BatchedTransitionOptimizer;
friend class JIT;
friend class JSCell;
+ friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
public:
explicit JSObject(NonNullPassRefPtr<Structure>);
@@ -85,6 +91,7 @@ namespace JSC {
JSValue prototype() const;
void setPrototype(JSValue prototype);
+ bool setPrototypeWithCycleCheck(JSValue prototype);
void setStructure(NonNullPassRefPtr<Structure>);
Structure* inheritorID();
@@ -105,6 +112,9 @@ namespace JSC {
virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
virtual void put(ExecState*, unsigned propertyName, JSValue value);
+ virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
+ virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes);
+ virtual void putWithAttributes(JSGlobalData*, unsigned propertyName, JSValue value, unsigned attributes);
virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
@@ -133,6 +143,7 @@ namespace JSC {
virtual JSObject* toObject(ExecState*) const;
virtual JSObject* toThisObject(ExecState*) const;
+ virtual JSValue toStrictThisObject(ExecState*) const;
virtual JSObject* unwrappedObject();
bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
@@ -168,16 +179,19 @@ namespace JSC {
bool hasCustomProperties() { return !m_structure->isEmpty(); }
bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
- void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
+ bool putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
+ bool putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot&);
void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
+ void putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr = 0);
void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
+ void putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr = 0);
// Fast access to known property offsets.
JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
@@ -194,8 +208,10 @@ namespace JSC {
virtual bool isGlobalObject() const { return false; }
virtual bool isVariableObject() const { return false; }
virtual bool isActivationObject() const { return false; }
- virtual bool isWatchdogException() const { return false; }
- virtual bool isNotAnObjectErrorStub() const { return false; }
+ virtual bool isStrictModeFunction() const { return false; }
+ virtual bool isErrorInstance() const { return false; }
+
+ virtual ComplType exceptionType() const { return Throw; }
void allocatePropertyStorage(size_t oldSize, size_t newSize);
void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
@@ -214,9 +230,6 @@ namespace JSC {
m_structure->flattenDictionaryStructure(this);
}
- protected:
- static const unsigned StructureFlags = 0;
-
void putAnonymousValue(unsigned index, JSValue value)
{
ASSERT(index < m_structure->anonymousSlotCount());
@@ -227,7 +240,10 @@ namespace JSC {
ASSERT(index < m_structure->anonymousSlotCount());
return *locationForOffset(index);
}
-
+
+ protected:
+ static const unsigned StructureFlags = 0;
+
private:
// Nobody should ever ask any of these questions on something already known to be a JSObject.
using JSCell::isAPIValueWrapper;
@@ -237,9 +253,6 @@ namespace JSC {
void getString(ExecState* exec);
void isObject();
void isString();
-#if USE(JSVALUE32)
- void isNumber();
-#endif
ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
@@ -254,8 +267,8 @@ namespace JSC {
return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
}
- void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
- void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
+ bool putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
+ bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
@@ -288,9 +301,7 @@ inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure)
ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
ASSERT(m_structure->isEmpty());
ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
-#if USE(JSVALUE64) || USE(JSVALUE32_64)
ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
-#endif
}
inline JSObject::~JSObject()
@@ -306,6 +317,19 @@ inline JSValue JSObject::prototype() const
return m_structure->storedPrototype();
}
+inline bool JSObject::setPrototypeWithCycleCheck(JSValue prototype)
+{
+ JSValue nextPrototypeValue = prototype;
+ while (nextPrototypeValue && nextPrototypeValue.isObject()) {
+ JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
+ if (nextPrototype == this)
+ return false;
+ nextPrototypeValue = nextPrototype->prototype();
+ }
+ setPrototype(prototype);
+ return true;
+}
+
inline void JSObject::setPrototype(JSValue prototype)
{
ASSERT(prototype);
@@ -316,7 +340,7 @@ inline void JSObject::setPrototype(JSValue prototype)
inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure)
{
m_structure->deref();
- m_structure = structure.releaseRef(); // ~JSObject balances this ref()
+ m_structure = structure.leakRef(); // ~JSObject balances this ref()
}
inline Structure* JSObject::inheritorID()
@@ -426,7 +450,7 @@ inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
return jsUndefined();
}
-inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
+inline bool JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
{
ASSERT(value);
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
@@ -436,14 +460,23 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
JSCell* currentSpecificFunction;
size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
if (offset != WTF::notFound) {
+ // If there is currently a specific function, and there now either isn't,
+ // or the new value is different, then despecify.
if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
m_structure->despecifyDictionaryFunction(propertyName);
if (checkReadOnly && currentAttributes & ReadOnly)
- return;
+ return false;
+
putDirectOffset(offset, value);
- if (!specificFunction && !currentSpecificFunction)
+ // At this point, the objects structure only has a specific value set if previously there
+ // had been one set, and if the new value being specified is the same (otherwise we would
+ // have despecified, above). So, if currentSpecificFunction is not set, or if the new
+ // value is different (or there is no new value), then the slot now has no value - and
+ // as such it is cachable.
+ // If there was previously a value, and the new value is the same, then we cannot cache.
+ if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
slot.setExistingProperty(this, offset);
- return;
+ return true;
}
size_t currentCapacity = m_structure->propertyStorageCapacity();
@@ -456,7 +489,7 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
// See comment on setNewProperty call below.
if (!specificFunction)
slot.setNewProperty(this, offset);
- return;
+ return true;
}
size_t offset;
@@ -468,10 +501,11 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
ASSERT(offset < structure->propertyStorageCapacity());
setStructure(structure.release());
putDirectOffset(offset, value);
- // See comment on setNewProperty call below.
+ // This is a new property; transitions with specific values are not currently cachable,
+ // so leave the slot in an uncachable state.
if (!specificFunction)
slot.setNewProperty(this, offset);
- return;
+ return true;
}
unsigned currentAttributes;
@@ -479,17 +513,31 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
if (offset != WTF::notFound) {
if (checkReadOnly && currentAttributes & ReadOnly)
- return;
+ return false;
- if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) {
+ // There are three possibilities here:
+ // (1) There is an existing specific value set, and we're overwriting with *the same value*.
+ // * Do nothing - no need to despecify, but that means we can't cache (a cached
+ // put could write a different value). Leave the slot in an uncachable state.
+ // (2) There is a specific value currently set, but we're writing a different value.
+ // * First, we have to despecify. Having done so, this is now a regular slot
+ // with no specific value, so go ahead & cache like normal.
+ // (3) Normal case, there is no specific value set.
+ // * Go ahead & cache like normal.
+ if (currentSpecificFunction) {
+ // case (1) Do the put, then return leaving the slot uncachable.
+ if (specificFunction == currentSpecificFunction) {
+ putDirectOffset(offset, value);
+ return true;
+ }
+ // case (2) Despecify, fall through to (3).
setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
- putDirectOffset(offset, value);
- // Function transitions are not currently cachable, so leave the slot in an uncachable state.
- return;
}
- putDirectOffset(offset, value);
+
+ // case (3) set the slot, do the put, return.
slot.setExistingProperty(this, offset);
- return;
+ putDirectOffset(offset, value);
+ return true;
}
// If we have a specific function, we may have got to this point if there is
@@ -510,17 +558,19 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue
ASSERT(offset < structure->propertyStorageCapacity());
setStructure(structure.release());
putDirectOffset(offset, value);
- // Function transitions are not currently cachable, so leave the slot in an uncachable state.
+ // This is a new property; transitions with specific values are not currently cachable,
+ // so leave the slot in an uncachable state.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ return true;
}
-inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
ASSERT(value);
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
+ return putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
}
inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
@@ -529,12 +579,12 @@ inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
}
-inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+inline bool JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
ASSERT(value);
ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
- putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
+ return putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
}
inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
@@ -543,6 +593,11 @@ inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, u
putDirectInternal(propertyName, value, attributes, false, slot, 0);
}
+inline bool JSObject::putDirect(const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ return putDirectInternal(propertyName, value, 0, false, slot, 0);
+}
+
inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
{
putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
@@ -645,6 +700,13 @@ inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValu
asCell()->put(exec, propertyName, value, slot);
}
+inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ ASSERT(isCell() && isObject());
+ if (!asObject(asCell())->putDirect(propertyName, value, slot) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+}
+
inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
{
if (UNLIKELY(!isCell())) {
@@ -685,6 +747,25 @@ ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
}
+// --- JSValue inlines ----------------------------
+
+ALWAYS_INLINE UString JSValue::toThisString(ExecState* exec) const
+{
+ return isString() ? static_cast<JSString*>(asCell())->value(exec) : toThisObject(exec)->toString(exec);
+}
+
+inline JSString* JSValue::toThisJSString(ExecState* exec) const
+{
+ return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec));
+}
+
+inline JSValue JSValue::toStrictThisObject(ExecState* exec) const
+{
+ if (!isObject())
+ return *this;
+ return asObject(asCell())->toStrictThisObject(exec);
+}
+
} // namespace JSC
#endif // JSObject_h