]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/JSObject.h
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / runtime / JSObject.h
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
f9bf01c6 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
9dae56ea
A
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"
4e4e5a6f 29#include "Completion.h"
9dae56ea 30#include "CallFrame.h"
f9bf01c6 31#include "JSCell.h"
f9bf01c6 32#include "MarkStack.h"
9dae56ea
A
33#include "PropertySlot.h"
34#include "PutPropertySlot.h"
35#include "ScopeChain.h"
36#include "Structure.h"
ba379fdc 37#include "JSGlobalData.h"
4e4e5a6f 38#include "JSString.h"
ba379fdc 39#include <wtf/StdLibExtras.h>
9dae56ea
A
40
41namespace JSC {
42
ba379fdc
A
43 inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
44 {
45 if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
46 return value.asCell();
47 return 0;
48 }
f9bf01c6
A
49
50 class HashEntry;
9dae56ea 51 class InternalFunction;
f9bf01c6 52 class PropertyDescriptor;
9dae56ea
A
53 class PropertyNameArray;
54 class Structure;
9dae56ea
A
55 struct HashTable;
56
14957cd0
A
57 JSObject* throwTypeError(ExecState*, const UString&);
58 extern const char* StrictModeReadonlyPropertyWriteError;
59
9dae56ea
A
60 // ECMA 262-3 8.6.1
61 // Property attributes
62 enum Attribute {
63 None = 0,
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
ba379fdc
A
68 Getter = 1 << 5, // property is a getter
69 Setter = 1 << 6 // property is a setter
9dae56ea
A
70 };
71
14957cd0
A
72 typedef WriteBarrierBase<Unknown>* PropertyStorage;
73 typedef const WriteBarrierBase<Unknown>* ConstPropertyStorage;
9dae56ea
A
74
75 class JSObject : public JSCell {
76 friend class BatchedTransitionOptimizer;
77 friend class JIT;
78 friend class JSCell;
14957cd0 79 friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
9dae56ea
A
80
81 public:
14957cd0
A
82 virtual void visitChildren(SlotVisitor&);
83 ALWAYS_INLINE void visitChildrenDirect(SlotVisitor&);
9dae56ea
A
84
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
87 virtual ~JSObject();
88
ba379fdc 89 JSValue prototype() const;
14957cd0
A
90 void setPrototype(JSGlobalData&, JSValue prototype);
91 bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
9dae56ea 92
14957cd0
A
93 void setStructure(JSGlobalData&, Structure*);
94 Structure* inheritorID(JSGlobalData&);
9dae56ea 95
9dae56ea
A
96 virtual UString className() const;
97
ba379fdc
A
98 JSValue get(ExecState*, const Identifier& propertyName) const;
99 JSValue get(ExecState*, unsigned propertyName) const;
9dae56ea
A
100
101 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
102 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
f9bf01c6 103 bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
9dae56ea
A
104
105 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
106 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
f9bf01c6 107 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
9dae56ea 108
ba379fdc
A
109 virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
110 virtual void put(ExecState*, unsigned propertyName, JSValue value);
9dae56ea 111
14957cd0
A
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);
ba379fdc
A
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);
9dae56ea
A
118
119 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
120
121 bool hasProperty(ExecState*, const Identifier& propertyName) const;
122 bool hasProperty(ExecState*, unsigned propertyName) const;
123 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
124
125 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
126 virtual bool deleteProperty(ExecState*, unsigned propertyName);
127
ba379fdc 128 virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
9dae56ea 129
ba379fdc 130 virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
9dae56ea 131
f9bf01c6
A
132 virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
133 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
9dae56ea 134
ba379fdc
A
135 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
136 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
9dae56ea
A
137 virtual bool toBoolean(ExecState*) const;
138 virtual double toNumber(ExecState*) const;
139 virtual UString toString(ExecState*) const;
14957cd0 140 virtual JSObject* toObject(ExecState*, JSGlobalObject*) const;
9dae56ea
A
141
142 virtual JSObject* toThisObject(ExecState*) const;
14957cd0 143 virtual JSValue toStrictThisObject(ExecState*) const;
9dae56ea
A
144 virtual JSObject* unwrappedObject();
145
ba379fdc 146 bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
9dae56ea
A
147
148 // This get function only looks at the property map.
14957cd0 149 JSValue getDirect(JSGlobalData& globalData, const Identifier& propertyName) const
9dae56ea 150 {
14957cd0 151 size_t offset = m_structure->get(globalData, propertyName);
ba379fdc 152 return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
9dae56ea
A
153 }
154
14957cd0 155 WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName)
9dae56ea 156 {
14957cd0 157 size_t offset = m_structure->get(globalData, propertyName);
9dae56ea
A
158 return offset != WTF::notFound ? locationForOffset(offset) : 0;
159 }
160
14957cd0 161 WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes)
9dae56ea 162 {
ba379fdc 163 JSCell* specificFunction;
14957cd0 164 size_t offset = m_structure->get(globalData, propertyName, attributes, specificFunction);
9dae56ea
A
165 return offset != WTF::notFound ? locationForOffset(offset) : 0;
166 }
167
14957cd0 168 size_t offsetForLocation(WriteBarrierBase<Unknown>* location) const
9dae56ea 169 {
14957cd0 170 return location - propertyStorage();
9dae56ea
A
171 }
172
14957cd0 173 void transitionTo(JSGlobalData&, Structure*);
9dae56ea 174
14957cd0
A
175 void removeDirect(JSGlobalData&, const Identifier& propertyName);
176 bool hasCustomProperties() { return m_structure->didTransition(); }
9dae56ea
A
177 bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
178
14957cd0
A
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&);
ba379fdc 182
14957cd0
A
183 void putDirectFunction(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr = 0);
184 void putDirectFunction(JSGlobalData&, const Identifier& propertyName, JSCell*, unsigned attr, bool checkReadOnly, PutPropertySlot&);
9dae56ea 185 void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
14957cd0 186 void putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr = 0);
ba379fdc 187
14957cd0
A
188 void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
189 void putDirectFunctionWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSCell* value, unsigned attr = 0);
9dae56ea 190 void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
14957cd0 191 void putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr = 0);
9dae56ea
A
192
193 // Fast access to known property offsets.
14957cd0
A
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(); }
9dae56ea 197
14957cd0 198 void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
9dae56ea 199
f9bf01c6
A
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);
ba379fdc
A
202 virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
203 virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
f9bf01c6 204 virtual bool defineOwnProperty(ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
9dae56ea
A
205
206 virtual bool isGlobalObject() const { return false; }
207 virtual bool isVariableObject() const { return false; }
208 virtual bool isActivationObject() const { return false; }
14957cd0
A
209 virtual bool isStrictModeFunction() const { return false; }
210 virtual bool isErrorInstance() const { return false; }
211
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(); }
9dae56ea 218
4e4e5a6f
A
219 virtual ComplType exceptionType() const { return Throw; }
220
9dae56ea 221 void allocatePropertyStorage(size_t oldSize, size_t newSize);
14957cd0 222 bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage) == static_cast<const void*>(this + 1); }
9dae56ea 223
14957cd0 224 static const unsigned baseExternalStorageCapacity = 16;
9dae56ea 225
14957cd0 226 void flattenDictionaryObject(JSGlobalData& globalData)
9dae56ea 227 {
14957cd0 228 m_structure->flattenDictionaryStructure(globalData, this);
9dae56ea
A
229 }
230
14957cd0
A
231 void putAnonymousValue(JSGlobalData& globalData, unsigned index, JSValue value)
232 {
233 ASSERT(index < m_structure->anonymousSlotCount());
234 locationForOffset(index)->set(globalData, this, value);
235 }
236 void clearAnonymousValue(unsigned index)
237 {
238 ASSERT(index < m_structure->anonymousSlotCount());
239 locationForOffset(index)->clear();
240 }
241 JSValue getAnonymousValue(unsigned index) const
ba379fdc 242 {
14957cd0
A
243 ASSERT(index < m_structure->anonymousSlotCount());
244 return locationForOffset(index)->get();
ba379fdc 245 }
9dae56ea 246
14957cd0
A
247 static size_t offsetOfInlineStorage();
248
249 static JS_EXPORTDATA const ClassInfo s_info;
250
f9bf01c6 251 protected:
14957cd0
A
252 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
253 {
254 return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
255 }
256
f9bf01c6
A
257 static const unsigned StructureFlags = 0;
258
14957cd0 259 void putThisToAnonymousValue(unsigned index)
f9bf01c6 260 {
14957cd0 261 locationForOffset(index)->setWithoutWriteBarrier(this);
f9bf01c6 262 }
14957cd0
A
263
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)
f9bf01c6 270 {
f9bf01c6
A
271 }
272
9dae56ea 273 private:
f9bf01c6
A
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;
278 void getObject();
279 void getString(ExecState* exec);
280 void isObject();
281 void isString();
14957cd0
A
282
283 ConstPropertyStorage propertyStorage() const { return m_propertyStorage; }
284 PropertyStorage propertyStorage() { return m_propertyStorage; }
ba379fdc 285
14957cd0 286 const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
ba379fdc 287 {
14957cd0 288 return &propertyStorage()[offset];
ba379fdc
A
289 }
290
14957cd0 291 WriteBarrierBase<Unknown>* locationForOffset(size_t offset)
ba379fdc 292 {
14957cd0 293 return &propertyStorage()[offset];
ba379fdc
A
294 }
295
14957cd0
A
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&);
ba379fdc
A
298 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
299
9dae56ea
A
300 bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
301
302 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
14957cd0 303 Structure* createInheritorID(JSGlobalData&);
9dae56ea 304
14957cd0
A
305 PropertyStorage m_propertyStorage;
306 WriteBarrier<Structure> m_inheritorID;
9dae56ea 307 };
14957cd0
A
308
309
310#if USE(JSVALUE32_64)
311#define JSNonFinalObject_inlineStorageCapacity 4
312#define JSFinalObject_inlineStorageCapacity 6
313#else
314#define JSNonFinalObject_inlineStorageCapacity 2
315#define JSFinalObject_inlineStorageCapacity 4
316#endif
317
318COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
319
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;
325
326 public:
327 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
328 {
329 return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
330 }
331
332 protected:
333 explicit JSNonFinalObject(VPtrStealingHackType)
334 : JSObject(VPtrStealingHack, m_inlineStorage)
335 {
336 }
ba379fdc 337
14957cd0
A
338 explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
339 : JSObject(globalData, structure, m_inlineStorage)
340 {
341 ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
342 ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
343 }
344
345 private:
346 WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
347 };
348
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;
353
354 public:
355 static JSFinalObject* create(ExecState* exec, Structure* structure)
356 {
357 return new (exec) JSFinalObject(exec->globalData(), structure);
358 }
359
360 static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
361 {
362 return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
363 }
364
365 private:
366 explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
367 : JSObject(globalData, structure, m_inlineStorage)
368 {
369 ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double) == 0);
370 ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
371 }
372
373 static const unsigned StructureFlags = JSObject::StructureFlags | IsJSFinalObject;
374
375 WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
376 };
377
378inline size_t JSObject::offsetOfInlineStorage()
379{
380 ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
381 return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
382}
383
384inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
385{
386 return JSFinalObject::create(exec, structure);
387}
388
389inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSValue prototype)
390{
391 return JSFinalObject::createStructure(globalData, prototype);
392}
393
f9bf01c6
A
394inline JSObject* asObject(JSCell* cell)
395{
396 ASSERT(cell->isObject());
397 return static_cast<JSObject*>(cell);
398}
9dae56ea 399
ba379fdc 400inline JSObject* asObject(JSValue value)
9dae56ea 401{
f9bf01c6 402 return asObject(value.asCell());
9dae56ea
A
403}
404
14957cd0
A
405inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage)
406 : JSCell(globalData, structure)
407 , m_propertyStorage(inlineStorage)
9dae56ea 408{
14957cd0
A
409 ASSERT(inherits(&s_info));
410 ASSERT(m_structure->propertyStorageCapacity() < baseExternalStorageCapacity);
9dae56ea
A
411 ASSERT(m_structure->isEmpty());
412 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
14957cd0
A
413 ASSERT(static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1));
414 ASSERT(m_structure->typeInfo().type() == ObjectType);
9dae56ea
A
415}
416
417inline JSObject::~JSObject()
418{
ba379fdc 419 if (!isUsingInlineStorage())
14957cd0 420 delete [] m_propertyStorage;
9dae56ea
A
421}
422
ba379fdc 423inline JSValue JSObject::prototype() const
9dae56ea
A
424{
425 return m_structure->storedPrototype();
426}
427
14957cd0
A
428inline bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
429{
430 JSValue nextPrototypeValue = prototype;
431 while (nextPrototypeValue && nextPrototypeValue.isObject()) {
432 JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
433 if (nextPrototype == this)
434 return false;
435 nextPrototypeValue = nextPrototype->prototype();
436 }
437 setPrototype(globalData, prototype);
438 return true;
439}
440
441inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
9dae56ea
A
442{
443 ASSERT(prototype);
14957cd0 444 setStructure(globalData, Structure::changePrototypeTransition(globalData, m_structure.get(), prototype));
9dae56ea
A
445}
446
14957cd0 447inline void JSObject::setStructure(JSGlobalData& globalData, Structure* structure)
9dae56ea 448{
14957cd0
A
449 ASSERT(structure->typeInfo().overridesVisitChildren() == m_structure->typeInfo().overridesVisitChildren());
450 m_structure.set(globalData, this, structure);
9dae56ea
A
451}
452
14957cd0 453inline Structure* JSObject::inheritorID(JSGlobalData& globalData)
9dae56ea 454{
14957cd0
A
455 if (m_inheritorID) {
456 ASSERT(m_inheritorID->isEmpty());
9dae56ea 457 return m_inheritorID.get();
14957cd0
A
458 }
459 return createInheritorID(globalData);
9dae56ea
A
460}
461
ba379fdc
A
462inline bool Structure::isUsingInlineStorage() const
463{
14957cd0 464 return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
ba379fdc
A
465}
466
f9bf01c6 467inline bool JSCell::inherits(const ClassInfo* info) const
9dae56ea
A
468{
469 for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
470 if (ci == info)
471 return true;
472 }
473 return false;
474}
475
f9bf01c6
A
476// this method is here to be after the inline declaration of JSCell::inherits
477inline bool JSValue::inherits(const ClassInfo* classInfo) const
9dae56ea 478{
f9bf01c6 479 return isCell() && asCell()->inherits(classInfo);
9dae56ea
A
480}
481
482ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
483{
14957cd0
A
484 if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
485 if (m_structure->hasGetterSetterProperties() && location->isGetterSetter())
9dae56ea
A
486 fillGetterPropertySlot(slot, location);
487 else
14957cd0 488 slot.setValue(this, location->get(), offsetForLocation(location));
9dae56ea
A
489 return true;
490 }
491
492 // non-standard Netscape extension
493 if (propertyName == exec->propertyNames().underscoreProto) {
494 slot.setValue(prototype());
495 return true;
496 }
497
498 return false;
499}
500
9dae56ea
A
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.
504ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
505{
506 return inlineGetOwnPropertySlot(exec, propertyName, slot);
507}
508
509ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
510{
f9bf01c6 511 if (!structure()->typeInfo().overridesGetOwnPropertySlot())
9dae56ea
A
512 return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
513 return getOwnPropertySlot(exec, propertyName, slot);
514}
515
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
f9bf01c6 518ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
9dae56ea
A
519{
520 JSObject* object = this;
521 while (true) {
522 if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
523 return true;
ba379fdc 524 JSValue prototype = object->prototype();
9dae56ea
A
525 if (!prototype.isObject())
526 return false;
527 object = asObject(prototype);
528 }
529}
530
f9bf01c6 531ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
9dae56ea
A
532{
533 JSObject* object = this;
534 while (true) {
535 if (object->getOwnPropertySlot(exec, propertyName, slot))
536 return true;
ba379fdc 537 JSValue prototype = object->prototype();
9dae56ea
A
538 if (!prototype.isObject())
539 return false;
540 object = asObject(prototype);
541 }
542}
543
ba379fdc 544inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const
9dae56ea
A
545{
546 PropertySlot slot(this);
547 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
548 return slot.getValue(exec, propertyName);
549
550 return jsUndefined();
551}
552
ba379fdc 553inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
9dae56ea
A
554{
555 PropertySlot slot(this);
556 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
557 return slot.getValue(exec, propertyName);
558
559 return jsUndefined();
560}
561
14957cd0 562inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
9dae56ea 563{
ba379fdc 564 ASSERT(value);
9dae56ea
A
565 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
566
567 if (m_structure->isDictionary()) {
568 unsigned currentAttributes;
ba379fdc 569 JSCell* currentSpecificFunction;
14957cd0 570 size_t offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
9dae56ea 571 if (offset != WTF::notFound) {
4e4e5a6f
A
572 // If there is currently a specific function, and there now either isn't,
573 // or the new value is different, then despecify.
ba379fdc 574 if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
14957cd0 575 m_structure->despecifyDictionaryFunction(globalData, propertyName);
9dae56ea 576 if (checkReadOnly && currentAttributes & ReadOnly)
14957cd0
A
577 return false;
578
579 putDirectOffset(globalData, offset, value);
4e4e5a6f
A
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))
ba379fdc 587 slot.setExistingProperty(this, offset);
14957cd0 588 return true;
9dae56ea
A
589 }
590
14957cd0
A
591 if (checkReadOnly && !isExtensible())
592 return false;
593
9dae56ea 594 size_t currentCapacity = m_structure->propertyStorageCapacity();
14957cd0 595 offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
9dae56ea
A
596 if (currentCapacity != m_structure->propertyStorageCapacity())
597 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
598
599 ASSERT(offset < m_structure->propertyStorageCapacity());
14957cd0 600 putDirectOffset(globalData, offset, value);
ba379fdc
A
601 // See comment on setNewProperty call below.
602 if (!specificFunction)
603 slot.setNewProperty(this, offset);
14957cd0 604 return true;
9dae56ea
A
605 }
606
607 size_t offset;
608 size_t currentCapacity = m_structure->propertyStorageCapacity();
14957cd0 609 if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(m_structure.get(), propertyName, attributes, specificFunction, offset)) {
9dae56ea
A
610 if (currentCapacity != structure->propertyStorageCapacity())
611 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
612
613 ASSERT(offset < structure->propertyStorageCapacity());
14957cd0
A
614 setStructure(globalData, structure);
615 putDirectOffset(globalData, offset, value);
4e4e5a6f
A
616 // This is a new property; transitions with specific values are not currently cachable,
617 // so leave the slot in an uncachable state.
ba379fdc
A
618 if (!specificFunction)
619 slot.setNewProperty(this, offset);
14957cd0 620 return true;
9dae56ea
A
621 }
622
623 unsigned currentAttributes;
ba379fdc 624 JSCell* currentSpecificFunction;
14957cd0 625 offset = m_structure->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
9dae56ea
A
626 if (offset != WTF::notFound) {
627 if (checkReadOnly && currentAttributes & ReadOnly)
14957cd0 628 return false;
ba379fdc 629
4e4e5a6f
A
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) {
14957cd0
A
642 putDirectOffset(globalData, offset, value);
643 return true;
4e4e5a6f
A
644 }
645 // case (2) Despecify, fall through to (3).
14957cd0 646 setStructure(globalData, Structure::despecifyFunctionTransition(globalData, m_structure.get(), propertyName));
ba379fdc 647 }
4e4e5a6f
A
648
649 // case (3) set the slot, do the put, return.
9dae56ea 650 slot.setExistingProperty(this, offset);
14957cd0
A
651 putDirectOffset(globalData, offset, value);
652 return true;
9dae56ea
A
653 }
654
14957cd0
A
655 if (checkReadOnly && !isExtensible())
656 return false;
ba379fdc 657
14957cd0 658 Structure* structure = Structure::addPropertyTransition(globalData, m_structure.get(), propertyName, attributes, specificFunction, offset);
ba379fdc 659
9dae56ea
A
660 if (currentCapacity != structure->propertyStorageCapacity())
661 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
662
663 ASSERT(offset < structure->propertyStorageCapacity());
14957cd0
A
664 setStructure(globalData, structure);
665 putDirectOffset(globalData, offset, value);
4e4e5a6f
A
666 // This is a new property; transitions with specific values are not currently cachable,
667 // so leave the slot in an uncachable state.
ba379fdc
A
668 if (!specificFunction)
669 slot.setNewProperty(this, offset);
14957cd0 670 return true;
ba379fdc
A
671}
672
14957cd0 673inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
ba379fdc
A
674{
675 ASSERT(value);
676 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
677
14957cd0 678 return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
9dae56ea
A
679}
680
ba379fdc
A
681inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
682{
683 PutPropertySlot slot;
14957cd0 684 putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
ba379fdc
A
685}
686
14957cd0 687inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
ba379fdc
A
688{
689 ASSERT(value);
690 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
691
14957cd0 692 return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, 0);
ba379fdc
A
693}
694
14957cd0 695inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
ba379fdc
A
696{
697 PutPropertySlot slot;
14957cd0 698 putDirectInternal(globalData, propertyName, value, attributes, false, slot, 0);
ba379fdc
A
699}
700
14957cd0 701inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
4e4e5a6f 702{
14957cd0 703 return putDirectInternal(globalData, propertyName, value, 0, false, slot, 0);
4e4e5a6f
A
704}
705
14957cd0 706inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
ba379fdc 707{
14957cd0 708 putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, value);
ba379fdc
A
709}
710
14957cd0 711inline void JSObject::putDirectFunction(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attr)
ba379fdc
A
712{
713 PutPropertySlot slot;
14957cd0 714 putDirectInternal(globalData, propertyName, value, attr, false, slot, value);
ba379fdc
A
715}
716
14957cd0 717inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
ba379fdc
A
718{
719 size_t currentCapacity = m_structure->propertyStorageCapacity();
14957cd0 720 size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, 0);
ba379fdc
A
721 if (currentCapacity != m_structure->propertyStorageCapacity())
722 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
14957cd0 723 putDirectOffset(globalData, offset, value);
ba379fdc
A
724}
725
14957cd0 726inline void JSObject::putDirectFunctionWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSCell* value, unsigned attributes)
9dae56ea
A
727{
728 size_t currentCapacity = m_structure->propertyStorageCapacity();
14957cd0 729 size_t offset = m_structure->addPropertyWithoutTransition(globalData, propertyName, attributes, value);
9dae56ea
A
730 if (currentCapacity != m_structure->propertyStorageCapacity())
731 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
14957cd0 732 putDirectOffset(globalData, offset, value);
9dae56ea
A
733}
734
14957cd0 735inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
9dae56ea
A
736{
737 if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
738 allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
14957cd0 739 setStructure(globalData, newStructure);
9dae56ea
A
740}
741
ba379fdc 742inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
9dae56ea
A
743{
744 return defaultValue(exec, preferredType);
745}
746
ba379fdc 747inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
9dae56ea
A
748{
749 PropertySlot slot(asValue());
750 return get(exec, propertyName, slot);
751}
752
ba379fdc 753inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
9dae56ea
A
754{
755 if (UNLIKELY(!isCell())) {
ba379fdc
A
756 JSObject* prototype = synthesizePrototype(exec);
757 if (propertyName == exec->propertyNames().underscoreProto)
758 return prototype;
9dae56ea
A
759 if (!prototype->getPropertySlot(exec, propertyName, slot))
760 return jsUndefined();
761 return slot.getValue(exec, propertyName);
762 }
763 JSCell* cell = asCell();
764 while (true) {
765 if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
766 return slot.getValue(exec, propertyName);
f9bf01c6 767 JSValue prototype = asObject(cell)->prototype();
9dae56ea
A
768 if (!prototype.isObject())
769 return jsUndefined();
770 cell = asObject(prototype);
771 }
772}
773
ba379fdc 774inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
9dae56ea
A
775{
776 PropertySlot slot(asValue());
777 return get(exec, propertyName, slot);
778}
779
ba379fdc 780inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
9dae56ea
A
781{
782 if (UNLIKELY(!isCell())) {
ba379fdc 783 JSObject* prototype = synthesizePrototype(exec);
9dae56ea
A
784 if (!prototype->getPropertySlot(exec, propertyName, slot))
785 return jsUndefined();
786 return slot.getValue(exec, propertyName);
787 }
788 JSCell* cell = const_cast<JSCell*>(asCell());
789 while (true) {
790 if (cell->getOwnPropertySlot(exec, propertyName, slot))
791 return slot.getValue(exec, propertyName);
f9bf01c6 792 JSValue prototype = asObject(cell)->prototype();
9dae56ea
A
793 if (!prototype.isObject())
794 return jsUndefined();
795 cell = prototype.asCell();
796 }
797}
798
ba379fdc 799inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
9dae56ea
A
800{
801 if (UNLIKELY(!isCell())) {
ba379fdc 802 synthesizeObject(exec)->put(exec, propertyName, value, slot);
9dae56ea
A
803 return;
804 }
805 asCell()->put(exec, propertyName, value, slot);
806}
807
14957cd0 808inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
4e4e5a6f
A
809{
810 ASSERT(isCell() && isObject());
14957cd0
A
811 if (!asObject(asCell())->putDirect(exec->globalData(), propertyName, value, slot) && slot.isStrictMode())
812 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
4e4e5a6f
A
813}
814
ba379fdc 815inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
9dae56ea
A
816{
817 if (UNLIKELY(!isCell())) {
ba379fdc 818 synthesizeObject(exec)->put(exec, propertyName, value);
9dae56ea
A
819 return;
820 }
821 asCell()->put(exec, propertyName, value);
822}
823
14957cd0 824ALWAYS_INLINE void JSObject::visitChildrenDirect(SlotVisitor& visitor)
f9bf01c6 825{
14957cd0 826 JSCell::visitChildren(visitor);
f9bf01c6 827
f9bf01c6
A
828 PropertyStorage storage = propertyStorage();
829 size_t storageSize = m_structure->propertyStorageSize();
14957cd0
A
830 visitor.appendValues(storage, storageSize);
831 if (m_inheritorID)
832 visitor.append(&m_inheritorID);
f9bf01c6
A
833}
834
4e4e5a6f
A
835// --- JSValue inlines ----------------------------
836
837ALWAYS_INLINE UString JSValue::toThisString(ExecState* exec) const
838{
839 return isString() ? static_cast<JSString*>(asCell())->value(exec) : toThisObject(exec)->toString(exec);
840}
841
842inline JSString* JSValue::toThisJSString(ExecState* exec) const
843{
844 return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec));
845}
846
14957cd0
A
847inline JSValue JSValue::toStrictThisObject(ExecState* exec) const
848{
849 if (!isObject())
850 return *this;
851 return asObject(asCell())->toStrictThisObject(exec);
852}
853
854ALWAYS_INLINE JSObject* Register::function() const
855{
856 if (!jsValue())
857 return 0;
858 return asObject(jsValue());
859}
860
861ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
862{
863 Register r;
864 r = JSValue(callee);
865 return r;
866}
867
9dae56ea
A
868} // namespace JSC
869
870#endif // JSObject_h