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.
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.
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.
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.
27 #include "ClassInfo.h"
28 #include "CommonIdentifiers.h"
29 #include "CallFrame.h"
31 #include "PropertySlot.h"
32 #include "PutPropertySlot.h"
33 #include "ScopeChain.h"
34 #include "StorageBarrier.h"
35 #include "Structure.h"
36 #include "JSGlobalData.h"
38 #include <wtf/StdLibExtras.h>
42 inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
44 if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
45 return value.asCell();
50 class InternalFunction;
52 class PropertyDescriptor;
53 class PropertyNameArray;
57 JSObject* throwTypeError(ExecState*, const UString&);
58 extern const char* StrictModeReadonlyPropertyWriteError;
61 // Property attributes
64 ReadOnly = 1 << 1, // property can be only read, not written
65 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
66 DontDelete = 1 << 3, // property can't be deleted
67 Function = 1 << 4, // property is a function - only used by static hashtables
68 Getter = 1 << 5, // property is a getter
69 Setter = 1 << 6 // property is a setter
72 class JSObject : public JSCell {
73 friend class BatchedTransitionOptimizer;
76 friend class MarkedBlock;
77 friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
82 virtual void visitChildren(SlotVisitor&);
83 ALWAYS_INLINE void visitChildrenDirect(SlotVisitor&);
85 // The inline virtual destructor cannot be the first virtual function declared
86 // in the class as it results in the vtable being generated as a weak symbol
89 JSValue prototype() const;
90 void setPrototype(JSGlobalData&, JSValue prototype);
91 bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
93 void setStructure(JSGlobalData&, Structure*);
94 Structure* inheritorID(JSGlobalData&);
96 virtual UString className() const;
98 JSValue get(ExecState*, const Identifier& propertyName) const;
99 JSValue get(ExecState*, unsigned propertyName) const;
101 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
102 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
103 bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
105 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
106 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
107 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
109 virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
110 virtual void put(ExecState*, unsigned propertyName, JSValue value);
112 virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
113 virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes);
114 virtual void putWithAttributes(JSGlobalData*, unsigned propertyName, JSValue value, unsigned attributes);
115 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
116 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
117 virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
119 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
121 bool hasProperty(ExecState*, const Identifier& propertyName) const;
122 bool hasProperty(ExecState*, unsigned propertyName) const;
123 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
125 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
126 virtual bool deleteProperty(ExecState*, unsigned propertyName);
128 virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
130 virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
132 virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
133 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
135 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
136 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
137 bool toBoolean(ExecState*) const;
138 virtual double toNumber(ExecState*) const;
139 virtual UString toString(ExecState*) const;
140 virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
142 virtual JSObject* toThisObject(ExecState*) const;
143 virtual JSValue toStrictThisObject(ExecState*) const;
144 virtual JSObject* unwrappedObject();
146 bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
148 // This get function only looks at the property map.
149 JSValue getDirect(JSGlobalData& globalData, const Identifier& propertyName) const
151 size_t offset = m_structure->get(globalData, propertyName);
152 return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
155 WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName)
157 size_t offset = m_structure->get(globalData, propertyName);
158 return offset != WTF::notFound ? locationForOffset(offset) : 0;
161 WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes)
163 JSCell* specificFunction;
164 size_t offset = m_structure->get(globalData, propertyName, attributes, specificFunction);
165 return offset != WTF::notFound ? locationForOffset(offset) : 0;
168 size_t offsetForLocation(WriteBarrierBase<Unknown>* location) const
170 return location - propertyStorage();
173 void transitionTo(JSGlobalData&, Structure*);
175 void removeDirect(JSGlobalData&, const Identifier& propertyName);
176 bool hasCustomProperties() { return m_structure->didTransition(); }
177 bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
179 bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&);
180 void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
181 bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
183 void putDirectFunction(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr = 0);
184 void putDirectFunction(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr, bool checkReadOnly, PutPropertySlot&);
185 void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
186 void putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr = 0);
188 void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
189 void putDirectFunctionWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSCell* value, unsigned attr = 0);
190 void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
191 void putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr = 0);
193 // Fast access to known property offsets.
194 JSValue getDirectOffset(size_t offset) const { return propertyStorage()[offset].get(); }
195 void putDirectOffset(JSGlobalData& globalData, size_t offset, JSValue value) { propertyStorage()[offset].set(globalData, this, value); }
196 void putUndefinedAtDirectOffset(size_t offset) { propertyStorage()[offset].setUndefined(); }
198 void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
200 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0);
201 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
202 virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
203 virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
204 virtual bool defineOwnProperty(ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
206 virtual bool isGlobalObject() const { return false; }
207 virtual bool isVariableObject() const { return false; }
208 virtual bool isActivationObject() const { return false; }
209 virtual bool isStrictModeFunction() const { return false; }
210 virtual bool isErrorInstance() const { return false; }
212 void seal(JSGlobalData&);
213 void freeze(JSGlobalData&);
214 virtual void preventExtensions(JSGlobalData&);
215 bool isSealed(JSGlobalData& globalData) { return m_structure->isSealed(globalData); }
216 bool isFrozen(JSGlobalData& globalData) { return m_structure->isFrozen(globalData); }
217 bool isExtensible() { return m_structure->isExtensible(); }
219 void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
220 bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); }
222 void* addressOfPropertyAtOffset(size_t offset)
224 return static_cast<void*>(&m_propertyStorage[offset]);
227 static const unsigned baseExternalStorageCapacity = 16;
229 void flattenDictionaryObject(JSGlobalData& globalData)
231 m_structure->flattenDictionaryStructure(globalData, this);
234 JSGlobalObject* globalObject() const
236 ASSERT(structure()->globalObject());
237 ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
238 return structure()->globalObject();
241 static size_t offsetOfInlineStorage();
242 static size_t offsetOfPropertyStorage();
243 static size_t offsetOfInheritorID();
245 static JS_EXPORTDATA const ClassInfo s_info;
248 void finishCreation(JSGlobalData& globalData, PropertyStorage inlineStorage)
250 Base::finishCreation(globalData);
251 ASSERT(inherits(&s_info));
252 ASSERT(m_structure->propertyStorageCapacity() < baseExternalStorageCapacity);
253 ASSERT(m_structure->isEmpty());
254 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
255 ASSERT_UNUSED(inlineStorage, static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1));
256 ASSERT(m_structure->typeInfo().type() == ObjectType);
259 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
261 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
264 static const unsigned StructureFlags = 0;
266 void putThisToAnonymousValue(unsigned index)
268 locationForOffset(index)->setWithoutWriteBarrier(this);
271 // To instantiate objects you likely want JSFinalObject, below.
272 // To create derived types you likely want JSNonFinalObject, below.
273 JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage);
274 JSObject(VPtrStealingHackType, PropertyStorage inlineStorage)
275 : JSCell(VPtrStealingHack)
276 , m_propertyStorage(inlineStorage, StorageBarrier::Unchecked)
281 // Nobody should ever ask any of these questions on something already known to be a JSObject.
282 using JSCell::isAPIValueWrapper;
283 using JSCell::isGetterSetter;
284 using JSCell::toObject;
286 void getString(ExecState* exec);
290 ConstPropertyStorage propertyStorage() const { return m_propertyStorage.get(); }
291 PropertyStorage propertyStorage() { return m_propertyStorage.get(); }
293 const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
295 return &propertyStorage()[offset];
298 WriteBarrierBase<Unknown>* locationForOffset(size_t offset)
300 return &propertyStorage()[offset];
303 bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&, JSCell*);
304 bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&);
305 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
307 bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
309 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
310 Structure* createInheritorID(JSGlobalData&);
312 StorageBarrier m_propertyStorage;
313 WriteBarrier<Structure> m_inheritorID;
317 #if USE(JSVALUE32_64)
318 #define JSNonFinalObject_inlineStorageCapacity 4
319 #define JSFinalObject_inlineStorageCapacity 6
321 #define JSNonFinalObject_inlineStorageCapacity 2
322 #define JSFinalObject_inlineStorageCapacity 4
325 COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
327 // JSNonFinalObject is a type of JSObject that has some internal storage,
328 // but also preserves some space in the collector cell for additional
329 // data members in derived types.
330 class JSNonFinalObject : public JSObject {
331 friend class JSObject;
334 typedef JSObject Base;
336 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
338 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
342 explicit JSNonFinalObject(VPtrStealingHackType)
343 : JSObject(VPtrStealingHack, m_inlineStorage)
347 explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
348 : JSObject(globalData, structure, m_inlineStorage)
352 void finishCreation(JSGlobalData& globalData)
354 Base::finishCreation(globalData, m_inlineStorage);
355 ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
356 ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
360 WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
363 // JSFinalObject is a type of JSObject that contains sufficent internal
364 // storage to fully make use of the colloctor cell containing it.
365 class JSFinalObject : public JSObject {
366 friend class JSObject;
369 typedef JSObject Base;
371 explicit JSFinalObject(VPtrStealingHackType)
372 : JSObject(VPtrStealingHack, m_inlineStorage)
376 static JSFinalObject* create(ExecState* exec, Structure* structure)
378 JSFinalObject* finalObject = new (allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure);
379 finalObject->finishCreation(exec->globalData());
383 static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
385 return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
389 void finishCreation(JSGlobalData& globalData)
391 Base::finishCreation(globalData, m_inlineStorage);
392 ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
393 ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
397 explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
398 : JSObject(globalData, structure, m_inlineStorage)
402 static const unsigned StructureFlags = JSObject::StructureFlags | IsJSFinalObject;
404 WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
407 inline size_t JSObject::offsetOfInlineStorage()
409 ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
410 return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
413 inline size_t JSObject::offsetOfPropertyStorage()
415 return OBJECT_OFFSETOF(JSObject, m_propertyStorage);
418 inline size_t JSObject::offsetOfInheritorID()
420 return OBJECT_OFFSETOF(JSObject, m_inheritorID);
423 inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
425 return JSFinalObject::create(exec, structure);
428 inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
430 return JSFinalObject::createStructure(globalData, globalObject, prototype);
433 inline JSObject* asObject(JSCell* cell)
435 ASSERT(cell->isObject());
436 return static_cast<JSObject*>(cell);
439 inline JSObject* asObject(JSValue value)
441 return asObject(value.asCell());
444 inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage)
445 : JSCell(globalData, structure)
446 , m_propertyStorage(globalData, this, inlineStorage)
450 inline JSObject::~JSObject()
452 if (!isUsingInlineStorage() && !Heap::heap(this)->inPropertyStorageNursery(m_propertyStorage.get()))
453 delete [] m_propertyStorage.get();
456 inline JSValue JSObject::prototype() const
458 return m_structure->storedPrototype();
461 inline bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
463 JSValue nextPrototypeValue = prototype;
464 while (nextPrototypeValue && nextPrototypeValue.isObject()) {
465 JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
466 if (nextPrototype == this)
468 nextPrototypeValue = nextPrototype->prototype();
470 setPrototype(globalData, prototype);
474 inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
477 setStructure(globalData, Structure::changePrototypeTransition(globalData, m_structure.get(), prototype));
480 inline void JSObject::setStructure(JSGlobalData& globalData, Structure* structure)
482 ASSERT(structure->typeInfo().overridesVisitChildren() == m_structure->typeInfo().overridesVisitChildren());
483 m_structure.set(globalData, this, structure);
486 inline Structure* JSObject::inheritorID(JSGlobalData& globalData)
489 ASSERT(m_inheritorID->isEmpty());
490 return m_inheritorID.get();
492 return createInheritorID(globalData);
495 inline bool Structure::isUsingInlineStorage() const
497 return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
500 inline bool JSCell::inherits(const ClassInfo* info) const
502 return classInfo()->isSubClassOf(info);
505 // this method is here to be after the inline declaration of JSCell::inherits
506 inline bool JSValue::inherits(const ClassInfo* classInfo) const
508 return isCell() && asCell()->inherits(classInfo);
511 ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
513 if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
514 if (m_structure->hasGetterSetterProperties() && location->isGetterSetter())
515 fillGetterPropertySlot(slot, location);
517 slot.setValue(this, location->get(), offsetForLocation(location));
521 // non-standard Netscape extension
522 if (propertyName == exec->propertyNames().underscoreProto) {
523 slot.setValue(prototype());
530 // It may seem crazy to inline a function this large, especially a virtual function,
531 // but it makes a big difference to property lookup that derived classes can inline their
532 // base class call to this.
533 ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
535 return inlineGetOwnPropertySlot(exec, propertyName, slot);
538 ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
540 if (!structure()->typeInfo().overridesGetOwnPropertySlot())
541 return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
542 return getOwnPropertySlot(exec, propertyName, slot);
545 // Fast call to get a property where we may not yet have converted the string to an
546 // identifier. The first time we perform a property access with a given string, try
547 // performing the property map lookup without forming an identifier. We detect this
548 // case by checking whether the hash has yet been set for this string.
549 ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const UString& name)
551 if (!m_structure->typeInfo().overridesGetOwnPropertySlot() && !m_structure->hasGetterSetterProperties()) {
552 size_t offset = name.impl()->hasHash()
553 ? m_structure->get(exec->globalData(), Identifier(exec, name))
554 : m_structure->get(exec->globalData(), name);
555 if (offset != WTF::notFound)
556 return asObject(this)->locationForOffset(offset)->get();
561 // It may seem crazy to inline a function this large but it makes a big difference
562 // since this is function very hot in variable lookup
563 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
565 JSObject* object = this;
567 if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
569 JSValue prototype = object->prototype();
570 if (!prototype.isObject())
572 object = asObject(prototype);
576 ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
578 JSObject* object = this;
580 if (object->getOwnPropertySlot(exec, propertyName, slot))
582 JSValue prototype = object->prototype();
583 if (!prototype.isObject())
585 object = asObject(prototype);
589 inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const
591 PropertySlot slot(this);
592 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
593 return slot.getValue(exec, propertyName);
595 return jsUndefined();
598 inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
600 PropertySlot slot(this);
601 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
602 return slot.getValue(exec, propertyName);
604 return jsUndefined();
607 inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
610 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
612 if (m_structure->isDictionary()) {
613 unsigned currentAttributes;
614 JSCell* currentSpecificFunction;
615 size_t offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
616 if (offset != WTF::notFound) {
617 // If there is currently a specific function, and there now either isn't,
618 // or the new value is different, then despecify.
619 if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
620 m_structure->despecifyDictionaryFunction(globalData, propertyName);
621 if (checkReadOnly && currentAttributes & ReadOnly)
624 putDirectOffset(globalData, offset, value);
625 // At this point, the objects structure only has a specific value set if previously there
626 // had been one set, and if the new value being specified is the same (otherwise we would
627 // have despecified, above). So, if currentSpecificFunction is not set, or if the new
628 // value is different (or there is no new value), then the slot now has no value - and
629 // as such it is cachable.
630 // If there was previously a value, and the new value is the same, then we cannot cache.
631 if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
632 slot.setExistingProperty(this, offset);
636 if (checkReadOnly && !isExtensible())
639 size_t currentCapacity = m_structure->propertyStorageCapacity();
640 offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
641 if (currentCapacity != m_structure->propertyStorageCapacity())
642 allocatePropertyStorage(globalData, currentCapacity, m_structure->propertyStorageCapacity());
644 ASSERT(offset < m_structure->propertyStorageCapacity());
645 putDirectOffset(globalData, offset, value);
646 // See comment on setNewProperty call below.
647 if (!specificFunction)
648 slot.setNewProperty(this, offset);
653 size_t currentCapacity = m_structure->propertyStorageCapacity();
654 if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(m_structure.get(), propertyName, attributes, specificFunction, offset)) {
655 if (currentCapacity != structure->propertyStorageCapacity())
656 allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
658 ASSERT(offset < structure->propertyStorageCapacity());
659 setStructure(globalData, structure);
660 putDirectOffset(globalData, offset, value);
661 // This is a new property; transitions with specific values are not currently cachable,
662 // so leave the slot in an uncachable state.
663 if (!specificFunction)
664 slot.setNewProperty(this, offset);
668 unsigned currentAttributes;
669 JSCell* currentSpecificFunction;
670 offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
671 if (offset != WTF::notFound) {
672 if (checkReadOnly && currentAttributes & ReadOnly)
675 // There are three possibilities here:
676 // (1) There is an existing specific value set, and we're overwriting with *the same value*.
677 // * Do nothing - no need to despecify, but that means we can't cache (a cached
678 // put could write a different value). Leave the slot in an uncachable state.
679 // (2) There is a specific value currently set, but we're writing a different value.
680 // * First, we have to despecify. Having done so, this is now a regular slot
681 // with no specific value, so go ahead & cache like normal.
682 // (3) Normal case, there is no specific value set.
683 // * Go ahead & cache like normal.
684 if (currentSpecificFunction) {
685 // case (1) Do the put, then return leaving the slot uncachable.
686 if (specificFunction == currentSpecificFunction) {
687 putDirectOffset(globalData, offset, value);
690 // case (2) Despecify, fall through to (3).
691 setStructure(globalData, Structure::despecifyFunctionTransition(globalData, m_structure.get(), propertyName));
694 // case (3) set the slot, do the put, return.
695 slot.setExistingProperty(this, offset);
696 putDirectOffset(globalData, offset, value);
700 if (checkReadOnly && !isExtensible())
703 Structure* structure = Structure::addPropertyTransition(globalData, m_structure.get(), propertyName, attributes, specificFunction, offset);
705 if (currentCapacity != structure->propertyStorageCapacity())
706 allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
708 ASSERT(offset < structure->propertyStorageCapacity());
709 setStructure(globalData, structure);
710 putDirectOffset(globalData, offset, value);
711 // This is a new property; transitions with specific values are not currently cachable,
712 // so leave the slot in an uncachable state.
713 if (!specificFunction)
714 slot.setNewProperty(this, offset);
718 inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
721 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
723 return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
726 inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
728 PutPropertySlot slot;
729 putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
732 inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
735 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
737 return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, 0);
740 inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
742 PutPropertySlot slot;
743 putDirectInternal(globalData, propertyName, value, attributes, false, slot, 0);
746 inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
748 return putDirectInternal(globalData, propertyName, value, 0, false, slot, 0);
751 inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
753 putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, value);
756 inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attr)
758 PutPropertySlot slot;
759 putDirectInternal(globalData, propertyName, value, attr, false, slot, value);
762 inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
764 size_t currentCapacity = m_structure->propertyStorageCapacity();
765 size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, 0);
766 if (currentCapacity != m_structure->propertyStorageCapacity())
767 allocatePropertyStorage(globalData, currentCapacity, m_structure->propertyStorageCapacity());
768 putDirectOffset(globalData, offset, value);
771 inline void JSObject::putDirectFunctionWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes)
773 size_t currentCapacity = m_structure->propertyStorageCapacity();
774 size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, value);
775 if (currentCapacity != m_structure->propertyStorageCapacity())
776 allocatePropertyStorage(globalData, currentCapacity, m_structure->propertyStorageCapacity());
777 putDirectOffset(globalData, offset, value);
780 inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
782 if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
783 allocatePropertyStorage(globalData, m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
784 setStructure(globalData, newStructure);
787 inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
789 return defaultValue(exec, preferredType);
792 inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
794 PropertySlot slot(asValue());
795 return get(exec, propertyName, slot);
798 inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
800 if (UNLIKELY(!isCell())) {
801 JSObject* prototype = synthesizePrototype(exec);
802 if (propertyName == exec->propertyNames().underscoreProto)
804 if (!prototype->getPropertySlot(exec, propertyName, slot))
805 return jsUndefined();
806 return slot.getValue(exec, propertyName);
808 JSCell* cell = asCell();
810 if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
811 return slot.getValue(exec, propertyName);
812 JSValue prototype = asObject(cell)->prototype();
813 if (!prototype.isObject())
814 return jsUndefined();
815 cell = asObject(prototype);
819 inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
821 PropertySlot slot(asValue());
822 return get(exec, propertyName, slot);
825 inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
827 if (UNLIKELY(!isCell())) {
828 JSObject* prototype = synthesizePrototype(exec);
829 if (!prototype->getPropertySlot(exec, propertyName, slot))
830 return jsUndefined();
831 return slot.getValue(exec, propertyName);
833 JSCell* cell = const_cast<JSCell*>(asCell());
835 if (cell->getOwnPropertySlot(exec, propertyName, slot))
836 return slot.getValue(exec, propertyName);
837 JSValue prototype = asObject(cell)->prototype();
838 if (!prototype.isObject())
839 return jsUndefined();
840 cell = prototype.asCell();
844 inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
846 if (UNLIKELY(!isCell())) {
847 synthesizeObject(exec)->put(exec, propertyName, value, slot);
850 asCell()->put(exec, propertyName, value, slot);
853 inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
855 ASSERT(isCell() && isObject());
856 if (!asObject(asCell())->putDirect(exec->globalData(), propertyName, value, slot) && slot.isStrictMode())
857 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
860 inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
862 if (UNLIKELY(!isCell())) {
863 synthesizeObject(exec)->put(exec, propertyName, value);
866 asCell()->put(exec, propertyName, value);
869 ALWAYS_INLINE void JSObject::visitChildrenDirect(SlotVisitor& visitor)
871 JSCell::visitChildren(visitor);
873 PropertyStorage storage = propertyStorage();
874 if (Heap::heap(this)->inPropertyStorageNursery(storage)) {
875 m_propertyStorage.set(new WriteBarrierBase<Unknown>[structure()->propertyStorageCapacity()], StorageBarrier::Unchecked);
876 if (structure()->propertyStorageCapacity() > m_structure->propertyStorageSize())
877 ASSERT(!storage[m_structure->propertyStorageSize()]);
878 memcpy(m_propertyStorage.get(), storage, m_structure->propertyStorageSize() * sizeof(WriteBarrierBase<Unknown>));
880 size_t storageSize = m_structure->propertyStorageSize();
881 visitor.appendValues(storage, storageSize);
883 visitor.append(&m_inheritorID);
886 // --- JSValue inlines ----------------------------
888 ALWAYS_INLINE UString JSValue::toThisString(ExecState* exec) const
890 return isString() ? static_cast<JSString*>(asCell())->value(exec) : toThisObject(exec)->toString(exec);
893 inline JSString* JSValue::toThisJSString(ExecState* exec) const
895 return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec));
898 inline JSValue JSValue::toStrictThisObject(ExecState* exec) const
902 return asObject(asCell())->toStrictThisObject(exec);
905 ALWAYS_INLINE JSObject* Register::function() const
909 return asObject(jsValue());
912 ALWAYS_INLINE Register Register::withCallee(JSObject* callee)