diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
commit | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch) | |
tree | b34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/JavaScriptCore/runtime/JSObject.cpp | |
parent | 03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff) | |
download | qtwebkit-ad0d549d4cc13433f77c1ac8f0ab379c83d93f28.tar.gz |
Imported WebKit commit bb52bf3c0119e8a128cd93afe5572413a8617de9 (http://svn.webkit.org/repository/webkit/trunk@108790)
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSObject.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSObject.cpp | 158 |
1 files changed, 86 insertions, 72 deletions
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index ba2d2a52a..acc4a181e 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -24,7 +24,7 @@ #include "config.h" #include "JSObject.h" -#include "BumpSpaceInlineMethods.h" +#include "CopiedSpaceInlineMethods.h" #include "DatePrototype.h" #include "ErrorConstructor.h" #include "GetterSetter.h" @@ -48,6 +48,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject); ASSERT_CLASS_FITS_IN_CELL(JSFinalObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject); const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property."; @@ -55,16 +56,6 @@ const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSOb const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) }; -void JSFinalObject::destroy(JSCell* cell) -{ - jsCast<JSFinalObject*>(cell)->JSFinalObject::~JSFinalObject(); -} - -void JSNonFinalObject::destroy(JSCell* cell) -{ - jsCast<JSNonFinalObject*>(cell)->JSNonFinalObject::~JSNonFinalObject(); -} - static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode) { // Add properties from the static hashtables of properties @@ -84,11 +75,6 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class } } -void JSObject::destroy(JSCell* cell) -{ - jsCast<JSObject*>(cell)->JSObject::~JSObject(); -} - void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSObject* thisObject = jsCast<JSObject*>(cell); @@ -146,47 +132,36 @@ void JSObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject)); JSGlobalData& globalData = exec->globalData(); - if (propertyName == exec->propertyNames().underscoreProto) { - // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. - if (!value.isObject() && !value.isNull()) - return; - - if (!thisObject->isExtensible()) { - if (slot.isStrictMode()) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return; - } - - if (!thisObject->setPrototypeWithCycleCheck(globalData, value)) - throwError(exec, createError(exec, "cyclic __proto__ value")); - return; - } - // Check if there are any setters or getters in the prototype chain JSValue prototype; - for (JSObject* obj = thisObject; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { - prototype = obj->prototype(); - if (prototype.isNull()) { - if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode()) - throwTypeError(exec, StrictModeReadonlyPropertyWriteError); - return; + if (propertyName != exec->propertyNames().underscoreProto) { + for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) { + prototype = obj->prototype(); + if (prototype.isNull()) { + if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode()) + throwTypeError(exec, StrictModeReadonlyPropertyWriteError); + return; + } } } - - unsigned attributes; - JSCell* specificValue; - if ((thisObject->structure()->get(globalData, propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) { - if (slot.isStrictMode()) - throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); - return; - } for (JSObject* obj = thisObject; ; obj = asObject(prototype)) { - if (JSValue gs = obj->getDirect(globalData, propertyName)) { + unsigned attributes; + JSCell* specificValue; + size_t offset = obj->structure()->get(globalData, propertyName, attributes, specificValue); + if (offset != WTF::notFound) { + if (attributes & ReadOnly) { + if (slot.isStrictMode()) + throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); + return; + } + + JSValue gs = obj->getDirectOffset(offset); if (gs.isGetterSetter()) { JSObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { - throwSetterError(exec); + if (slot.isStrictMode()) + throwSetterError(exec); return; } @@ -229,10 +204,31 @@ void JSObject::putDirectVirtual(JSObject* object, ExecState* exec, const Identif object->putDirectInternal<PutModeDefineOwnProperty>(exec->globalData(), propertyName, value, attributes, slot, getJSFunction(value)); } +bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) +{ + JSValue checkFor = this; + if (this->isGlobalObject()) + checkFor = static_cast<JSGlobalObject*>(this)->globalExec()->thisValue(); + + JSValue nextPrototype = prototype; + while (nextPrototype && nextPrototype.isObject()) { + if (nextPrototype == checkFor) + return false; + nextPrototype = asObject(nextPrototype)->prototype(); + } + setPrototype(globalData, prototype); + return true; +} + +bool JSObject::allowsAccessFrom(ExecState* exec) +{ + JSGlobalObject* globalObject = isGlobalThis() ? static_cast<JSGlobalThis*>(this)->unwrappedObject() : this->globalObject(); + return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec); +} + void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) { ASSERT(value.isGetterSetter() && (attributes & Accessor)); - ASSERT(propertyName != globalData.propertyNames->underscoreProto); PutPropertySlot slot; putDirectInternal<PutModeDefineOwnProperty>(globalData, propertyName, value, attributes, slot, getJSFunction(value)); @@ -243,7 +239,10 @@ void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& pro if (slot.type() != PutPropertySlot::NewProperty) setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes)); - structure()->setHasGetterSetterProperties(true); + if (attributes & ReadOnly) + structure()->setContainsReadOnlyProperties(); + + structure()->setHasGetterSetterProperties(propertyName == globalData.propertyNames->underscoreProto); } bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const @@ -269,7 +268,7 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& p unsigned attributes; JSCell* specificValue; if (thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) { - if ((attributes & DontDelete)) + if (attributes & DontDelete && !exec->globalData().isInDefineOwnProperty()) return false; thisObject->removeDirect(exec->globalData(), propertyName); return true; @@ -277,7 +276,7 @@ bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& p // Look in the static hashtable of properties const HashEntry* entry = thisObject->findPropertyHashEntry(exec, propertyName); - if (entry && entry->attributes() & DontDelete) + if (entry && entry->attributes() & DontDelete && !exec->globalData().isInDefineOwnProperty()) return false; // this builtin property can't be deleted // FIXME: Should the code here actually do some deletion? @@ -479,6 +478,8 @@ void JSObject::freeze(JSGlobalData& globalData) void JSObject::preventExtensions(JSGlobalData& globalData) { + if (isJSArray(this)) + asArray(this)->enterDictionaryMode(globalData); if (isExtensible()) setStructure(globalData, Structure::preventExtensionsTransition(globalData, structure())); } @@ -623,6 +624,8 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p else if (oldDescriptor.value()) newValue = oldDescriptor.value(); target->putDirect(exec->globalData(), propertyName, newValue, attributes & ~Accessor); + if (attributes & ReadOnly) + target->structure()->setContainsReadOnlyProperties(); return true; } attributes &= ~ReadOnly; @@ -641,12 +644,30 @@ static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& p return true; } +class DefineOwnPropertyScope { +public: + DefineOwnPropertyScope(ExecState* exec) + : m_globalData(exec->globalData()) + { + m_globalData.setInDefineOwnProperty(true); + } + + ~DefineOwnPropertyScope() + { + m_globalData.setInDefineOwnProperty(false); + } + +private: + JSGlobalData& m_globalData; +}; + bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException) { - // __proto__ is magic; we don't currently support setting it as a regular property. - // Silent filter out calls to set __proto__ at an early stage; pretend all is okay. - if (propertyName == exec->propertyNames().underscoreProto) - return true; + // Track on the globaldata that we're in define property. + // Currently DefineOwnProperty uses delete to remove properties when they are being replaced + // (particularly when changing attributes), however delete won't allow non-configurable (i.e. + // DontDelete) properties to be deleted. For now, we can use this flag to make this work. + DefineOwnPropertyScope scope(exec); // If we have a new property we can just put it on normally PropertyDescriptor current; @@ -711,21 +732,15 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi return false; } if (!current.writable()) { - if (descriptor.value() || !sameValue(exec, current.value(), descriptor.value())) { + if (descriptor.value() && !sameValue(exec, current.value(), descriptor.value())) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property.")); return false; } } - } else if (current.attributesEqual(descriptor)) { - if (!descriptor.value()) - return true; - PutPropertySlot slot; - object->methodTable()->put(object, exec, propertyName, descriptor.value(), slot); - if (exec->hadException()) - return false; - return true; } + if (current.attributesEqual(descriptor) && !descriptor.value()) + return true; object->methodTable()->deleteProperty(object, exec, propertyName); return putDescriptor(exec, object, propertyName, descriptor, current.attributesWithOverride(descriptor), current); } @@ -748,15 +763,14 @@ bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identi if (!accessor) return false; GetterSetter* getterSetter = asGetterSetter(accessor); - if (current.attributesEqual(descriptor)) { - if (descriptor.setterPresent()) - getterSetter->setSetter(exec->globalData(), descriptor.setterObject()); - if (descriptor.getterPresent()) - getterSetter->setGetter(exec->globalData(), descriptor.getterObject()); + if (descriptor.setterPresent()) + getterSetter->setSetter(exec->globalData(), descriptor.setterObject()); + if (descriptor.getterPresent()) + getterSetter->setGetter(exec->globalData(), descriptor.getterObject()); + if (current.attributesEqual(descriptor)) return true; - } object->methodTable()->deleteProperty(object, exec, propertyName); - unsigned attrs = current.attributesWithOverride(descriptor); + unsigned attrs = descriptor.attributesOverridingCurrent(current); object->putDirectAccessor(exec->globalData(), propertyName, getterSetter, attrs | Accessor); return true; } |