summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSObject.h')
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h235
1 files changed, 200 insertions, 35 deletions
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 82455390f..4f7f4700b 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -39,6 +39,7 @@
#include "Structure.h"
#include "JSGlobalData.h"
#include "JSString.h"
+#include "SlotVisitorInlines.h"
#include "SparseArrayValueMap.h"
#include <wtf/StdLibExtras.h>
@@ -151,30 +152,16 @@ public:
unsigned getArrayLength() const
{
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
+ if (!hasIndexedProperties(structure()->indexingType()))
return 0;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->publicLength();
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ return m_butterfly->publicLength();
}
unsigned getVectorLength()
{
- switch (structure()->indexingType()) {
- case ALL_BLANK_INDEXING_TYPES:
+ if (!hasIndexedProperties(structure()->indexingType()))
return 0;
- case ALL_CONTIGUOUS_INDEXING_TYPES:
- case ALL_ARRAY_STORAGE_INDEXING_TYPES:
- return m_butterfly->vectorLength();
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ return m_butterfly->vectorLength();
}
JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
@@ -214,9 +201,19 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i];
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (i >= m_butterfly->vectorLength())
+ return false;
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value != value)
+ return false;
+ return true;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i];
default:
@@ -228,8 +225,11 @@ public:
JSValue getIndexQuickly(unsigned i)
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous()[i].get();
+ case ALL_DOUBLE_INDEXING_TYPES:
+ return JSValue(JSValue::EncodeAsDouble, m_butterfly->contiguousDouble()[i]);
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return m_butterfly->arrayStorage()->m_vector[i].get();
default:
@@ -242,11 +242,21 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
break;
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
if (i < m_butterfly->publicLength())
return m_butterfly->contiguous()[i].get();
break;
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ if (i >= m_butterfly->publicLength())
+ break;
+ double result = m_butterfly->contiguousDouble()[i];
+ if (result != result)
+ break;
+ return JSValue(JSValue::EncodeAsDouble, result);
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
if (i < m_butterfly->arrayStorage()->vectorLength())
return m_butterfly->arrayStorage()->m_vector[i].get();
@@ -279,7 +289,10 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case NonArrayWithArrayStorage:
case ArrayWithArrayStorage:
@@ -298,7 +311,10 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
return false;
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
return i < m_butterfly->vectorLength();
@@ -311,6 +327,14 @@ public:
void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isInt32()) {
+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ // Fall through to contiguous case.
+ }
case ALL_CONTIGUOUS_INDEXING_TYPES: {
ASSERT(i < m_butterfly->vectorLength());
m_butterfly->contiguous()[i].set(globalData, this, v);
@@ -318,6 +342,22 @@ public:
m_butterfly->setPublicLength(i + 1);
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isNumber()) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ double value = v.asNumber();
+ if (value != value) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ m_butterfly->contiguousDouble()[i] = value;
+ if (i >= m_butterfly->publicLength())
+ m_butterfly->setPublicLength(i + 1);
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
WriteBarrier<Unknown>& x = storage->m_vector[i];
@@ -338,12 +378,40 @@ public:
void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
{
switch (structure()->indexingType()) {
+ case ALL_UNDECIDED_INDEXING_TYPES: {
+ setIndexQuicklyToUndecided(globalData, i, v);
+ break;
+ }
+ case ALL_INT32_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->publicLength());
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isInt32()) {
+ convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(globalData, i, v);
+ break;
+ }
+ // Fall through.
+ }
case ALL_CONTIGUOUS_INDEXING_TYPES: {
ASSERT(i < m_butterfly->publicLength());
ASSERT(i < m_butterfly->vectorLength());
m_butterfly->contiguous()[i].set(globalData, this, v);
break;
}
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ ASSERT(i < m_butterfly->publicLength());
+ ASSERT(i < m_butterfly->vectorLength());
+ if (!v.isNumber()) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ double value = v.asNumber();
+ if (value != value) {
+ convertDoubleToContiguousWhilePerformingSetIndex(globalData, i, v);
+ return;
+ }
+ m_butterfly->contiguousDouble()[i] = value;
+ break;
+ }
case ALL_ARRAY_STORAGE_INDEXING_TYPES: {
ArrayStorage* storage = m_butterfly->arrayStorage();
ASSERT(i < storage->length());
@@ -360,6 +428,9 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -374,6 +445,9 @@ public:
{
switch (structure()->indexingType()) {
case ALL_BLANK_INDEXING_TYPES:
+ case ALL_UNDECIDED_INDEXING_TYPES:
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return false;
case ALL_ARRAY_STORAGE_INDEXING_TYPES:
@@ -571,6 +645,30 @@ public:
// foo->attemptToInterceptPutByIndexOnHole(...);
bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow);
+ // Returns 0 if int32 storage cannot be created - either because
+ // indexing should be sparse, we're having a bad time, or because
+ // we already have a more general form of storage (double,
+ // contiguous, array storage).
+ WriteBarrier<Unknown>* ensureInt32(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasInt32(structure()->indexingType())))
+ return m_butterfly->contiguousInt32();
+
+ return ensureInt32Slow(globalData);
+ }
+
+ // Returns 0 if double storage cannot be created - either because
+ // indexing should be sparse, we're having a bad time, or because
+ // we already have a more general form of storage (contiguous,
+ // or array storage).
+ double* ensureDouble(JSGlobalData& globalData)
+ {
+ if (LIKELY(hasDouble(structure()->indexingType())))
+ return m_butterfly->contiguousDouble();
+
+ return ensureDoubleSlow(globalData);
+ }
+
// Returns 0 if contiguous storage cannot be created - either because
// indexing should be sparse or because we're having a bad time.
WriteBarrier<Unknown>* ensureContiguous(JSGlobalData& globalData)
@@ -593,14 +691,6 @@ public:
return ensureArrayStorageSlow(globalData);
}
- Butterfly* ensureIndexedStorage(JSGlobalData& globalData)
- {
- if (LIKELY(hasIndexedProperties(structure()->indexingType())))
- return m_butterfly;
-
- return ensureIndexedStorageSlow(globalData);
- }
-
static size_t offsetOfInlineStorage();
static ptrdiff_t butterflyOffset()
@@ -661,19 +751,47 @@ protected:
return 0;
}
}
-
+
+ Butterfly* createInitialUndecided(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* createInitialInt32(JSGlobalData&, unsigned length);
+ double* createInitialDouble(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length);
+
+ void convertUndecidedForValue(JSGlobalData&, JSValue);
+ void convertInt32ForValue(JSGlobalData&, JSValue);
+
ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength);
ArrayStorage* createInitialArrayStorage(JSGlobalData&);
- WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length);
+
+ WriteBarrier<Unknown>* convertUndecidedToInt32(JSGlobalData&);
+ double* convertUndecidedToDouble(JSGlobalData&);
+ WriteBarrier<Unknown>* convertUndecidedToContiguous(JSGlobalData&);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertUndecidedToArrayStorage(JSGlobalData&);
+
+ double* convertInt32ToDouble(JSGlobalData&);
+ WriteBarrier<Unknown>* convertInt32ToContiguous(JSGlobalData&);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertInt32ToArrayStorage(JSGlobalData&);
+
+ WriteBarrier<Unknown>* convertDoubleToContiguous(JSGlobalData&);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&, NonPropertyTransition);
+ ArrayStorage* convertDoubleToArrayStorage(JSGlobalData&);
+
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition, unsigned neededLength);
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&, NonPropertyTransition);
ArrayStorage* convertContiguousToArrayStorage(JSGlobalData&);
+
ArrayStorage* ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData&);
bool defineOwnNonIndexProperty(ExecState*, PropertyName, PropertyDescriptor&, bool throwException);
- void putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
+ template<IndexingType indexingShape>
+ void putByIndexBeyondVectorLengthWithoutAttributes(ExecState*, unsigned propertyName, JSValue);
void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*);
bool increaseVectorLength(JSGlobalData&, unsigned newLength);
@@ -687,24 +805,33 @@ protected:
// Call this if you want setIndexQuickly to succeed and you're sure that
// the array is contiguous.
- void ensureContiguousLength(JSGlobalData& globalData, unsigned length)
+ void ensureLength(JSGlobalData& globalData, unsigned length)
{
ASSERT(length < MAX_ARRAY_INDEX);
- ASSERT(hasContiguous(structure()->indexingType()));
+ ASSERT(hasContiguous(structure()->indexingType()) || hasInt32(structure()->indexingType()) || hasDouble(structure()->indexingType()) || hasUndecided(structure()->indexingType()));
if (m_butterfly->vectorLength() < length)
- ensureContiguousLengthSlow(globalData, length);
+ ensureLengthSlow(globalData, length);
if (m_butterfly->publicLength() < length)
m_butterfly->setPublicLength(length);
}
- unsigned countElementsInContiguous(Butterfly*);
+ template<IndexingType indexingShape>
+ unsigned countElements(Butterfly*);
+ // This is relevant to undecided, int32, double, and contiguous.
+ unsigned countElements();
+
+ // This strange method returns a pointer to the start of the indexed data
+ // as if it contained JSValues. But it won't always contain JSValues.
+ // Make sure you cast this to the appropriate type before using.
template<IndexingType indexingType>
WriteBarrier<Unknown>* indexingData()
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -720,6 +847,7 @@ protected:
WriteBarrier<Unknown>* currentIndexingData()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->contiguous();
@@ -732,10 +860,32 @@ protected:
}
}
+ JSValue getHolyIndexQuickly(unsigned i)
+ {
+ switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_CONTIGUOUS_INDEXING_TYPES:
+ return m_butterfly->contiguous()[i].get();
+ case ALL_DOUBLE_INDEXING_TYPES: {
+ double value = m_butterfly->contiguousDouble()[i];
+ if (value == value)
+ return JSValue(JSValue::EncodeAsDouble, value);
+ return JSValue();
+ }
+ case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+ return m_butterfly->arrayStorage()->m_vector[i].get();
+ default:
+ CRASH();
+ return JSValue();
+ }
+ }
+
template<IndexingType indexingType>
unsigned relevantLength()
{
switch (indexingType) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->publicLength();
@@ -753,6 +903,8 @@ protected:
unsigned currentRelevantLength()
{
switch (structure()->indexingType()) {
+ case ALL_INT32_INDEXING_TYPES:
+ case ALL_DOUBLE_INDEXING_TYPES:
case ALL_CONTIGUOUS_INDEXING_TYPES:
return m_butterfly->publicLength();
@@ -778,6 +930,8 @@ private:
void isObject();
void isString();
+ Butterfly* createInitialIndexedStorage(JSGlobalData&, unsigned length, size_t elementSize);
+
ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(JSGlobalData&, ArrayStorage*);
template<PutMode>
@@ -800,11 +954,18 @@ private:
JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&);
- void ensureContiguousLengthSlow(JSGlobalData&, unsigned length);
+ ArrayStorage* constructConvertedArrayStorageWithoutCopyingElements(JSGlobalData&, unsigned neededLength);
+
+ JS_EXPORT_PRIVATE void setIndexQuicklyToUndecided(JSGlobalData&, unsigned index, JSValue);
+ JS_EXPORT_PRIVATE void convertInt32ToDoubleOrContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue);
+ JS_EXPORT_PRIVATE void convertDoubleToContiguousWhilePerformingSetIndex(JSGlobalData&, unsigned index, JSValue);
+
+ void ensureLengthSlow(JSGlobalData&, unsigned length);
+ WriteBarrier<Unknown>* ensureInt32Slow(JSGlobalData&);
+ double* ensureDoubleSlow(JSGlobalData&);
WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&);
ArrayStorage* ensureArrayStorageSlow(JSGlobalData&);
- Butterfly* ensureIndexedStorageSlow(JSGlobalData&);
protected:
Butterfly* m_butterfly;
@@ -1152,6 +1313,8 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
// See comment on setNewProperty call below.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ if (attributes & ReadOnly)
+ structure()->setContainsReadOnlyProperties();
return true;
}
@@ -1219,6 +1382,8 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, PropertyName p
// so leave the slot in an uncachable state.
if (!specificFunction)
slot.setNewProperty(this, offset);
+ if (attributes & ReadOnly)
+ structure->setContainsReadOnlyProperties();
return true;
}