summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSArray.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSArray.h')
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h233
1 files changed, 118 insertions, 115 deletions
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index fe30d9f96..bdbd71533 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2003-2017 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -18,11 +18,11 @@
*
*/
-#ifndef JSArray_h
-#define JSArray_h
+#pragma once
#include "ArrayConventions.h"
#include "ButterflyInlines.h"
+#include "JSCellInlines.h"
#include "JSObject.h"
namespace JSC {
@@ -37,6 +37,7 @@ class JSArray : public JSNonFinalObject {
public:
typedef JSNonFinalObject Base;
+ static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
static size_t allocationSize(size_t inlineCapacity)
{
@@ -51,30 +52,45 @@ protected:
}
public:
+ static JSArray* tryCreate(VM&, Structure*, unsigned initialLength = 0);
static JSArray* create(VM&, Structure*, unsigned initialLength = 0);
+ static JSArray* createWithButterfly(VM&, GCDeferralContext*, Structure*, Butterfly*);
- // tryCreateUninitialized is used for fast construction of arrays whose size and
- // contents are known at time of creation. Clients of this interface must:
+ // tryCreateForInitializationPrivate is used for fast construction of arrays whose size and
+ // contents are known at time of creation. This should be considered a private API.
+ // Clients of this interface must:
// - null-check the result (indicating out of memory, or otherwise unable to allocate vector).
// - call 'initializeIndex' for all properties in sequence, for 0 <= i < initialLength.
- static JSArray* tryCreateUninitialized(VM&, Structure*, unsigned initialLength);
+ // - Provide a valid GCDefferalContext* if they might garbage collect when initializing properties,
+ // otherwise the caller can provide a null GCDefferalContext*.
+ //
+ JS_EXPORT_PRIVATE static JSArray* tryCreateForInitializationPrivate(VM&, GCDeferralContext*, Structure*, unsigned initialLength);
+ static JSArray* tryCreateForInitializationPrivate(VM& vm, Structure* structure, unsigned initialLength)
+ {
+ return tryCreateForInitializationPrivate(vm, nullptr, structure, initialLength);
+ }
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool throwException);
- static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
+ JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
DECLARE_EXPORT_INFO;
-
+
+ // OK if we know this is a JSArray, but not if it could be an object of a derived class; for RuntimeArray this always returns 0.
unsigned length() const { return getArrayLength(); }
- // OK to use on new arrays, but not if it might be a RegExpMatchArray.
- bool setLength(ExecState*, unsigned, bool throwException = false);
- void sort(ExecState*);
- void sort(ExecState*, JSValue compareFunction, CallType, const CallData&);
- void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&);
+ // OK to use on new arrays, but not if it might be a RegExpMatchArray or RuntimeArray.
+ JS_EXPORT_PRIVATE bool setLength(ExecState*, unsigned, bool throwException = false);
- void push(ExecState*, JSValue);
- JSValue pop(ExecState*);
+ JS_EXPORT_PRIVATE void push(ExecState*, JSValue);
+ JS_EXPORT_PRIVATE JSValue pop(ExecState*);
+
+ JSArray* fastSlice(ExecState&, unsigned startIndex, unsigned count);
+
+ bool canFastCopy(VM&, JSArray* otherArray);
+ // This function returns NonArray if the indexing types are not compatable for copying.
+ IndexingType mergeIndexingTypeForCopying(IndexingType other);
+ bool appendMemcpy(ExecState*, VM&, unsigned startIndex, JSArray* otherArray);
enum ShiftCountMode {
// This form of shift hints that we're doing queueing. With this assumption in hand,
@@ -89,14 +105,14 @@ public:
bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count)
{
- return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->vm()));
+ return shiftCountWithArrayStorage(exec->vm(), startIndex, count, ensureArrayStorage(exec->vm()));
}
- bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count)
+ bool shiftCountForSplice(ExecState* exec, unsigned& startIndex, unsigned count)
{
return shiftCountWithAnyIndexingType(exec, startIndex, count);
}
template<ShiftCountMode shiftCountMode>
- bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count)
+ bool shiftCount(ExecState* exec, unsigned& startIndex, unsigned count)
{
switch (shiftCountMode) {
case ShiftCountForShift:
@@ -131,17 +147,24 @@ public:
}
}
- void fillArgList(ExecState*, MarkedArgumentBuffer&);
- void copyToArguments(ExecState*, CallFrame*, uint32_t length);
+ JS_EXPORT_PRIVATE void fillArgList(ExecState*, MarkedArgumentBuffer&);
+ JS_EXPORT_PRIVATE void copyToArguments(ExecState*, VirtualRegister firstElementDest, unsigned offset, unsigned length);
+
+ bool isIteratorProtocolFastAndNonObservable();
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, IndexingType indexingType)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), indexingType);
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ArrayType, StructureFlags), info(), indexingType);
}
protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
- static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
+ void finishCreation(VM& vm)
+ {
+ Base::finishCreation(vm);
+ ASSERT_WITH_MESSAGE(type() == ArrayType || type() == DerivedArrayType, "Instance inheriting JSArray should have either ArrayType or DerivedArrayType");
+ }
+
+ static bool put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
static bool deleteProperty(JSCell*, ExecState*, PropertyName);
JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
@@ -156,119 +179,93 @@ private:
return !map || !map->lengthIsReadOnly();
}
- bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
- bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*);
+ bool shiftCountWithAnyIndexingType(ExecState*, unsigned& startIndex, unsigned count);
+ JS_EXPORT_PRIVATE bool shiftCountWithArrayStorage(VM&, unsigned startIndex, unsigned count, ArrayStorage*);
bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count);
bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*);
- bool unshiftCountSlowCase(VM&, bool, unsigned);
-
- template<IndexingType indexingType>
- void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
-
- template<IndexingType indexingType, typename StorageType>
- void sortCompactedVector(ExecState*, ContiguousData<StorageType>, unsigned relevantLength);
-
- template<IndexingType indexingType>
- void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&);
+ bool unshiftCountSlowCase(const AbstractLocker&, VM&, DeferGC&, bool, unsigned);
bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*);
void setLengthWritable(ExecState*, bool writable);
-
- template<IndexingType indexingType>
- void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength);
};
-inline Butterfly* createContiguousArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned length, unsigned& vectorLength)
+inline Butterfly* tryCreateArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned initialLength)
{
- IndexingHeader header;
- vectorLength = std::max(length, BASE_VECTOR_LEN);
- header.setVectorLength(vectorLength);
- header.setPublicLength(length);
- Butterfly* result = Butterfly::create(
- vm, intendedOwner, 0, 0, true, header, vectorLength * sizeof(EncodedJSValue));
- return result;
-}
-
-inline Butterfly* createArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned initialLength)
-{
- Butterfly* butterfly = Butterfly::create(
- vm, intendedOwner, 0, 0, true, baseIndexingHeaderForArray(initialLength),
- ArrayStorage::sizeFor(BASE_VECTOR_LEN));
+ Butterfly* butterfly = Butterfly::tryCreate(
+ vm, intendedOwner, 0, 0, true, baseIndexingHeaderForArrayStorage(initialLength),
+ ArrayStorage::sizeFor(BASE_ARRAY_STORAGE_VECTOR_LEN));
+ if (!butterfly)
+ return nullptr;
ArrayStorage* storage = butterfly->arrayStorage();
- storage->m_indexBias = 0;
storage->m_sparseMap.clear();
+ storage->m_indexBias = 0;
storage->m_numValuesInVector = 0;
return butterfly;
}
+inline Butterfly* createArrayButterfly(VM& vm, JSCell* intendedOwner, unsigned initialLength)
+{
+ Butterfly* result = tryCreateArrayButterfly(vm, intendedOwner, initialLength);
+ RELEASE_ASSERT(result);
+ return result;
+}
+
Butterfly* createArrayButterflyInDictionaryIndexingMode(
VM&, JSCell* intendedOwner, unsigned initialLength);
-inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
+inline JSArray* JSArray::tryCreate(VM& vm, Structure* structure, unsigned initialLength)
{
- Butterfly* butterfly;
- if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
- ASSERT(
- hasUndecided(structure->indexingType())
- || hasInt32(structure->indexingType())
- || hasDouble(structure->indexingType())
- || hasContiguous(structure->indexingType()));
- unsigned vectorLength;
- butterfly = createContiguousArrayButterfly(vm, 0, initialLength, vectorLength);
- ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX);
- if (hasDouble(structure->indexingType())) {
- for (unsigned i = 0; i < vectorLength; ++i)
- butterfly->contiguousDouble()[i] = QNaN;
- }
- } else {
- ASSERT(
- structure->indexingType() == ArrayWithSlowPutArrayStorage
- || structure->indexingType() == ArrayWithArrayStorage);
- butterfly = createArrayButterfly(vm, 0, initialLength);
- }
- JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
- array->finishCreation(vm);
- return array;
-}
+ unsigned outOfLineStorage = structure->outOfLineCapacity();
-inline JSArray* JSArray::tryCreateUninitialized(VM& vm, Structure* structure, unsigned initialLength)
-{
- unsigned vectorLength = std::max(BASE_VECTOR_LEN, initialLength);
- if (vectorLength > MAX_STORAGE_VECTOR_LENGTH)
- return 0;
-
Butterfly* butterfly;
- if (LIKELY(!hasArrayStorage(structure->indexingType()))) {
+ IndexingType indexingType = structure->indexingType();
+ if (LIKELY(!hasAnyArrayStorage(indexingType))) {
ASSERT(
- hasUndecided(structure->indexingType())
- || hasInt32(structure->indexingType())
- || hasDouble(structure->indexingType())
- || hasContiguous(structure->indexingType()));
+ hasUndecided(indexingType)
+ || hasInt32(indexingType)
+ || hasDouble(indexingType)
+ || hasContiguous(indexingType));
- void* temp;
- if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp))
+ if (initialLength > MAX_STORAGE_VECTOR_LENGTH)
return 0;
- butterfly = Butterfly::fromBase(temp, 0, 0);
+
+ unsigned vectorLength = Butterfly::optimalContiguousVectorLength(structure, initialLength);
+ void* temp = vm.auxiliarySpace.tryAllocate(nullptr, Butterfly::totalSize(0, outOfLineStorage, true, vectorLength * sizeof(EncodedJSValue)));
+ if (!temp)
+ return nullptr;
+ butterfly = Butterfly::fromBase(temp, 0, outOfLineStorage);
butterfly->setVectorLength(vectorLength);
butterfly->setPublicLength(initialLength);
- if (hasDouble(structure->indexingType())) {
- for (unsigned i = initialLength; i < vectorLength; ++i)
- butterfly->contiguousDouble()[i] = QNaN;
- }
+ if (hasDouble(indexingType))
+ clearArray(butterfly->contiguousDouble().data(), vectorLength);
+ else
+ clearArray(butterfly->contiguous().data(), vectorLength);
} else {
- void* temp;
- if (!vm.heap.tryAllocateStorage(0, Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp))
- return 0;
- butterfly = Butterfly::fromBase(temp, 0, 0);
- *butterfly->indexingHeader() = indexingHeaderForArray(initialLength, vectorLength);
- ArrayStorage* storage = butterfly->arrayStorage();
- storage->m_indexBias = 0;
- storage->m_sparseMap.clear();
- storage->m_numValuesInVector = initialLength;
+ ASSERT(
+ indexingType == ArrayWithSlowPutArrayStorage
+ || indexingType == ArrayWithArrayStorage);
+ butterfly = tryCreateArrayButterfly(vm, 0, initialLength);
+ if (!butterfly)
+ return nullptr;
+ for (unsigned i = 0; i < BASE_ARRAY_STORAGE_VECTOR_LEN; ++i)
+ butterfly->arrayStorage()->m_vector[i].clear();
}
-
- JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap)) JSArray(vm, structure, butterfly);
+
+ return createWithButterfly(vm, nullptr, structure, butterfly);
+}
+
+inline JSArray* JSArray::create(VM& vm, Structure* structure, unsigned initialLength)
+{
+ JSArray* result = JSArray::tryCreate(vm, structure, initialLength);
+ RELEASE_ASSERT(result);
+
+ return result;
+}
+
+inline JSArray* JSArray::createWithButterfly(VM& vm, GCDeferralContext* deferralContext, Structure* structure, Butterfly* butterfly)
+{
+ JSArray* array = new (NotNull, allocateCell<JSArray>(vm.heap, deferralContext)) JSArray(vm, structure, butterfly);
array->finishCreation(vm);
return array;
}
@@ -277,7 +274,7 @@ JSArray* asArray(JSValue);
inline JSArray* asArray(JSCell* cell)
{
- ASSERT(cell->inherits(JSArray::info()));
+ ASSERT(cell->inherits(*cell->vm(), JSArray::info()));
return jsCast<JSArray*>(cell);
}
@@ -286,18 +283,24 @@ inline JSArray* asArray(JSValue value)
return asArray(value.asCell());
}
-inline bool isJSArray(JSCell* cell) { return cell->classInfo() == JSArray::info(); }
+inline bool isJSArray(JSCell* cell)
+{
+ ASSERT((cell->classInfo(*cell->vm()) == JSArray::info()) == (cell->type() == ArrayType));
+ return cell->type() == ArrayType;
+}
+
inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); }
inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const ArgList& values)
{
VM& vm = exec->vm();
unsigned length = values.size();
- JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
+ JSArray* array = JSArray::tryCreateForInitializationPrivate(vm, arrayStructure, length);
// FIXME: we should probably throw an out of memory error here, but
// when making this change we should check that all clients of this
// function will correctly handle an exception being thrown from here.
+ // https://bugs.webkit.org/show_bug.cgi?id=169786
RELEASE_ASSERT(array);
for (unsigned i = 0; i < length; ++i)
@@ -308,11 +311,12 @@ inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const
inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length)
{
VM& vm = exec->vm();
- JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
+ JSArray* array = JSArray::tryCreateForInitializationPrivate(vm, arrayStructure, length);
// FIXME: we should probably throw an out of memory error here, but
// when making this change we should check that all clients of this
// function will correctly handle an exception being thrown from here.
+ // https://bugs.webkit.org/show_bug.cgi?id=169786
RELEASE_ASSERT(array);
for (unsigned i = 0; i < length; ++i)
@@ -323,11 +327,12 @@ inline JSArray* constructArray(ExecState* exec, Structure* arrayStructure, const
inline JSArray* constructArrayNegativeIndexed(ExecState* exec, Structure* arrayStructure, const JSValue* values, unsigned length)
{
VM& vm = exec->vm();
- JSArray* array = JSArray::tryCreateUninitialized(vm, arrayStructure, length);
+ JSArray* array = JSArray::tryCreateForInitializationPrivate(vm, arrayStructure, length);
// FIXME: we should probably throw an out of memory error here, but
// when making this change we should check that all clients of this
// function will correctly handle an exception being thrown from here.
+ // https://bugs.webkit.org/show_bug.cgi?id=169786
RELEASE_ASSERT(array);
for (int i = 0; i < static_cast<int>(length); ++i)
@@ -336,5 +341,3 @@ inline JSArray* constructArrayNegativeIndexed(ExecState* exec, Structure* arrayS
}
} // namespace JSC
-
-#endif // JSArray_h