2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003-2009, 2012-2015 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();
61 class InternalFunction
;
63 class LLIntOffsetsExtractor
;
65 class PropertyDescriptor
;
66 class PropertyNameArray
;
69 struct HashTableValue
;
71 JS_EXPORT_PRIVATE JSObject
* throwTypeError(ExecState
*, const String
&);
72 extern JS_EXPORTDATA
const char* StrictModeReadonlyPropertyWriteError
;
74 COMPILE_ASSERT(None
< FirstInternalAttribute
, None_is_below_FirstInternalAttribute
);
75 COMPILE_ASSERT(ReadOnly
< FirstInternalAttribute
, ReadOnly_is_below_FirstInternalAttribute
);
76 COMPILE_ASSERT(DontEnum
< FirstInternalAttribute
, DontEnum_is_below_FirstInternalAttribute
);
77 COMPILE_ASSERT(DontDelete
< FirstInternalAttribute
, DontDelete_is_below_FirstInternalAttribute
);
78 COMPILE_ASSERT(Function
< FirstInternalAttribute
, Function_is_below_FirstInternalAttribute
);
79 COMPILE_ASSERT(Accessor
< FirstInternalAttribute
, Accessor_is_below_FirstInternalAttribute
);
83 class JSObject
: public JSCell
{
84 friend class BatchedTransitionOptimizer
;
87 friend class JSFinalObject
;
88 friend class MarkedBlock
;
89 JS_EXPORT_PRIVATE
friend bool setUpStaticFunctionSlot(ExecState
*, const HashTableValue
*, JSObject
*, PropertyName
, PropertySlot
&);
93 PutModeDefineOwnProperty
,
99 JS_EXPORT_PRIVATE
static void visitChildren(JSCell
*, SlotVisitor
&);
100 JS_EXPORT_PRIVATE
static void copyBackingStore(JSCell
*, CopyVisitor
&, CopyToken
);
102 JS_EXPORT_PRIVATE
static String
className(const JSObject
*);
103 JS_EXPORT_PRIVATE
static String
calculatedClassName(JSObject
*);
105 JSValue
prototype() const;
106 JS_EXPORT_PRIVATE
void setPrototype(VM
&, JSValue prototype
);
107 JS_EXPORT_PRIVATE
bool setPrototypeWithCycleCheck(ExecState
*, JSValue prototype
);
109 bool mayInterceptIndexedAccesses()
111 return structure()->mayInterceptIndexedAccesses();
114 JSValue
get(ExecState
*, PropertyName
) const;
115 JSValue
get(ExecState
*, unsigned propertyName
) const;
117 bool fastGetOwnPropertySlot(ExecState
*, VM
&, Structure
&, PropertyName
, PropertySlot
&);
118 bool getPropertySlot(ExecState
*, PropertyName
, PropertySlot
&);
119 bool getPropertySlot(ExecState
*, unsigned propertyName
, PropertySlot
&);
121 static bool getOwnPropertySlot(JSObject
*, ExecState
*, PropertyName
, PropertySlot
&);
122 JS_EXPORT_PRIVATE
static bool getOwnPropertySlotByIndex(JSObject
*, ExecState
*, unsigned propertyName
, PropertySlot
&);
124 // The key difference between this and getOwnPropertySlot is that getOwnPropertySlot
125 // currently returns incorrect results for the DOM window (with non-own properties)
126 // being returned. Once this is fixed we should migrate code & remove this method.
127 JS_EXPORT_PRIVATE
bool getOwnPropertyDescriptor(ExecState
*, PropertyName
, PropertyDescriptor
&);
129 JS_EXPORT_PRIVATE
bool allowsAccessFrom(ExecState
*);
131 unsigned getArrayLength() const
133 if (!hasIndexedProperties(indexingType()))
135 return m_butterfly
->publicLength();
138 unsigned getVectorLength()
140 if (!hasIndexedProperties(indexingType()))
142 return m_butterfly
->vectorLength();
145 JS_EXPORT_PRIVATE
static void put(JSCell
*, ExecState
*, PropertyName
, JSValue
, PutPropertySlot
&);
146 JS_EXPORT_PRIVATE
static void putByIndex(JSCell
*, ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
148 ALWAYS_INLINE
void putByIndexInline(ExecState
* exec
, unsigned propertyName
, JSValue value
, bool shouldThrow
)
150 if (canSetIndexQuickly(propertyName
)) {
151 setIndexQuickly(exec
->vm(), propertyName
, value
);
154 methodTable(exec
->vm())->putByIndex(this, exec
, propertyName
, value
, shouldThrow
);
157 // This is similar to the putDirect* methods:
158 // - the prototype chain is not consulted
159 // - accessors are not called.
160 // - it will ignore extensibility and read-only properties if PutDirectIndexLikePutDirect is passed as the mode (the default).
161 // This method creates a property with attributes writable, enumerable and configurable all set to true.
162 bool putDirectIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
, unsigned attributes
, PutDirectIndexMode mode
)
164 if (!attributes
&& canSetIndexQuicklyForPutDirect(propertyName
)) {
165 setIndexQuickly(exec
->vm(), propertyName
, value
);
168 return putDirectIndexBeyondVectorLength(exec
, propertyName
, value
, attributes
, mode
);
170 bool putDirectIndex(ExecState
* exec
, unsigned propertyName
, JSValue value
)
172 return putDirectIndex(exec
, propertyName
, value
, 0, PutDirectIndexLikePutDirect
);
175 // A non-throwing version of putDirect and putDirectIndex.
176 JS_EXPORT_PRIVATE
void putDirectMayBeIndex(ExecState
*, PropertyName
, JSValue
);
178 bool hasIndexingHeader() const
180 return structure()->hasIndexingHeader(this);
183 bool canGetIndexQuickly(unsigned i
)
185 switch (indexingType()) {
186 case ALL_BLANK_INDEXING_TYPES
:
187 case ALL_UNDECIDED_INDEXING_TYPES
:
189 case ALL_INT32_INDEXING_TYPES
:
190 case ALL_CONTIGUOUS_INDEXING_TYPES
:
191 return i
< m_butterfly
->vectorLength() && m_butterfly
->contiguous()[i
];
192 case ALL_DOUBLE_INDEXING_TYPES
: {
193 if (i
>= m_butterfly
->vectorLength())
195 double value
= m_butterfly
->contiguousDouble()[i
];
200 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
201 return i
< m_butterfly
->arrayStorage()->vectorLength() && m_butterfly
->arrayStorage()->m_vector
[i
];
203 RELEASE_ASSERT_NOT_REACHED();
208 JSValue
getIndexQuickly(unsigned i
)
210 switch (indexingType()) {
211 case ALL_INT32_INDEXING_TYPES
:
212 return jsNumber(m_butterfly
->contiguous()[i
].get().asInt32());
213 case ALL_CONTIGUOUS_INDEXING_TYPES
:
214 return m_butterfly
->contiguous()[i
].get();
215 case ALL_DOUBLE_INDEXING_TYPES
:
216 return JSValue(JSValue::EncodeAsDouble
, m_butterfly
->contiguousDouble()[i
]);
217 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
218 return m_butterfly
->arrayStorage()->m_vector
[i
].get();
220 RELEASE_ASSERT_NOT_REACHED();
225 JSValue
tryGetIndexQuickly(unsigned i
)
227 switch (indexingType()) {
228 case ALL_BLANK_INDEXING_TYPES
:
229 case ALL_UNDECIDED_INDEXING_TYPES
:
231 case ALL_INT32_INDEXING_TYPES
:
232 if (i
< m_butterfly
->publicLength()) {
233 JSValue result
= m_butterfly
->contiguous()[i
].get();
234 ASSERT(result
.isInt32() || !result
);
238 case ALL_CONTIGUOUS_INDEXING_TYPES
:
239 if (i
< m_butterfly
->publicLength())
240 return m_butterfly
->contiguous()[i
].get();
242 case ALL_DOUBLE_INDEXING_TYPES
: {
243 if (i
>= m_butterfly
->publicLength())
245 double result
= m_butterfly
->contiguousDouble()[i
];
246 if (result
!= result
)
248 return JSValue(JSValue::EncodeAsDouble
, result
);
250 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
251 if (i
< m_butterfly
->arrayStorage()->vectorLength())
252 return m_butterfly
->arrayStorage()->m_vector
[i
].get();
255 RELEASE_ASSERT_NOT_REACHED();
261 JSValue
getDirectIndex(ExecState
* exec
, unsigned i
)
263 if (JSValue result
= tryGetIndexQuickly(i
))
265 PropertySlot
slot(this);
266 if (methodTable(exec
->vm())->getOwnPropertySlotByIndex(this, exec
, i
, slot
))
267 return slot
.getValue(exec
, i
);
271 JSValue
getIndex(ExecState
* exec
, unsigned i
)
273 if (JSValue result
= tryGetIndexQuickly(i
))
278 bool canSetIndexQuickly(unsigned i
)
280 switch (indexingType()) {
281 case ALL_BLANK_INDEXING_TYPES
:
282 case ALL_UNDECIDED_INDEXING_TYPES
:
284 case ALL_INT32_INDEXING_TYPES
:
285 case ALL_DOUBLE_INDEXING_TYPES
:
286 case ALL_CONTIGUOUS_INDEXING_TYPES
:
287 case NonArrayWithArrayStorage
:
288 case ArrayWithArrayStorage
:
289 return i
< m_butterfly
->vectorLength();
290 case NonArrayWithSlowPutArrayStorage
:
291 case ArrayWithSlowPutArrayStorage
:
292 return i
< m_butterfly
->arrayStorage()->vectorLength()
293 && !!m_butterfly
->arrayStorage()->m_vector
[i
];
295 RELEASE_ASSERT_NOT_REACHED();
300 bool canSetIndexQuicklyForPutDirect(unsigned i
)
302 switch (indexingType()) {
303 case ALL_BLANK_INDEXING_TYPES
:
304 case ALL_UNDECIDED_INDEXING_TYPES
:
306 case ALL_INT32_INDEXING_TYPES
:
307 case ALL_DOUBLE_INDEXING_TYPES
:
308 case ALL_CONTIGUOUS_INDEXING_TYPES
:
309 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
310 return i
< m_butterfly
->vectorLength();
312 RELEASE_ASSERT_NOT_REACHED();
317 void setIndexQuickly(VM
& vm
, unsigned i
, JSValue v
)
319 switch (indexingType()) {
320 case ALL_INT32_INDEXING_TYPES
: {
321 ASSERT(i
< m_butterfly
->vectorLength());
323 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm
, i
, v
);
328 case ALL_CONTIGUOUS_INDEXING_TYPES
: {
329 ASSERT(i
< m_butterfly
->vectorLength());
330 m_butterfly
->contiguous()[i
].set(vm
, this, v
);
331 if (i
>= m_butterfly
->publicLength())
332 m_butterfly
->setPublicLength(i
+ 1);
335 case ALL_DOUBLE_INDEXING_TYPES
: {
336 ASSERT(i
< m_butterfly
->vectorLength());
338 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
341 double value
= v
.asNumber();
342 if (value
!= value
) {
343 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
346 m_butterfly
->contiguousDouble()[i
] = value
;
347 if (i
>= m_butterfly
->publicLength())
348 m_butterfly
->setPublicLength(i
+ 1);
351 case ALL_ARRAY_STORAGE_INDEXING_TYPES
: {
352 ArrayStorage
* storage
= m_butterfly
->arrayStorage();
353 WriteBarrier
<Unknown
>& x
= storage
->m_vector
[i
];
354 JSValue old
= x
.get();
357 ++storage
->m_numValuesInVector
;
358 if (i
>= storage
->length())
359 storage
->setLength(i
+ 1);
364 RELEASE_ASSERT_NOT_REACHED();
368 void initializeIndex(VM
& vm
, unsigned i
, JSValue v
)
370 initializeIndex(vm
, i
, v
, indexingType());
373 void initializeIndex(VM
& vm
, unsigned i
, JSValue v
, IndexingType indexingType
)
375 switch (indexingType
) {
376 case ALL_UNDECIDED_INDEXING_TYPES
: {
377 setIndexQuicklyToUndecided(vm
, i
, v
);
380 case ALL_INT32_INDEXING_TYPES
: {
381 ASSERT(i
< m_butterfly
->publicLength());
382 ASSERT(i
< m_butterfly
->vectorLength());
384 convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(vm
, i
, v
);
389 case ALL_CONTIGUOUS_INDEXING_TYPES
: {
390 ASSERT(i
< m_butterfly
->publicLength());
391 ASSERT(i
< m_butterfly
->vectorLength());
392 m_butterfly
->contiguous()[i
].set(vm
, this, v
);
395 case ALL_DOUBLE_INDEXING_TYPES
: {
396 ASSERT(i
< m_butterfly
->publicLength());
397 ASSERT(i
< m_butterfly
->vectorLength());
399 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
402 double value
= v
.asNumber();
403 if (value
!= value
) {
404 convertDoubleToContiguousWhilePerformingSetIndex(vm
, i
, v
);
407 m_butterfly
->contiguousDouble()[i
] = value
;
410 case ALL_ARRAY_STORAGE_INDEXING_TYPES
: {
411 ArrayStorage
* storage
= m_butterfly
->arrayStorage();
412 ASSERT(i
< storage
->length());
413 ASSERT(i
< storage
->m_numValuesInVector
);
414 storage
->m_vector
[i
].set(vm
, this, v
);
418 RELEASE_ASSERT_NOT_REACHED();
424 switch (indexingType()) {
425 case ALL_BLANK_INDEXING_TYPES
:
426 case ALL_UNDECIDED_INDEXING_TYPES
:
427 case ALL_INT32_INDEXING_TYPES
:
428 case ALL_DOUBLE_INDEXING_TYPES
:
429 case ALL_CONTIGUOUS_INDEXING_TYPES
:
431 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
432 return !!m_butterfly
->arrayStorage()->m_sparseMap
;
434 RELEASE_ASSERT_NOT_REACHED();
439 bool inSparseIndexingMode()
441 switch (indexingType()) {
442 case ALL_BLANK_INDEXING_TYPES
:
443 case ALL_UNDECIDED_INDEXING_TYPES
:
444 case ALL_INT32_INDEXING_TYPES
:
445 case ALL_DOUBLE_INDEXING_TYPES
:
446 case ALL_CONTIGUOUS_INDEXING_TYPES
:
448 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
449 return m_butterfly
->arrayStorage()->inSparseMode();
451 RELEASE_ASSERT_NOT_REACHED();
456 void enterDictionaryIndexingMode(VM
&);
458 // putDirect is effectively an unchecked vesion of 'defineOwnProperty':
459 // - the prototype chain is not consulted
460 // - accessors are not called.
461 // - attributes will be respected (after the call the property will exist with the given attributes)
462 // - the property name is assumed to not be an index.
463 void putDirect(VM
&, PropertyName
, JSValue
, unsigned attributes
= 0);
464 void putDirect(VM
&, PropertyName
, JSValue
, PutPropertySlot
&);
465 void putDirectWithoutTransition(VM
&, PropertyName
, JSValue
, unsigned attributes
= 0);
466 void putDirectNonIndexAccessor(VM
&, PropertyName
, JSValue
, unsigned attributes
);
467 void putDirectAccessor(ExecState
*, PropertyName
, JSValue
, unsigned attributes
);
468 JS_EXPORT_PRIVATE
void putDirectCustomAccessor(VM
&, PropertyName
, JSValue
, unsigned attributes
);
470 void putGetter(ExecState
*, PropertyName
, JSValue
);
471 void putSetter(ExecState
*, PropertyName
, JSValue
);
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;
476 bool hasOwnProperty(ExecState
*, unsigned) const;
478 JS_EXPORT_PRIVATE
static bool deleteProperty(JSCell
*, ExecState
*, PropertyName
);
479 JS_EXPORT_PRIVATE
static bool deletePropertyByIndex(JSCell
*, ExecState
*, unsigned propertyName
);
481 JS_EXPORT_PRIVATE
static JSValue
defaultValue(const JSObject
*, ExecState
*, PreferredPrimitiveType
);
483 bool hasInstance(ExecState
*, JSValue
);
484 static bool defaultHasInstance(ExecState
*, JSValue
, JSValue prototypeProperty
);
486 JS_EXPORT_PRIVATE
static void getOwnPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
487 JS_EXPORT_PRIVATE
static void getOwnNonIndexPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
488 JS_EXPORT_PRIVATE
static void getPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
490 JS_EXPORT_PRIVATE
static uint32_t getEnumerableLength(ExecState
*, JSObject
*);
491 JS_EXPORT_PRIVATE
static void getStructurePropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
492 JS_EXPORT_PRIVATE
static void getGenericPropertyNames(JSObject
*, ExecState
*, PropertyNameArray
&, EnumerationMode
);
494 JSValue
toPrimitive(ExecState
*, PreferredPrimitiveType
= NoPreference
) const;
495 bool getPrimitiveNumber(ExecState
*, double& number
, JSValue
&) const;
496 JS_EXPORT_PRIVATE
double toNumber(ExecState
*) const;
497 JS_EXPORT_PRIVATE JSString
* toString(ExecState
*) const;
499 JS_EXPORT_PRIVATE
static JSValue
toThis(JSCell
*, ExecState
*, ECMAMode
);
501 // This get function only looks at the property map.
502 JSValue
getDirect(VM
& vm
, PropertyName propertyName
) const
504 Structure
* structure
= this->structure(vm
);
505 PropertyOffset offset
= structure
->get(vm
, propertyName
);
506 checkOffset(offset
, structure
->inlineCapacity());
507 return offset
!= invalidOffset
? getDirect(offset
) : JSValue();
510 JSValue
getDirect(VM
& vm
, PropertyName propertyName
, unsigned& attributes
) const
512 Structure
* structure
= this->structure(vm
);
513 PropertyOffset offset
= structure
->get(vm
, propertyName
, attributes
);
514 checkOffset(offset
, structure
->inlineCapacity());
515 return offset
!= invalidOffset
? getDirect(offset
) : JSValue();
518 PropertyOffset
getDirectOffset(VM
& vm
, PropertyName propertyName
)
520 Structure
* structure
= this->structure(vm
);
521 PropertyOffset offset
= structure
->get(vm
, propertyName
);
522 checkOffset(offset
, structure
->inlineCapacity());
526 PropertyOffset
getDirectOffset(VM
& vm
, PropertyName propertyName
, unsigned& attributes
)
528 Structure
* structure
= this->structure(vm
);
529 PropertyOffset offset
= structure
->get(vm
, propertyName
, attributes
);
530 checkOffset(offset
, structure
->inlineCapacity());
534 bool hasInlineStorage() const { return structure()->hasInlineStorage(); }
535 ConstPropertyStorage
inlineStorageUnsafe() const
537 return bitwise_cast
<ConstPropertyStorage
>(this + 1);
539 PropertyStorage
inlineStorageUnsafe()
541 return bitwise_cast
<PropertyStorage
>(this + 1);
543 ConstPropertyStorage
inlineStorage() const
545 ASSERT(hasInlineStorage());
546 return inlineStorageUnsafe();
548 PropertyStorage
inlineStorage()
550 ASSERT(hasInlineStorage());
551 return inlineStorageUnsafe();
554 const Butterfly
* butterfly() const { return m_butterfly
.get(); }
555 Butterfly
* butterfly() { return m_butterfly
.get(); }
557 ConstPropertyStorage
outOfLineStorage() const { return m_butterfly
->propertyStorage(); }
558 PropertyStorage
outOfLineStorage() { return m_butterfly
->propertyStorage(); }
560 const WriteBarrierBase
<Unknown
>* locationForOffset(PropertyOffset offset
) const
562 if (isInlineOffset(offset
))
563 return &inlineStorage()[offsetInInlineStorage(offset
)];
564 return &outOfLineStorage()[offsetInOutOfLineStorage(offset
)];
567 WriteBarrierBase
<Unknown
>* locationForOffset(PropertyOffset offset
)
569 if (isInlineOffset(offset
))
570 return &inlineStorage()[offsetInInlineStorage(offset
)];
571 return &outOfLineStorage()[offsetInOutOfLineStorage(offset
)];
574 void transitionTo(VM
&, Structure
*);
576 JS_EXPORT_PRIVATE
bool removeDirect(VM
&, PropertyName
); // Return true if anything is removed.
577 bool hasCustomProperties() { return structure()->didTransition(); }
578 bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
579 bool hasCustomGetterSetterProperties() { return structure()->hasCustomGetterSetterProperties(); }
581 // putOwnDataProperty has 'put' like semantics, however this method:
582 // - assumes the object contains no own getter/setter properties.
583 // - provides no special handling for __proto__
584 // - does not walk the prototype chain (to check for accessors or non-writable properties).
585 // This is used by JSLexicalEnvironment.
586 bool putOwnDataProperty(VM
&, PropertyName
, JSValue
, PutPropertySlot
&);
588 // Fast access to known property offsets.
589 JSValue
getDirect(PropertyOffset offset
) const { return locationForOffset(offset
)->get(); }
590 void putDirect(VM
& vm
, PropertyOffset offset
, JSValue value
) { locationForOffset(offset
)->set(vm
, this, value
); }
591 void putDirectUndefined(PropertyOffset offset
) { locationForOffset(offset
)->setUndefined(); }
593 JS_EXPORT_PRIVATE
void putDirectNativeFunction(VM
&, JSGlobalObject
*, const PropertyName
&, unsigned functionLength
, NativeFunction
, Intrinsic
, unsigned attributes
);
594 JS_EXPORT_PRIVATE JSFunction
* putDirectBuiltinFunction(VM
&, JSGlobalObject
*, const PropertyName
&, FunctionExecutable
*, unsigned attributes
);
595 JSFunction
* putDirectBuiltinFunctionWithoutTransition(VM
&, JSGlobalObject
*, const PropertyName
&, FunctionExecutable
*, unsigned attributes
);
596 JS_EXPORT_PRIVATE
void putDirectNativeFunctionWithoutTransition(VM
&, JSGlobalObject
*, const PropertyName
&, unsigned functionLength
, NativeFunction
, Intrinsic
, unsigned attributes
);
598 JS_EXPORT_PRIVATE
static bool defineOwnProperty(JSObject
*, ExecState
*, PropertyName
, const PropertyDescriptor
&, bool shouldThrow
);
600 bool isGlobalObject() const;
601 bool isVariableObject() const;
602 bool isStaticScopeObject() const;
603 bool isNameScopeObject() const;
604 bool isCatchScopeObject() const;
605 bool isFunctionNameScopeObject() const;
606 bool isActivationObject() const;
607 bool isErrorInstance() const;
608 bool isWithScope() const;
610 JS_EXPORT_PRIVATE
void seal(VM
&);
611 JS_EXPORT_PRIVATE
void freeze(VM
&);
612 JS_EXPORT_PRIVATE
void preventExtensions(VM
&);
613 bool isSealed(VM
& vm
) { return structure(vm
)->isSealed(vm
); }
614 bool isFrozen(VM
& vm
) { return structure(vm
)->isFrozen(vm
); }
615 bool isExtensible() { return structure()->isExtensible(); }
616 bool indexingShouldBeSparse()
618 return !isExtensible()
619 || structure()->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero();
622 bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
623 void reifyStaticFunctionsForDelete(ExecState
* exec
);
625 JS_EXPORT_PRIVATE Butterfly
* growOutOfLineStorage(VM
&, size_t oldSize
, size_t newSize
);
626 void setButterflyWithoutChangingStructure(VM
&, Butterfly
*);
628 void setStructure(VM
&, Structure
*);
629 void setStructureAndButterfly(VM
&, Structure
*, Butterfly
*);
630 void setStructureAndReallocateStorageIfNecessary(VM
&, unsigned oldCapacity
, Structure
*);
631 void setStructureAndReallocateStorageIfNecessary(VM
&, Structure
*);
633 void convertToDictionary(VM
& vm
)
635 setStructure(vm
, Structure::toCacheableDictionaryTransition(vm
, structure(vm
)));
638 void flattenDictionaryObject(VM
& vm
)
640 structure(vm
)->flattenDictionaryStructure(vm
, this);
642 void shiftButterflyAfterFlattening(VM
&, size_t outOfLineCapacityBefore
, size_t outOfLineCapacityAfter
);
644 JSGlobalObject
* globalObject() const
646 ASSERT(structure()->globalObject());
647 ASSERT(!isGlobalObject() || ((JSObject
*)structure()->globalObject()) == this);
648 return structure()->globalObject();
651 void switchToSlowPutArrayStorage(VM
&);
653 // The receiver is the prototype in this case. The following:
655 // asObject(foo->structure()->storedPrototype())->attemptToInterceptPutByIndexOnHoleForPrototype(...)
659 // foo->attemptToInterceptPutByIndexOnHole(...);
660 bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState
*, JSValue thisValue
, unsigned propertyName
, JSValue
, bool shouldThrow
);
662 // Returns 0 if int32 storage cannot be created - either because
663 // indexing should be sparse, we're having a bad time, or because
664 // we already have a more general form of storage (double,
665 // contiguous, array storage).
666 ContiguousJSValues
ensureInt32(VM
& vm
)
668 if (LIKELY(hasInt32(indexingType())))
669 return m_butterfly
->contiguousInt32();
671 return ensureInt32Slow(vm
);
674 // Returns 0 if double storage cannot be created - either because
675 // indexing should be sparse, we're having a bad time, or because
676 // we already have a more general form of storage (contiguous,
677 // or array storage).
678 ContiguousDoubles
ensureDouble(VM
& vm
)
680 if (LIKELY(hasDouble(indexingType())))
681 return m_butterfly
->contiguousDouble();
683 return ensureDoubleSlow(vm
);
686 // Returns 0 if contiguous storage cannot be created - either because
687 // indexing should be sparse or because we're having a bad time.
688 ContiguousJSValues
ensureContiguous(VM
& vm
)
690 if (LIKELY(hasContiguous(indexingType())))
691 return m_butterfly
->contiguous();
693 return ensureContiguousSlow(vm
);
696 // Ensure that the object is in a mode where it has array storage. Use
697 // this if you're about to perform actions that would have required the
698 // object to be converted to have array storage, if it didn't have it
700 ArrayStorage
* ensureArrayStorage(VM
& vm
)
702 if (LIKELY(hasAnyArrayStorage(indexingType())))
703 return m_butterfly
->arrayStorage();
705 return ensureArrayStorageSlow(vm
);
708 static size_t offsetOfInlineStorage();
710 static ptrdiff_t butterflyOffset()
712 return OBJECT_OFFSETOF(JSObject
, m_butterfly
);
715 void* butterflyAddress()
723 void finishCreation(VM
& vm
)
725 Base::finishCreation(vm
);
726 ASSERT(inherits(info()));
727 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
728 ASSERT(structure()->isObject());
732 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
734 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), info());
737 // To instantiate objects you likely want JSFinalObject, below.
738 // To create derived types you likely want JSNonFinalObject, below.
739 JSObject(VM
&, Structure
*, Butterfly
* = 0);
741 void visitButterfly(SlotVisitor
&, Butterfly
*, size_t storageSize
);
742 void copyButterfly(CopyVisitor
&, Butterfly
*, size_t storageSize
);
744 // Call this if you know that the object is in a mode where it has array
745 // storage. This will assert otherwise.
746 ArrayStorage
* arrayStorage()
748 ASSERT(hasAnyArrayStorage(indexingType()));
749 return m_butterfly
->arrayStorage();
752 // Call this if you want to predicate some actions on whether or not the
753 // object is in a mode where it has array storage.
754 ArrayStorage
* arrayStorageOrNull()
756 switch (indexingType()) {
757 case ALL_ARRAY_STORAGE_INDEXING_TYPES
:
758 return m_butterfly
->arrayStorage();
765 size_t butterflyTotalSize();
766 size_t butterflyPreCapacity();
768 Butterfly
* createInitialUndecided(VM
&, unsigned length
);
769 ContiguousJSValues
createInitialInt32(VM
&, unsigned length
);
770 ContiguousDoubles
createInitialDouble(VM
&, unsigned length
);
771 ContiguousJSValues
createInitialContiguous(VM
&, unsigned length
);
773 void convertUndecidedForValue(VM
&, JSValue
);
774 void createInitialForValueAndSet(VM
&, unsigned index
, JSValue
);
775 void convertInt32ForValue(VM
&, JSValue
);
777 ArrayStorage
* createArrayStorage(VM
&, unsigned length
, unsigned vectorLength
);
778 ArrayStorage
* createInitialArrayStorage(VM
&);
780 ContiguousJSValues
convertUndecidedToInt32(VM
&);
781 ContiguousDoubles
convertUndecidedToDouble(VM
&);
782 ContiguousJSValues
convertUndecidedToContiguous(VM
&);
783 ArrayStorage
* convertUndecidedToArrayStorage(VM
&, NonPropertyTransition
);
784 ArrayStorage
* convertUndecidedToArrayStorage(VM
&);
786 ContiguousDoubles
convertInt32ToDouble(VM
&);
787 ContiguousJSValues
convertInt32ToContiguous(VM
&);
788 ArrayStorage
* convertInt32ToArrayStorage(VM
&, NonPropertyTransition
);
789 ArrayStorage
* convertInt32ToArrayStorage(VM
&);
791 ContiguousJSValues
convertDoubleToContiguous(VM
&);
792 ArrayStorage
* convertDoubleToArrayStorage(VM
&, NonPropertyTransition
);
793 ArrayStorage
* convertDoubleToArrayStorage(VM
&);
795 ArrayStorage
* convertContiguousToArrayStorage(VM
&, NonPropertyTransition
);
796 ArrayStorage
* convertContiguousToArrayStorage(VM
&);
799 ArrayStorage
* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(VM
&);
801 bool defineOwnNonIndexProperty(ExecState
*, PropertyName
, const PropertyDescriptor
&, bool throwException
);
803 template<IndexingType indexingShape
>
804 void putByIndexBeyondVectorLengthWithoutAttributes(ExecState
*, unsigned propertyName
, JSValue
);
805 void putByIndexBeyondVectorLengthWithArrayStorage(ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
, ArrayStorage
*);
807 bool increaseVectorLength(VM
&, unsigned newLength
);
808 void deallocateSparseIndexMap();
809 bool defineOwnIndexedProperty(ExecState
*, unsigned, const PropertyDescriptor
&, bool throwException
);
810 SparseArrayValueMap
* allocateSparseIndexMap(VM
&);
812 void notifyPresenceOfIndexedAccessors(VM
&);
814 bool attemptToInterceptPutByIndexOnHole(ExecState
*, unsigned index
, JSValue
, bool shouldThrow
);
816 // Call this if you want setIndexQuickly to succeed and you're sure that
817 // the array is contiguous.
818 void ensureLength(VM
& vm
, unsigned length
)
820 ASSERT(length
< MAX_ARRAY_INDEX
);
821 ASSERT(hasContiguous(indexingType()) || hasInt32(indexingType()) || hasDouble(indexingType()) || hasUndecided(indexingType()));
823 if (m_butterfly
->vectorLength() < length
)
824 ensureLengthSlow(vm
, length
);
826 if (m_butterfly
->publicLength() < length
)
827 m_butterfly
->setPublicLength(length
);
830 // Call this if you want to shrink the butterfly backing store, and you're
831 // sure that the array is contiguous.
832 void reallocateAndShrinkButterfly(VM
&, unsigned length
);
834 template<IndexingType indexingShape
>
835 unsigned countElements(Butterfly
*);
837 // This is relevant to undecided, int32, double, and contiguous.
838 unsigned countElements();
841 friend class LLIntOffsetsExtractor
;
843 // Nobody should ever ask any of these questions on something already known to be a JSObject.
844 using JSCell::isAPIValueWrapper
;
845 using JSCell::isGetterSetter
;
847 void getString(ExecState
* exec
);
851 Butterfly
* createInitialIndexedStorage(VM
&, unsigned length
, size_t elementSize
);
853 ArrayStorage
* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM
&, ArrayStorage
*);
856 bool putDirectInternal(VM
&, PropertyName
, JSValue
, unsigned attr
, PutPropertySlot
&);
858 bool inlineGetOwnPropertySlot(VM
&, Structure
&, PropertyName
, PropertySlot
&);
859 JS_EXPORT_PRIVATE
void fillGetterPropertySlot(PropertySlot
&, JSValue
, unsigned, PropertyOffset
);
860 void fillCustomGetterPropertySlot(PropertySlot
&, JSValue
, unsigned, Structure
&);
862 const HashTableValue
* findPropertyHashEntry(PropertyName
) const;
864 void putIndexedDescriptor(ExecState
*, SparseArrayEntry
*, const PropertyDescriptor
&, PropertyDescriptor
& old
);
866 void putByIndexBeyondVectorLength(ExecState
*, unsigned propertyName
, JSValue
, bool shouldThrow
);
867 bool putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState
*, unsigned propertyName
, JSValue
, unsigned attributes
, PutDirectIndexMode
, ArrayStorage
*);
868 JS_EXPORT_PRIVATE
bool putDirectIndexBeyondVectorLength(ExecState
*, unsigned propertyName
, JSValue
, unsigned attributes
, PutDirectIndexMode
);
870 unsigned getNewVectorLength(unsigned currentVectorLength
, unsigned currentLength
, unsigned desiredLength
);
871 unsigned getNewVectorLength(unsigned desiredLength
);
873 ArrayStorage
* constructConvertedArrayStorageWithoutCopyingElements(VM
&, unsigned neededLength
);
875 JS_EXPORT_PRIVATE
void setIndexQuicklyToUndecided(VM
&, unsigned index
, JSValue
);
876 JS_EXPORT_PRIVATE
void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(VM
&, unsigned index
, JSValue
);
877 JS_EXPORT_PRIVATE
void convertDoubleToContiguousWhilePerformingSetIndex(VM
&, unsigned index
, JSValue
);
879 void ensureLengthSlow(VM
&, unsigned length
);
881 ContiguousJSValues
ensureInt32Slow(VM
&);
882 ContiguousDoubles
ensureDoubleSlow(VM
&);
883 ContiguousJSValues
ensureContiguousSlow(VM
&);
884 JS_EXPORT_PRIVATE ArrayStorage
* ensureArrayStorageSlow(VM
&);
887 CopyWriteBarrier
<Butterfly
> m_butterfly
;
888 #if USE(JSVALUE32_64)
894 // JSNonFinalObject is a type of JSObject that has some internal storage,
895 // but also preserves some space in the collector cell for additional
896 // data members in derived types.
897 class JSNonFinalObject
: public JSObject
{
898 friend class JSObject
;
901 typedef JSObject Base
;
903 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
)
905 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(ObjectType
, StructureFlags
), info());
909 explicit JSNonFinalObject(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
= 0)
910 : JSObject(vm
, structure
, butterfly
)
914 void finishCreation(VM
& vm
)
916 Base::finishCreation(vm
);
917 ASSERT(!this->structure()->hasInlineStorage());
924 // JSFinalObject is a type of JSObject that contains sufficent internal
925 // storage to fully make use of the colloctor cell containing it.
926 class JSFinalObject
: public JSObject
{
927 friend class JSObject
;
930 typedef JSObject Base
;
931 static const unsigned StructureFlags
= Base::StructureFlags
;
933 static size_t allocationSize(size_t inlineCapacity
)
935 return sizeof(JSObject
) + inlineCapacity
* sizeof(WriteBarrierBase
<Unknown
>);
938 static const unsigned defaultSize
= 64;
939 static inline unsigned defaultInlineCapacity()
941 return (defaultSize
- allocationSize(0)) / sizeof(WriteBarrier
<Unknown
>);
944 static const unsigned maxSize
= 512;
945 static inline unsigned maxInlineCapacity()
947 return (maxSize
- allocationSize(0)) / sizeof(WriteBarrier
<Unknown
>);
950 static JSFinalObject
* create(ExecState
*, Structure
*, Butterfly
* = nullptr);
951 static JSFinalObject
* create(VM
&, Structure
*);
952 static Structure
* createStructure(VM
& vm
, JSGlobalObject
* globalObject
, JSValue prototype
, unsigned inlineCapacity
)
954 return Structure::create(vm
, globalObject
, prototype
, TypeInfo(FinalObjectType
, StructureFlags
), info(), NonArray
, inlineCapacity
);
957 JS_EXPORT_PRIVATE
static void visitChildren(JSCell
*, SlotVisitor
&);
962 void visitChildrenCommon(SlotVisitor
&);
964 void finishCreation(VM
& vm
)
966 Base::finishCreation(vm
);
967 ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity());
972 friend class LLIntOffsetsExtractor
;
974 explicit JSFinalObject(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
= nullptr)
975 : JSObject(vm
, structure
, butterfly
)
980 inline JSFinalObject
* JSFinalObject::create(
981 ExecState
* exec
, Structure
* structure
, Butterfly
* butterfly
)
983 JSFinalObject
* finalObject
= new (
985 allocateCell
<JSFinalObject
>(
987 allocationSize(structure
->inlineCapacity())
989 ) JSFinalObject(exec
->vm(), structure
, butterfly
);
990 finalObject
->finishCreation(exec
->vm());
994 inline JSFinalObject
* JSFinalObject::create(VM
& vm
, Structure
* structure
)
996 JSFinalObject
* finalObject
= new (NotNull
, allocateCell
<JSFinalObject
>(vm
.heap
, allocationSize(structure
->inlineCapacity()))) JSFinalObject(vm
, structure
);
997 finalObject
->finishCreation(vm
);
1001 inline bool isJSFinalObject(JSCell
* cell
)
1003 return cell
->classInfo() == JSFinalObject::info();
1006 inline bool isJSFinalObject(JSValue value
)
1008 return value
.isCell() && isJSFinalObject(value
.asCell());
1011 inline size_t JSObject::offsetOfInlineStorage()
1013 return sizeof(JSObject
);
1016 inline bool JSObject::isGlobalObject() const
1018 return type() == GlobalObjectType
;
1021 inline bool JSObject::isVariableObject() const
1023 return type() == GlobalObjectType
|| type() == ActivationObjectType
;
1026 inline bool JSObject::isStaticScopeObject() const
1028 JSType type
= this->type();
1029 return type
== NameScopeObjectType
|| type
== ActivationObjectType
;
1032 inline bool JSObject::isNameScopeObject() const
1034 return type() == NameScopeObjectType
;
1037 inline bool JSObject::isActivationObject() const
1039 return type() == ActivationObjectType
;
1042 inline bool JSObject::isErrorInstance() const
1044 return type() == ErrorInstanceType
;
1047 inline bool JSObject::isWithScope() const
1049 return type() == WithScopeType
;
1052 inline void JSObject::setStructureAndButterfly(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
)
1055 ASSERT(!butterfly
== (!structure
->outOfLineCapacity() && !structure
->hasIndexingHeader(this)));
1056 m_butterfly
.set(vm
, this, butterfly
);
1057 setStructure(vm
, structure
);
1060 inline void JSObject::setStructure(VM
& vm
, Structure
* structure
)
1063 ASSERT(!m_butterfly
== !(structure
->outOfLineCapacity() || structure
->hasIndexingHeader(this)));
1064 JSCell::setStructure(vm
, structure
);
1067 inline void JSObject::setButterflyWithoutChangingStructure(VM
& vm
, Butterfly
* butterfly
)
1069 m_butterfly
.set(vm
, this, butterfly
);
1072 inline CallType
getCallData(JSValue value
, CallData
& callData
)
1074 CallType result
= value
.isCell() ? value
.asCell()->methodTable()->getCallData(value
.asCell(), callData
) : CallTypeNone
;
1075 ASSERT(result
== CallTypeNone
|| value
.isValidCallee());
1079 inline ConstructType
getConstructData(JSValue value
, ConstructData
& constructData
)
1081 ConstructType result
= value
.isCell() ? value
.asCell()->methodTable()->getConstructData(value
.asCell(), constructData
) : ConstructTypeNone
;
1082 ASSERT(result
== ConstructTypeNone
|| value
.isValidCallee());
1086 inline JSObject
* asObject(JSCell
* cell
)
1088 ASSERT(cell
->isObject());
1089 return jsCast
<JSObject
*>(cell
);
1092 inline JSObject
* asObject(JSValue value
)
1094 return asObject(value
.asCell());
1097 inline JSObject::JSObject(VM
& vm
, Structure
* structure
, Butterfly
* butterfly
)
1098 : JSCell(vm
, structure
)
1099 , m_butterfly(vm
, this, butterfly
)
1101 vm
.heap
.ascribeOwner(this, butterfly
);
1104 inline JSValue
JSObject::prototype() const
1106 return structure()->storedPrototype();
1109 ALWAYS_INLINE
bool JSObject::inlineGetOwnPropertySlot(VM
& vm
, Structure
& structure
, PropertyName propertyName
, PropertySlot
& slot
)
1111 unsigned attributes
;
1112 PropertyOffset offset
= structure
.get(vm
, propertyName
, attributes
);
1113 if (!isValidOffset(offset
))
1116 JSValue value
= getDirect(offset
);
1117 if (structure
.hasGetterSetterProperties() && value
.isGetterSetter())
1118 fillGetterPropertySlot(slot
, value
, attributes
, offset
);
1119 else if (structure
.hasCustomGetterSetterProperties() && value
.isCustomGetterSetter())
1120 fillCustomGetterPropertySlot(slot
, value
, attributes
, structure
);
1122 slot
.setValue(this, attributes
, value
, offset
);
1127 ALWAYS_INLINE
void JSObject::fillCustomGetterPropertySlot(PropertySlot
& slot
, JSValue customGetterSetter
, unsigned attributes
, Structure
& structure
)
1129 if (structure
.isDictionary()) {
1130 slot
.setCustom(this, attributes
, jsCast
<CustomGetterSetter
*>(customGetterSetter
)->getter());
1133 slot
.setCacheableCustom(this, attributes
, jsCast
<CustomGetterSetter
*>(customGetterSetter
)->getter());
1136 // It may seem crazy to inline a function this large, especially a virtual function,
1137 // but it makes a big difference to property lookup that derived classes can inline their
1138 // base class call to this.
1139 ALWAYS_INLINE
bool JSObject::getOwnPropertySlot(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
1141 VM
& vm
= exec
->vm();
1142 Structure
& structure
= *object
->structure(vm
);
1143 if (object
->inlineGetOwnPropertySlot(vm
, structure
, propertyName
, slot
))
1145 if (Optional
<uint32_t> index
= parseIndex(propertyName
))
1146 return getOwnPropertySlotByIndex(object
, exec
, index
.value(), slot
);
1150 ALWAYS_INLINE
bool JSObject::fastGetOwnPropertySlot(ExecState
* exec
, VM
& vm
, Structure
& structure
, PropertyName propertyName
, PropertySlot
& slot
)
1152 if (LIKELY(!TypeInfo::overridesGetOwnPropertySlot(inlineTypeFlags())))
1153 return inlineGetOwnPropertySlot(vm
, structure
, propertyName
, slot
);
1154 return structure
.classInfo()->methodTable
.getOwnPropertySlot(this, exec
, propertyName
, slot
);
1157 // It may seem crazy to inline a function this large but it makes a big difference
1158 // since this is function very hot in variable lookup
1159 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
1161 VM
& vm
= exec
->vm();
1162 auto& structureIDTable
= vm
.heap
.structureIDTable();
1163 JSObject
* object
= this;
1165 Structure
& structure
= *structureIDTable
.get(object
->structureID());
1166 if (object
->fastGetOwnPropertySlot(exec
, vm
, structure
, propertyName
, slot
))
1168 JSValue prototype
= structure
.storedPrototype();
1169 if (!prototype
.isObject())
1171 object
= asObject(prototype
);
1174 if (Optional
<uint32_t> index
= parseIndex(propertyName
))
1175 return getPropertySlot(exec
, index
.value(), slot
);
1179 ALWAYS_INLINE
bool JSObject::getPropertySlot(ExecState
* exec
, unsigned propertyName
, PropertySlot
& slot
)
1181 VM
& vm
= exec
->vm();
1182 auto& structureIDTable
= vm
.heap
.structureIDTable();
1183 JSObject
* object
= this;
1185 Structure
& structure
= *structureIDTable
.get(object
->structureID());
1186 if (structure
.classInfo()->methodTable
.getOwnPropertySlotByIndex(object
, exec
, propertyName
, slot
))
1188 JSValue prototype
= structure
.storedPrototype();
1189 if (!prototype
.isObject())
1191 object
= asObject(prototype
);
1195 inline JSValue
JSObject::get(ExecState
* exec
, PropertyName propertyName
) const
1197 PropertySlot
slot(this);
1198 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
1199 return slot
.getValue(exec
, propertyName
);
1201 return jsUndefined();
1204 inline JSValue
JSObject::get(ExecState
* exec
, unsigned propertyName
) const
1206 PropertySlot
slot(this);
1207 if (const_cast<JSObject
*>(this)->getPropertySlot(exec
, propertyName
, slot
))
1208 return slot
.getValue(exec
, propertyName
);
1210 return jsUndefined();
1213 template<JSObject::PutMode mode
>
1214 inline bool JSObject::putDirectInternal(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
, PutPropertySlot
& slot
)
1217 ASSERT(value
.isGetterSetter() == !!(attributes
& Accessor
));
1218 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
1219 ASSERT(!parseIndex(propertyName
));
1221 Structure
* structure
= this->structure(vm
);
1222 if (structure
->isDictionary()) {
1223 unsigned currentAttributes
;
1224 PropertyOffset offset
= structure
->get(vm
, propertyName
, currentAttributes
);
1225 if (offset
!= invalidOffset
) {
1226 if ((mode
== PutModePut
) && currentAttributes
& ReadOnly
)
1229 putDirect(vm
, offset
, value
);
1230 structure
->didReplaceProperty(offset
);
1231 slot
.setExistingProperty(this, offset
);
1233 if ((attributes
& Accessor
) != (currentAttributes
& Accessor
)) {
1234 ASSERT(!(attributes
& ReadOnly
));
1235 setStructure(vm
, Structure::attributeChangeTransition(vm
, structure
, propertyName
, attributes
));
1240 if ((mode
== PutModePut
) && !isExtensible())
1243 DeferGC
deferGC(vm
.heap
);
1244 Butterfly
* newButterfly
= butterfly();
1245 if (this->structure()->putWillGrowOutOfLineStorage())
1246 newButterfly
= growOutOfLineStorage(vm
, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity());
1247 offset
= this->structure()->addPropertyWithoutTransition(vm
, propertyName
, attributes
);
1248 setStructureAndButterfly(vm
, this->structure(), newButterfly
);
1250 validateOffset(offset
);
1251 ASSERT(this->structure()->isValidOffset(offset
));
1252 putDirect(vm
, offset
, value
);
1253 slot
.setNewProperty(this, offset
);
1254 if (attributes
& ReadOnly
)
1255 this->structure()->setContainsReadOnlyProperties();
1259 PropertyOffset offset
;
1260 size_t currentCapacity
= this->structure()->outOfLineCapacity();
1261 if (Structure
* structure
= Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName
, attributes
, offset
)) {
1262 DeferGC
deferGC(vm
.heap
);
1263 Butterfly
* newButterfly
= butterfly();
1264 if (currentCapacity
!= structure
->outOfLineCapacity()) {
1265 ASSERT(structure
!= this->structure());
1266 newButterfly
= growOutOfLineStorage(vm
, currentCapacity
, structure
->outOfLineCapacity());
1269 validateOffset(offset
);
1270 ASSERT(structure
->isValidOffset(offset
));
1271 setStructureAndButterfly(vm
, structure
, newButterfly
);
1272 putDirect(vm
, offset
, value
);
1273 slot
.setNewProperty(this, offset
);
1277 unsigned currentAttributes
;
1278 offset
= structure
->get(vm
, propertyName
, currentAttributes
);
1279 if (offset
!= invalidOffset
) {
1280 if ((mode
== PutModePut
) && currentAttributes
& ReadOnly
)
1283 structure
->didReplaceProperty(offset
);
1284 slot
.setExistingProperty(this, offset
);
1285 putDirect(vm
, offset
, value
);
1287 if ((attributes
& Accessor
) != (currentAttributes
& Accessor
)) {
1288 ASSERT(!(attributes
& ReadOnly
));
1289 setStructure(vm
, Structure::attributeChangeTransition(vm
, structure
, propertyName
, attributes
));
1294 if ((mode
== PutModePut
) && !isExtensible())
1297 structure
= Structure::addPropertyTransition(vm
, structure
, propertyName
, attributes
, offset
, slot
.context());
1299 validateOffset(offset
);
1300 ASSERT(structure
->isValidOffset(offset
));
1301 setStructureAndReallocateStorageIfNecessary(vm
, structure
);
1303 putDirect(vm
, offset
, value
);
1304 slot
.setNewProperty(this, offset
);
1305 if (attributes
& ReadOnly
)
1306 structure
->setContainsReadOnlyProperties();
1310 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM
& vm
, unsigned oldCapacity
, Structure
* newStructure
)
1312 ASSERT(oldCapacity
<= newStructure
->outOfLineCapacity());
1314 if (oldCapacity
== newStructure
->outOfLineCapacity()) {
1315 setStructure(vm
, newStructure
);
1319 DeferGC
deferGC(vm
.heap
);
1320 Butterfly
* newButterfly
= growOutOfLineStorage(
1321 vm
, oldCapacity
, newStructure
->outOfLineCapacity());
1322 setStructureAndButterfly(vm
, newStructure
, newButterfly
);
1325 inline void JSObject::setStructureAndReallocateStorageIfNecessary(VM
& vm
, Structure
* newStructure
)
1327 setStructureAndReallocateStorageIfNecessary(
1328 vm
, structure(vm
)->outOfLineCapacity(), newStructure
);
1331 inline bool JSObject::putOwnDataProperty(VM
& vm
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
1334 ASSERT(!Heap::heap(value
) || Heap::heap(value
) == Heap::heap(this));
1335 ASSERT(!structure()->hasGetterSetterProperties());
1336 ASSERT(!structure()->hasCustomGetterSetterProperties());
1338 return putDirectInternal
<PutModePut
>(vm
, propertyName
, value
, 0, slot
);
1341 inline void JSObject::putDirect(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
1343 ASSERT(!value
.isGetterSetter() && !(attributes
& Accessor
));
1344 ASSERT(!value
.isCustomGetterSetter());
1345 PutPropertySlot
slot(this);
1346 putDirectInternal
<PutModeDefineOwnProperty
>(vm
, propertyName
, value
, attributes
, slot
);
1349 inline void JSObject::putDirect(VM
& vm
, PropertyName propertyName
, JSValue value
, PutPropertySlot
& slot
)
1351 ASSERT(!value
.isGetterSetter());
1352 ASSERT(!value
.isCustomGetterSetter());
1353 putDirectInternal
<PutModeDefineOwnProperty
>(vm
, propertyName
, value
, 0, slot
);
1356 inline void JSObject::putDirectWithoutTransition(VM
& vm
, PropertyName propertyName
, JSValue value
, unsigned attributes
)
1358 DeferGC
deferGC(vm
.heap
);
1359 ASSERT(!value
.isGetterSetter() && !(attributes
& Accessor
));
1360 ASSERT(!value
.isCustomGetterSetter());
1361 Butterfly
* newButterfly
= m_butterfly
.get();
1362 if (structure()->putWillGrowOutOfLineStorage())
1363 newButterfly
= growOutOfLineStorage(vm
, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity());
1364 PropertyOffset offset
= structure()->addPropertyWithoutTransition(vm
, propertyName
, attributes
);
1365 setStructureAndButterfly(vm
, structure(), newButterfly
);
1366 putDirect(vm
, offset
, value
);
1369 inline JSValue
JSObject::toPrimitive(ExecState
* exec
, PreferredPrimitiveType preferredType
) const
1371 return methodTable()->defaultValue(this, exec
, preferredType
);
1374 ALWAYS_INLINE JSObject
* Register::object() const
1376 return asObject(jsValue());
1379 ALWAYS_INLINE Register
& Register::operator=(JSObject
* object
)
1381 u
.value
= JSValue::encode(JSValue(object
));
1385 inline size_t offsetInButterfly(PropertyOffset offset
)
1387 return offsetInOutOfLineStorage(offset
) + Butterfly::indexOfPropertyStorage();
1390 inline size_t JSObject::butterflyPreCapacity()
1392 if (UNLIKELY(hasIndexingHeader()))
1393 return butterfly()->indexingHeader()->preCapacity(structure());
1397 inline size_t JSObject::butterflyTotalSize()
1399 Structure
* structure
= this->structure();
1400 Butterfly
* butterfly
= this->butterfly();
1402 size_t indexingPayloadSizeInBytes
;
1403 bool hasIndexingHeader
= this->hasIndexingHeader();
1405 if (UNLIKELY(hasIndexingHeader
)) {
1406 preCapacity
= butterfly
->indexingHeader()->preCapacity(structure
);
1407 indexingPayloadSizeInBytes
= butterfly
->indexingHeader()->indexingPayloadSizeInBytes(structure
);
1410 indexingPayloadSizeInBytes
= 0;
1413 return Butterfly::totalSize(preCapacity
, structure
->outOfLineCapacity(), hasIndexingHeader
, indexingPayloadSizeInBytes
);
1416 // Helpers for patching code where you want to emit a load or store and
1418 // For inline offsets: a pointer to the out-of-line storage pointer.
1419 // For out-of-line offsets: the base of the out-of-line storage.
1420 inline size_t offsetRelativeToPatchedStorage(PropertyOffset offset
)
1422 if (isOutOfLineOffset(offset
))
1423 return sizeof(EncodedJSValue
) * offsetInButterfly(offset
);
1424 return JSObject::offsetOfInlineStorage() - JSObject::butterflyOffset() + sizeof(EncodedJSValue
) * offsetInInlineStorage(offset
);
1427 // Returns the maximum offset (away from zero) a load instruction will encode.
1428 inline size_t maxOffsetRelativeToPatchedStorage(PropertyOffset offset
)
1430 ptrdiff_t addressOffset
= static_cast<ptrdiff_t>(offsetRelativeToPatchedStorage(offset
));
1431 #if USE(JSVALUE32_64)
1432 if (addressOffset
>= 0)
1433 return static_cast<size_t>(addressOffset
) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
);
1435 return static_cast<size_t>(addressOffset
);
1438 inline int indexRelativeToBase(PropertyOffset offset
)
1440 if (isOutOfLineOffset(offset
))
1441 return offsetInOutOfLineStorage(offset
) + Butterfly::indexOfPropertyStorage();
1442 ASSERT(!(JSObject::offsetOfInlineStorage() % sizeof(EncodedJSValue
)));
1443 return JSObject::offsetOfInlineStorage() / sizeof(EncodedJSValue
) + offsetInInlineStorage(offset
);
1446 inline int offsetRelativeToBase(PropertyOffset offset
)
1448 if (isOutOfLineOffset(offset
))
1449 return offsetInOutOfLineStorage(offset
) * sizeof(EncodedJSValue
) + Butterfly::offsetOfPropertyStorage();
1450 return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset
) * sizeof(EncodedJSValue
);
1453 COMPILE_ASSERT(!(sizeof(JSObject
) % sizeof(WriteBarrierBase
<Unknown
>)), JSObject_inline_storage_has_correct_alignment
);
1455 ALWAYS_INLINE Identifier
makeIdentifier(VM
& vm
, const char* name
)
1457 return Identifier::fromString(&vm
, name
);
1460 ALWAYS_INLINE Identifier
makeIdentifier(VM
&, const Identifier
& name
)
1465 // Helper for defining native functions, if you're not using a static hash table.
1466 // Use this macro from within finishCreation() methods in prototypes. This assumes
1467 // you've defined variables called exec, globalObject, and vm, and they
1468 // have the expected meanings.
1469 #define JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, attributes, length, intrinsic) \
1470 putDirectNativeFunction(\
1471 vm, globalObject, makeIdentifier(vm, (jsName)), (length), cppName, \
1472 (intrinsic), (attributes))
1474 // As above, but this assumes that the function you're defining doesn't have an
1476 #define JSC_NATIVE_FUNCTION(jsName, cppName, attributes, length) \
1477 JSC_NATIVE_INTRINSIC_FUNCTION(jsName, cppName, (attributes), (length), NoIntrinsic)
1479 // Identical helpers but for builtins. Note that currently, we don't support builtins that are
1480 // also intrinsics, but we probably will do that eventually.
1481 #define JSC_BUILTIN_FUNCTION(jsName, generatorName, attributes) \
1482 putDirectBuiltinFunction(\
1483 vm, globalObject, makeIdentifier(vm, (jsName)), (generatorName)(vm), (attributes))
1487 #endif // JSObject_h