diff options
Diffstat (limited to 'src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp')
-rw-r--r-- | src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp | 699 |
1 files changed, 0 insertions, 699 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp deleted file mode 100644 index 0e3475f..0000000 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp +++ /dev/null @@ -1,699 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Eric Seidel (eric@webkit.org) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "JSObject.h" - -#include "DatePrototype.h" -#include "ErrorConstructor.h" -#include "GetterSetter.h" -#include "JSGlobalObject.h" -#include "NativeErrorConstructor.h" -#include "ObjectPrototype.h" -#include "PropertyDescriptor.h" -#include "PropertyNameArray.h" -#include "Lookup.h" -#include "Nodes.h" -#include "Operations.h" -#include <math.h> -#include <wtf/Assertions.h> - -namespace JSC { - -ASSERT_CLASS_FITS_IN_CELL(JSObject); - -static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - // Add properties from the static hashtables of properties - for (; classInfo; classInfo = classInfo->parentClass) { - const HashTable* table = classInfo->propHashTable(exec); - if (!table) - continue; - table->initializeIfNeeded(exec); - ASSERT(table->table); - - int hashSizeMask = table->compactSize - 1; - const HashEntry* entry = table->table; - for (int i = 0; i <= hashSizeMask; ++i, ++entry) { - if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties))) - propertyNames.add(entry->key()); - } - } -} - -void JSObject::markChildren(MarkStack& markStack) -{ -#ifndef NDEBUG - bool wasCheckingForDefaultMarkViolation = markStack.m_isCheckingForDefaultMarkViolation; - markStack.m_isCheckingForDefaultMarkViolation = false; -#endif - - markChildrenDirect(markStack); - -#ifndef NDEBUG - markStack.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation; -#endif -} - -UString JSObject::className() const -{ - const ClassInfo* info = classInfo(); - if (info) - return info->className; - return "Object"; -} - -bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) -{ - return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); -} - -static void throwSetterError(ExecState* exec) -{ - throwError(exec, TypeError, "setting a property that has only a getter"); -} - -// ECMA 8.6.2.2 -void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) -{ - ASSERT(value); - ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); - - 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; - - JSValue nextPrototypeValue = value; - while (nextPrototypeValue && nextPrototypeValue.isObject()) { - JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject(); - if (nextPrototype == this) { - throwError(exec, GeneralError, "cyclic __proto__ value"); - return; - } - nextPrototypeValue = nextPrototype->prototype(); - } - - setPrototype(value); - return; - } - - // Check if there are any setters or getters in the prototype chain - JSValue prototype; - for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { - prototype = obj->prototype(); - if (prototype.isNull()) { - putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); - return; - } - } - - unsigned attributes; - JSCell* specificValue; - if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) - return; - - for (JSObject* obj = this; ; obj = asObject(prototype)) { -#ifdef QT_BUILD_SCRIPT_LIB - PropertyDescriptor descriptor; - if (obj->getPropertyDescriptor(exec, propertyName, descriptor)) { - JSObject* setterFunc; - if ((descriptor.isAccessorDescriptor() && ((setterFunc = asObject(descriptor.setter())), true)) - || (descriptor.value().isGetterSetter() && ((setterFunc = asGetterSetter(descriptor.value())->setter()), true))) { -#else - if (JSValue gs = obj->getDirect(propertyName)) { - if (gs.isGetterSetter()) { - JSObject* setterFunc = asGetterSetter(gs)->setter(); -#endif - if (!setterFunc) { - throwSetterError(exec); - return; - } - - CallData callData; - CallType callType = setterFunc->getCallData(callData); - MarkedArgumentBuffer args; - args.append(value); - call(exec, setterFunc, callType, callData, this, args); - return; - } - - // If there's an existing property on the object or one of its - // prototypes it should be replaced, so break here. - break; - } - - prototype = obj->prototype(); - if (prototype.isNull()) - break; - } - - putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); - return; -} - -void JSObject::put(ExecState* exec, unsigned propertyName, JSValue value) -{ - PutPropertySlot slot; - put(exec, Identifier::from(exec, propertyName), value, slot); -} - -void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) -{ - putDirectInternal(exec->globalData(), propertyName, value, attributes, checkReadOnly, slot); -} - -void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes) -{ - putDirectInternal(exec->globalData(), propertyName, value, attributes); -} - -void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes) -{ - putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes); -} - -bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const -{ - PropertySlot slot; - return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot); -} - -bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const -{ - PropertySlot slot; - return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot); -} - -// ECMA 8.6.2.5 -bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName) -{ - unsigned attributes; - JSCell* specificValue; - if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) { - if ((attributes & DontDelete)) - return false; - removeDirect(propertyName); - return true; - } - - // Look in the static hashtable of properties - const HashEntry* entry = findPropertyHashEntry(exec, propertyName); - if (entry && entry->attributes() & DontDelete) - return false; // this builtin property can't be deleted - - // FIXME: Should the code here actually do some deletion? - return true; -} - -bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const -{ - PropertySlot slot; - return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot); -} - -bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName) -{ - return deleteProperty(exec, Identifier::from(exec, propertyName)); -} - -static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName) -{ - JSValue function = object->get(exec, propertyName); - CallData callData; - CallType callType = function.getCallData(callData); - if (callType == CallTypeNone) - return exec->exception(); - - // Prevent "toString" and "valueOf" from observing execution if an exception - // is pending. - if (exec->hadException()) - return exec->exception(); - - JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList()); - ASSERT(!result.isGetterSetter()); - if (exec->hadException()) - return exec->exception(); - if (result.isObject()) - return JSValue(); - return result; -} - -bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) -{ - result = defaultValue(exec, PreferNumber); - number = result.toNumber(exec); - return !result.isString(); -} - -// ECMA 8.6.2.6 -JSValue JSObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const -{ - // Must call toString first for Date objects. - if ((hint == PreferString) || (hint != PreferNumber && prototype() == exec->lexicalGlobalObject()->datePrototype())) { - JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().toString); - if (value) - return value; - value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf); - if (value) - return value; - } else { - JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf); - if (value) - return value; - value = callDefaultValueFunction(exec, this, exec->propertyNames().toString); - if (value) - return value; - } - - ASSERT(!exec->hadException()); - - return throwError(exec, TypeError, "No default value"); -} - -const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const -{ - for (const ClassInfo* info = classInfo(); info; info = info->parentClass) { - if (const HashTable* propHashTable = info->propHashTable(exec)) { - if (const HashEntry* entry = propHashTable->entry(exec, propertyName)) - return entry; - } - } - return 0; -} - -void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) -{ - JSValue object = getDirect(propertyName); - if (object && object.isGetterSetter()) { - ASSERT(m_structure->hasGetterSetterProperties()); - asGetterSetter(object)->setGetter(getterFunction); - return; - } - - PutPropertySlot slot; - GetterSetter* getterSetter = new (exec) GetterSetter(exec); - putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Getter, true, slot); - - // putDirect will change our Structure if we add a new property. For - // getters and setters, though, we also need to change our Structure - // if we override an existing non-getter or non-setter. - if (slot.type() != PutPropertySlot::NewProperty) { - if (!m_structure->isDictionary()) { - RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure); - setStructure(structure.release()); - } - } - - m_structure->setHasGetterSetterProperties(true); - getterSetter->setGetter(getterFunction); -} - -void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) -{ - JSValue object = getDirect(propertyName); - if (object && object.isGetterSetter()) { - ASSERT(m_structure->hasGetterSetterProperties()); - asGetterSetter(object)->setSetter(setterFunction); - return; - } - - PutPropertySlot slot; - GetterSetter* getterSetter = new (exec) GetterSetter(exec); - putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Setter, true, slot); - - // putDirect will change our Structure if we add a new property. For - // getters and setters, though, we also need to change our Structure - // if we override an existing non-getter or non-setter. - if (slot.type() != PutPropertySlot::NewProperty) { - if (!m_structure->isDictionary()) { - RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure); - setStructure(structure.release()); - } - } - - m_structure->setHasGetterSetterProperties(true); - getterSetter->setSetter(setterFunction); -} - -JSValue JSObject::lookupGetter(ExecState*, const Identifier& propertyName) -{ - JSObject* object = this; - while (true) { - if (JSValue value = object->getDirect(propertyName)) { - if (!value.isGetterSetter()) - return jsUndefined(); - JSObject* functionObject = asGetterSetter(value)->getter(); - if (!functionObject) - return jsUndefined(); - return functionObject; - } - - if (!object->prototype() || !object->prototype().isObject()) - return jsUndefined(); - object = asObject(object->prototype()); - } -} - -JSValue JSObject::lookupSetter(ExecState*, const Identifier& propertyName) -{ - JSObject* object = this; - while (true) { - if (JSValue value = object->getDirect(propertyName)) { - if (!value.isGetterSetter()) - return jsUndefined(); - JSObject* functionObject = asGetterSetter(value)->setter(); - if (!functionObject) - return jsUndefined(); - return functionObject; - } - - if (!object->prototype() || !object->prototype().isObject()) - return jsUndefined(); - object = asObject(object->prototype()); - } -} - -bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue proto) -{ - if (!value.isObject()) - return false; - - if (!proto.isObject()) { - throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property."); - return false; - } - - JSObject* object = asObject(value); - while ((object = object->prototype().getObject())) { - if (proto == object) - return true; - } - return false; -} - -bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const -{ - PropertyDescriptor descriptor; - if (!const_cast<JSObject*>(this)->getOwnPropertyDescriptor(exec, propertyName, descriptor)) - return false; - return descriptor.enumerable(); -} - -bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyName, JSCell*& specificValue) const -{ - unsigned attributes; - if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) - return true; - - // This could be a function within the static table? - should probably - // also look in the hash? This currently should not be a problem, since - // we've currently always call 'get' first, which should have populated - // the normal storage. - return false; -} - -void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - getOwnPropertyNames(exec, propertyNames, mode); - - if (prototype().isNull()) - return; - - JSObject* prototype = asObject(this->prototype()); - while(1) { - if (prototype->structure()->typeInfo().overridesGetPropertyNames()) { - prototype->getPropertyNames(exec, propertyNames, mode); - break; - } - prototype->getOwnPropertyNames(exec, propertyNames, mode); - JSValue nextProto = prototype->prototype(); - if (nextProto.isNull()) - break; - prototype = asObject(nextProto); - } -} - -void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - m_structure->getPropertyNames(propertyNames, mode); - getClassPropertyNames(exec, classInfo(), propertyNames, mode); -} - -bool JSObject::toBoolean(ExecState*) const -{ - return true; -} - -double JSObject::toNumber(ExecState* exec) const -{ - JSValue primitive = toPrimitive(exec, PreferNumber); - if (exec->hadException()) // should be picked up soon in Nodes.cpp - return 0.0; - return primitive.toNumber(exec); -} - -UString JSObject::toString(ExecState* exec) const -{ - JSValue primitive = toPrimitive(exec, PreferString); - if (exec->hadException()) - return ""; - return primitive.toString(exec); -} - -JSObject* JSObject::toObject(ExecState*) const -{ - return const_cast<JSObject*>(this); -} - -JSObject* JSObject::toThisObject(ExecState*) const -{ - return const_cast<JSObject*>(this); -} - -JSObject* JSObject::unwrappedObject() -{ - return this; -} - -void JSObject::removeDirect(const Identifier& propertyName) -{ - size_t offset; - if (m_structure->isUncacheableDictionary()) { - offset = m_structure->removePropertyWithoutTransition(propertyName); - if (offset != WTF::notFound) - putDirectOffset(offset, jsUndefined()); - return; - } - - RefPtr<Structure> structure = Structure::removePropertyTransition(m_structure, propertyName, offset); - setStructure(structure.release()); - if (offset != WTF::notFound) - putDirectOffset(offset, jsUndefined()); -} - -void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr) -{ - putDirectFunction(Identifier(exec, function->name(exec)), function, attr); -} - -void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr) -{ - putDirectFunctionWithoutTransition(Identifier(exec, function->name(exec)), function, attr); -} - -NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location) -{ - if (JSObject* getterFunction = asGetterSetter(*location)->getter()) - slot.setGetterSlot(getterFunction); - else - slot.setUndefined(); -} - -Structure* JSObject::createInheritorID() -{ -#ifdef QT_BUILD_SCRIPT_LIB - // ### QtScript needs the hasOwnProperty() calls etc. for QScriptObject - m_inheritorID = Structure::create(this, TypeInfo(ObjectType, ImplementsHasInstance | JSC::OverridesHasInstance | JSC::OverridesGetOwnPropertySlot | JSC::OverridesMarkChildren | JSC::OverridesGetPropertyNames)); -#else - m_inheritorID = JSObject::createStructure(this); -#endif - return m_inheritorID.get(); -} - -void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize) -{ - allocatePropertyStorageInline(oldSize, newSize); -} - -bool JSObject::getOwnPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor& descriptor) -{ - unsigned attributes = 0; - JSCell* cell = 0; - size_t offset = m_structure->get(propertyName, attributes, cell); - if (offset == WTF::notFound) - return false; - descriptor.setDescriptor(getDirectOffset(offset), attributes); - return true; -} - -bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) -{ - JSObject* object = this; - while (true) { - if (object->getOwnPropertyDescriptor(exec, propertyName, descriptor)) - return true; - JSValue prototype = object->prototype(); - if (!prototype.isObject()) - return false; - object = asObject(prototype); - } -} - -static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, JSValue oldValue) -{ - if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) { - target->putWithAttributes(exec, propertyName, descriptor.value() ? descriptor.value() : oldValue, attributes & ~(Getter | Setter)); - return true; - } - attributes &= ~ReadOnly; - if (descriptor.getter() && descriptor.getter().isObject()) - target->defineGetter(exec, propertyName, asObject(descriptor.getter()), attributes); - if (exec->hadException()) - return false; - if (descriptor.setter() && descriptor.setter().isObject()) - target->defineSetter(exec, propertyName, asObject(descriptor.setter()), attributes); - return !exec->hadException(); -} - -bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException) -{ - // If we have a new property we can just put it on normally - PropertyDescriptor current; - if (!getOwnPropertyDescriptor(exec, propertyName, current)) - return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), jsUndefined()); - - if (descriptor.isEmpty()) - return true; - - if (current.equalTo(exec, descriptor)) - return true; - - // Filter out invalid changes - if (!current.configurable()) { - if (descriptor.configurable()) { - if (throwException) - throwError(exec, TypeError, "Attempting to configurable attribute of unconfigurable property."); - return false; - } - if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) { - if (throwException) - throwError(exec, TypeError, "Attempting to change enumerable attribute of unconfigurable property."); - return false; - } - } - - // A generic descriptor is simply changing the attributes of an existing property - if (descriptor.isGenericDescriptor()) { - if (!current.attributesEqual(descriptor)) { - deleteProperty(exec, propertyName); - putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value()); - } - return true; - } - - // Changing between a normal property or an accessor property - if (descriptor.isDataDescriptor() != current.isDataDescriptor()) { - if (!current.configurable()) { - if (throwException) - throwError(exec, TypeError, "Attempting to change access mechanism for an unconfigurable property."); - return false; - } - deleteProperty(exec, propertyName); - return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value() ? current.value() : jsUndefined()); - } - - // Changing the value and attributes of an existing property - if (descriptor.isDataDescriptor()) { - if (!current.configurable()) { - if (!current.writable() && descriptor.writable()) { - if (throwException) - throwError(exec, TypeError, "Attempting to change writable attribute of unconfigurable property."); - return false; - } - if (!current.writable()) { - if (descriptor.value() || !JSValue::strictEqual(exec, current.value(), descriptor.value())) { - if (throwException) - throwError(exec, TypeError, "Attempting to change value of a readonly property."); - return false; - } - } - } else if (current.attributesEqual(descriptor)) { - if (!descriptor.value()) - return true; - PutPropertySlot slot; - put(exec, propertyName, descriptor.value(), slot); - if (exec->hadException()) - return false; - return true; - } - deleteProperty(exec, propertyName); - return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value()); - } - - // Changing the accessor functions of an existing accessor property - ASSERT(descriptor.isAccessorDescriptor()); - if (!current.configurable()) { - if (descriptor.setterPresent() && !(current.setter() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) { - if (throwException) - throwError(exec, TypeError, "Attempting to change the setter of an unconfigurable property."); - return false; - } - if (descriptor.getterPresent() && !(current.getter() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) { - if (throwException) - throwError(exec, TypeError, "Attempting to change the getter of an unconfigurable property."); - return false; - } - } - JSValue accessor = getDirect(propertyName); - if (!accessor) - return false; - GetterSetter* getterSetter = asGetterSetter(accessor); - if (current.attributesEqual(descriptor)) { - if (descriptor.setter()) - getterSetter->setSetter(asObject(descriptor.setter())); - if (descriptor.getter()) - getterSetter->setGetter(asObject(descriptor.getter())); - return true; - } - deleteProperty(exec, propertyName); - unsigned attrs = current.attributesWithOverride(descriptor); - if (descriptor.setter()) - attrs |= Setter; - if (descriptor.getter()) - attrs |= Getter; - putDirect(propertyName, getterSetter, attrs); - return true; -} - -} // namespace JSC |