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