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 "Completion.h"
30 #include "CallFrame.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"
39 #include <wtf/StdLibExtras.h>
43 inline JSCell
* getJSFunction(JSGlobalData
& globalData
, JSValue value
)
45 if (value
.isCell() && (value
.asCell()->vptr() == globalData
.jsFunctionVPtr
))
46 return value
.asCell();
51 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 typedef WriteBarrierBase
<Unknown
>* PropertyStorage
;
73 typedef const WriteBarrierBase
<Unknown
>* ConstPropertyStorage
;
75 class JSObject
: public JSCell
{
76 friend class BatchedTransitionOptimizer
;
79 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 virtual 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 virtual ComplType
exceptionType() const { return Throw
; }
221 void allocatePropertyStorage(size_t oldSize
, size_t newSize
);
222 bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage
) == static_cast<const void*>(this + 1); }
224 static const unsigned baseExternalStorageCapacity
= 16;
226 void flattenDictionaryObject(JSGlobalData
& globalData
)
228 m_structure
->flattenDictionaryStructure(globalData
, this);
231 void putAnonymousValue(JSGlobalData
& globalData
, unsigned index
, JSValue value
)
233 ASSERT(index
< m_structure
->anonymousSlotCount());
234 locationForOffset(index
)->set(globalData
, this, value
);
236 void clearAnonymousValue(unsigned index
)
238 ASSERT(index
< m_structure
->anonymousSlotCount());
239 locationForOffset(index
)->clear();
241 JSValue
getAnonymousValue(unsigned index
) const
243 ASSERT(index
< m_structure
->anonymousSlotCount());
244 return locationForOffset(index
)->get();
247 static size_t offsetOfInlineStorage();
249 static JS_EXPORTDATA
const ClassInfo s_info
;
252 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue prototype
)
254 return Structure::create(globalData
, prototype
, TypeInfo(ObjectType
, StructureFlags
), AnonymousSlotCount
, &s_info
);
257 static const unsigned StructureFlags
= 0;
259 void putThisToAnonymousValue(unsigned index
)
261 locationForOffset(index
)->setWithoutWriteBarrier(this);
264 // To instantiate objects you likely want JSFinalObject, below.
265 // To create derived types you likely want JSNonFinalObject, below.
266 JSObject(JSGlobalData
&, Structure
*, PropertyStorage inlineStorage
);
267 JSObject(VPtrStealingHackType
, PropertyStorage inlineStorage
)
268 : JSCell(VPtrStealingHack
)
269 , m_propertyStorage(inlineStorage
)
274 // Nobody should ever ask any of these questions on something already known to be a JSObject.
275 using JSCell::isAPIValueWrapper
;
276 using JSCell::isGetterSetter
;
277 using JSCell::toObject
;
279 void getString(ExecState
* exec
);
283 ConstPropertyStorage
propertyStorage() const { return m_propertyStorage
; }
284 PropertyStorage
propertyStorage() { return m_propertyStorage
; }
286 const WriteBarrierBase
<Unknown
>* locationForOffset(size_t offset
) const
288 return &propertyStorage()[offset
];
291 WriteBarrierBase
<Unknown
>* locationForOffset(size_t offset
)
293 return &propertyStorage()[offset
];
296 bool putDirectInternal(JSGlobalData
&, const Identifier
& propertyName
, JSValue
, unsigned attr
, bool checkReadOnly
, PutPropertySlot
&, JSCell
*);
297 bool putDirectInternal(JSGlobalData
&, const Identifier
& propertyName
, JSValue
, unsigned attr
, bool checkReadOnly
, PutPropertySlot
&);
298 void putDirectInternal(JSGlobalData
&, const Identifier
& propertyName
, JSValue value
, unsigned attr
= 0);
300 bool inlineGetOwnPropertySlot(ExecState
*, const Identifier
& propertyName
, PropertySlot
&);
302 const HashEntry
* findPropertyHashEntry(ExecState
*, const Identifier
& propertyName
) const;
303 Structure
* createInheritorID(JSGlobalData
&);
305 PropertyStorage m_propertyStorage
;
306 WriteBarrier
<Structure
> m_inheritorID
;
310 #if USE(JSVALUE32_64)
311 #define JSNonFinalObject_inlineStorageCapacity 4
312 #define JSFinalObject_inlineStorageCapacity 6
314 #define JSNonFinalObject_inlineStorageCapacity 2
315 #define JSFinalObject_inlineStorageCapacity 4
318 COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity
>= JSNonFinalObject_inlineStorageCapacity
), final_storage_is_at_least_as_large_as_non_final
);
320 // JSNonFinalObject is a type of JSObject that has some internal storage,
321 // but also preserves some space in the collector cell for additional
322 // data members in derived types.
323 class JSNonFinalObject
: public JSObject
{
324 friend class JSObject
;
327 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue prototype
)
329 return Structure::create(globalData
, prototype
, TypeInfo(ObjectType
, StructureFlags
), AnonymousSlotCount
, &s_info
);
333 explicit JSNonFinalObject(VPtrStealingHackType
)
334 : JSObject(VPtrStealingHack
, m_inlineStorage
)
338 explicit JSNonFinalObject(JSGlobalData
& globalData
, Structure
* structure
)
339 : JSObject(globalData
, structure
, m_inlineStorage
)
341 ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject
, m_inlineStorage
) % sizeof(double)));
342 ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity
);
346 WriteBarrier
<Unknown
> m_inlineStorage
[JSNonFinalObject_inlineStorageCapacity
];
349 // JSFinalObject is a type of JSObject that contains sufficent internal
350 // storage to fully make use of the colloctor cell containing it.
351 class JSFinalObject
: public JSObject
{
352 friend class JSObject
;
355 static JSFinalObject
* create(ExecState
* exec
, Structure
* structure
)
357 return new (exec
) JSFinalObject(exec
->globalData(), structure
);
360 static Structure
* createStructure(JSGlobalData
& globalData
, JSValue prototype
)
362 return Structure::create(globalData
, prototype
, TypeInfo(ObjectType
, StructureFlags
), AnonymousSlotCount
, &s_info
);
366 explicit JSFinalObject(JSGlobalData
& globalData
, Structure
* structure
)
367 : JSObject(globalData
, structure
, m_inlineStorage
)
369 ASSERT(OBJECT_OFFSETOF(JSFinalObject
, m_inlineStorage
) % sizeof(double) == 0);
370 ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity
);
373 static const unsigned StructureFlags
= JSObject::StructureFlags
| IsJSFinalObject
;
375 WriteBarrierBase
<Unknown
> m_inlineStorage
[JSFinalObject_inlineStorageCapacity
];
378 inline size_t JSObject::offsetOfInlineStorage()
380 ASSERT(OBJECT_OFFSETOF(JSFinalObject
, m_inlineStorage
) == OBJECT_OFFSETOF(JSNonFinalObject
, m_inlineStorage
));
381 return OBJECT_OFFSETOF(JSFinalObject
, m_inlineStorage
);
384 inline JSObject
* constructEmptyObject(ExecState
* exec
, Structure
* structure
)
386 return JSFinalObject::create(exec
, structure
);
389 inline Structure
* createEmptyObjectStructure(JSGlobalData
& globalData
, JSValue prototype
)
391 return JSFinalObject::createStructure(globalData
, prototype
);
394 inline JSObject
* asObject(JSCell
* cell
)
396 ASSERT(cell
->isObject());
397 return static_cast<JSObject
*>(cell
);
400 inline JSObject
* asObject(JSValue value
)
402 return asObject(value
.asCell());
405 inline JSObject::JSObject(JSGlobalData
& globalData
, Structure
* structure
, PropertyStorage inlineStorage
)
406 : JSCell(globalData
, structure
)
407 , m_propertyStorage(inlineStorage
)
409 ASSERT(inherits(&s_info
));
410 ASSERT(m_structure
->propertyStorageCapacity() < baseExternalStorageCapacity
);
411 ASSERT(m_structure
->isEmpty());
412 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
413 ASSERT(static_cast<void*>(inlineStorage
) == static_cast<void*>(this + 1));
414 ASSERT(m_structure
->typeInfo().type() == ObjectType
);
417 inline JSObject::~JSObject()
419 if (!isUsingInlineStorage())
420 delete [] m_propertyStorage
;
423 inline JSValue
JSObject::prototype() const
425 return m_structure
->storedPrototype();
428 inline bool JSObject::setPrototypeWithCycleCheck(JSGlobalData
& globalData
, JSValue prototype
)
430 JSValue nextPrototypeValue
= prototype
;
431 while (nextPrototypeValue
&& nextPrototypeValue
.isObject()) {
432 JSObject
* nextPrototype
= asObject(nextPrototypeValue
)->unwrappedObject();
433 if (nextPrototype
== this)
435 nextPrototypeValue
= nextPrototype
->prototype();
437 setPrototype(globalData
, prototype
);
441 inline void JSObject::setPrototype(JSGlobalData
& globalData
, JSValue prototype
)
444 setStructure(globalData
, Structure::changePrototypeTransition(globalData
, m_structure
.get(), prototype
));
447 inline void JSObject::setStructure(JSGlobalData
& globalData
, Structure
* structure
)
449 ASSERT(structure
->typeInfo().overridesVisitChildren() == m_structure
->typeInfo().overridesVisitChildren());
450 m_structure
.set(globalData
, this, structure
);
453 inline Structure
* JSObject::inheritorID(JSGlobalData
& globalData
)
456 ASSERT(m_inheritorID
->isEmpty());
457 return m_inheritorID
.get();
459 return createInheritorID(globalData
);
462 inline bool Structure::isUsingInlineStorage() const
464 return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity
;
467 inline bool JSCell::inherits(const ClassInfo
* info
) const
469 for (const ClassInfo
* ci
= classInfo(); ci
; ci
= ci
->parentClass
) {
476 // this method is here to be after the inline declaration of JSCell::inherits
477 inline bool JSValue::inherits(const ClassInfo
* classInfo
) const
479 return isCell() && asCell()->inherits(classInfo
);
482 ALWAYS_INLINE
bool JSObject::inlineGetOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
484 if (WriteBarrierBase
<Unknown
>* location
= getDirectLocation(exec
->globalData(), propertyName
)) {
485 if (m_structure
->hasGetterSetterProperties() && location
->isGetterSetter())
486 fillGetterPropertySlot(slot
, location
);
488 slot
.setValue(this, location
->get(), offsetForLocation(location
));
492 // non-standard Netscape extension
493 if (propertyName
== exec
->propertyNames().underscoreProto
) {
494 slot
.setValue(prototype());
501 // It may seem crazy to inline a function this large, especially a virtual function,
502 // but it makes a big difference to property lookup that derived classes can inline their
503 // base class call to this.
504 ALWAYS_INLINE
bool JSObject::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
506 return inlineGetOwnPropertySlot(exec
, propertyName
, slot
);
509 ALWAYS_INLINE
bool JSCell::fastGetOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
511 if (!structure()->typeInfo().overridesGetOwnPropertySlot())
512 return asObject(this)->inlineGetOwnPropertySlot(exec
, propertyName
, slot
);
513 return getOwnPropertySlot(exec
, propertyName
, slot
);
516 // It may seem crazy to inline a function this large but it makes a big difference
517 // since this is function very hot in variable lookup
518 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
520 JSObject
* object
= this;
522 if (object
->fastGetOwnPropertySlot(exec
, propertyName
, slot
))
524 JSValue prototype
= object
->prototype();
525 if (!prototype
.isObject())
527 object
= asObject(prototype
);
531 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
)
533 JSObject
* object
= this;
535 if (object
->getOwnPropertySlot(exec
, propertyName
, slot
))
537 JSValue prototype
= object
->prototype();
538 if (!prototype
.isObject())
540 object
= asObject(prototype
);
544 inline JSValue
JSObject::get(ExecState
* exec
, const Identifier
& propertyName
) const
546 PropertySlot
slot(this);
547 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
548 return slot
.getValue(exec
, propertyName
);
550 return jsUndefined();
553 inline JSValue
JSObject::get(ExecState
* exec
, unsigned propertyName
) const
555 PropertySlot
slot(this);
556 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
557 return slot
.getValue(exec
, propertyName
);
559 return jsUndefined();
562 inline bool JSObject::putDirectInternal(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
, bool checkReadOnly
, PutPropertySlot
& slot
, JSCell
* specificFunction
)
565 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
567 if (m_structure
->isDictionary()) {
568 unsigned currentAttributes
;
569 JSCell
* currentSpecificFunction
;
570 size_t offset
= m_structure
->get(globalData
, propertyName
, currentAttributes
, currentSpecificFunction
);
571 if (offset
!= WTF::notFound
) {
572 // If there is currently a specific function, and there now either isn't,
573 // or the new value is different, then despecify.
574 if (currentSpecificFunction
&& (specificFunction
!= currentSpecificFunction
))
575 m_structure
->despecifyDictionaryFunction(globalData
, propertyName
);
576 if (checkReadOnly
&& currentAttributes
& ReadOnly
)
579 putDirectOffset(globalData
, offset
, value
);
580 // At this point, the objects structure only has a specific value set if previously there
581 // had been one set, and if the new value being specified is the same (otherwise we would
582 // have despecified, above). So, if currentSpecificFunction is not set, or if the new
583 // value is different (or there is no new value), then the slot now has no value - and
584 // as such it is cachable.
585 // If there was previously a value, and the new value is the same, then we cannot cache.
586 if (!currentSpecificFunction
|| (specificFunction
!= currentSpecificFunction
))
587 slot
.setExistingProperty(this, offset
);
591 if (checkReadOnly
&& !isExtensible())
594 size_t currentCapacity
= m_structure
->propertyStorageCapacity();
595 offset
= m_structure
->addPropertyWithoutTransition(globalData
, propertyName
, attributes
, specificFunction
);
596 if (currentCapacity
!= m_structure
->propertyStorageCapacity())
597 allocatePropertyStorage(currentCapacity
, m_structure
->propertyStorageCapacity());
599 ASSERT(offset
< m_structure
->propertyStorageCapacity());
600 putDirectOffset(globalData
, offset
, value
);
601 // See comment on setNewProperty call below.
602 if (!specificFunction
)
603 slot
.setNewProperty(this, offset
);
608 size_t currentCapacity
= m_structure
->propertyStorageCapacity();
609 if (Structure
* structure
= Structure::addPropertyTransitionToExistingStructure(m_structure
.get(), propertyName
, attributes
, specificFunction
, offset
)) {
610 if (currentCapacity
!= structure
->propertyStorageCapacity())
611 allocatePropertyStorage(currentCapacity
, structure
->propertyStorageCapacity());
613 ASSERT(offset
< structure
->propertyStorageCapacity());
614 setStructure(globalData
, structure
);
615 putDirectOffset(globalData
, offset
, value
);
616 // This is a new property; transitions with specific values are not currently cachable,
617 // so leave the slot in an uncachable state.
618 if (!specificFunction
)
619 slot
.setNewProperty(this, offset
);
623 unsigned currentAttributes
;
624 JSCell
* currentSpecificFunction
;
625 offset
= m_structure
->get(globalData
, propertyName
, currentAttributes
, currentSpecificFunction
);
626 if (offset
!= WTF::notFound
) {
627 if (checkReadOnly
&& currentAttributes
& ReadOnly
)
630 // There are three possibilities here:
631 // (1) There is an existing specific value set, and we're overwriting with *the same value*.
632 // * Do nothing - no need to despecify, but that means we can't cache (a cached
633 // put could write a different value). Leave the slot in an uncachable state.
634 // (2) There is a specific value currently set, but we're writing a different value.
635 // * First, we have to despecify. Having done so, this is now a regular slot
636 // with no specific value, so go ahead & cache like normal.
637 // (3) Normal case, there is no specific value set.
638 // * Go ahead & cache like normal.
639 if (currentSpecificFunction
) {
640 // case (1) Do the put, then return leaving the slot uncachable.
641 if (specificFunction
== currentSpecificFunction
) {
642 putDirectOffset(globalData
, offset
, value
);
645 // case (2) Despecify, fall through to (3).
646 setStructure(globalData
, Structure::despecifyFunctionTransition(globalData
, m_structure
.get(), propertyName
));
649 // case (3) set the slot, do the put, return.
650 slot
.setExistingProperty(this, offset
);
651 putDirectOffset(globalData
, offset
, value
);
655 if (checkReadOnly
&& !isExtensible())
658 Structure
* structure
= Structure::addPropertyTransition(globalData
, m_structure
.get(), propertyName
, attributes
, specificFunction
, offset
);
660 if (currentCapacity
!= structure
->propertyStorageCapacity())
661 allocatePropertyStorage(currentCapacity
, structure
->propertyStorageCapacity());
663 ASSERT(offset
< structure
->propertyStorageCapacity());
664 setStructure(globalData
, structure
);
665 putDirectOffset(globalData
, offset
, value
);
666 // This is a new property; transitions with specific values are not currently cachable,
667 // so leave the slot in an uncachable state.
668 if (!specificFunction
)
669 slot
.setNewProperty(this, offset
);
673 inline bool JSObject::putDirectInternal(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
, bool checkReadOnly
, PutPropertySlot
& slot
)
676 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
678 return putDirectInternal(globalData
, propertyName
, value
, attributes
, checkReadOnly
, slot
, getJSFunction(globalData
, value
));
681 inline void JSObject::putDirectInternal(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
)
683 PutPropertySlot slot
;
684 putDirectInternal(globalData
, propertyName
, value
, attributes
, false, slot
, getJSFunction(globalData
, value
));
687 inline bool JSObject::putDirect(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
, bool checkReadOnly
, PutPropertySlot
& slot
)
690 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
692 return putDirectInternal(globalData
, propertyName
, value
, attributes
, checkReadOnly
, slot
, 0);
695 inline void JSObject::putDirect(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
)
697 PutPropertySlot slot
;
698 putDirectInternal(globalData
, propertyName
, value
, attributes
, false, slot
, 0);
701 inline bool JSObject::putDirect(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
703 return putDirectInternal(globalData
, propertyName
, value
, 0, false, slot
, 0);
706 inline void JSObject::putDirectFunction(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSCell
* value
, unsigned attributes
, bool checkReadOnly
, PutPropertySlot
& slot
)
708 putDirectInternal(globalData
, propertyName
, value
, attributes
, checkReadOnly
, slot
, value
);
711 inline void JSObject::putDirectFunction(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSCell
* value
, unsigned attr
)
713 PutPropertySlot slot
;
714 putDirectInternal(globalData
, propertyName
, value
, attr
, false, slot
, value
);
717 inline void JSObject::putDirectWithoutTransition(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSValue value
, unsigned attributes
)
719 size_t currentCapacity
= m_structure
->propertyStorageCapacity();
720 size_t offset
= m_structure
->addPropertyWithoutTransition(globalData
, propertyName
, attributes
, 0);
721 if (currentCapacity
!= m_structure
->propertyStorageCapacity())
722 allocatePropertyStorage(currentCapacity
, m_structure
->propertyStorageCapacity());
723 putDirectOffset(globalData
, offset
, value
);
726 inline void JSObject::putDirectFunctionWithoutTransition(JSGlobalData
& globalData
, const Identifier
& propertyName
, JSCell
* value
, unsigned attributes
)
728 size_t currentCapacity
= m_structure
->propertyStorageCapacity();
729 size_t offset
= m_structure
->addPropertyWithoutTransition(globalData
, propertyName
, attributes
, value
);
730 if (currentCapacity
!= m_structure
->propertyStorageCapacity())
731 allocatePropertyStorage(currentCapacity
, m_structure
->propertyStorageCapacity());
732 putDirectOffset(globalData
, offset
, value
);
735 inline void JSObject::transitionTo(JSGlobalData
& globalData
, Structure
* newStructure
)
737 if (m_structure
->propertyStorageCapacity() != newStructure
->propertyStorageCapacity())
738 allocatePropertyStorage(m_structure
->propertyStorageCapacity(), newStructure
->propertyStorageCapacity());
739 setStructure(globalData
, newStructure
);
742 inline JSValue
JSObject::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const
744 return defaultValue(exec
, preferredType
);
747 inline JSValue
JSValue::get(ExecState
* exec
, const Identifier
& propertyName
) const
749 PropertySlot
slot(asValue());
750 return get(exec
, propertyName
, slot
);
753 inline JSValue
JSValue::get(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
) const
755 if (UNLIKELY(!isCell())) {
756 JSObject
* prototype
= synthesizePrototype(exec
);
757 if (propertyName
== exec
->propertyNames().underscoreProto
)
759 if (!prototype
->getPropertySlot(exec
, propertyName
, slot
))
760 return jsUndefined();
761 return slot
.getValue(exec
, propertyName
);
763 JSCell
* cell
= asCell();
765 if (cell
->fastGetOwnPropertySlot(exec
, propertyName
, slot
))
766 return slot
.getValue(exec
, propertyName
);
767 JSValue prototype
= asObject(cell
)->prototype();
768 if (!prototype
.isObject())
769 return jsUndefined();
770 cell
= asObject(prototype
);
774 inline JSValue
JSValue::get(ExecState
* exec
, unsigned propertyName
) const
776 PropertySlot
slot(asValue());
777 return get(exec
, propertyName
, slot
);
780 inline JSValue
JSValue::get(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
) const
782 if (UNLIKELY(!isCell())) {
783 JSObject
* prototype
= synthesizePrototype(exec
);
784 if (!prototype
->getPropertySlot(exec
, propertyName
, slot
))
785 return jsUndefined();
786 return slot
.getValue(exec
, propertyName
);
788 JSCell
* cell
= const_cast<JSCell
*>(asCell());
790 if (cell
->getOwnPropertySlot(exec
, propertyName
, slot
))
791 return slot
.getValue(exec
, propertyName
);
792 JSValue prototype
= asObject(cell
)->prototype();
793 if (!prototype
.isObject())
794 return jsUndefined();
795 cell
= prototype
.asCell();
799 inline void JSValue::put(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
801 if (UNLIKELY(!isCell())) {
802 synthesizeObject(exec
)->put(exec
, propertyName
, value
, slot
);
805 asCell()->put(exec
, propertyName
, value
, slot
);
808 inline void JSValue::putDirect(ExecState
* exec
, const Identifier
& propertyName
, JSValue value
, PutPropertySlot
& slot
)
810 ASSERT(isCell() && isObject());
811 if (!asObject(asCell())->putDirect(exec
->globalData(), propertyName
, value
, slot
) && slot
.isStrictMode())
812 throwTypeError(exec
, StrictModeReadonlyPropertyWriteError
);
815 inline void JSValue::put(ExecState
* exec
, unsigned propertyName
, JSValue value
)
817 if (UNLIKELY(!isCell())) {
818 synthesizeObject(exec
)->put(exec
, propertyName
, value
);
821 asCell()->put(exec
, propertyName
, value
);
824 ALWAYS_INLINE
void JSObject::visitChildrenDirect(SlotVisitor
& visitor
)
826 JSCell::visitChildren(visitor
);
828 PropertyStorage storage
= propertyStorage();
829 size_t storageSize
= m_structure
->propertyStorageSize();
830 visitor
.appendValues(storage
, storageSize
);
832 visitor
.append(&m_inheritorID
);
835 // --- JSValue inlines ----------------------------
837 ALWAYS_INLINE UString
JSValue::toThisString(ExecState
* exec
) const
839 return isString() ? static_cast<JSString
*>(asCell())->value(exec
) : toThisObject(exec
)->toString(exec
);
842 inline JSString
* JSValue::toThisJSString(ExecState
* exec
) const
844 return isString() ? static_cast<JSString
*>(asCell()) : jsString(exec
, toThisObject(exec
)->toString(exec
));
847 inline JSValue
JSValue::toStrictThisObject(ExecState
* exec
) const
851 return asObject(asCell())->toStrictThisObject(exec
);
854 ALWAYS_INLINE JSObject
* Register::function() const
858 return asObject(jsValue());
861 ALWAYS_INLINE Register
Register::withCallee(JSObject
* callee
)