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