1/*
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)
6 *
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.
11 *
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.
16 *
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.
21 *
22 */
23
24#include "config.h"
25#include "JSObject.h"
26
27#include "DatePrototype.h"
28#include "ErrorConstructor.h"
29#include "GetterSetter.h"
30#include "JSGlobalObject.h"
31#include "NativeErrorConstructor.h"
32#include "ObjectPrototype.h"
33#include "PropertyDescriptor.h"
34#include "PropertyNameArray.h"
35#include "Lookup.h"
36#include "Nodes.h"
37#include "Operations.h"
38#include <math.h>
39#include <wtf/Assertions.h>
40
41namespace JSC {
42
43ASSERT_CLASS_FITS_IN_CELL(JSObject);
44
45static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
46{
47 // Add properties from the static hashtables of properties
48 for (; classInfo; classInfo = classInfo->parentClass) {
49 const HashTable* table = classInfo->propHashTable(exec);
50 if (!table)
51 continue;
52 table->initializeIfNeeded(exec);
53 ASSERT(table->table);
54
55 int hashSizeMask = table->compactSize - 1;
56 const HashEntry* entry = table->table;
57 for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
58 if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)))
59 propertyNames.add(entry->key());
60 }
61 }
62}
63
64void JSObject::markChildren(MarkStack& markStack)
65{
66#ifndef NDEBUG
67 bool wasCheckingForDefaultMarkViolation = markStack.m_isCheckingForDefaultMarkViolation;
68 markStack.m_isCheckingForDefaultMarkViolation = false;
69#endif
70
71 markChildrenDirect(markStack);
72
73#ifndef NDEBUG
74 markStack.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
75#endif
76}
77
78UString JSObject::className() const
79{
80 const ClassInfo* info = classInfo();
81 if (info)
82 return info->className;
83 return "Object";
84}
85
86bool JSObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
87{
88 return getOwnPropertySlot(exec, propertyName: Identifier::from(exec, y: propertyName), slot);
89}
90
91static void throwSetterError(ExecState* exec)
92{
93 throwError(exec, TypeError, message: "setting a property that has only a getter");
94}
95
96// ECMA 8.6.2.2
97void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
98{
99 ASSERT(value);
100 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
101
102 if (propertyName == exec->propertyNames().underscoreProto) {
103 // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
104 if (!value.isObject() && !value.isNull())
105 return;
106
107 JSValue nextPrototypeValue = value;
108 while (nextPrototypeValue && nextPrototypeValue.isObject()) {
109 JSObject* nextPrototype = asObject(value: nextPrototypeValue)->unwrappedObject();
110 if (nextPrototype == this) {
111 throwError(exec, GeneralError, message: "cyclic __proto__ value");
112 return;
113 }
114 nextPrototypeValue = nextPrototype->prototype();
115 }
116
117 setPrototype(value);
118 return;
119 }
120
121 // Check if there are any setters or getters in the prototype chain
122 JSValue prototype;
123 for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(value: prototype)) {
124 prototype = obj->prototype();
125 if (prototype.isNull()) {
126 putDirectInternal(globalData&: exec->globalData(), propertyName, value, attributes: 0, checkReadOnly: true, slot);
127 return;
128 }
129 }
130
131 unsigned attributes;
132 JSCell* specificValue;
133 if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly)
134 return;
135
136 for (JSObject* obj = this; ; obj = asObject(value: prototype)) {
137#ifdef QT_BUILD_SCRIPT_LIB
138 PropertyDescriptor descriptor;
139 if (obj->getPropertyDescriptor(exec, propertyName, descriptor)) {
140 JSObject* setterFunc;
141 if ((descriptor.isAccessorDescriptor() && !!descriptor.setter() && ((setterFunc = asObject(value: descriptor.setter())), true))
142 || (!!descriptor.value() && descriptor.value().isGetterSetter() && ((setterFunc = asGetterSetter(value: descriptor.value())->setter()), true))) {
143#else
144 if (JSValue gs = obj->getDirect(propertyName)) {
145 if (gs.isGetterSetter()) {
146 JSObject* setterFunc = asGetterSetter(gs)->setter();
147#endif
148 if (!setterFunc) {
149 throwSetterError(exec);
150 return;
151 }
152
153 CallData callData;
154 CallType callType = setterFunc->getCallData(callData);
155 MarkedArgumentBuffer args;
156 args.append(v: value);
157 call(exec, functionObject: setterFunc, callType, callData, thisValue: this, args);
158 return;
159 }
160
161 // If there's an existing property on the object or one of its
162 // prototypes it should be replaced, so break here.
163 break;
164 }
165
166 prototype = obj->prototype();
167 if (prototype.isNull())
168 break;
169 }
170
171 putDirectInternal(globalData&: exec->globalData(), propertyName, value, attributes: 0, checkReadOnly: true, slot);
172 return;
173}
174
175void JSObject::put(ExecState* exec, unsigned propertyName, JSValue value)
176{
177 PutPropertySlot slot;
178 put(exec, propertyName: Identifier::from(exec, y: propertyName), value, slot);
179}
180
181void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
182{
183 putDirectInternal(globalData&: exec->globalData(), propertyName, value, attributes, checkReadOnly, slot);
184}
185
186void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
187{
188 putDirectInternal(globalData&: exec->globalData(), propertyName, value, attributes);
189}
190
191void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes)
192{
193 putWithAttributes(exec, propertyName: Identifier::from(exec, y: propertyName), value, attributes);
194}
195
196bool JSObject::hasProperty(ExecState* exec, const Identifier& propertyName) const
197{
198 PropertySlot slot;
199 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
200}
201
202bool JSObject::hasProperty(ExecState* exec, unsigned propertyName) const
203{
204 PropertySlot slot;
205 return const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot);
206}
207
208// ECMA 8.6.2.5
209bool JSObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
210{
211 unsigned attributes;
212 JSCell* specificValue;
213 if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) {
214 if ((attributes & DontDelete))
215 return false;
216 removeDirect(propertyName);
217 return true;
218 }
219
220 // Look in the static hashtable of properties
221 const HashEntry* entry = findPropertyHashEntry(exec, propertyName);
222 if (entry && entry->attributes() & DontDelete)
223 return false; // this builtin property can't be deleted
224
225 // FIXME: Should the code here actually do some deletion?
226 return true;
227}
228
229bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
230{
231 PropertySlot slot;
232 return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
233}
234
235bool JSObject::deleteProperty(ExecState* exec, unsigned propertyName)
236{
237 return deleteProperty(exec, propertyName: Identifier::from(exec, y: propertyName));
238}
239
240static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName)
241{
242 JSValue function = object->get(exec, propertyName);
243 CallData callData;
244 CallType callType = function.getCallData(callData);
245 if (callType == CallTypeNone)
246 return exec->exception();
247
248 // Prevent "toString" and "valueOf" from observing execution if an exception
249 // is pending.
250 if (exec->hadException())
251 return exec->exception();
252
253 JSValue result = call(exec, functionObject: function, callType, callData, thisValue: const_cast<JSObject*>(object), exec->emptyList());
254 ASSERT(!result.isGetterSetter());
255 if (exec->hadException())
256 return exec->exception();
257 if (result.isObject())
258 return JSValue();
259 return result;
260}
261
262bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result)
263{
264 result = defaultValue(exec, PreferNumber);
265 number = result.toNumber(exec);
266 return !result.isString();
267}
268
269// ECMA 8.6.2.6
270JSValue JSObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
271{
272 // Must call toString first for Date objects.
273 if ((hint == PreferString) || (hint != PreferNumber && prototype() == exec->lexicalGlobalObject()->datePrototype())) {
274 JSValue value = callDefaultValueFunction(exec, object: this, propertyName: exec->propertyNames().toString);
275 if (value)
276 return value;
277 value = callDefaultValueFunction(exec, object: this, propertyName: exec->propertyNames().valueOf);
278 if (value)
279 return value;
280 } else {
281 JSValue value = callDefaultValueFunction(exec, object: this, propertyName: exec->propertyNames().valueOf);
282 if (value)
283 return value;
284 value = callDefaultValueFunction(exec, object: this, propertyName: exec->propertyNames().toString);
285 if (value)
286 return value;
287 }
288
289 ASSERT(!exec->hadException());
290
291 return throwError(exec, TypeError, message: "No default value");
292}
293
294const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifier& propertyName) const
295{
296 for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
297 if (const HashTable* propHashTable = info->propHashTable(exec)) {
298 if (const HashEntry* entry = propHashTable->entry(exec, identifier: propertyName))
299 return entry;
300 }
301 }
302 return 0;
303}
304
305void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes)
306{
307 JSValue object = getDirect(propertyName);
308 if (object && object.isGetterSetter()) {
309 ASSERT(m_structure->hasGetterSetterProperties());
310 asGetterSetter(value: object)->setGetter(getterFunction);
311 return;
312 }
313
314 PutPropertySlot slot;
315 GetterSetter* getterSetter = new (exec) GetterSetter(exec);
316 putDirectInternal(globalData&: exec->globalData(), propertyName, value: getterSetter, attributes: attributes | Getter, checkReadOnly: true, slot);
317
318 // putDirect will change our Structure if we add a new property. For
319 // getters and setters, though, we also need to change our Structure
320 // if we override an existing non-getter or non-setter.
321 if (slot.type() != PutPropertySlot::NewProperty) {
322 if (!m_structure->isDictionary()) {
323 RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure);
324 setStructure(structure.release());
325 }
326 }
327
328 m_structure->setHasGetterSetterProperties(true);
329 getterSetter->setGetter(getterFunction);
330}
331
332void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes)
333{
334 JSValue object = getDirect(propertyName);
335 if (object && object.isGetterSetter()) {
336 ASSERT(m_structure->hasGetterSetterProperties());
337 asGetterSetter(value: object)->setSetter(setterFunction);
338 return;
339 }
340
341 PutPropertySlot slot;
342 GetterSetter* getterSetter = new (exec) GetterSetter(exec);
343 putDirectInternal(globalData&: exec->globalData(), propertyName, value: getterSetter, attributes: attributes | Setter, checkReadOnly: true, slot);
344
345 // putDirect will change our Structure if we add a new property. For
346 // getters and setters, though, we also need to change our Structure
347 // if we override an existing non-getter or non-setter.
348 if (slot.type() != PutPropertySlot::NewProperty) {
349 if (!m_structure->isDictionary()) {
350 RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure);
351 setStructure(structure.release());
352 }
353 }
354
355 m_structure->setHasGetterSetterProperties(true);
356 getterSetter->setSetter(setterFunction);
357}
358
359JSValue JSObject::lookupGetter(ExecState*, const Identifier& propertyName)
360{
361 JSObject* object = this;
362 while (true) {
363 if (JSValue value = object->getDirect(propertyName)) {
364 if (!value.isGetterSetter())
365 return jsUndefined();
366 JSObject* functionObject = asGetterSetter(value)->getter();
367 if (!functionObject)
368 return jsUndefined();
369 return functionObject;
370 }
371
372 if (!object->prototype() || !object->prototype().isObject())
373 return jsUndefined();
374 object = asObject(value: object->prototype());
375 }
376}
377
378JSValue JSObject::lookupSetter(ExecState*, const Identifier& propertyName)
379{
380 JSObject* object = this;
381 while (true) {
382 if (JSValue value = object->getDirect(propertyName)) {
383 if (!value.isGetterSetter())
384 return jsUndefined();
385 JSObject* functionObject = asGetterSetter(value)->setter();
386 if (!functionObject)
387 return jsUndefined();
388 return functionObject;
389 }
390
391 if (!object->prototype() || !object->prototype().isObject())
392 return jsUndefined();
393 object = asObject(value: object->prototype());
394 }
395}
396
397bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue proto)
398{
399 if (!value.isObject())
400 return false;
401
402 if (!proto.isObject()) {
403 throwError(exec, TypeError, message: "instanceof called on an object with an invalid prototype property.");
404 return false;
405 }
406
407 JSObject* object = asObject(value);
408 while ((object = object->prototype().getObject())) {
409 if (proto == object)
410 return true;
411 }
412 return false;
413}
414
415bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
416{
417 PropertyDescriptor descriptor;
418 if (!const_cast<JSObject*>(this)->getOwnPropertyDescriptor(exec, propertyName, descriptor))
419 return false;
420 return descriptor.enumerable();
421}
422
423bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyName, JSCell*& specificValue) const
424{
425 unsigned attributes;
426 if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound)
427 return true;
428
429 // This could be a function within the static table? - should probably
430 // also look in the hash? This currently should not be a problem, since
431 // we've currently always call 'get' first, which should have populated
432 // the normal storage.
433 return false;
434}
435
436void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
437{
438 getOwnPropertyNames(exec, propertyNames, mode);
439
440 if (prototype().isNull())
441 return;
442
443 JSObject* prototype = asObject(value: this->prototype());
444 while(1) {
445 if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
446 prototype->getPropertyNames(exec, propertyNames, mode);
447 break;
448 }
449 prototype->getOwnPropertyNames(exec, propertyNames, mode);
450 JSValue nextProto = prototype->prototype();
451 if (nextProto.isNull())
452 break;
453 prototype = asObject(value: nextProto);
454 }
455}
456
457void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
458{
459 m_structure->getPropertyNames(propertyNames, mode);
460 getClassPropertyNames(exec, classInfo: classInfo(), propertyNames, mode);
461}
462
463bool JSObject::toBoolean(ExecState*) const
464{
465 return true;
466}
467
468double JSObject::toNumber(ExecState* exec) const
469{
470 JSValue primitive = toPrimitive(exec, preferredType: PreferNumber);
471 if (exec->hadException()) // should be picked up soon in Nodes.cpp
472 return 0.0;
473 return primitive.toNumber(exec);
474}
475
476UString JSObject::toString(ExecState* exec) const
477{
478 JSValue primitive = toPrimitive(exec, preferredType: PreferString);
479 if (exec->hadException())
480 return "";
481 return primitive.toString(exec);
482}
483
484JSObject* JSObject::toObject(ExecState*) const
485{
486 return const_cast<JSObject*>(this);
487}
488
489JSObject* JSObject::toThisObject(ExecState*) const
490{
491 return const_cast<JSObject*>(this);
492}
493
494JSObject* JSObject::unwrappedObject()
495{
496 return this;
497}
498
499void JSObject::removeDirect(const Identifier& propertyName)
500{
501 size_t offset;
502 if (m_structure->isUncacheableDictionary()) {
503 offset = m_structure->removePropertyWithoutTransition(propertyName);
504 if (offset != WTF::notFound)
505 putDirectOffset(offset, value: jsUndefined());
506 return;
507 }
508
509 RefPtr<Structure> structure = Structure::removePropertyTransition(m_structure, propertyName, offset);
510 setStructure(structure.release());
511 if (offset != WTF::notFound)
512 putDirectOffset(offset, value: jsUndefined());
513}
514
515void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr)
516{
517 putDirectFunction(propertyName: Identifier(exec, function->name(exec)), value: function, attr);
518}
519
520void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr)
521{
522 putDirectFunctionWithoutTransition(propertyName: Identifier(exec, function->name(exec)), value: function, attributes: attr);
523}
524
525NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location)
526{
527 if (JSObject* getterFunction = asGetterSetter(value: *location)->getter())
528 slot.setGetterSlot(getterFunction);
529 else
530 slot.setUndefined();
531}
532
533Structure* JSObject::createInheritorID()
534{
535#ifdef QT_BUILD_SCRIPT_LIB
536 // ### Qt Script needs the hasOwnProperty() calls etc. for QScriptObject
537 m_inheritorID = Structure::create(prototype: this, typeInfo: TypeInfo(ObjectType, ImplementsHasInstance | JSC::OverridesHasInstance | JSC::OverridesGetOwnPropertySlot | JSC::OverridesMarkChildren | JSC::OverridesGetPropertyNames));
538#else
539 m_inheritorID = JSObject::createStructure(this);
540#endif
541 return m_inheritorID.get();
542}
543
544void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize)
545{
546 allocatePropertyStorageInline(oldSize, newSize);
547}
548
549bool JSObject::getOwnPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor& descriptor)
550{
551 unsigned attributes = 0;
552 JSCell* cell = 0;
553 size_t offset = m_structure->get(propertyName, attributes, specificValue&: cell);
554 if (offset == WTF::notFound)
555 return false;
556 descriptor.setDescriptor(value: getDirectOffset(offset), attributes);
557 return true;
558}
559
560bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
561{
562 JSObject* object = this;
563 while (true) {
564 if (object->getOwnPropertyDescriptor(exec, propertyName, descriptor))
565 return true;
566 JSValue prototype = object->prototype();
567 if (!prototype.isObject())
568 return false;
569 object = asObject(value: prototype);
570 }
571}
572
573static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, JSValue oldValue)
574{
575 if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
576 target->putWithAttributes(exec, propertyName, value: descriptor.value() ? descriptor.value() : oldValue, attributes: attributes & ~(Getter | Setter));
577 return true;
578 }
579 attributes &= ~ReadOnly;
580 if (descriptor.getter() && descriptor.getter().isObject())
581 target->defineGetter(exec, propertyName, getterFunction: asObject(value: descriptor.getter()), attributes);
582 if (exec->hadException())
583 return false;
584 if (descriptor.setter() && descriptor.setter().isObject())
585 target->defineSetter(exec, propertyName, setterFunction: asObject(value: descriptor.setter()), attributes);
586 return !exec->hadException();
587}
588
589bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
590{
591 // If we have a new property we can just put it on normally
592 PropertyDescriptor current;
593 if (!getOwnPropertyDescriptor(exec, propertyName, descriptor&: current))
594 return putDescriptor(exec, target: this, propertyName, descriptor, attributes: descriptor.attributes(), oldValue: jsUndefined());
595
596 if (descriptor.isEmpty())
597 return true;
598
599 if (current.equalTo(exec, other: descriptor))
600 return true;
601
602 // Filter out invalid changes
603 if (!current.configurable()) {
604 if (descriptor.configurable()) {
605 if (throwException)
606 throwError(exec, TypeError, message: "Attempting to configurable attribute of unconfigurable property.");
607 return false;
608 }
609 if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
610 if (throwException)
611 throwError(exec, TypeError, message: "Attempting to change enumerable attribute of unconfigurable property.");
612 return false;
613 }
614 }
615
616 // A generic descriptor is simply changing the attributes of an existing property
617 if (descriptor.isGenericDescriptor()) {
618 if (!current.attributesEqual(other: descriptor)) {
619 deleteProperty(exec, propertyName);
620 putDescriptor(exec, target: this, propertyName, descriptor, attributes: current.attributesWithOverride(other: descriptor), oldValue: current.value());
621 }
622 return true;
623 }
624
625 // Changing between a normal property or an accessor property
626 if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
627 if (!current.configurable()) {
628 if (throwException)
629 throwError(exec, TypeError, message: "Attempting to change access mechanism for an unconfigurable property.");
630 return false;
631 }
632 deleteProperty(exec, propertyName);
633 return putDescriptor(exec, target: this, propertyName, descriptor, attributes: current.attributesWithOverride(other: descriptor), oldValue: current.value() ? current.value() : jsUndefined());
634 }
635
636 // Changing the value and attributes of an existing property
637 if (descriptor.isDataDescriptor()) {
638 if (!current.configurable()) {
639 if (!current.writable() && descriptor.writable()) {
640 if (throwException)
641 throwError(exec, TypeError, message: "Attempting to change writable attribute of unconfigurable property.");
642 return false;
643 }
644 if (!current.writable()) {
645 if (descriptor.value() || !JSValue::strictEqual(exec, v1: current.value(), v2: descriptor.value())) {
646 if (throwException)
647 throwError(exec, TypeError, message: "Attempting to change value of a readonly property.");
648 return false;
649 }
650 }
651 } else if (current.attributesEqual(other: descriptor)) {
652 if (!descriptor.value())
653 return true;
654 PutPropertySlot slot;
655 put(exec, propertyName, value: descriptor.value(), slot);
656 if (exec->hadException())
657 return false;
658 return true;
659 }
660 deleteProperty(exec, propertyName);
661 return putDescriptor(exec, target: this, propertyName, descriptor, attributes: current.attributesWithOverride(other: descriptor), oldValue: current.value());
662 }
663
664 // Changing the accessor functions of an existing accessor property
665 ASSERT(descriptor.isAccessorDescriptor());
666 if (!current.configurable()) {
667 if (descriptor.setterPresent() && !(current.setter() && JSValue::strictEqual(exec, v1: current.setter(), v2: descriptor.setter()))) {
668 if (throwException)
669 throwError(exec, TypeError, message: "Attempting to change the setter of an unconfigurable property.");
670 return false;
671 }
672 if (descriptor.getterPresent() && !(current.getter() && JSValue::strictEqual(exec, v1: current.getter(), v2: descriptor.getter()))) {
673 if (throwException)
674 throwError(exec, TypeError, message: "Attempting to change the getter of an unconfigurable property.");
675 return false;
676 }
677 }
678 JSValue accessor = getDirect(propertyName);
679 if (!accessor)
680 return false;
681 GetterSetter* getterSetter = asGetterSetter(value: accessor);
682 if (current.attributesEqual(other: descriptor)) {
683 if (descriptor.setter())
684 getterSetter->setSetter(asObject(value: descriptor.setter()));
685 if (descriptor.getter())
686 getterSetter->setGetter(asObject(value: descriptor.getter()));
687 return true;
688 }
689 deleteProperty(exec, propertyName);
690 unsigned attrs = current.attributesWithOverride(other: descriptor);
691 if (descriptor.setter())
692 attrs |= Setter;
693 if (descriptor.getter())
694 attrs |= Getter;
695 putDirect(propertyName, value: getterSetter, attributes: attrs);
696 return true;
697}
698
699} // namespace JSC
700

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp