2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Eric Seidel (eric@webkit.org)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
27 #include "DatePrototype.h"
28 #include "ErrorConstructor.h"
29 #include "GetterSetter.h"
30 #include "JSFunction.h"
31 #include "JSGlobalObject.h"
32 #include "NativeErrorConstructor.h"
33 #include "ObjectPrototype.h"
34 #include "PropertyDescriptor.h"
35 #include "PropertyNameArray.h"
38 #include "Operations.h"
40 #include <wtf/Assertions.h>
44 ASSERT_CLASS_FITS_IN_CELL(JSObject);
45 ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject);
46 ASSERT_CLASS_FITS_IN_CELL(JSFinalObject);
48 const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
50 const ClassInfo JSObject::s_info = { "Object", 0, 0, 0 };
52 static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
54 // Add properties from the static hashtables of properties
55 for (; classInfo; classInfo = classInfo->parentClass) {
56 const HashTable* table = classInfo->propHashTable(exec);
59 table->initializeIfNeeded(exec);
62 int hashSizeMask = table->compactSize - 1;
63 const HashEntry* entry = table->table;
64 for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
65 if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)))
66 propertyNames.add(entry->key());
71 void JSObject::visitChildren(SlotVisitor& visitor)
73 ASSERT_GC_OBJECT_INHERITS(this, &s_info);
75 bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
76 visitor.m_isCheckingForDefaultMarkViolation = false;
79 visitChildrenDirect(visitor);
82 visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
86 UString JSObject::className() const
88 const ClassInfo* info = classInfo();
90 return info->className;
93 bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
95 return getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot);
98 static void throwSetterError(ExecState* exec)
100 throwError(exec, createTypeError(exec, "setting a property that has only a getter"));
104 void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
107 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
109 if (propertyName == exec->propertyNames().underscoreProto) {
110 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
111 if (!value.isObject() && !value.isNull())
114 if (!isExtensible()) {
115 if (slot.isStrictMode())
116 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
120 if (!setPrototypeWithCycleCheck(exec->globalData(), value))
121 throwError(exec, createError(exec, "cyclic __proto__ value"));
125 // Check if there are any setters or getters in the prototype chain
127 for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
128 prototype = obj->prototype();
129 if (prototype.isNull()) {
130 if (!putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot) && slot.isStrictMode())
131 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
137 JSCell* specificValue;
138 if ((m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) {
139 if (slot.isStrictMode())
140 throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
144 for (JSObject* obj = this; ; obj = asObject(prototype)) {
145 if (JSValue gs = obj->getDirect(exec->globalData(), propertyName)) {
146 if (gs.isGetterSetter()) {
147 JSObject* setterFunc = asGetterSetter(gs)->setter();
149 throwSetterError(exec);
154 CallType callType = setterFunc->getCallData(callData);
155 MarkedArgumentBuffer args;
158 // If this is WebCore's global object then we need to substitute the shell.
159 call(exec, setterFunc, callType, callData, this->toThisObject(exec), args);
163 // If there's an existing property on the object or one of its
164 // prototypes it should be replaced, so break here.
168 prototype = obj->prototype();
169 if (prototype.isNull())
173 if (!putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot) && slot.isStrictMode())
174 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
178 void JSObject::put(ExecState* exec, unsigned propertyName, JSValue value)
180 PutPropertySlot slot;
181 put(exec, Identifier::from(exec, propertyName), value, slot);
184 void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
186 putDirectInternal(*globalData, propertyName, value, attributes, checkReadOnly, slot);
189 void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
191 putDirectInternal(*globalData, propertyName, value, attributes);
194 void JSObject::putWithAttributes(JSGlobalData* globalData, unsigned propertyName, JSValue value, unsigned attributes)
196 putWithAttributes(globalData, Identifier::from(globalData, propertyName), value, attributes);
199 void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
201 putDirectInternal(exec->globalData(), propertyName, value, attributes, checkReadOnly, slot);
204 void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
206 putDirectInternal(exec->globalData(), propertyName, value, attributes);
209 void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes)
211 putWithAttributes(exec, Identifier::from(exec, propertyName), value, attributes);
214 bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const
217 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
220 bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
223 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
227 bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
230 JSCell* specificValue;
231 if (m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) {
232 if ((attributes & DontDelete))
234 removeDirect(exec->globalData(), propertyName);
238 // Look in the static hashtable of properties
239 const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
240 if (entry && entry->attributes() & DontDelete)
241 return false; // this builtin property can't be deleted
243 // FIXME: Should the code here actually do some deletion?
247 bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
250 return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
253 bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName)
255 return deleteProperty(exec, Identifier::from(exec, propertyName));
258 static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName)
260 JSValue function = object->get(exec, propertyName);
262 CallType callType = getCallData(function, callData);
263 if (callType == CallTypeNone)
264 return exec->exception();
266 // Prevent "toString" and "valueOf" from observing execution if an exception
268 if (exec->hadException())
269 return exec->exception();
271 JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
272 ASSERT(!result.isGetterSetter());
273 if (exec->hadException())
274 return exec->exception();
275 if (result.isObject())
280 bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
282 result = defaultValue(exec, PreferNumber);
283 number = result.toNumber(exec);
284 return !result.isString();
288 JSValue JSObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
290 // Must call toString first for Date objects.
291 if ((hint == PreferString) || (hint != PreferNumber && prototype() == exec->lexicalGlobalObject()->datePrototype())) {
292 JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().toString);
295 value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf);
299 JSValue value = callDefaultValueFunction(exec, this, exec->propertyNames().valueOf);
302 value = callDefaultValueFunction(exec, this, exec->propertyNames().toString);
307 ASSERT(!exec->hadException());
309 return throwError(exec, createTypeError(exec, "No default value"));
312 const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
314 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
315 if (const HashTable* propHashTable = info->propHashTable(exec)) {
316 if (const HashEntry* entry = propHashTable->entry(exec, propertyName))
323 void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes)
325 if (propertyName == exec->propertyNames().underscoreProto) {
326 // Defining a getter for __proto__ is silently ignored.
330 JSValue object = getDirect(exec->globalData(), propertyName);
331 if (object && object.isGetterSetter()) {
332 ASSERT(m_structure->hasGetterSetterProperties());
333 asGetterSetter(object)->setGetter(exec->globalData(), getterFunction);
337 JSGlobalData& globalData = exec->globalData();
338 PutPropertySlot slot;
339 GetterSetter* getterSetter = GetterSetter::create(exec);
340 putDirectInternal(globalData, propertyName, getterSetter, attributes | Getter, true, slot);
342 // putDirect will change our Structure if we add a new property. For
343 // getters and setters, though, we also need to change our Structure
344 // if we override an existing non-getter or non-setter.
345 if (slot.type() != PutPropertySlot::NewProperty) {
346 if (!m_structure->isDictionary())
347 setStructure(exec->globalData(), Structure::getterSetterTransition(globalData, m_structure.get()));
350 m_structure->setHasGetterSetterProperties(true);
351 getterSetter->setGetter(globalData, getterFunction);
354 void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes)
356 if (propertyName == exec->propertyNames().underscoreProto) {
357 // Defining a setter for __proto__ is silently ignored.
361 JSValue object = getDirect(exec->globalData(), propertyName);
362 if (object && object.isGetterSetter()) {
363 ASSERT(m_structure->hasGetterSetterProperties());
364 asGetterSetter(object)->setSetter(exec->globalData(), setterFunction);
368 PutPropertySlot slot;
369 GetterSetter* getterSetter = GetterSetter::create(exec);
370 putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Setter, true, slot);
372 // putDirect will change our Structure if we add a new property. For
373 // getters and setters, though, we also need to change our Structure
374 // if we override an existing non-getter or non-setter.
375 if (slot.type() != PutPropertySlot::NewProperty) {
376 if (!m_structure->isDictionary())
377 setStructure(exec->globalData(), Structure::getterSetterTransition(exec->globalData(), m_structure.get()));
380 m_structure->setHasGetterSetterProperties(true);
381 getterSetter->setSetter(exec->globalData(), setterFunction);
384 JSValue JSObject::lookupGetter(ExecState* exec, const Identifier& propertyName)
386 JSObject* object = this;
388 if (JSValue value = object->getDirect(exec->globalData(), propertyName)) {
389 if (!value.isGetterSetter())
390 return jsUndefined();
391 JSObject* functionObject = asGetterSetter(value)->getter();
393 return jsUndefined();
394 return functionObject;
397 if (!object->prototype() || !object->prototype().isObject())
398 return jsUndefined();
399 object = asObject(object->prototype());
403 JSValue JSObject::lookupSetter(ExecState* exec, const Identifier& propertyName)
405 JSObject* object = this;
407 if (JSValue value = object->getDirect(exec->globalData(), propertyName)) {
408 if (!value.isGetterSetter())
409 return jsUndefined();
410 JSObject* functionObject = asGetterSetter(value)->setter();
412 return jsUndefined();
413 return functionObject;
416 if (!object->prototype() || !object->prototype().isObject())
417 return jsUndefined();
418 object = asObject(object->prototype());
422 bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue proto)
424 if (!value.isObject())
427 if (!proto.isObject()) {
428 throwError(exec, createTypeError(exec, "instanceof called on an object with an invalid prototype property."));
432 JSObject* object = asObject(value);
433 while ((object = object->prototype().getObject())) {
440 bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
442 PropertyDescriptor descriptor;
443 if (!const_cast<JSObject*>(this)->getOwnPropertyDescriptor(exec, propertyName, descriptor))
445 return descriptor.enumerable();
448 bool JSObject::getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificValue) const
451 if (m_structure->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound)
454 // This could be a function within the static table? - should probably
455 // also look in the hash? This currently should not be a problem, since
456 // we've currently always call 'get' first, which should have populated
457 // the normal storage.
461 void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
463 getOwnPropertyNames(exec, propertyNames, mode);
465 if (prototype().isNull())
468 JSObject* prototype = asObject(this->prototype());
470 if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
471 prototype->getPropertyNames(exec, propertyNames, mode);
474 prototype->getOwnPropertyNames(exec, propertyNames, mode);
475 JSValue nextProto = prototype->prototype();
476 if (nextProto.isNull())
478 prototype = asObject(nextProto);
482 void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
484 m_structure->getPropertyNames(exec->globalData(), propertyNames, mode);
485 getClassPropertyNames(exec, classInfo(), propertyNames, mode);
488 bool JSObject::toBoolean(ExecState*) const
493 double JSObject::toNumber(ExecState* exec) const
495 JSValue primitive = toPrimitive(exec, PreferNumber);
496 if (exec->hadException()) // should be picked up soon in Nodes.cpp
498 return primitive.toNumber(exec);
501 UString JSObject::toString(ExecState* exec) const
503 JSValue primitive = toPrimitive(exec, PreferString);
504 if (exec->hadException())
506 return primitive.toString(exec);
509 JSObject* JSObject::toObject(ExecState*, JSGlobalObject*) const
511 return const_cast<JSObject*>(this);
514 JSObject* JSObject::toThisObject(ExecState*) const
516 return const_cast<JSObject*>(this);
519 JSValue JSObject::toStrictThisObject(ExecState*) const
521 return const_cast<JSObject*>(this);
524 JSObject* JSObject::unwrappedObject()
529 void JSObject::seal(JSGlobalData& globalData)
531 if (isSealed(globalData))
533 preventExtensions(globalData);
534 setStructure(globalData, Structure::sealTransition(globalData, m_structure.get()));
537 void JSObject::freeze(JSGlobalData& globalData)
539 if (isFrozen(globalData))
541 preventExtensions(globalData);
542 setStructure(globalData, Structure::freezeTransition(globalData, m_structure.get()));
545 void JSObject::preventExtensions(JSGlobalData& globalData)
548 setStructure(globalData, Structure::preventExtensionsTransition(globalData, m_structure.get()));
551 void JSObject::removeDirect(JSGlobalData& globalData, const Identifier& propertyName)
553 if (m_structure->get(globalData, propertyName) == WTF::notFound)
557 if (m_structure->isUncacheableDictionary()) {
558 offset = m_structure->removePropertyWithoutTransition(globalData, propertyName);
559 if (offset != WTF::notFound)
560 putUndefinedAtDirectOffset(offset);
564 setStructure(globalData, Structure::removePropertyTransition(globalData, m_structure.get(), propertyName, offset));
565 if (offset != WTF::notFound)
566 putUndefinedAtDirectOffset(offset);
569 void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr)
571 putDirectFunction(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
574 void JSObject::putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr)
576 putDirectFunction(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
579 void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr)
581 putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
584 void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr)
586 putDirectFunctionWithoutTransition(exec->globalData(), Identifier(exec, function->name(exec)), function, attr);
589 NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarrierBase<Unknown>* location)
591 if (JSObject* getterFunction = asGetterSetter(location->get())->getter()) {
592 if (!structure()->isDictionary())
593 slot.setCacheableGetterSlot(this, getterFunction, offsetForLocation(location));
595 slot.setGetterSlot(getterFunction);
600 Structure* JSObject::createInheritorID(JSGlobalData& globalData)
602 m_inheritorID.set(globalData, this, createEmptyObjectStructure(globalData, m_structure->globalObject(), this));
603 ASSERT(m_inheritorID->isEmpty());
604 return m_inheritorID.get();
607 void JSObject::allocatePropertyStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
609 ASSERT(newSize > oldSize);
611 // It's important that this function not rely on m_structure, since
612 // we might be in the middle of a transition.
613 PropertyStorage newPropertyStorage = 0;
614 if (globalData.heap.inPropertyStorageNursery(m_propertyStorage.get())) {
615 newPropertyStorage = static_cast<PropertyStorage>(globalData.heap.allocatePropertyStorage(newSize * sizeof(WriteBarrierBase<Unknown>)));
616 if (!newPropertyStorage || !globalData.heap.inPropertyStorageNursery(m_propertyStorage.get())) {
617 // If allocation failed because it's too big, or it triggered a GC
618 // that promoted us to old space, we need to allocate our property
619 // storage in old space.
620 newPropertyStorage = new WriteBarrierBase<Unknown>[newSize];
623 newPropertyStorage = new WriteBarrierBase<Unknown>[newSize];
625 PropertyStorage oldPropertyStorage = m_propertyStorage.get();
626 ASSERT(newPropertyStorage);
628 for (unsigned i = 0; i < oldSize; ++i)
629 newPropertyStorage[i] = oldPropertyStorage[i];
631 if (!isUsingInlineStorage() && !globalData.heap.inPropertyStorageNursery(m_propertyStorage.get()))
632 delete [] oldPropertyStorage;
634 m_propertyStorage.set(globalData, this, newPropertyStorage);
637 bool JSObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
639 unsigned attributes = 0;
641 size_t offset = m_structure->get(exec->globalData(), propertyName, attributes, cell);
642 if (offset == WTF::notFound)
644 descriptor.setDescriptor(getDirectOffset(offset), attributes);
648 bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
650 JSObject* object = this;
652 if (object->getOwnPropertyDescriptor(exec, propertyName, descriptor))
654 JSValue prototype = object->prototype();
655 if (!prototype.isObject())
657 object = asObject(prototype);
661 static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
663 if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
664 if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
665 GetterSetter* accessor = GetterSetter::create(exec);
666 if (oldDescriptor.getter()) {
667 attributes |= Getter;
668 accessor->setGetter(exec->globalData(), asObject(oldDescriptor.getter()));
670 if (oldDescriptor.setter()) {
671 attributes |= Setter;
672 accessor->setSetter(exec->globalData(), asObject(oldDescriptor.setter()));
674 target->putWithAttributes(exec, propertyName, accessor, attributes);
677 JSValue newValue = jsUndefined();
678 if (descriptor.value())
679 newValue = descriptor.value();
680 else if (oldDescriptor.value())
681 newValue = oldDescriptor.value();
682 target->putWithAttributes(exec, propertyName, newValue, attributes & ~(Getter | Setter));
685 attributes &= ~ReadOnly;
686 if (descriptor.getter() && descriptor.getter().isObject())
687 target->defineGetter(exec, propertyName, asObject(descriptor.getter()), attributes);
688 if (exec->hadException())
690 if (descriptor.setter() && descriptor.setter().isObject())
691 target->defineSetter(exec, propertyName, asObject(descriptor.setter()), attributes);
692 return !exec->hadException();
695 bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
697 // If we have a new property we can just put it on normally
698 PropertyDescriptor current;
699 if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
700 // unless extensions are prevented!
701 if (!isExtensible()) {
703 throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
706 PropertyDescriptor oldDescriptor;
707 oldDescriptor.setValue(jsUndefined());
708 return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
711 if (descriptor.isEmpty())
714 if (current.equalTo(exec, descriptor))
717 // Filter out invalid changes
718 if (!current.configurable()) {
719 if (descriptor.configurable()) {
721 throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
724 if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
726 throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
731 // A generic descriptor is simply changing the attributes of an existing property
732 if (descriptor.isGenericDescriptor()) {
733 if (!current.attributesEqual(descriptor)) {
734 deleteProperty(exec, propertyName);
735 putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
740 // Changing between a normal property or an accessor property
741 if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
742 if (!current.configurable()) {
744 throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
747 deleteProperty(exec, propertyName);
748 return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
751 // Changing the value and attributes of an existing property
752 if (descriptor.isDataDescriptor()) {
753 if (!current.configurable()) {
754 if (!current.writable() && descriptor.writable()) {
756 throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
759 if (!current.writable()) {
760 if (descriptor.value() || !JSValue::strictEqual(exec, current.value(), descriptor.value())) {
762 throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
766 } else if (current.attributesEqual(descriptor)) {
767 if (!descriptor.value())
769 PutPropertySlot slot;
770 put(exec, propertyName, descriptor.value(), slot);
771 if (exec->hadException())
775 deleteProperty(exec, propertyName);
776 return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
779 // Changing the accessor functions of an existing accessor property
780 ASSERT(descriptor.isAccessorDescriptor());
781 if (!current.configurable()) {
782 if (descriptor.setterPresent() && !(current.setterPresent() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) {
784 throwError(exec, createTypeError(exec, "Attempting to change the setter of an unconfigurable property."));
787 if (descriptor.getterPresent() && !(current.getterPresent() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) {
789 throwError(exec, createTypeError(exec, "Attempting to change the getter of an unconfigurable property."));
793 JSValue accessor = getDirect(exec->globalData(), propertyName);
796 GetterSetter* getterSetter = asGetterSetter(accessor);
797 if (current.attributesEqual(descriptor)) {
798 if (descriptor.setter())
799 getterSetter->setSetter(exec->globalData(), asObject(descriptor.setter()));
800 if (descriptor.getter())
801 getterSetter->setGetter(exec->globalData(), asObject(descriptor.getter()));
804 deleteProperty(exec, propertyName);
805 unsigned attrs = current.attributesWithOverride(descriptor);
806 if (descriptor.setter())
808 if (descriptor.getter())
810 putDirect(exec->globalData(), propertyName, getterSetter, attrs);
814 JSObject* throwTypeError(ExecState* exec, const UString& message)
816 return throwError(exec, createTypeError(exec, message));