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, 2013 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 "CallFrame.h"
31 #include "ClassInfo.h"
32 #include "CommonIdentifiers.h"
33 #include "CopyWriteBarrier.h"
34 #include "CustomGetterSetter.h"
37 #include "HeapInlines.h"
38 #include "IndexingHeaderInlines.h"
40 #include "PropertySlot.h"
41 #include "PropertyStorage.h"
42 #include "PutDirectIndexMode.h"
43 #include "PutPropertySlot.h"
45 #include "Structure.h"
48 #include "SparseArrayValueMap.h"
49 #include <wtf/StdLibExtras.h>
53 inline JSCell
* getJSFunction(JSValue value
)
55 if (value
.isCell() && (value
.asCell()->type() == JSFunctionType
))
56 return value
.asCell();
60 JS_EXPORT_PRIVATE JSCell
* getCallableObjectSlow(JSCell
*);
62 inline JSCell
* getCallableObject(JSValue value
)
66 return getCallableObjectSlow(value
.asCell());
70 class InternalFunction
;
72 class LLIntOffsetsExtractor
;
74 class PropertyDescriptor
;
75 class PropertyNameArray
;
78 struct HashTableValue
;
80 JS_EXPORT_PRIVATE JSObject
* throwTypeError(ExecState
*, const String
&);
81 extern JS_EXPORTDATA
const char* StrictModeReadonlyPropertyWriteError
;
83 COMPILE_ASSERT(None
< FirstInternalAttribute
, None_is_below_FirstInternalAttribute
);
84 COMPILE_ASSERT(ReadOnly
< FirstInternalAttribute
, ReadOnly_is_below_FirstInternalAttribute
);
85 COMPILE_ASSERT(DontEnum
< FirstInternalAttribute
, DontEnum_is_below_FirstInternalAttribute
);
86 COMPILE_ASSERT(DontDelete
< FirstInternalAttribute
, DontDelete_is_below_FirstInternalAttribute
);
87 COMPILE_ASSERT(Function
< FirstInternalAttribute
, Function_is_below_FirstInternalAttribute
);
88 COMPILE_ASSERT(Accessor
< FirstInternalAttribute
, Accessor_is_below_FirstInternalAttribute
);
92 class JSObject
: public JSCell
{
93 friend class BatchedTransitionOptimizer
;
96 friend class JSFinalObject
;
97 friend class MarkedBlock
;
98 JS_EXPORT_PRIVATE
friend bool setUpStaticFunctionSlot(ExecState
*, const HashTableValue
*, JSObject
*, PropertyName
, PropertySlot
&);
102 PutModeDefineOwnProperty
,
108 JS_EXPORT_PRIVATE
static void visitChildren(JSCell
*, SlotVisitor
&);
109 JS_EXPORT_PRIVATE
static void copyBackingStore(JSCell
*, CopyVisitor
&, CopyToken
);
111 JS_EXPORT_PRIVATE
static String
className(const JSObject
*);
113 JSValue
prototype() const;
114 void setPrototype(VM
&, JSValue prototype
);
115 bool setPrototypeWithCycleCheck(ExecState
*, JSValue prototype
);
117 bool mayInterceptIndexedAccesses()
119 return structure()->mayInterceptIndexedAccesses();
122 JSValue
get(ExecState
*, PropertyName
) const;
123 JSValue
get(ExecState
*, unsigned propertyName
) const;
125 bool fastGetOwnPropertySlot(ExecState
*, VM
&, Structure
&, PropertyName
, PropertySlot
&);
126 bool getPropertySlot(ExecState
*, PropertyName
, PropertySlot
&);
127 bool getPropertySlot(ExecState
*, unsigned propertyName
, PropertySlot
&);
129 static bool getOwnPropertySlot(JSObject
*, ExecState
*, PropertyName
, PropertySlot
&);
130 JS_EXPORT_PRIVATE
static bool getOwnPropertySlotByIndex(JSObject
*, ExecState
*, unsigned propertyName
, PropertySlot
&);
132 // The key difference between this and getOwnPropertySlot is that getOwnPropertySlot
133 // currently returns incorrect results for the DOM window (with non-own properties)
134 // being returned. Once this is fixed we should migrate code & remove this method.
135 bool getOwnPropertyDescriptor(ExecState
*, PropertyName
, PropertyDescriptor
&);
137 bool allowsAccessFrom(ExecState
*);
139 unsigned getArrayLength() const
141 if (!hasIndexedProperties(indexingType()))
143 return m_butterfly
->publicLength();
146 unsigned getVectorLength()
148 if (!hasIndexedProperties(indexingType()))
150 return m_butterfly
->vectorLength();
153 JS_EXPORT_PRIVATE
static void put(JSCell
*, ExecState
*, PropertyName
, JSValue
, PutPropertySlot
&);
154 JS_EXPORT_PRIVATE
static void putByIndex(JSCell
*, ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
156 void putByIndexInline(ExecState
* exec
, unsigned propertyName
, JSValue value
, bool shouldThrow
)
158 if (canSetIndexQuickly(propertyName
)) {
159 setIndexQuickly(exec
->vm(), propertyName
, value
);
162 methodTable(exec
->vm())->putByIndex(this, exec
, propertyName
, value
, shouldThrow
);
165 // This is similar to the putDirect* methods:
166 // - the prototype chain is not consulted
167 // - accessors are not called.
168 // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).
169 // This method creates a property with attributes writable, enumerable and configurable all set to true.
170 bool putDirectIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
, unsigned attributes
, PutDirectIndexMode mode
)
172 if (!attributes
&& canSetIndexQuicklyForPutDirect(propertyName
)) {
173 setIndexQuickly(exec
->vm(), propertyName
, value
);
176 return putDirectIndexBeyondVectorLength(exec
, propertyName
, value
, attributes
, mode
);
178 bool putDirectIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
)
180 return putDirectIndex(exec
, propertyName
, value
, 0, PutDirectIndexLikePutDirect
);
183 // A non-throwing version of putDirect and putDirectIndex.
184 JS_EXPORT_PRIVATE
void putDirectMayBeIndex(ExecState
*, PropertyName
, JSValue
);
186 bool hasIndexingHeader() const
188 return structure()->hasIndexingHeader(this);
191 bool canGetIndexQuickly(unsigned i
)
193 switch (indexingType()) {
194 case ALL_BLANK_INDEXING_TYPES
:
195 case ALL_UNDECIDED_INDEXING_TYPES
:
197 case ALL_INT32_INDEXING_TYPES
:
198 case ALL_CONTIGUOUS_INDEXING_TYPES
:
199 return i
< m_butterfly
->vectorLength() && m_butterfly
->contiguous()[i
];
200 case ALL_DOUBLE_INDEXING_TYPES
: {
201 if (i
>= m_butterfly
->vectorLength())
203 double value
= m_butterfly
->contiguousDouble()[i
];
208 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
209 return i
< m_butterfly
->arrayStorage()->vectorLength() && m_butterfly
->arrayStorage()->m_vector
[i
];
211 RELEASE_ASSERT_NOT_REACHED();
216 JSValue
getIndexQuickly(unsigned i
)
218 switch (indexingType()) {
219 case ALL_INT32_INDEXING_TYPES
:
220 return jsNumber(m_butterfly
->contiguous()[i
].get().asInt32());
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 (indexingType()) {
236 case ALL_BLANK_INDEXING_TYPES
:
237 case ALL_UNDECIDED_INDEXING_TYPES
:
239 case ALL_INT32_INDEXING_TYPES
:
240 if (i
< m_butterfly
->publicLength()) {
241 JSValue result
= m_butterfly
->contiguous()[i
].get();
242 ASSERT(result
.isInt32() || !result
);
246 case ALL_CONTIGUOUS_INDEXING_TYPES
:
247 if (i
< m_butterfly
->publicLength())
248 return m_butterfly
->contiguous()[i
].get();
250 case ALL_DOUBLE_INDEXING_TYPES
: {
251 if (i
>= m_butterfly
->publicLength())
253 double result
= m_butterfly
->contiguousDouble()[i
];
254 if (result
!= result
)
256 return JSValue(JSValue::EncodeAsDouble
, result
);
258 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
259 if (i
< m_butterfly
->arrayStorage()->vectorLength())
260 return m_butterfly
->arrayStorage()->m_vector
[i
].get();
263 RELEASE_ASSERT_NOT_REACHED();
269 JSValue
getDirectIndex(ExecState
* exec
, unsigned i
)
271 if (JSValue result
= tryGetIndexQuickly(i
))
273 PropertySlot
slot(this);
274 if (methodTable(exec
->vm())->getOwnPropertySlotByIndex(this, exec
, i
, slot
))
275 return slot
.getValue(exec
, i
);
279 JSValue
getIndex(ExecState
* exec
, unsigned i
)
281 if (JSValue result
= tryGetIndexQuickly(i
))
286 bool canSetIndexQuickly(unsigned i
)
288 switch (indexingType()) {
289 case ALL_BLANK_INDEXING_TYPES
:
290 case ALL_UNDECIDED_INDEXING_TYPES
:
292 case ALL_INT32_INDEXING_TYPES
:
293 case ALL_DOUBLE_INDEXING_TYPES
:
294 case ALL_CONTIGUOUS_INDEXING_TYPES
:
295 case NonArrayWithArrayStorage
:
296 case ArrayWithArrayStorage
:
297 return i
< m_butterfly
->vectorLength();
298 case NonArrayWithSlowPutArrayStorage
:
299 case ArrayWithSlowPutArrayStorage
:
300 return i
< m_butterfly
->arrayStorage()->vectorLength()
301 && !!m_butterfly
->arrayStorage()->m_vector
[i
];
303 RELEASE_ASSERT_NOT_REACHED();
308 bool canSetIndexQuicklyForPutDirect(unsigned i
)
310 switch (indexingType()) {
311 case ALL_BLANK_INDEXING_TYPES
:
312 case ALL_UNDECIDED_INDEXING_TYPES
:
314 case ALL_INT32_INDEXING_TYPES
:
315 case ALL_DOUBLE_INDEXING_TYPES
:
316 case ALL_CONTIGUOUS_INDEXING_TYPES
:
317 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
318 return i
< m_butterfly
->vectorLength();
320 RELEASE_ASSERT_NOT_REACHED();
325 void setIndexQuickly(VM
& vm
, unsigned i
, JSValue v
)
327 switch (indexingType()) {
328 case ALL_INT32_INDEXING_TYPES
: {
329 ASSERT(i
< m_butterfly
->vectorLength());
331 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm
, i
, v
);
336 case ALL_CONTIGUOUS_INDEXING_TYPES
: {
337 ASSERT(i
< m_butterfly
->vectorLength());
338 m_butterfly
->contiguous()[i
].set(vm
, this, v
);
339 if (i
>= m_butterfly
->publicLength())
340 m_butterfly
->setPublicLength(i
+ 1);
343 case ALL_DOUBLE_INDEXING_TYPES
: {
344 ASSERT(i
< m_butterfly
->vectorLength());
346 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
349 double value
= v
.asNumber();
350 if (value
!= value
) {
351 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
354 m_butterfly
->contiguousDouble()[i
] = value
;
355 if (i
>= m_butterfly
->publicLength())
356 m_butterfly
->setPublicLength(i
+ 1);
359 case ALL_ARRAY_STORAGE_INDEXING_TYPES
: {
360 ArrayStorage
* storage
= m_butterfly
->arrayStorage();
361 WriteBarrier
<Unknown
>& x
= storage
->m_vector
[i
];
362 JSValue old
= x
.get();
365 ++storage
->m_numValuesInVector
;
366 if (i
>= storage
->length())
367 storage
->setLength(i
+ 1);
372 RELEASE_ASSERT_NOT_REACHED();
376 void initializeIndex(VM
& vm
, unsigned i
, JSValue v
)
378 switch (indexingType()) {
379 case ALL_UNDECIDED_INDEXING_TYPES
: {
380 setIndexQuicklyToUndecided(vm
, i
, v
);
383 case ALL_INT32_INDEXING_TYPES
: {
384 ASSERT(i
< m_butterfly
->publicLength());
385 ASSERT(i
< m_butterfly
->vectorLength());
387 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm
, i
, v
);
392 case ALL_CONTIGUOUS_INDEXING_TYPES
: {
393 ASSERT(i
< m_butterfly
->publicLength());
394 ASSERT(i
< m_butterfly
->vectorLength());
395 m_butterfly
->contiguous()[i
].set(vm
, this, v
);
398 case ALL_DOUBLE_INDEXING_TYPES
: {
399 ASSERT(i
< m_butterfly
->publicLength());
400 ASSERT(i
< m_butterfly
->vectorLength());
402 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
405 double value
= v
.asNumber();
406 if (value
!= value
) {
407 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
410 m_butterfly
->contiguousDouble()[i
] = value
;
413 case ALL_ARRAY_STORAGE_INDEXING_TYPES
: {
414 ArrayStorage
* storage
= m_butterfly
->arrayStorage();
415 ASSERT(i
< storage
->length());
416 ASSERT(i
< storage
->m_numValuesInVector
);
417 storage
->m_vector
[i
].set(vm
, this, v
);
421 RELEASE_ASSERT_NOT_REACHED();
427 switch (indexingType()) {
428 case ALL_BLANK_INDEXING_TYPES
:
429 case ALL_UNDECIDED_INDEXING_TYPES
:
430 case ALL_INT32_INDEXING_TYPES
:
431 case ALL_DOUBLE_INDEXING_TYPES
:
432 case ALL_CONTIGUOUS_INDEXING_TYPES
:
434 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
435 return m_butterfly
->arrayStorage()->m_sparseMap
;
437 RELEASE_ASSERT_NOT_REACHED();
442 bool inSparseIndexingMode()
444 switch (indexingType()) {
445 case ALL_BLANK_INDEXING_TYPES
:
446 case ALL_UNDECIDED_INDEXING_TYPES
:
447 case ALL_INT32_INDEXING_TYPES
:
448 case ALL_DOUBLE_INDEXING_TYPES
:
449 case ALL_CONTIGUOUS_INDEXING_TYPES
:
451 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
452 return m_butterfly
->arrayStorage()->inSparseMode();
454 RELEASE_ASSERT_NOT_REACHED();
459 void enterDictionaryIndexingMode(VM
&);
461 // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
462 // - the prototype chain is not consulted
463 // - accessors are not called.
464 // - attributes will be respected (after the call the property will exist with the given attributes)
465 // - the property name is assumed to not be an index.
466 void putDirect(VM
&, PropertyName
, JSValue
, unsigned attributes
= 0);
467 void putDirect(VM
&, PropertyName
, JSValue
, PutPropertySlot
&);
468 void putDirectWithoutTransition(VM
&, PropertyName
, JSValue
, unsigned attributes
= 0);
469 void putDirectNonIndexAccessor(VM
&, PropertyName
, JSValue
, unsigned attributes
);
470 void putDirectAccessor(ExecState
*, PropertyName
, JSValue
, unsigned attributes
);
471 JS_EXPORT_PRIVATE
void putDirectCustomAccessor(VM
&, PropertyName
, JSValue
, unsigned attributes
);
473 JS_EXPORT_PRIVATE
bool hasProperty(ExecState
*, PropertyName
) const;
474 JS_EXPORT_PRIVATE
bool hasProperty(ExecState
*, unsigned propertyName
) const;
475 bool hasOwnProperty(ExecState
*, PropertyName
) const;
477 JS_EXPORT_PRIVATE
static bool deleteProperty(JSCell
*, ExecState
*, PropertyName
);
478 JS_EXPORT_PRIVATE
static bool deletePropertyByIndex(JSCell
*, ExecState
*, unsigned propertyName
);
480 JS_EXPORT_PRIVATE
static JSValue
defaultValue(const JSObject
*, ExecState
*, PreferredPrimitiveType
);
482 bool hasInstance(ExecState
*, JSValue
);
483 static bool defaultHasInstance(ExecState
*, JSValue
, JSValue prototypeProperty
);
485 JS_EXPORT_PRIVATE
static void getOwnPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
486 JS_EXPORT_PRIVATE
static void getOwnNonIndexPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
487 JS_EXPORT_PRIVATE
static void getPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
489 JSValue
toPrimitive(ExecState
*, PreferredPrimitiveType
= NoPreference
) const;
490 bool getPrimitiveNumber(ExecState
*, double& number
, JSValue
&) const;
491 JS_EXPORT_PRIVATE
double toNumber(ExecState
*) const;
492 JS_EXPORT_PRIVATE JSString
* toString(ExecState
*) const;
494 JS_EXPORT_PRIVATE
static JSValue
toThis(JSCell
*, ExecState
*, ECMAMode
);
496 bool getPropertySpecificValue(ExecState
*, PropertyName
, JSCell
*& specificFunction
) const;
498 // This get function only looks at the property map.
499 JSValue
getDirect(VM
& vm
, PropertyName propertyName
) const
501 Structure
* structure
= this->structure(vm
);
502 PropertyOffset offset
= structure
->get(vm
, propertyName
);
503 checkOffset(offset
, structure
->inlineCapacity());
504 return offset
!= invalidOffset
? getDirect(offset
) : JSValue();
507 JSValue
getDirect(VM
& vm
, PropertyName propertyName
, unsigned& attributes
) const
510 Structure
* structure
= this->structure(vm
);
511 PropertyOffset offset
= structure
->get(vm
, propertyName
, attributes
, specific
);
512 checkOffset(offset
, structure
->inlineCapacity());
513 return offset
!= invalidOffset
? getDirect(offset
) : JSValue();
516 PropertyOffset
getDirectOffset(VM
& vm
, PropertyName propertyName
)
518 Structure
* structure
= this->structure(vm
);
519 PropertyOffset offset
= structure
->get(vm
, propertyName
);
520 checkOffset(offset
, structure
->inlineCapacity());
524 PropertyOffset
getDirectOffset(VM
& vm
, PropertyName propertyName
, unsigned& attributes
)
527 Structure
* structure
= this->structure(vm
);
528 PropertyOffset offset
= structure
->get(vm
, propertyName
, attributes
, specific
);
529 checkOffset(offset
, structure
->inlineCapacity());
533 bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
534 ConstPropertyStorage
inlineStorageUnsafe() const
536 return bitwise_cast
<ConstPropertyStorage
>(this + 1);
538 PropertyStorage
inlineStorageUnsafe()
540 return bitwise_cast
<PropertyStorage
>(this + 1);
542 ConstPropertyStorage
inlineStorage() const
544 ASSERT(hasInlineStorage());
545 return inlineStorageUnsafe();
547 PropertyStorage
inlineStorage()
549 ASSERT(hasInlineStorage());
550 return inlineStorageUnsafe();
553 const Butterfly
* butterfly() const { return m_butterfly
.get(); }
554 Butterfly
* butterfly() { return m_butterfly
.get(); }
556 ConstPropertyStorage
outOfLineStorage() const { return m_butterfly
->propertyStorage(); }
557 PropertyStorage
outOfLineStorage() { return m_butterfly
->propertyStorage(); }
559 const WriteBarrierBase
<Unknown
>* locationForOffset(PropertyOffset offset
) const
561 if (isInlineOffset(offset
))
562 return &inlineStorage()[offsetInInlineStorage(offset
)];
563 return &outOfLineStorage()[offsetInOutOfLineStorage(offset
)];
566 WriteBarrierBase
<Unknown
>* locationForOffset(PropertyOffset offset
)
568 if (isInlineOffset(offset
))
569 return &inlineStorage()[offsetInInlineStorage(offset
)];
570 return &outOfLineStorage()[offsetInOutOfLineStorage(offset
)];
573 void transitionTo(VM
&, Structure
*);
575 JS_EXPORT_PRIVATE
bool removeDirect(VM
&, PropertyName
); // Return true if anything is removed.
576 bool hasCustomProperties() { return structure()->didTransition(); }
577 bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
578 bool hasCustomGetterSetterProperties() { return structure()->hasCustomGetterSetterProperties(); }
580 // putOwnDataProperty has 'put' like semantics, however this method:
581 // - assumes the object contains no own getter/setter properties.
582 // - provides no special handling for __proto__
583 // - does not walk the prototype chain (to check for accessors or non-writable properties).
584 // This is used by JSActivation.
585 bool putOwnDataProperty(VM
&, PropertyName
, JSValue
, PutPropertySlot
&);
587 // Fast access to known property offsets.
588 JSValue
getDirect(PropertyOffset offset
) const { return locationForOffset(offset
)->get(); }
589 void putDirect(VM
& vm
, PropertyOffset offset
, JSValue value
) { locationForOffset(offset
)->set(vm
, this, value
); }
590 void putDirectUndefined(PropertyOffset offset
) { locationForOffset(offset
)->setUndefined(); }
592 JS_EXPORT_PRIVATE
void putDirectNativeFunction(VM
&, JSGlobalObject
*, const PropertyName
&, unsigned functionLength
, NativeFunction
, Intrinsic
, unsigned attributes
);
593 JS_EXPORT_PRIVATE JSFunction
* putDirectBuiltinFunction(VM
&, JSGlobalObject
*, const PropertyName
&, FunctionExecutable
*, unsigned attributes
);
594 JSFunction
* putDirectBuiltinFunctionWithoutTransition(VM
&, JSGlobalObject
*, const PropertyName
&, FunctionExecutable
*, unsigned attributes
);
595 void putDirectNativeFunctionWithoutTransition(VM
&, JSGlobalObject
*, const PropertyName
&, unsigned functionLength
, NativeFunction
, Intrinsic
, unsigned attributes
);
597 JS_EXPORT_PRIVATE
static bool defineOwnProperty(JSObject
*, ExecState
*, PropertyName
, const PropertyDescriptor
&, bool shouldThrow
);
599 bool isGlobalObject() const;
600 bool isVariableObject() const;
601 bool isStaticScopeObject() const;
602 bool isNameScopeObject() const;
603 bool isActivationObject() const;
604 bool isErrorInstance() const;
608 JS_EXPORT_PRIVATE
void preventExtensions(VM
&);
609 bool isSealed(VM
& vm
) { return structure(vm
)->isSealed(vm
); }
610 bool isFrozen(VM
& vm
) { return structure(vm
)->isFrozen(vm
); }
611 bool isExtensible() { return structure()->isExtensible(); }
612 bool indexingShouldBeSparse()
614 return !isExtensible()
615 || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
618 bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
619 void reifyStaticFunctionsForDelete(ExecState
* exec
);
621 JS_EXPORT_PRIVATE Butterfly
* growOutOfLineStorage(VM
&, size_t oldSize
, size_t newSize
);
622 void setButterflyWithoutChangingStructure(VM
&, Butterfly
*);
624 void setStructure(VM
&, Structure
*);
625 void setStructureAndButterfly(VM
&, Structure
*, Butterfly
*);
626 void setStructureAndReallocateStorageIfNecessary(VM
&, unsigned oldCapacity
, Structure
*);
627 void setStructureAndReallocateStorageIfNecessary(VM
&, Structure
*);
629 void convertToDictionary(VM
& vm
)
631 setStructure(vm
, Structure::toCacheableDictionaryTransition(vm
, structure(vm
)));
634 void flattenDictionaryObject(VM
& vm
)
636 structure(vm
)->flattenDictionaryStructure(vm
, this);
638 void shiftButterflyAfterFlattening(VM
&, size_t outOfLineCapacityBefore
, size_t outOfLineCapacityAfter
);
640 JSGlobalObject
* globalObject() const
642 ASSERT(structure()->globalObject());
643 ASSERT(!isGlobalObject() || ((JSObject
*)structure()->globalObject()) == this);
644 return structure()->globalObject();
647 void switchToSlowPutArrayStorage(VM
&);
649 // The receiver is the prototype in this case. The following:
651 // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
655 // foo->attemptToInterceptPutByIndexOnHole(...);
656 bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState
*, JSValue thisValue
, unsigned propertyName
, JSValue
, bool shouldThrow
);
658 // Returns 0 if int32 storage cannot be created - either because
659 // indexing should be sparse, we're having a bad time, or because
660 // we already have a more general form of storage (double,
661 // contiguous, array storage).
662 ContiguousJSValues
ensureInt32(VM
& vm
)
664 if (LIKELY(hasInt32(indexingType())))
665 return m_butterfly
->contiguousInt32();
667 return ensureInt32Slow(vm
);
670 // Returns 0 if double storage cannot be created - either because
671 // indexing should be sparse, we're having a bad time, or because
672 // we already have a more general form of storage (contiguous,
673 // or array storage).
674 ContiguousDoubles
ensureDouble(VM
& vm
)
676 if (LIKELY(hasDouble(indexingType())))
677 return m_butterfly
->contiguousDouble();
679 return ensureDoubleSlow(vm
);
682 // Returns 0 if contiguous storage cannot be created - either because
683 // indexing should be sparse or because we're having a bad time.
684 ContiguousJSValues
ensureContiguous(VM
& vm
)
686 if (LIKELY(hasContiguous(indexingType())))
687 return m_butterfly
->contiguous();
689 return ensureContiguousSlow(vm
);
692 // Same as ensureContiguous(), except that if the indexed storage is in
693 // double mode, then it does a rage conversion to contiguous: it
694 // attempts to convert each double to an int32.
695 ContiguousJSValues
rageEnsureContiguous(VM
& vm
)
697 if (LIKELY(hasContiguous(indexingType())))
698 return m_butterfly
->contiguous();
700 return rageEnsureContiguousSlow(vm
);
703 // Ensure that the object is in a mode where it has array storage. Use
704 // this if you're about to perform actions that would have required the
705 // object to be converted to have array storage, if it didn't have it
707 ArrayStorage
* ensureArrayStorage(VM
& vm
)
709 if (LIKELY(hasAnyArrayStorage(indexingType())))
710 return m_butterfly
->arrayStorage();
712 return ensureArrayStorageSlow(vm
);
715 static size_t offsetOfInlineStorage();
717 static ptrdiff_t butterflyOffset()
719 return OBJECT_OFFSETOF(JSObject
, m_butterfly
);
722 void* butterflyAddress()
730 void finishCreation(VM
& vm
)
732 Base::finishCreation(vm
);
733 ASSERT(inherits(info()));
734 ASSERT(!structure()->outOfLineCapacity());
735 ASSERT(structure()->isEmpty());
736 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
737 ASSERT(structure()->isObject());
741 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
743 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), info());
746 // To instantiate objects you likely want JSFinalObject, below.
747 // To create derived types you likely want JSNonFinalObject, below.
748 JSObject(VM
&, Structure
*, Butterfly
* = 0);
750 void visitButterfly(SlotVisitor
&, Butterfly
*, size_t storageSize
);
751 void copyButterfly(CopyVisitor
&, Butterfly
*, size_t storageSize
);
753 // Call this if you know that the object is in a mode where it has array
754 // storage. This will assert otherwise.
755 ArrayStorage
* arrayStorage()
757 ASSERT(hasAnyArrayStorage(indexingType()));
758 return m_butterfly
->arrayStorage();
761 // Call this if you want to predicate some actions on whether or not the
762 // object is in a mode where it has array storage.
763 ArrayStorage
* arrayStorageOrNull()
765 switch (indexingType()) {
766 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
767 return m_butterfly
->arrayStorage();
774 size_t butterflyTotalSize();
775 size_t butterflyPreCapacity();
777 Butterfly
* createInitialUndecided(VM
&, unsigned length
);
778 ContiguousJSValues
createInitialInt32(VM
&, unsigned length
);
779 ContiguousDoubles
createInitialDouble(VM
&, unsigned length
);
780 ContiguousJSValues
createInitialContiguous(VM
&, unsigned length
);
782 void convertUndecidedForValue(VM
&, JSValue
);
783 void createInitialForValueAndSet(VM
&, unsigned index
, JSValue
);
784 void convertInt32ForValue(VM
&, JSValue
);
786 ArrayStorage
* createArrayStorage(VM
&, unsigned length
, unsigned vectorLength
);
787 ArrayStorage
* createInitialArrayStorage(VM
&);
789 ContiguousJSValues
convertUndecidedToInt32(VM
&);
790 ContiguousDoubles
convertUndecidedToDouble(VM
&);
791 ContiguousJSValues
convertUndecidedToContiguous(VM
&);
792 ArrayStorage
* convertUndecidedToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
793 ArrayStorage
* convertUndecidedToArrayStorage(VM
&, NonPropertyTransition
);
794 ArrayStorage
* convertUndecidedToArrayStorage(VM
&);
796 ContiguousDoubles
convertInt32ToDouble(VM
&);
797 ContiguousJSValues
convertInt32ToContiguous(VM
&);
798 ArrayStorage
* convertInt32ToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
799 ArrayStorage
* convertInt32ToArrayStorage(VM
&, NonPropertyTransition
);
800 ArrayStorage
* convertInt32ToArrayStorage(VM
&);
802 ContiguousJSValues
convertDoubleToContiguous(VM
&);
803 ContiguousJSValues
rageConvertDoubleToContiguous(VM
&);
804 ArrayStorage
* convertDoubleToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
805 ArrayStorage
* convertDoubleToArrayStorage(VM
&, NonPropertyTransition
);
806 ArrayStorage
* convertDoubleToArrayStorage(VM
&);
808 ArrayStorage
* convertContiguousToArrayStorage(VM
&, NonPropertyTransition
, unsigned neededLength
);
809 ArrayStorage
* convertContiguousToArrayStorage(VM
&, NonPropertyTransition
);
810 ArrayStorage
* convertContiguousToArrayStorage(VM
&);
813 ArrayStorage
* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM
&);
815 bool defineOwnNonIndexProperty(ExecState
*, PropertyName
, const PropertyDescriptor
&, bool throwException
);
817 template<IndexingType indexingShape
>
818 void putByIndexBeyondVectorLengthWithoutAttributes(ExecState
*, unsigned propertyName
, JSValue
);
819 void putByIndexBeyondVectorLengthWithArrayStorage(ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
, ArrayStorage
*);
821 bool increaseVectorLength(VM
&, unsigned newLength
);
822 void deallocateSparseIndexMap();
823 bool defineOwnIndexedProperty(ExecState
*, unsigned, const PropertyDescriptor
&, bool throwException
);
824 SparseArrayValueMap
* allocateSparseIndexMap(VM
&);
826 void notifyPresenceOfIndexedAccessors(VM
&);
828 bool attemptToInterceptPutByIndexOnHole(ExecState
*, unsigned index
, JSValue
, bool shouldThrow
);
830 // Call this if you want setIndexQuickly to succeed and you're sure that
831 // the array is contiguous.
832 void ensureLength(VM
& vm
, unsigned length
)
834 ASSERT(length
< MAX_ARRAY_INDEX
);
835 ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
837 if (m_butterfly
->vectorLength() < length
)
838 ensureLengthSlow(vm
, length
);
840 if (m_butterfly
->publicLength() < length
)
841 m_butterfly
->setPublicLength(length
);
844 template<IndexingType indexingShape
>
845 unsigned countElements(Butterfly
*);
847 // This is relevant to undecided, int32, double, and contiguous.
848 unsigned countElements();
850 // This strange method returns a pointer to the start of the indexed data
851 // as if it contained JSValues. But it won't always contain JSValues.
852 // Make sure you cast this to the appropriate type before using.
853 template<IndexingType indexingType
>
854 ContiguousJSValues
indexingData()
856 switch (indexingType
) {
857 case ALL_INT32_INDEXING_TYPES
:
858 case ALL_DOUBLE_INDEXING_TYPES
:
859 case ALL_CONTIGUOUS_INDEXING_TYPES
:
860 return m_butterfly
->contiguous();
862 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
863 return m_butterfly
->arrayStorage()->vector();
867 return ContiguousJSValues();
871 ContiguousJSValues
currentIndexingData()
873 switch (indexingType()) {
874 case ALL_INT32_INDEXING_TYPES
:
875 case ALL_CONTIGUOUS_INDEXING_TYPES
:
876 return m_butterfly
->contiguous();
878 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
879 return m_butterfly
->arrayStorage()->vector();
883 return ContiguousJSValues();
887 JSValue
getHolyIndexQuickly(unsigned i
)
889 ASSERT(i
< m_butterfly
->vectorLength());
890 switch (indexingType()) {
891 case ALL_INT32_INDEXING_TYPES
:
892 case ALL_CONTIGUOUS_INDEXING_TYPES
:
893 return m_butterfly
->contiguous()[i
].get();
894 case ALL_DOUBLE_INDEXING_TYPES
: {
895 double value
= m_butterfly
->contiguousDouble()[i
];
897 return JSValue(JSValue::EncodeAsDouble
, value
);
900 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
901 return m_butterfly
->arrayStorage()->m_vector
[i
].get();
908 template<IndexingType indexingType
>
909 unsigned relevantLength()
911 switch (indexingType
) {
912 case ALL_INT32_INDEXING_TYPES
:
913 case ALL_DOUBLE_INDEXING_TYPES
:
914 case ALL_CONTIGUOUS_INDEXING_TYPES
:
915 return m_butterfly
->publicLength();
917 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
919 m_butterfly
->arrayStorage()->length(),
920 m_butterfly
->arrayStorage()->vectorLength());
928 unsigned currentRelevantLength()
930 switch (indexingType()) {
931 case ALL_INT32_INDEXING_TYPES
:
932 case ALL_DOUBLE_INDEXING_TYPES
:
933 case ALL_CONTIGUOUS_INDEXING_TYPES
:
934 return m_butterfly
->publicLength();
936 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
938 m_butterfly
->arrayStorage()->length(),
939 m_butterfly
->arrayStorage()->vectorLength());
948 friend class LLIntOffsetsExtractor
;
950 // Nobody should ever ask any of these questions on something already known to be a JSObject.
951 using JSCell::isAPIValueWrapper
;
952 using JSCell::isGetterSetter
;
954 void getString(ExecState
* exec
);
958 Butterfly
* createInitialIndexedStorage(VM
&, unsigned length
, size_t elementSize
);
960 ArrayStorage
* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM
&, ArrayStorage
*);
963 bool putDirectInternal(VM
&, PropertyName
, JSValue
, unsigned attr
, PutPropertySlot
&, JSCell
*);
965 bool inlineGetOwnPropertySlot(VM
&, Structure
&, PropertyName
, PropertySlot
&);
966 JS_EXPORT_PRIVATE
void fillGetterPropertySlot(PropertySlot
&, JSValue
, unsigned, PropertyOffset
);
967 void fillCustomGetterPropertySlot(PropertySlot
&, JSValue
, unsigned, Structure
&);
969 const HashTableValue
* findPropertyHashEntry(VM
&, PropertyName
) const;
971 void putIndexedDescriptor(ExecState
*, SparseArrayEntry
*, const PropertyDescriptor
&, PropertyDescriptor
& old
);
973 void putByIndexBeyondVectorLength(ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
974 bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState
*, unsigned propertyName
, JSValue
, unsigned attributes
, PutDirectIndexMode
, ArrayStorage
*);
975 JS_EXPORT_PRIVATE
bool putDirectIndexBeyondVectorLength(ExecState
*, unsigned propertyName
, JSValue
, unsigned attributes
, PutDirectIndexMode
);
977 unsigned getNewVectorLength(unsigned currentVectorLength
, unsigned currentLength
, unsigned desiredLength
);
978 unsigned getNewVectorLength(unsigned desiredLength
);
980 ArrayStorage
* constructConvertedArrayStorageWithoutCopyingElements(VM
&, unsigned neededLength
);
982 JS_EXPORT_PRIVATE
void setIndexQuicklyToUndecided(VM
&, unsigned index
, JSValue
);
983 JS_EXPORT_PRIVATE
void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM
&, unsigned index
, JSValue
);
984 JS_EXPORT_PRIVATE
void convertDoubleToContiguousWhilePerformingSetIndex(VM
&, unsigned index
, JSValue
);
986 void ensureLengthSlow(VM
&, unsigned length
);
988 ContiguousJSValues
ensureInt32Slow(VM
&);
989 ContiguousDoubles
ensureDoubleSlow(VM
&);
990 ContiguousJSValues
ensureContiguousSlow(VM
&);
991 ContiguousJSValues
rageEnsureContiguousSlow(VM
&);
992 ArrayStorage
* ensureArrayStorageSlow(VM
&);
994 enum DoubleToContiguousMode
{ EncodeValueAsDouble
, RageConvertDoubleToValue
};
995 template<DoubleToContiguousMode mode
>
996 ContiguousJSValues
genericConvertDoubleToContiguous(VM
&);
997 ContiguousJSValues
ensureContiguousSlow(VM
&, DoubleToContiguousMode
);
1000 CopyWriteBarrier
<Butterfly
> m_butterfly
;
1001 #if USE(JSVALUE32_64)
1007 // JSNonFinalObject is a type of JSObject that has some internal storage,
1008 // but also preserves some space in the collector cell for additional
1009 // data members in derived types.
1010 class JSNonFinalObject
: public JSObject
{
1011 friend class JSObject
;
1014 typedef JSObject Base
;
1016 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
1018 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), info());
1022 explicit JSNonFinalObject(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
= 0)
1023 : JSObject(vm
, structure
, butterfly
)
1027 void finishCreation(VM
& vm
)
1029 Base::finishCreation(vm
);
1030 ASSERT(!this->structure()->totalStorageCapacity());
1031 ASSERT(classInfo());
1035 class JSFinalObject
;
1037 // JSFinalObject is a type of JSObject that contains sufficent internal
1038 // storage to fully make use of the colloctor cell containing it.
1039 class JSFinalObject
: public JSObject
{
1040 friend class JSObject
;
1043 typedef JSObject Base
;
1045 static size_t allocationSize(size_t inlineCapacity
)
1047 return sizeof(JSObject
) + inlineCapacity
* sizeof(WriteBarrierBase
<Unknown
>);
1050 static const unsigned defaultSize
= 64;
1051 static inline unsigned defaultInlineCapacity()
1053 return (defaultSize
- allocationSize(0)) / sizeof(WriteBarrier
<Unknown
>);
1056 static const unsigned maxSize
= 512;
1057 static inline unsigned maxInlineCapacity()
1059 return (maxSize
- allocationSize(0)) / sizeof(WriteBarrier
<Unknown
>);
1062 static JSFinalObject
* create(ExecState
*, Structure
*);
1063 static JSFinalObject
* create(VM
&, Structure
*);
1064 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
, unsigned inlineCapacity
)
1066 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(FinalObjectType
, StructureFlags
), info(), NonArray
, inlineCapacity
);
1069 JS_EXPORT_PRIVATE
static void visitChildren(JSCell
*, SlotVisitor
&);
1071 DECLARE_EXPORT_INFO
;
1074 void visitChildrenCommon(SlotVisitor
&);
1076 void finishCreation(VM
& vm
)
1078 Base::finishCreation(vm
);
1079 ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
1080 ASSERT(classInfo());
1084 friend class LLIntOffsetsExtractor
;
1086 explicit JSFinalObject(VM
& vm
, Structure
* structure
)
1087 : JSObject(vm
, structure
)
1091 static const unsigned StructureFlags
= JSObject::StructureFlags
;
1094 inline JSFinalObject
* JSFinalObject::create(ExecState
* exec
, Structure
* structure
)
1096 JSFinalObject
* finalObject
= new (
1098 allocateCell
<JSFinalObject
>(
1100 allocationSize(structure
->inlineCapacity())
1102 ) JSFinalObject(exec
->vm(), structure
);
1103 finalObject
->finishCreation(exec
->vm());
1107 inline JSFinalObject
* JSFinalObject::create(VM
& vm
, Structure
* structure
)
1109 JSFinalObject
* finalObject
= new (NotNull
, allocateCell
<JSFinalObject
>(vm
.heap
, allocationSize(structure
->inlineCapacity()))) JSFinalObject(vm
, structure
);
1110 finalObject
->finishCreation(vm
);
1114 inline bool isJSFinalObject(JSCell
* cell
)
1116 return cell
->classInfo() == JSFinalObject::info();
1119 inline bool isJSFinalObject(JSValue value
)
1121 return value
.isCell() && isJSFinalObject(value
.asCell());
1124 inline size_t JSObject::offsetOfInlineStorage()
1126 return sizeof(JSObject
);
1129 inline bool JSObject::isGlobalObject() const
1131 return type() == GlobalObjectType
;
1134 inline bool JSObject::isVariableObject() const
1136 return type() == GlobalObjectType
|| type() == ActivationObjectType
;
1139 inline bool JSObject::isStaticScopeObject() const
1141 JSType type
= this->type();
1142 return type
== NameScopeObjectType
|| type
== ActivationObjectType
;
1146 inline bool JSObject::isNameScopeObject() const
1148 return type() == NameScopeObjectType
;
1151 inline bool JSObject::isActivationObject() const
1153 return type() == ActivationObjectType
;
1156 inline bool JSObject::isErrorInstance() const
1158 return type() == ErrorInstanceType
;
1161 inline void JSObject::setStructureAndButterfly(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
)
1164 ASSERT(!butterfly
== (!structure
->outOfLineCapacity() && !structure
->hasIndexingHeader(this)));
1165 m_butterfly
.set(vm
, this, butterfly
);
1166 setStructure(vm
, structure
);
1169 inline void JSObject::setStructure(VM
& vm
, Structure
* structure
)
1172 ASSERT(!m_butterfly
== !(structure
->outOfLineCapacity() || structure
->hasIndexingHeader(this)));
1173 JSCell::setStructure(vm
, structure
);
1176 inline void JSObject::setButterflyWithoutChangingStructure(VM
& vm
, Butterfly
* butterfly
)
1178 m_butterfly
.set(vm
, this, butterfly
);
1181 inline CallType
getCallData(JSValue value
, CallData
& callData
)
1183 CallType result
= value
.isCell() ? value
.asCell()->methodTable()->getCallData(value
.asCell(), callData
) : CallTypeNone
;
1184 ASSERT(result
== CallTypeNone
|| value
.isValidCallee());
1188 inline ConstructType
getConstructData(JSValue value
, ConstructData
& constructData
)
1190 ConstructType result
= value
.isCell() ? value
.asCell()->methodTable()->getConstructData(value
.asCell(), constructData
) : ConstructTypeNone
;
1191 ASSERT(result
== ConstructTypeNone
|| value
.isValidCallee());
1195 inline JSObject
* asObject(JSCell
* cell
)
1197 ASSERT(cell
->isObject());
1198 return jsCast
<JSObject
*>(cell
);
1201 inline JSObject
* asObject(JSValue value
)
1203 return asObject(value
.asCell());
1206 inline JSObject::JSObject(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
)
1207 : JSCell(vm
, structure
)
1208 , m_butterfly(vm
, this, butterfly
)
1210 vm
.heap
.ascribeOwner(this, butterfly
);
1213 inline JSValue
JSObject::prototype() const
1215 return structure()->storedPrototype();
1218 ALWAYS_INLINE
bool JSObject::inlineGetOwnPropertySlot(VM
& vm
, Structure
& structure
, PropertyName propertyName
, PropertySlot
& slot
)
1220 unsigned attributes
;
1222 PropertyOffset offset
= structure
.get(vm
, propertyName
, attributes
, specific
);
1223 if (!isValidOffset(offset
))
1226 JSValue value
= getDirect(offset
);
1227 if (structure
.hasGetterSetterProperties() && value
.isGetterSetter())
1228 fillGetterPropertySlot(slot
, value
, attributes
, offset
);
1229 else if (structure
.hasCustomGetterSetterProperties() && value
.isCustomGetterSetter())
1230 fillCustomGetterPropertySlot(slot
, value
, attributes
, structure
);
1232 slot
.setValue(this, attributes
, value
, offset
);
1237 ALWAYS_INLINE
void JSObject::fillCustomGetterPropertySlot(PropertySlot
& slot
, JSValue customGetterSetter
, unsigned attributes
, Structure
& structure
)
1239 if (structure
.isDictionary()) {
1240 slot
.setCustom(this, attributes
, jsCast
<CustomGetterSetter
*>(customGetterSetter
)->getter());
1243 slot
.setCacheableCustom(this, attributes
, jsCast
<CustomGetterSetter
*>(customGetterSetter
)->getter());
1246 // It may seem crazy to inline a function this large, especially a virtual function,
1247 // but it makes a big difference to property lookup that derived classes can inline their
1248 // base class call to this.
1249 ALWAYS_INLINE
bool JSObject::getOwnPropertySlot(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
1251 VM
& vm
= exec
->vm();
1252 Structure
& structure
= *object
->structure(vm
);
1253 if (object
->inlineGetOwnPropertySlot(vm
, structure
, propertyName
, slot
))
1255 unsigned index
= propertyName
.asIndex();
1256 if (index
!= PropertyName::NotAnIndex
)
1257 return getOwnPropertySlotByIndex(object
, exec
, index
, slot
);
1261 ALWAYS_INLINE
bool JSObject::fastGetOwnPropertySlot(ExecState
* exec
, VM
& vm
, Structure
& structure
, PropertyName propertyName
, PropertySlot
& slot
)
1263 if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags())))
1264 return inlineGetOwnPropertySlot(vm
, structure
, propertyName
, slot
);
1265 return structure
.classInfo()->methodTable
.getOwnPropertySlot(this, exec
, propertyName
, slot
);
1268 // It may seem crazy to inline a function this large but it makes a big difference
1269 // since this is function very hot in variable lookup
1270 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
1272 VM
& vm
= exec
->vm();
1273 auto& structureIDTable
= vm
.heap
.structureIDTable();
1274 JSObject
* object
= this;
1276 Structure
& structure
= *structureIDTable
.get(object
->structureID());
1277 if (object
->fastGetOwnPropertySlot(exec
, vm
, structure
, propertyName
, slot
))
1279 JSValue prototype
= structure
.storedPrototype();
1280 if (!prototype
.isObject())
1282 object
= asObject(prototype
);
1285 unsigned index
= propertyName
.asIndex();
1286 if (index
!= PropertyName::NotAnIndex
)
1287 return getPropertySlot(exec
, index
, slot
);
1291 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
)
1293 VM
& vm
= exec
->vm();
1294 auto& structureIDTable
= vm
.heap
.structureIDTable();
1295 JSObject
* object
= this;
1297 Structure
& structure
= *structureIDTable
.get(object
->structureID());
1298 if (structure
.classInfo()->methodTable
.getOwnPropertySlotByIndex(object
, exec
, propertyName
, slot
))
1300 JSValue prototype
= structure
.storedPrototype();
1301 if (!prototype
.isObject())
1303 object
= asObject(prototype
);
1307 inline JSValue
JSObject::get(ExecState
* exec
, PropertyName propertyName
) const
1309 PropertySlot
slot(this);
1310 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
1311 return slot
.getValue(exec
, propertyName
);
1313 return jsUndefined();
1316 inline JSValue
JSObject::get(ExecState
* exec
, unsigned propertyName
) const
1318 PropertySlot
slot(this);
1319 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
1320 return slot
.getValue(exec
, propertyName
);
1322 return jsUndefined();
1325 template<JSObject::PutMode mode
>
1326 inline bool JSObject::putDirectInternal(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
, PutPropertySlot
& slot
, JSCell
* specificFunction
)
1329 ASSERT(value
.isGetterSetter() == !!(attributes
& Accessor
));
1330 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
1331 ASSERT(propertyName
.asIndex() == PropertyName::NotAnIndex
);
1333 Structure
* structure
= this->structure(vm
);
1334 if (structure
->isDictionary()) {
1335 unsigned currentAttributes
;
1336 JSCell
* currentSpecificFunction
;
1337 PropertyOffset offset
= structure
->get(vm
, propertyName
, currentAttributes
, currentSpecificFunction
);
1338 if (offset
!= invalidOffset
) {
1339 // If there is currently a specific function, and there now either isn't,
1340 // or the new value is different, then despecify.
1341 if (currentSpecificFunction
&& (specificFunction
!= currentSpecificFunction
))
1342 structure
->despecifyDictionaryFunction(vm
, propertyName
);
1343 if ((mode
== PutModePut
) && currentAttributes
& ReadOnly
)
1346 putDirect(vm
, offset
, value
);
1347 // At this point, the objects structure only has a specific value set if previously there
1348 // had been one set, and if the new value being specified is the same (otherwise we would
1349 // have despecified, above). So, if currentSpecificFunction is not set, or if the new
1350 // value is different (or there is no new value), then the slot now has no value - and
1351 // as such it is cachable.
1352 // If there was previously a value, and the new value is the same, then we cannot cache.
1353 if (!currentSpecificFunction
|| (specificFunction
!= currentSpecificFunction
))
1354 slot
.setExistingProperty(this, offset
);
1358 if ((mode
== PutModePut
) && !isExtensible())
1361 DeferGC
deferGC(vm
.heap
);
1362 Butterfly
* newButterfly
= butterfly();
1363 if (this->structure()->putWillGrowOutOfLineStorage())
1364 newButterfly
= growOutOfLineStorage(vm
, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity());
1365 offset
= this->structure()->addPropertyWithoutTransition(vm
, propertyName
, attributes
, specificFunction
);
1366 setStructureAndButterfly(vm
, this->structure(), newButterfly
);
1368 validateOffset(offset
);
1369 ASSERT(this->structure()->isValidOffset(offset
));
1370 putDirect(vm
, offset
, value
);
1371 // See comment on setNewProperty call below.
1372 if (!specificFunction
)
1373 slot
.setNewProperty(this, offset
);
1374 if (attributes
& ReadOnly
)
1375 this->structure()->setContainsReadOnlyProperties();
1379 PropertyOffset offset
;
1380 size_t currentCapacity
= this->structure()->outOfLineCapacity();
1381 if (Structure
* structure
= Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName
, attributes
, specificFunction
, offset
)) {
1382 DeferGC
deferGC(vm
.heap
);
1383 Butterfly
* newButterfly
= butterfly();
1384 if (currentCapacity
!= structure
->outOfLineCapacity()) {
1385 ASSERT(structure
!= this->structure());
1386 newButterfly
= growOutOfLineStorage(vm
, currentCapacity
, structure
->outOfLineCapacity());
1389 validateOffset(offset
);
1390 ASSERT(structure
->isValidOffset(offset
));
1391 setStructureAndButterfly(vm
, structure
, newButterfly
);
1392 putDirect(vm
, offset
, value
);
1393 // This is a new property; transitions with specific values are not currently cachable,
1394 // so leave the slot in an uncachable state.
1395 if (!specificFunction
)
1396 slot
.setNewProperty(this, offset
);
1400 unsigned currentAttributes
;
1401 JSCell
* currentSpecificFunction
;
1402 offset
= structure
->get(vm
, propertyName
, currentAttributes
, currentSpecificFunction
);
1403 if (offset
!= invalidOffset
) {
1404 if ((mode
== PutModePut
) && currentAttributes
& ReadOnly
)
1407 // There are three possibilities here:
1408 // (1) There is an existing specific value set, and we're overwriting with *the same value*.
1409 // * Do nothing - no need to despecify, but that means we can't cache (a cached
1410 // put could write a different value). Leave the slot in an uncachable state.
1411 // (2) There is a specific value currently set, but we're writing a different value.
1412 // * First, we have to despecify. Having done so, this is now a regular slot
1413 // with no specific value, so go ahead & cache like normal.
1414 // (3) Normal case, there is no specific value set.
1415 // * Go ahead & cache like normal.
1416 if (currentSpecificFunction
) {
1417 // case (1) Do the put, then return leaving the slot uncachable.
1418 if (specificFunction
== currentSpecificFunction
) {
1419 putDirect(vm
, offset
, value
);
1422 // case (2) Despecify, fall through to (3).
1423 setStructure(vm
, Structure::despecifyFunctionTransition(vm
, structure
, propertyName
));
1426 // case (3) set the slot, do the put, return.
1427 slot
.setExistingProperty(this, offset
);
1428 putDirect(vm
, offset
, value
);
1432 if ((mode
== PutModePut
) && !isExtensible())
1435 structure
= Structure::addPropertyTransition(vm
, structure
, propertyName
, attributes
, specificFunction
, offset
, slot
.context());
1437 validateOffset(offset
);
1438 ASSERT(structure
->isValidOffset(offset
));
1439 setStructureAndReallocateStorageIfNecessary(vm
, structure
);
1441 putDirect(vm
, offset
, value
);
1442 // This is a new property; transitions with specific values are not currently cachable,
1443 // so leave the slot in an uncachable state.
1444 if (!specificFunction
)
1445 slot
.setNewProperty(this, offset
);
1446 if (attributes
& ReadOnly
)
1447 structure
->setContainsReadOnlyProperties();
1451 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM
& vm
, unsigned oldCapacity
, Structure
* newStructure
)
1453 ASSERT(oldCapacity
<= newStructure
->outOfLineCapacity());
1455 if (oldCapacity
== newStructure
->outOfLineCapacity()) {
1456 setStructure(vm
, newStructure
);
1460 DeferGC
deferGC(vm
.heap
);
1461 Butterfly
* newButterfly
= growOutOfLineStorage(
1462 vm
, oldCapacity
, newStructure
->outOfLineCapacity());
1463 setStructureAndButterfly(vm
, newStructure
, newButterfly
);
1466 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM
& vm
, Structure
* newStructure
)
1468 setStructureAndReallocateStorageIfNecessary(
1469 vm
, structure(vm
)->outOfLineCapacity(), newStructure
);
1472 inline bool JSObject::putOwnDataProperty(VM
& vm
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
1475 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
1476 ASSERT(!structure()->hasGetterSetterProperties());
1477 ASSERT(!structure()->hasCustomGetterSetterProperties());
1479 return putDirectInternal
<PutModePut
>(vm
, propertyName
, value
, 0, slot
, getCallableObject(value
));
1482 inline void JSObject::putDirect(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
1484 ASSERT(!value
.isGetterSetter() && !(attributes
& Accessor
));
1485 ASSERT(!value
.isCustomGetterSetter());
1486 PutPropertySlot
slot(this);
1487 putDirectInternal
<PutModeDefineOwnProperty
>(vm
, propertyName
, value
, attributes
, slot
, getCallableObject(value
));
1490 inline void JSObject::putDirect(VM
& vm
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
1492 ASSERT(!value
.isGetterSetter());
1493 ASSERT(!value
.isCustomGetterSetter());
1494 putDirectInternal
<PutModeDefineOwnProperty
>(vm
, propertyName
, value
, 0, slot
, getCallableObject(value
));
1497 inline void JSObject::putDirectWithoutTransition(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
1499 DeferGC
deferGC(vm
.heap
);
1500 ASSERT(!value
.isGetterSetter() && !(attributes
& Accessor
));
1501 ASSERT(!value
.isCustomGetterSetter());
1502 Butterfly
* newButterfly
= m_butterfly
.get();
1503 if (structure()->putWillGrowOutOfLineStorage())
1504 newButterfly
= growOutOfLineStorage(vm
, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
1505 PropertyOffset offset
= structure()->addPropertyWithoutTransition(vm
, propertyName
, attributes
, getCallableObject(value
));
1506 setStructureAndButterfly(vm
, structure(), newButterfly
);
1507 putDirect(vm
, offset
, value
);
1510 inline JSValue
JSObject::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const
1512 return methodTable()->defaultValue(this, exec
, preferredType
);
1515 ALWAYS_INLINE JSObject
* Register::function() const
1519 return asObject(jsValue());
1522 ALWAYS_INLINE Register
Register::withCallee(JSObject
* callee
)
1525 r
= JSValue(callee
);
1529 inline size_t offsetInButterfly(PropertyOffset offset
)
1531 return offsetInOutOfLineStorage(offset
) + Butterfly::indexOfPropertyStorage();
1534 inline size_t JSObject::butterflyPreCapacity()
1536 if (UNLIKELY(hasIndexingHeader()))
1537 return butterfly()->indexingHeader()->preCapacity(structure());
1541 inline size_t JSObject::butterflyTotalSize()
1543 Structure
* structure
= this->structure();
1544 Butterfly
* butterfly
= this->butterfly();
1546 size_t indexingPayloadSizeInBytes
;
1547 bool hasIndexingHeader
= this->hasIndexingHeader();
1549 if (UNLIKELY(hasIndexingHeader
)) {
1550 preCapacity
= butterfly
->indexingHeader()->preCapacity(structure
);
1551 indexingPayloadSizeInBytes
= butterfly
->indexingHeader()->indexingPayloadSizeInBytes(structure
);
1554 indexingPayloadSizeInBytes
= 0;
1557 return Butterfly::totalSize(preCapacity
, structure
->outOfLineCapacity(), hasIndexingHeader
, indexingPayloadSizeInBytes
);
1560 // Helpers for patching code where you want to emit a load or store and
1562 // For inline offsets: a pointer to the out-of-line storage pointer.
1563 // For out-of-line offsets: the base of the out-of-line storage.
1564 inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset
)
1566 if (isOutOfLineOffset(offset
))
1567 return sizeof(EncodedJSValue
) * offsetInButterfly(offset
);
1568 return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue
) * offsetInInlineStorage(offset
);
1571 // Returns the maximum offset (away from zero) a load instruction will encode.
1572 inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset
)
1574 ptrdiff_t addressOffset
= static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset
));
1575 #if USE(JSVALUE32_64)
1576 if (addressOffset
>= 0)
1577 return static_cast<size_t>(addressOffset
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
);
1579 return static_cast<size_t>(addressOffset
);
1582 inline int indexRelativeToBase(PropertyOffset offset
)
1584 if (isOutOfLineOffset(offset
))
1585 return offsetInOutOfLineStorage(offset
) + Butterfly::indexOfPropertyStorage();
1586 ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue
)));
1587 return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue
) + offsetInInlineStorage(offset
);
1590 inline int offsetRelativeToBase(PropertyOffset offset
)
1592 if (isOutOfLineOffset(offset
))
1593 return offsetInOutOfLineStorage(offset
) * sizeof(EncodedJSValue
) + Butterfly::offsetOfPropertyStorage();
1594 return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset
) * sizeof(EncodedJSValue
);
1597 COMPILE_ASSERT(!(sizeof(JSObject
) % sizeof(WriteBarrierBase
<Unknown
>)), JSObject_inline_storage_has_correct_alignment
);
1599 ALWAYS_INLINE Identifier
makeIdentifier(VM
& vm
, const char* name
)
1601 return Identifier(&vm
, name
);
1604 ALWAYS_INLINE Identifier
makeIdentifier(VM
&, const Identifier
& name
)
1609 // Helper for defining native functions, if you're not using a static hash table.
1610 // Use this macro from within finishCreation() methods in prototypes. This assumes
1611 // you've defined variables called exec, globalObject, and vm, and they
1612 // have the expected meanings.
1613 #define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
1614 putDirectNativeFunction(\
1615 vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
1616 (intrinsic), (attributes))
1618 // As above, but this assumes that the function you're defining doesn't have an
1620 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
1621 JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
1623 ALWAYS_INLINE JSValue
PropertySlot::getValue(ExecState
* exec
, PropertyName propertyName
) const
1625 if (m_propertyType
== TypeValue
)
1626 return JSValue::decode(m_data
.value
);
1627 if (m_propertyType
== TypeGetter
)
1628 return functionGetter(exec
);
1629 return JSValue::decode(m_data
.custom
.getValue(exec
, slotBase(), JSValue::encode(m_thisValue
), propertyName
));
1632 ALWAYS_INLINE JSValue
PropertySlot::getValue(ExecState
* exec
, unsigned propertyName
) const
1634 if (m_propertyType
== TypeValue
)
1635 return JSValue::decode(m_data
.value
);
1636 if (m_propertyType
== TypeGetter
)
1637 return functionGetter(exec
);
1638 return JSValue::decode(m_data
.custom
.getValue(exec
, slotBase(), JSValue::encode(m_thisValue
), Identifier::from(exec
, propertyName
)));
1643 #endif // JSObject_h