source: webkit/trunk/JavaScriptCore/runtime/JSObject.h@ 48048

Last change on this file since 48048 was 47780, checked in by [email protected], 16 years ago

[ES5] Implement getOwnPropertyDescriptor
https://bugs.webkit.org/show_bug.cgi?id=28724

Reviewed by Gavin Barraclough.

JavaScriptCore:
Implement the core runtime support for getOwnPropertyDescriptor.
This adds a virtual getOwnPropertyDescriptor method to every class
that implements getOwnPropertySlot that shadows the behaviour of
getOwnPropertySlot. The alternative would be to make getOwnPropertySlot
(or PropertySlots in general) provide property attribute information,
but quick testing showed this to be a regression.

WebCore:
Implement the WebCore side of getOwnPropertyDescriptor. This
requires a custom implementation of getOwnPropertyDescriptor
for every class with a custom implementation of getOwnPropertySlot.

The bindings generator has been updated to generate appropriate
versions of getOwnPropertyDescriptor for the general case where
a custom getOwnPropertyDescriptor is not needed. ES5 is vague
about how getOwnPropertyDescriptor should work in the context of
"host" functions with polymorphic GetOwnProperty, so it seems
okay that occasionally we "guess" what attributes -- eg. determining
whether a property is writable.

Test: fast/js/getOwnPropertyDescriptor.html

  • Property svn:eol-style set to native
