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, 2007, 2008, 2009 Apple Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef JSObject_h 24 #define JSObject_h 25 26 #include "ArgList.h" 27 #include "ClassInfo.h" 28 #include "CommonIdentifiers.h" 29 #include "CallFrame.h" 30 #include "JSCell.h" 31 #include "JSNumberCell.h" 32 #include "MarkStack.h" 33 #include "PropertySlot.h" 34 #include "PutPropertySlot.h" 35 #include "ScopeChain.h" 36 #include "Structure.h" 37 #include "JSGlobalData.h" 38 #include <wtf/StdLibExtras.h> 39 40 namespace JSC { 41 42 inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value) 43 { 44 if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr)) 45 return value.asCell(); 46 return 0; 47 } 48 49 class HashEntry; 50 class InternalFunction; 51 class PropertyDescriptor; 52 class PropertyNameArray; 53 class Structure; 54 struct HashTable; 55 56 // ECMA 262-3 8.6.1 57 // Property attributes 58 enum Attribute { 59 None = 0, 60 ReadOnly = 1 << 1, // property can be only read, not written 61 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) 62 DontDelete = 1 << 3, // property can't be deleted 63 Function = 1 << 4, // property is a function - only used by static hashtables 64 Getter = 1 << 5, // property is a getter 65 Setter = 1 << 6 // property is a setter 66 }; 67 68 typedef EncodedJSValue* PropertyStorage; 69 typedef const EncodedJSValue* ConstPropertyStorage; 70 71 class JSObject : public JSCell { 72 friend class BatchedTransitionOptimizer; 73 friend class JIT; 74 friend class JSCell; 75 76 public: 77 explicit JSObject(NonNullPassRefPtr<Structure>); 78 79 virtual void markChildren(MarkStack&); 80 ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack); 81 82 // The inline virtual destructor cannot be the first virtual function declared 83 // in the class as it results in the vtable being generated as a weak symbol 84 virtual ~JSObject(); 85 86 JSValue prototype() const; 87 void setPrototype(JSValue prototype); 88 89 void setStructure(NonNullPassRefPtr<Structure>); 90 Structure* inheritorID(); 91 92 virtual UString className() const; 93 94 JSValue get(ExecState*, const Identifier& propertyName) const; 95 JSValue get(ExecState*, unsigned propertyName) const; 96 97 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 98 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 99 bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); 100 101 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 102 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); 103 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); 104 105 virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&); 106 virtual void put(ExecState*, unsigned propertyName, JSValue value); 107 108 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot); 109 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes); 110 virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes); 111 112 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const; 113 114 bool hasProperty(ExecState*, const Identifier& propertyName) const; 115 bool hasProperty(ExecState*, unsigned propertyName) const; 116 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const; 117 118 virtual bool deleteProperty(ExecState*, const Identifier& propertyName); 119 virtual bool deleteProperty(ExecState*, unsigned propertyName); 120 121 virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const; 122 123 virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty); 124 125 virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); 126 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); 127 128 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; 129 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); 130 virtual bool toBoolean(ExecState*) const; 131 virtual double toNumber(ExecState*) const; 132 virtual UString toString(ExecState*) const; 133 virtual JSObject* toObject(ExecState*) const; 134 135 virtual JSObject* toThisObject(ExecState*) const; 136 virtual JSObject* unwrappedObject(); 137 138 bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const; 139 140 // This get function only looks at the property map. 141 JSValue getDirect(const Identifier& propertyName) const 142 { 143 size_t offset = m_structure->get(propertyName); 144 return offset != WTF::notFound ? getDirectOffset(offset) : JSValue(); 145 } 146 147 JSValue* getDirectLocation(const Identifier& propertyName) 148 { 149 size_t offset = m_structure->get(propertyName); 150 return offset != WTF::notFound ? locationForOffset(offset) : 0; 151 } 152 153 JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes) 154 { 155 JSCell* specificFunction; 156 size_t offset = m_structure->get(propertyName, attributes, specificFunction); 157 return offset != WTF::notFound ? locationForOffset(offset) : 0; 158 } 159 160 size_t offsetForLocation(JSValue* location) const 161 { 162 return location - reinterpret_cast<const JSValue*>(propertyStorage()); 163 } 164 165 void transitionTo(Structure*); 166 167 void removeDirect(const Identifier& propertyName); 168 bool hasCustomProperties() { return !m_structure->isEmpty(); } 169 bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); } 170 171 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); 172 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0); 173 174 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0); 175 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); 176 void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0); 177 178 void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0); 179 void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0); 180 void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0); 181 182 // Fast access to known property offsets. 183 JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); } 184 void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); } 185 186 void fillGetterPropertySlot(PropertySlot&, JSValue* location); 187 188 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0); 189 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0); 190 virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName); 191 virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName); 192 virtual bool defineOwnProperty(ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); 193 194 virtual bool isGlobalObject() const { return false; } 195 virtual bool isVariableObject() const { return false; } 196 virtual bool isActivationObject() const { return false; } 197 virtual bool isWatchdogException() const { return false; } 198 virtual bool isNotAnObjectErrorStub() const { return false; } 199 200 void allocatePropertyStorage(size_t oldSize, size_t newSize); 201 void allocatePropertyStorageInline(size_t oldSize, size_t newSize); 202 bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); } 203 204 static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3; 205 static const unsigned nonInlineBaseStorageCapacity = 16; 206 207 static PassRefPtr<Structure> createStructure(JSValue prototype) 208 { 209 return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); 210 } 211 212 void flattenDictionaryObject() 213 { 214 m_structure->flattenDictionaryStructure(this); 215 } 216 217 protected: 218 static const unsigned StructureFlags = 0; 219 220 void putAnonymousValue(unsigned index, JSValue value) 221 { 222 ASSERT(index < m_structure->anonymousSlotCount()); 223 *locationForOffset(index) = value; 224 } 225 JSValue getAnonymousValue(unsigned index) const 226 { 227 ASSERT(index < m_structure->anonymousSlotCount()); 228 return *locationForOffset(index); 229 } 230 231 private: 232 // Nobody should ever ask any of these questions on something already known to be a JSObject. 233 using JSCell::isAPIValueWrapper; 234 using JSCell::isGetterSetter; 235 using JSCell::toObject; 236 void getObject(); 237 void getString(ExecState* exec); 238 void isObject(); 239 void isString(); 240 #if USE(JSVALUE32) 241 void isNumber(); 242 #endif 243 244 ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } 245 PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } 246 247 const JSValue* locationForOffset(size_t offset) const 248 { 249 return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]); 250 } 251 252 JSValue* locationForOffset(size_t offset) 253 { 254 return reinterpret_cast<JSValue*>(&propertyStorage()[offset]); 255 } 256 257 void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*); 258 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); 259 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0); 260 261 bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); 262 263 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const; 264 Structure* createInheritorID(); 265 266 union { 267 PropertyStorage m_externalStorage; 268 EncodedJSValue m_inlineStorage[inlineStorageCapacity]; 269 }; 270 271 RefPtr<Structure> m_inheritorID; 272 }; 273 274 inline JSObject* asObject(JSCell* cell) 275 { 276 ASSERT(cell->isObject()); 277 return static_cast<JSObject*>(cell); 278 } 279 280 inline JSObject* asObject(JSValue value) 281 { 282 return asObject(value.asCell()); 283 } 284 285 inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure) 286 : JSCell(structure.releaseRef()) // ~JSObject balances this ref() 287 { 288 ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity); 289 ASSERT(m_structure->isEmpty()); 290 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); 291 #if USE(JSVALUE64) || USE(JSVALUE32_64) 292 ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0); 293 #endif 294 } 295 296 inline JSObject::~JSObject() 297 { 298 ASSERT(m_structure); 299 if (!isUsingInlineStorage()) 300 delete [] m_externalStorage; 301 m_structure->deref(); 302 } 303 304 inline JSValue JSObject::prototype() const 305 { 306 return m_structure->storedPrototype(); 307 } 308 309 inline void JSObject::setPrototype(JSValue prototype) 310 { 311 ASSERT(prototype); 312 RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype); 313 setStructure(newStructure.release()); 314 } 315 316 inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure) 317 { 318 m_structure->deref(); 319 m_structure = structure.releaseRef(); // ~JSObject balances this ref() 320 } 321 322 inline Structure* JSObject::inheritorID() 323 { 324 if (m_inheritorID) 325 return m_inheritorID.get(); 326 return createInheritorID(); 327 } 328 329 inline bool Structure::isUsingInlineStorage() const 330 { 331 return (propertyStorageCapacity() == JSObject::inlineStorageCapacity); 332 } 333 334 inline bool JSCell::inherits(const ClassInfo* info) const 335 { 336 for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) { 337 if (ci == info) 338 return true; 339 } 340 return false; 341 } 342 343 // this method is here to be after the inline declaration of JSCell::inherits 344 inline bool JSValue::inherits(const ClassInfo* classInfo) const 345 { 346 return isCell() && asCell()->inherits(classInfo); 347 } 348 349 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 350 { 351 if (JSValue* location = getDirectLocation(propertyName)) { 352 if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter()) 353 fillGetterPropertySlot(slot, location); 354 else 355 slot.setValueSlot(this, location, offsetForLocation(location)); 356 return true; 357 } 358 359 // non-standard Netscape extension 360 if (propertyName == exec->propertyNames().underscoreProto) { 361 slot.setValue(prototype()); 362 return true; 363 } 364 365 return false; 366 } 367 368 // It may seem crazy to inline a function this large, especially a virtual function, 369 // but it makes a big difference to property lookup that derived classes can inline their 370 // base class call to this. 371 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 372 { 373 return inlineGetOwnPropertySlot(exec, propertyName, slot); 374 } 375 376 ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 377 { 378 if (!structure()->typeInfo().overridesGetOwnPropertySlot()) 379 return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); 380 return getOwnPropertySlot(exec, propertyName, slot); 381 } 382 383 // It may seem crazy to inline a function this large but it makes a big difference 384 // since this is function very hot in variable lookup 385 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) 386 { 387 JSObject* object = this; 388 while (true) { 389 if (object->fastGetOwnPropertySlot(exec, propertyName, slot)) 390 return true; 391 JSValue prototype = object->prototype(); 392 if (!prototype.isObject()) 393 return false; 394 object = asObject(prototype); 395 } 396 } 397 398 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) 399 { 400 JSObject* object = this; 401 while (true) { 402 if (object->getOwnPropertySlot(exec, propertyName, slot)) 403 return true; 404 JSValue prototype = object->prototype(); 405 if (!prototype.isObject()) 406 return false; 407 object = asObject(prototype); 408 } 409 } 410 411 inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const 412 { 413 PropertySlot slot(this); 414 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) 415 return slot.getValue(exec, propertyName); 416 417 return jsUndefined(); 418 } 419 420 inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const 421 { 422 PropertySlot slot(this); 423 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) 424 return slot.getValue(exec, propertyName); 425 426 return jsUndefined(); 427 } 428 429 inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction) 430 { 431 ASSERT(value); 432 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); 433 434 if (m_structure->isDictionary()) { 435 unsigned currentAttributes; 436 JSCell* currentSpecificFunction; 437 size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction); 438 if (offset != WTF::notFound) { 439 if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) 440 m_structure->despecifyDictionaryFunction(propertyName); 441 if (checkReadOnly && currentAttributes & ReadOnly) 442 return; 443 putDirectOffset(offset, value); 444 if (!specificFunction && !currentSpecificFunction) 445 slot.setExistingProperty(this, offset); 446 return; 447 } 448 449 size_t currentCapacity = m_structure->propertyStorageCapacity(); 450 offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction); 451 if (currentCapacity != m_structure->propertyStorageCapacity()) 452 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); 453 454 ASSERT(offset < m_structure->propertyStorageCapacity()); 455 putDirectOffset(offset, value); 456 // See comment on setNewProperty call below. 457 if (!specificFunction) 458 slot.setNewProperty(this, offset); 459 return; 460 } 461 462 size_t offset; 463 size_t currentCapacity = m_structure->propertyStorageCapacity(); 464 if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) { 465 if (currentCapacity != structure->propertyStorageCapacity()) 466 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); 467 468 ASSERT(offset < structure->propertyStorageCapacity()); 469 setStructure(structure.release()); 470 putDirectOffset(offset, value); 471 // See comment on setNewProperty call below. 472 if (!specificFunction) 473 slot.setNewProperty(this, offset); 474 return; 475 } 476 477 unsigned currentAttributes; 478 JSCell* currentSpecificFunction; 479 offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction); 480 if (offset != WTF::notFound) { 481 if (checkReadOnly && currentAttributes & ReadOnly) 482 return; 483 484 if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) { 485 setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName)); 486 putDirectOffset(offset, value); 487 // Function transitions are not currently cachable, so leave the slot in an uncachable state. 488 return; 489 } 490 putDirectOffset(offset, value); 491 slot.setExistingProperty(this, offset); 492 return; 493 } 494 495 // If we have a specific function, we may have got to this point if there is 496 // already a transition with the correct property name and attributes, but 497 // specialized to a different function. In this case we just want to give up 498 // and despecialize the transition. 499 // In this case we clear the value of specificFunction which will result 500 // in us adding a non-specific transition, and any subsequent lookup in 501 // Structure::addPropertyTransitionToExistingStructure will just use that. 502 if (specificFunction && m_structure->hasTransition(propertyName, attributes)) 503 specificFunction = 0; 504 505 RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset); 506 507 if (currentCapacity != structure->propertyStorageCapacity()) 508 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); 509 510 ASSERT(offset < structure->propertyStorageCapacity()); 511 setStructure(structure.release()); 512 putDirectOffset(offset, value); 513 // Function transitions are not currently cachable, so leave the slot in an uncachable state. 514 if (!specificFunction) 515 slot.setNewProperty(this, offset); 516 } 517 518 inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) 519 { 520 ASSERT(value); 521 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); 522 523 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value)); 524 } 525 526 inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) 527 { 528 PutPropertySlot slot; 529 putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value)); 530 } 531 532 inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) 533 { 534 ASSERT(value); 535 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); 536 537 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0); 538 } 539 540 inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes) 541 { 542 PutPropertySlot slot; 543 putDirectInternal(propertyName, value, attributes, false, slot, 0); 544 } 545 546 inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) 547 { 548 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value); 549 } 550 551 inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr) 552 { 553 PutPropertySlot slot; 554 putDirectInternal(propertyName, value, attr, false, slot, value); 555 } 556 557 inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes) 558 { 559 size_t currentCapacity = m_structure->propertyStorageCapacity(); 560 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0); 561 if (currentCapacity != m_structure->propertyStorageCapacity()) 562 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); 563 putDirectOffset(offset, value); 564 } 565 566 inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes) 567 { 568 size_t currentCapacity = m_structure->propertyStorageCapacity(); 569 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value); 570 if (currentCapacity != m_structure->propertyStorageCapacity()) 571 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity()); 572 putDirectOffset(offset, value); 573 } 574 575 inline void JSObject::transitionTo(Structure* newStructure) 576 { 577 if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) 578 allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity()); 579 setStructure(newStructure); 580 } 581 582 inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const 583 { 584 return defaultValue(exec, preferredType); 585 } 586 587 inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const 588 { 589 PropertySlot slot(asValue()); 590 return get(exec, propertyName, slot); 591 } 592 593 inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const 594 { 595 if (UNLIKELY(!isCell())) { 596 JSObject* prototype = synthesizePrototype(exec); 597 if (propertyName == exec->propertyNames().underscoreProto) 598 return prototype; 599 if (!prototype->getPropertySlot(exec, propertyName, slot)) 600 return jsUndefined(); 601 return slot.getValue(exec, propertyName); 602 } 603 JSCell* cell = asCell(); 604 while (true) { 605 if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) 606 return slot.getValue(exec, propertyName); 607 JSValue prototype = asObject(cell)->prototype(); 608 if (!prototype.isObject()) 609 return jsUndefined(); 610 cell = asObject(prototype); 611 } 612 } 613 614 inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const 615 { 616 PropertySlot slot(asValue()); 617 return get(exec, propertyName, slot); 618 } 619 620 inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const 621 { 622 if (UNLIKELY(!isCell())) { 623 JSObject* prototype = synthesizePrototype(exec); 624 if (!prototype->getPropertySlot(exec, propertyName, slot)) 625 return jsUndefined(); 626 return slot.getValue(exec, propertyName); 627 } 628 JSCell* cell = const_cast<JSCell*>(asCell()); 629 while (true) { 630 if (cell->getOwnPropertySlot(exec, propertyName, slot)) 631 return slot.getValue(exec, propertyName); 632 JSValue prototype = asObject(cell)->prototype(); 633 if (!prototype.isObject()) 634 return jsUndefined(); 635 cell = prototype.asCell(); 636 } 637 } 638 639 inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) 640 { 641 if (UNLIKELY(!isCell())) { 642 synthesizeObject(exec)->put(exec, propertyName, value, slot); 643 return; 644 } 645 asCell()->put(exec, propertyName, value, slot); 646 } 647 648 inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value) 649 { 650 if (UNLIKELY(!isCell())) { 651 synthesizeObject(exec)->put(exec, propertyName, value); 652 return; 653 } 654 asCell()->put(exec, propertyName, value); 655 } 656 657 ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize) 658 { 659 ASSERT(newSize > oldSize); 660 661 // It's important that this function not rely on m_structure, since 662 // we might be in the middle of a transition. 663 bool wasInline = (oldSize == JSObject::inlineStorageCapacity); 664 665 PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage); 666 PropertyStorage newPropertyStorage = new EncodedJSValue[newSize]; 667 668 for (unsigned i = 0; i < oldSize; ++i) 669 newPropertyStorage[i] = oldPropertyStorage[i]; 670 671 if (!wasInline) 672 delete [] oldPropertyStorage; 673 674 m_externalStorage = newPropertyStorage; 675 } 676 677 ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack) 678 { 679 JSCell::markChildren(markStack); 680 681 markStack.append(prototype()); 682 683 PropertyStorage storage = propertyStorage(); 684 size_t storageSize = m_structure->propertyStorageSize(); 685 markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize); 686 } 687 688 } // namespace JSC 689 690 #endif // JSObject_h 691