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