| 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, 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, specificValue&: 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(ptr: 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 | #ifdef QT_BUILD_SCRIPT_LIB | 
| 200 |         virtual bool compareToObject(ExecState*, JSObject *other) { return other == this; } | 
| 201 | #endif | 
| 202 |  | 
| 203 |         void allocatePropertyStorage(size_t oldSize, size_t newSize); | 
| 204 |         void allocatePropertyStorageInline(size_t oldSize, size_t newSize); | 
| 205 |         bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); } | 
| 206 |  | 
| 207 |         static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3; | 
| 208 |         static const unsigned nonInlineBaseStorageCapacity = 16; | 
| 209 |  | 
| 210 |         static PassRefPtr<Structure> createStructure(JSValue prototype) | 
| 211 |         { | 
| 212 |             return Structure::create(prototype, typeInfo: TypeInfo(ObjectType, StructureFlags)); | 
| 213 |         } | 
| 214 |  | 
| 215 |         void flattenDictionaryObject() | 
| 216 |         { | 
| 217 |             m_structure->flattenDictionaryStructure(this); | 
| 218 |         } | 
| 219 |  | 
| 220 |     protected: | 
| 221 |         static const unsigned StructureFlags = 0; | 
| 222 |  | 
| 223 |         void addAnonymousSlots(unsigned count); | 
| 224 |         void putAnonymousValue(unsigned index, JSValue value) | 
| 225 |         { | 
| 226 |             *locationForOffset(offset: index) = value; | 
| 227 |         } | 
| 228 |         JSValue getAnonymousValue(unsigned index) | 
| 229 |         { | 
| 230 |             return *locationForOffset(offset: index); | 
| 231 |         } | 
| 232 |  | 
| 233 |     private: | 
| 234 |         // Nobody should ever ask any of these questions on something already known to be a JSObject. | 
| 235 |         using JSCell::isAPIValueWrapper; | 
| 236 |         using JSCell::isGetterSetter; | 
| 237 |         using JSCell::toObject; | 
| 238 |         void getObject(); | 
| 239 |         void getString(ExecState* exec); | 
| 240 |         void isObject(); | 
| 241 |         void isString(); | 
| 242 | #if USE(JSVALUE32) | 
| 243 |         void isNumber(); | 
| 244 | #endif | 
| 245 |  | 
| 246 |         ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } | 
| 247 |         PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } | 
| 248 |  | 
| 249 |         const JSValue* locationForOffset(size_t offset) const | 
| 250 |         { | 
| 251 |             return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]); | 
| 252 |         } | 
| 253 |  | 
| 254 |         JSValue* locationForOffset(size_t offset) | 
| 255 |         { | 
| 256 |             return reinterpret_cast<JSValue*>(&propertyStorage()[offset]); | 
| 257 |         } | 
| 258 |  | 
| 259 |         void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*); | 
| 260 |         void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot); | 
| 261 |         void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0); | 
| 262 |  | 
| 263 |         bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); | 
| 264 |  | 
| 265 |         const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const; | 
| 266 |         Structure* createInheritorID(); | 
| 267 |  | 
| 268 |         union { | 
| 269 |             PropertyStorage m_externalStorage; | 
| 270 |             EncodedJSValue m_inlineStorage[inlineStorageCapacity]; | 
| 271 |         }; | 
| 272 |  | 
| 273 |         RefPtr<Structure> m_inheritorID; | 
| 274 |     }; | 
| 275 |      | 
| 276 | inline JSObject* asObject(JSCell* cell) | 
| 277 | { | 
| 278 |     ASSERT(cell->isObject()); | 
| 279 |     return static_cast<JSObject*>(cell); | 
| 280 | } | 
| 281 |  | 
| 282 | inline JSObject* asObject(JSValue value) | 
| 283 | { | 
| 284 |     return asObject(cell: value.asCell()); | 
| 285 | } | 
| 286 |  | 
| 287 | inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure) | 
| 288 |     : JSCell(structure.releaseRef()) // ~JSObject balances this ref() | 
| 289 | { | 
| 290 |     ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity); | 
| 291 |     ASSERT(m_structure->isEmpty()); | 
| 292 |     ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); | 
| 293 | #if USE(JSVALUE64) || USE(JSVALUE32_64) | 
| 294 |     ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0); | 
| 295 | #endif | 
| 296 | } | 
| 297 |  | 
| 298 | inline JSObject::~JSObject() | 
| 299 | { | 
| 300 |     ASSERT(m_structure); | 
| 301 |     if (!isUsingInlineStorage()) | 
| 302 |         delete [] m_externalStorage; | 
| 303 |     m_structure->deref(); | 
| 304 | } | 
| 305 |  | 
| 306 | inline JSValue JSObject::prototype() const | 
| 307 | { | 
| 308 |     return m_structure->storedPrototype(); | 
| 309 | } | 
| 310 |  | 
| 311 | inline void JSObject::setPrototype(JSValue prototype) | 
| 312 | { | 
| 313 |     ASSERT(prototype); | 
| 314 |     RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype); | 
| 315 |     setStructure(newStructure.release()); | 
| 316 | } | 
| 317 |  | 
| 318 | inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure) | 
| 319 | { | 
| 320 |     m_structure->deref(); | 
| 321 |     m_structure = structure.releaseRef(); // ~JSObject balances this ref() | 
| 322 | } | 
| 323 |  | 
| 324 | inline Structure* JSObject::inheritorID() | 
| 325 | { | 
| 326 |     if (m_inheritorID) | 
| 327 |         return m_inheritorID.get(); | 
| 328 |     return createInheritorID(); | 
| 329 | } | 
| 330 |  | 
| 331 | inline bool Structure::isUsingInlineStorage() const | 
| 332 | { | 
| 333 |     return (propertyStorageCapacity() == JSObject::inlineStorageCapacity); | 
| 334 | } | 
| 335 |  | 
| 336 | inline bool JSCell::inherits(const ClassInfo* info) const | 
| 337 | { | 
| 338 |     for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) { | 
| 339 |         if (ci == info) | 
| 340 |             return true; | 
| 341 |     } | 
| 342 |     return false; | 
| 343 | } | 
| 344 |  | 
| 345 | // this method is here to be after the inline declaration of JSCell::inherits | 
| 346 | inline bool JSValue::inherits(const ClassInfo* classInfo) const | 
| 347 | { | 
| 348 |     return isCell() && asCell()->inherits(info: classInfo); | 
| 349 | } | 
| 350 |  | 
| 351 | ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | 
| 352 | { | 
| 353 |     if (JSValue* location = getDirectLocation(propertyName)) { | 
| 354 |         if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter()) | 
| 355 |             fillGetterPropertySlot(slot, location); | 
| 356 |         else | 
| 357 |             slot.setValueSlot(slotBase: this, valueSlot: location, offset: offsetForLocation(location)); | 
| 358 |         return true; | 
| 359 |     } | 
| 360 |  | 
| 361 |     // non-standard Netscape extension | 
| 362 |     if (propertyName == exec->propertyNames().underscoreProto) { | 
| 363 |         slot.setValue(prototype()); | 
| 364 |         return true; | 
| 365 |     } | 
| 366 |  | 
| 367 |     return false; | 
| 368 | } | 
| 369 |  | 
| 370 | // It may seem crazy to inline a function this large, especially a virtual function, | 
| 371 | // but it makes a big difference to property lookup that derived classes can inline their | 
| 372 | // base class call to this. | 
| 373 | ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | 
| 374 | { | 
| 375 |     return inlineGetOwnPropertySlot(exec, propertyName, slot); | 
| 376 | } | 
| 377 |  | 
| 378 | ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | 
| 379 | { | 
| 380 |     if (!structure()->typeInfo().overridesGetOwnPropertySlot()) | 
| 381 |         return asObject(cell: this)->inlineGetOwnPropertySlot(exec, propertyName, slot); | 
| 382 |     return getOwnPropertySlot(exec, propertyName, slot); | 
| 383 | } | 
| 384 |  | 
| 385 | // It may seem crazy to inline a function this large but it makes a big difference | 
| 386 | // since this is function very hot in variable lookup | 
| 387 | ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | 
| 388 | { | 
| 389 |     JSObject* object = this; | 
| 390 |     while (true) { | 
| 391 |         if (object->fastGetOwnPropertySlot(exec, propertyName, slot)) | 
| 392 |             return true; | 
| 393 |         JSValue prototype = object->prototype(); | 
| 394 |         if (!prototype.isObject()) | 
| 395 |             return false; | 
| 396 |         object = asObject(value: prototype); | 
| 397 |     } | 
| 398 | } | 
| 399 |  | 
| 400 | ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) | 
| 401 | { | 
| 402 |     JSObject* object = this; | 
| 403 |     while (true) { | 
| 404 |         if (object->getOwnPropertySlot(exec, propertyName, slot)) | 
| 405 |             return true; | 
| 406 |         JSValue prototype = object->prototype(); | 
| 407 |         if (!prototype.isObject()) | 
| 408 |             return false; | 
| 409 |         object = asObject(value: prototype); | 
| 410 |     } | 
| 411 | } | 
| 412 |  | 
| 413 | inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const | 
| 414 | { | 
| 415 |     PropertySlot slot(this); | 
| 416 |     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) | 
| 417 |         return slot.getValue(exec, propertyName); | 
| 418 |      | 
| 419 |     return jsUndefined(); | 
| 420 | } | 
| 421 |  | 
| 422 | inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const | 
| 423 | { | 
| 424 |     PropertySlot slot(this); | 
| 425 |     if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) | 
| 426 |         return slot.getValue(exec, propertyName); | 
| 427 |  | 
| 428 |     return jsUndefined(); | 
| 429 | } | 
| 430 |  | 
| 431 | inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction) | 
| 432 | { | 
| 433 |     ASSERT(value); | 
| 434 |     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); | 
| 435 |  | 
| 436 |     if (m_structure->isDictionary()) { | 
| 437 |         unsigned currentAttributes; | 
| 438 |         JSCell* currentSpecificFunction; | 
| 439 |         size_t offset = m_structure->get(propertyName, attributes&: currentAttributes, specificValue&: currentSpecificFunction); | 
| 440 |         if (offset != WTF::notFound) { | 
| 441 |             if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) | 
| 442 |                 m_structure->despecifyDictionaryFunction(propertyName); | 
| 443 |             if (checkReadOnly && currentAttributes & ReadOnly) | 
| 444 |                 return; | 
| 445 |             putDirectOffset(offset, value); | 
| 446 |             if (!specificFunction && !currentSpecificFunction) | 
| 447 |                 slot.setExistingProperty(base: this, offset); | 
| 448 |             return; | 
| 449 |         } | 
| 450 |  | 
| 451 |         size_t currentCapacity = m_structure->propertyStorageCapacity(); | 
| 452 |         offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificValue: specificFunction); | 
| 453 |         if (currentCapacity != m_structure->propertyStorageCapacity()) | 
| 454 |             allocatePropertyStorage(oldSize: currentCapacity, newSize: m_structure->propertyStorageCapacity()); | 
| 455 |  | 
| 456 |         ASSERT(offset < m_structure->propertyStorageCapacity()); | 
| 457 |         putDirectOffset(offset, value); | 
| 458 |         // See comment on setNewProperty call below. | 
| 459 |         if (!specificFunction) | 
| 460 |             slot.setNewProperty(base: this, offset); | 
| 461 |         return; | 
| 462 |     } | 
| 463 |  | 
| 464 |     size_t offset; | 
| 465 |     size_t currentCapacity = m_structure->propertyStorageCapacity(); | 
| 466 |     if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificValue: specificFunction, offset)) {     | 
| 467 |         if (currentCapacity != structure->propertyStorageCapacity()) | 
| 468 |             allocatePropertyStorage(oldSize: currentCapacity, newSize: structure->propertyStorageCapacity()); | 
| 469 |  | 
| 470 |         ASSERT(offset < structure->propertyStorageCapacity()); | 
| 471 |         setStructure(structure.release()); | 
| 472 |         putDirectOffset(offset, value); | 
| 473 |         // See comment on setNewProperty call below. | 
| 474 |         if (!specificFunction) | 
| 475 |             slot.setNewProperty(base: this, offset); | 
| 476 |         return; | 
| 477 |     } | 
| 478 |  | 
| 479 |     unsigned currentAttributes; | 
| 480 |     JSCell* currentSpecificFunction; | 
| 481 |     offset = m_structure->get(propertyName, attributes&: currentAttributes, specificValue&: currentSpecificFunction); | 
| 482 |     if (offset != WTF::notFound) { | 
| 483 |         if (checkReadOnly && currentAttributes & ReadOnly) | 
| 484 |             return; | 
| 485 |  | 
| 486 |         if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) { | 
| 487 |             setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName)); | 
| 488 |             putDirectOffset(offset, value); | 
| 489 |             // Function transitions are not currently cachable, so leave the slot in an uncachable state. | 
| 490 |             return; | 
| 491 |         } | 
| 492 |         putDirectOffset(offset, value); | 
| 493 |         slot.setExistingProperty(base: this, offset); | 
| 494 |         return; | 
| 495 |     } | 
| 496 |  | 
| 497 |     // If we have a specific function, we may have got to this point if there is | 
| 498 |     // already a transition with the correct property name and attributes, but | 
| 499 |     // specialized to a different function.  In this case we just want to give up | 
| 500 |     // and despecialize the transition. | 
| 501 |     // In this case we clear the value of specificFunction which will result | 
| 502 |     // in us adding a non-specific transition, and any subsequent lookup in | 
| 503 |     // Structure::addPropertyTransitionToExistingStructure will just use that. | 
| 504 |     if (specificFunction && m_structure->hasTransition(propertyName, attributes)) | 
| 505 |         specificFunction = 0; | 
| 506 |  | 
| 507 |     RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificValue: specificFunction, offset); | 
| 508 |  | 
| 509 |     if (currentCapacity != structure->propertyStorageCapacity()) | 
| 510 |         allocatePropertyStorage(oldSize: currentCapacity, newSize: structure->propertyStorageCapacity()); | 
| 511 |  | 
| 512 |     ASSERT(offset < structure->propertyStorageCapacity()); | 
| 513 |     setStructure(structure.release()); | 
| 514 |     putDirectOffset(offset, value); | 
| 515 |     // Function transitions are not currently cachable, so leave the slot in an uncachable state. | 
| 516 |     if (!specificFunction) | 
| 517 |         slot.setNewProperty(base: this, offset); | 
| 518 | } | 
| 519 |  | 
| 520 | inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) | 
| 521 | { | 
| 522 |     ASSERT(value); | 
| 523 |     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); | 
| 524 |  | 
| 525 |     putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, specificFunction: getJSFunction(globalData, value)); | 
| 526 | } | 
| 527 |  | 
| 528 | inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes) | 
| 529 | { | 
| 530 |     PutPropertySlot slot; | 
| 531 |     putDirectInternal(propertyName, value, attributes, checkReadOnly: false, slot, specificFunction: getJSFunction(globalData, value)); | 
| 532 | } | 
| 533 |  | 
| 534 | inline void JSObject::addAnonymousSlots(unsigned count) | 
| 535 | { | 
| 536 |     size_t currentCapacity = m_structure->propertyStorageCapacity(); | 
| 537 |     RefPtr<Structure> structure = Structure::addAnonymousSlotsTransition(m_structure, count); | 
| 538 |  | 
| 539 |     if (currentCapacity != structure->propertyStorageCapacity()) | 
| 540 |         allocatePropertyStorage(oldSize: currentCapacity, newSize: structure->propertyStorageCapacity()); | 
| 541 |  | 
| 542 |     setStructure(structure.release()); | 
| 543 | } | 
| 544 |  | 
| 545 | inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) | 
| 546 | { | 
| 547 |     ASSERT(value); | 
| 548 |     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); | 
| 549 |  | 
| 550 |     putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, specificFunction: 0); | 
| 551 | } | 
| 552 |  | 
| 553 | inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes) | 
| 554 | { | 
| 555 |     PutPropertySlot slot; | 
| 556 |     putDirectInternal(propertyName, value, attributes, checkReadOnly: false, slot, specificFunction: 0); | 
| 557 | } | 
| 558 |  | 
| 559 | inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) | 
| 560 | { | 
| 561 |     putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, specificFunction: value); | 
| 562 | } | 
| 563 |  | 
| 564 | inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr) | 
| 565 | { | 
| 566 |     PutPropertySlot slot; | 
| 567 |     putDirectInternal(propertyName, value, attributes: attr, checkReadOnly: false, slot, specificFunction: value); | 
| 568 | } | 
| 569 |  | 
| 570 | inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes) | 
| 571 | { | 
| 572 |     size_t currentCapacity = m_structure->propertyStorageCapacity(); | 
| 573 |     size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificValue: 0); | 
| 574 |     if (currentCapacity != m_structure->propertyStorageCapacity()) | 
| 575 |         allocatePropertyStorage(oldSize: currentCapacity, newSize: m_structure->propertyStorageCapacity()); | 
| 576 |     putDirectOffset(offset, value); | 
| 577 | } | 
| 578 |  | 
| 579 | inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes) | 
| 580 | { | 
| 581 |     size_t currentCapacity = m_structure->propertyStorageCapacity(); | 
| 582 |     size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificValue: value); | 
| 583 |     if (currentCapacity != m_structure->propertyStorageCapacity()) | 
| 584 |         allocatePropertyStorage(oldSize: currentCapacity, newSize: m_structure->propertyStorageCapacity()); | 
| 585 |     putDirectOffset(offset, value); | 
| 586 | } | 
| 587 |  | 
| 588 | inline void JSObject::transitionTo(Structure* newStructure) | 
| 589 | { | 
| 590 |     if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity()) | 
| 591 |         allocatePropertyStorage(oldSize: m_structure->propertyStorageCapacity(), newSize: newStructure->propertyStorageCapacity()); | 
| 592 |     setStructure(newStructure); | 
| 593 | } | 
| 594 |  | 
| 595 | inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const | 
| 596 | { | 
| 597 |     return defaultValue(exec, preferredType); | 
| 598 | } | 
| 599 |  | 
| 600 | inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const | 
| 601 | { | 
| 602 |     PropertySlot slot(asValue()); | 
| 603 |     return get(exec, propertyName, slot); | 
| 604 | } | 
| 605 |  | 
| 606 | inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const | 
| 607 | { | 
| 608 |     if (UNLIKELY(!isCell())) { | 
| 609 |         JSObject* prototype = synthesizePrototype(exec); | 
| 610 |         if (propertyName == exec->propertyNames().underscoreProto) | 
| 611 |             return prototype; | 
| 612 |         if (!prototype->getPropertySlot(exec, propertyName, slot)) | 
| 613 |             return jsUndefined(); | 
| 614 |         return slot.getValue(exec, propertyName); | 
| 615 |     } | 
| 616 |     JSCell* cell = asCell(); | 
| 617 |     while (true) { | 
| 618 |         if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) | 
| 619 |             return slot.getValue(exec, propertyName); | 
| 620 |         JSValue prototype = asObject(cell)->prototype(); | 
| 621 |         if (!prototype.isObject()) | 
| 622 |             return jsUndefined(); | 
| 623 |         cell = asObject(value: prototype); | 
| 624 |     } | 
| 625 | } | 
| 626 |  | 
| 627 | inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const | 
| 628 | { | 
| 629 |     PropertySlot slot(asValue()); | 
| 630 |     return get(exec, propertyName, slot); | 
| 631 | } | 
| 632 |  | 
| 633 | inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const | 
| 634 | { | 
| 635 |     if (UNLIKELY(!isCell())) { | 
| 636 |         JSObject* prototype = synthesizePrototype(exec); | 
| 637 |         if (!prototype->getPropertySlot(exec, propertyName, slot)) | 
| 638 |             return jsUndefined(); | 
| 639 |         return slot.getValue(exec, propertyName); | 
| 640 |     } | 
| 641 |     JSCell* cell = const_cast<JSCell*>(asCell()); | 
| 642 |     while (true) { | 
| 643 |         if (cell->getOwnPropertySlot(exec, propertyName, slot)) | 
| 644 |             return slot.getValue(exec, propertyName); | 
| 645 |         JSValue prototype = asObject(cell)->prototype(); | 
| 646 |         if (!prototype.isObject()) | 
| 647 |             return jsUndefined(); | 
| 648 |         cell = prototype.asCell(); | 
| 649 |     } | 
| 650 | } | 
| 651 |  | 
| 652 | inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) | 
| 653 | { | 
| 654 |     if (UNLIKELY(!isCell())) { | 
| 655 |         synthesizeObject(exec)->put(exec, propertyName, value, slot); | 
| 656 |         return; | 
| 657 |     } | 
| 658 |     asCell()->put(exec, propertyName, value, slot); | 
| 659 | } | 
| 660 |  | 
| 661 | inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value) | 
| 662 | { | 
| 663 |     if (UNLIKELY(!isCell())) { | 
| 664 |         synthesizeObject(exec)->put(exec, propertyName, value); | 
| 665 |         return; | 
| 666 |     } | 
| 667 |     asCell()->put(exec, propertyName, value); | 
| 668 | } | 
| 669 |  | 
| 670 | ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize) | 
| 671 | { | 
| 672 |     ASSERT(newSize > oldSize); | 
| 673 |  | 
| 674 |     // It's important that this function not rely on m_structure, since | 
| 675 |     // we might be in the middle of a transition. | 
| 676 |     bool wasInline = (oldSize == JSObject::inlineStorageCapacity); | 
| 677 |  | 
| 678 |     PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage); | 
| 679 |     PropertyStorage newPropertyStorage = new EncodedJSValue[newSize]; | 
| 680 |  | 
| 681 |     for (unsigned i = 0; i < oldSize; ++i) | 
| 682 |        newPropertyStorage[i] = oldPropertyStorage[i]; | 
| 683 |  | 
| 684 |     if (!wasInline) | 
| 685 |         delete [] oldPropertyStorage; | 
| 686 |  | 
| 687 |     m_externalStorage = newPropertyStorage; | 
| 688 | } | 
| 689 |  | 
| 690 | ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack) | 
| 691 | { | 
| 692 |     JSCell::markChildren(markStack); | 
| 693 |  | 
| 694 |     markStack.append(value: prototype()); | 
| 695 |      | 
| 696 |     PropertyStorage storage = propertyStorage(); | 
| 697 |     size_t storageSize = m_structure->propertyStorageSize(); | 
| 698 |     markStack.appendValues(values: reinterpret_cast<JSValue*>(storage), count: storageSize); | 
| 699 | } | 
| 700 |  | 
| 701 | } // namespace JSC | 
| 702 |  | 
| 703 | #endif // JSObject_h | 
| 704 |  |