source: webkit/trunk/JavaScriptCore/runtime/JSObject.cpp@ 60390

Last change on this file since 60390 was 60390, checked in by [email protected], 15 years ago

2010-05-28 Jedrzej Nowacki <[email protected]>

Reviewed by Geoffrey Garen.

Fix the JSObjectSetPrototype function.

A cycle in a prototype chain can cause an application hang or
even crash.
A check for a prototype chain cycles was added to
the JSObjectSetPrototype.

JSObjectSetPrototype doesn't check for cycle in prototype chain.
https://bugs.webkit.org/show_bug.cgi?id=39360

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