X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..14957cd040308e3eeec43d26bae5d76da13fcd85:/runtime/JSArray.h diff --git a/runtime/JSArray.h b/runtime/JSArray.h index ad6ee88..3cb8aad 100644 --- a/runtime/JSArray.h +++ b/runtime/JSArray.h @@ -23,27 +23,49 @@ #include "JSObject.h" +#define CHECK_ARRAY_CONSISTENCY 0 + namespace JSC { - typedef HashMap SparseArrayValueMap; + typedef HashMap > SparseArrayValueMap; + // This struct holds the actual data values of an array. A JSArray object points to it's contained ArrayStorage + // struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and + // setStorage() methods. It is important to note that there may be space before the ArrayStorage that + // is used to quick unshift / shift operation. The actual allocated pointer is available by using: + // getStorage() - m_indexBias * sizeof(JSValue) struct ArrayStorage { - unsigned m_length; + unsigned m_length; // The "length" property on the array unsigned m_numValuesInVector; SparseArrayValueMap* m_sparseValueMap; - void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily. + void* subclassData; // A JSArray subclass can use this to fill the vector lazily. + void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector. size_t reportedMapCapacity; - JSValue m_vector[1]; +#if CHECK_ARRAY_CONSISTENCY + bool m_inCompactInitialization; +#endif + WriteBarrier m_vector[1]; }; - class JSArray : public JSObject { - friend class JIT; + // The CreateCompact creation mode is used for fast construction of arrays + // whose size and contents are known at time of creation. + // + // There are two obligations when using this mode: + // + // - uncheckedSetIndex() must be used when initializing the array. + // - setLength() must be called after initialization. + + enum ArrayCreationMode { CreateCompact, CreateInitialized }; + + class JSArray : public JSNonFinalObject { friend class Walker; public: - explicit JSArray(NonNullPassRefPtr); - JSArray(NonNullPassRefPtr, unsigned initialLength); - JSArray(NonNullPassRefPtr, const ArgList& initialValues); + JSArray(VPtrStealingHackType); + + explicit JSArray(JSGlobalData&, Structure*); + JSArray(JSGlobalData&, Structure*, unsigned initialLength, ArrayCreationMode); + JSArray(JSGlobalData&, Structure*, const ArgList& initialValues); virtual ~JSArray(); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); @@ -51,8 +73,8 @@ namespace JSC { virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem. - static JS_EXPORTDATA const ClassInfo info; - + static JS_EXPORTDATA const ClassInfo s_info; + unsigned length() const { return m_storage->m_length; } void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray. @@ -63,69 +85,95 @@ namespace JSC { void push(ExecState*, JSValue); JSValue pop(); + void shiftCount(ExecState*, int count); + void unshiftCount(ExecState*, int count); + bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; } JSValue getIndex(unsigned i) { ASSERT(canGetIndex(i)); - return m_storage->m_vector[i]; + return m_storage->m_vector[i].get(); } bool canSetIndex(unsigned i) { return i < m_vectorLength; } - void setIndex(unsigned i, JSValue v) + void setIndex(JSGlobalData& globalData, unsigned i, JSValue v) { ASSERT(canSetIndex(i)); - JSValue& x = m_storage->m_vector[i]; + + WriteBarrier& x = m_storage->m_vector[i]; if (!x) { - ++m_storage->m_numValuesInVector; - if (i >= m_storage->m_length) - m_storage->m_length = i + 1; + ArrayStorage *storage = m_storage; + ++storage->m_numValuesInVector; + if (i >= storage->m_length) + storage->m_length = i + 1; } - x = v; + x.set(globalData, this, v); + } + + void uncheckedSetIndex(JSGlobalData& globalData, unsigned i, JSValue v) + { + ASSERT(canSetIndex(i)); + ArrayStorage *storage = m_storage; +#if CHECK_ARRAY_CONSISTENCY + ASSERT(storage->m_inCompactInitialization); +#endif + storage->m_vector[i].set(globalData, this, v); } void fillArgList(ExecState*, MarkedArgumentBuffer&); void copyToRegisters(ExecState*, Register*, uint32_t); - static PassRefPtr createStructure(JSValue prototype) + static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } - inline void markChildrenDirect(MarkStack& markStack); + inline void visitChildrenDirect(SlotVisitor&); + + static ptrdiff_t storageOffset() + { + return OBJECT_OFFSETOF(JSArray, m_storage); + } + + static ptrdiff_t vectorLengthOffset() + { + return OBJECT_OFFSETOF(JSArray, m_vectorLength); + } protected: - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags; virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); virtual bool deleteProperty(ExecState*, unsigned propertyName); virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties); - virtual void markChildren(MarkStack&); + virtual void visitChildren(SlotVisitor&); - void* lazyCreationData(); - void setLazyCreationData(void*); + void* subclassData() const; + void setSubclassData(void*); private: - virtual const ClassInfo* classInfo() const { return &info; } - bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&); void putSlowCase(ExecState*, unsigned propertyName, JSValue); + unsigned getNewVectorLength(unsigned desiredLength); bool increaseVectorLength(unsigned newLength); + bool increaseVectorPrefixLength(unsigned newLength); unsigned compactForSorting(); enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck }; void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck); - unsigned m_vectorLength; - ArrayStorage* m_storage; + unsigned m_vectorLength; // The valid length of m_vector + int m_indexBias; // The number of JSValue sized blocks before ArrayStorage. + ArrayStorage *m_storage; }; JSArray* asArray(JSValue); inline JSArray* asArray(JSCell* cell) { - ASSERT(cell->inherits(&JSArray::info)); + ASSERT(cell->inherits(&JSArray::s_info)); return static_cast(cell); } @@ -134,93 +182,35 @@ namespace JSC { return asArray(value.asCell()); } - inline bool isJSArray(JSGlobalData* globalData, JSValue v) - { - return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr; - } inline bool isJSArray(JSGlobalData* globalData, JSCell* cell) { return cell->vptr() == globalData->jsArrayVPtr; } + inline bool isJSArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && isJSArray(globalData, v.asCell()); } - inline void JSArray::markChildrenDirect(MarkStack& markStack) + inline void JSArray::visitChildrenDirect(SlotVisitor& visitor) { - JSObject::markChildrenDirect(markStack); + JSObject::visitChildrenDirect(visitor); ArrayStorage* storage = m_storage; unsigned usedVectorLength = std::min(storage->m_length, m_vectorLength); - markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues); + visitor.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues); if (SparseArrayValueMap* map = storage->m_sparseValueMap) { SparseArrayValueMap::iterator end = map->end(); for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) - markStack.append(it->second); + visitor.append(&it->second); } } - inline void MarkStack::markChildren(JSCell* cell) + // Rule from ECMA 15.2 about what an array index is. + // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1. + inline unsigned Identifier::toArrayIndex(bool& ok) const { - ASSERT(Heap::isCellMarked(cell)); - if (!cell->structure()->typeInfo().overridesMarkChildren()) { -#ifdef NDEBUG - asObject(cell)->markChildrenDirect(*this); -#else - ASSERT(!m_isCheckingForDefaultMarkViolation); - m_isCheckingForDefaultMarkViolation = true; - cell->markChildren(*this); - ASSERT(m_isCheckingForDefaultMarkViolation); - m_isCheckingForDefaultMarkViolation = false; -#endif - return; - } - if (cell->vptr() == m_jsArrayVPtr) { - asArray(cell)->markChildrenDirect(*this); - return; - } - cell->markChildren(*this); + unsigned i = toUInt32(ok); + if (ok && i >= 0xFFFFFFFFU) + ok = false; + return i; } - inline void MarkStack::drain() - { - while (!m_markSets.isEmpty() || !m_values.isEmpty()) { - while (!m_markSets.isEmpty() && m_values.size() < 50) { - ASSERT(!m_markSets.isEmpty()); - MarkSet& current = m_markSets.last(); - ASSERT(current.m_values); - JSValue* end = current.m_end; - ASSERT(current.m_values); - ASSERT(current.m_values != end); - findNextUnmarkedNullValue: - ASSERT(current.m_values != end); - JSValue value = *current.m_values; - current.m_values++; - - JSCell* cell; - if (!value || !value.isCell() || Heap::isCellMarked(cell = value.asCell())) { - if (current.m_values == end) { - m_markSets.removeLast(); - continue; - } - goto findNextUnmarkedNullValue; - } - - Heap::markCell(cell); - if (cell->structure()->typeInfo().type() < CompoundType) { - if (current.m_values == end) { - m_markSets.removeLast(); - continue; - } - goto findNextUnmarkedNullValue; - } - - if (current.m_values == end) - m_markSets.removeLast(); - - markChildren(cell); - } - while (!m_values.isEmpty()) - markChildren(m_values.removeLast()); - } - } - } // namespace JSC #endif // JSArray_h