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, 2012 Apple Inc. All rights reserved.
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.
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.
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.
27 #include "ArrayConventions.h"
28 #include "ArrayStorage.h"
29 #include "Butterfly.h"
30 #include "ClassInfo.h"
31 #include "CommonIdentifiers.h"
32 #include "CallFrame.h"
34 #include "PropertySlot.h"
35 #include "PropertyStorage.h"
36 #include "PutDirectIndexMode.h"
37 #include "PutPropertySlot.h"
39 #include "Structure.h"
42 #include "SlotVisitorInlines.h"
43 #include "SparseArrayValueMap.h"
44 #include <wtf/StdLibExtras.h>
48 inline JSCell
* getJSFunction(JSValue value
)
50 if (value
.isCell() && (value
.asCell()->structure()->typeInfo().type() == JSFunctionType
))
51 return value
.asCell();
55 JS_EXPORT_PRIVATE JSCell
* getCallableObjectSlow(JSCell
*);
57 inline JSCell
* getCallableObject(JSValue value
)
61 return getCallableObjectSlow(value
.asCell());
66 class InternalFunction
;
67 class LLIntOffsetsExtractor
;
69 class PropertyDescriptor
;
70 class PropertyNameArray
;
74 JS_EXPORT_PRIVATE JSObject
* throwTypeError(ExecState
*, const String
&);
75 extern JS_EXPORTDATA
const char* StrictModeReadonlyPropertyWriteError
;
78 // Property attributes
81 ReadOnly
= 1 << 1, // property can be only read, not written
82 DontEnum
= 1 << 2, // property doesn't appear in (for .. in ..)
83 DontDelete
= 1 << 3, // property can't be deleted
84 Function
= 1 << 4, // property is a function - only used by static hashtables
85 Accessor
= 1 << 5, // property is a getter/setter
88 COMPILE_ASSERT(None
< FirstInternalAttribute
, None_is_below_FirstInternalAttribute
);
89 COMPILE_ASSERT(ReadOnly
< FirstInternalAttribute
, ReadOnly_is_below_FirstInternalAttribute
);
90 COMPILE_ASSERT(DontEnum
< FirstInternalAttribute
, DontEnum_is_below_FirstInternalAttribute
);
91 COMPILE_ASSERT(DontDelete
< FirstInternalAttribute
, DontDelete_is_below_FirstInternalAttribute
);
92 COMPILE_ASSERT(Function
< FirstInternalAttribute
, Function_is_below_FirstInternalAttribute
);
93 COMPILE_ASSERT(Accessor
< FirstInternalAttribute
, Accessor_is_below_FirstInternalAttribute
);
97 class JSObject
: public JSCell
{
98 friend class BatchedTransitionOptimizer
;
101 friend class JSFinalObject
;
102 friend class MarkedBlock
;
103 JS_EXPORT_PRIVATE
friend bool setUpStaticFunctionSlot(ExecState
*, const HashEntry
*, JSObject
*, PropertyName
, PropertySlot
&);
107 PutModeDefineOwnProperty
,
113 static size_t allocationSize(size_t inlineCapacity
)
115 return sizeof(JSObject
) + inlineCapacity
* sizeof(WriteBarrierBase
<Unknown
>);
118 JS_EXPORT_PRIVATE
static void visitChildren(JSCell
*, SlotVisitor
&);
119 JS_EXPORT_PRIVATE
static void copyBackingStore(JSCell
*, CopyVisitor
&);
121 JS_EXPORT_PRIVATE
static String
className(const JSObject
*);
123 JSValue
prototype() const;
124 void setPrototype(VM
&, JSValue prototype
);
125 bool setPrototypeWithCycleCheck(VM
&, JSValue prototype
);
127 bool mayInterceptIndexedAccesses()
129 return structure()->mayInterceptIndexedAccesses();
132 JSValue
get(ExecState
*, PropertyName
) const;
133 JSValue
get(ExecState
*, unsigned propertyName
) const;
135 bool getPropertySlot(ExecState
*, PropertyName
, PropertySlot
&);
136 bool getPropertySlot(ExecState
*, unsigned propertyName
, PropertySlot
&);
137 JS_EXPORT_PRIVATE
bool getPropertyDescriptor(ExecState
*, PropertyName
, PropertyDescriptor
&);
139 static bool getOwnPropertySlot(JSCell
*, ExecState
*, PropertyName
, PropertySlot
&);
140 JS_EXPORT_PRIVATE
static bool getOwnPropertySlotByIndex(JSCell
*, ExecState
*, unsigned propertyName
, PropertySlot
&);
141 JS_EXPORT_PRIVATE
static bool getOwnPropertyDescriptor(JSObject
*, ExecState
*, PropertyName
, PropertyDescriptor
&);
143 bool allowsAccessFrom(ExecState
*);
145 unsigned getArrayLength() const
147 if (!hasIndexedProperties(structure()->indexingType()))
149 return m_butterfly
->publicLength();
152 unsigned getVectorLength()
154 if (!hasIndexedProperties(structure()->indexingType()))
156 return m_butterfly
->vectorLength();
159 JS_EXPORT_PRIVATE
static void put(JSCell
*, ExecState
*, PropertyName
, JSValue
, PutPropertySlot
&);
160 JS_EXPORT_PRIVATE
static void putByIndex(JSCell
*, ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
162 void putByIndexInline(ExecState
* exec
, unsigned propertyName
, JSValue value
, bool shouldThrow
)
164 if (canSetIndexQuickly(propertyName
)) {
165 setIndexQuickly(exec
->vm(), propertyName
, value
);
168 methodTable()->putByIndex(this, exec
, propertyName
, value
, shouldThrow
);
171 // This is similar to the putDirect* methods:
172 // - the prototype chain is not consulted
173 // - accessors are not called.
174 // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).
175 // This method creates a property with attributes writable, enumerable and configurable all set to true.
176 bool putDirectIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
, unsigned attributes
, PutDirectIndexMode mode
)
178 if (!attributes
&& canSetIndexQuicklyForPutDirect(propertyName
)) {
179 setIndexQuickly(exec
->vm(), propertyName
, value
);
182 return putDirectIndexBeyondVectorLength(exec
, propertyName
, value
, attributes
, mode
);
184 bool putDirectIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
)
186 return putDirectIndex(exec
, propertyName
, value
, 0, PutDirectIndexLikePutDirect
);
189 // A non-throwing version of putDirect and putDirectIndex.
190 JS_EXPORT_PRIVATE
void putDirectMayBeIndex(ExecState
*, PropertyName
, JSValue
);
192 bool canGetIndexQuickly(unsigned i
)
194 switch (structure()->indexingType()) {
195 case ALL_BLANK_INDEXING_TYPES
:
196 case ALL_UNDECIDED_INDEXING_TYPES
:
198 case ALL_INT32_INDEXING_TYPES
:
199 case ALL_CONTIGUOUS_INDEXING_TYPES
:
200 return i
< m_butterfly
->vectorLength() && m_butterfly
->contiguous()[i
];
201 case ALL_DOUBLE_INDEXING_TYPES
: {
202 if (i
>= m_butterfly
->vectorLength())
204 double value
= m_butterfly
->contiguousDouble()[i
];
209 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
210 return i
< m_butterfly
->arrayStorage()->vectorLength() && m_butterfly
->arrayStorage()->m_vector
[i
];
212 RELEASE_ASSERT_NOT_REACHED();
217 JSValue
getIndexQuickly(unsigned i
)
219 switch (structure()->indexingType()) {
220 case ALL_INT32_INDEXING_TYPES
:
221 case ALL_CONTIGUOUS_INDEXING_TYPES
:
222 return m_butterfly
->contiguous()[i
].get();
223 case ALL_DOUBLE_INDEXING_TYPES
:
224 return JSValue(JSValue::EncodeAsDouble
, m_butterfly
->contiguousDouble()[i
]);
225 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
226 return m_butterfly
->arrayStorage()->m_vector
[i
].get();
228 RELEASE_ASSERT_NOT_REACHED();
233 JSValue
tryGetIndexQuickly(unsigned i
)
235 switch (structure()->indexingType()) {
236 case ALL_BLANK_INDEXING_TYPES
:
237 case ALL_UNDECIDED_INDEXING_TYPES
:
239 case ALL_INT32_INDEXING_TYPES
:
240 case ALL_CONTIGUOUS_INDEXING_TYPES
:
241 if (i
< m_butterfly
->publicLength())
242 return m_butterfly
->contiguous()[i
].get();
244 case ALL_DOUBLE_INDEXING_TYPES
: {
245 if (i
>= m_butterfly
->publicLength())
247 double result
= m_butterfly
->contiguousDouble()[i
];
248 if (result
!= result
)
250 return JSValue(JSValue::EncodeAsDouble
, result
);
252 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
253 if (i
< m_butterfly
->arrayStorage()->vectorLength())
254 return m_butterfly
->arrayStorage()->m_vector
[i
].get();
257 RELEASE_ASSERT_NOT_REACHED();
263 JSValue
getDirectIndex(ExecState
* exec
, unsigned i
)
265 if (JSValue result
= tryGetIndexQuickly(i
))
267 PropertySlot
slot(this);
268 if (methodTable()->getOwnPropertySlotByIndex(this, exec
, i
, slot
))
269 return slot
.getValue(exec
, i
);
273 JSValue
getIndex(ExecState
* exec
, unsigned i
)
275 if (JSValue result
= tryGetIndexQuickly(i
))
280 bool canSetIndexQuickly(unsigned i
)
282 switch (structure()->indexingType()) {
283 case ALL_BLANK_INDEXING_TYPES
:
284 case ALL_UNDECIDED_INDEXING_TYPES
:
286 case ALL_INT32_INDEXING_TYPES
:
287 case ALL_DOUBLE_INDEXING_TYPES
:
288 case ALL_CONTIGUOUS_INDEXING_TYPES
:
289 case NonArrayWithArrayStorage
:
290 case ArrayWithArrayStorage
:
291 return i
< m_butterfly
->vectorLength();
292 case NonArrayWithSlowPutArrayStorage
:
293 case ArrayWithSlowPutArrayStorage
:
294 return i
< m_butterfly
->arrayStorage()->vectorLength()
295 && !!m_butterfly
->arrayStorage()->m_vector
[i
];
297 RELEASE_ASSERT_NOT_REACHED();
302 bool canSetIndexQuicklyForPutDirect(unsigned i
)
304 switch (structure()->indexingType()) {
305 case ALL_BLANK_INDEXING_TYPES
:
306 case ALL_UNDECIDED_INDEXING_TYPES
:
308 case ALL_INT32_INDEXING_TYPES
:
309 case ALL_DOUBLE_INDEXING_TYPES
:
310 case ALL_CONTIGUOUS_INDEXING_TYPES
:
311 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
312 return i
< m_butterfly
->vectorLength();
314 RELEASE_ASSERT_NOT_REACHED();
319 void setIndexQuickly(VM
& vm
, unsigned i
, JSValue v
)
321 switch (structure()->indexingType()) {
322 case ALL_INT32_INDEXING_TYPES
: {
323 ASSERT(i
< m_butterfly
->vectorLength());
325 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm
, i
, v
);
328 // Fall through to contiguous case.
330 case ALL_CONTIGUOUS_INDEXING_TYPES
: {
331 ASSERT(i
< m_butterfly
->vectorLength());
332 m_butterfly
->contiguous()[i
].set(vm
, this, v
);
333 if (i
>= m_butterfly
->publicLength())
334 m_butterfly
->setPublicLength(i
+ 1);
337 case ALL_DOUBLE_INDEXING_TYPES
: {
338 ASSERT(i
< m_butterfly
->vectorLength());
340 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
343 double value
= v
.asNumber();
344 if (value
!= value
) {
345 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
348 m_butterfly
->contiguousDouble()[i
] = value
;
349 if (i
>= m_butterfly
->publicLength())
350 m_butterfly
->setPublicLength(i
+ 1);
353 case ALL_ARRAY_STORAGE_INDEXING_TYPES
: {
354 ArrayStorage
* storage
= m_butterfly
->arrayStorage();
355 WriteBarrier
<Unknown
>& x
= storage
->m_vector
[i
];
356 JSValue old
= x
.get();
359 ++storage
->m_numValuesInVector
;
360 if (i
>= storage
->length())
361 storage
->setLength(i
+ 1);
366 RELEASE_ASSERT_NOT_REACHED();
370 void initializeIndex(VM
& vm
, unsigned i
, JSValue v
)
372 switch (structure()->indexingType()) {
373 case ALL_UNDECIDED_INDEXING_TYPES
: {
374 setIndexQuicklyToUndecided(vm
, i
, v
);
377 case ALL_INT32_INDEXING_TYPES
: {
378 ASSERT(i
< m_butterfly
->publicLength());
379 ASSERT(i
< m_butterfly
->vectorLength());
381 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm
, i
, v
);
386 case ALL_CONTIGUOUS_INDEXING_TYPES
: {
387 ASSERT(i
< m_butterfly
->publicLength());
388 ASSERT(i
< m_butterfly
->vectorLength());
389 m_butterfly
->contiguous()[i
].set(vm
, this, v
);
392 case ALL_DOUBLE_INDEXING_TYPES
: {
393 ASSERT(i
< m_butterfly
->publicLength());
394 ASSERT(i
< m_butterfly
->vectorLength());
396 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
399 double value
= v
.asNumber();
400 if (value
!= value
) {
401 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
404 m_butterfly
->contiguousDouble()[i
] = value
;
407 case ALL_ARRAY_STORAGE_INDEXING_TYPES
: {
408 ArrayStorage
* storage
= m_butterfly
->arrayStorage();
409 ASSERT(i
< storage
->length());
410 ASSERT(i
< storage
->m_numValuesInVector
);
411 storage
->m_vector
[i
].set(vm
, this, v
);
415 RELEASE_ASSERT_NOT_REACHED();
421 switch (structure()->indexingType()) {
422 case ALL_BLANK_INDEXING_TYPES
:
423 case ALL_UNDECIDED_INDEXING_TYPES
:
424 case ALL_INT32_INDEXING_TYPES
:
425 case ALL_DOUBLE_INDEXING_TYPES
:
426 case ALL_CONTIGUOUS_INDEXING_TYPES
:
428 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
429 return m_butterfly
->arrayStorage()->m_sparseMap
;
431 RELEASE_ASSERT_NOT_REACHED();
436 bool inSparseIndexingMode()
438 switch (structure()->indexingType()) {
439 case ALL_BLANK_INDEXING_TYPES
:
440 case ALL_UNDECIDED_INDEXING_TYPES
:
441 case ALL_INT32_INDEXING_TYPES
:
442 case ALL_DOUBLE_INDEXING_TYPES
:
443 case ALL_CONTIGUOUS_INDEXING_TYPES
:
445 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
446 return m_butterfly
->arrayStorage()->inSparseMode();
448 RELEASE_ASSERT_NOT_REACHED();
453 void enterDictionaryIndexingMode(VM
&);
455 // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
456 // - the prototype chain is not consulted
457 // - accessors are not called.
458 // - attributes will be respected (after the call the property will exist with the given attributes)
459 // - the property name is assumed to not be an index.
460 JS_EXPORT_PRIVATE
static void putDirectVirtual(JSObject
*, ExecState
*, PropertyName
, JSValue
, unsigned attributes
);
461 void putDirect(VM
&, PropertyName
, JSValue
, unsigned attributes
= 0);
462 void putDirect(VM
&, PropertyName
, JSValue
, PutPropertySlot
&);
463 void putDirectWithoutTransition(VM
&, PropertyName
, JSValue
, unsigned attributes
= 0);
464 void putDirectAccessor(ExecState
*, PropertyName
, JSValue
, unsigned attributes
);
466 bool propertyIsEnumerable(ExecState
*, const Identifier
& propertyName
) const;
468 JS_EXPORT_PRIVATE
bool hasProperty(ExecState
*, PropertyName
) const;
469 JS_EXPORT_PRIVATE
bool hasProperty(ExecState
*, unsigned propertyName
) const;
470 bool hasOwnProperty(ExecState
*, PropertyName
) const;
472 JS_EXPORT_PRIVATE
static bool deleteProperty(JSCell
*, ExecState
*, PropertyName
);
473 JS_EXPORT_PRIVATE
static bool deletePropertyByIndex(JSCell
*, ExecState
*, unsigned propertyName
);
475 JS_EXPORT_PRIVATE
static JSValue
defaultValue(const JSObject
*, ExecState
*, PreferredPrimitiveType
);
477 bool hasInstance(ExecState
*, JSValue
);
478 static bool defaultHasInstance(ExecState
*, JSValue
, JSValue prototypeProperty
);
480 JS_EXPORT_PRIVATE
static void getOwnPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
481 JS_EXPORT_PRIVATE
static void getOwnNonIndexPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
482 JS_EXPORT_PRIVATE
static void getPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
484 JSValue
toPrimitive(ExecState
*, PreferredPrimitiveType
= NoPreference
) const;
485 bool getPrimitiveNumber(ExecState
*, double& number
, JSValue
&) const;
486 JS_EXPORT_PRIVATE
double toNumber(ExecState
*) const;
487 JS_EXPORT_PRIVATE JSString
* toString(ExecState
*) const;
489 // NOTE: JSObject and its subclasses must be able to gracefully handle ExecState* = 0,
490 // because this call may come from inside the compiler.
491 JS_EXPORT_PRIVATE
static JSObject
* toThisObject(JSCell
*, ExecState
*);
493 bool getPropertySpecificValue(ExecState
*, PropertyName
, JSCell
*& specificFunction
) const;
495 // This get function only looks at the property map.
496 JSValue
getDirect(VM
& vm
, PropertyName propertyName
) const
498 PropertyOffset offset
= structure()->get(vm
, propertyName
);
499 checkOffset(offset
, structure()->inlineCapacity());
500 return offset
!= invalidOffset
? getDirect(offset
) : JSValue();
503 PropertyOffset
getDirectOffset(VM
& vm
, PropertyName propertyName
)
505 PropertyOffset offset
= structure()->get(vm
, propertyName
);
506 checkOffset(offset
, structure()->inlineCapacity());
510 bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
511 ConstPropertyStorage
inlineStorageUnsafe() const
513 return bitwise_cast
<ConstPropertyStorage
>(this + 1);
515 PropertyStorage
inlineStorageUnsafe()
517 return bitwise_cast
<PropertyStorage
>(this + 1);
519 ConstPropertyStorage
inlineStorage() const
521 ASSERT(hasInlineStorage());
522 return inlineStorageUnsafe();
524 PropertyStorage
inlineStorage()
526 ASSERT(hasInlineStorage());
527 return inlineStorageUnsafe();
530 const Butterfly
* butterfly() const { return m_butterfly
; }
531 Butterfly
* butterfly() { return m_butterfly
; }
533 ConstPropertyStorage
outOfLineStorage() const { return m_butterfly
->propertyStorage(); }
534 PropertyStorage
outOfLineStorage() { return m_butterfly
->propertyStorage(); }
536 const WriteBarrierBase
<Unknown
>* locationForOffset(PropertyOffset offset
) const
538 if (isInlineOffset(offset
))
539 return &inlineStorage()[offsetInInlineStorage(offset
)];
540 return &outOfLineStorage()[offsetInOutOfLineStorage(offset
)];
543 WriteBarrierBase
<Unknown
>* locationForOffset(PropertyOffset offset
)
545 if (isInlineOffset(offset
))
546 return &inlineStorage()[offsetInInlineStorage(offset
)];
547 return &outOfLineStorage()[offsetInOutOfLineStorage(offset
)];
550 void transitionTo(VM
&, Structure
*);
552 bool removeDirect(VM
&, PropertyName
); // Return true if anything is removed.
553 bool hasCustomProperties() { return structure()->didTransition(); }
554 bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
556 // putOwnDataProperty has 'put' like semantics, however this method:
557 // - assumes the object contains no own getter/setter properties.
558 // - provides no special handling for __proto__
559 // - does not walk the prototype chain (to check for accessors or non-writable properties).
560 // This is used by JSActivation.
561 bool putOwnDataProperty(VM
&, PropertyName
, JSValue
, PutPropertySlot
&);
563 // Fast access to known property offsets.
564 JSValue
getDirect(PropertyOffset offset
) const { return locationForOffset(offset
)->get(); }
565 void putDirect(VM
& vm
, PropertyOffset offset
, JSValue value
) { locationForOffset(offset
)->set(vm
, this, value
); }
566 void putDirectUndefined(PropertyOffset offset
) { locationForOffset(offset
)->setUndefined(); }
568 void putDirectNativeFunction(ExecState
*, JSGlobalObject
*, const PropertyName
&, unsigned functionLength
, NativeFunction
, Intrinsic
, unsigned attributes
);
570 JS_EXPORT_PRIVATE
static bool defineOwnProperty(JSObject
*, ExecState
*, PropertyName
, PropertyDescriptor
&, bool shouldThrow
);
572 bool isGlobalObject() const;
573 bool isVariableObject() const;
574 bool isStaticScopeObject() const;
575 bool isNameScopeObject() const;
576 bool isActivationObject() const;
577 bool isErrorInstance() const;
581 JS_EXPORT_PRIVATE
void preventExtensions(VM
&);
582 bool isSealed(VM
& vm
) { return structure()->isSealed(vm
); }
583 bool isFrozen(VM
& vm
) { return structure()->isFrozen(vm
); }
584 bool isExtensible() { return structure()->isExtensible(); }
585 bool indexingShouldBeSparse()
587 return !isExtensible()
588 || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
591 bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
592 void reifyStaticFunctionsForDelete(ExecState
* exec
);
594 JS_EXPORT_PRIVATE Butterfly
* growOutOfLineStorage(VM
&, size_t oldSize
, size_t newSize
);
595 void setButterfly(VM
&, Butterfly
*, Structure
*);
596 void setButterflyWithoutChangingStructure(Butterfly
*); // You probably don't want to call this.
598 void setStructure(VM
&, Structure
*, Butterfly
* = 0);
599 void setStructureAndReallocateStorageIfNecessary(VM
&, unsigned oldCapacity
, Structure
*);
600 void setStructureAndReallocateStorageIfNecessary(VM
&, Structure
*);
602 void flattenDictionaryObject(VM
& vm
)
604 structure()->flattenDictionaryStructure(vm
, this);
607 JSGlobalObject
* globalObject() const
609 ASSERT(structure()->globalObject());
610 ASSERT(!isGlobalObject() || ((JSObject
*)structure()->globalObject()) == this);
611 return structure()->globalObject();
614 void switchToSlowPutArrayStorage(VM
&);
616 // The receiver is the prototype in this case. The following:
618 // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
622 // foo->attemptToInterceptPutByIndexOnHole(...);
623 bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState
*, JSValue thisValue
, unsigned propertyName
, JSValue
, bool shouldThrow
);
625 // Returns 0 if int32 storage cannot be created - either because
626 // indexing should be sparse, we're having a bad time, or because
627 // we already have a more general form of storage (double,
628 // contiguous, array storage).
629 ContiguousJSValues
ensureInt32(VM
& vm
)
631 if (LIKELY(hasInt32(structure()->indexingType())))
632 return m_butterfly
->contiguousInt32();
634 return ensureInt32Slow(vm
);
637 // Returns 0 if double storage cannot be created - either because
638 // indexing should be sparse, we're having a bad time, or because
639 // we already have a more general form of storage (contiguous,
640 // or array storage).
641 ContiguousDoubles
ensureDouble(VM
& vm
)
643 if (LIKELY(hasDouble(structure()->indexingType())))
644 return m_butterfly
->contiguousDouble();
646 return ensureDoubleSlow(vm
);
649 // Returns 0 if contiguous storage cannot be created - either because
650 // indexing should be sparse or because we're having a bad time.
651 ContiguousJSValues
ensureContiguous(VM
& vm
)
653 if (LIKELY(hasContiguous(structure()->indexingType())))
654 return m_butterfly
->contiguous();
656 return ensureContiguousSlow(vm
);
659 // Same as ensureContiguous(), except that if the indexed storage is in
660 // double mode, then it does a rage conversion to contiguous: it
661 // attempts to convert each double to an int32.
662 ContiguousJSValues
rageEnsureContiguous(VM
& vm
)
664 if (LIKELY(hasContiguous(structure()->indexingType())))
665 return m_butterfly
->contiguous();
667 return rageEnsureContiguousSlow(vm
);
670 // Ensure that the object is in a mode where it has array storage. Use
671 // this if you're about to perform actions that would have required the
672 // object to be converted to have array storage, if it didn't have it
674 ArrayStorage
* ensureArrayStorage(VM
& vm
)
676 if (LIKELY(hasArrayStorage(structure()->indexingType())))
677 return m_butterfly
->arrayStorage();
679 return ensureArrayStorageSlow(vm
);
682 static size_t offsetOfInlineStorage();
684 static ptrdiff_t butterflyOffset()
686 return OBJECT_OFFSETOF(JSObject
, m_butterfly
);
689 void* butterflyAddress()
694 static JS_EXPORTDATA
const ClassInfo s_info
;
697 void finishCreation(VM
& vm
)
699 Base::finishCreation(vm
);
700 ASSERT(inherits(&s_info
));
701 ASSERT(!structure()->outOfLineCapacity());
702 ASSERT(structure()->isEmpty());
703 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
704 ASSERT(structure()->isObject());
708 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
710 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), &s_info
);
713 // To instantiate objects you likely want JSFinalObject, below.
714 // To create derived types you likely want JSNonFinalObject, below.
715 JSObject(VM
&, Structure
*, Butterfly
* = 0);
717 void visitButterfly(SlotVisitor
&, Butterfly
*, size_t storageSize
);
718 void copyButterfly(CopyVisitor
&, Butterfly
*, size_t storageSize
);
720 // Call this if you know that the object is in a mode where it has array
721 // storage. This will assert otherwise.
722 ArrayStorage
* arrayStorage()
724 ASSERT(hasArrayStorage(structure()->indexingType()));
725 return m_butterfly
->arrayStorage();
728 // Call this if you want to predicate some actions on whether or not the
729 // object is in a mode where it has array storage.
730 ArrayStorage
* arrayStorageOrNull()
732 switch (structure()->indexingType()) {
733 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
734 return m_butterfly
->arrayStorage();
741 Butterfly
* createInitialUndecided(VM
&, unsigned length
);
742 ContiguousJSValues
createInitialInt32(VM
&, unsigned length
);
743 ContiguousDoubles
createInitialDouble(VM
&, unsigned length
);
744 ContiguousJSValues
createInitialContiguous(VM
&, unsigned length
);
746 void convertUndecidedForValue(VM
&, JSValue
);
747 void convertInt32ForValue(VM
&, JSValue
);
749 ArrayStorage
* createArrayStorage(VM
&, unsigned length
, unsigned vectorLength
);
750 ArrayStorage
* createInitialArrayStorage(VM
&);
752 ContiguousJSValues
convertUndecidedToInt32(VM
&);
753 ContiguousDoubles
convertUndecidedToDouble(VM
&);
754 ContiguousJSValues
convertUndecidedToContiguous(VM
&);
755 ArrayStorage
* convertUndecidedToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
756 ArrayStorage
* convertUndecidedToArrayStorage(VM
&, NonPropertyTransition
);
757 ArrayStorage
* convertUndecidedToArrayStorage(VM
&);
759 ContiguousDoubles
convertInt32ToDouble(VM
&);
760 ContiguousJSValues
convertInt32ToContiguous(VM
&);
761 ArrayStorage
* convertInt32ToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
762 ArrayStorage
* convertInt32ToArrayStorage(VM
&, NonPropertyTransition
);
763 ArrayStorage
* convertInt32ToArrayStorage(VM
&);
765 ContiguousJSValues
convertDoubleToContiguous(VM
&);
766 ContiguousJSValues
rageConvertDoubleToContiguous(VM
&);
767 ArrayStorage
* convertDoubleToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
768 ArrayStorage
* convertDoubleToArrayStorage(VM
&, NonPropertyTransition
);
769 ArrayStorage
* convertDoubleToArrayStorage(VM
&);
771 ArrayStorage
* convertContiguousToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
772 ArrayStorage
* convertContiguousToArrayStorage(VM
&, NonPropertyTransition
);
773 ArrayStorage
* convertContiguousToArrayStorage(VM
&);
776 ArrayStorage
* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM
&);
778 bool defineOwnNonIndexProperty(ExecState
*, PropertyName
, PropertyDescriptor
&, bool throwException
);
780 template<IndexingType indexingShape
>
781 void putByIndexBeyondVectorLengthWithoutAttributes(ExecState
*, unsigned propertyName
, JSValue
);
782 void putByIndexBeyondVectorLengthWithArrayStorage(ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
, ArrayStorage
*);
784 bool increaseVectorLength(VM
&, unsigned newLength
);
785 void deallocateSparseIndexMap();
786 bool defineOwnIndexedProperty(ExecState
*, unsigned, PropertyDescriptor
&, bool throwException
);
787 SparseArrayValueMap
* allocateSparseIndexMap(VM
&);
789 void notifyPresenceOfIndexedAccessors(VM
&);
791 bool attemptToInterceptPutByIndexOnHole(ExecState
*, unsigned index
, JSValue
, bool shouldThrow
);
793 // Call this if you want setIndexQuickly to succeed and you're sure that
794 // the array is contiguous.
795 void ensureLength(VM
& vm
, unsigned length
)
797 ASSERT(length
< MAX_ARRAY_INDEX
);
798 ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
800 if (m_butterfly
->vectorLength() < length
)
801 ensureLengthSlow(vm
, length
);
803 if (m_butterfly
->publicLength() < length
)
804 m_butterfly
->setPublicLength(length
);
807 template<IndexingType indexingShape
>
808 unsigned countElements(Butterfly
*);
810 // This is relevant to undecided, int32, double, and contiguous.
811 unsigned countElements();
813 // This strange method returns a pointer to the start of the indexed data
814 // as if it contained JSValues. But it won't always contain JSValues.
815 // Make sure you cast this to the appropriate type before using.
816 template<IndexingType indexingType
>
817 ContiguousJSValues
indexingData()
819 switch (indexingType
) {
820 case ALL_INT32_INDEXING_TYPES
:
821 case ALL_DOUBLE_INDEXING_TYPES
:
822 case ALL_CONTIGUOUS_INDEXING_TYPES
:
823 return m_butterfly
->contiguous();
825 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
826 return m_butterfly
->arrayStorage()->vector();
830 return ContiguousJSValues();
834 ContiguousJSValues
currentIndexingData()
836 switch (structure()->indexingType()) {
837 case ALL_INT32_INDEXING_TYPES
:
838 case ALL_CONTIGUOUS_INDEXING_TYPES
:
839 return m_butterfly
->contiguous();
841 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
842 return m_butterfly
->arrayStorage()->vector();
846 return ContiguousJSValues();
850 JSValue
getHolyIndexQuickly(unsigned i
)
852 ASSERT(i
< m_butterfly
->vectorLength());
853 switch (structure()->indexingType()) {
854 case ALL_INT32_INDEXING_TYPES
:
855 case ALL_CONTIGUOUS_INDEXING_TYPES
:
856 return m_butterfly
->contiguous()[i
].get();
857 case ALL_DOUBLE_INDEXING_TYPES
: {
858 double value
= m_butterfly
->contiguousDouble()[i
];
860 return JSValue(JSValue::EncodeAsDouble
, value
);
863 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
864 return m_butterfly
->arrayStorage()->m_vector
[i
].get();
871 template<IndexingType indexingType
>
872 unsigned relevantLength()
874 switch (indexingType
) {
875 case ALL_INT32_INDEXING_TYPES
:
876 case ALL_DOUBLE_INDEXING_TYPES
:
877 case ALL_CONTIGUOUS_INDEXING_TYPES
:
878 return m_butterfly
->publicLength();
880 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
882 m_butterfly
->arrayStorage()->length(),
883 m_butterfly
->arrayStorage()->vectorLength());
891 unsigned currentRelevantLength()
893 switch (structure()->indexingType()) {
894 case ALL_INT32_INDEXING_TYPES
:
895 case ALL_DOUBLE_INDEXING_TYPES
:
896 case ALL_CONTIGUOUS_INDEXING_TYPES
:
897 return m_butterfly
->publicLength();
899 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
901 m_butterfly
->arrayStorage()->length(),
902 m_butterfly
->arrayStorage()->vectorLength());
911 friend class LLIntOffsetsExtractor
;
913 // Nobody should ever ask any of these questions on something already known to be a JSObject.
914 using JSCell::isAPIValueWrapper
;
915 using JSCell::isGetterSetter
;
917 void getString(ExecState
* exec
);
921 Butterfly
* createInitialIndexedStorage(VM
&, unsigned length
, size_t elementSize
);
923 ArrayStorage
* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM
&, ArrayStorage
*);
926 bool putDirectInternal(VM
&, PropertyName
, JSValue
, unsigned attr
, PutPropertySlot
&, JSCell
*);
928 bool inlineGetOwnPropertySlot(ExecState
*, PropertyName
, PropertySlot
&);
929 JS_EXPORT_PRIVATE
void fillGetterPropertySlot(PropertySlot
&, PropertyOffset
);
931 const HashEntry
* findPropertyHashEntry(ExecState
*, PropertyName
) const;
933 void putIndexedDescriptor(ExecState
*, SparseArrayEntry
*, PropertyDescriptor
&, PropertyDescriptor
& old
);
935 void putByIndexBeyondVectorLength(ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
936 bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState
*, unsigned propertyName
, JSValue
, unsigned attributes
, PutDirectIndexMode
, ArrayStorage
*);
937 JS_EXPORT_PRIVATE
bool putDirectIndexBeyondVectorLength(ExecState
*, unsigned propertyName
, JSValue
, unsigned attributes
, PutDirectIndexMode
);
939 unsigned getNewVectorLength(unsigned currentVectorLength
, unsigned currentLength
, unsigned desiredLength
);
940 unsigned getNewVectorLength(unsigned desiredLength
);
942 JS_EXPORT_PRIVATE
bool getOwnPropertySlotSlow(ExecState
*, PropertyName
, PropertySlot
&);
944 ArrayStorage
* constructConvertedArrayStorageWithoutCopyingElements(VM
&, unsigned neededLength
);
946 JS_EXPORT_PRIVATE
void setIndexQuicklyToUndecided(VM
&, unsigned index
, JSValue
);
947 JS_EXPORT_PRIVATE
void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM
&, unsigned index
, JSValue
);
948 JS_EXPORT_PRIVATE
void convertDoubleToContiguousWhilePerformingSetIndex(VM
&, unsigned index
, JSValue
);
950 void ensureLengthSlow(VM
&, unsigned length
);
952 ContiguousJSValues
ensureInt32Slow(VM
&);
953 ContiguousDoubles
ensureDoubleSlow(VM
&);
954 ContiguousJSValues
ensureContiguousSlow(VM
&);
955 ContiguousJSValues
rageEnsureContiguousSlow(VM
&);
956 ArrayStorage
* ensureArrayStorageSlow(VM
&);
958 enum DoubleToContiguousMode
{ EncodeValueAsDouble
, RageConvertDoubleToValue
};
959 template<DoubleToContiguousMode mode
>
960 ContiguousJSValues
genericConvertDoubleToContiguous(VM
&);
961 ContiguousJSValues
ensureContiguousSlow(VM
&, DoubleToContiguousMode
);
964 Butterfly
* m_butterfly
;
967 // JSNonFinalObject is a type of JSObject that has some internal storage,
968 // but also preserves some space in the collector cell for additional
969 // data members in derived types.
970 class JSNonFinalObject
: public JSObject
{
971 friend class JSObject
;
974 typedef JSObject Base
;
976 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
978 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), &s_info
);
982 explicit JSNonFinalObject(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
= 0)
983 : JSObject(vm
, structure
, butterfly
)
987 void finishCreation(VM
& vm
)
989 Base::finishCreation(vm
);
990 ASSERT(!this->structure()->totalStorageCapacity());
997 // JSFinalObject is a type of JSObject that contains sufficent internal
998 // storage to fully make use of the colloctor cell containing it.
999 class JSFinalObject
: public JSObject
{
1000 friend class JSObject
;
1003 typedef JSObject Base
;
1005 static const unsigned defaultSize
= 64;
1006 static inline unsigned defaultInlineCapacity()
1008 return (defaultSize
- allocationSize(0)) / sizeof(WriteBarrier
<Unknown
>);
1011 static const unsigned maxSize
= 512;
1012 static inline unsigned maxInlineCapacity()
1014 return (maxSize
- allocationSize(0)) / sizeof(WriteBarrier
<Unknown
>);
1017 static JSFinalObject
* create(ExecState
*, Structure
*);
1018 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
, unsigned inlineCapacity
)
1020 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(FinalObjectType
, StructureFlags
), &s_info
, NonArray
, inlineCapacity
);
1023 JS_EXPORT_PRIVATE
static void visitChildren(JSCell
*, SlotVisitor
&);
1025 static JS_EXPORTDATA
const ClassInfo s_info
;
1028 void visitChildrenCommon(SlotVisitor
&);
1030 void finishCreation(VM
& vm
)
1032 Base::finishCreation(vm
);
1033 ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
1034 ASSERT(classInfo());
1038 friend class LLIntOffsetsExtractor
;
1040 explicit JSFinalObject(VM
& vm
, Structure
* structure
)
1041 : JSObject(vm
, structure
)
1045 static const unsigned StructureFlags
= JSObject::StructureFlags
;
1048 inline JSFinalObject
* JSFinalObject::create(ExecState
* exec
, Structure
* structure
)
1050 JSFinalObject
* finalObject
= new (
1052 allocateCell
<JSFinalObject
>(
1054 allocationSize(structure
->inlineCapacity())
1056 ) JSFinalObject(exec
->vm(), structure
);
1057 finalObject
->finishCreation(exec
->vm());
1061 inline bool isJSFinalObject(JSCell
* cell
)
1063 return cell
->classInfo() == &JSFinalObject::s_info
;
1066 inline bool isJSFinalObject(JSValue value
)
1068 return value
.isCell() && isJSFinalObject(value
.asCell());
1071 inline size_t JSObject::offsetOfInlineStorage()
1073 return sizeof(JSObject
);
1076 inline bool JSObject::isGlobalObject() const
1078 return structure()->typeInfo().type() == GlobalObjectType
;
1081 inline bool JSObject::isVariableObject() const
1083 return structure()->typeInfo().type() >= VariableObjectType
;
1087 inline bool JSObject::isStaticScopeObject() const
1089 JSType type
= structure()->typeInfo().type();
1090 return type
== NameScopeObjectType
|| type
== ActivationObjectType
;
1094 inline bool JSObject::isNameScopeObject() const
1096 return structure()->typeInfo().type() == NameScopeObjectType
;
1099 inline bool JSObject::isActivationObject() const
1101 return structure()->typeInfo().type() == ActivationObjectType
;
1104 inline bool JSObject::isErrorInstance() const
1106 return structure()->typeInfo().type() == ErrorInstanceType
;
1109 inline void JSObject::setButterfly(VM
& vm
, Butterfly
* butterfly
, Structure
* structure
)
1112 ASSERT(!butterfly
== (!structure
->outOfLineCapacity() && !hasIndexingHeader(structure
->indexingType())));
1113 setStructure(vm
, structure
, butterfly
);
1114 m_butterfly
= butterfly
;
1117 inline void JSObject::setButterflyWithoutChangingStructure(Butterfly
* butterfly
)
1119 m_butterfly
= butterfly
;
1122 inline CallType
getCallData(JSValue value
, CallData
& callData
)
1124 CallType result
= value
.isCell() ? value
.asCell()->methodTable()->getCallData(value
.asCell(), callData
) : CallTypeNone
;
1125 ASSERT(result
== CallTypeNone
|| value
.isValidCallee());
1129 inline ConstructType
getConstructData(JSValue value
, ConstructData
& constructData
)
1131 ConstructType result
= value
.isCell() ? value
.asCell()->methodTable()->getConstructData(value
.asCell(), constructData
) : ConstructTypeNone
;
1132 ASSERT(result
== ConstructTypeNone
|| value
.isValidCallee());
1136 inline JSObject
* asObject(JSCell
* cell
)
1138 ASSERT(cell
->isObject());
1139 return jsCast
<JSObject
*>(cell
);
1142 inline JSObject
* asObject(JSValue value
)
1144 return asObject(value
.asCell());
1147 inline JSObject::JSObject(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
)
1148 : JSCell(vm
, structure
)
1149 , m_butterfly(butterfly
)
1153 inline JSValue
JSObject::prototype() const
1155 return structure()->storedPrototype();
1158 ALWAYS_INLINE
bool JSObject::inlineGetOwnPropertySlot(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
1160 PropertyOffset offset
= structure()->get(exec
->vm(), propertyName
);
1161 if (LIKELY(isValidOffset(offset
))) {
1162 JSValue value
= getDirect(offset
);
1163 if (structure()->hasGetterSetterProperties() && value
.isGetterSetter())
1164 fillGetterPropertySlot(slot
, offset
);
1166 slot
.setValue(this, value
, offset
);
1170 return getOwnPropertySlotSlow(exec
, propertyName
, slot
);
1173 // It may seem crazy to inline a function this large, especially a virtual function,
1174 // but it makes a big difference to property lookup that derived classes can inline their
1175 // base class call to this.
1176 ALWAYS_INLINE
bool JSObject::getOwnPropertySlot(JSCell
* cell
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
1178 return jsCast
<JSObject
*>(cell
)->inlineGetOwnPropertySlot(exec
, propertyName
, slot
);
1181 // It may seem crazy to inline a function this large but it makes a big difference
1182 // since this is function very hot in variable lookup
1183 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
1185 JSObject
* object
= this;
1187 if (object
->fastGetOwnPropertySlot(exec
, propertyName
, slot
))
1189 JSValue prototype
= object
->prototype();
1190 if (!prototype
.isObject())
1192 object
= asObject(prototype
);
1196 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
)
1198 JSObject
* object
= this;
1200 if (object
->methodTable()->getOwnPropertySlotByIndex(object
, exec
, propertyName
, slot
))
1202 JSValue prototype
= object
->prototype();
1203 if (!prototype
.isObject())
1205 object
= asObject(prototype
);
1209 inline JSValue
JSObject::get(ExecState
* exec
, PropertyName propertyName
) const
1211 PropertySlot
slot(this);
1212 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
1213 return slot
.getValue(exec
, propertyName
);
1215 return jsUndefined();
1218 inline JSValue
JSObject::get(ExecState
* exec
, unsigned propertyName
) const
1220 PropertySlot
slot(this);
1221 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
1222 return slot
.getValue(exec
, propertyName
);
1224 return jsUndefined();
1227 template<JSObject::PutMode mode
>
1228 inline bool JSObject::putDirectInternal(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
, PutPropertySlot
& slot
, JSCell
* specificFunction
)
1231 ASSERT(value
.isGetterSetter() == !!(attributes
& Accessor
));
1232 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
1233 ASSERT(propertyName
.asIndex() == PropertyName::NotAnIndex
);
1235 if (structure()->isDictionary()) {
1236 unsigned currentAttributes
;
1237 JSCell
* currentSpecificFunction
;
1238 PropertyOffset offset
= structure()->get(vm
, propertyName
, currentAttributes
, currentSpecificFunction
);
1239 if (offset
!= invalidOffset
) {
1240 // If there is currently a specific function, and there now either isn't,
1241 // or the new value is different, then despecify.
1242 if (currentSpecificFunction
&& (specificFunction
!= currentSpecificFunction
))
1243 structure()->despecifyDictionaryFunction(vm
, propertyName
);
1244 if ((mode
== PutModePut
) && currentAttributes
& ReadOnly
)
1247 putDirect(vm
, offset
, value
);
1248 // At this point, the objects structure only has a specific value set if previously there
1249 // had been one set, and if the new value being specified is the same (otherwise we would
1250 // have despecified, above). So, if currentSpecificFunction is not set, or if the new
1251 // value is different (or there is no new value), then the slot now has no value - and
1252 // as such it is cachable.
1253 // If there was previously a value, and the new value is the same, then we cannot cache.
1254 if (!currentSpecificFunction
|| (specificFunction
!= currentSpecificFunction
))
1255 slot
.setExistingProperty(this, offset
);
1259 if ((mode
== PutModePut
) && !isExtensible())
1262 Butterfly
* newButterfly
= m_butterfly
;
1263 if (structure()->putWillGrowOutOfLineStorage())
1264 newButterfly
= growOutOfLineStorage(vm
, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
1265 offset
= structure()->addPropertyWithoutTransition(vm
, propertyName
, attributes
, specificFunction
);
1266 setButterfly(vm
, newButterfly
, structure());
1268 validateOffset(offset
);
1269 ASSERT(structure()->isValidOffset(offset
));
1270 putDirect(vm
, offset
, value
);
1271 // See comment on setNewProperty call below.
1272 if (!specificFunction
)
1273 slot
.setNewProperty(this, offset
);
1274 if (attributes
& ReadOnly
)
1275 structure()->setContainsReadOnlyProperties();
1279 PropertyOffset offset
;
1280 size_t currentCapacity
= structure()->outOfLineCapacity();
1281 if (Structure
* structure
= Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName
, attributes
, specificFunction
, offset
)) {
1282 Butterfly
* newButterfly
= m_butterfly
;
1283 if (currentCapacity
!= structure
->outOfLineCapacity())
1284 newButterfly
= growOutOfLineStorage(vm
, currentCapacity
, structure
->outOfLineCapacity());
1286 validateOffset(offset
);
1287 ASSERT(structure
->isValidOffset(offset
));
1288 setButterfly(vm
, newButterfly
, structure
);
1289 putDirect(vm
, offset
, value
);
1290 // This is a new property; transitions with specific values are not currently cachable,
1291 // so leave the slot in an uncachable state.
1292 if (!specificFunction
)
1293 slot
.setNewProperty(this, offset
);
1297 unsigned currentAttributes
;
1298 JSCell
* currentSpecificFunction
;
1299 offset
= structure()->get(vm
, propertyName
, currentAttributes
, currentSpecificFunction
);
1300 if (offset
!= invalidOffset
) {
1301 if ((mode
== PutModePut
) && currentAttributes
& ReadOnly
)
1304 // There are three possibilities here:
1305 // (1) There is an existing specific value set, and we're overwriting with *the same value*.
1306 // * Do nothing - no need to despecify, but that means we can't cache (a cached
1307 // put could write a different value). Leave the slot in an uncachable state.
1308 // (2) There is a specific value currently set, but we're writing a different value.
1309 // * First, we have to despecify. Having done so, this is now a regular slot
1310 // with no specific value, so go ahead & cache like normal.
1311 // (3) Normal case, there is no specific value set.
1312 // * Go ahead & cache like normal.
1313 if (currentSpecificFunction
) {
1314 // case (1) Do the put, then return leaving the slot uncachable.
1315 if (specificFunction
== currentSpecificFunction
) {
1316 putDirect(vm
, offset
, value
);
1319 // case (2) Despecify, fall through to (3).
1320 setStructure(vm
, Structure::despecifyFunctionTransition(vm
, structure(), propertyName
), m_butterfly
);
1323 // case (3) set the slot, do the put, return.
1324 slot
.setExistingProperty(this, offset
);
1325 putDirect(vm
, offset
, value
);
1329 if ((mode
== PutModePut
) && !isExtensible())
1332 Structure
* structure
= Structure::addPropertyTransition(vm
, this->structure(), propertyName
, attributes
, specificFunction
, offset
);
1334 validateOffset(offset
);
1335 ASSERT(structure
->isValidOffset(offset
));
1336 setStructureAndReallocateStorageIfNecessary(vm
, structure
);
1338 putDirect(vm
, offset
, value
);
1339 // This is a new property; transitions with specific values are not currently cachable,
1340 // so leave the slot in an uncachable state.
1341 if (!specificFunction
)
1342 slot
.setNewProperty(this, offset
);
1343 if (attributes
& ReadOnly
)
1344 structure
->setContainsReadOnlyProperties();
1348 inline void JSObject::setStructure(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
)
1350 JSCell::setStructure(vm
, structure
);
1351 ASSERT_UNUSED(butterfly
, !butterfly
== !(structure
->outOfLineCapacity() || hasIndexingHeader(structure
->indexingType())));
1354 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM
& vm
, unsigned oldCapacity
, Structure
* newStructure
)
1356 ASSERT(oldCapacity
<= newStructure
->outOfLineCapacity());
1358 if (oldCapacity
== newStructure
->outOfLineCapacity()) {
1359 setStructure(vm
, newStructure
, m_butterfly
);
1363 Butterfly
* newButterfly
= growOutOfLineStorage(
1364 vm
, oldCapacity
, newStructure
->outOfLineCapacity());
1365 setButterfly(vm
, newButterfly
, newStructure
);
1368 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM
& vm
, Structure
* newStructure
)
1370 setStructureAndReallocateStorageIfNecessary(
1371 vm
, structure()->outOfLineCapacity(), newStructure
);
1374 inline bool JSObject::putOwnDataProperty(VM
& vm
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
1377 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
1378 ASSERT(!structure()->hasGetterSetterProperties());
1380 return putDirectInternal
<PutModePut
>(vm
, propertyName
, value
, 0, slot
, getCallableObject(value
));
1383 inline void JSObject::putDirect(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
1385 ASSERT(!value
.isGetterSetter() && !(attributes
& Accessor
));
1386 PutPropertySlot slot
;
1387 putDirectInternal
<PutModeDefineOwnProperty
>(vm
, propertyName
, value
, attributes
, slot
, getCallableObject(value
));
1390 inline void JSObject::putDirect(VM
& vm
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
1392 ASSERT(!value
.isGetterSetter());
1393 putDirectInternal
<PutModeDefineOwnProperty
>(vm
, propertyName
, value
, 0, slot
, getCallableObject(value
));
1396 inline void JSObject::putDirectWithoutTransition(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
1398 ASSERT(!value
.isGetterSetter() && !(attributes
& Accessor
));
1399 Butterfly
* newButterfly
= m_butterfly
;
1400 if (structure()->putWillGrowOutOfLineStorage())
1401 newButterfly
= growOutOfLineStorage(vm
, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
1402 PropertyOffset offset
= structure()->addPropertyWithoutTransition(vm
, propertyName
, attributes
, getCallableObject(value
));
1403 setButterfly(vm
, newButterfly
, structure());
1404 putDirect(vm
, offset
, value
);
1407 inline JSValue
JSObject::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const
1409 return methodTable()->defaultValue(this, exec
, preferredType
);
1412 ALWAYS_INLINE JSObject
* Register::function() const
1416 return asObject(jsValue());
1419 ALWAYS_INLINE Register
Register::withCallee(JSObject
* callee
)
1422 r
= JSValue(callee
);
1426 inline size_t offsetInButterfly(PropertyOffset offset
)
1428 return offsetInOutOfLineStorage(offset
) + Butterfly::indexOfPropertyStorage();
1431 // Helpers for patching code where you want to emit a load or store and
1433 // For inline offsets: a pointer to the out-of-line storage pointer.
1434 // For out-of-line offsets: the base of the out-of-line storage.
1435 inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset
)
1437 if (isOutOfLineOffset(offset
))
1438 return sizeof(EncodedJSValue
) * offsetInButterfly(offset
);
1439 return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue
) * offsetInInlineStorage(offset
);
1442 // Returns the maximum offset (away from zero) a load instruction will encode.
1443 inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset
)
1445 ptrdiff_t addressOffset
= static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset
));
1446 #if USE(JSVALUE32_64)
1447 if (addressOffset
>= 0)
1448 return static_cast<size_t>(addressOffset
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
);
1450 return static_cast<size_t>(addressOffset
);
1453 inline int indexRelativeToBase(PropertyOffset offset
)
1455 if (isOutOfLineOffset(offset
))
1456 return offsetInOutOfLineStorage(offset
) + Butterfly::indexOfPropertyStorage();
1457 ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue
)));
1458 return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue
) + offsetInInlineStorage(offset
);
1461 inline int offsetRelativeToBase(PropertyOffset offset
)
1463 if (isOutOfLineOffset(offset
))
1464 return offsetInOutOfLineStorage(offset
) * sizeof(EncodedJSValue
) + Butterfly::offsetOfPropertyStorage();
1465 return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset
) * sizeof(EncodedJSValue
);
1468 COMPILE_ASSERT(!(sizeof(JSObject
) % sizeof(WriteBarrierBase
<Unknown
>)), JSObject_inline_storage_has_correct_alignment
);
1470 ALWAYS_INLINE Identifier
makeIdentifier(ExecState
* exec
, const char* name
)
1472 return Identifier(exec
, name
);
1475 ALWAYS_INLINE Identifier
makeIdentifier(ExecState
*, const Identifier
& name
)
1480 // Helper for defining native functions, if you're not using a static hash table.
1481 // Use this macro from within finishCreation() methods in prototypes. This assumes
1482 // you've defined variables called exec, globalObject, and vm, and they
1483 // have the expected meanings.
1484 #define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
1485 putDirectNativeFunction(\
1486 exec, globalObject, makeIdentifier(exec, (jsName)), (length), cppName, \
1487 (intrinsic), (attributes))
1489 // As above, but this assumes that the function you're defining doesn't have an
1491 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
1492 JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
1496 #endif // JSObject_h