File size: 26.4 KB
Line 
1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
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
40namespace 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
127 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
128 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
129 virtual bool toBoolean(ExecState*) const;
130 virtual double toNumber(ExecState*) const;
131 virtual UString toString(ExecState*) const;
132 virtual JSObject* toObject(ExecState*) const;
133
134 virtual JSObject* toThisObject(ExecState*) const;
135 virtual JSObject* unwrappedObject();
136
137 virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const;
138 bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
139
140 // This get function only looks at the property map.
141 JSValue getDirect(const Identifier& propertyName) const
142 {
143 size_t offset = m_structure->get(propertyName);
144 return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
145 }
146
147 JSValue* getDirectLocation(const Identifier& propertyName)
148 {
149 size_t offset = m_structure->get(propertyName);
150 return offset != WTF::notFound ? locationForOffset(offset) : 0;
151 }
152
153 JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
154 {
155 JSCell* specificFunction;
156 size_t offset = m_structure->get(propertyName, attributes, specificFunction);
157 return offset != WTF::notFound ? locationForOffset(offset) : 0;
158 }
159
160 size_t offsetForLocation(JSValue* location) const
161 {
162 return location - reinterpret_cast<const JSValue*>(propertyStorage());
163 }
164
165 void transitionTo(Structure*);
166
167 void removeDirect(const Identifier& propertyName);
168 bool hasCustomProperties() { return !m_structure->isEmpty(); }
169 bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
170
171 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
172 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
173
174 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
175 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
176 void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
177
178 void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
179 void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
180 void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
181
182 // Fast access to known property offsets.
183 JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
184 void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }
185
186 void fillGetterPropertySlot(PropertySlot&, JSValue* location);
187
188 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction);
189 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction);
190 virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
191 virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
192
193 virtual bool isGlobalObject() const { return false; }
194 virtual bool isVariableObject() const { return false; }
195 virtual bool isActivationObject() const { return false; }
196 virtual bool isWatchdogException() const { return false; }
197 virtual bool isNotAnObjectErrorStub() const { return false; }
198
199 void allocatePropertyStorage(size_t oldSize, size_t newSize);
200 void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
201 bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
202
203 static const size_t inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
204 static const size_t nonInlineBaseStorageCapacity = 16;
205
206 static PassRefPtr<Structure> createStructure(JSValue prototype)
207 {
208 return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot | HasDefaultMark));
209 }
210
211 private:
212 // Nobody should ever ask any of these questions on something already known to be a JSObject.
213 using JSCell::isAPIValueWrapper;
214 using JSCell::isGetterSetter;
215 using JSCell::toObject;
216 void getObject();
217 void getString();
218 void isObject();
219 void isString();
220#if USE(JSVALUE32)
221 void isNumber();
222#endif
223
224 ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
225 PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
226
227 const JSValue* locationForOffset(size_t offset) const
228 {
229 return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]);
230 }
231
232 JSValue* locationForOffset(size_t offset)
233 {
234 return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
235 }
236
237 void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
238 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
239 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
240
241 bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
242
243 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
244 Structure* createInheritorID();
245
246 union {
247 PropertyStorage m_externalStorage;
248 EncodedJSValue m_inlineStorage[inlineStorageCapacity];
249 };
250
251 RefPtr<Structure> m_inheritorID;
252 };
253
254JSObject* constructEmptyObject(ExecState*);
255
256inline JSObject* asObject(JSValue value)
257{
258 ASSERT(asCell(value)->isObject());
259 return static_cast<JSObject*>(asCell(value));
260}
261
262inline JSObject::JSObject(PassRefPtr<Structure> structure)
263 : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
264{
265 ASSERT(m_structure);
266 ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
267 ASSERT(m_structure->isEmpty());
268 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
269#if USE(JSVALUE64) || USE(JSVALUE32_64)
270 ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
271#endif
272}
273
274inline JSObject::~JSObject()
275{
276 ASSERT(m_structure);
277 if (!isUsingInlineStorage())
278 delete [] m_externalStorage;
279 m_structure->deref();
280}
281
282inline JSValue JSObject::prototype() const
283{
284 return m_structure->storedPrototype();
285}
286
287inline void JSObject::setPrototype(JSValue prototype)
288{
289 ASSERT(prototype);
290 RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype);
291 setStructure(newStructure.release());
292}
293
294inline void JSObject::setStructure(PassRefPtr<Structure> structure)
295{
296 m_structure->deref();
297 m_structure = structure.releaseRef(); // ~JSObject balances this ref()
298}
299
300inline Structure* JSObject::inheritorID()
301{
302 if (m_inheritorID)
303 return m_inheritorID.get();
304 return createInheritorID();
305}
306
307inline bool Structure::isUsingInlineStorage() const
308{
309 return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
310}
311
312inline bool JSCell::inherits(const ClassInfo* info) const
313{
314 for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
315 if (ci == info)
316 return true;
317 }
318 return false;
319}
320
321// this method is here to be after the inline declaration of JSCell::inherits
322inline bool JSValue::inherits(const ClassInfo* classInfo) const
323{
324 return isCell() && asCell()->inherits(classInfo);
325}
326
327ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
328{
329 if (JSValue* location = getDirectLocation(propertyName)) {
330 if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter())
331 fillGetterPropertySlot(slot, location);
332 else
333 slot.setValueSlot(this, location, offsetForLocation(location));
334 return true;
335 }
336
337 // non-standard Netscape extension
338 if (propertyName == exec->propertyNames().underscoreProto) {
339 slot.setValue(prototype());
340 return true;
341 }
342
343 return false;
344}
345
346// It may seem crazy to inline a function this large, especially a virtual function,
347// but it makes a big difference to property lookup that derived classes can inline their
348// base class call to this.
349ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
350{
351 return inlineGetOwnPropertySlot(exec, propertyName, slot);
352}
353
354ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
355{
356 if (structure()->typeInfo().hasStandardGetOwnPropertySlot())
357 return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
358 return getOwnPropertySlot(exec, propertyName, slot);
359}
360
361// It may seem crazy to inline a function this large but it makes a big difference
362// since this is function very hot in variable lookup
363inline bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
364{
365 JSObject* object = this;
366 while (true) {
367 if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
368 return true;
369 JSValue prototype = object->prototype();
370 if (!prototype.isObject())
371 return false;
372 object = asObject(prototype);
373 }
374}
375
376inline bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
377{
378 JSObject* object = this;
379 while (true) {
380 if (object->getOwnPropertySlot(exec, propertyName, slot))
381 return true;
382 JSValue prototype = object->prototype();
383 if (!prototype.isObject())
384 return false;
385 object = asObject(prototype);
386 }
387}
388
389inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const
390{
391 PropertySlot slot(this);
392 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
393 return slot.getValue(exec, propertyName);
394
395 return jsUndefined();
396}
397
398inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
399{
400 PropertySlot slot(this);
401 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
402 return slot.getValue(exec, propertyName);
403
404 return jsUndefined();
405}
406
407inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
408{
409 ASSERT(value);
410 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
411
412 if (m_structure->isDictionary()) {
413 unsigned currentAttributes;
414 JSCell* currentSpecificFunction;
415 size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
416 if (offset != WTF::notFound) {
417 if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
418 m_structure->despecifyDictionaryFunction(propertyName);
419 if (checkReadOnly && currentAttributes & ReadOnly)
420 return;
421 putDirectOffset(offset, value);
422 if (!specificFunction && !currentSpecificFunction)
423 slot.setExistingProperty(this, offset);
424 return;
425 }
426
427 size_t currentCapacity = m_structure->propertyStorageCapacity();
428 offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
429 if (currentCapacity != m_structure->propertyStorageCapacity())
430 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
431
432 ASSERT(offset < m_structure->propertyStorageCapacity());
433 putDirectOffset(offset, value);
434 // See comment on setNewProperty call below.
435 if (!specificFunction)
436 slot.setNewProperty(this, offset);
437 return;
438 }
439
440 size_t offset;
441 size_t currentCapacity = m_structure->propertyStorageCapacity();
442 if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) {
443 if (currentCapacity != structure->propertyStorageCapacity())
444 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
445
446 ASSERT(offset < structure->propertyStorageCapacity());
447 setStructure(structure.release());
448 putDirectOffset(offset, value);
449 // See comment on setNewProperty call below.
450 if (!specificFunction)
451 slot.setNewProperty(this, offset);
452 return;
453 }
454
455 unsigned currentAttributes;
456 JSCell* currentSpecificFunction;
457 offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
458 if (offset != WTF::notFound) {
459 if (checkReadOnly && currentAttributes & ReadOnly)
460 return;
461
462 if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) {
463 setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
464 putDirectOffset(offset, value);
465 // Function transitions are not currently cachable, so leave the slot in an uncachable state.
466 return;
467 }
468 putDirectOffset(offset, value);
469 slot.setExistingProperty(this, offset);
470 return;
471 }
472
473 // If we have a specific function, we may have got to this point if there is
474 // already a transition with the correct property name and attributes, but
475 // specialized to a different function. In this case we just want to give up
476 // and despecialize the transition.
477 // In this case we clear the value of specificFunction which will result
478 // in us adding a non-specific transition, and any subsequent lookup in
479 // Structure::addPropertyTransitionToExistingStructure will just use that.
480 if (specificFunction && m_structure->hasTransition(propertyName, attributes))
481 specificFunction = 0;
482
483 RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
484
485 if (currentCapacity != structure->propertyStorageCapacity())
486 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
487
488 ASSERT(offset < structure->propertyStorageCapacity());
489 setStructure(structure.release());
490 putDirectOffset(offset, value);
491 // Function transitions are not currently cachable, so leave the slot in an uncachable state.
492 if (!specificFunction)
493 slot.setNewProperty(this, offset);
494}
495
496inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
497{
498 ASSERT(value);
499 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
500
501 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
502}
503
504inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
505{
506 PutPropertySlot slot;
507 putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
508}
509
510inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
511{
512 ASSERT(value);
513 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
514
515 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
516}
517
518inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
519{
520 PutPropertySlot slot;
521 putDirectInternal(propertyName, value, attributes, false, slot, 0);
522}
523
524inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
525{
526 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
527}
528
529inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
530{
531 PutPropertySlot slot;
532 putDirectInternal(propertyName, value, attr, false, slot, value);
533}
534
535inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes)
536{
537 size_t currentCapacity = m_structure->propertyStorageCapacity();
538 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0);
539 if (currentCapacity != m_structure->propertyStorageCapacity())
540 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
541 putDirectOffset(offset, value);
542}
543
544inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
545{
546 size_t currentCapacity = m_structure->propertyStorageCapacity();
547 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value);
548 if (currentCapacity != m_structure->propertyStorageCapacity())
549 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
550 putDirectOffset(offset, value);
551}
552
553inline void JSObject::transitionTo(Structure* newStructure)
554{
555 if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
556 allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
557 setStructure(newStructure);
558}
559
560inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
561{
562 return defaultValue(exec, preferredType);
563}
564
565inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
566{
567 PropertySlot slot(asValue());
568 return get(exec, propertyName, slot);
569}
570
571inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
572{
573 if (UNLIKELY(!isCell())) {
574 JSObject* prototype = synthesizePrototype(exec);
575 if (propertyName == exec->propertyNames().underscoreProto)
576 return prototype;
577 if (!prototype->getPropertySlot(exec, propertyName, slot))
578 return jsUndefined();
579 return slot.getValue(exec, propertyName);
580 }
581 JSCell* cell = asCell();
582 while (true) {
583 if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
584 return slot.getValue(exec, propertyName);
585 ASSERT(cell->isObject());
586 JSValue prototype = static_cast<JSObject*>(cell)->prototype();
587 if (!prototype.isObject())
588 return jsUndefined();
589 cell = asObject(prototype);
590 }
591}
592
593inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
594{
595 PropertySlot slot(asValue());
596 return get(exec, propertyName, slot);
597}
598
599inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
600{
601 if (UNLIKELY(!isCell())) {
602 JSObject* prototype = synthesizePrototype(exec);
603 if (!prototype->getPropertySlot(exec, propertyName, slot))
604 return jsUndefined();
605 return slot.getValue(exec, propertyName);
606 }
607 JSCell* cell = const_cast<JSCell*>(asCell());
608 while (true) {
609 if (cell->getOwnPropertySlot(exec, propertyName, slot))
610 return slot.getValue(exec, propertyName);
611 ASSERT(cell->isObject());
612 JSValue prototype = static_cast<JSObject*>(cell)->prototype();
613 if (!prototype.isObject())
614 return jsUndefined();
615 cell = prototype.asCell();
616 }
617}
618
619inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
620{
621 if (UNLIKELY(!isCell())) {
622 synthesizeObject(exec)->put(exec, propertyName, value, slot);
623 return;
624 }
625 asCell()->put(exec, propertyName, value, slot);
626}
627
628inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
629{
630 if (UNLIKELY(!isCell())) {
631 synthesizeObject(exec)->put(exec, propertyName, value);
632 return;
633 }
634 asCell()->put(exec, propertyName, value);
635}
636
637ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
638{
639 ASSERT(newSize > oldSize);
640
641 // It's important that this function not rely on m_structure, since
642 // we might be in the middle of a transition.
643 bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
644
645 PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
646 PropertyStorage newPropertyStorage = new EncodedJSValue[newSize];
647
648 for (unsigned i = 0; i < oldSize; ++i)
649 newPropertyStorage[i] = oldPropertyStorage[i];
650
651 if (!wasInline)
652 delete [] oldPropertyStorage;
653
654 m_externalStorage = newPropertyStorage;
655}
656
657ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
658{
659 JSCell::markChildren(markStack);
660 m_structure->markAggregate(markStack);
661
662 PropertyStorage storage = propertyStorage();
663 size_t storageSize = m_structure->propertyStorageSize();
664 markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
665}
666
667} // namespace JSC
668
669#endif // JSObject_h
Note: See TracBrowser for help on using the repository browser.