diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-15 16:08:57 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-15 16:08:57 +0200 |
commit | 5466563f4b5b6b86523e3f89bb7f77e5b5270c78 (patch) | |
tree | 8caccf7cd03a15207cde3ba282c88bf132482a91 /Source/JavaScriptCore/runtime | |
parent | 33b26980cb24288b5a9f2590ccf32a949281bb79 (diff) | |
download | qtwebkit-5466563f4b5b6b86523e3f89bb7f77e5b5270c78.tar.gz |
Imported WebKit commit 0dc6cd75e1d4836eaffbb520be96fac4847cc9d2 (http://svn.webkit.org/repository/webkit/trunk@131300)
WebKit update which introduces the QtWebKitWidgets module that contains the WK1
widgets based API. (In fact it renames QtWebKit to QtWebKitWidgets while we're
working on completing the entire split as part of
https://bugs.webkit.org/show_bug.cgi?id=99314
Diffstat (limited to 'Source/JavaScriptCore/runtime')
96 files changed, 2051 insertions, 1001 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index fdf202192..ba73b2cf2 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -33,9 +33,7 @@ using namespace std; namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(Arguments); - -const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) }; +const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) }; void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor) { @@ -406,19 +404,19 @@ void Arguments::tearOffForInlineCallFrame(JSGlobalData& globalData, Register* re JSValue value; Register* location = ®isters[CallFrame::argumentOffset(i)]; switch (recovery.technique()) { - case AlreadyInRegisterFile: + case AlreadyInJSStack: value = location->jsValue(); break; - case AlreadyInRegisterFileAsUnboxedInt32: + case AlreadyInJSStackAsUnboxedInt32: value = jsNumber(location->unboxedInt32()); break; - case AlreadyInRegisterFileAsUnboxedCell: + case AlreadyInJSStackAsUnboxedCell: value = location->unboxedCell(); break; - case AlreadyInRegisterFileAsUnboxedBoolean: + case AlreadyInJSStackAsUnboxedBoolean: value = jsBoolean(location->unboxedBoolean()); break; - case AlreadyInRegisterFileAsUnboxedDouble: + case AlreadyInJSStackAsUnboxedDouble: #if USE(JSVALUE64) value = jsNumber(*bitwise_cast<double*>(location)); #else diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h index 40063bead..7c8b69bd1 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -26,6 +26,7 @@ #include "CodeOrigin.h" #include "JSActivation.h" +#include "JSDestructibleObject.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "Interpreter.h" @@ -33,11 +34,11 @@ namespace JSC { - class Arguments : public JSNonFinalObject { + class Arguments : public JSDestructibleObject { friend class JIT; friend class DFG::SpeculativeJIT; public: - typedef JSNonFinalObject Base; + typedef JSDestructibleObject Base; static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame) { @@ -147,12 +148,12 @@ namespace JSC { } inline Arguments::Arguments(CallFrame* callFrame) - : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) { } inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) - : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) { } diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index eda35e146..a13648442 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -53,8 +53,6 @@ const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_in @end */ -ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor); - ArrayConstructor::ArrayConstructor(JSGlobalObject* globalObject, Structure* structure) : InternalFunction(globalObject, structure) { diff --git a/Source/JavaScriptCore/runtime/ArrayConventions.h b/Source/JavaScriptCore/runtime/ArrayConventions.h index 3ea6b0471..a557b1ef9 100644 --- a/Source/JavaScriptCore/runtime/ArrayConventions.h +++ b/Source/JavaScriptCore/runtime/ArrayConventions.h @@ -79,7 +79,7 @@ static const unsigned minDensityMultiplier = 8; inline bool isDenseEnoughForVector(unsigned length, unsigned numValues) { - return length <= MIN_SPARSE_ARRAY_INDEX || length / minDensityMultiplier <= numValues; + return length / minDensityMultiplier <= numValues; } inline IndexingHeader indexingHeaderForArray(unsigned length, unsigned vectorLength) diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp index 1eacd1179..6975dc778 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -42,8 +42,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype); - static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*); static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*); static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*); @@ -194,7 +192,8 @@ static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument // currentCount) will be shifted to the left or right as appropriate; in the // case of shift this must be removing values, in the case of unshift this // must be introducing new values. -static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) +template<JSArray::ShiftCountMode shiftCountMode> +void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { ASSERT(currentCount > resultCount); unsigned count = currentCount - resultCount; @@ -202,9 +201,9 @@ static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, un ASSERT(header <= length); ASSERT(currentCount <= (length - header)); - if (!header && isJSArray(thisObj)) { + if (isJSArray(thisObj)) { JSArray* array = asArray(thisObj); - if (array->length() == length && asArray(thisObj)->shiftCount(exec, count)) + if (array->length() == length && asArray(thisObj)->shiftCount<shiftCountMode>(exec, header, count)) return; } @@ -231,7 +230,8 @@ static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, un } } } -static inline void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) +template<JSArray::ShiftCountMode shiftCountMode> +void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { ASSERT(resultCount > currentCount); unsigned count = resultCount - currentCount; @@ -245,12 +245,12 @@ static inline void unshift(ExecState* exec, JSObject* thisObj, unsigned header, return; } - if (!header && isJSArray(thisObj)) { + if (isJSArray(thisObj)) { JSArray* array = asArray(thisObj); - if (array->length() == length && asArray(thisObj)->unshiftCount(exec, count)) + if (array->length() == length && array->unshiftCount<shiftCountMode>(exec, header, count)) return; } - + for (unsigned k = length - currentCount; k > header; --k) { unsigned from = k + currentCount - 1; unsigned to = k + resultCount - 1; @@ -526,7 +526,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) array->push(exec, exec->argument(0)); return JSValue::encode(jsNumber(array->length())); } - + JSObject* thisObj = thisValue.toObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) @@ -544,6 +544,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec) if (exec->hadException()) return JSValue::encode(jsUndefined()); } + JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount())); putProperty(exec, thisObj, exec->propertyNames().length, newLength); return JSValue::encode(newLength); @@ -600,7 +601,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) result = jsUndefined(); } else { result = thisObj->get(exec, 0); - shift(exec, thisObj, 0, 1, 0, length); + shift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 1, 0, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1)); @@ -655,7 +656,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) CallData callData; CallType callType = getCallData(function, callData); - if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseIndexingMode() && !shouldUseSlowPut(thisObj->structure()->indexingType())) { + if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->hasSparseMap() && !shouldUseSlowPut(thisObj->structure()->indexingType())) { if (isNumericCompareFunction(exec, callType, callData)) asArray(thisObj)->sortNumeric(exec, function, callType, callData); else if (callType != CallTypeNone) @@ -730,7 +731,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); - + if (!exec->argumentCount()) return JSValue::encode(constructEmptyArray(exec)); @@ -762,11 +763,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0); if (additionalArgs < deleteCount) { - shift(exec, thisObj, begin, deleteCount, additionalArgs, length); + shift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); } else if (additionalArgs > deleteCount) { - unshift(exec, thisObj, begin, deleteCount, additionalArgs, length); + unshift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); } @@ -791,7 +792,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) unsigned nrArgs = exec->argumentCount(); if (nrArgs) { - unshift(exec, thisObj, 0, 0, nrArgs, length); + unshift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 0, nrArgs, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); } diff --git a/Source/JavaScriptCore/runtime/ArrayStorage.h b/Source/JavaScriptCore/runtime/ArrayStorage.h index 1ab936335..ffd84b281 100644 --- a/Source/JavaScriptCore/runtime/ArrayStorage.h +++ b/Source/JavaScriptCore/runtime/ArrayStorage.h @@ -41,6 +41,8 @@ namespace JSC { // 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) +// All slots in ArrayStorage (slots from 0 to vectorLength) are expected to be initialized to a JSValue or, +// for hole slots, JSValue(). struct ArrayStorage { WTF_MAKE_NONCOPYABLE(ArrayStorage); private: diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp index 9b666292c..0485350ce 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -26,7 +26,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(BooleanConstructor); ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanConstructor); const ClassInfo BooleanConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanConstructor) }; diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp index bf2655bbb..355993864 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.cpp +++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp @@ -25,7 +25,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(BooleanObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanObject); const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanObject) }; diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp index c8c77220a..a331c6c15 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -47,7 +47,6 @@ const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, @end */ -ASSERT_CLASS_FITS_IN_CELL(BooleanPrototype); ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanPrototype); BooleanPrototype::BooleanPrototype(ExecState* exec, Structure* structure) diff --git a/Source/JavaScriptCore/runtime/Butterfly.h b/Source/JavaScriptCore/runtime/Butterfly.h index 1926169ba..cb93aea8a 100644 --- a/Source/JavaScriptCore/runtime/Butterfly.h +++ b/Source/JavaScriptCore/runtime/Butterfly.h @@ -35,7 +35,7 @@ namespace JSC { class JSGlobalData; -class SlotVisitor; +class CopyVisitor; struct ArrayStorage; class Butterfly { @@ -56,6 +56,15 @@ public: return reinterpret_cast<Butterfly*>(static_cast<EncodedJSValue*>(base) + preCapacity + propertyCapacity + 1); } + // This method is here not just because it's handy, but to remind you that + // the whole point of butterflies is to do evil pointer arithmetic. + static Butterfly* fromPointer(char* ptr) + { + return reinterpret_cast<Butterfly*>(ptr); + } + + char* pointer() { return reinterpret_cast<char*>(this); } + static ptrdiff_t offsetOfIndexingHeader() { return IndexingHeader::offsetOfIndexingHeader(); } static ptrdiff_t offsetOfPublicLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfPublicLength(); } static ptrdiff_t offsetOfVectorLength() { return offsetOfIndexingHeader() + IndexingHeader::offsetOfVectorLength(); } @@ -64,15 +73,27 @@ public: static Butterfly* create(JSGlobalData&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, const IndexingHeader&, size_t indexingPayloadSizeInBytes); static Butterfly* create(JSGlobalData&, Structure*); - static Butterfly* createUninitializedDuringCollection(SlotVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); + static Butterfly* createUninitializedDuringCollection(CopyVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); IndexingHeader* indexingHeader() { return IndexingHeader::from(this); } const IndexingHeader* indexingHeader() const { return IndexingHeader::from(this); } PropertyStorage propertyStorage() { return indexingHeader()->propertyStorage(); } ConstPropertyStorage propertyStorage() const { return indexingHeader()->propertyStorage(); } + + uint32_t publicLength() { return indexingHeader()->publicLength(); } + uint32_t vectorLength() { return indexingHeader()->vectorLength(); } + void setPublicLength(uint32_t value) { indexingHeader()->setPublicLength(value); } + void setVectorLength(uint32_t value) { indexingHeader()->setVectorLength(value); } + template<typename T> T* indexingPayload() { return reinterpret_cast<T*>(this); } ArrayStorage* arrayStorage() { return indexingPayload<ArrayStorage>(); } + WriteBarrier<Unknown>* contiguous() { return indexingPayload<WriteBarrier<Unknown> >(); } + + static Butterfly* fromContiguous(WriteBarrier<Unknown>* contiguous) + { + return reinterpret_cast<Butterfly*>(contiguous); + } static ptrdiff_t offsetOfPropertyStorage() { return -static_cast<ptrdiff_t>(sizeof(IndexingHeader)); } static int indexOfPropertyStorage() diff --git a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h b/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h index 049350342..86a836bef 100644 --- a/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h +++ b/Source/JavaScriptCore/runtime/ButterflyInlineMethods.h @@ -29,8 +29,8 @@ #include "ArrayStorage.h" #include "Butterfly.h" #include "CopiedSpaceInlineMethods.h" +#include "CopyVisitor.h" #include "JSGlobalData.h" -#include "SlotVisitor.h" #include "Structure.h" namespace JSC { @@ -59,7 +59,7 @@ inline Butterfly* Butterfly::create(JSGlobalData& globalData, Structure* structu return create(globalData, 0, structure->outOfLineCapacity(), hasIndexingHeader(structure->indexingType()), IndexingHeader(), 0); } -inline Butterfly* Butterfly::createUninitializedDuringCollection(SlotVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) +inline Butterfly* Butterfly::createUninitializedDuringCollection(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) { Butterfly* result = fromBase( visitor.allocateNewSpace(totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes)), @@ -144,7 +144,7 @@ inline Butterfly* Butterfly::resizeArray(JSGlobalData& globalData, Structure* st inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) { - ASSERT(hasIndexingHeader(structure->indexingType())); + ASSERT(hasArrayStorage(structure->indexingType())); ASSERT(numberOfSlots <= indexingHeader()->preCapacity(structure)); unsigned propertyCapacity = structure->outOfLineCapacity(); // FIXME: It would probably be wise to rewrite this as a loop since (1) we know in which @@ -163,7 +163,7 @@ inline Butterfly* Butterfly::unshift(Structure* structure, size_t numberOfSlots) inline Butterfly* Butterfly::shift(Structure* structure, size_t numberOfSlots) { - ASSERT(hasIndexingHeader(structure->indexingType())); + ASSERT(hasArrayStorage(structure->indexingType())); unsigned propertyCapacity = structure->outOfLineCapacity(); // FIXME: See comment in unshift(), above. memmove( diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h index e8823d571..c918621fe 100644 --- a/Source/JavaScriptCore/runtime/ClassInfo.h +++ b/Source/JavaScriptCore/runtime/ClassInfo.h @@ -39,6 +39,9 @@ namespace JSC { typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&); VisitChildrenFunctionPtr visitChildren; + typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&); + CopyBackingStoreFunctionPtr copyBackingStore; + typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&); GetCallDataFunctionPtr getCallData; @@ -116,6 +119,7 @@ struct MemberCheck##member { \ #define CREATE_METHOD_TABLE(ClassName) { \ &ClassName::destroy, \ &ClassName::visitChildren, \ + &ClassName::copyBackingStore, \ &ClassName::getCallData, \ &ClassName::getConstructData, \ &ClassName::put, \ diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h index 7edd9091c..2f5159461 100644 --- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h +++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h @@ -43,7 +43,7 @@ namespace JSC { namespace CommonSlowPaths { -ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFile, CodeSpecializationKind kind) +ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, JSStack* stack, CodeSpecializationKind kind) { JSFunction* callee = jsCast<JSFunction*>(exec->callee()); ASSERT(!callee->isHostFunction()); @@ -51,7 +51,7 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFi int argumentCountIncludingThis = exec->argumentCountIncludingThis(); // This ensures enough space for the worst case scenario of zero arguments passed by the caller. - if (!registerFile->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters)) + if (!stack->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters)) return 0; ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters()); @@ -71,7 +71,7 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFi dst[i] = jsUndefined(); ExecState* newExec = ExecState::create(dst); - ASSERT((void*)newExec <= registerFile->end()); + ASSERT((void*)newExec <= stack->end()); return newExec; } diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index e4f89dd37..f78e8bf55 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.cpp +++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp @@ -71,7 +71,6 @@ const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_inf @end */ -ASSERT_CLASS_FITS_IN_CELL(DateConstructor); ASSERT_HAS_TRIVIAL_DESTRUCTOR(DateConstructor); DateConstructor::DateConstructor(JSGlobalObject* globalObject, Structure* structure) diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp index 9b2cb164f..75da466fb 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -70,8 +70,6 @@ using namespace WTF; namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(DatePrototype); - static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*); static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*); static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*); diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index 27a729d0a..68ae12d90 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -177,8 +177,6 @@ JSObject* throwSyntaxError(ExecState* exec) return throwError(exec, createSyntaxError(exec, ASCIILiteral("Syntax error"))); } -ASSERT_CLASS_FITS_IN_CELL(StrictModeTypeErrorFunction); - const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) }; void StrictModeTypeErrorFunction::destroy(JSCell* cell) diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp index 96272d0cf..f2578a497 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -27,7 +27,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(ErrorConstructor); ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorConstructor); const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorConstructor) }; diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp index 6c9d6df04..a30efdc31 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -30,7 +30,7 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorPrototype); static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*); @@ -48,8 +48,6 @@ const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, 0, E @end */ -ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); - ErrorPrototype::ErrorPrototype(ExecState* exec, Structure* structure) : ErrorInstance(exec->globalData(), structure) { diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h index 6eeda3a82..76a537da3 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -81,6 +81,8 @@ namespace JSC { typedef JSCell Base; #if ENABLE(JIT) + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); #endif diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp index 570444e3c..bf74c0a97 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -34,7 +34,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor); ASSERT_HAS_TRIVIAL_DESTRUCTOR(FunctionConstructor); const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionConstructor) }; diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp index dd1628b29..a4b2202c1 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -32,7 +32,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype); ASSERT_HAS_TRIVIAL_DESTRUCTOR(FunctionPrototype); const ClassInfo FunctionPrototype::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionPrototype) }; diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp index a9a2a66bf..45dd0bbde 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -30,6 +30,7 @@ #include <wtf/Assertions.h> #include <wtf/FastMalloc.h> #include <wtf/HashSet.h> +#include <wtf/text/ASCIIFastPath.h> #include <wtf/text/StringHash.h> using WTF::ThreadSpecific; @@ -80,11 +81,7 @@ struct IdentifierLCharFromUCharTranslator { { LChar* d; StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef(); - for (unsigned i = 0; i != buf.length; i++) { - UChar c = buf.s[i]; - ASSERT(c <= 0xff); - d[i] = c; - } + WTF::copyLCharsFromUCharSource(d, buf.s, buf.length); r->setHash(hash); location = r; } @@ -102,7 +99,7 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c) const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c); if (iter != literalIdentifierTable.end()) - return iter->second; + return iter->value; HashSet<StringImpl*>::AddResult addResult = identifierTable.add<const LChar*, IdentifierASCIIStringTranslator>(reinterpret_cast<const LChar*>(c)); diff --git a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h index e1d893b0b..22785ce24 100644 --- a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h +++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h @@ -42,10 +42,17 @@ inline size_t IndexingHeader::preCapacity(Structure* structure) inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure) { - if (LIKELY(!hasArrayStorage(structure->indexingType()))) + switch (structure->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return vectorLength() * sizeof(EncodedJSValue); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return ArrayStorage::sizeFor(arrayStorage()->vectorLength()); + + default: + ASSERT(!hasIndexedProperties(structure->indexingType())); return 0; - - return ArrayStorage::sizeFor(arrayStorage()->vectorLength()); + } } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/IndexingType.cpp b/Source/JavaScriptCore/runtime/IndexingType.cpp new file mode 100644 index 000000000..7261847a2 --- /dev/null +++ b/Source/JavaScriptCore/runtime/IndexingType.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IndexingType.h" + +#include <stdio.h> +#include <wtf/StringExtras.h> + +namespace JSC { + +const char* indexingTypeToString(IndexingType indexingType) +{ + static char result[128]; + const char* basicName; + switch (indexingType & AllArrayTypes) { + case NonArray: + basicName = "NonArray"; + break; + case NonArrayWithContiguous: + basicName = "NonArrayWithContiguous"; + break; + case NonArrayWithArrayStorage: + basicName = "NonArrayWithArrayStorage"; + break; + case NonArrayWithSlowPutArrayStorage: + basicName = "NonArrayWithSlowPutArrayStorage"; + break; + case ArrayClass: + basicName = "ArrayClass"; + break; + case ArrayWithContiguous: + basicName = "ArrayWithContiguous"; + break; + case ArrayWithArrayStorage: + basicName = "ArrayWithArrayStorage"; + break; + case ArrayWithSlowPutArrayStorage: + basicName = "ArrayWithSlowPutArrayStorage"; + break; + default: + basicName = "Unknown!"; + break; + } + + snprintf( + result, sizeof(result), "%s%s", basicName, + (indexingType & MayHaveIndexedAccessors) ? "|MayHaveIndexedAccessors" : ""); + + return result; +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/IndexingType.h b/Source/JavaScriptCore/runtime/IndexingType.h index 3b97230ea..4bbe3cfa0 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.h +++ b/Source/JavaScriptCore/runtime/IndexingType.h @@ -26,32 +26,44 @@ #ifndef IndexingType_h #define IndexingType_h +#include <wtf/StdLibExtras.h> + namespace JSC { typedef uint8_t IndexingType; // Flags for testing the presence of capabilities. static const IndexingType IsArray = 1; -static const IndexingType HasArrayStorage = 8; -static const IndexingType HasSlowPutArrayStorage = 16; + +// The shape of the indexed property storage. +static const IndexingType IndexingShapeMask = 30; +static const IndexingType NoIndexingShape = 0; +static const IndexingType ContiguousShape = 26; +static const IndexingType ArrayStorageShape = 28; +static const IndexingType SlowPutArrayStorageShape = 30; // Additional flags for tracking the history of the type. These are usually // masked off unless you ask for them directly. -static const IndexingType HadArrayStorage = 32; // Means that this object did have array storage in the past. -static const IndexingType MayHaveIndexedAccessors = 64; +static const IndexingType MayHaveIndexedAccessors = 32; // List of acceptable array types. static const IndexingType NonArray = 0; -static const IndexingType NonArrayWithArrayStorage = HasArrayStorage; -static const IndexingType NonArrayWithSlowPutArrayStorage = HasSlowPutArrayStorage; +static const IndexingType NonArrayWithContiguous = ContiguousShape; +static const IndexingType NonArrayWithArrayStorage = ArrayStorageShape; +static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape; static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution. -static const IndexingType ArrayWithArrayStorage = IsArray | HasArrayStorage; -static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | HasSlowPutArrayStorage; +static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape; +static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape; +static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape; #define ALL_BLANK_INDEXING_TYPES \ NonArray: \ case ArrayClass +#define ALL_CONTIGUOUS_INDEXING_TYPES \ + NonArrayWithContiguous: \ + case ArrayWithContiguous + #define ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES \ ArrayWithArrayStorage: \ case ArrayWithSlowPutArrayStorage @@ -63,12 +75,7 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | HasSlowPut static inline bool hasIndexedProperties(IndexingType indexingType) { - switch (indexingType) { - case ALL_BLANK_INDEXING_TYPES: - return false; - default: - return true; - } + return (indexingType & IndexingShapeMask) != NoIndexingShape; } static inline bool hasIndexingHeader(IndexingType type) @@ -76,16 +83,30 @@ static inline bool hasIndexingHeader(IndexingType type) return hasIndexedProperties(type); } +static inline bool hasContiguous(IndexingType indexingType) +{ + return (indexingType & IndexingShapeMask) == ContiguousShape; +} + +// FIXME: This is an awkward name. This should really be called hasArrayStorage() +// and then next method down should be called hasAnyArrayStorage(). +static inline bool hasFastArrayStorage(IndexingType indexingType) +{ + return (indexingType & IndexingShapeMask) == ArrayStorageShape; +} + static inline bool hasArrayStorage(IndexingType indexingType) { - return !!(indexingType & (HasArrayStorage | HasSlowPutArrayStorage)); + return static_cast<uint8_t>((indexingType & IndexingShapeMask) - ArrayStorageShape) <= static_cast<uint8_t>(SlowPutArrayStorageShape - ArrayStorageShape); } static inline bool shouldUseSlowPut(IndexingType indexingType) { - return !!(indexingType & HasSlowPutArrayStorage); + return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape; } +const char* indexingTypeToString(IndexingType); + // Mask of all possible types. static const IndexingType AllArrayTypes = 31; diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp index 1a7239f60..1a6c84514 100644 --- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp @@ -31,6 +31,7 @@ #include "ExecutableAllocator.h" #include "Heap.h" +#include "HeapStatistics.h" #include "Options.h" #include "Identifier.h" #include "JSDateMath.h" @@ -56,13 +57,15 @@ static void initializeThreadingOnce() WTF::initializeThreading(); GlobalJSLock::initialize(); Options::initialize(); + if (Options::recordGCPauseTimes()) + HeapStatistics::initialize(); #if ENABLE(WRITE_BARRIER_PROFILING) WriteBarrierCounters::initialize(); #endif #if ENABLE(ASSEMBLER) ExecutableAllocator::initializeAllocator(); #endif - RegisterFile::initializeThreading(); + JSStack::initializeThreading(); #if ENABLE(LLINT) LLInt::initialize(); #endif diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp index e2de03d92..afb5e6317 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.cpp +++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp @@ -29,13 +29,12 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(InternalFunction); ASSERT_HAS_TRIVIAL_DESTRUCTOR(InternalFunction); -const ClassInfo InternalFunction::s_info = { "Function", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) }; +const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) }; InternalFunction::InternalFunction(JSGlobalObject* globalObject, Structure* structure) - : JSNonFinalObject(globalObject->globalData(), structure) + : JSDestructibleObject(globalObject->globalData(), structure) { } diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h index e26b9f953..daeebc34d 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.h +++ b/Source/JavaScriptCore/runtime/InternalFunction.h @@ -24,16 +24,16 @@ #ifndef InternalFunction_h #define InternalFunction_h -#include "JSObject.h" #include "Identifier.h" +#include "JSDestructibleObject.h" namespace JSC { class FunctionPrototype; - class InternalFunction : public JSNonFinalObject { + class InternalFunction : public JSDestructibleObject { public: - typedef JSNonFinalObject Base; + typedef JSDestructibleObject Base; static JS_EXPORTDATA const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index c34e10bc8..3b665962f 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -37,8 +37,6 @@ using namespace std; namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSActivation); - const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) }; void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) @@ -49,7 +47,7 @@ void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor) ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); - // No need to mark our registers if they're still in the RegisterFile. + // No need to mark our registers if they're still in the JSStack. if (!thisObject->isTornOff()) return; @@ -116,11 +114,11 @@ void JSActivation::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec SymbolTable::const_iterator end = thisObject->symbolTable()->end(); for (SymbolTable::const_iterator it = thisObject->symbolTable()->begin(); it != end; ++it) { - if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) + if (it->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) continue; - if (!thisObject->isValid(it->second)) + if (!thisObject->isValid(it->value)) continue; - propertyNames.add(Identifier(exec, it->first.get())); + propertyNames.add(Identifier(exec, it->key.get())); } // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); @@ -133,7 +131,7 @@ inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, SymbolTable::iterator iter = symbolTable()->find(propertyName.publicName()); if (iter == symbolTable()->end()) return false; - SymbolTableEntry& entry = iter->second; + SymbolTableEntry& entry = iter->value; ASSERT(!entry.isNull()); if (!isValid(entry)) return false; diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index 8398ae77d..7028c3b95 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -44,8 +44,6 @@ using namespace WTF; namespace JSC { - -ASSERT_CLASS_FITS_IN_CELL(JSArray); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSArray); const ClassInfo JSArray::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)}; @@ -245,8 +243,8 @@ void JSArray::getOwnNonIndexPropertyNames(JSObject* object, ExecState* exec, Pro JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); } -// This method makes room in the vector, but leaves the new space uncleared. -bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) +// This method makes room in the vector, but leaves the new space for count slots uncleared. +bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, unsigned count) { ArrayStorage* storage = ensureArrayStorage(globalData); Butterfly* butterfly = storage->butterfly(); @@ -254,7 +252,7 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) unsigned propertySize = structure()->outOfLineSize(); // If not, we should have handled this on the fast path. - ASSERT(count > storage->m_indexBias); + ASSERT(!addToFront || count > storage->m_indexBias); // Step 1: // Gather 4 key metrics: @@ -278,7 +276,7 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) unsigned desiredCapacity = min(MAX_STORAGE_VECTOR_LENGTH, max(BASE_VECTOR_LEN, requiredVectorLength) << 1); // Step 2: - // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing on. + // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing one. void* newAllocBase = 0; unsigned newStorageCapacity; @@ -297,36 +295,48 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) // Work out where we're going to move things to. // Determine how much of the vector to use as pre-capacity, and how much as post-capacity. + // If we're adding to the end, we'll add all the new space to the end. // If the vector had no free post-capacity (length >= m_vectorLength), don't give it any. // If it did, we calculate the amount that will remain based on an atomic decay - leave the // vector with half the post-capacity it had previously. unsigned postCapacity = 0; - if (length < storage->vectorLength()) { + if (!addToFront) + postCapacity = max(newStorageCapacity - requiredVectorLength, count); + else if (length < storage->vectorLength()) { // Atomic decay, + the post-capacity cannot be greater than what is available. postCapacity = min((storage->vectorLength() - length) >> 1, newStorageCapacity - requiredVectorLength); // If we're moving contents within the same allocation, the post-capacity is being reduced. ASSERT(newAllocBase != butterfly->base(structure()) || postCapacity < storage->vectorLength() - length); } - + unsigned newVectorLength = requiredVectorLength + postCapacity; unsigned newIndexBias = newStorageCapacity - newVectorLength; Butterfly* newButterfly = Butterfly::fromBase(newAllocBase, newIndexBias, propertyCapacity); - - memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength); - memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); - + + if (addToFront) { + ASSERT(count + usedVectorLength <= newVectorLength); + memmove(newButterfly->arrayStorage()->m_vector + count, storage->m_vector, sizeof(JSValue) * usedVectorLength); + memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); + } else if ((newAllocBase != butterfly->base(structure())) || (newIndexBias != storage->m_indexBias)) { + memmove(newButterfly->propertyStorage() - propertySize, butterfly->propertyStorage() - propertySize, sizeof(JSValue) * propertySize + sizeof(IndexingHeader) + ArrayStorage::sizeFor(0)); + memmove(newButterfly->arrayStorage()->m_vector, storage->m_vector, sizeof(JSValue) * usedVectorLength); + + WriteBarrier<Unknown>* newVector = newButterfly->arrayStorage()->m_vector; + for (unsigned i = requiredVectorLength; i < newVectorLength; i++) + newVector[i].clear(); + } + newButterfly->arrayStorage()->setVectorLength(newVectorLength); newButterfly->arrayStorage()->m_indexBias = newIndexBias; - + m_butterfly = newButterfly; return true; } -bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException) +bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, bool throwException, ArrayStorage* storage) { - ArrayStorage* storage = ensureArrayStorage(exec->globalData()); unsigned length = storage->length(); // If the length is read only then we enter sparse mode, so should enter the following 'if'. @@ -343,7 +353,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException keys.reserveCapacity(min(map->size(), static_cast<size_t>(length - newLength))); SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) { - unsigned index = static_cast<unsigned>(it->first); + unsigned index = static_cast<unsigned>(it->key); if (index < length && index >= newLength) keys.append(index); } @@ -358,7 +368,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException unsigned index = keys[--i]; SparseArrayValueMap::iterator it = map->find(index); ASSERT(it != map->notFound()); - if (it->second.attributes & DontDelete) { + if (it->value.attributes & DontDelete) { storage->setLength(index + 1); return reject(exec, throwException, "Unable to delete property."); } @@ -389,12 +399,71 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException return true; } +bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException) +{ + switch (structure()->indexingType()) { + case ArrayClass: + if (!newLength) + return true; + if (newLength >= MIN_SPARSE_ARRAY_INDEX) { + return setLengthWithArrayStorage( + exec, newLength, throwException, + convertContiguousToArrayStorage(exec->globalData())); + } + createInitialContiguous(exec->globalData(), newLength); + return true; + + case ArrayWithContiguous: + if (newLength == m_butterfly->publicLength()) + return true; + if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push. + || (newLength >= MIN_SPARSE_ARRAY_INDEX + && !isDenseEnoughForVector(newLength, countElementsInContiguous(m_butterfly)))) { + return setLengthWithArrayStorage( + exec, newLength, throwException, + convertContiguousToArrayStorage(exec->globalData())); + } + if (newLength > m_butterfly->publicLength()) { + ensureContiguousLength(exec->globalData(), newLength); + return true; + } + for (unsigned i = m_butterfly->publicLength(); i-- > newLength;) + m_butterfly->contiguous()[i].clear(); + m_butterfly->setPublicLength(newLength); + return true; + + case ArrayWithArrayStorage: + case ArrayWithSlowPutArrayStorage: + return setLengthWithArrayStorage(exec, newLength, throwException, arrayStorage()); + + default: + CRASH(); + return false; + } +} + JSValue JSArray::pop(ExecState* exec) { switch (structure()->indexingType()) { case ArrayClass: return jsUndefined(); + case ArrayWithContiguous: { + unsigned length = m_butterfly->publicLength(); + + if (!length--) + return jsUndefined(); + + ASSERT(length < m_butterfly->vectorLength()); + JSValue value = m_butterfly->contiguous()[length].get(); + if (value) { + m_butterfly->contiguous()[length].clear(); + m_butterfly->setPublicLength(length); + return value; + } + break; + } + case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); @@ -418,26 +487,28 @@ JSValue JSArray::pop(ExecState* exec) return element; } } - - // Let element be the result of calling the [[Get]] internal method of O with argument indx. - JSValue element = get(exec, index); - if (exec->hadException()) - return jsUndefined(); - // Call the [[Delete]] internal method of O with arguments indx and true. - if (!deletePropertyByIndex(this, exec, index)) { - throwTypeError(exec, "Unable to delete property."); - return jsUndefined(); - } - // Call the [[Put]] internal method of O with arguments "length", indx, and true. - setLength(exec, index, true); - // Return element. - return element; + break; } default: - ASSERT_NOT_REACHED(); + CRASH(); return JSValue(); } + + unsigned index = getArrayLength() - 1; + // Let element be the result of calling the [[Get]] internal method of O with argument indx. + JSValue element = get(exec, index); + if (exec->hadException()) + return jsUndefined(); + // Call the [[Delete]] internal method of O with arguments indx and true. + if (!deletePropertyByIndex(this, exec, index)) { + throwTypeError(exec, "Unable to delete property."); + return jsUndefined(); + } + // Call the [[Put]] internal method of O with arguments "length", indx, and true. + setLength(exec, index, true); + // Return element. + return element; } // Push & putIndex are almost identical, with two small differences. @@ -451,6 +522,26 @@ void JSArray::push(ExecState* exec, JSValue value) break; } + case ArrayWithContiguous: { + unsigned length = m_butterfly->publicLength(); + ASSERT(length <= m_butterfly->vectorLength()); + if (length < m_butterfly->vectorLength()) { + m_butterfly->contiguous()[length].set(exec->globalData(), this, value); + m_butterfly->setPublicLength(length + 1); + return; + } + + if (length > MAX_ARRAY_INDEX) { + methodTable()->putByIndex(this, exec, length, value, true); + if (!exec->hadException()) + throwError(exec, createRangeError(exec, "Invalid array length")); + return; + } + + putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, length, value); + return; + } + case ArrayWithSlowPutArrayStorage: { unsigned oldLength = length(); if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true)) { @@ -492,59 +583,139 @@ void JSArray::push(ExecState* exec, JSValue value) } } -bool JSArray::shiftCount(ExecState* exec, unsigned count) +bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage) { - ASSERT(count > 0); - - ArrayStorage* storage = ensureArrayStorage(exec->globalData()); - unsigned oldLength = storage->length(); ASSERT(count <= oldLength); // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. - if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode()) + if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode() || shouldUseSlowPut(structure()->indexingType())) return false; if (!oldLength) return true; + unsigned length = oldLength - count; + storage->m_numValuesInVector -= count; - storage->setLength(oldLength - count); + storage->setLength(length); unsigned vectorLength = storage->vectorLength(); + if (!vectorLength) + return true; + + if (startIndex >= vectorLength) + return true; + + if (startIndex + count > vectorLength) + count = vectorLength - startIndex; + + unsigned usedVectorLength = min(vectorLength, oldLength); + + vectorLength -= count; + storage->setVectorLength(vectorLength); + if (vectorLength) { - count = min(vectorLength, (unsigned)count); - - vectorLength -= count; - storage->setVectorLength(vectorLength); - - if (vectorLength) { + if (startIndex < usedVectorLength - (startIndex + count)) { + if (startIndex) { + memmove( + storage->m_vector + count, + storage->m_vector, + sizeof(JSValue) * startIndex); + } m_butterfly = m_butterfly->shift(structure(), count); storage = m_butterfly->arrayStorage(); storage->m_indexBias += count; + } else { + memmove( + storage->m_vector + startIndex, + storage->m_vector + startIndex + count, + sizeof(JSValue) * (usedVectorLength - (startIndex + count))); + for (unsigned i = usedVectorLength - count; i < usedVectorLength; ++i) + storage->m_vector[i].clear(); } } return true; } +bool JSArray::shiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count) +{ + ASSERT(count > 0); + + switch (structure()->indexingType()) { + case ArrayClass: + return true; + + case ArrayWithContiguous: { + unsigned oldLength = m_butterfly->publicLength(); + ASSERT(count <= oldLength); + + // We may have to walk the entire array to do the shift. We're willing to do + // so only if it's not horribly slow. + if (oldLength - (startIndex + count) >= MIN_SPARSE_ARRAY_INDEX) + return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + + unsigned end = oldLength - count; + for (unsigned i = startIndex; i < end; ++i) { + // Storing to a hole is fine since we're still having a good time. But reading + // from a hole is totally not fine, since we might have to read from the proto + // chain. + JSValue v = m_butterfly->contiguous()[i + count].get(); + if (UNLIKELY(!v)) { + // The purpose of this path is to ensure that we don't make the same + // mistake in the future: shiftCountWithArrayStorage() can't do anything + // about holes (at least for now), but it can detect them quickly. So + // we convert to array storage and then allow the array storage path to + // figure it out. + return shiftCountWithArrayStorage(startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + } + // No need for a barrier since we're just moving data around in the same vector. + // This is in line with our standing assumption that we won't have a deletion + // barrier. + m_butterfly->contiguous()[i].setWithoutWriteBarrier(v); + } + for (unsigned i = end; i < oldLength; ++i) + m_butterfly->contiguous()[i].clear(); + + m_butterfly->setPublicLength(oldLength - count); + return true; + } + + case ArrayWithArrayStorage: + case ArrayWithSlowPutArrayStorage: + return shiftCountWithArrayStorage(startIndex, count, arrayStorage()); + + default: + CRASH(); + return false; + } +} + // Returns true if the unshift can be handled, false to fallback. -bool JSArray::unshiftCount(ExecState* exec, unsigned count) +bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, unsigned count, ArrayStorage* storage) { - ArrayStorage* storage = ensureArrayStorage(exec->globalData()); unsigned length = storage->length(); + ASSERT(startIndex <= length); + // If the array contains holes or is otherwise in an abnormal state, // use the generic algorithm in ArrayPrototype. - if (length != storage->m_numValuesInVector || storage->inSparseMode()) + if (length != storage->m_numValuesInVector || storage->inSparseMode() || shouldUseSlowPut(structure()->indexingType())) return false; - if (storage->m_indexBias >= count) { + bool moveFront = !startIndex || startIndex < length / 2; + + unsigned vectorLength = storage->vectorLength(); + + if (moveFront && storage->m_indexBias >= count) { m_butterfly = storage->butterfly()->unshift(structure(), count); storage = m_butterfly->arrayStorage(); storage->m_indexBias -= count; - storage->setVectorLength(storage->vectorLength() + count); - } else if (unshiftCountSlowCase(exec->globalData(), count)) + storage->setVectorLength(vectorLength + count); + } else if (!moveFront && vectorLength - length >= count) + storage = storage->butterfly()->arrayStorage(); + else if (unshiftCountSlowCase(exec->globalData(), moveFront, count)) storage = arrayStorage(); else { throwOutOfMemoryError(exec); @@ -552,11 +723,61 @@ bool JSArray::unshiftCount(ExecState* exec, unsigned count) } WriteBarrier<Unknown>* vector = storage->m_vector; + + if (startIndex) { + if (moveFront) + memmove(vector, vector + count, startIndex * sizeof(JSValue)); + else if (length - startIndex) + memmove(vector + startIndex + count, vector + startIndex, (length - startIndex) * sizeof(JSValue)); + } + for (unsigned i = 0; i < count; i++) - vector[i].clear(); + vector[i + startIndex].clear(); return true; } +bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startIndex, unsigned count) +{ + switch (structure()->indexingType()) { + case ArrayClass: + // We could handle this. But it shouldn't ever come up, so we won't. + return false; + + case ArrayWithContiguous: { + unsigned oldLength = m_butterfly->publicLength(); + + // We may have to walk the entire array to do the unshift. We're willing to do so + // only if it's not horribly slow. + if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX) + return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + + ensureContiguousLength(exec->globalData(), oldLength + count); + + for (unsigned i = oldLength; i-- > startIndex;) { + JSValue v = m_butterfly->contiguous()[i].get(); + if (UNLIKELY(!v)) + return unshiftCountWithArrayStorage(exec, startIndex, count, convertContiguousToArrayStorage(exec->globalData())); + m_butterfly->contiguous()[i + count].setWithoutWriteBarrier(v); + } + + // NOTE: we're leaving being garbage in the part of the array that we shifted out + // of. This is fine because the caller is required to store over that area, and + // in contiguous mode storing into a hole is guaranteed to behave exactly the same + // as storing over an existing element. + + return true; + } + + case ArrayWithArrayStorage: + case ArrayWithSlowPutArrayStorage: + return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage()); + + default: + CRASH(); + return false; + } +} + static int compareNumbersForQSort(const void* a, const void* b) { double da = static_cast<const JSValue*>(a)->asNumber(); @@ -571,6 +792,45 @@ static int compareByStringPairForQSort(const void* a, const void* b) return codePointCompare(va->second, vb->second); } +template<IndexingType indexingType> +void JSArray::sortNumericVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + ASSERT(indexingType == ArrayWithContiguous || indexingType == ArrayWithArrayStorage); + + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<indexingType>( + lengthNotIncludingUndefined, + newRelevantLength); + + WriteBarrier<Unknown>* data = indexingData<indexingType>(); + + if (indexingType == ArrayWithArrayStorage && arrayStorage()->m_sparseMap.get()) { + throwOutOfMemoryError(exec); + return; + } + + if (!lengthNotIncludingUndefined) + return; + + bool allValuesAreNumbers = true; + for (size_t i = 0; i < newRelevantLength; ++i) { + if (!data[i].isNumber()) { + allValuesAreNumbers = false; + break; + } + } + + if (!allValuesAreNumbers) + return sort(exec, compareFunction, callType, callData); + + // For numeric comparison, which is fast, qsort is faster than mergesort. We + // also don't require mergesort's stability, since there's no user visible + // side-effect from swapping the order of equal primitive values. + qsort(data, newRelevantLength, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort); + return; +} + void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { ASSERT(!inSparseIndexingMode()); @@ -579,123 +839,129 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal case ArrayClass: return; - case ArrayWithArrayStorage: { - unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData()); - ArrayStorage* storage = m_butterfly->arrayStorage(); - - if (storage->m_sparseMap.get()) { - throwOutOfMemoryError(exec); - return; - } - - if (!lengthNotIncludingUndefined) - return; - - bool allValuesAreNumbers = true; - size_t size = storage->m_numValuesInVector; - for (size_t i = 0; i < size; ++i) { - if (!storage->m_vector[i].isNumber()) { - allValuesAreNumbers = false; - break; - } - } - - if (!allValuesAreNumbers) - return sort(exec, compareFunction, callType, callData); - - // For numeric comparison, which is fast, qsort is faster than mergesort. We - // also don't require mergesort's stability, since there's no user visible - // side-effect from swapping the order of equal primitive values. - qsort(storage->m_vector, size, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort); - + case ArrayWithContiguous: + sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); + return; + + case ArrayWithArrayStorage: + sortNumericVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData); return; - } default: - ASSERT_NOT_REACHED(); + CRASH(); + return; } } -void JSArray::sort(ExecState* exec) +template<IndexingType indexingType> +void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, unsigned relevantLength) { - ASSERT(!inSparseIndexingMode()); - - switch (structure()->indexingType()) { - case ArrayClass: + if (!relevantLength) return; + + JSGlobalData& globalData = exec->globalData(); + + // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that. + // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary + // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return + // random or otherwise changing results, effectively making compare function inconsistent. - case ArrayWithArrayStorage: { - unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData()); - ArrayStorage* storage = m_butterfly->arrayStorage(); - if (storage->m_sparseMap.get()) { - throwOutOfMemoryError(exec); - return; - } - - if (!lengthNotIncludingUndefined) - return; - - // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that. - // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary - // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return - // random or otherwise changing results, effectively making compare function inconsistent. - - Vector<ValueStringPair> values(lengthNotIncludingUndefined); - if (!values.begin()) { - throwOutOfMemoryError(exec); - return; - } + Vector<ValueStringPair> values(relevantLength); + if (!values.begin()) { + throwOutOfMemoryError(exec); + return; + } - Heap::heap(this)->pushTempSortVector(&values); + Heap::heap(this)->pushTempSortVector(&values); - bool isSortingPrimitiveValues = true; - for (size_t i = 0; i < lengthNotIncludingUndefined; i++) { - JSValue value = storage->m_vector[i].get(); - ASSERT(!value.isUndefined()); - values[i].first = value; - isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); - } + bool isSortingPrimitiveValues = true; + for (size_t i = 0; i < relevantLength; i++) { + JSValue value = begin[i].get(); + ASSERT(!value.isUndefined()); + values[i].first = value; + isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive(); + } - // FIXME: The following loop continues to call toString on subsequent values even after - // a toString call raises an exception. + // FIXME: The following loop continues to call toString on subsequent values even after + // a toString call raises an exception. - for (size_t i = 0; i < lengthNotIncludingUndefined; i++) - values[i].second = values[i].first.toWTFStringInline(exec); + for (size_t i = 0; i < relevantLength; i++) + values[i].second = values[i].first.toWTFStringInline(exec); - if (exec->hadException()) { - Heap::heap(this)->popTempSortVector(&values); - return; - } + if (exec->hadException()) { + Heap::heap(this)->popTempSortVector(&values); + return; + } - // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather - // than O(N log N). + // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather + // than O(N log N). #if HAVE(MERGESORT) - if (isSortingPrimitiveValues) - qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); - else - mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); -#else - // FIXME: The qsort library function is likely to not be a stable sort. - // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort. + if (isSortingPrimitiveValues) qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); + else + mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); +#else + // FIXME: The qsort library function is likely to not be a stable sort. + // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort. + qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort); #endif + + // If the toString function changed the length of the array or vector storage, + // increase the length to handle the orignal number of actual values. + switch (indexingType) { + case ArrayWithContiguous: + ensureContiguousLength(globalData, relevantLength); + break; - // If the toString function changed the length of the array or vector storage, - // increase the length to handle the orignal number of actual values. - if (storage->vectorLength() < lengthNotIncludingUndefined) { - increaseVectorLength(exec->globalData(), lengthNotIncludingUndefined); - storage = m_butterfly->arrayStorage(); + case ArrayWithArrayStorage: + if (arrayStorage()->vectorLength() < relevantLength) { + increaseVectorLength(exec->globalData(), relevantLength); + begin = arrayStorage()->m_vector; } - if (storage->length() < lengthNotIncludingUndefined) - storage->setLength(lengthNotIncludingUndefined); + if (arrayStorage()->length() < relevantLength) + arrayStorage()->setLength(relevantLength); + break; + + default: + CRASH(); + } + + for (size_t i = 0; i < relevantLength; i++) + begin[i].set(globalData, this, values[i].first); + + Heap::heap(this)->popTempSortVector(&values); +} + +void JSArray::sort(ExecState* exec) +{ + ASSERT(!inSparseIndexingMode()); + + switch (structure()->indexingType()) { + case ArrayClass: + return; - JSGlobalData& globalData = exec->globalData(); - for (size_t i = 0; i < lengthNotIncludingUndefined; i++) - storage->m_vector[i].set(globalData, this, values[i].first); + case ArrayWithContiguous: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithContiguous>( + lengthNotIncludingUndefined, newRelevantLength); - Heap::heap(this)->popTempSortVector(&values); + sortCompactedVector<ArrayWithContiguous>( + exec, m_butterfly->contiguous(), lengthNotIncludingUndefined); + return; + } + + case ArrayWithArrayStorage: { + unsigned lengthNotIncludingUndefined; + unsigned newRelevantLength; + compactForSorting<ArrayWithArrayStorage>( + lengthNotIncludingUndefined, newRelevantLength); + ArrayStorage* storage = m_butterfly->arrayStorage(); + ASSERT(!storage->m_sparseMap); + sortCompactedVector<ArrayWithArrayStorage>( + exec, storage->m_vector, lengthNotIncludingUndefined); return; } @@ -781,122 +1047,116 @@ struct AVLTreeAbstractorForArrayCompare { static handle null() { return 0x7FFFFFFF; } }; -void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +template<IndexingType indexingType> +void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { ASSERT(!inSparseIndexingMode()); + ASSERT(indexingType == structure()->indexingType()); - switch (structure()->indexingType()) { - case ArrayClass: - return; - - case ArrayWithArrayStorage: { - ArrayStorage* storage = m_butterfly->arrayStorage(); - - // FIXME: This ignores exceptions raised in the compare function or in toNumber. + // FIXME: This ignores exceptions raised in the compare function or in toNumber. - // The maximum tree depth is compiled in - but the caller is clearly up to no good - // if a larger array is passed. - ASSERT(storage->length() <= static_cast<unsigned>(std::numeric_limits<int>::max())); - if (storage->length() > static_cast<unsigned>(std::numeric_limits<int>::max())) - return; - - unsigned usedVectorLength = min(storage->length(), storage->vectorLength()); - unsigned nodeCount = usedVectorLength + (storage->m_sparseMap ? storage->m_sparseMap->size() : 0); - - if (!nodeCount) - return; - - AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items - tree.abstractor().m_exec = exec; - tree.abstractor().m_compareFunction = compareFunction; - tree.abstractor().m_compareCallType = callType; - tree.abstractor().m_compareCallData = &callData; - tree.abstractor().m_nodes.grow(nodeCount); + // The maximum tree depth is compiled in - but the caller is clearly up to no good + // if a larger array is passed. + ASSERT(m_butterfly->publicLength() <= static_cast<unsigned>(std::numeric_limits<int>::max())); + if (m_butterfly->publicLength() > static_cast<unsigned>(std::numeric_limits<int>::max())) + return; - if (callType == CallTypeJS) - tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2)); + unsigned usedVectorLength = relevantLength<indexingType>(); + unsigned nodeCount = usedVectorLength; - if (!tree.abstractor().m_nodes.begin()) { - throwOutOfMemoryError(exec); - return; - } + if (!nodeCount) + return; - // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified - // right out from under us while we're building the tree here. + AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items + tree.abstractor().m_exec = exec; + tree.abstractor().m_compareFunction = compareFunction; + tree.abstractor().m_compareCallType = callType; + tree.abstractor().m_compareCallData = &callData; + tree.abstractor().m_nodes.grow(nodeCount); - unsigned numDefined = 0; - unsigned numUndefined = 0; + if (callType == CallTypeJS) + tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2)); - // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. - for (; numDefined < usedVectorLength; ++numDefined) { - JSValue v = storage->m_vector[numDefined].get(); - if (!v || v.isUndefined()) - break; - tree.abstractor().m_nodes[numDefined].value = v; - tree.insert(numDefined); - } - for (unsigned i = numDefined; i < usedVectorLength; ++i) { - JSValue v = storage->m_vector[i].get(); - if (v) { - if (v.isUndefined()) - ++numUndefined; - else { - tree.abstractor().m_nodes[numDefined].value = v; - tree.insert(numDefined); - ++numDefined; - } - } - } - - unsigned newUsedVectorLength = numDefined + numUndefined; + if (!tree.abstractor().m_nodes.begin()) { + throwOutOfMemoryError(exec); + return; + } - if (SparseArrayValueMap* map = storage->m_sparseMap.get()) { - newUsedVectorLength += map->size(); - if (newUsedVectorLength > storage->vectorLength()) { - // Check that it is possible to allocate an array large enough to hold all the entries. - if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(exec->globalData(), newUsedVectorLength)) { - throwOutOfMemoryError(exec); - return; - } - storage = m_butterfly->arrayStorage(); - } - - SparseArrayValueMap::const_iterator end = map->end(); - for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) { - tree.abstractor().m_nodes[numDefined].value = it->second.getNonSparseMode(); + // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified + // right out from under us while we're building the tree here. + + unsigned numDefined = 0; + unsigned numUndefined = 0; + + // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree. + for (; numDefined < usedVectorLength; ++numDefined) { + if (numDefined > m_butterfly->vectorLength()) + break; + JSValue v = indexingData<indexingType>()[numDefined].get(); + if (!v || v.isUndefined()) + break; + tree.abstractor().m_nodes[numDefined].value = v; + tree.insert(numDefined); + } + for (unsigned i = numDefined; i < usedVectorLength; ++i) { + if (i > m_butterfly->vectorLength()) + break; + JSValue v = indexingData<indexingType>()[i].get(); + if (v) { + if (v.isUndefined()) + ++numUndefined; + else { + tree.abstractor().m_nodes[numDefined].value = v; tree.insert(numDefined); ++numDefined; } - - deallocateSparseIndexMap(); } + } - ASSERT(tree.abstractor().m_nodes.size() >= numDefined); - - // FIXME: If the compare function changed the length of the array, the following might be - // modifying the vector incorrectly. + unsigned newUsedVectorLength = numDefined + numUndefined; - // Copy the values back into m_storage. - AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; - iter.start_iter_least(tree); - JSGlobalData& globalData = exec->globalData(); - for (unsigned i = 0; i < numDefined; ++i) { - storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); - ++iter; - } + // The array size may have changed. Figure out the new bounds. + unsigned newestUsedVectorLength = relevantLength<indexingType>(); - // Put undefined values back in. - for (unsigned i = numDefined; i < newUsedVectorLength; ++i) - storage->m_vector[i].setUndefined(); + unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast<unsigned>(tree.abstractor().m_nodes.size())); + unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength); + unsigned clearElementsThreshold = min(newestUsedVectorLength, usedVectorLength); - // Ensure that unused values in the vector are zeroed out. - for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) - storage->m_vector[i].clear(); - - storage->m_numValuesInVector = newUsedVectorLength; + // Copy the values back into m_storage. + AVLTree<AVLTreeAbstractorForArrayCompare, 44>::Iterator iter; + iter.start_iter_least(tree); + JSGlobalData& globalData = exec->globalData(); + for (unsigned i = 0; i < elementsToExtractThreshold; ++i) { + indexingData<indexingType>()[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value); + ++iter; + } + // Put undefined values back in. + for (unsigned i = elementsToExtractThreshold; i < undefinedElementsThreshold; ++i) + indexingData<indexingType>()[i].setUndefined(); + + // Ensure that unused values in the vector are zeroed out. + for (unsigned i = undefinedElementsThreshold; i < clearElementsThreshold; ++i) + indexingData<indexingType>()[i].clear(); + + if (hasArrayStorage(indexingType)) + arrayStorage()->m_numValuesInVector = newUsedVectorLength; +} + +void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +{ + ASSERT(!inSparseIndexingMode()); + + switch (structure()->indexingType()) { + case ArrayClass: + return; + case ArrayWithContiguous: + sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); + return; + + case ArrayWithArrayStorage: + sortVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData); return; - } default: ASSERT_NOT_REACHED(); @@ -905,129 +1165,127 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) { + unsigned i = 0; + unsigned vectorEnd; + WriteBarrier<Unknown>* vector; + switch (structure()->indexingType()) { case ArrayClass: return; + + case ArrayWithContiguous: { + vectorEnd = m_butterfly->publicLength(); + vector = m_butterfly->contiguous(); + break; + } case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); - WriteBarrier<Unknown>* vector = storage->m_vector; - unsigned vectorEnd = min(storage->length(), storage->vectorLength()); - unsigned i = 0; - for (; i < vectorEnd; ++i) { - WriteBarrier<Unknown>& v = vector[i]; - if (!v) - break; - args.append(v.get()); - } - - for (; i < storage->length(); ++i) - args.append(get(exec, i)); - return; + vector = storage->m_vector; + vectorEnd = min(storage->length(), storage->vectorLength()); + break; } default: - ASSERT_NOT_REACHED(); + CRASH(); + vector = 0; + vectorEnd = 0; + break; } + + for (; i < vectorEnd; ++i) { + WriteBarrier<Unknown>& v = vector[i]; + if (!v) + break; + args.append(v.get()); + } + + for (; i < length(); ++i) + args.append(get(exec, i)); } void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length) { + unsigned i = 0; + WriteBarrier<Unknown>* vector; + unsigned vectorEnd; + ASSERT(length == this->length()); switch (structure()->indexingType()) { case ArrayClass: return; + case ArrayWithContiguous: { + vector = m_butterfly->contiguous(); + vectorEnd = m_butterfly->publicLength(); + break; + } + case ARRAY_WITH_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); - unsigned i = 0; - WriteBarrier<Unknown>* vector = storage->m_vector; - unsigned vectorEnd = min(length, storage->vectorLength()); - for (; i < vectorEnd; ++i) { - WriteBarrier<Unknown>& v = vector[i]; - if (!v) - break; - callFrame->setArgument(i, v.get()); - } - - for (; i < length; ++i) - callFrame->setArgument(i, get(exec, i)); - return; + vector = storage->m_vector; + vectorEnd = min(length, storage->vectorLength()); + break; } default: - ASSERT_NOT_REACHED(); + CRASH(); + vector = 0; + vectorEnd = 0; + break; + } + + for (; i < vectorEnd; ++i) { + WriteBarrier<Unknown>& v = vector[i]; + if (!v) + break; + callFrame->setArgument(i, v.get()); } + + for (; i < length; ++i) + callFrame->setArgument(i, get(exec, i)); } -unsigned JSArray::compactForSorting(JSGlobalData& globalData) +template<IndexingType indexingType> +void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength) { ASSERT(!inSparseIndexingMode()); + ASSERT(indexingType == structure()->indexingType()); - switch (structure()->indexingType()) { - case ArrayClass: - return 0; - - case ArrayWithArrayStorage: { - ArrayStorage* storage = m_butterfly->arrayStorage(); - - unsigned usedVectorLength = min(storage->length(), storage->vectorLength()); - - unsigned numDefined = 0; - unsigned numUndefined = 0; - - for (; numDefined < usedVectorLength; ++numDefined) { - JSValue v = storage->m_vector[numDefined].get(); - if (!v || v.isUndefined()) - break; - } + unsigned myRelevantLength = relevantLength<indexingType>(); + + numDefined = 0; + unsigned numUndefined = 0; - for (unsigned i = numDefined; i < usedVectorLength; ++i) { - JSValue v = storage->m_vector[i].get(); - if (v) { - if (v.isUndefined()) - ++numUndefined; - else - storage->m_vector[numDefined++].setWithoutWriteBarrier(v); - } - } + for (; numDefined < myRelevantLength; ++numDefined) { + JSValue v = indexingData<indexingType>()[numDefined].get(); + if (!v || v.isUndefined()) + break; + } - unsigned newUsedVectorLength = numDefined + numUndefined; - - if (SparseArrayValueMap* map = storage->m_sparseMap.get()) { - newUsedVectorLength += map->size(); - if (newUsedVectorLength > storage->vectorLength()) { - // Check that it is possible to allocate an array large enough to hold all the entries - if not, - // exception is thrown by caller. - if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(globalData, newUsedVectorLength)) - return 0; - - storage = m_butterfly->arrayStorage(); - } - - SparseArrayValueMap::const_iterator end = map->end(); - for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) - storage->m_vector[numDefined++].setWithoutWriteBarrier(it->second.getNonSparseMode()); - - deallocateSparseIndexMap(); + for (unsigned i = numDefined; i < myRelevantLength; ++i) { + JSValue v = indexingData<indexingType>()[i].get(); + if (v) { + if (v.isUndefined()) + ++numUndefined; + else + indexingData<indexingType>()[numDefined++].setWithoutWriteBarrier(v); } - - for (unsigned i = numDefined; i < newUsedVectorLength; ++i) - storage->m_vector[i].setUndefined(); - for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) - storage->m_vector[i].clear(); - - storage->m_numValuesInVector = newUsedVectorLength; - - return numDefined; } - default: - ASSERT_NOT_REACHED(); - return 0; - } -} + newRelevantLength = numDefined + numUndefined; + + if (hasArrayStorage(indexingType)) + ASSERT(!arrayStorage()->m_sparseMap); + + for (unsigned i = numDefined; i < newRelevantLength; ++i) + indexingData<indexingType>()[i].setUndefined(); + for (unsigned i = newRelevantLength; i < myRelevantLength; ++i) + indexingData<indexingType>()[i].clear(); + if (hasArrayStorage(indexingType)) + arrayStorage()->m_numValuesInVector = newRelevantLength; +} } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index 6e539c9db..d4622aacc 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -71,8 +71,60 @@ namespace JSC { void push(ExecState*, JSValue); JSValue pop(ExecState*); - bool shiftCount(ExecState*, unsigned count); - bool unshiftCount(ExecState*, unsigned count); + enum ShiftCountMode { + // This form of shift hints that we're doing queueing. With this assumption in hand, + // we convert to ArrayStorage, which has queue optimizations. + ShiftCountForShift, + + // This form of shift hints that we're just doing care and feeding on an array that + // is probably typically used for ordinary accesses. With this assumption in hand, + // we try to preserve whatever indexing type it has already. + ShiftCountForSplice + }; + + bool shiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) + { + return shiftCountWithArrayStorage(startIndex, count, ensureArrayStorage(exec->globalData())); + } + bool shiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) + { + return shiftCountWithAnyIndexingType(exec, startIndex, count); + } + template<ShiftCountMode shiftCountMode> + bool shiftCount(ExecState* exec, unsigned startIndex, unsigned count) + { + switch (shiftCountMode) { + case ShiftCountForShift: + return shiftCountForShift(exec, startIndex, count); + case ShiftCountForSplice: + return shiftCountForSplice(exec, startIndex, count); + default: + CRASH(); + return false; + } + } + + bool unshiftCountForShift(ExecState* exec, unsigned startIndex, unsigned count) + { + return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(exec->globalData())); + } + bool unshiftCountForSplice(ExecState* exec, unsigned startIndex, unsigned count) + { + return unshiftCountWithAnyIndexingType(exec, startIndex, count); + } + template<ShiftCountMode shiftCountMode> + bool unshiftCount(ExecState* exec, unsigned startIndex, unsigned count) + { + switch (shiftCountMode) { + case ShiftCountForShift: + return unshiftCountForShift(exec, startIndex, count); + case ShiftCountForSplice: + return unshiftCountForSplice(exec, startIndex, count); + default: + CRASH(); + return false; + } + } void fillArgList(ExecState*, MarkedArgumentBuffer&); void copyToArguments(ExecState*, CallFrame*, uint32_t length); @@ -94,18 +146,44 @@ namespace JSC { { ArrayStorage* storage = arrayStorageOrNull(); if (!storage) - return false; + return true; SparseArrayValueMap* map = storage->m_sparseMap.get(); return !map || !map->lengthIsReadOnly(); } + + bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); + bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*); - void setLengthWritable(ExecState*, bool writable); + bool unshiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); + bool unshiftCountWithArrayStorage(ExecState*, unsigned startIndex, unsigned count, ArrayStorage*); + bool unshiftCountSlowCase(JSGlobalData&, bool, unsigned); + + template<IndexingType indexingType> + void sortNumericVector(ExecState*, JSValue compareFunction, CallType, const CallData&); + + template<IndexingType indexingType> + void sortCompactedVector(ExecState*, WriteBarrier<Unknown>* begin, unsigned relevantLength); + + template<IndexingType indexingType> + void sortVector(ExecState*, JSValue compareFunction, CallType, const CallData&); - bool unshiftCountSlowCase(JSGlobalData&, unsigned count); + bool setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*); + void setLengthWritable(ExecState*, bool writable); - unsigned compactForSorting(JSGlobalData&); + template<IndexingType indexingType> + void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); }; + inline Butterfly* createContiguousArrayButterfly(JSGlobalData& globalData, unsigned length) + { + IndexingHeader header; + header.setVectorLength(std::max(length, BASE_VECTOR_LEN)); + header.setPublicLength(length); + Butterfly* result = Butterfly::create( + globalData, 0, 0, true, header, header.vectorLength() * sizeof(EncodedJSValue)); + return result; + } + inline Butterfly* createArrayButterfly(JSGlobalData& globalData, unsigned initialLength) { Butterfly* butterfly = Butterfly::create( @@ -121,7 +199,16 @@ namespace JSC { inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned initialLength) { - Butterfly* butterfly = createArrayButterfly(globalData, initialLength); + Butterfly* butterfly; + if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { + butterfly = createContiguousArrayButterfly(globalData, initialLength); + ASSERT(initialLength < MIN_SPARSE_ARRAY_INDEX); + } else { + ASSERT( + structure->indexingType() == ArrayWithSlowPutArrayStorage + || (initialLength && structure->indexingType() == ArrayWithArrayStorage)); + butterfly = createArrayButterfly(globalData, initialLength); + } JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); array->finishCreation(globalData); return array; @@ -133,15 +220,26 @@ namespace JSC { if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) return 0; - void* temp; - if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, ArrayStorage::sizeFor(vectorLength)), &temp)) - return 0; - Butterfly* 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; + Butterfly* butterfly; + if (LIKELY(structure->indexingType() == ArrayWithContiguous)) { + + void* temp; + if (!globalData.heap.tryAllocateStorage(Butterfly::totalSize(0, 0, true, vectorLength * sizeof(EncodedJSValue)), &temp)) + return 0; + butterfly = Butterfly::fromBase(temp, 0, 0); + butterfly->setVectorLength(vectorLength); + butterfly->setPublicLength(initialLength); + } else { + void* temp; + if (!globalData.heap.tryAllocateStorage(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; + } JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); array->finishCreation(globalData); diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp index 3815c144e..d8f611477 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp @@ -31,7 +31,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSBoundFunction); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSBoundFunction); const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) }; diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp index 739247fb2..f6f4d716d 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -38,6 +38,10 @@ void JSCell::destroy(JSCell* cell) cell->JSCell::~JSCell(); } +void JSCell::copyBackingStore(JSCell*, CopyVisitor&) +{ +} + bool JSCell::getString(ExecState* exec, String& stringValue) const { if (!isString()) diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h index cf6f4ec45..a39af1283 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -31,12 +31,15 @@ #include "JSValueInlineMethods.h" #include "SlotVisitor.h" #include "SlotVisitorInlineMethods.h" +#include "TypedArrayDescriptor.h" #include "WriteBarrier.h" #include <wtf/Noncopyable.h> #include <wtf/TypeTraits.h> namespace JSC { + class CopyVisitor; + class JSDestructibleObject; class JSGlobalObject; class LLIntOffsetsExtractor; class PropertyDescriptor; @@ -48,19 +51,6 @@ namespace JSC { IncludeDontEnumProperties }; - enum TypedArrayType { - TypedArrayNone, - TypedArrayInt8, - TypedArrayInt16, - TypedArrayInt32, - TypedArrayUint8, - TypedArrayUint8Clamped, - TypedArrayUint16, - TypedArrayUint32, - TypedArrayFloat32, - TypedArrayFloat64 - }; - class JSCell { friend class JSValue; friend class MarkedBlock; @@ -70,6 +60,9 @@ namespace JSC { public: static const unsigned StructureFlags = 0; + static const bool needsDestruction = false; + static const bool hasImmortalStructure = false; + enum CreatingEarlyCellTag { CreatingEarlyCell }; JSCell(CreatingEarlyCellTag); @@ -108,6 +101,7 @@ namespace JSC { JS_EXPORT_PRIVATE JSObject* toObject(ExecState*, JSGlobalObject*) const; static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&); // Object operations, with the toObject operation included. const ClassInfo* classInfo() const; @@ -309,46 +303,29 @@ namespace JSC { return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject); } - template<class T> - struct NeedsDestructor { - static const bool value = !WTF::HasTrivialDestructor<T>::value; - }; - template<typename T> - void* allocateCell(Heap& heap) + void* allocateCell(Heap& heap, size_t size) { + ASSERT(size >= sizeof(T)); #if ENABLE(GC_VALIDATION) ASSERT(!heap.globalData()->isInitializingObject()); heap.globalData()->setInitializingObjectClass(&T::s_info); #endif JSCell* result = 0; - if (NeedsDestructor<T>::value) - result = static_cast<JSCell*>(heap.allocateWithDestructor(sizeof(T))); - else { - ASSERT(T::s_info.methodTable.destroy == JSCell::destroy); - result = static_cast<JSCell*>(heap.allocateWithoutDestructor(sizeof(T))); - } + if (T::needsDestruction && T::hasImmortalStructure) + result = static_cast<JSCell*>(heap.allocateWithImmortalStructureDestructor(size)); + else if (T::needsDestruction && !T::hasImmortalStructure) + result = static_cast<JSCell*>(heap.allocateWithNormalDestructor(size)); + else + result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size)); result->clearStructure(); return result; } template<typename T> - void* allocateCell(Heap& heap, size_t size) + void* allocateCell(Heap& heap) { - ASSERT(size >= sizeof(T)); -#if ENABLE(GC_VALIDATION) - ASSERT(!heap.globalData()->isInitializingObject()); - heap.globalData()->setInitializingObjectClass(&T::s_info); -#endif - JSCell* result = 0; - if (NeedsDestructor<T>::value) - result = static_cast<JSCell*>(heap.allocateWithDestructor(size)); - else { - ASSERT(T::s_info.methodTable.destroy == JSCell::destroy); - result = static_cast<JSCell*>(heap.allocateWithoutDestructor(size)); - } - result->clearStructure(); - return result; + return allocateCell<T>(heap, sizeof(T)); } inline bool isZapped(const JSCell* cell) @@ -362,7 +339,7 @@ namespace JSC { ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info)); return static_cast<To>(from); } - + template<typename To> inline To jsCast(JSValue from) { diff --git a/Source/JavaScriptCore/runtime/JSDestructibleObject.h b/Source/JavaScriptCore/runtime/JSDestructibleObject.h new file mode 100644 index 000000000..b8479be62 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSDestructibleObject.h @@ -0,0 +1,43 @@ +#ifndef JSDestructibleObject_h +#define JSDestructibleObject_h + +#include "JSObject.h" + +namespace JSC { + +struct ClassInfo; + +class JSDestructibleObject : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + static const bool needsDestruction = true; + + const ClassInfo* classInfo() const { return m_classInfo; } + +protected: + JSDestructibleObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0) + : JSNonFinalObject(globalData, structure, butterfly) + , m_classInfo(structure->classInfo()) + { + ASSERT(m_classInfo); + } + +private: + const ClassInfo* m_classInfo; +}; + +inline const ClassInfo* JSCell::classInfo() const +{ + if (MarkedBlock::blockFor(this)->destructorType() == MarkedBlock::Normal) + return static_cast<const JSDestructibleObject*>(this)->classInfo(); +#if ENABLE(GC_VALIDATION) + return m_structure.unvalidatedGet()->classInfo(); +#else + return m_structure->classInfo(); +#endif +} + +} // namespace JSC + +#endif diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp index 4afe63216..891a23930 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -48,7 +48,6 @@ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec) return throwVMError(exec, createNotAConstructorError(exec, exec->callee())); } -ASSERT_CLASS_FITS_IN_CELL(JSFunction); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFunction); const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) }; diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp index e30a7913d..bc3d00067 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -231,7 +231,9 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread interpreter->initialize(this->canUseJIT()); +#if ENABLE(JIT) initializeHostCallReturnValue(); // This is needed to convince the linker not to drop host call return support. +#endif heap.notifyIsSafeToCollect(); diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h index 603f9f82a..6cc0aad8d 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -44,6 +44,7 @@ #include "Strong.h" #include "Terminator.h" #include "TimeoutChecker.h" +#include "TypedArrayDescriptor.h" #include "WeakRandom.h" #include <wtf/BumpPointerAllocator.h> #include <wtf/Forward.h> @@ -108,24 +109,6 @@ namespace JSC { ThreadStackTypeSmall }; - struct TypedArrayDescriptor { - TypedArrayDescriptor() - : m_classInfo(0) - , m_storageOffset(0) - , m_lengthOffset(0) - { - } - TypedArrayDescriptor(const ClassInfo* classInfo, size_t storageOffset, size_t lengthOffset) - : m_classInfo(classInfo) - , m_storageOffset(storageOffset) - , m_lengthOffset(lengthOffset) - { - } - const ClassInfo* m_classInfo; - size_t m_storageOffset; - size_t m_lengthOffset; - }; - #if ENABLE(DFG_JIT) class ConservativeRoots; @@ -429,6 +412,35 @@ namespace JSC { registerTypedArrayFunction(float32, Float32); registerTypedArrayFunction(float64, Float64); #undef registerTypedArrayFunction + + const TypedArrayDescriptor* typedArrayDescriptor(TypedArrayType type) const + { + switch (type) { + case TypedArrayNone: + return 0; + case TypedArrayInt8: + return &int8ArrayDescriptor(); + case TypedArrayInt16: + return &int16ArrayDescriptor(); + case TypedArrayInt32: + return &int32ArrayDescriptor(); + case TypedArrayUint8: + return &uint8ArrayDescriptor(); + case TypedArrayUint8Clamped: + return &uint8ClampedArrayDescriptor(); + case TypedArrayUint16: + return &uint16ArrayDescriptor(); + case TypedArrayUint32: + return &uint32ArrayDescriptor(); + case TypedArrayFloat32: + return &float32ArrayDescriptor(); + case TypedArrayFloat64: + return &float64ArrayDescriptor(); + default: + CRASH(); + return 0; + } + } JSLock& apiLock() { return m_apiLock; } diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp index b0a0e8122..9eb266135 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -100,8 +100,6 @@ const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &all @end */ -ASSERT_CLASS_FITS_IN_CELL(JSGlobalObject); - // Default number of ticks before a timeout check should be done. static const int initialTickCountThreshold = 255; @@ -228,10 +226,11 @@ void JSGlobalObject::reset(JSValue prototype) m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), this, m_functionPrototype.get())); m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), this, m_objectPrototype.get())); m_callbackConstructorStructure.set(exec->globalData(), this, JSCallbackConstructor::createStructure(exec->globalData(), this, m_objectPrototype.get())); - m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSNonFinalObject>::createStructure(exec->globalData(), this, m_objectPrototype.get())); + m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get())); m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()))); - m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage)); + m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithContiguous)); + m_arrayStructureWithArrayStorage.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithArrayStorage)); m_arrayStructureForSlowPut.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get(), ArrayWithSlowPutArrayStorage)); m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get())); @@ -318,6 +317,9 @@ void JSGlobalObject::reset(JSValue prototype) GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly) }; addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals)); + + m_specialPointers[Special::CallFunction] = m_callFunction.get(); + m_specialPointers[Special::ApplyFunction] = m_applyFunction.get(); if (m_experimentsEnabled) { NamePrototype* privateNamePrototype = NamePrototype::create(exec, NamePrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())); @@ -354,7 +356,8 @@ ObjectsWithBrokenIndexingFinder::ObjectsWithBrokenIndexingFinder( inline bool hasBrokenIndexing(JSObject* object) { // This will change if we have more indexing types. - return !!(object->structure()->indexingType() & HasArrayStorage); + IndexingType type = object->structure()->indexingType(); + return hasContiguous(type) || hasFastArrayStorage(type); } void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell) @@ -407,6 +410,7 @@ void JSGlobalObject::haveABadTime(JSGlobalData& globalData) // Make sure that all JSArray allocations that load the appropriate structure from // this object now load a structure that uses SlowPut. m_arrayStructure.set(globalData, this, m_arrayStructureForSlowPut.get()); + m_arrayStructureWithArrayStorage.set(globalData, this, m_arrayStructureForSlowPut.get()); // Make sure that all objects that have indexed storage switch to the slow kind of // indexed storage. @@ -482,6 +486,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_nameScopeStructure); visitor.append(&thisObject->m_argumentsStructure); visitor.append(&thisObject->m_arrayStructure); + visitor.append(&thisObject->m_arrayStructureWithArrayStorage); visitor.append(&thisObject->m_arrayStructureForSlowPut); visitor.append(&thisObject->m_booleanObjectStructure); visitor.append(&thisObject->m_callbackConstructorStructure); @@ -502,9 +507,14 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) visitor.append(&thisObject->m_internalFunctionStructure); } +JSObject* JSGlobalObject::toThisObject(JSCell* cell, ExecState*) +{ + return jsCast<JSGlobalObject*>(cell)->globalThis(); +} + ExecState* JSGlobalObject::globalExec() { - return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize); + return CallFrame::create(m_globalCallFrame + JSStack::CallFrameHeaderSize); } void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index ad56783cc..2994aa64b 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -24,10 +24,10 @@ #include "JSArray.h" #include "JSGlobalData.h" -#include "JSGlobalThis.h" #include "JSSegmentedVariableObject.h" #include "JSWeakObjectMapRefInternal.h" #include "NumberPrototype.h" +#include "SpecialPointer.h" #include "StringPrototype.h" #include "StructureChain.h" #include "Watchpoint.h" @@ -46,12 +46,12 @@ namespace JSC { class FunctionPrototype; class GetterSetter; class GlobalCodeBlock; + class JSStack; class LLIntOffsetsExtractor; class NativeErrorConstructor; class ProgramCodeBlock; class RegExpConstructor; class RegExpPrototype; - class RegisterFile; struct ActivationStackNode; struct HashTable; @@ -77,7 +77,6 @@ namespace JSC { class JSGlobalObject : public JSSegmentedVariableObject { private: - typedef JSSegmentedVariableObject Base; typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; struct JSGlobalObjectRareData { @@ -92,7 +91,7 @@ namespace JSC { protected: - Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize]; + Register m_globalCallFrame[JSStack::CallFrameHeaderSize]; WriteBarrier<JSObject> m_globalThis; WriteBarrier<JSObject> m_methodCallDummy; @@ -127,6 +126,7 @@ namespace JSC { WriteBarrier<Structure> m_nameScopeStructure; WriteBarrier<Structure> m_argumentsStructure; WriteBarrier<Structure> m_arrayStructure; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time. + WriteBarrier<Structure> m_arrayStructureWithArrayStorage; // This gets set to m_arrayStructureForSlowPut as soon as we decide to have a bad time. WriteBarrier<Structure> m_arrayStructureForSlowPut; WriteBarrier<Structure> m_booleanObjectStructure; WriteBarrier<Structure> m_callbackConstructorStructure; @@ -146,6 +146,8 @@ namespace JSC { WriteBarrier<Structure> m_regExpStructure; WriteBarrier<Structure> m_stringObjectStructure; WriteBarrier<Structure> m_internalFunctionStructure; + + void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT. Debugger* m_debugger; @@ -168,14 +170,16 @@ namespace JSC { if (m_rareData) return; m_rareData = adoptPtr(new JSGlobalObjectRareData); - Heap::heap(this)->addFinalizer(this, clearRareData); } public: + typedef JSSegmentedVariableObject Base; + static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure) { JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(globalData.heap)) JSGlobalObject(globalData, structure); globalObject->finishCreation(globalData); + globalData.heap.addFinalizer(globalObject, destroy); return globalObject; } @@ -192,7 +196,7 @@ namespace JSC { init(this); } - void finishCreation(JSGlobalData& globalData, JSGlobalThis* thisValue) + void finishCreation(JSGlobalData& globalData, JSObject* thisValue) { Base::finishCreation(globalData); structure()->setGlobalObject(globalData, this); @@ -203,6 +207,8 @@ namespace JSC { public: JS_EXPORT_PRIVATE ~JSGlobalObject(); JS_EXPORT_PRIVATE static void destroy(JSCell*); + // We don't need a destructor because we use a finalizer instead. + static const bool needsDestruction = false; JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); @@ -262,7 +268,9 @@ namespace JSC { Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); } Structure* argumentsStructure() const { return m_argumentsStructure.get(); } Structure* arrayStructure() const { return m_arrayStructure.get(); } + Structure* arrayStructureWithArrayStorage() const { return m_arrayStructureWithArrayStorage.get(); } void* addressOfArrayStructure() { return &m_arrayStructure; } + void* addressOfArrayStructureWithArrayStorage() { return &m_arrayStructureWithArrayStorage; } Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } @@ -282,6 +290,12 @@ namespace JSC { Structure* regExpStructure() const { return m_regExpStructure.get(); } Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); } + void* actualPointerFor(Special::Pointer pointer) + { + ASSERT(pointer < Special::TableSize); + return m_specialPointers[pointer]; + } + WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); } WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); } @@ -366,13 +380,16 @@ namespace JSC { }; JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count); + JS_EXPORT_PRIVATE static JSC::JSObject* toThisObject(JSC::JSCell*, JSC::ExecState*); + + JS_EXPORT_PRIVATE void setGlobalThis(JSGlobalData&, JSObject* globalThis); + private: friend class LLIntOffsetsExtractor; // FIXME: Fold reset into init. JS_EXPORT_PRIVATE void init(JSObject* thisValue); void reset(JSValue prototype); - void setGlobalThis(JSGlobalData&, JSObject* globalThis); void createThrowTypeError(ExecState*); @@ -465,7 +482,7 @@ namespace JSC { inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0) { - return JSArray::create(exec->globalData(), globalObject->arrayStructure(), initialLength); + return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength); } inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0) diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.cpp b/Source/JavaScriptCore/runtime/JSGlobalThis.cpp deleted file mode 100644 index a3f2e7785..000000000 --- a/Source/JavaScriptCore/runtime/JSGlobalThis.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSGlobalThis.h" - -#include "JSGlobalObject.h" - -namespace JSC { - -ASSERT_CLASS_FITS_IN_CELL(JSGlobalThis); -ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSGlobalThis); - -const ClassInfo JSGlobalThis::s_info = { "JSGlobalThis", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSGlobalThis) }; - -void JSGlobalThis::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSGlobalThis* thisObject = jsCast<JSGlobalThis*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); - - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - - Base::visitChildren(thisObject, visitor); - visitor.append(&thisObject->m_unwrappedObject); -} - -void JSGlobalThis::setUnwrappedObject(JSGlobalData& globalData, JSGlobalObject* globalObject) -{ - ASSERT_ARG(globalObject, globalObject); - m_unwrappedObject.set(globalData, this, globalObject); - setPrototype(globalData, globalObject->prototype()); - resetInheritorID(globalData); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.h b/Source/JavaScriptCore/runtime/JSGlobalThis.h deleted file mode 100644 index 0ca99414a..000000000 --- a/Source/JavaScriptCore/runtime/JSGlobalThis.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef JSGlobalThis_h -#define JSGlobalThis_h - -#include "JSObject.h" - -namespace JSC { - -class JSGlobalThis : public JSNonFinalObject { -public: - typedef JSNonFinalObject Base; - - static JSGlobalThis* create(JSGlobalData& globalData, Structure* structure) - { - JSGlobalThis* globalThis = new (NotNull, allocateCell<JSGlobalThis>(globalData.heap)) JSGlobalThis(globalData, structure); - globalThis->finishCreation(globalData); - return globalThis; - } - - static Structure* createStructure(JSGlobalData& globalData, JSValue prototype) - { - return Structure::create(globalData, 0, prototype, TypeInfo(GlobalThisType, StructureFlags), &s_info); - } - - static JS_EXPORTDATA const JSC::ClassInfo s_info; - - JSGlobalObject* unwrappedObject() const { return m_unwrappedObject.get(); } - -protected: - JSGlobalThis(JSGlobalData& globalData, Structure* structure) - : JSNonFinalObject(globalData, structure) - { - } - - void finishCreation(JSGlobalData& globalData) - { - Base::finishCreation(globalData); - } - - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; - - JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); - - JS_EXPORT_PRIVATE void setUnwrappedObject(JSGlobalData&, JSGlobalObject*); - -private: - WriteBarrier<JSGlobalObject> m_unwrappedObject; -}; - -} // namespace JSC - -#endif // JSGlobalThis_h diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp index 9f02b69b8..85dbdfedb 100644 --- a/Source/JavaScriptCore/runtime/JSLock.cpp +++ b/Source/JavaScriptCore/runtime/JSLock.cpp @@ -140,13 +140,13 @@ bool JSLock::currentThreadIsHoldingLock() // context if the thread leaves JSC by making a call out to an external // function through a callback. // -// All threads using the context share the same JS stack (the RegisterFile). -// Whenever a thread calls into JSC it starts using the RegisterFile from the +// All threads using the context share the same JS stack (the JSStack). +// Whenever a thread calls into JSC it starts using the JSStack from the // previous 'high water mark' - the maximum point the stack has ever grown to -// (returned by RegisterFile::end()). So if a first thread calls out to a +// (returned by JSStack::end()). So if a first thread calls out to a // callback, and a second thread enters JSC, then also exits by calling out // to a callback, we can be left with stackframes from both threads in the -// RegisterFile. As such, a problem may occur should the first thread's +// JSStack. As such, a problem may occur should the first thread's // callback complete first, and attempt to return to JSC. Were we to allow // this to happen, and were its stack to grow further, then it may potentially // write over the second thread's call frames. diff --git a/Source/JavaScriptCore/runtime/JSNameScope.cpp b/Source/JavaScriptCore/runtime/JSNameScope.cpp index 5dc665c44..335631fd0 100644 --- a/Source/JavaScriptCore/runtime/JSNameScope.cpp +++ b/Source/JavaScriptCore/runtime/JSNameScope.cpp @@ -30,8 +30,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSNameScope); - const ClassInfo JSNameScope::s_info = { "NameScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNameScope) }; void JSNameScope::visitChildren(JSCell* cell, SlotVisitor& visitor) diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp index f75fa1f96..53592ba2b 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -34,7 +34,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSNotAnObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSNotAnObject); const ClassInfo JSNotAnObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNotAnObject) }; diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index fe894afba..fd939934e 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -41,7 +41,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSONObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSONObject); static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*); diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp index bf38f6876..6a3fb84e4 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -26,13 +26,14 @@ #include "ButterflyInlineMethods.h" #include "CopiedSpaceInlineMethods.h" +#include "CopyVisitor.h" +#include "CopyVisitorInlineMethods.h" #include "DatePrototype.h" #include "ErrorConstructor.h" #include "GetterSetter.h" #include "IndexingHeaderInlineMethods.h" #include "JSFunction.h" #include "JSGlobalObject.h" -#include "JSGlobalThis.h" #include "Lookup.h" #include "NativeErrorConstructor.h" #include "Nodes.h" @@ -63,10 +64,6 @@ JSCell* getCallableObjectSlow(JSCell* cell) return 0; } -ASSERT_CLASS_FITS_IN_CELL(JSObject); -ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject); -ASSERT_CLASS_FITS_IN_CELL(JSFinalObject); - ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSFinalObject); @@ -95,7 +92,7 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class } } -ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize) +ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize) { ASSERT(butterfly); @@ -112,61 +109,93 @@ ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* but preCapacity = 0; indexingPayloadSizeInBytes = 0; } - size_t capacityInBytes = Butterfly::totalSize( - preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - if (visitor.checkIfShouldCopyAndPinOtherwise( - butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) { + size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) { Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - // Mark and copy the properties. + // Copy the properties. PropertyStorage currentTarget = newButterfly->propertyStorage(); PropertyStorage currentSource = butterfly->propertyStorage(); - for (size_t count = storageSize; count--;) { - JSValue value = (--currentSource)->get(); - ASSERT(value); - visitor.appendUnbarrieredValue(&value); - (--currentTarget)->setWithoutWriteBarrier(value); - } + for (size_t count = storageSize; count--;) + (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get()); if (UNLIKELY(hasIndexingHeader)) { *newButterfly->indexingHeader() = *butterfly->indexingHeader(); - // Mark and copy the array if appropriate. + // Copy the array if appropriate. + + WriteBarrier<Unknown>* currentTarget; + WriteBarrier<Unknown>* currentSource; + size_t count; + switch (structure->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: { + currentTarget = newButterfly->contiguous(); + currentSource = butterfly->contiguous(); + ASSERT(newButterfly->publicLength() <= newButterfly->vectorLength()); + count = newButterfly->vectorLength(); + break; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { newButterfly->arrayStorage()->copyHeaderFromDuringGC(*butterfly->arrayStorage()); - WriteBarrier<Unknown>* currentTarget = newButterfly->arrayStorage()->m_vector; - WriteBarrier<Unknown>* currentSource = butterfly->arrayStorage()->m_vector; - for (size_t count = newButterfly->arrayStorage()->vectorLength(); count--;) { - JSValue value = (currentSource++)->get(); - if (value) - visitor.appendUnbarrieredValue(&value); - (currentTarget++)->setWithoutWriteBarrier(value); - } - if (newButterfly->arrayStorage()->m_sparseMap) - visitor.append(&newButterfly->arrayStorage()->m_sparseMap); + currentTarget = newButterfly->arrayStorage()->m_vector; + currentSource = butterfly->arrayStorage()->m_vector; + count = newButterfly->arrayStorage()->vectorLength(); break; } default: + CRASH(); + currentTarget = 0; + currentSource = 0; + count = 0; break; } + + while (count--) + (currentTarget++)->setWithoutWriteBarrier((currentSource++)->get()); } m_butterfly = newButterfly; + visitor.didCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes); + } +} + +ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize) +{ + ASSERT(butterfly); + + Structure* structure = this->structure(); + + size_t propertyCapacity = structure->outOfLineCapacity(); + size_t preCapacity; + size_t indexingPayloadSizeInBytes; + bool hasIndexingHeader = JSC::hasIndexingHeader(structure->indexingType()); + if (UNLIKELY(hasIndexingHeader)) { + preCapacity = butterfly->indexingHeader()->preCapacity(structure); + indexingPayloadSizeInBytes = butterfly->indexingHeader()->indexingPayloadSizeInBytes(structure); } else { - // Mark the properties. - visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize); - - // Mark the array if appropriate. - switch (structure->indexingType()) { - case ALL_ARRAY_STORAGE_INDEXING_TYPES: - visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength()); - if (butterfly->arrayStorage()->m_sparseMap) - visitor.append(&butterfly->arrayStorage()->m_sparseMap); - break; - default: - break; - } + preCapacity = 0; + indexingPayloadSizeInBytes = 0; + } + size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + + // Mark the properties. + visitor.appendValues(butterfly->propertyStorage() - storageSize, storageSize); + visitor.copyLater(butterfly->base(preCapacity, propertyCapacity), capacityInBytes); + + // Mark the array if appropriate. + switch (structure->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + visitor.appendValues(butterfly->contiguous(), butterfly->publicLength()); + break; + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + visitor.appendValues(butterfly->arrayStorage()->m_vector, butterfly->arrayStorage()->vectorLength()); + if (butterfly->arrayStorage()->m_sparseMap) + visitor.append(&butterfly->arrayStorage()->m_sparseMap); + break; + default: + break; } } @@ -183,13 +212,23 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor) Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownNonFinalObject()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); #if !ASSERT_DISABLED visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation; #endif } +void JSObject::copyBackingStore(JSCell* cell, CopyVisitor& visitor) +{ + JSObject* thisObject = jsCast<JSObject*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + + Butterfly* butterfly = thisObject->butterfly(); + if (butterfly) + thisObject->copyButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); +} + void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSFinalObject* thisObject = jsCast<JSFinalObject*>(cell); @@ -203,9 +242,9 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownFinalObject()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); - size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject(); + size_t storageSize = thisObject->structure()->inlineSize(); visitor.appendValues(thisObject->inlineStorage(), storageSize); #if !ASSERT_DISABLED @@ -235,6 +274,20 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned case ALL_BLANK_INDEXING_TYPES: break; + case ALL_CONTIGUOUS_INDEXING_TYPES: { + Butterfly* butterfly = thisObject->m_butterfly; + if (i >= butterfly->vectorLength()) + return false; + + JSValue value = butterfly->contiguous()[i].get(); + if (value) { + slot.setValue(value); + return true; + } + + return false; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = thisObject->m_butterfly->arrayStorage(); if (i >= storage->length()) @@ -249,7 +302,7 @@ bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) { SparseArrayValueMap::iterator it = map->find(i); if (it != map->notFound()) { - it->second.get(slot); + it->value.get(slot); return true; } } @@ -352,6 +405,16 @@ void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, case ALL_BLANK_INDEXING_TYPES: break; + case ALL_CONTIGUOUS_INDEXING_TYPES: { + Butterfly* butterfly = thisObject->m_butterfly; + if (propertyName >= butterfly->vectorLength()) + break; + butterfly->contiguous()[propertyName].set(exec->globalData(), thisObject, value); + if (propertyName >= butterfly->publicLength()) + butterfly->setPublicLength(propertyName + 1); + return; + } + case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { ArrayStorage* storage = thisObject->m_butterfly->arrayStorage(); @@ -426,7 +489,7 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists // This will always be a new entry in the map, so no need to check we can write, // and attributes are default so no need to set them. if (value) - map->add(this, i).iterator->second.set(globalData, this, value); + map->add(this, i).iterator->value.set(globalData, this, value); } Butterfly* newButterfly = storage->butterfly()->resizeArray(globalData, structure(), 0, ArrayStorage::sizeFor(0)); @@ -444,6 +507,11 @@ ArrayStorage* JSObject::enterDictionaryIndexingModeWhenArrayStorageAlreadyExists void JSObject::enterDictionaryIndexingMode(JSGlobalData& globalData) { switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + // NOTE: this is horribly inefficient, as it will perform two conversions. We could optimize + // this case if we ever cared. + enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); + break; case ALL_ARRAY_STORAGE_INDEXING_TYPES: enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); break; @@ -466,6 +534,24 @@ void JSObject::notifyPresenceOfIndexedAccessors(JSGlobalData& globalData) globalObject()->haveABadTime(globalData); } +WriteBarrier<Unknown>* JSObject::createInitialContiguous(JSGlobalData& globalData, unsigned length) +{ + ASSERT(length < MAX_ARRAY_INDEX); + IndexingType oldType = structure()->indexingType(); + ASSERT_UNUSED(oldType, !hasIndexedProperties(oldType)); + ASSERT(!structure()->needsSlowPutIndexing()); + ASSERT(!indexingShouldBeSparse()); + unsigned vectorLength = std::max(length, BASE_VECTOR_LEN); + Butterfly* newButterfly = m_butterfly->growArrayRight( + globalData, structure(), structure()->outOfLineCapacity(), false, 0, + sizeof(EncodedJSValue) * vectorLength); + newButterfly->setPublicLength(length); + newButterfly->setVectorLength(vectorLength); + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), AllocateContiguous); + setButterfly(globalData, newButterfly, newStructure); + return newButterfly->contiguous(); +} + ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned length, unsigned vectorLength) { IndexingType oldType = structure()->indexingType(); @@ -481,7 +567,7 @@ ArrayStorage* JSObject::createArrayStorage(JSGlobalData& globalData, unsigned le result->m_sparseMap.clear(); result->m_numValuesInVector = 0; result->m_indexBias = 0; - Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedIndexingTransition()); + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedArrayStorageTransition()); setButterfly(globalData, newButterfly, newStructure); return result; } @@ -491,9 +577,107 @@ ArrayStorage* JSObject::createInitialArrayStorage(JSGlobalData& globalData) return createArrayStorage(globalData, 0, BASE_VECTOR_LEN); } +ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition, unsigned neededLength) +{ + ASSERT(hasContiguous(structure()->indexingType())); + + unsigned publicLength = m_butterfly->publicLength(); + unsigned propertyCapacity = structure()->outOfLineCapacity(); + unsigned propertySize = structure()->outOfLineSize(); + + Butterfly* newButterfly = Butterfly::createUninitialized( + globalData, 0, propertyCapacity, true, ArrayStorage::sizeFor(neededLength)); + + memcpy( + newButterfly->propertyStorage() - propertySize, + m_butterfly->propertyStorage() - propertySize, + propertySize * sizeof(EncodedJSValue)); + + ArrayStorage* newStorage = newButterfly->arrayStorage(); + newStorage->setVectorLength(neededLength); + newStorage->setLength(publicLength); + newStorage->m_sparseMap.clear(); + newStorage->m_indexBias = 0; + newStorage->m_numValuesInVector = 0; + for (unsigned i = publicLength; i--;) { + JSValue v = m_butterfly->contiguous()[i].get(); + if (!v) + continue; + newStorage->m_vector[i].setWithoutWriteBarrier(v); + newStorage->m_numValuesInVector++; + } + + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), transition); + setButterfly(globalData, newButterfly, newStructure); + return newStorage; +} + +ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData, NonPropertyTransition transition) +{ + return convertContiguousToArrayStorage(globalData, transition, m_butterfly->vectorLength()); +} + +ArrayStorage* JSObject::convertContiguousToArrayStorage(JSGlobalData& globalData) +{ + return convertContiguousToArrayStorage(globalData, structure()->suggestedArrayStorageTransition()); +} + +WriteBarrier<Unknown>* JSObject::ensureContiguousSlow(JSGlobalData& globalData) +{ + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + if (UNLIKELY(indexingShouldBeSparse() || structure()->needsSlowPutIndexing())) + return 0; + return createInitialContiguous(globalData, 0); + + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + +ArrayStorage* JSObject::ensureArrayStorageSlow(JSGlobalData& globalData) +{ + switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + ASSERT(!indexingShouldBeSparse()); + ASSERT(!structure()->needsSlowPutIndexing()); + return convertContiguousToArrayStorage(globalData); + + case ALL_BLANK_INDEXING_TYPES: + if (UNLIKELY(indexingShouldBeSparse())) + return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData); + return createInitialArrayStorage(globalData); + + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + +Butterfly* JSObject::ensureIndexedStorageSlow(JSGlobalData& globalData) +{ + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + if (UNLIKELY(structure()->needsSlowPutIndexing())) + return createInitialArrayStorage(globalData)->butterfly(); + if (UNLIKELY(indexingShouldBeSparse())) + return ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)->butterfly(); + return Butterfly::fromContiguous(createInitialContiguous(globalData, 0)); + + default: + ASSERT_NOT_REACHED(); + return 0; + } +} + ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(JSGlobalData& globalData) { switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + // FIXME: This could be made way more efficient, if we cared. + return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, convertContiguousToArrayStorage(globalData)); + case ALL_ARRAY_STORAGE_INDEXING_TYPES: return enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(globalData, m_butterfly->arrayStorage()); @@ -513,6 +697,11 @@ ArrayStorage* JSObject::ensureArrayStorageExistsAndEnterDictionaryIndexingMode(J void JSObject::switchToSlowPutArrayStorage(JSGlobalData& globalData) { switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: { + convertContiguousToArrayStorage(globalData, AllocateSlowPutArrayStorage); + break; + } + case NonArrayWithArrayStorage: case ArrayWithArrayStorage: { Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), SwitchToSlowPutArrayStorage); @@ -556,8 +745,7 @@ void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype) if (shouldUseSlowPut(structure()->indexingType())) return; - newStructure = Structure::nonPropertyTransition(globalData, newStructure, SwitchToSlowPutArrayStorage); - setStructure(globalData, newStructure); + switchToSlowPutArrayStorage(globalData); } bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) @@ -691,6 +879,14 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) case ALL_BLANK_INDEXING_TYPES: return true; + case ALL_CONTIGUOUS_INDEXING_TYPES: { + Butterfly* butterfly = thisObject->m_butterfly; + if (i >= butterfly->vectorLength()) + return true; + butterfly->contiguous()[i].clear(); + return true; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = thisObject->m_butterfly->arrayStorage(); @@ -703,7 +899,7 @@ bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i) } else if (SparseArrayValueMap* map = storage->m_sparseMap.get()) { SparseArrayValueMap::iterator it = map->find(i); if (it != map->notFound()) { - if (it->second.attributes & DontDelete) + if (it->value.attributes & DontDelete) return false; map->remove(it); } @@ -864,6 +1060,17 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa case ALL_BLANK_INDEXING_TYPES: break; + case ALL_CONTIGUOUS_INDEXING_TYPES: { + Butterfly* butterfly = object->m_butterfly; + unsigned usedLength = butterfly->publicLength(); + for (unsigned i = 0; i < usedLength; ++i) { + if (!butterfly->contiguous()[i]) + continue; + propertyNames.add(Identifier::from(exec, i)); + } + break; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = object->m_butterfly->arrayStorage(); @@ -879,8 +1086,8 @@ void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNa SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) { - if (mode == IncludeDontEnumProperties || !(it->second.attributes & DontEnum)) - keys.append(static_cast<unsigned>(it->first)); + if (mode == IncludeDontEnumProperties || !(it->value.attributes & DontEnum)) + keys.append(static_cast<unsigned>(it->key)); } std::sort(keys.begin(), keys.end()); @@ -1089,9 +1296,6 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert { ASSERT(index <= MAX_ARRAY_INDEX); - if (descriptor.attributes() & (ReadOnly | Accessor)) - notifyPresenceOfIndexedAccessors(exec->globalData()); - if (!inSparseIndexingMode()) { // Fast case: we're putting a regular property to a regular array // FIXME: this will pessimistically assume that if attributes are missing then they'll default to false @@ -1101,16 +1305,19 @@ bool JSObject::defineOwnIndexedProperty(ExecState* exec, unsigned index, Propert ASSERT(!descriptor.isAccessorDescriptor()); return putDirectIndex(exec, index, descriptor.value(), 0, throwException ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); } - + ensureArrayStorageExistsAndEnterDictionaryIndexingMode(exec->globalData()); } + if (descriptor.attributes() & (ReadOnly | Accessor)) + notifyPresenceOfIndexedAccessors(exec->globalData()); + SparseArrayValueMap* map = m_butterfly->arrayStorage()->m_sparseMap.get(); ASSERT(map); // 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P. SparseArrayValueMap::AddResult result = map->add(this, index); - SparseArrayEntry* entryInMap = &result.iterator->second; + SparseArrayEntry* entryInMap = &result.iterator->value; // 2. Let extensible be the value of the [[Extensible]] internal property of O. // 3. If current is undefined and extensible is false, then Reject. @@ -1230,8 +1437,8 @@ bool JSObject::attemptToInterceptPutByIndexOnHoleForPrototype(ExecState* exec, J ArrayStorage* storage = current->arrayStorageOrNull(); if (storage && storage->m_sparseMap) { SparseArrayValueMap::iterator iter = storage->m_sparseMap->find(i); - if (iter != storage->m_sparseMap->notFound() && (iter->second.attributes & (Accessor | ReadOnly))) { - iter->second.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow); + if (iter != storage->m_sparseMap->notFound() && (iter->value.attributes & (Accessor | ReadOnly))) { + iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow); return true; } } @@ -1253,6 +1460,35 @@ bool JSObject::attemptToInterceptPutByIndexOnHole(ExecState* exec, unsigned i, J return asObject(prototypeValue)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, this, i, value, shouldThrow); } +void JSObject::putByIndexBeyondVectorLengthContiguousWithoutAttributes(ExecState* exec, unsigned i, JSValue value) +{ + ASSERT(hasContiguous(structure()->indexingType())); + ASSERT(!indexingShouldBeSparse()); + + // For us to get here, the index is either greater than the public length, or greater than + // or equal to the vector length. + ASSERT(i >= m_butterfly->vectorLength()); + + JSGlobalData& globalData = exec->globalData(); + + if (i >= MAX_ARRAY_INDEX - 1 + || (i >= MIN_SPARSE_ARRAY_INDEX + && !isDenseEnoughForVector(i, countElementsInContiguous(m_butterfly)))) { + ASSERT(i <= MAX_ARRAY_INDEX); + convertContiguousToArrayStorage(globalData, AllocateArrayStorage); + SparseArrayValueMap* map = allocateSparseIndexMap(globalData); + map->putEntry(exec, this, i, value, false); + ASSERT(i >= arrayStorage()->length()); + arrayStorage()->setLength(i + 1); + return; + } + + ensureContiguousLength(globalData, i + 1); + + ASSERT(i < m_butterfly->vectorLength()); + m_butterfly->contiguous()[i].set(globalData, this, value); +} + void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, bool shouldThrow, ArrayStorage* storage) { JSGlobalData& globalData = exec->globalData(); @@ -1315,7 +1551,7 @@ void JSObject::putByIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, uns WriteBarrier<Unknown>* vector = storage->m_vector; SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) - vector[it->first].set(globalData, this, it->second.getNonSparseMode()); + vector[it->key].set(globalData, this, it->value.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. @@ -1335,17 +1571,29 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: { if (indexingShouldBeSparse()) { - putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); + putByIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, shouldThrow, + ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); + break; + } + if (i >= MIN_SPARSE_ARRAY_INDEX) { + putByIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0)); break; } - if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH) { - putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0)); + if (structure()->needsSlowPutIndexing()) { + ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(globalData, this, value); + storage->m_numValuesInVector++; break; } + + createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value); + break; + } - ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); - storage->m_vector[i].set(globalData, this, value); - storage->m_numValuesInVector = 1; + case ALL_CONTIGUOUS_INDEXING_TYPES: { + putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); break; } @@ -1371,8 +1619,10 @@ void JSObject::putByIndexBeyondVectorLength(ExecState* exec, unsigned i, JSValue bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode, ArrayStorage* storage) { JSGlobalData& globalData = exec->globalData(); - + // i should be a valid array index that is outside of the current vector. + ASSERT(hasArrayStorage(structure()->indexingType())); + ASSERT(arrayStorage() == storage); ASSERT(i >= storage->vectorLength() || attributes); ASSERT(i <= MAX_ARRAY_INDEX); @@ -1431,7 +1681,7 @@ bool JSObject::putDirectIndexBeyondVectorLengthWithArrayStorage(ExecState* exec, WriteBarrier<Unknown>* vector = storage->m_vector; SparseArrayValueMap::const_iterator end = map->end(); for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) - vector[it->first].set(globalData, this, it->second.getNonSparseMode()); + vector[it->key].set(globalData, this, it->value.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. @@ -1454,14 +1704,32 @@ bool JSObject::putDirectIndexBeyondVectorLength(ExecState* exec, unsigned i, JSV switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: { - if (indexingShouldBeSparse() || attributes) - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); - if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH) - return putDirectIndexBeyondVectorLengthWithArrayStorage(exec, i, value, attributes, mode, createArrayStorage(globalData, 0, 0)); + if (indexingShouldBeSparse() || attributes) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, + ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); + } + if (i >= MIN_SPARSE_ARRAY_INDEX) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, createArrayStorage(globalData, 0, 0)); + } + if (structure()->needsSlowPutIndexing()) { + ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(globalData, this, value); + storage->m_numValuesInVector++; + return true; + } - ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); - storage->m_vector[i].set(globalData, this, value); - storage->m_numValuesInVector = 1; + createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value); + return true; + } + + case ALL_CONTIGUOUS_INDEXING_TYPES: { + if (attributes & (ReadOnly | Accessor)) { + return putDirectIndexBeyondVectorLengthWithArrayStorage( + exec, i, value, attributes, mode, convertContiguousToArrayStorage(globalData)); + } + putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); return true; } @@ -1486,12 +1754,7 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength else if (!currentVectorLength) increasedLength = std::max(desiredLength, lastArraySize); else { - // Mathematically equivalent to: - // increasedLength = (newLength * 3 + 1) / 2; - // or: - // increasedLength = (unsigned)ceil(newLength * 1.5)); - // This form is not prone to internal overflow. - increasedLength = desiredLength + (desiredLength >> 1) + (desiredLength & 1); + increasedLength = timesThreePlusOneDividedByTwo(desiredLength); } ASSERT(increasedLength >= desiredLength); @@ -1511,9 +1774,10 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength) vectorLength = 0; length = 0; break; + case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: - vectorLength = m_butterfly->arrayStorage()->vectorLength(); - length = m_butterfly->arrayStorage()->length(); + vectorLength = m_butterfly->vectorLength(); + length = m_butterfly->publicLength(); break; default: CRASH(); @@ -1522,6 +1786,16 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned desiredLength) return getNewVectorLength(vectorLength, length, desiredLength); } +unsigned JSObject::countElementsInContiguous(Butterfly* butterfly) +{ + unsigned numValues = 0; + for (unsigned i = butterfly->publicLength(); i--;) { + if (butterfly->contiguous()[i]) + numValues++; + } + return numValues; +} + bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength) { // This function leaves the array in an internally inconsistent state, because it does not move any values from sparse value map @@ -1530,6 +1804,10 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength return false; ArrayStorage* storage = arrayStorage(); + + if (newLength >= MIN_SPARSE_ARRAY_INDEX + && !isDenseEnoughForVector(newLength, storage->m_numValuesInVector)) + return false; unsigned indexBias = storage->m_indexBias; unsigned vectorLength = storage->vectorLength(); @@ -1561,6 +1839,22 @@ bool JSObject::increaseVectorLength(JSGlobalData& globalData, unsigned newLength return true; } +void JSObject::ensureContiguousLengthSlow(JSGlobalData& globalData, unsigned length) +{ + ASSERT(length < MAX_ARRAY_INDEX); + ASSERT(hasContiguous(structure()->indexingType())); + ASSERT(length > m_butterfly->vectorLength()); + + unsigned newVectorLength = std::min( + length << 1, + MAX_STORAGE_VECTOR_LENGTH); + m_butterfly = m_butterfly->growArrayRight( + globalData, structure(), structure()->outOfLineCapacity(), true, + m_butterfly->vectorLength() * sizeof(EncodedJSValue), + newVectorLength * sizeof(EncodedJSValue)); + m_butterfly->setVectorLength(newVectorLength); +} + Butterfly* JSObject::growOutOfLineStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize) { ASSERT(newSize > oldSize); @@ -1589,6 +1883,17 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope case ALL_BLANK_INDEXING_TYPES: return false; + case ALL_CONTIGUOUS_INDEXING_TYPES: { + Butterfly* butterfly = object->m_butterfly; + if (i >= butterfly->vectorLength()) + return false; + JSValue value = butterfly->contiguous()[i].get(); + if (!value) + return false; + descriptor.setDescriptor(value, 0); + return true; + } + case ALL_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = object->m_butterfly->arrayStorage(); if (i >= storage->length()) @@ -1604,7 +1909,7 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope SparseArrayValueMap::iterator it = map->find(i); if (it == map->notFound()) return false; - it->second.get(descriptor); + it->value.get(descriptor); return true; } return false; diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 4b9cff5ad..9204099cb 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -109,7 +109,13 @@ namespace JSC { public: typedef JSCell Base; + static size_t allocationSize(size_t inlineCapacity) + { + return sizeof(JSObject) + inlineCapacity * sizeof(WriteBarrierBase<Unknown>); + } + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&); JS_EXPORT_PRIVATE static String className(const JSObject*); @@ -148,8 +154,9 @@ namespace JSC { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: return 0; + case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage()->length(); + return m_butterfly->publicLength(); default: ASSERT_NOT_REACHED(); return 0; @@ -161,8 +168,9 @@ namespace JSC { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: return 0; + case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return m_butterfly->arrayStorage()->vectorLength(); + return m_butterfly->vectorLength(); default: ASSERT_NOT_REACHED(); return 0; @@ -207,6 +215,8 @@ namespace JSC { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: return false; + case ALL_CONTIGUOUS_INDEXING_TYPES: + return i < m_butterfly->vectorLength() && m_butterfly->contiguous()[i]; case ALL_ARRAY_STORAGE_INDEXING_TYPES: return i < m_butterfly->arrayStorage()->vectorLength() && m_butterfly->arrayStorage()->m_vector[i]; default: @@ -218,6 +228,8 @@ namespace JSC { JSValue getIndexQuickly(unsigned i) { switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous()[i].get(); case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage()->m_vector[i].get(); default: @@ -231,12 +243,13 @@ namespace JSC { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: break; + case ALL_CONTIGUOUS_INDEXING_TYPES: + if (i < m_butterfly->publicLength()) + return m_butterfly->contiguous()[i].get(); + break; case ALL_ARRAY_STORAGE_INDEXING_TYPES: - if (i < m_butterfly->arrayStorage()->vectorLength()) { - JSValue v = m_butterfly->arrayStorage()->m_vector[i].get(); - if (v) - return v; - } + if (i < m_butterfly->arrayStorage()->vectorLength()) + return m_butterfly->arrayStorage()->m_vector[i].get(); break; default: ASSERT_NOT_REACHED(); @@ -267,9 +280,10 @@ namespace JSC { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: return false; + case ALL_CONTIGUOUS_INDEXING_TYPES: case NonArrayWithArrayStorage: case ArrayWithArrayStorage: - return i < m_butterfly->arrayStorage()->vectorLength(); + return i < m_butterfly->vectorLength(); case NonArrayWithSlowPutArrayStorage: case ArrayWithSlowPutArrayStorage: return i < m_butterfly->arrayStorage()->vectorLength() @@ -285,8 +299,9 @@ namespace JSC { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: return false; + case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: - return i < m_butterfly->arrayStorage()->vectorLength(); + return i < m_butterfly->vectorLength(); default: ASSERT_NOT_REACHED(); return false; @@ -296,15 +311,23 @@ namespace JSC { void setIndexQuickly(JSGlobalData& globalData, unsigned i, JSValue v) { switch (structure()->indexingType()) { + case ALL_CONTIGUOUS_INDEXING_TYPES: { + ASSERT(i < m_butterfly->vectorLength()); + m_butterfly->contiguous()[i].set(globalData, this, v); + if (i >= m_butterfly->publicLength()) + m_butterfly->setPublicLength(i + 1); + break; + } case ALL_ARRAY_STORAGE_INDEXING_TYPES: { - WriteBarrier<Unknown>& x = m_butterfly->arrayStorage()->m_vector[i]; - if (!x) { - ArrayStorage* storage = m_butterfly->arrayStorage(); + ArrayStorage* storage = m_butterfly->arrayStorage(); + WriteBarrier<Unknown>& x = storage->m_vector[i]; + JSValue old = x.get(); + x.set(globalData, this, v); + if (!old) { ++storage->m_numValuesInVector; if (i >= storage->length()) storage->setLength(i + 1); } - x.set(globalData, this, v); break; } default: @@ -315,6 +338,12 @@ namespace JSC { void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v) { switch (structure()->indexingType()) { + 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_ARRAY_STORAGE_INDEXING_TYPES: { ArrayStorage* storage = m_butterfly->arrayStorage(); ASSERT(i < storage->length()); @@ -327,10 +356,25 @@ namespace JSC { } } + bool hasSparseMap() + { + switch (structure()->indexingType()) { + case ALL_BLANK_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: + return false; + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_sparseMap; + default: + ASSERT_NOT_REACHED(); + return false; + } + } + bool inSparseIndexingMode() { switch (structure()->indexingType()) { case ALL_BLANK_INDEXING_TYPES: + case ALL_CONTIGUOUS_INDEXING_TYPES: return false; case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage()->inSparseMode(); @@ -448,10 +492,10 @@ namespace JSC { { PropertyOffset result; size_t offsetInInlineStorage = location - inlineStorageUnsafe(); - if (offsetInInlineStorage < static_cast<size_t>(inlineStorageCapacity)) + if (offsetInInlineStorage < static_cast<size_t>(firstOutOfLineOffset)) result = offsetInInlineStorage; else - result = outOfLineStorage() - location + (inlineStorageCapacity - 1); + result = outOfLineStorage() - location + (firstOutOfLineOffset - 1); validateOffset(result, structure()->typeInfo().type()); return result; } @@ -481,7 +525,7 @@ namespace JSC { bool isNameScopeObject() const; bool isActivationObject() const; bool isErrorInstance() const; - bool isGlobalThis() const; + bool isProxy() const; void seal(JSGlobalData&); void freeze(JSGlobalData&); @@ -528,23 +572,34 @@ namespace JSC { // foo->attemptToInterceptPutByIndexOnHole(...); bool attemptToInterceptPutByIndexOnHoleForPrototype(ExecState*, JSValue thisValue, unsigned propertyName, JSValue, bool shouldThrow); + // 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) + { + if (LIKELY(hasContiguous(structure()->indexingType()))) + return m_butterfly->contiguous(); + + return ensureContiguousSlow(globalData); + } + // Ensure that the object is in a mode where it has array storage. Use // this if you're about to perform actions that would have required the // object to be converted to have array storage, if it didn't have it // already. ArrayStorage* ensureArrayStorage(JSGlobalData& globalData) { - switch (structure()->indexingType()) { - case ALL_ARRAY_STORAGE_INDEXING_TYPES: + if (LIKELY(hasArrayStorage(structure()->indexingType()))) return m_butterfly->arrayStorage(); - - case ALL_BLANK_INDEXING_TYPES: - return createInitialArrayStorage(globalData); - - default: - ASSERT_NOT_REACHED(); - return 0; - } + + return ensureArrayStorageSlow(globalData); + } + + Butterfly* ensureIndexedStorage(JSGlobalData& globalData) + { + if (LIKELY(hasIndexedProperties(structure()->indexingType()))) + return m_butterfly; + + return ensureIndexedStorageSlow(globalData); } static size_t offsetOfInlineStorage(); @@ -585,6 +640,7 @@ namespace JSC { void resetInheritorID(JSGlobalData&); void visitButterfly(SlotVisitor&, Butterfly*, size_t storageSize); + void copyButterfly(CopyVisitor&, Butterfly*, size_t storageSize); // Call this if you know that the object is in a mode where it has array // storage. This will assert otherwise. @@ -609,11 +665,16 @@ namespace JSC { ArrayStorage* createArrayStorage(JSGlobalData&, unsigned length, unsigned vectorLength); ArrayStorage* createInitialArrayStorage(JSGlobalData&); + WriteBarrier<Unknown>* createInitialContiguous(JSGlobalData&, unsigned length); + 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); void putByIndexBeyondVectorLengthWithArrayStorage(ExecState*, unsigned propertyName, JSValue, bool shouldThrow, ArrayStorage*); bool increaseVectorLength(JSGlobalData&, unsigned newLength); @@ -624,6 +685,56 @@ namespace JSC { void notifyPresenceOfIndexedAccessors(JSGlobalData&); bool attemptToInterceptPutByIndexOnHole(ExecState*, unsigned index, JSValue, bool shouldThrow); + + // Call this if you want setIndexQuickly to succeed and you're sure that + // the array is contiguous. + void ensureContiguousLength(JSGlobalData& globalData, unsigned length) + { + ASSERT(length < MAX_ARRAY_INDEX); + ASSERT(hasContiguous(structure()->indexingType())); + + if (m_butterfly->vectorLength() < length) + ensureContiguousLengthSlow(globalData, length); + + if (m_butterfly->publicLength() < length) + m_butterfly->setPublicLength(length); + } + + unsigned countElementsInContiguous(Butterfly*); + + template<IndexingType indexingType> + WriteBarrier<Unknown>* indexingData() + { + switch (indexingType) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->contiguous(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return m_butterfly->arrayStorage()->m_vector; + + default: + CRASH(); + return 0; + } + } + + template<IndexingType indexingType> + unsigned relevantLength() + { + switch (indexingType) { + case ALL_CONTIGUOUS_INDEXING_TYPES: + return m_butterfly->publicLength(); + + case ALL_ARRAY_STORAGE_INDEXING_TYPES: + return std::min( + m_butterfly->arrayStorage()->length(), + m_butterfly->arrayStorage()->vectorLength()); + + default: + CRASH(); + return 0; + } + } private: friend class LLIntOffsetsExtractor; @@ -658,6 +769,12 @@ namespace JSC { JS_EXPORT_PRIVATE bool getOwnPropertySlotSlow(ExecState*, PropertyName, PropertySlot&); + void ensureContiguousLengthSlow(JSGlobalData&, unsigned length); + + WriteBarrier<Unknown>* ensureContiguousSlow(JSGlobalData&); + ArrayStorage* ensureArrayStorageSlow(JSGlobalData&); + Butterfly* ensureIndexedStorageSlow(JSGlobalData&); + protected: Butterfly* m_butterfly; }; @@ -677,11 +794,6 @@ namespace JSC { return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); } - static bool hasInlineStorage() - { - return false; - } - protected: explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure, Butterfly* butterfly = 0) : JSObject(globalData, structure, butterfly) @@ -709,45 +821,43 @@ namespace JSC { static JSFinalObject* create(ExecState*, Structure*); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) { - return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info); + return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info, NonArray, INLINE_STORAGE_CAPACITY); } JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); static JS_EXPORTDATA const ClassInfo s_info; - static bool hasInlineStorage() - { - return true; - } protected: void visitChildrenCommon(SlotVisitor&); void finishCreation(JSGlobalData& globalData) { Base::finishCreation(globalData); - ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double))); - ASSERT(this->structure()->inlineCapacity() == static_cast<unsigned>(inlineStorageCapacity)); - ASSERT(this->structure()->totalStorageCapacity() == static_cast<unsigned>(inlineStorageCapacity)); + ASSERT(structure()->totalStorageCapacity() == structure()->inlineCapacity()); ASSERT(classInfo()); } private: friend class LLIntOffsetsExtractor; - + explicit JSFinalObject(JSGlobalData& globalData, Structure* structure) : JSObject(globalData, structure) { } static const unsigned StructureFlags = JSObject::StructureFlags; - - WriteBarrierBase<Unknown> m_inlineStorage[INLINE_STORAGE_CAPACITY]; }; inline JSFinalObject* JSFinalObject::create(ExecState* exec, Structure* structure) { - JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure); + JSFinalObject* finalObject = new ( + NotNull, + allocateCell<JSFinalObject>( + *exec->heap(), + allocationSize(structure->inlineCapacity()) + ) + ) JSFinalObject(exec->globalData(), structure); finalObject->finishCreation(exec->globalData()); return finalObject; } @@ -764,7 +874,7 @@ inline bool isJSFinalObject(JSValue value) inline size_t JSObject::offsetOfInlineStorage() { - return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage); + return sizeof(JSObject); } inline bool JSObject::isGlobalObject() const @@ -792,9 +902,9 @@ inline bool JSObject::isErrorInstance() const return structure()->typeInfo().type() == ErrorInstanceType; } -inline bool JSObject::isGlobalThis() const +inline bool JSObject::isProxy() const { - return structure()->typeInfo().type() == GlobalThisType; + return structure()->typeInfo().type() == ProxyType; } inline void JSObject::setButterfly(JSGlobalData& globalData, Butterfly* butterfly, Structure* structure) @@ -856,14 +966,14 @@ inline JSValue JSObject::prototype() const return structure()->storedPrototype(); } -inline bool JSCell::inherits(const ClassInfo* info) const +inline const MethodTable* JSCell::methodTable() const { - return classInfo()->isSubClassOf(info); + return &classInfo()->methodTable; } -inline const MethodTable* JSCell::methodTable() const +inline bool JSCell::inherits(const ClassInfo* info) const { - return &classInfo()->methodTable; + return classInfo()->isSubClassOf(info); } // this method is here to be after the inline declaration of JSCell::inherits @@ -1257,6 +1367,8 @@ inline int offsetRelativeToBase(PropertyOffset offset) return JSObject::offsetOfInlineStorage() + offsetInInlineStorage(offset) * sizeof(EncodedJSValue); } +COMPILE_ASSERT(!(sizeof(JSObject) % sizeof(WriteBarrierBase<Unknown>)), JSObject_inline_storage_has_correct_alignment); + } // namespace JSC #endif // JSObject_h diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index 897ceff8c..225401fbd 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -33,8 +33,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator); - const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) }; inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h index 057ffe293..e59a5c6a4 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -48,6 +48,8 @@ namespace JSC { static JSPropertyNameIterator* create(ExecState*, JSObject*); + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) @@ -57,14 +59,6 @@ namespace JSC { static void visitChildren(JSCell*, SlotVisitor&); - bool getOffset(size_t i, PropertyOffset& offset) - { - if (i >= m_numCacheableSlots) - return false; - offset = i + m_offsetBase; - return true; - } - JSValue get(ExecState*, JSObject*, size_t i); size_t size() { return m_jsStringsSize; } @@ -88,7 +82,7 @@ namespace JSC { PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector(); for (size_t i = 0; i < m_jsStringsSize; ++i) m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].string())); - m_offsetBase = object->structure()->firstValidOffset(); + m_cachedStructureInlineCapacity = object->structure()->inlineCapacity(); } private: @@ -100,7 +94,7 @@ namespace JSC { WriteBarrier<StructureChain> m_cachedPrototypeChain; uint32_t m_numCacheableSlots; uint32_t m_jsStringsSize; - PropertyOffset m_offsetBase; + unsigned m_cachedStructureInlineCapacity; OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings; }; diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp new file mode 100644 index 000000000..7108dcfa0 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSProxy.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSProxy.h" + +#include "JSGlobalObject.h" + +namespace JSC { + +ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSProxy); + +const ClassInfo JSProxy::s_info = { "JSProxy", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSProxy) }; + +void JSProxy::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + JSProxy* thisObject = jsCast<JSProxy*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info); + + COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); + ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); + + Base::visitChildren(thisObject, visitor); + visitor.append(&thisObject->m_target); +} + +void JSProxy::setTarget(JSGlobalData& globalData, JSGlobalObject* globalObject) +{ + ASSERT_ARG(globalObject, globalObject); + m_target.set(globalData, this, globalObject); + setPrototype(globalData, globalObject->prototype()); + resetInheritorID(globalData); +} + +String JSProxy::className(const JSObject* object) +{ + const JSProxy* thisObject = jsCast<const JSProxy*>(object); + return thisObject->target()->methodTable()->className(thisObject->target()); +} + +bool JSProxy::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + JSProxy* thisObject = jsCast<JSProxy*>(cell); + return thisObject->target()->methodTable()->getOwnPropertySlot(thisObject->target(), exec, propertyName, slot); +} + +bool JSProxy::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + JSProxy* thisObject = jsCast<JSProxy*>(cell); + return thisObject->target()->methodTable()->getOwnPropertySlotByIndex(thisObject->target(), exec, propertyName, slot); +} + +bool JSProxy::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) +{ + JSProxy* thisObject = jsCast<JSProxy*>(object); + return thisObject->target()->methodTable()->getOwnPropertyDescriptor(thisObject->target(), exec, propertyName, descriptor); +} + +void JSProxy::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +{ + JSProxy* thisObject = jsCast<JSProxy*>(cell); + thisObject->target()->methodTable()->put(thisObject->target(), exec, propertyName, value, slot); +} + +void JSProxy::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) +{ + JSProxy* thisObject = jsCast<JSProxy*>(cell); + thisObject->target()->methodTable()->putByIndex(thisObject->target(), exec, propertyName, value, shouldThrow); +} + +void JSProxy::putDirectVirtual(JSObject* object, ExecState* exec, PropertyName propertyName, JSValue value, unsigned attributes) +{ + JSProxy* thisObject = jsCast<JSProxy*>(object); + thisObject->target()->putDirectVirtual(thisObject->target(), exec, propertyName, value, attributes); +} + +bool JSProxy::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow) +{ + JSProxy* thisObject = jsCast<JSProxy*>(object); + return thisObject->target()->methodTable()->defineOwnProperty(thisObject->target(), exec, propertyName, descriptor, shouldThrow); +} + +bool JSProxy::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) +{ + JSProxy* thisObject = jsCast<JSProxy*>(cell); + return thisObject->target()->methodTable()->deleteProperty(thisObject->target(), exec, propertyName); +} + +bool JSProxy::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) +{ + JSProxy* thisObject = jsCast<JSProxy*>(cell); + return thisObject->target()->methodTable()->deletePropertyByIndex(thisObject->target(), exec, propertyName); +} + +void JSProxy::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSProxy* thisObject = jsCast<JSProxy*>(object); + thisObject->target()->methodTable()->getPropertyNames(thisObject->target(), exec, propertyNames, mode); +} + +void JSProxy::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSProxy* thisObject = jsCast<JSProxy*>(object); + thisObject->target()->methodTable()->getOwnPropertyNames(thisObject->target(), exec, propertyNames, mode); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSProxy.h b/Source/JavaScriptCore/runtime/JSProxy.h new file mode 100644 index 000000000..144085a79 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSProxy.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSProxy_h +#define JSProxy_h + +#include "JSDestructibleObject.h" + +namespace JSC { + +class JSProxy : public JSDestructibleObject { +public: + typedef JSDestructibleObject Base; + + static JSProxy* create(JSGlobalData& globalData, Structure* structure, JSObject* target) + { + JSProxy* proxy = new (NotNull, allocateCell<JSProxy>(globalData.heap)) JSProxy(globalData, structure); + proxy->finishCreation(globalData, target); + return proxy; + } + + static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(globalData, globalObject, prototype, TypeInfo(ProxyType, StructureFlags), &s_info); + } + + static JS_EXPORTDATA const ClassInfo s_info; + + JSObject* target() const { return m_target.get(); } + +protected: + JSProxy(JSGlobalData& globalData, Structure* structure) + : JSDestructibleObject(globalData, structure) + { + } + + void finishCreation(JSGlobalData& globalData) + { + Base::finishCreation(globalData); + } + + void finishCreation(JSGlobalData& globalData, JSObject* target) + { + Base::finishCreation(globalData); + m_target.set(globalData, this, target); + } + + static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | Base::StructureFlags; + + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + + JS_EXPORT_PRIVATE void setTarget(JSGlobalData&, JSGlobalObject*); + + JS_EXPORT_PRIVATE static String className(const JSObject*); + JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned, PropertySlot&); + JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&); + JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + JS_EXPORT_PRIVATE static void putByIndex(JSCell*, ExecState*, unsigned, JSValue, bool shouldThrow); + JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes); + JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); + JS_EXPORT_PRIVATE static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned); + JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow); + +private: + WriteBarrier<JSObject> m_target; +}; + +} // namespace JSC + +#endif // JSProxy_h diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp index b22211970..8fd49b861 100644 --- a/Source/JavaScriptCore/runtime/JSScope.cpp +++ b/Source/JavaScriptCore/runtime/JSScope.cpp @@ -33,7 +33,7 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSScope); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSScope); void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor) { diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 1500636f2..245c48a51 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -71,6 +71,8 @@ namespace JSC { typedef JSCell Base; + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); private: diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp index 765e1d3d4..7dcde4700 100644 --- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.cpp @@ -61,8 +61,8 @@ void JSSymbolTableObject::getOwnNonIndexPropertyNames(JSObject* object, ExecStat JSSymbolTableObject* thisObject = jsCast<JSSymbolTableObject*>(object); SymbolTable::const_iterator end = thisObject->symbolTable()->end(); for (SymbolTable::const_iterator it = thisObject->symbolTable()->begin(); it != end; ++it) { - if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) - propertyNames.add(Identifier(exec, it->first.get())); + if (!(it->value.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) + propertyNames.add(Identifier(exec, it->key.get())); } JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h index b4d313c19..913679f80 100644 --- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h +++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h @@ -76,7 +76,7 @@ inline bool symbolTableGet( SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); if (iter == symbolTable.end()) return false; - SymbolTableEntry::Fast entry = iter->second; + SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); slot.setValue(object->registerAt(entry.getIndex()).get()); return true; @@ -90,7 +90,7 @@ inline bool symbolTableGet( SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); if (iter == symbolTable.end()) return false; - SymbolTableEntry::Fast entry = iter->second; + SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); descriptor.setDescriptor( object->registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete); @@ -106,7 +106,7 @@ inline bool symbolTableGet( SymbolTable::iterator iter = symbolTable.find(propertyName.publicName()); if (iter == symbolTable.end()) return false; - SymbolTableEntry::Fast entry = iter->second; + SymbolTableEntry::Fast entry = iter->value; ASSERT(!entry.isNull()); slot.setValue(object->registerAt(entry.getIndex()).get()); slotIsWriteable = !entry.isReadOnly(); @@ -126,7 +126,7 @@ inline bool symbolTablePut( if (iter == symbolTable.end()) return false; bool wasFat; - SymbolTableEntry::Fast fastEntry = iter->second.getFast(wasFat); + SymbolTableEntry::Fast fastEntry = iter->value.getFast(wasFat); ASSERT(!fastEntry.isNull()); if (fastEntry.isReadOnly()) { if (shouldThrow) @@ -134,7 +134,7 @@ inline bool symbolTablePut( return true; } if (UNLIKELY(wasFat)) - iter->second.notifyWrite(); + iter->value.notifyWrite(); object->registerAt(fastEntry.getIndex()).set(globalData, object, value); return true; } @@ -149,7 +149,7 @@ inline bool symbolTablePutWithAttributes( SymbolTable::iterator iter = object->symbolTable()->find(propertyName.publicName()); if (iter == object->symbolTable()->end()) return false; - SymbolTableEntry& entry = iter->second; + SymbolTableEntry& entry = iter->value; ASSERT(!entry.isNull()); entry.notifyWrite(); entry.setAttributes(attributes); diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h index b8ab330f5..03f4a7790 100644 --- a/Source/JavaScriptCore/runtime/JSType.h +++ b/Source/JavaScriptCore/runtime/JSType.h @@ -48,7 +48,7 @@ enum JSType { NameInstanceType, NumberObjectType, ErrorInstanceType, - GlobalThisType, + ProxyType, WithScopeType, NameScopeObjectType, diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index ac00fad3d..651e50cec 100644 --- a/Source/JavaScriptCore/runtime/JSValue.cpp +++ b/Source/JavaScriptCore/runtime/JSValue.cpp @@ -195,7 +195,7 @@ void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSVa char* JSValue::description() const { - static const size_t size = 128; + static const size_t size = 256; static char description[size]; if (!*this) @@ -213,9 +213,12 @@ char* JSValue::description() const u.asDouble = asDouble(); snprintf(description, size, "Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble()); #endif - } else if (isCell()) - snprintf(description, size, "Cell: %p", asCell()); - else if (isTrue()) + } else if (isCell()) { + snprintf( + description, size, "Cell: %p (%p: %s, %s)", + asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className, + indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory())); + } else if (isTrue()) snprintf(description, size, "True"); else if (isFalse()) snprintf(description, size, "False"); diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h index 55952820e..25961dc09 100644 --- a/Source/JavaScriptCore/runtime/JSVariableObject.h +++ b/Source/JavaScriptCore/runtime/JSVariableObject.h @@ -68,7 +68,7 @@ namespace JSC { { } - WriteBarrierBase<Unknown>* m_registers; // "r" in the register file. + WriteBarrierBase<Unknown>* m_registers; // "r" in the stack. }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSWithScope.cpp b/Source/JavaScriptCore/runtime/JSWithScope.cpp index 0c4b6e2cc..7d74e63c3 100644 --- a/Source/JavaScriptCore/runtime/JSWithScope.cpp +++ b/Source/JavaScriptCore/runtime/JSWithScope.cpp @@ -28,8 +28,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSWithScope); - const ClassInfo JSWithScope::s_info = { "WithScope", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSWithScope) }; void JSWithScope::visitChildren(JSCell* cell, SlotVisitor& visitor) diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp index 4a46c2c69..ff80c1e20 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp @@ -24,7 +24,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(JSWrapperObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSWrapperObject); void JSWrapperObject::visitChildren(JSCell* cell, SlotVisitor& visitor) diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h index 65b4bdb7f..72bc1874c 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.h +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h @@ -22,15 +22,15 @@ #ifndef JSWrapperObject_h #define JSWrapperObject_h -#include "JSObject.h" +#include "JSDestructibleObject.h" namespace JSC { // This class is used as a base for classes such as String, // Number, Boolean and Date which are wrappers for primitive types. - class JSWrapperObject : public JSNonFinalObject { + class JSWrapperObject : public JSDestructibleObject { public: - typedef JSNonFinalObject Base; + typedef JSDestructibleObject Base; JSValue internalValue() const; void setInternalValue(JSGlobalData&, JSValue); @@ -42,7 +42,7 @@ namespace JSC { protected: explicit JSWrapperObject(JSGlobalData&, Structure*); - static const unsigned StructureFlags = OverridesVisitChildren | JSNonFinalObject::StructureFlags; + static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; static void visitChildren(JSCell*, SlotVisitor&); @@ -51,7 +51,7 @@ namespace JSC { }; inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, Structure* structure) - : JSNonFinalObject(globalData, structure) + : JSDestructibleObject(globalData, structure) { } diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index 2a550a38b..2f4df375a 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -32,7 +32,7 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(MathObject); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(MathObject); static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*); static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*); @@ -59,9 +59,7 @@ static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*); namespace JSC { -ASSERT_HAS_TRIVIAL_DESTRUCTOR(MathObject); - -const ClassInfo MathObject::s_info = { "Math", &JSNonFinalObject::s_info, 0, ExecState::mathTable, CREATE_METHOD_TABLE(MathObject) }; +const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, ExecState::mathTable, CREATE_METHOD_TABLE(MathObject) }; /* Source for MathObject.lut.h @begin mathTable diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp index b35e9fbda..0f8efc604 100644 --- a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp +++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp @@ -28,7 +28,7 @@ #include "ExecutableAllocator.h" #include "JSGlobalData.h" -#include "RegisterFile.h" +#include "JSStack.h" namespace JSC { @@ -36,7 +36,7 @@ GlobalMemoryStatistics globalMemoryStatistics() { GlobalMemoryStatistics stats; - stats.stackBytes = RegisterFile::committedByteCount(); + stats.stackBytes = JSStack::committedByteCount(); #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED) || ((PLATFORM(BLACKBERRY) || PLATFORM(EFL)) && ENABLE(JIT)) stats.JITBytes = ExecutableAllocator::committedByteCount(); #else diff --git a/Source/JavaScriptCore/runtime/NameConstructor.cpp b/Source/JavaScriptCore/runtime/NameConstructor.cpp index 63f1f647a..b5facc7cf 100644 --- a/Source/JavaScriptCore/runtime/NameConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NameConstructor.cpp @@ -31,7 +31,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(NameConstructor); ASSERT_HAS_TRIVIAL_DESTRUCTOR(NameConstructor); const ClassInfo NameConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(NameConstructor) }; diff --git a/Source/JavaScriptCore/runtime/NameInstance.h b/Source/JavaScriptCore/runtime/NameInstance.h index c5931e8ef..129e7c407 100644 --- a/Source/JavaScriptCore/runtime/NameInstance.h +++ b/Source/JavaScriptCore/runtime/NameInstance.h @@ -26,14 +26,14 @@ #ifndef NameInstance_h #define NameInstance_h -#include "JSObject.h" +#include "JSDestructibleObject.h" #include "PrivateName.h" namespace JSC { -class NameInstance : public JSNonFinalObject { +class NameInstance : public JSDestructibleObject { public: - typedef JSNonFinalObject Base; + typedef JSDestructibleObject Base; static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/NamePrototype.cpp b/Source/JavaScriptCore/runtime/NamePrototype.cpp index 3e52856b6..f14e58522 100644 --- a/Source/JavaScriptCore/runtime/NamePrototype.cpp +++ b/Source/JavaScriptCore/runtime/NamePrototype.cpp @@ -30,8 +30,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(NamePrototype); - static EncodedJSValue JSC_HOST_CALL privateNameProtoFuncToString(ExecState*); } @@ -48,8 +46,6 @@ const ClassInfo NamePrototype::s_info = { "Name", &Base::s_info, 0, ExecState::p @end */ -ASSERT_CLASS_FITS_IN_CELL(NamePrototype); - NamePrototype::NamePrototype(ExecState* exec, Structure* structure) : Base(exec->globalData(), structure, jsEmptyString(exec)) { diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp index a4ba240fd..1f1730805 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -28,7 +28,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor); ASSERT_HAS_TRIVIAL_DESTRUCTOR(NativeErrorConstructor); const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(NativeErrorConstructor) }; diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp index 7fee213fa..296a86a22 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -27,8 +27,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype); - NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, Structure* structure) : ErrorPrototype(exec, structure) { diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.cpp b/Source/JavaScriptCore/runtime/NumberConstructor.cpp index 03d616073..daa643da7 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp @@ -28,8 +28,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(NumberConstructor); - static JSValue numberConstructorNaNValue(ExecState*, JSValue, PropertyName); static JSValue numberConstructorNegInfinity(ExecState*, JSValue, PropertyName); static JSValue numberConstructorPosInfinity(ExecState*, JSValue, PropertyName); diff --git a/Source/JavaScriptCore/runtime/NumberObject.cpp b/Source/JavaScriptCore/runtime/NumberObject.cpp index 1fea25464..b87753d4d 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.cpp +++ b/Source/JavaScriptCore/runtime/NumberObject.cpp @@ -27,7 +27,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(NumberObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberObject); const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(NumberObject) }; diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp index 4a10efd6d..23c9dbfdd 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp @@ -68,7 +68,6 @@ const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, @end */ -ASSERT_CLASS_FITS_IN_CELL(NumberPrototype); ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberPrototype); NumberPrototype::NumberPrototype(ExecState* exec, Structure* structure) diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp index 8614b9c45..7df047d28 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -35,8 +35,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor); - static EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*); static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*); static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*); diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp index b1a5b9fb3..e94edfadf 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -63,8 +63,6 @@ const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, @end */ -ASSERT_CLASS_FITS_IN_CELL(ObjectPrototype); - ObjectPrototype::ObjectPrototype(ExecState* exec, Structure* stucture) : JSNonFinalObject(exec->globalData(), stucture) { diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp index ed0720b54..386eb4fcf 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "Options.h" +#include "HeapStatistics.h" #include <algorithm> #include <limits> #include <stdio.h> @@ -41,10 +42,6 @@ #include <sys/sysctl.h> #endif -// Set to 1 to control the heuristics using environment variables. -#define ENABLE_RUN_TIME_HEURISTICS 0 - - namespace JSC { static bool parse(const char* string, bool& value) @@ -75,10 +72,10 @@ static bool parse(const char* string, double& value) return sscanf(string, "%lf", &value) == 1; } -#if ENABLE(RUN_TIME_HEURISTICS) template<typename T> void overrideOptionWithHeuristic(T& variable, const char* name) { +#if !OS(WINCE) const char* stringValue = getenv(name); if (!stringValue) return; @@ -87,9 +84,8 @@ void overrideOptionWithHeuristic(T& variable, const char* name) return; fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue); -} #endif - +} static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) { @@ -130,17 +126,19 @@ void Options::initialize() #if USE(CF) || OS(UNIX) objectsAreImmortal() = !!getenv("JSImmortalZombieEnabled"); useZombieMode() = !!getenv("JSImmortalZombieEnabled") || !!getenv("JSZombieEnabled"); + + gcMaxHeapSize() = getenv("GCMaxHeapSize") ? HeapStatistics::parseMemoryAmount(getenv("GCMaxHeapSize")) : 0; + recordGCPauseTimes() = !!getenv("JSRecordGCPauseTimes"); + logHeapStatisticsAtExit() = gcMaxHeapSize() || recordGCPauseTimes(); #endif // Allow environment vars to override options if applicable. // The evn var should be the name of the option prefixed with // "JSC_". -#if ENABLE(RUN_TIME_HEURISTICS) #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ overrideOptionWithHeuristic(name_(), "JSC_" #name_); JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION -#endif // RUN_TIME_HEURISTICS #if 0 ; // Deconfuse editors that do auto indentation @@ -153,7 +151,7 @@ void Options::initialize() #if !ENABLE(YARR_JIT) useRegExpJIT() = false; #endif - + // Do range checks where needed and make corrections to the options: ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp()); ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon()); diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h index 7571f9138..d6d8c66c8 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -51,9 +51,8 @@ namespace JSC { // purposes, you can do so in Options::initialize() after the default values // are set. // -// Alternatively, you can enable RUN_TIME_HEURISTICS which will allow you -// to override the default values by specifying environment variables of the -// form: JSC_<name of JSC option>. +// Alternatively, you can override the default values by specifying +// environment variables of the form: JSC_<name of JSC option>. // // Note: Options::initialize() tries to ensure some sanity on the option values // which are set by doing some range checks, and value corrections. These @@ -116,14 +115,19 @@ namespace JSC { v(unsigned, gcMarkStackSegmentSize, pageSize()) \ v(unsigned, numberOfGCMarkers, computeNumberOfGCMarkers(7)) \ v(unsigned, opaqueRootMergeThreshold, 1000) \ + v(double, minHeapUtilization, 0.8) \ + v(double, minCopiedBlockUtilization, 0.9) \ \ v(bool, forceWeakRandomSeed, false) \ v(unsigned, forcedWeakRandomSeed, 0) \ \ v(bool, useZombieMode, false) \ v(bool, objectsAreImmortal, false) \ - v(bool, showHeapStatistics, false) - + v(bool, showObjectStatistics, false) \ + \ + v(unsigned, gcMaxHeapSize, 0) \ + v(bool, recordGCPauseTimes, false) \ + v(bool, logHeapStatisticsAtExit, false) class Options { public: @@ -161,7 +165,7 @@ private: boolType, unsignedType, doubleType, - int32Type + int32Type, }; // For storing for an option value: diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h index 2d0f27a3e..9c6ddb20f 100644 --- a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h +++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -178,7 +178,7 @@ public: PropertyOffset getDeletedOffset(); void addDeletedOffset(PropertyOffset); - PropertyOffset nextOffset(JSType); + PropertyOffset nextOffset(PropertyOffset inlineCapacity); // Copy this PropertyTable, ensuring the copy has at least the capacity provided. PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity); @@ -486,15 +486,12 @@ inline void PropertyTable::addDeletedOffset(PropertyOffset offset) m_deletedOffsets->append(offset); } -inline PropertyOffset PropertyTable::nextOffset(JSType type) +inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity) { if (hasDeletedOffset()) return getDeletedOffset(); - - if (type == FinalObjectType) - return size(); - - return size() + firstOutOfLineOffset; + + return propertyOffsetFor(size(), inlineCapacity); } inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity) diff --git a/Source/JavaScriptCore/runtime/PropertyOffset.h b/Source/JavaScriptCore/runtime/PropertyOffset.h index 2aea2981e..1a2bba446 100644 --- a/Source/JavaScriptCore/runtime/PropertyOffset.h +++ b/Source/JavaScriptCore/runtime/PropertyOffset.h @@ -26,7 +26,6 @@ #ifndef PropertyOffset_h #define PropertyOffset_h -#include "JSType.h" #include <wtf/Platform.h> #include <wtf/StdLibExtras.h> #include <wtf/UnusedParam.h> @@ -42,14 +41,13 @@ namespace JSC { typedef int PropertyOffset; static const PropertyOffset invalidOffset = -1; -static const PropertyOffset inlineStorageCapacity = INLINE_STORAGE_CAPACITY; -static const PropertyOffset firstOutOfLineOffset = inlineStorageCapacity; +static const PropertyOffset firstOutOfLineOffset = 100; // Declare all of the functions because they tend to do forward calls. inline void checkOffset(PropertyOffset); -inline void checkOffset(PropertyOffset, JSType); +inline void checkOffset(PropertyOffset, PropertyOffset inlineCapacity); inline void validateOffset(PropertyOffset); -inline void validateOffset(PropertyOffset, JSType); +inline void validateOffset(PropertyOffset, PropertyOffset inlineCapacity); inline bool isValidOffset(PropertyOffset); inline bool isInlineOffset(PropertyOffset); inline bool isOutOfLineOffset(PropertyOffset); @@ -57,9 +55,7 @@ inline size_t offsetInInlineStorage(PropertyOffset); inline size_t offsetInOutOfLineStorage(PropertyOffset); inline size_t offsetInRespectiveStorage(PropertyOffset); inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset); -inline size_t numberOfSlotsForLastOffset(PropertyOffset, JSType); -inline PropertyOffset nextPropertyOffsetFor(PropertyOffset, JSType); -inline PropertyOffset firstPropertyOffsetFor(JSType); +inline size_t numberOfSlotsForLastOffset(PropertyOffset, PropertyOffset inlineCapacity); inline void checkOffset(PropertyOffset offset) { @@ -67,14 +63,14 @@ inline void checkOffset(PropertyOffset offset) ASSERT(offset >= invalidOffset); } -inline void checkOffset(PropertyOffset offset, JSType type) +inline void checkOffset(PropertyOffset offset, PropertyOffset inlineCapacity) { UNUSED_PARAM(offset); - UNUSED_PARAM(type); + UNUSED_PARAM(inlineCapacity); ASSERT(offset >= invalidOffset); ASSERT(offset == invalidOffset - || type == FinalObjectType - || isOutOfLineOffset(offset)); + || offset < inlineCapacity + || isOutOfLineOffset(offset)); } inline void validateOffset(PropertyOffset offset) @@ -83,9 +79,9 @@ inline void validateOffset(PropertyOffset offset) ASSERT(isValidOffset(offset)); } -inline void validateOffset(PropertyOffset offset, JSType type) +inline void validateOffset(PropertyOffset offset, PropertyOffset inlineCapacity) { - checkOffset(offset, type); + checkOffset(offset, inlineCapacity); ASSERT(isValidOffset(offset)); } @@ -98,7 +94,7 @@ inline bool isValidOffset(PropertyOffset offset) inline bool isInlineOffset(PropertyOffset offset) { checkOffset(offset); - return offset < inlineStorageCapacity; + return offset < firstOutOfLineOffset; } inline bool isOutOfLineOffset(PropertyOffset offset) @@ -136,28 +132,24 @@ inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset offset) return offset - firstOutOfLineOffset + 1; } -inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, JSType type) +inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, PropertyOffset inlineCapacity) { - checkOffset(offset, type); - if (type == FinalObjectType) + checkOffset(offset, inlineCapacity); + if (offset < inlineCapacity) return offset + 1; - return numberOfOutOfLineSlotsForLastOffset(offset); + return inlineCapacity + numberOfOutOfLineSlotsForLastOffset(offset); } -inline PropertyOffset nextPropertyOffsetFor(PropertyOffset offset, JSType type) +inline PropertyOffset propertyOffsetFor(PropertyOffset propertyNumber, PropertyOffset inlineCapacity) { - checkOffset(offset, type); - if (type != FinalObjectType && offset == invalidOffset) - return firstOutOfLineOffset; - return offset + 1; -} - -inline PropertyOffset firstPropertyOffsetFor(JSType type) -{ - return nextPropertyOffsetFor(invalidOffset, type); + PropertyOffset offset = propertyNumber; + if (offset >= inlineCapacity) { + offset += firstOutOfLineOffset; + offset -= inlineCapacity; + } + return offset; } } // namespace JSC #endif // PropertyOffset_h - diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h index 287444b95..b2b65d90c 100644 --- a/Source/JavaScriptCore/runtime/RegExp.h +++ b/Source/JavaScriptCore/runtime/RegExp.h @@ -47,6 +47,8 @@ namespace JSC { typedef JSCell Base; JS_EXPORT_PRIVATE static RegExp* create(JSGlobalData&, const String& pattern, RegExpFlags); + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); bool global() const { return m_flags & FlagGlobal; } diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp index c67dab8e6..8acafba23 100644 --- a/Source/JavaScriptCore/runtime/RegExpCache.cpp +++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp @@ -80,7 +80,7 @@ void RegExpCache::invalidateCode() RegExpCacheMap::iterator end = m_weakCache.end(); for (RegExpCacheMap::iterator it = m_weakCache.begin(); it != end; ++it) { - RegExp* regExp = it->second.get(); + RegExp* regExp = it->value.get(); if (!regExp) // Skip zombies. continue; regExp->invalidateCode(); diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index b8c4cd0b3..cc6ceb1d1 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -53,8 +53,6 @@ static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue); namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor); - const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) }; /* Source for RegExpConstructor.lut.h diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp index 04fea60e8..ce9c2d2db 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp @@ -30,8 +30,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(RegExpMatchesArray); - const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)}; RegExpMatchesArray::RegExpMatchesArray(JSGlobalData& globalData, Butterfly* butterfly, JSGlobalObject* globalObject, JSString* input, RegExp* regExp, MatchResult result) diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp index bed44f22c..dfbf533f7 100644 --- a/Source/JavaScriptCore/runtime/RegExpObject.cpp +++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp @@ -49,9 +49,9 @@ static JSValue regExpObjectSource(ExecState*, JSValue, PropertyName); namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(RegExpObject); +ASSERT_HAS_TRIVIAL_DESTRUCTOR(RegExpObject); -const ClassInfo RegExpObject::s_info = { "RegExp", &JSNonFinalObject::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) }; +const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) }; /* Source for RegExpObject.lut.h @begin regExpTable diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp index 3c742a0d3..e4bf2cf9a 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -59,8 +59,6 @@ const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, 0, @end */ -ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype); - RegExpPrototype::RegExpPrototype(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp) : RegExpObject(globalObject, structure, regExp) { diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp index b9ba25735..7f21e2c9f 100644 --- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp +++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.cpp @@ -88,7 +88,7 @@ SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSObject* array, unsigne void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i, JSValue value, bool shouldThrow) { AddResult result = add(array, i); - SparseArrayEntry& entry = result.iterator->second; + SparseArrayEntry& entry = result.iterator->value; // To save a separate find & add, we first always add to the sparse map. // In the uncommon case that this is a new property, and the array is not @@ -106,7 +106,7 @@ void SparseArrayValueMap::putEntry(ExecState* exec, JSObject* array, unsigned i, bool SparseArrayValueMap::putDirect(ExecState* exec, JSObject* array, unsigned i, JSValue value, unsigned attributes, PutDirectIndexMode mode) { AddResult result = add(array, i); - SparseArrayEntry& entry = result.iterator->second; + SparseArrayEntry& entry = result.iterator->value; // To save a separate find & add, we first always add to the sparse map. // In the uncommon case that this is a new property, and the array is not @@ -207,7 +207,7 @@ void SparseArrayValueMap::visitChildren(JSCell* thisObject, SlotVisitor& visitor SparseArrayValueMap* thisMap = jsCast<SparseArrayValueMap*>(thisObject); iterator end = thisMap->m_map.end(); for (iterator it = thisMap->m_map.begin(); it != end; ++it) - visitor.append(&it->second); + visitor.append(&it->value); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h index 5d8d0577a..366a7b8ba 100644 --- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h +++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h @@ -81,6 +81,8 @@ public: static SparseArrayValueMap* create(JSGlobalData&); + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue prototype); diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp index 460343761..7f36a84be 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.cpp +++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp @@ -45,7 +45,6 @@ const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_i @end */ -ASSERT_CLASS_FITS_IN_CELL(StringConstructor); ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringConstructor); StringConstructor::StringConstructor(JSGlobalObject* globalObject, Structure* structure) diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp index 15900913d..ab7d6cb23 100644 --- a/Source/JavaScriptCore/runtime/StringObject.cpp +++ b/Source/JavaScriptCore/runtime/StringObject.cpp @@ -27,7 +27,6 @@ namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(StringObject); ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringObject); const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringObject) }; diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp index 8daa0f335..1540177be 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -47,7 +47,6 @@ using namespace WTF; namespace JSC { -ASSERT_CLASS_FITS_IN_CELL(StringPrototype); ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringPrototype); static EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*); diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp index a59a0860d..a931def27 100644 --- a/Source/JavaScriptCore/runtime/Structure.cpp +++ b/Source/JavaScriptCore/runtime/Structure.cpp @@ -149,7 +149,7 @@ void Structure::dumpStatistics() #endif } -Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType) +Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity) : JSCell(globalData, globalData.structureStructure.get()) , m_typeInfo(typeInfo) , m_indexingType(indexingType) @@ -158,6 +158,7 @@ Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSV , m_classInfo(classInfo) , m_transitionWatchpointSet(InitializedWatching) , m_outOfLineCapacity(0) + , m_inlineCapacity(inlineCapacity) , m_offset(invalidOffset) , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) @@ -182,6 +183,7 @@ Structure::Structure(JSGlobalData& globalData) , m_classInfo(&s_info) , m_transitionWatchpointSet(InitializedWatching) , m_outOfLineCapacity(0) + , m_inlineCapacity(0) , m_offset(invalidOffset) , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) @@ -204,6 +206,7 @@ Structure::Structure(JSGlobalData& globalData, const Structure* previous) , m_classInfo(previous->m_classInfo) , m_transitionWatchpointSet(InitializedWatching) , m_outOfLineCapacity(previous->m_outOfLineCapacity) + , m_inlineCapacity(previous->m_inlineCapacity) , m_offset(invalidOffset) , m_dictionaryKind(previous->m_dictionaryKind) , m_isPinnedPropertyTable(false) @@ -323,11 +326,15 @@ bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const } } -NonPropertyTransition Structure::suggestedIndexingTransition() const +bool Structure::needsSlowPutIndexing() const { - ASSERT(!hasIndexedProperties(indexingType())); - - if (anyObjectInChainMayInterceptIndexedAccesses() || globalObject()->isHavingABadTime()) + return anyObjectInChainMayInterceptIndexedAccesses() + || globalObject()->isHavingABadTime(); +} + +NonPropertyTransition Structure::suggestedArrayStorageTransition() const +{ + if (needsSlowPutIndexing()) return AllocateSlowPutArrayStorage; return AllocateArrayStorage; @@ -546,6 +553,7 @@ Structure* Structure::nonPropertyTransition(JSGlobalData& globalData, Structure* transition->m_previous.set(globalData, transition, structure); transition->m_attributesInPrevious = attributes; transition->m_indexingType = indexingType; + transition->m_offset = structure->m_offset; if (structure->m_propertyTable) { if (structure->m_isPinnedPropertyTable) @@ -608,20 +616,21 @@ Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObj ASSERT(m_propertyTable); size_t propertyCount = m_propertyTable->size(); + + // Holds our values compacted by insertion order. Vector<JSValue> values(propertyCount); - + + // Copies out our values from their hashed locations, compacting property table offsets as we go. unsigned i = 0; - PropertyOffset firstOffset = firstPropertyOffsetFor(m_typeInfo.type()); PropertyTable::iterator end = m_propertyTable->end(); for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) { values[i] = object->getDirectOffset(iter->offset); - // Update property table to have the new property offsets - iter->offset = i + firstOffset; + iter->offset = propertyOffsetFor(i, m_inlineCapacity); } - // Copy the original property values into their final locations + // Copies in our values to their compacted locations. for (unsigned i = 0; i < propertyCount; i++) - object->putDirectOffset(globalData, firstOffset + i, values[i]); + object->putDirectOffset(globalData, propertyOffsetFor(i, m_inlineCapacity), values[i]); m_propertyTable->clearDeletedOffsets(); } @@ -759,7 +768,7 @@ PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyNam if (!m_propertyTable) createPropertyMap(); - PropertyOffset newOffset = m_propertyTable->nextOffset(m_typeInfo.type()); + PropertyOffset newOffset = m_propertyTable->nextOffset(m_inlineCapacity); m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue)); diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h index e77287b20..f45e9f1d9 100644 --- a/Source/JavaScriptCore/runtime/Structure.h +++ b/Source/JavaScriptCore/runtime/Structure.h @@ -69,7 +69,7 @@ namespace JSC { typedef JSCell Base; - static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0); + static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = NonArray, PropertyOffset inlineCapacity = 0); protected: void finishCreation(JSGlobalData& globalData) @@ -128,6 +128,8 @@ namespace JSC { Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*); + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); // These should be used with caution. @@ -152,7 +154,8 @@ namespace JSC { bool anyObjectInChainMayInterceptIndexedAccesses() const; - NonPropertyTransition suggestedIndexingTransition() const; + bool needsSlowPutIndexing() const; + NonPropertyTransition suggestedArrayStorageTransition() const; JSGlobalObject* globalObject() const { return m_globalObject.get(); } void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); } @@ -177,24 +180,6 @@ namespace JSC { ASSERT(structure()->classInfo() == &s_info); return m_outOfLineCapacity; } - unsigned outOfLineSizeForKnownFinalObject() const - { - ASSERT(m_typeInfo.type() == FinalObjectType); - if (m_propertyTable) { - unsigned totalSize = m_propertyTable->propertyStorageSize(); - if (totalSize < static_cast<unsigned>(inlineStorageCapacity)) - return 0; - return totalSize - inlineStorageCapacity; - } - return numberOfOutOfLineSlotsForLastOffset(m_offset); - } - unsigned outOfLineSizeForKnownNonFinalObject() const - { - ASSERT(m_typeInfo.type() != FinalObjectType); - if (m_propertyTable) - return m_propertyTable->propertyStorageSize(); - return numberOfOutOfLineSlotsForLastOffset(m_offset); - } unsigned outOfLineSize() const { ASSERT(structure()->classInfo() == &s_info); @@ -209,31 +194,20 @@ namespace JSC { } bool hasInlineStorage() const { - return m_typeInfo.type() == FinalObjectType; + return !!m_inlineCapacity; } unsigned inlineCapacity() const { - if (hasInlineStorage()) - return inlineStorageCapacity; - return 0; + return m_inlineCapacity; } - unsigned inlineSizeForKnownFinalObject() const + unsigned inlineSize() const { - ASSERT(m_typeInfo.type() == FinalObjectType); unsigned result; if (m_propertyTable) result = m_propertyTable->propertyStorageSize(); else result = m_offset + 1; - if (result > static_cast<unsigned>(inlineStorageCapacity)) - return inlineStorageCapacity; - return result; - } - unsigned inlineSize() const - { - if (!hasInlineStorage()) - return 0; - return inlineSizeForKnownFinalObject(); + return std::min<unsigned>(result, m_inlineCapacity); } unsigned totalStorageSize() const { @@ -251,16 +225,12 @@ namespace JSC { { if (hasInlineStorage()) return 0; - return inlineStorageCapacity; + return firstOutOfLineOffset; } PropertyOffset lastValidOffset() const { - if (m_propertyTable) { - PropertyOffset size = m_propertyTable->propertyStorageSize(); - if (!hasInlineStorage()) - size += inlineStorageCapacity; - return size - 1; - } + if (m_propertyTable) + return propertyOffsetFor(m_propertyTable->propertyStorageSize() - 1, m_inlineCapacity); return m_offset; } bool isValidOffset(PropertyOffset offset) const @@ -381,7 +351,7 @@ namespace JSC { private: friend class LLIntOffsetsExtractor; - JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0); + JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, PropertyOffset inlineCapacity); Structure(JSGlobalData&); Structure(JSGlobalData&, const Structure*); @@ -457,6 +427,8 @@ namespace JSC { mutable InlineWatchpointSet m_transitionWatchpointSet; uint32_t m_outOfLineCapacity; + uint8_t m_inlineCapacity; + COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits); // m_offset does not account for anonymous slots PropertyOffset m_offset; @@ -473,22 +445,11 @@ namespace JSC { unsigned m_staticFunctionReified; }; - template <> inline void* allocateCell<Structure>(Heap& heap) - { -#if ENABLE(GC_VALIDATION) - ASSERT(!heap.globalData()->isInitializingObject()); - heap.globalData()->setInitializingObjectClass(&Structure::s_info); -#endif - JSCell* result = static_cast<JSCell*>(heap.allocateStructure(sizeof(Structure))); - result->clearStructure(); - return result; - } - - inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType) + inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity) { ASSERT(globalData.structureStructure); ASSERT(classInfo); - Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType); + Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity); structure->finishCreation(globalData); return structure; } @@ -628,15 +589,6 @@ namespace JSC { ASSERT(m_structure || !globalData.structureStructure); } - inline const ClassInfo* JSCell::classInfo() const - { -#if ENABLE(GC_VALIDATION) - return m_structure.unvalidatedGet()->classInfo(); -#else - return m_structure->classInfo(); -#endif - } - } // namespace JSC #endif // Structure_h diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h index 3b19d4cf1..878f606b4 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.h +++ b/Source/JavaScriptCore/runtime/StructureChain.h @@ -59,6 +59,10 @@ namespace JSC { static ClassInfo s_info; + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + protected: void finishCreation(JSGlobalData& globalData, Structure* head) { @@ -78,7 +82,6 @@ namespace JSC { friend class LLIntOffsetsExtractor; StructureChain(JSGlobalData&, Structure*); - static void destroy(JSCell*); OwnArrayPtr<WriteBarrier<Structure> > m_vector; }; diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h index 90cb6a4db..3ab7b2014 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -43,6 +43,7 @@ static const unsigned FirstInternalAttribute = 1 << 6; // Use for transitions th // Support for attributes used to indicate transitions not related to properties. // If any of these are used, the string portion of the key should be 0. enum NonPropertyTransition { + AllocateContiguous, AllocateArrayStorage, AllocateSlowPutArrayStorage, SwitchToSlowPutArrayStorage, @@ -57,13 +58,18 @@ inline unsigned toAttributes(NonPropertyTransition transition) inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition) { switch (transition) { + case AllocateContiguous: + ASSERT(!hasIndexedProperties(oldType)); + return oldType | ContiguousShape; case AllocateArrayStorage: - return oldType | HasArrayStorage; + ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); + return (oldType & ~IndexingShapeMask) | ArrayStorageShape; case AllocateSlowPutArrayStorage: - return oldType | HasSlowPutArrayStorage; + ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); + return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; case SwitchToSlowPutArrayStorage: - ASSERT(oldType & HasArrayStorage); - return (oldType & ~HasArrayStorage) | HasSlowPutArrayStorage; + ASSERT(hasFastArrayStorage(oldType)); + return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; case AddIndexedAccessors: return oldType | MayHaveIndexedAccessors; default: diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index 6063dbab4..debb76499 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -344,12 +344,16 @@ namespace JSC { class SharedSymbolTable : public JSCell, public SymbolTable { public: + typedef JSCell Base; + static SharedSymbolTable* create(JSGlobalData& globalData) { SharedSymbolTable* sharedSymbolTable = new (NotNull, allocateCell<SharedSymbolTable>(globalData.heap)) SharedSymbolTable(globalData); sharedSymbolTable->finishCreation(globalData); return sharedSymbolTable; } + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; static void destroy(JSCell*); static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) @@ -396,6 +400,7 @@ namespace JSC { OwnArrayPtr<SlowArgument> m_slowArguments; }; + } // namespace JSC #endif // SymbolTable_h diff --git a/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h b/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h new file mode 100644 index 000000000..1ae4818be --- /dev/null +++ b/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TypedArrayDescriptor_h +#define TypedArrayDescriptor_h + +namespace JSC { + +struct ClassInfo; + +enum TypedArrayType { + TypedArrayNone, + TypedArrayInt8, + TypedArrayInt16, + TypedArrayInt32, + TypedArrayUint8, + TypedArrayUint8Clamped, + TypedArrayUint16, + TypedArrayUint32, + TypedArrayFloat32, + TypedArrayFloat64 +}; + +struct TypedArrayDescriptor { + TypedArrayDescriptor() + : m_classInfo(0) + , m_storageOffset(0) + , m_lengthOffset(0) + { + } + TypedArrayDescriptor(const ClassInfo* classInfo, size_t storageOffset, size_t lengthOffset) + : m_classInfo(classInfo) + , m_storageOffset(storageOffset) + , m_lengthOffset(lengthOffset) + { + } + const ClassInfo* m_classInfo; + size_t m_storageOffset; + size_t m_lengthOffset; +}; + +enum TypedArraySignedness { + SignedTypedArray, + UnsignedTypedArray +}; +enum TypedArrayRounding { + TruncateRounding, + ClampRounding +}; + +} // namespace JSC + +#endif // TypedArrayDescriptor_h + diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h index 6926165a7..52e5e2946 100644 --- a/Source/JavaScriptCore/runtime/WeakGCMap.h +++ b/Source/JavaScriptCore/runtime/WeakGCMap.h @@ -63,7 +63,7 @@ public: { typename MapType::iterator end = m_map.end(); for (typename MapType::iterator ptr = m_map.begin(); ptr != end; ++ptr) - WeakSet::deallocate(ptr->second); + WeakSet::deallocate(ptr->value); m_map.clear(); } @@ -80,8 +80,8 @@ public: ASSERT_UNUSED(globalData, globalData.apiLock().currentThreadIsHoldingLock()); typename MapType::AddResult result = m_map.add(key, 0); if (!result.isNewEntry) - WeakSet::deallocate(result.iterator->second); - result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key)); + WeakSet::deallocate(result.iterator->value); + result.iterator->value = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key)); } void remove(const KeyType& key) |