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