diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-16 14:56:46 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-16 14:57:30 +0200 |
commit | b297e0fa5c217c9467033b7c8b46891a52870120 (patch) | |
tree | 43fc14689295e9e64f2719d05aad94e3049f6cd7 /Source/JavaScriptCore/runtime | |
parent | 69d517dbfa69903d8593cc1737f0474b21e3251e (diff) | |
download | qtwebkit-b297e0fa5c217c9467033b7c8b46891a52870120.tar.gz |
Revert "Imported WebKit commit 0dc6cd75e1d4836eaffbb520be96fac4847cc9d2 (http://svn.webkit.org/repository/webkit/trunk@131300)"
This reverts commit 5466563f4b5b6b86523e3f89bb7f77e5b5270c78.
Caused OOM issues on some CI machines :(
Diffstat (limited to 'Source/JavaScriptCore/runtime')
96 files changed, 1001 insertions, 2051 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp index ba73b2cf2..fdf202192 100644 --- a/Source/JavaScriptCore/runtime/Arguments.cpp +++ b/Source/JavaScriptCore/runtime/Arguments.cpp @@ -33,7 +33,9 @@ using namespace std; namespace JSC { -const ClassInfo Arguments::s_info = { "Arguments", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) }; +ASSERT_CLASS_FITS_IN_CELL(Arguments); + +const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) }; void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor) { @@ -404,19 +406,19 @@ void Arguments::tearOffForInlineCallFrame(JSGlobalData& globalData, Register* re JSValue value; Register* location = ®isters[CallFrame::argumentOffset(i)]; switch (recovery.technique()) { - case AlreadyInJSStack: + case AlreadyInRegisterFile: value = location->jsValue(); break; - case AlreadyInJSStackAsUnboxedInt32: + case AlreadyInRegisterFileAsUnboxedInt32: value = jsNumber(location->unboxedInt32()); break; - case AlreadyInJSStackAsUnboxedCell: + case AlreadyInRegisterFileAsUnboxedCell: value = location->unboxedCell(); break; - case AlreadyInJSStackAsUnboxedBoolean: + case AlreadyInRegisterFileAsUnboxedBoolean: value = jsBoolean(location->unboxedBoolean()); break; - case AlreadyInJSStackAsUnboxedDouble: + case AlreadyInRegisterFileAsUnboxedDouble: #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 7c8b69bd1..40063bead 100644 --- a/Source/JavaScriptCore/runtime/Arguments.h +++ b/Source/JavaScriptCore/runtime/Arguments.h @@ -26,7 +26,6 @@ #include "CodeOrigin.h" #include "JSActivation.h" -#include "JSDestructibleObject.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "Interpreter.h" @@ -34,11 +33,11 @@ namespace JSC { - class Arguments : public JSDestructibleObject { + class Arguments : public JSNonFinalObject { friend class JIT; friend class DFG::SpeculativeJIT; public: - typedef JSDestructibleObject Base; + typedef JSNonFinalObject Base; static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame) { @@ -148,12 +147,12 @@ namespace JSC { } inline Arguments::Arguments(CallFrame* callFrame) - : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) { } inline Arguments::Arguments(CallFrame* callFrame, NoParametersType) - : JSDestructibleObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) + : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure()) { } diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp index a13648442..eda35e146 100644 --- a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -53,6 +53,8 @@ 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 a557b1ef9..3ea6b0471 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 / minDensityMultiplier <= numValues; + return length <= MIN_SPARSE_ARRAY_INDEX || 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 6975dc778..1eacd1179 100644 --- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -42,6 +42,8 @@ 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*); @@ -192,8 +194,7 @@ 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. -template<JSArray::ShiftCountMode shiftCountMode> -void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) +static inline void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) { ASSERT(currentCount > resultCount); unsigned count = currentCount - resultCount; @@ -201,9 +202,9 @@ void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned current ASSERT(header <= length); ASSERT(currentCount <= (length - header)); - if (isJSArray(thisObj)) { + if (!header && isJSArray(thisObj)) { JSArray* array = asArray(thisObj); - if (array->length() == length && asArray(thisObj)->shiftCount<shiftCountMode>(exec, header, count)) + if (array->length() == length && asArray(thisObj)->shiftCount(exec, count)) return; } @@ -230,8 +231,7 @@ void shift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned current } } } -template<JSArray::ShiftCountMode shiftCountMode> -void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned currentCount, unsigned resultCount, unsigned length) +static inline 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 @@ void unshift(ExecState* exec, JSObject* thisObj, unsigned header, unsigned curre return; } - if (isJSArray(thisObj)) { + if (!header && isJSArray(thisObj)) { JSArray* array = asArray(thisObj); - if (array->length() == length && array->unshiftCount<shiftCountMode>(exec, header, count)) + if (array->length() == length && asArray(thisObj)->unshiftCount(exec, 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,7 +544,6 @@ 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); @@ -601,7 +600,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec) result = jsUndefined(); } else { result = thisObj->get(exec, 0); - shift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 1, 0, length); + shift(exec, thisObj, 0, 1, 0, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1)); @@ -656,7 +655,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec) CallData callData; CallType callType = getCallData(function, callData); - if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->hasSparseMap() && !shouldUseSlowPut(thisObj->structure()->indexingType())) { + if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseIndexingMode() && !shouldUseSlowPut(thisObj->structure()->indexingType())) { if (isNumericCompareFunction(exec, callType, callData)) asArray(thisObj)->sortNumeric(exec, function, callType, callData); else if (callType != CallTypeNone) @@ -731,7 +730,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)); @@ -763,11 +762,11 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec) unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0); if (additionalArgs < deleteCount) { - shift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length); + shift(exec, thisObj, begin, deleteCount, additionalArgs, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); } else if (additionalArgs > deleteCount) { - unshift<JSArray::ShiftCountForSplice>(exec, thisObj, begin, deleteCount, additionalArgs, length); + unshift(exec, thisObj, begin, deleteCount, additionalArgs, length); if (exec->hadException()) return JSValue::encode(jsUndefined()); } @@ -792,7 +791,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec) unsigned nrArgs = exec->argumentCount(); if (nrArgs) { - unshift<JSArray::ShiftCountForShift>(exec, thisObj, 0, 0, nrArgs, length); + unshift(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 ffd84b281..1ab936335 100644 --- a/Source/JavaScriptCore/runtime/ArrayStorage.h +++ b/Source/JavaScriptCore/runtime/ArrayStorage.h @@ -41,8 +41,6 @@ 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 0485350ce..9b666292c 100644 --- a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -26,6 +26,7 @@ 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 355993864..bf2655bbb 100644 --- a/Source/JavaScriptCore/runtime/BooleanObject.cpp +++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp @@ -25,6 +25,7 @@ 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 a331c6c15..c8c77220a 100644 --- a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -47,6 +47,7 @@ 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 cb93aea8a..1926169ba 100644 --- a/Source/JavaScriptCore/runtime/Butterfly.h +++ b/Source/JavaScriptCore/runtime/Butterfly.h @@ -35,7 +35,7 @@ namespace JSC { class JSGlobalData; -class CopyVisitor; +class SlotVisitor; struct ArrayStorage; class Butterfly { @@ -56,15 +56,6 @@ 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(); } @@ -73,27 +64,15 @@ 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(CopyVisitor&, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes); + static Butterfly* createUninitializedDuringCollection(SlotVisitor&, 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 86a836bef..049350342 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(CopyVisitor& visitor, size_t preCapacity, size_t propertyCapacity, bool hasIndexingHeader, size_t indexingPayloadSizeInBytes) +inline Butterfly* Butterfly::createUninitializedDuringCollection(SlotVisitor& 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(hasArrayStorage(structure->indexingType())); + ASSERT(hasIndexingHeader(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(hasArrayStorage(structure->indexingType())); + ASSERT(hasIndexingHeader(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 c918621fe..e8823d571 100644 --- a/Source/JavaScriptCore/runtime/ClassInfo.h +++ b/Source/JavaScriptCore/runtime/ClassInfo.h @@ -39,9 +39,6 @@ namespace JSC { typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&); VisitChildrenFunctionPtr visitChildren; - typedef void (*CopyBackingStoreFunctionPtr)(JSCell*, CopyVisitor&); - CopyBackingStoreFunctionPtr copyBackingStore; - typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&); GetCallDataFunctionPtr getCallData; @@ -119,7 +116,6 @@ 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 2f5159461..7edd9091c 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, JSStack* stack, CodeSpecializationKind kind) +ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFile, CodeSpecializationKind kind) { JSFunction* callee = jsCast<JSFunction*>(exec->callee()); ASSERT(!callee->isHostFunction()); @@ -51,7 +51,7 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, JSStack* stack, CodeSpec int argumentCountIncludingThis = exec->argumentCountIncludingThis(); // This ensures enough space for the worst case scenario of zero arguments passed by the caller. - if (!stack->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters)) + if (!registerFile->grow(exec->registers() + newCodeBlock->numParameters() + newCodeBlock->m_numCalleeRegisters)) return 0; ASSERT(argumentCountIncludingThis < newCodeBlock->numParameters()); @@ -71,7 +71,7 @@ ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, JSStack* stack, CodeSpec dst[i] = jsUndefined(); ExecState* newExec = ExecState::create(dst); - ASSERT((void*)newExec <= stack->end()); + ASSERT((void*)newExec <= registerFile->end()); return newExec; } diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp index f78e8bf55..e4f89dd37 100644 --- a/Source/JavaScriptCore/runtime/DateConstructor.cpp +++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp @@ -71,6 +71,7 @@ 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 75da466fb..9b2cb164f 100644 --- a/Source/JavaScriptCore/runtime/DatePrototype.cpp +++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp @@ -70,6 +70,8 @@ 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 68ae12d90..27a729d0a 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -177,6 +177,8 @@ 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 f2578a497..96272d0cf 100644 --- a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -27,6 +27,7 @@ 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 a30efdc31..6c9d6df04 100644 --- a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -30,7 +30,7 @@ namespace JSC { -ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorPrototype); +ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*); @@ -48,6 +48,8 @@ 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 76a537da3..6eeda3a82 100644 --- a/Source/JavaScriptCore/runtime/Executable.h +++ b/Source/JavaScriptCore/runtime/Executable.h @@ -81,8 +81,6 @@ 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 bf74c0a97..570444e3c 100644 --- a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -34,6 +34,7 @@ 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 a4b2202c1..dd1628b29 100644 --- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -32,6 +32,7 @@ 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 45dd0bbde..a9a2a66bf 100644 --- a/Source/JavaScriptCore/runtime/Identifier.cpp +++ b/Source/JavaScriptCore/runtime/Identifier.cpp @@ -30,7 +30,6 @@ #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; @@ -81,7 +80,11 @@ struct IdentifierLCharFromUCharTranslator { { LChar* d; StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef(); - WTF::copyLCharsFromUCharSource(d, buf.s, buf.length); + for (unsigned i = 0; i != buf.length; i++) { + UChar c = buf.s[i]; + ASSERT(c <= 0xff); + d[i] = c; + } r->setHash(hash); location = r; } @@ -99,7 +102,7 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c) const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c); if (iter != literalIdentifierTable.end()) - return iter->value; + return iter->second; 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 22785ce24..e1d893b0b 100644 --- a/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h +++ b/Source/JavaScriptCore/runtime/IndexingHeaderInlineMethods.h @@ -42,17 +42,10 @@ inline size_t IndexingHeader::preCapacity(Structure* structure) inline size_t IndexingHeader::indexingPayloadSizeInBytes(Structure* structure) { - 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())); + if (LIKELY(!hasArrayStorage(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 deleted file mode 100644 index 7261847a2..000000000 --- a/Source/JavaScriptCore/runtime/IndexingType.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 4bbe3cfa0..3b97230ea 100644 --- a/Source/JavaScriptCore/runtime/IndexingType.h +++ b/Source/JavaScriptCore/runtime/IndexingType.h @@ -26,44 +26,32 @@ #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; - -// 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; +static const IndexingType HasArrayStorage = 8; +static const IndexingType HasSlowPutArrayStorage = 16; // Additional flags for tracking the history of the type. These are usually // masked off unless you ask for them directly. -static const IndexingType MayHaveIndexedAccessors = 32; +static const IndexingType HadArrayStorage = 32; // Means that this object did have array storage in the past. +static const IndexingType MayHaveIndexedAccessors = 64; // List of acceptable array types. static const IndexingType NonArray = 0; -static const IndexingType NonArrayWithContiguous = ContiguousShape; -static const IndexingType NonArrayWithArrayStorage = ArrayStorageShape; -static const IndexingType NonArrayWithSlowPutArrayStorage = SlowPutArrayStorageShape; +static const IndexingType NonArrayWithArrayStorage = HasArrayStorage; +static const IndexingType NonArrayWithSlowPutArrayStorage = HasSlowPutArrayStorage; static const IndexingType ArrayClass = IsArray; // I'd want to call this "Array" but this would lead to disastrous namespace pollution. -static const IndexingType ArrayWithContiguous = IsArray | ContiguousShape; -static const IndexingType ArrayWithArrayStorage = IsArray | ArrayStorageShape; -static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArrayStorageShape; +static const IndexingType ArrayWithArrayStorage = IsArray | HasArrayStorage; +static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | HasSlowPutArrayStorage; #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 @@ -75,7 +63,12 @@ static const IndexingType ArrayWithSlowPutArrayStorage = IsArray | SlowPutArr static inline bool hasIndexedProperties(IndexingType indexingType) { - return (indexingType & IndexingShapeMask) != NoIndexingShape; + switch (indexingType) { + case ALL_BLANK_INDEXING_TYPES: + return false; + default: + return true; + } } static inline bool hasIndexingHeader(IndexingType type) @@ -83,30 +76,16 @@ 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 static_cast<uint8_t>((indexingType & IndexingShapeMask) - ArrayStorageShape) <= static_cast<uint8_t>(SlowPutArrayStorageShape - ArrayStorageShape); + return !!(indexingType & (HasArrayStorage | HasSlowPutArrayStorage)); } static inline bool shouldUseSlowPut(IndexingType indexingType) { - return (indexingType & IndexingShapeMask) == SlowPutArrayStorageShape; + return !!(indexingType & HasSlowPutArrayStorage); } -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 1a6c84514..1a7239f60 100644 --- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp @@ -31,7 +31,6 @@ #include "ExecutableAllocator.h" #include "Heap.h" -#include "HeapStatistics.h" #include "Options.h" #include "Identifier.h" #include "JSDateMath.h" @@ -57,15 +56,13 @@ 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 - JSStack::initializeThreading(); + RegisterFile::initializeThreading(); #if ENABLE(LLINT) LLInt::initialize(); #endif diff --git a/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp index afb5e6317..e2de03d92 100644 --- a/Source/JavaScriptCore/runtime/InternalFunction.cpp +++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp @@ -29,12 +29,13 @@ namespace JSC { +ASSERT_CLASS_FITS_IN_CELL(InternalFunction); ASSERT_HAS_TRIVIAL_DESTRUCTOR(InternalFunction); -const ClassInfo InternalFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) }; +const ClassInfo InternalFunction::s_info = { "Function", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) }; InternalFunction::InternalFunction(JSGlobalObject* globalObject, Structure* structure) - : JSDestructibleObject(globalObject->globalData(), structure) + : JSNonFinalObject(globalObject->globalData(), structure) { } diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h index daeebc34d..e26b9f953 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 JSDestructibleObject { + class InternalFunction : public JSNonFinalObject { public: - typedef JSDestructibleObject Base; + typedef JSNonFinalObject Base; static JS_EXPORTDATA const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp index 3b665962f..c34e10bc8 100644 --- a/Source/JavaScriptCore/runtime/JSActivation.cpp +++ b/Source/JavaScriptCore/runtime/JSActivation.cpp @@ -37,6 +37,8 @@ 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) @@ -47,7 +49,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 JSStack. + // No need to mark our registers if they're still in the RegisterFile. if (!thisObject->isTornOff()) return; @@ -114,11 +116,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->value.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) + if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties) continue; - if (!thisObject->isValid(it->value)) + if (!thisObject->isValid(it->second)) continue; - propertyNames.add(Identifier(exec, it->key.get())); + propertyNames.add(Identifier(exec, it->first.get())); } // Skip the JSVariableObject implementation of getOwnNonIndexPropertyNames JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); @@ -131,7 +133,7 @@ inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, SymbolTable::iterator iter = symbolTable()->find(propertyName.publicName()); if (iter == symbolTable()->end()) return false; - SymbolTableEntry& entry = iter->value; + SymbolTableEntry& entry = iter->second; ASSERT(!entry.isNull()); if (!isValid(entry)) return false; diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp index 7028c3b95..8398ae77d 100644 --- a/Source/JavaScriptCore/runtime/JSArray.cpp +++ b/Source/JavaScriptCore/runtime/JSArray.cpp @@ -44,6 +44,8 @@ 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)}; @@ -243,8 +245,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 for count slots uncleared. -bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, unsigned count) +// This method makes room in the vector, but leaves the new space uncleared. +bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, unsigned count) { ArrayStorage* storage = ensureArrayStorage(globalData); Butterfly* butterfly = storage->butterfly(); @@ -252,7 +254,7 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, un unsigned propertySize = structure()->outOfLineSize(); // If not, we should have handled this on the fast path. - ASSERT(!addToFront || count > storage->m_indexBias); + ASSERT(count > storage->m_indexBias); // Step 1: // Gather 4 key metrics: @@ -276,7 +278,7 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, un 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 one. + // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing on. void* newAllocBase = 0; unsigned newStorageCapacity; @@ -295,48 +297,36 @@ bool JSArray::unshiftCountSlowCase(JSGlobalData& globalData, bool addToFront, un // 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 (!addToFront) - postCapacity = max(newStorageCapacity - requiredVectorLength, count); - else if (length < storage->vectorLength()) { + 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); - - 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(); - } - + + 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)); + newButterfly->arrayStorage()->setVectorLength(newVectorLength); newButterfly->arrayStorage()->m_indexBias = newIndexBias; - + m_butterfly = newButterfly; return true; } -bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, bool throwException, ArrayStorage* storage) +bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException) { + 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'. @@ -353,7 +343,7 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo 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->key); + unsigned index = static_cast<unsigned>(it->first); if (index < length && index >= newLength) keys.append(index); } @@ -368,7 +358,7 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo unsigned index = keys[--i]; SparseArrayValueMap::iterator it = map->find(index); ASSERT(it != map->notFound()); - if (it->value.attributes & DontDelete) { + if (it->second.attributes & DontDelete) { storage->setLength(index + 1); return reject(exec, throwException, "Unable to delete property."); } @@ -399,71 +389,12 @@ bool JSArray::setLengthWithArrayStorage(ExecState* exec, unsigned newLength, boo 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(); @@ -487,28 +418,26 @@ JSValue JSArray::pop(ExecState* exec) return element; } } - break; + + // 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; } default: - CRASH(); + ASSERT_NOT_REACHED(); 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. @@ -522,26 +451,6 @@ 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)) { @@ -583,139 +492,59 @@ void JSArray::push(ExecState* exec, JSValue value) } } -bool JSArray::shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage* storage) +bool JSArray::shiftCount(ExecState* exec, unsigned count) { + 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() || shouldUseSlowPut(structure()->indexingType())) + if (oldLength != storage->m_numValuesInVector || inSparseIndexingMode()) return false; if (!oldLength) return true; - unsigned length = oldLength - count; - storage->m_numValuesInVector -= count; - storage->setLength(length); + storage->setLength(oldLength - count); 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) { - if (startIndex < usedVectorLength - (startIndex + count)) { - if (startIndex) { - memmove( - storage->m_vector + count, - storage->m_vector, - sizeof(JSValue) * startIndex); - } + count = min(vectorLength, (unsigned)count); + + vectorLength -= count; + storage->setVectorLength(vectorLength); + + if (vectorLength) { 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::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, unsigned count, ArrayStorage* storage) +bool JSArray::unshiftCount(ExecState* exec, unsigned count) { + 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() || shouldUseSlowPut(structure()->indexingType())) + if (length != storage->m_numValuesInVector || storage->inSparseMode()) return false; - bool moveFront = !startIndex || startIndex < length / 2; - - unsigned vectorLength = storage->vectorLength(); - - if (moveFront && storage->m_indexBias >= count) { + if (storage->m_indexBias >= count) { m_butterfly = storage->butterfly()->unshift(structure(), count); storage = m_butterfly->arrayStorage(); storage->m_indexBias -= count; - storage->setVectorLength(vectorLength + count); - } else if (!moveFront && vectorLength - length >= count) - storage = storage->butterfly()->arrayStorage(); - else if (unshiftCountSlowCase(exec->globalData(), moveFront, count)) + storage->setVectorLength(storage->vectorLength() + count); + } else if (unshiftCountSlowCase(exec->globalData(), count)) storage = arrayStorage(); else { throwOutOfMemoryError(exec); @@ -723,61 +552,11 @@ bool JSArray::unshiftCountWithArrayStorage(ExecState* exec, unsigned startIndex, } 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 + startIndex].clear(); + vector[i].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(); @@ -792,45 +571,6 @@ 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()); @@ -839,98 +579,41 @@ void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType cal case ArrayClass: return; - case ArrayWithContiguous: - sortNumericVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); - return; - - case ArrayWithArrayStorage: - sortNumericVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData); - return; - - default: - CRASH(); - return; - } -} - -template<IndexingType indexingType> -void JSArray::sortCompactedVector(ExecState* exec, WriteBarrier<Unknown>* begin, unsigned relevantLength) -{ - 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(); - Vector<ValueStringPair> values(relevantLength); - if (!values.begin()) { - throwOutOfMemoryError(exec); - return; - } + if (storage->m_sparseMap.get()) { + throwOutOfMemoryError(exec); + return; + } - Heap::heap(this)->pushTempSortVector(&values); + if (!lengthNotIncludingUndefined) + return; - 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(); - } + 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; + } + } - // FIXME: The following loop continues to call toString on subsequent values even after - // a toString call raises an exception. + if (!allValuesAreNumbers) + return sort(exec, compareFunction, callType, callData); - for (size_t i = 0; i < relevantLength; i++) - values[i].second = values[i].first.toWTFStringInline(exec); + // 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); - 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). - -#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. - 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; - - case ArrayWithArrayStorage: - if (arrayStorage()->vectorLength() < relevantLength) { - increaseVectorLength(exec->globalData(), relevantLength); - begin = arrayStorage()->m_vector; - } - if (arrayStorage()->length() < relevantLength) - arrayStorage()->setLength(relevantLength); - break; - default: - CRASH(); + ASSERT_NOT_REACHED(); } - - 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) @@ -941,27 +624,78 @@ void JSArray::sort(ExecState* exec) case ArrayClass: return; - case ArrayWithContiguous: { - unsigned lengthNotIncludingUndefined; - unsigned newRelevantLength; - compactForSorting<ArrayWithContiguous>( - lengthNotIncludingUndefined, newRelevantLength); - - sortCompactedVector<ArrayWithContiguous>( - exec, m_butterfly->contiguous(), lengthNotIncludingUndefined); - return; - } - case ArrayWithArrayStorage: { - unsigned lengthNotIncludingUndefined; - unsigned newRelevantLength; - compactForSorting<ArrayWithArrayStorage>( - lengthNotIncludingUndefined, newRelevantLength); + unsigned lengthNotIncludingUndefined = compactForSorting(exec->globalData()); ArrayStorage* storage = m_butterfly->arrayStorage(); - ASSERT(!storage->m_sparseMap); + 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; + } + + 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(); + } + + // 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); + + 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). + +#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. + 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. + if (storage->vectorLength() < lengthNotIncludingUndefined) { + increaseVectorLength(exec->globalData(), lengthNotIncludingUndefined); + storage = m_butterfly->arrayStorage(); + } + if (storage->length() < lengthNotIncludingUndefined) + storage->setLength(lengthNotIncludingUndefined); + + JSGlobalData& globalData = exec->globalData(); + for (size_t i = 0; i < lengthNotIncludingUndefined; i++) + storage->m_vector[i].set(globalData, this, values[i].first); + + Heap::heap(this)->popTempSortVector(&values); - sortCompactedVector<ArrayWithArrayStorage>( - exec, storage->m_vector, lengthNotIncludingUndefined); return; } @@ -1047,116 +781,122 @@ struct AVLTreeAbstractorForArrayCompare { static handle null() { return 0x7FFFFFFF; } }; -template<IndexingType indexingType> -void JSArray::sortVector(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) +void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData) { ASSERT(!inSparseIndexingMode()); - ASSERT(indexingType == structure()->indexingType()); - // 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(m_butterfly->publicLength() <= static_cast<unsigned>(std::numeric_limits<int>::max())); - if (m_butterfly->publicLength() > static_cast<unsigned>(std::numeric_limits<int>::max())) + switch (structure()->indexingType()) { + case ArrayClass: return; - unsigned usedVectorLength = relevantLength<indexingType>(); - unsigned nodeCount = usedVectorLength; + case ArrayWithArrayStorage: { + ArrayStorage* storage = m_butterfly->arrayStorage(); - if (!nodeCount) - return; + // FIXME: This ignores exceptions raised in the compare function or in toNumber. - 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(storage->length() <= static_cast<unsigned>(std::numeric_limits<int>::max())); + if (storage->length() > 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 = min(storage->length(), storage->vectorLength()); + unsigned nodeCount = usedVectorLength + (storage->m_sparseMap ? storage->m_sparseMap->size() : 0); - 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. - - 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; + 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); + + if (callType == CallTypeJS) + tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2)); + + if (!tree.abstractor().m_nodes.begin()) { + throwOutOfMemoryError(exec); + 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. + + 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) { + 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 (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(); tree.insert(numDefined); ++numDefined; } + + deallocateSparseIndexMap(); } - } - unsigned newUsedVectorLength = numDefined + numUndefined; + ASSERT(tree.abstractor().m_nodes.size() >= numDefined); - // The array size may have changed. Figure out the new bounds. - unsigned newestUsedVectorLength = relevantLength<indexingType>(); + // FIXME: If the compare function changed the length of the array, the following might be + // modifying the vector incorrectly. - unsigned elementsToExtractThreshold = min(min(newestUsedVectorLength, numDefined), static_cast<unsigned>(tree.abstractor().m_nodes.size())); - unsigned undefinedElementsThreshold = min(newestUsedVectorLength, newUsedVectorLength); - unsigned clearElementsThreshold = min(newestUsedVectorLength, usedVectorLength); + // 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; + } - // 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; + // Put undefined values back in. + for (unsigned i = numDefined; i < newUsedVectorLength; ++i) + storage->m_vector[i].setUndefined(); + + // 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; - case ArrayWithContiguous: - sortVector<ArrayWithContiguous>(exec, compareFunction, callType, callData); - return; - - case ArrayWithArrayStorage: - sortVector<ArrayWithArrayStorage>(exec, compareFunction, callType, callData); return; + } default: ASSERT_NOT_REACHED(); @@ -1165,127 +905,129 @@ 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(); - vector = storage->m_vector; - vectorEnd = min(storage->length(), storage->vectorLength()); - break; + 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; } default: - CRASH(); - vector = 0; - vectorEnd = 0; - break; - } - - for (; i < vectorEnd; ++i) { - WriteBarrier<Unknown>& v = vector[i]; - if (!v) - break; - args.append(v.get()); + ASSERT_NOT_REACHED(); } - - 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(); - vector = storage->m_vector; - vectorEnd = min(length, storage->vectorLength()); - break; + 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; } default: - CRASH(); - vector = 0; - vectorEnd = 0; - break; - } - - for (; i < vectorEnd; ++i) { - WriteBarrier<Unknown>& v = vector[i]; - if (!v) - break; - callFrame->setArgument(i, v.get()); + ASSERT_NOT_REACHED(); } - - for (; i < length; ++i) - callFrame->setArgument(i, get(exec, i)); } -template<IndexingType indexingType> -void JSArray::compactForSorting(unsigned& numDefined, unsigned& newRelevantLength) +unsigned JSArray::compactForSorting(JSGlobalData& globalData) { ASSERT(!inSparseIndexingMode()); - ASSERT(indexingType == structure()->indexingType()); - unsigned myRelevantLength = relevantLength<indexingType>(); - - numDefined = 0; - unsigned numUndefined = 0; + switch (structure()->indexingType()) { + case ArrayClass: + return 0; + + case ArrayWithArrayStorage: { + ArrayStorage* storage = m_butterfly->arrayStorage(); - for (; numDefined < myRelevantLength; ++numDefined) { - JSValue v = indexingData<indexingType>()[numDefined].get(); - if (!v || v.isUndefined()) - break; - } + unsigned usedVectorLength = min(storage->length(), storage->vectorLength()); - 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); + unsigned numDefined = 0; + unsigned numUndefined = 0; + + for (; numDefined < usedVectorLength; ++numDefined) { + JSValue v = storage->m_vector[numDefined].get(); + if (!v || v.isUndefined()) + break; } + + 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); + } + } + + 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 < 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; } - 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; + default: + ASSERT_NOT_REACHED(); + return 0; + } } + } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h index d4622aacc..6e539c9db 100644 --- a/Source/JavaScriptCore/runtime/JSArray.h +++ b/Source/JavaScriptCore/runtime/JSArray.h @@ -71,60 +71,8 @@ namespace JSC { void push(ExecState*, JSValue); JSValue pop(ExecState*); - 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; - } - } + bool shiftCount(ExecState*, unsigned count); + bool unshiftCount(ExecState*, unsigned count); void fillArgList(ExecState*, MarkedArgumentBuffer&); void copyToArguments(ExecState*, CallFrame*, uint32_t length); @@ -146,44 +94,18 @@ namespace JSC { { ArrayStorage* storage = arrayStorageOrNull(); if (!storage) - return true; + return false; SparseArrayValueMap* map = storage->m_sparseMap.get(); return !map || !map->lengthIsReadOnly(); } - - bool shiftCountWithAnyIndexingType(ExecState*, unsigned startIndex, unsigned count); - bool shiftCountWithArrayStorage(unsigned startIndex, unsigned count, ArrayStorage*); - - 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 setLengthWithArrayStorage(ExecState*, unsigned newLength, bool throwException, ArrayStorage*); void setLengthWritable(ExecState*, bool writable); + + bool unshiftCountSlowCase(JSGlobalData&, unsigned count); - template<IndexingType indexingType> - void compactForSorting(unsigned& numDefined, unsigned& newRelevantLength); + unsigned compactForSorting(JSGlobalData&); }; - 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( @@ -199,16 +121,7 @@ namespace JSC { inline JSArray* JSArray::create(JSGlobalData& globalData, Structure* structure, unsigned 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); - } + Butterfly* butterfly = createArrayButterfly(globalData, initialLength); JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure, butterfly); array->finishCreation(globalData); return array; @@ -220,26 +133,15 @@ namespace JSC { if (vectorLength > MAX_STORAGE_VECTOR_LENGTH) return 0; - 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; - } + 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; 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 d8f611477..3815c144e 100644 --- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp @@ -31,6 +31,7 @@ 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 f6f4d716d..739247fb2 100644 --- a/Source/JavaScriptCore/runtime/JSCell.cpp +++ b/Source/JavaScriptCore/runtime/JSCell.cpp @@ -38,10 +38,6 @@ 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 a39af1283..cf6f4ec45 100644 --- a/Source/JavaScriptCore/runtime/JSCell.h +++ b/Source/JavaScriptCore/runtime/JSCell.h @@ -31,15 +31,12 @@ #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; @@ -51,6 +48,19 @@ namespace JSC { IncludeDontEnumProperties }; + enum TypedArrayType { + TypedArrayNone, + TypedArrayInt8, + TypedArrayInt16, + TypedArrayInt32, + TypedArrayUint8, + TypedArrayUint8Clamped, + TypedArrayUint16, + TypedArrayUint32, + TypedArrayFloat32, + TypedArrayFloat64 + }; + class JSCell { friend class JSValue; friend class MarkedBlock; @@ -60,9 +70,6 @@ namespace JSC { public: static const unsigned StructureFlags = 0; - static const bool needsDestruction = false; - static const bool hasImmortalStructure = false; - enum CreatingEarlyCellTag { CreatingEarlyCell }; JSCell(CreatingEarlyCellTag); @@ -101,7 +108,6 @@ 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; @@ -303,29 +309,46 @@ 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, 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 (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)); + 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))); + } result->clearStructure(); return result; } template<typename T> - void* allocateCell(Heap& heap) + void* allocateCell(Heap& heap, size_t size) { - return allocateCell<T>(heap, sizeof(T)); + 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; } inline bool isZapped(const JSCell* cell) @@ -339,7 +362,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 deleted file mode 100644 index b8479be62..000000000 --- a/Source/JavaScriptCore/runtime/JSDestructibleObject.h +++ /dev/null @@ -1,43 +0,0 @@ -#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 891a23930..4afe63216 100644 --- a/Source/JavaScriptCore/runtime/JSFunction.cpp +++ b/Source/JavaScriptCore/runtime/JSFunction.cpp @@ -48,6 +48,7 @@ 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 bc3d00067..e30a7913d 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp @@ -231,9 +231,7 @@ 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 6cc0aad8d..603f9f82a 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalData.h +++ b/Source/JavaScriptCore/runtime/JSGlobalData.h @@ -44,7 +44,6 @@ #include "Strong.h" #include "Terminator.h" #include "TimeoutChecker.h" -#include "TypedArrayDescriptor.h" #include "WeakRandom.h" #include <wtf/BumpPointerAllocator.h> #include <wtf/Forward.h> @@ -109,6 +108,24 @@ 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; @@ -412,35 +429,6 @@ 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 9eb266135..b0a0e8122 100644 --- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -100,6 +100,8 @@ 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; @@ -226,11 +228,10 @@ 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<JSDestructibleObject>::createStructure(exec->globalData(), this, m_objectPrototype.get())); + m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSNonFinalObject>::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(), ArrayWithContiguous)); - m_arrayStructureWithArrayStorage.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(), 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())); @@ -317,9 +318,6 @@ 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())); @@ -356,8 +354,7 @@ ObjectsWithBrokenIndexingFinder::ObjectsWithBrokenIndexingFinder( inline bool hasBrokenIndexing(JSObject* object) { // This will change if we have more indexing types. - IndexingType type = object->structure()->indexingType(); - return hasContiguous(type) || hasFastArrayStorage(type); + return !!(object->structure()->indexingType() & HasArrayStorage); } void ObjectsWithBrokenIndexingFinder::operator()(JSCell* cell) @@ -410,7 +407,6 @@ 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. @@ -486,7 +482,6 @@ 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); @@ -507,14 +502,9 @@ 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 + JSStack::CallFrameHeaderSize); + return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize); } void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h index 2994aa64b..ad56783cc 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,6 +77,7 @@ namespace JSC { class JSGlobalObject : public JSSegmentedVariableObject { private: + typedef JSSegmentedVariableObject Base; typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; struct JSGlobalObjectRareData { @@ -91,7 +92,7 @@ namespace JSC { protected: - Register m_globalCallFrame[JSStack::CallFrameHeaderSize]; + Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize]; WriteBarrier<JSObject> m_globalThis; WriteBarrier<JSObject> m_methodCallDummy; @@ -126,7 +127,6 @@ 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,8 +146,6 @@ 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; @@ -170,16 +168,14 @@ 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; } @@ -196,7 +192,7 @@ namespace JSC { init(this); } - void finishCreation(JSGlobalData& globalData, JSObject* thisValue) + void finishCreation(JSGlobalData& globalData, JSGlobalThis* thisValue) { Base::finishCreation(globalData); structure()->setGlobalObject(globalData, this); @@ -207,8 +203,6 @@ 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&); @@ -268,9 +262,7 @@ 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(); } @@ -290,12 +282,6 @@ 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(); } @@ -380,16 +366,13 @@ 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*); @@ -482,7 +465,7 @@ namespace JSC { inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0) { - return JSArray::create(exec->globalData(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureWithArrayStorage() : globalObject->arrayStructure(), initialLength); + return JSArray::create(exec->globalData(), 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 new file mode 100644 index 000000000..a3f2e7785 --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSGlobalThis.cpp @@ -0,0 +1,58 @@ +/* + * 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 new file mode 100644 index 000000000..0ca99414a --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSGlobalThis.h @@ -0,0 +1,76 @@ +/* + * 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 85dbdfedb..9f02b69b8 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 JSStack). -// Whenever a thread calls into JSC it starts using the JSStack from the +// 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 // previous 'high water mark' - the maximum point the stack has ever grown to -// (returned by JSStack::end()). So if a first thread calls out to a +// (returned by RegisterFile::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 -// JSStack. As such, a problem may occur should the first thread's +// RegisterFile. 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 335631fd0..5dc665c44 100644 --- a/Source/JavaScriptCore/runtime/JSNameScope.cpp +++ b/Source/JavaScriptCore/runtime/JSNameScope.cpp @@ -30,6 +30,8 @@ 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 53592ba2b..f75fa1f96 100644 --- a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -34,6 +34,7 @@ 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 fd939934e..fe894afba 100644 --- a/Source/JavaScriptCore/runtime/JSONObject.cpp +++ b/Source/JavaScriptCore/runtime/JSONObject.cpp @@ -41,6 +41,7 @@ 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 6a3fb84e4..bf38f6876 100644 --- a/Source/JavaScriptCore/runtime/JSObject.cpp +++ b/Source/JavaScriptCore/runtime/JSObject.cpp @@ -26,14 +26,13 @@ #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" @@ -64,6 +63,10 @@ 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); @@ -92,7 +95,7 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class } } -ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butterfly, size_t storageSize) +ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor& visitor, Butterfly* butterfly, size_t storageSize) { ASSERT(butterfly); @@ -109,93 +112,61 @@ ALWAYS_INLINE void JSObject::copyButterfly(CopyVisitor& visitor, Butterfly* butt preCapacity = 0; indexingPayloadSizeInBytes = 0; } - size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - if (visitor.checkIfShouldCopy(butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) { + size_t capacityInBytes = Butterfly::totalSize( + preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); + if (visitor.checkIfShouldCopyAndPinOtherwise( + butterfly->base(preCapacity, propertyCapacity), capacityInBytes)) { Butterfly* newButterfly = Butterfly::createUninitializedDuringCollection(visitor, preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes); - // Copy the properties. + // Mark and copy the properties. PropertyStorage currentTarget = newButterfly->propertyStorage(); PropertyStorage currentSource = butterfly->propertyStorage(); - for (size_t count = storageSize; count--;) - (--currentTarget)->setWithoutWriteBarrier((--currentSource)->get()); + for (size_t count = storageSize; count--;) { + JSValue value = (--currentSource)->get(); + ASSERT(value); + visitor.appendUnbarrieredValue(&value); + (--currentTarget)->setWithoutWriteBarrier(value); + } if (UNLIKELY(hasIndexingHeader)) { *newButterfly->indexingHeader() = *butterfly->indexingHeader(); - // Copy the array if appropriate. - - WriteBarrier<Unknown>* currentTarget; - WriteBarrier<Unknown>* currentSource; - size_t count; - + // Mark and copy the array if appropriate. 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()); - currentTarget = newButterfly->arrayStorage()->m_vector; - currentSource = butterfly->arrayStorage()->m_vector; - count = newButterfly->arrayStorage()->vectorLength(); + 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); 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 { - 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; + // 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; + } } } @@ -212,23 +183,13 @@ void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor) Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownNonFinalObject()); #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); @@ -242,9 +203,9 @@ void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) Butterfly* butterfly = thisObject->butterfly(); if (butterfly) - thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSize()); + thisObject->visitButterfly(visitor, butterfly, thisObject->structure()->outOfLineSizeForKnownFinalObject()); - size_t storageSize = thisObject->structure()->inlineSize(); + size_t storageSize = thisObject->structure()->inlineSizeForKnownFinalObject(); visitor.appendValues(thisObject->inlineStorage(), storageSize); #if !ASSERT_DISABLED @@ -274,20 +235,6 @@ 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()) @@ -302,7 +249,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->value.get(slot); + it->second.get(slot); return true; } } @@ -405,16 +352,6 @@ 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(); @@ -489,7 +426,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->value.set(globalData, this, value); + map->add(this, i).iterator->second.set(globalData, this, value); } Butterfly* newButterfly = storage->butterfly()->resizeArray(globalData, structure(), 0, ArrayStorage::sizeFor(0)); @@ -507,11 +444,6 @@ 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; @@ -534,24 +466,6 @@ 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(); @@ -567,7 +481,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()->suggestedArrayStorageTransition()); + Structure* newStructure = Structure::nonPropertyTransition(globalData, structure(), structure()->suggestedIndexingTransition()); setButterfly(globalData, newButterfly, newStructure); return result; } @@ -577,107 +491,9 @@ 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()); @@ -697,11 +513,6 @@ 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); @@ -745,7 +556,8 @@ void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype) if (shouldUseSlowPut(structure()->indexingType())) return; - switchToSlowPutArrayStorage(globalData); + newStructure = Structure::nonPropertyTransition(globalData, newStructure, SwitchToSlowPutArrayStorage); + setStructure(globalData, newStructure); } bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype) @@ -879,14 +691,6 @@ 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(); @@ -899,7 +703,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->value.attributes & DontDelete) + if (it->second.attributes & DontDelete) return false; map->remove(it); } @@ -1060,17 +864,6 @@ 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(); @@ -1086,8 +879,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->value.attributes & DontEnum)) - keys.append(static_cast<unsigned>(it->key)); + if (mode == IncludeDontEnumProperties || !(it->second.attributes & DontEnum)) + keys.append(static_cast<unsigned>(it->first)); } std::sort(keys.begin(), keys.end()); @@ -1296,6 +1089,9 @@ 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 @@ -1305,19 +1101,16 @@ 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->value; + SparseArrayEntry* entryInMap = &result.iterator->second; // 2. Let extensible be the value of the [[Extensible]] internal property of O. // 3. If current is undefined and extensible is false, then Reject. @@ -1437,8 +1230,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->value.attributes & (Accessor | ReadOnly))) { - iter->value.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow); + if (iter != storage->m_sparseMap->notFound() && (iter->second.attributes & (Accessor | ReadOnly))) { + iter->second.put(exec, thisValue, storage->m_sparseMap.get(), value, shouldThrow); return true; } } @@ -1460,35 +1253,6 @@ 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(); @@ -1551,7 +1315,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->key].set(globalData, this, it->value.getNonSparseMode()); + vector[it->first].set(globalData, this, it->second.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. @@ -1571,29 +1335,17 @@ 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)); - break; - } - if (i >= MIN_SPARSE_ARRAY_INDEX) { - putByIndexBeyondVectorLengthWithArrayStorage( - exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0)); + putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, ensureArrayStorageExistsAndEnterDictionaryIndexingMode(globalData)); break; } - 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++; + if (!isDenseEnoughForVector(i, 0) || i >= MAX_STORAGE_VECTOR_LENGTH) { + putByIndexBeyondVectorLengthWithArrayStorage(exec, i, value, shouldThrow, createArrayStorage(globalData, 0, 0)); break; } - - createInitialContiguous(globalData, i + 1)[i].set(globalData, this, value); - break; - } - case ALL_CONTIGUOUS_INDEXING_TYPES: { - putByIndexBeyondVectorLengthContiguousWithoutAttributes(exec, i, value); + ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(globalData, this, value); + storage->m_numValuesInVector = 1; break; } @@ -1619,10 +1371,8 @@ 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); @@ -1681,7 +1431,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->key].set(globalData, this, it->value.getNonSparseMode()); + vector[it->first].set(globalData, this, it->second.getNonSparseMode()); deallocateSparseIndexMap(); // Store the new property into the vector. @@ -1704,32 +1454,14 @@ 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 (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; - } + 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)); - 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); + ArrayStorage* storage = createArrayStorage(globalData, i + 1, getNewVectorLength(0, 0, i + 1)); + storage->m_vector[i].set(globalData, this, value); + storage->m_numValuesInVector = 1; return true; } @@ -1754,7 +1486,12 @@ ALWAYS_INLINE unsigned JSObject::getNewVectorLength(unsigned currentVectorLength else if (!currentVectorLength) increasedLength = std::max(desiredLength, lastArraySize); else { - increasedLength = timesThreePlusOneDividedByTwo(desiredLength); + // 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); } ASSERT(increasedLength >= desiredLength); @@ -1774,10 +1511,9 @@ 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->vectorLength(); - length = m_butterfly->publicLength(); + vectorLength = m_butterfly->arrayStorage()->vectorLength(); + length = m_butterfly->arrayStorage()->length(); break; default: CRASH(); @@ -1786,16 +1522,6 @@ 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 @@ -1804,10 +1530,6 @@ 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(); @@ -1839,22 +1561,6 @@ 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); @@ -1883,17 +1589,6 @@ 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()) @@ -1909,7 +1604,7 @@ bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, Prope SparseArrayValueMap::iterator it = map->find(i); if (it == map->notFound()) return false; - it->value.get(descriptor); + it->second.get(descriptor); return true; } return false; diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h index 9204099cb..4b9cff5ad 100644 --- a/Source/JavaScriptCore/runtime/JSObject.h +++ b/Source/JavaScriptCore/runtime/JSObject.h @@ -109,13 +109,7 @@ 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*); @@ -154,9 +148,8 @@ 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->publicLength(); + return m_butterfly->arrayStorage()->length(); default: ASSERT_NOT_REACHED(); return 0; @@ -168,9 +161,8 @@ 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->vectorLength(); + return m_butterfly->arrayStorage()->vectorLength(); default: ASSERT_NOT_REACHED(); return 0; @@ -215,8 +207,6 @@ 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: @@ -228,8 +218,6 @@ 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: @@ -243,13 +231,12 @@ 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()) - return m_butterfly->arrayStorage()->m_vector[i].get(); + if (i < m_butterfly->arrayStorage()->vectorLength()) { + JSValue v = m_butterfly->arrayStorage()->m_vector[i].get(); + if (v) + return v; + } break; default: ASSERT_NOT_REACHED(); @@ -280,10 +267,9 @@ 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->vectorLength(); + return i < m_butterfly->arrayStorage()->vectorLength(); case NonArrayWithSlowPutArrayStorage: case ArrayWithSlowPutArrayStorage: return i < m_butterfly->arrayStorage()->vectorLength() @@ -299,9 +285,8 @@ 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->vectorLength(); + return i < m_butterfly->arrayStorage()->vectorLength(); default: ASSERT_NOT_REACHED(); return false; @@ -311,23 +296,15 @@ 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: { - ArrayStorage* storage = m_butterfly->arrayStorage(); - WriteBarrier<Unknown>& x = storage->m_vector[i]; - JSValue old = x.get(); - x.set(globalData, this, v); - if (!old) { + WriteBarrier<Unknown>& x = m_butterfly->arrayStorage()->m_vector[i]; + if (!x) { + ArrayStorage* storage = m_butterfly->arrayStorage(); ++storage->m_numValuesInVector; if (i >= storage->length()) storage->setLength(i + 1); } + x.set(globalData, this, v); break; } default: @@ -338,12 +315,6 @@ 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()); @@ -356,25 +327,10 @@ 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(); @@ -492,10 +448,10 @@ namespace JSC { { PropertyOffset result; size_t offsetInInlineStorage = location - inlineStorageUnsafe(); - if (offsetInInlineStorage < static_cast<size_t>(firstOutOfLineOffset)) + if (offsetInInlineStorage < static_cast<size_t>(inlineStorageCapacity)) result = offsetInInlineStorage; else - result = outOfLineStorage() - location + (firstOutOfLineOffset - 1); + result = outOfLineStorage() - location + (inlineStorageCapacity - 1); validateOffset(result, structure()->typeInfo().type()); return result; } @@ -525,7 +481,7 @@ namespace JSC { bool isNameScopeObject() const; bool isActivationObject() const; bool isErrorInstance() const; - bool isProxy() const; + bool isGlobalThis() const; void seal(JSGlobalData&); void freeze(JSGlobalData&); @@ -572,34 +528,23 @@ 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) { - if (LIKELY(hasArrayStorage(structure()->indexingType()))) + switch (structure()->indexingType()) { + case ALL_ARRAY_STORAGE_INDEXING_TYPES: return m_butterfly->arrayStorage(); - - return ensureArrayStorageSlow(globalData); - } - - Butterfly* ensureIndexedStorage(JSGlobalData& globalData) - { - if (LIKELY(hasIndexedProperties(structure()->indexingType()))) - return m_butterfly; - - return ensureIndexedStorageSlow(globalData); + + case ALL_BLANK_INDEXING_TYPES: + return createInitialArrayStorage(globalData); + + default: + ASSERT_NOT_REACHED(); + return 0; + } } static size_t offsetOfInlineStorage(); @@ -640,7 +585,6 @@ 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. @@ -665,16 +609,11 @@ 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); @@ -685,56 +624,6 @@ 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; @@ -769,12 +658,6 @@ 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; }; @@ -794,6 +677,11 @@ 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) @@ -821,43 +709,45 @@ 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, NonArray, INLINE_STORAGE_CAPACITY); + return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info); } 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(structure()->totalStorageCapacity() == structure()->inlineCapacity()); + 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(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(), - allocationSize(structure->inlineCapacity()) - ) - ) JSFinalObject(exec->globalData(), structure); + JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure); finalObject->finishCreation(exec->globalData()); return finalObject; } @@ -874,7 +764,7 @@ inline bool isJSFinalObject(JSValue value) inline size_t JSObject::offsetOfInlineStorage() { - return sizeof(JSObject); + return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage); } inline bool JSObject::isGlobalObject() const @@ -902,9 +792,9 @@ inline bool JSObject::isErrorInstance() const return structure()->typeInfo().type() == ErrorInstanceType; } -inline bool JSObject::isProxy() const +inline bool JSObject::isGlobalThis() const { - return structure()->typeInfo().type() == ProxyType; + return structure()->typeInfo().type() == GlobalThisType; } inline void JSObject::setButterfly(JSGlobalData& globalData, Butterfly* butterfly, Structure* structure) @@ -966,14 +856,14 @@ inline JSValue JSObject::prototype() const return structure()->storedPrototype(); } -inline const MethodTable* JSCell::methodTable() const +inline bool JSCell::inherits(const ClassInfo* info) const { - return &classInfo()->methodTable; + return classInfo()->isSubClassOf(info); } -inline bool JSCell::inherits(const ClassInfo* info) const +inline const MethodTable* JSCell::methodTable() const { - return classInfo()->isSubClassOf(info); + return &classInfo()->methodTable; } // this method is here to be after the inline declaration of JSCell::inherits @@ -1367,8 +1257,6 @@ 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 225401fbd..897ceff8c 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -33,6 +33,8 @@ 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 e59a5c6a4..057ffe293 100644 --- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -48,8 +48,6 @@ 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) @@ -59,6 +57,14 @@ 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; } @@ -82,7 +88,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_cachedStructureInlineCapacity = object->structure()->inlineCapacity(); + m_offsetBase = object->structure()->firstValidOffset(); } private: @@ -94,7 +100,7 @@ namespace JSC { WriteBarrier<StructureChain> m_cachedPrototypeChain; uint32_t m_numCacheableSlots; uint32_t m_jsStringsSize; - unsigned m_cachedStructureInlineCapacity; + PropertyOffset m_offsetBase; OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings; }; diff --git a/Source/JavaScriptCore/runtime/JSProxy.cpp b/Source/JavaScriptCore/runtime/JSProxy.cpp deleted file mode 100644 index 7108dcfa0..000000000 --- a/Source/JavaScriptCore/runtime/JSProxy.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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 deleted file mode 100644 index 144085a79..000000000 --- a/Source/JavaScriptCore/runtime/JSProxy.h +++ /dev/null @@ -1,95 +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 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 8fd49b861..b22211970 100644 --- a/Source/JavaScriptCore/runtime/JSScope.cpp +++ b/Source/JavaScriptCore/runtime/JSScope.cpp @@ -33,7 +33,7 @@ namespace JSC { -ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSScope); +ASSERT_CLASS_FITS_IN_CELL(JSScope); void JSScope::visitChildren(JSCell* cell, SlotVisitor& visitor) { diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h index 245c48a51..1500636f2 100644 --- a/Source/JavaScriptCore/runtime/JSString.h +++ b/Source/JavaScriptCore/runtime/JSString.h @@ -71,8 +71,6 @@ 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 7dcde4700..765e1d3d4 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->value.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) - propertyNames.add(Identifier(exec, it->key.get())); + if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties)) + propertyNames.add(Identifier(exec, it->first.get())); } JSObject::getOwnNonIndexPropertyNames(thisObject, exec, propertyNames, mode); diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h index 913679f80..b4d313c19 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->value; + SymbolTableEntry::Fast entry = iter->second; 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->value; + SymbolTableEntry::Fast entry = iter->second; 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->value; + SymbolTableEntry::Fast entry = iter->second; 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->value.getFast(wasFat); + SymbolTableEntry::Fast fastEntry = iter->second.getFast(wasFat); ASSERT(!fastEntry.isNull()); if (fastEntry.isReadOnly()) { if (shouldThrow) @@ -134,7 +134,7 @@ inline bool symbolTablePut( return true; } if (UNLIKELY(wasFat)) - iter->value.notifyWrite(); + iter->second.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->value; + SymbolTableEntry& entry = iter->second; ASSERT(!entry.isNull()); entry.notifyWrite(); entry.setAttributes(attributes); diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h index 03f4a7790..b8ab330f5 100644 --- a/Source/JavaScriptCore/runtime/JSType.h +++ b/Source/JavaScriptCore/runtime/JSType.h @@ -48,7 +48,7 @@ enum JSType { NameInstanceType, NumberObjectType, ErrorInstanceType, - ProxyType, + GlobalThisType, WithScopeType, NameScopeObjectType, diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp index 651e50cec..ac00fad3d 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 = 256; + static const size_t size = 128; static char description[size]; if (!*this) @@ -213,12 +213,9 @@ 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 (%p: %s, %s)", - asCell(), asCell()->structure(), asCell()->structure()->classInfo()->className, - indexingTypeToString(asCell()->structure()->indexingTypeIncludingHistory())); - } else if (isTrue()) + } else if (isCell()) + snprintf(description, size, "Cell: %p", asCell()); + 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 25961dc09..55952820e 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 stack. + WriteBarrierBase<Unknown>* m_registers; // "r" in the register file. }; } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/JSWithScope.cpp b/Source/JavaScriptCore/runtime/JSWithScope.cpp index 7d74e63c3..0c4b6e2cc 100644 --- a/Source/JavaScriptCore/runtime/JSWithScope.cpp +++ b/Source/JavaScriptCore/runtime/JSWithScope.cpp @@ -28,6 +28,8 @@ 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 ff80c1e20..4a46c2c69 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp @@ -24,6 +24,7 @@ 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 72bc1874c..65b4bdb7f 100644 --- a/Source/JavaScriptCore/runtime/JSWrapperObject.h +++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h @@ -22,15 +22,15 @@ #ifndef JSWrapperObject_h #define JSWrapperObject_h -#include "JSDestructibleObject.h" +#include "JSObject.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 JSDestructibleObject { + class JSWrapperObject : public JSNonFinalObject { public: - typedef JSDestructibleObject Base; + typedef JSNonFinalObject Base; JSValue internalValue() const; void setInternalValue(JSGlobalData&, JSValue); @@ -42,7 +42,7 @@ namespace JSC { protected: explicit JSWrapperObject(JSGlobalData&, Structure*); - static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags; + static const unsigned StructureFlags = OverridesVisitChildren | JSNonFinalObject::StructureFlags; static void visitChildren(JSCell*, SlotVisitor&); @@ -51,7 +51,7 @@ namespace JSC { }; inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, Structure* structure) - : JSDestructibleObject(globalData, structure) + : JSNonFinalObject(globalData, structure) { } diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp index 2f4df375a..2a550a38b 100644 --- a/Source/JavaScriptCore/runtime/MathObject.cpp +++ b/Source/JavaScriptCore/runtime/MathObject.cpp @@ -32,7 +32,7 @@ namespace JSC { -ASSERT_HAS_TRIVIAL_DESTRUCTOR(MathObject); +ASSERT_CLASS_FITS_IN_CELL(MathObject); static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*); static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*); @@ -59,7 +59,9 @@ static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*); namespace JSC { -const ClassInfo MathObject::s_info = { "Math", &Base::s_info, 0, ExecState::mathTable, CREATE_METHOD_TABLE(MathObject) }; +ASSERT_HAS_TRIVIAL_DESTRUCTOR(MathObject); + +const ClassInfo MathObject::s_info = { "Math", &JSNonFinalObject::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 0f8efc604..b35e9fbda 100644 --- a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp +++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp @@ -28,7 +28,7 @@ #include "ExecutableAllocator.h" #include "JSGlobalData.h" -#include "JSStack.h" +#include "RegisterFile.h" namespace JSC { @@ -36,7 +36,7 @@ GlobalMemoryStatistics globalMemoryStatistics() { GlobalMemoryStatistics stats; - stats.stackBytes = JSStack::committedByteCount(); + stats.stackBytes = RegisterFile::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 b5facc7cf..63f1f647a 100644 --- a/Source/JavaScriptCore/runtime/NameConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NameConstructor.cpp @@ -31,6 +31,7 @@ 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 129e7c407..c5931e8ef 100644 --- a/Source/JavaScriptCore/runtime/NameInstance.h +++ b/Source/JavaScriptCore/runtime/NameInstance.h @@ -26,14 +26,14 @@ #ifndef NameInstance_h #define NameInstance_h -#include "JSDestructibleObject.h" +#include "JSObject.h" #include "PrivateName.h" namespace JSC { -class NameInstance : public JSDestructibleObject { +class NameInstance : public JSNonFinalObject { public: - typedef JSDestructibleObject Base; + typedef JSNonFinalObject Base; static const ClassInfo s_info; diff --git a/Source/JavaScriptCore/runtime/NamePrototype.cpp b/Source/JavaScriptCore/runtime/NamePrototype.cpp index f14e58522..3e52856b6 100644 --- a/Source/JavaScriptCore/runtime/NamePrototype.cpp +++ b/Source/JavaScriptCore/runtime/NamePrototype.cpp @@ -30,6 +30,8 @@ namespace JSC { +ASSERT_CLASS_FITS_IN_CELL(NamePrototype); + static EncodedJSValue JSC_HOST_CALL privateNameProtoFuncToString(ExecState*); } @@ -46,6 +48,8 @@ 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 1f1730805..a4ba240fd 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -28,6 +28,7 @@ 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 296a86a22..7fee213fa 100644 --- a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -27,6 +27,8 @@ 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 daa643da7..03d616073 100644 --- a/Source/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp @@ -28,6 +28,8 @@ 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 b87753d4d..1fea25464 100644 --- a/Source/JavaScriptCore/runtime/NumberObject.cpp +++ b/Source/JavaScriptCore/runtime/NumberObject.cpp @@ -27,6 +27,7 @@ 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 23c9dbfdd..4a10efd6d 100644 --- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp @@ -68,6 +68,7 @@ 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 7df047d28..8614b9c45 100644 --- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -35,6 +35,8 @@ 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 e94edfadf..b1a5b9fb3 100644 --- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -63,6 +63,8 @@ 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 386eb4fcf..ed0720b54 100644 --- a/Source/JavaScriptCore/runtime/Options.cpp +++ b/Source/JavaScriptCore/runtime/Options.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "Options.h" -#include "HeapStatistics.h" #include <algorithm> #include <limits> #include <stdio.h> @@ -42,6 +41,10 @@ #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) @@ -72,10 +75,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; @@ -84,8 +87,9 @@ void overrideOptionWithHeuristic(T& variable, const char* name) return; fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue); -#endif } +#endif + static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) { @@ -126,19 +130,17 @@ 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 @@ -151,7 +153,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 d6d8c66c8..7571f9138 100644 --- a/Source/JavaScriptCore/runtime/Options.h +++ b/Source/JavaScriptCore/runtime/Options.h @@ -51,8 +51,9 @@ namespace JSC { // purposes, you can do so in Options::initialize() after the default values // are set. // -// Alternatively, you can override the default values by specifying -// environment variables of the form: JSC_<name of JSC option>. +// 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>. // // Note: Options::initialize() tries to ensure some sanity on the option values // which are set by doing some range checks, and value corrections. These @@ -115,19 +116,14 @@ 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, showObjectStatistics, false) \ - \ - v(unsigned, gcMaxHeapSize, 0) \ - v(bool, recordGCPauseTimes, false) \ - v(bool, logHeapStatisticsAtExit, false) + v(bool, showHeapStatistics, false) + class Options { public: @@ -165,7 +161,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 9c6ddb20f..2d0f27a3e 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(PropertyOffset inlineCapacity); + PropertyOffset nextOffset(JSType); // Copy this PropertyTable, ensuring the copy has at least the capacity provided. PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity); @@ -486,12 +486,15 @@ inline void PropertyTable::addDeletedOffset(PropertyOffset offset) m_deletedOffsets->append(offset); } -inline PropertyOffset PropertyTable::nextOffset(PropertyOffset inlineCapacity) +inline PropertyOffset PropertyTable::nextOffset(JSType type) { if (hasDeletedOffset()) return getDeletedOffset(); - - return propertyOffsetFor(size(), inlineCapacity); + + if (type == FinalObjectType) + return size(); + + return size() + firstOutOfLineOffset; } 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 1a2bba446..2aea2981e 100644 --- a/Source/JavaScriptCore/runtime/PropertyOffset.h +++ b/Source/JavaScriptCore/runtime/PropertyOffset.h @@ -26,6 +26,7 @@ #ifndef PropertyOffset_h #define PropertyOffset_h +#include "JSType.h" #include <wtf/Platform.h> #include <wtf/StdLibExtras.h> #include <wtf/UnusedParam.h> @@ -41,13 +42,14 @@ namespace JSC { typedef int PropertyOffset; static const PropertyOffset invalidOffset = -1; -static const PropertyOffset firstOutOfLineOffset = 100; +static const PropertyOffset inlineStorageCapacity = INLINE_STORAGE_CAPACITY; +static const PropertyOffset firstOutOfLineOffset = inlineStorageCapacity; // Declare all of the functions because they tend to do forward calls. inline void checkOffset(PropertyOffset); -inline void checkOffset(PropertyOffset, PropertyOffset inlineCapacity); +inline void checkOffset(PropertyOffset, JSType); inline void validateOffset(PropertyOffset); -inline void validateOffset(PropertyOffset, PropertyOffset inlineCapacity); +inline void validateOffset(PropertyOffset, JSType); inline bool isValidOffset(PropertyOffset); inline bool isInlineOffset(PropertyOffset); inline bool isOutOfLineOffset(PropertyOffset); @@ -55,7 +57,9 @@ 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, PropertyOffset inlineCapacity); +inline size_t numberOfSlotsForLastOffset(PropertyOffset, JSType); +inline PropertyOffset nextPropertyOffsetFor(PropertyOffset, JSType); +inline PropertyOffset firstPropertyOffsetFor(JSType); inline void checkOffset(PropertyOffset offset) { @@ -63,14 +67,14 @@ inline void checkOffset(PropertyOffset offset) ASSERT(offset >= invalidOffset); } -inline void checkOffset(PropertyOffset offset, PropertyOffset inlineCapacity) +inline void checkOffset(PropertyOffset offset, JSType type) { UNUSED_PARAM(offset); - UNUSED_PARAM(inlineCapacity); + UNUSED_PARAM(type); ASSERT(offset >= invalidOffset); ASSERT(offset == invalidOffset - || offset < inlineCapacity - || isOutOfLineOffset(offset)); + || type == FinalObjectType + || isOutOfLineOffset(offset)); } inline void validateOffset(PropertyOffset offset) @@ -79,9 +83,9 @@ inline void validateOffset(PropertyOffset offset) ASSERT(isValidOffset(offset)); } -inline void validateOffset(PropertyOffset offset, PropertyOffset inlineCapacity) +inline void validateOffset(PropertyOffset offset, JSType type) { - checkOffset(offset, inlineCapacity); + checkOffset(offset, type); ASSERT(isValidOffset(offset)); } @@ -94,7 +98,7 @@ inline bool isValidOffset(PropertyOffset offset) inline bool isInlineOffset(PropertyOffset offset) { checkOffset(offset); - return offset < firstOutOfLineOffset; + return offset < inlineStorageCapacity; } inline bool isOutOfLineOffset(PropertyOffset offset) @@ -132,24 +136,28 @@ inline size_t numberOfOutOfLineSlotsForLastOffset(PropertyOffset offset) return offset - firstOutOfLineOffset + 1; } -inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, PropertyOffset inlineCapacity) +inline size_t numberOfSlotsForLastOffset(PropertyOffset offset, JSType type) { - checkOffset(offset, inlineCapacity); - if (offset < inlineCapacity) + checkOffset(offset, type); + if (type == FinalObjectType) return offset + 1; - return inlineCapacity + numberOfOutOfLineSlotsForLastOffset(offset); + return numberOfOutOfLineSlotsForLastOffset(offset); } -inline PropertyOffset propertyOffsetFor(PropertyOffset propertyNumber, PropertyOffset inlineCapacity) +inline PropertyOffset nextPropertyOffsetFor(PropertyOffset offset, JSType type) { - PropertyOffset offset = propertyNumber; - if (offset >= inlineCapacity) { - offset += firstOutOfLineOffset; - offset -= inlineCapacity; - } - return offset; + checkOffset(offset, type); + if (type != FinalObjectType && offset == invalidOffset) + return firstOutOfLineOffset; + return offset + 1; +} + +inline PropertyOffset firstPropertyOffsetFor(JSType type) +{ + return nextPropertyOffsetFor(invalidOffset, type); } } // namespace JSC #endif // PropertyOffset_h + diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h index b2b65d90c..287444b95 100644 --- a/Source/JavaScriptCore/runtime/RegExp.h +++ b/Source/JavaScriptCore/runtime/RegExp.h @@ -47,8 +47,6 @@ 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 8acafba23..c67dab8e6 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->value.get(); + RegExp* regExp = it->second.get(); if (!regExp) // Skip zombies. continue; regExp->invalidateCode(); diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp index cc6ceb1d1..b8c4cd0b3 100644 --- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -53,6 +53,8 @@ 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 ce9c2d2db..04fea60e8 100644 --- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp +++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp @@ -30,6 +30,8 @@ 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 dfbf533f7..bed44f22c 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_HAS_TRIVIAL_DESTRUCTOR(RegExpObject); +ASSERT_CLASS_FITS_IN_CELL(RegExpObject); -const ClassInfo RegExpObject::s_info = { "RegExp", &Base::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) }; +const ClassInfo RegExpObject::s_info = { "RegExp", &JSNonFinalObject::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 e4bf2cf9a..3c742a0d3 100644 --- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -59,6 +59,8 @@ 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 7f21e2c9f..b9ba25735 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->value; + SparseArrayEntry& entry = result.iterator->second; // 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->value; + SparseArrayEntry& entry = result.iterator->second; // 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->value); + visitor.append(&it->second); } } // namespace JSC diff --git a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h index 366a7b8ba..5d8d0577a 100644 --- a/Source/JavaScriptCore/runtime/SparseArrayValueMap.h +++ b/Source/JavaScriptCore/runtime/SparseArrayValueMap.h @@ -81,8 +81,6 @@ 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 7f36a84be..460343761 100644 --- a/Source/JavaScriptCore/runtime/StringConstructor.cpp +++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp @@ -45,6 +45,7 @@ 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 ab7d6cb23..15900913d 100644 --- a/Source/JavaScriptCore/runtime/StringObject.cpp +++ b/Source/JavaScriptCore/runtime/StringObject.cpp @@ -27,6 +27,7 @@ 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 1540177be..8daa0f335 100644 --- a/Source/JavaScriptCore/runtime/StringPrototype.cpp +++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp @@ -47,6 +47,7 @@ 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 a931def27..a59a0860d 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, PropertyOffset inlineCapacity) +Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType) : JSCell(globalData, globalData.structureStructure.get()) , m_typeInfo(typeInfo) , m_indexingType(indexingType) @@ -158,7 +158,6 @@ 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) @@ -183,7 +182,6 @@ 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) @@ -206,7 +204,6 @@ 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) @@ -326,15 +323,11 @@ bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const } } -bool Structure::needsSlowPutIndexing() const +NonPropertyTransition Structure::suggestedIndexingTransition() const { - return anyObjectInChainMayInterceptIndexedAccesses() - || globalObject()->isHavingABadTime(); -} - -NonPropertyTransition Structure::suggestedArrayStorageTransition() const -{ - if (needsSlowPutIndexing()) + ASSERT(!hasIndexedProperties(indexingType())); + + if (anyObjectInChainMayInterceptIndexedAccesses() || globalObject()->isHavingABadTime()) return AllocateSlowPutArrayStorage; return AllocateArrayStorage; @@ -553,7 +546,6 @@ 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) @@ -616,21 +608,20 @@ 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); - iter->offset = propertyOffsetFor(i, m_inlineCapacity); + // Update property table to have the new property offsets + iter->offset = i + firstOffset; } - // Copies in our values to their compacted locations. + // Copy the original property values into their final locations for (unsigned i = 0; i < propertyCount; i++) - object->putDirectOffset(globalData, propertyOffsetFor(i, m_inlineCapacity), values[i]); + object->putDirectOffset(globalData, firstOffset + i, values[i]); m_propertyTable->clearDeletedOffsets(); } @@ -768,7 +759,7 @@ PropertyOffset Structure::putSpecificValue(JSGlobalData& globalData, PropertyNam if (!m_propertyTable) createPropertyMap(); - PropertyOffset newOffset = m_propertyTable->nextOffset(m_inlineCapacity); + PropertyOffset newOffset = m_propertyTable->nextOffset(m_typeInfo.type()); 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 f45e9f1d9..e77287b20 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 = NonArray, PropertyOffset inlineCapacity = 0); + static Structure* create(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0); protected: void finishCreation(JSGlobalData& globalData) @@ -128,8 +128,6 @@ 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. @@ -154,8 +152,7 @@ namespace JSC { bool anyObjectInChainMayInterceptIndexedAccesses() const; - bool needsSlowPutIndexing() const; - NonPropertyTransition suggestedArrayStorageTransition() const; + NonPropertyTransition suggestedIndexingTransition() const; JSGlobalObject* globalObject() const { return m_globalObject.get(); } void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); } @@ -180,6 +177,24 @@ 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); @@ -194,20 +209,31 @@ namespace JSC { } bool hasInlineStorage() const { - return !!m_inlineCapacity; + return m_typeInfo.type() == FinalObjectType; } unsigned inlineCapacity() const { - return m_inlineCapacity; + if (hasInlineStorage()) + return inlineStorageCapacity; + return 0; } - unsigned inlineSize() const + unsigned inlineSizeForKnownFinalObject() const { + ASSERT(m_typeInfo.type() == FinalObjectType); unsigned result; if (m_propertyTable) result = m_propertyTable->propertyStorageSize(); else result = m_offset + 1; - return std::min<unsigned>(result, m_inlineCapacity); + if (result > static_cast<unsigned>(inlineStorageCapacity)) + return inlineStorageCapacity; + return result; + } + unsigned inlineSize() const + { + if (!hasInlineStorage()) + return 0; + return inlineSizeForKnownFinalObject(); } unsigned totalStorageSize() const { @@ -225,12 +251,16 @@ namespace JSC { { if (hasInlineStorage()) return 0; - return firstOutOfLineOffset; + return inlineStorageCapacity; } PropertyOffset lastValidOffset() const { - if (m_propertyTable) - return propertyOffsetFor(m_propertyTable->propertyStorageSize() - 1, m_inlineCapacity); + if (m_propertyTable) { + PropertyOffset size = m_propertyTable->propertyStorageSize(); + if (!hasInlineStorage()) + size += inlineStorageCapacity; + return size - 1; + } return m_offset; } bool isValidOffset(PropertyOffset offset) const @@ -351,7 +381,7 @@ namespace JSC { private: friend class LLIntOffsetsExtractor; - JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, PropertyOffset inlineCapacity); + JS_EXPORT_PRIVATE Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType = 0); Structure(JSGlobalData&); Structure(JSGlobalData&, const Structure*); @@ -427,8 +457,6 @@ 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; @@ -445,11 +473,22 @@ namespace JSC { unsigned m_staticFunctionReified; }; - inline Structure* Structure::create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, PropertyOffset inlineCapacity) + 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) { ASSERT(globalData.structureStructure); ASSERT(classInfo); - Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType, inlineCapacity); + Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo, indexingType); structure->finishCreation(globalData); return structure; } @@ -589,6 +628,15 @@ 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 878f606b4..3b19d4cf1 100644 --- a/Source/JavaScriptCore/runtime/StructureChain.h +++ b/Source/JavaScriptCore/runtime/StructureChain.h @@ -59,10 +59,6 @@ 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) { @@ -82,6 +78,7 @@ 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 3ab7b2014..90cb6a4db 100644 --- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h @@ -43,7 +43,6 @@ 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, @@ -58,18 +57,13 @@ inline unsigned toAttributes(NonPropertyTransition transition) inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition) { switch (transition) { - case AllocateContiguous: - ASSERT(!hasIndexedProperties(oldType)); - return oldType | ContiguousShape; case AllocateArrayStorage: - ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); - return (oldType & ~IndexingShapeMask) | ArrayStorageShape; + return oldType | HasArrayStorage; case AllocateSlowPutArrayStorage: - ASSERT(!hasIndexedProperties(oldType) || hasContiguous(oldType)); - return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; + return oldType | HasSlowPutArrayStorage; case SwitchToSlowPutArrayStorage: - ASSERT(hasFastArrayStorage(oldType)); - return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; + ASSERT(oldType & HasArrayStorage); + return (oldType & ~HasArrayStorage) | HasSlowPutArrayStorage; case AddIndexedAccessors: return oldType | MayHaveIndexedAccessors; default: diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h index debb76499..6063dbab4 100644 --- a/Source/JavaScriptCore/runtime/SymbolTable.h +++ b/Source/JavaScriptCore/runtime/SymbolTable.h @@ -344,16 +344,12 @@ 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) @@ -400,7 +396,6 @@ 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 deleted file mode 100644 index 1ae4818be..000000000 --- a/Source/JavaScriptCore/runtime/TypedArrayDescriptor.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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 52e5e2946..6926165a7 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->value); + WeakSet::deallocate(ptr->second); 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->value); - result.iterator->value = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key)); + WeakSet::deallocate(result.iterator->second); + result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key)); } void remove(const KeyType& key) |