diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSArray.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSArray.h | 233 |
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 |