diff options
Diffstat (limited to 'JavaScriptCore/runtime/JSObject.h')
| -rw-r--r-- | JavaScriptCore/runtime/JSObject.h | 149 |
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 |
